C#: Re-introduce exception logging and error stack traces in editor
These two had been disabled while moving to .NET 5, as the previous implementation relied on Mono embedding APIs.
This commit is contained in:
parent
67db89988d
commit
778007a358
@ -104,7 +104,7 @@ Error CSharpLanguage::execute_file(const String &p_path) {
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void *godotsharp_pinvoke_funcs[181];
|
extern void *godotsharp_pinvoke_funcs[185];
|
||||||
[[maybe_unused]] volatile void **do_not_strip_godotsharp_pinvoke_funcs;
|
[[maybe_unused]] volatile void **do_not_strip_godotsharp_pinvoke_funcs;
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
extern void *godotsharp_editor_pinvoke_funcs[30];
|
extern void *godotsharp_editor_pinvoke_funcs[30];
|
||||||
@ -592,8 +592,6 @@ String CSharpLanguage::debug_get_stack_level_source(int p_level) const {
|
|||||||
return String();
|
return String();
|
||||||
}
|
}
|
||||||
|
|
||||||
#warning TODO
|
|
||||||
#if 0
|
|
||||||
Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info() {
|
Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info() {
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
// Printing an error here will result in endless recursion, so we must be careful
|
// Printing an error here will result in endless recursion, so we must be careful
|
||||||
@ -606,21 +604,15 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info()
|
|||||||
_recursion_flag_ = false;
|
_recursion_flag_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
GD_MONO_SCOPE_THREAD_ATTACH;
|
if (!gdmono->is_runtime_initialized()) {
|
||||||
|
|
||||||
if (!gdmono->is_runtime_initialized() || !GDMono::get_singleton()->get_core_api_assembly() || !GDMonoCache::cached_data.corlib_cache_updated) {
|
|
||||||
return Vector<StackInfo>();
|
return Vector<StackInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
MonoObject *stack_trace = mono_object_new(mono_domain_get(), CACHED_CLASS(System_Diagnostics_StackTrace)->get_mono_ptr());
|
|
||||||
|
|
||||||
MonoBoolean need_file_info = true;
|
|
||||||
void *ctor_args[1] = { &need_file_info };
|
|
||||||
|
|
||||||
CACHED_METHOD(System_Diagnostics_StackTrace, ctor_bool)->invoke_raw(stack_trace, ctor_args);
|
|
||||||
|
|
||||||
Vector<StackInfo> si;
|
Vector<StackInfo> si;
|
||||||
si = stack_trace_get_info(stack_trace);
|
|
||||||
|
if (GDMonoCache::godot_api_cache_updated) {
|
||||||
|
GDMonoCache::managed_callbacks.DebuggingUtils_GetCurrentStackInfo(&si);
|
||||||
|
}
|
||||||
|
|
||||||
return si;
|
return si;
|
||||||
#else
|
#else
|
||||||
@ -628,70 +620,6 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
|
||||||
Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObject *p_stack_trace) {
|
|
||||||
// Printing an error here will result in endless recursion, so we must be careful
|
|
||||||
static thread_local bool _recursion_flag_ = false;
|
|
||||||
if (_recursion_flag_) {
|
|
||||||
return Vector<StackInfo>();
|
|
||||||
}
|
|
||||||
_recursion_flag_ = true;
|
|
||||||
SCOPE_EXIT {
|
|
||||||
_recursion_flag_ = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
GD_MONO_SCOPE_THREAD_ATTACH;
|
|
||||||
|
|
||||||
MonoException *exc = nullptr;
|
|
||||||
|
|
||||||
MonoArray *frames = CACHED_METHOD_THUNK(System_Diagnostics_StackTrace, GetFrames).invoke(p_stack_trace, &exc);
|
|
||||||
|
|
||||||
if (exc) {
|
|
||||||
GDMonoUtils::debug_print_unhandled_exception(exc);
|
|
||||||
return Vector<StackInfo>();
|
|
||||||
}
|
|
||||||
|
|
||||||
int frame_count = mono_array_length(frames);
|
|
||||||
|
|
||||||
if (frame_count <= 0) {
|
|
||||||
return Vector<StackInfo>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<StackInfo> si;
|
|
||||||
si.resize(frame_count);
|
|
||||||
|
|
||||||
for (int i = 0; i < frame_count; i++) {
|
|
||||||
StackInfo &sif = si.write[i];
|
|
||||||
MonoObject *frame = mono_array_get(frames, MonoObject *, i);
|
|
||||||
|
|
||||||
MonoString *file_name;
|
|
||||||
int file_line_num;
|
|
||||||
MonoString *method_decl;
|
|
||||||
CACHED_METHOD_THUNK(DebuggingUtils, GetStackFrameInfo).invoke(frame, &file_name, &file_line_num, &method_decl, &exc);
|
|
||||||
|
|
||||||
if (exc) {
|
|
||||||
GDMonoUtils::debug_print_unhandled_exception(exc);
|
|
||||||
return Vector<StackInfo>();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
// what if the StackFrame method is null (method_decl is empty). should we skip this frame?
|
|
||||||
// can reproduce with a MissingMethodException on internal calls
|
|
||||||
|
|
||||||
sif.file = GDMonoMarshal::mono_string_to_godot(file_name);
|
|
||||||
sif.line = file_line_num;
|
|
||||||
sif.func = GDMonoMarshal::mono_string_to_godot(method_decl);
|
|
||||||
}
|
|
||||||
|
|
||||||
return si;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info() {
|
|
||||||
return Vector<StackInfo>();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void CSharpLanguage::post_unsafe_reference(Object *p_obj) {
|
void CSharpLanguage::post_unsafe_reference(Object *p_obj) {
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
MutexLock lock(unsafe_object_references_lock);
|
MutexLock lock(unsafe_object_references_lock);
|
||||||
|
@ -464,13 +464,6 @@ public:
|
|||||||
static void tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, Ref<CSharpScript> *p_script, bool p_ref_counted);
|
static void tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, Ref<CSharpScript> *p_script, bool p_ref_counted);
|
||||||
static void tie_managed_to_unmanaged_with_pre_setup(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged);
|
static void tie_managed_to_unmanaged_with_pre_setup(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged);
|
||||||
|
|
||||||
#warning TODO
|
|
||||||
#if 0
|
|
||||||
#ifdef DEBUG_ENABLED
|
|
||||||
Vector<StackInfo> stack_trace_get_info(MonoObject *p_stack_trace);
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void post_unsafe_reference(Object *p_obj);
|
void post_unsafe_reference(Object *p_obj);
|
||||||
void pre_unsafe_unreference(Object *p_obj);
|
void pre_unsafe_unreference(Object *p_obj);
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
*ret = default;
|
*ret = default;
|
||||||
return false.ToGodotBool();
|
return false.ToGodotBool();
|
||||||
}
|
}
|
||||||
@ -69,7 +69,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
return false.ToGodotBool();
|
return false.ToGodotBool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,7 +107,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
*outRet = default;
|
*outRet = default;
|
||||||
return false.ToGodotBool();
|
return false.ToGodotBool();
|
||||||
}
|
}
|
||||||
@ -127,7 +127,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,7 +159,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
*outRes = default;
|
*outRes = default;
|
||||||
*outValid = false.ToGodotBool();
|
*outValid = false.ToGodotBool();
|
||||||
}
|
}
|
||||||
@ -179,7 +179,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
return false.ToGodotBool();
|
return false.ToGodotBool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,9 +34,9 @@ namespace Godot.Bridge
|
|||||||
public delegate* unmanaged<IntPtr, godot_string*, godot_bool*, void> CSharpInstanceBridge_CallToString;
|
public delegate* unmanaged<IntPtr, godot_string*, godot_bool*, void> CSharpInstanceBridge_CallToString;
|
||||||
public delegate* unmanaged<IntPtr, godot_string_name*, godot_bool> CSharpInstanceBridge_HasMethodUnknownParams;
|
public delegate* unmanaged<IntPtr, godot_string_name*, godot_bool> CSharpInstanceBridge_HasMethodUnknownParams;
|
||||||
public delegate* unmanaged<IntPtr, void> GCHandleBridge_FreeGCHandle;
|
public delegate* unmanaged<IntPtr, void> GCHandleBridge_FreeGCHandle;
|
||||||
public delegate* unmanaged<void> DebuggingUtils_InstallTraceListener;
|
public delegate* unmanaged<void*, void> DebuggingUtils_GetCurrentStackInfo;
|
||||||
public delegate* unmanaged<void> Dispatcher_InitializeDefaultGodotTaskScheduler;
|
|
||||||
public delegate* unmanaged<void> DisposablesTracker_OnGodotShuttingDown;
|
public delegate* unmanaged<void> DisposablesTracker_OnGodotShuttingDown;
|
||||||
|
public delegate* unmanaged<godot_bool, void> GD_OnCoreApiAssemblyLoaded;
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
||||||
public static ManagedCallbacks Create()
|
public static ManagedCallbacks Create()
|
||||||
@ -70,9 +70,9 @@ namespace Godot.Bridge
|
|||||||
CSharpInstanceBridge_CallToString = &CSharpInstanceBridge.CallToString,
|
CSharpInstanceBridge_CallToString = &CSharpInstanceBridge.CallToString,
|
||||||
CSharpInstanceBridge_HasMethodUnknownParams = &CSharpInstanceBridge.HasMethodUnknownParams,
|
CSharpInstanceBridge_HasMethodUnknownParams = &CSharpInstanceBridge.HasMethodUnknownParams,
|
||||||
GCHandleBridge_FreeGCHandle = &GCHandleBridge.FreeGCHandle,
|
GCHandleBridge_FreeGCHandle = &GCHandleBridge.FreeGCHandle,
|
||||||
DebuggingUtils_InstallTraceListener = &DebuggingUtils.InstallTraceListener,
|
DebuggingUtils_GetCurrentStackInfo = &DebuggingUtils.GetCurrentStackInfo,
|
||||||
Dispatcher_InitializeDefaultGodotTaskScheduler = &Dispatcher.InitializeDefaultGodotTaskScheduler,
|
|
||||||
DisposablesTracker_OnGodotShuttingDown = &DisposablesTracker.OnGodotShuttingDown,
|
DisposablesTracker_OnGodotShuttingDown = &DisposablesTracker.OnGodotShuttingDown,
|
||||||
|
GD_OnCoreApiAssemblyLoaded = &GD.OnCoreApiAssemblyLoaded,
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
return IntPtr.Zero;
|
return IntPtr.Zero;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,7 +111,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
return false.ToGodotBool();
|
return false.ToGodotBool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,7 +151,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
*outRes = default;
|
*outRes = default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,7 +167,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,7 +280,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
*outOwnerIsNull = false.ToGodotBool();
|
*outOwnerIsNull = false.ToGodotBool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -374,7 +374,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
*outRetSignals = NativeFuncs.godotsharp_dictionary_new();
|
*outRetSignals = NativeFuncs.godotsharp_dictionary_new();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -425,7 +425,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
return false.ToGodotBool();
|
return false.ToGodotBool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -445,7 +445,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
return false.ToGodotBool();
|
return false.ToGodotBool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -473,7 +473,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
return false.ToGodotBool();
|
return false.ToGodotBool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -524,7 +524,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -596,7 +596,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
*outTool = false.ToGodotBool();
|
*outTool = false.ToGodotBool();
|
||||||
*outRpcFunctionsDest = NativeFuncs.godotsharp_dictionary_new();
|
*outRpcFunctionsDest = NativeFuncs.godotsharp_dictionary_new();
|
||||||
}
|
}
|
||||||
@ -629,7 +629,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
*outNewGCHandlePtr = IntPtr.Zero;
|
*outNewGCHandlePtr = IntPtr.Zero;
|
||||||
return false.ToGodotBool();
|
return false.ToGodotBool();
|
||||||
}
|
}
|
||||||
@ -665,7 +665,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -757,7 +757,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -794,7 +794,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -882,7 +882,7 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Godot.NativeInterop;
|
using Godot.NativeInterop;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
namespace Godot
|
namespace Godot
|
||||||
{
|
{
|
||||||
internal static class DebuggingUtils
|
internal static class DebuggingUtils
|
||||||
{
|
{
|
||||||
internal static void AppendTypeName(this StringBuilder sb, Type type)
|
private static void AppendTypeName(this StringBuilder sb, Type type)
|
||||||
{
|
{
|
||||||
if (type.IsPrimitive)
|
if (type.IsPrimitive)
|
||||||
sb.Append(type.Name);
|
sb.Append(type.Name);
|
||||||
@ -21,28 +24,94 @@ namespace Godot
|
|||||||
sb.Append(' ');
|
sb.Append(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
|
||||||
internal static void InstallTraceListener()
|
internal static void InstallTraceListener()
|
||||||
{
|
{
|
||||||
try
|
Trace.Listeners.Clear();
|
||||||
|
Trace.Listeners.Add(new GodotTraceListener());
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
internal ref struct godot_stack_info
|
||||||
|
{
|
||||||
|
public godot_string File;
|
||||||
|
public godot_string Func;
|
||||||
|
public int Line;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
|
internal ref struct godot_stack_info_vector
|
||||||
|
{
|
||||||
|
private IntPtr _writeProxy;
|
||||||
|
private unsafe godot_stack_info* _ptr;
|
||||||
|
|
||||||
|
public readonly unsafe godot_stack_info* Elements
|
||||||
{
|
{
|
||||||
Trace.Listeners.Clear();
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
Trace.Listeners.Add(new GodotTraceListener());
|
get => _ptr;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
|
||||||
|
public void Resize(int size)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
if (size < 0)
|
||||||
ExceptionUtils.PushError("Failed to install 'System.Diagnostics.Trace' listener.");
|
throw new ArgumentOutOfRangeException(nameof(size));
|
||||||
|
var err = NativeFuncs.godotsharp_stack_info_vector_resize(ref this, size);
|
||||||
|
if (err != Error.Ok)
|
||||||
|
throw new InvalidOperationException("Failed to resize vector. Error code is: " + err.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe void Dispose()
|
||||||
|
{
|
||||||
|
if (_ptr == null)
|
||||||
|
return;
|
||||||
|
NativeFuncs.godotsharp_stack_info_vector_destroy(ref this);
|
||||||
|
_ptr = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void GetStackFrameInfo(StackFrame frame, out string fileName, out int fileLineNumber,
|
[UnmanagedCallersOnly]
|
||||||
out string methodDecl)
|
internal static unsafe void GetCurrentStackInfo(void* destVector)
|
||||||
{
|
{
|
||||||
fileName = frame.GetFileName();
|
try
|
||||||
fileLineNumber = frame.GetFileLineNumber();
|
{
|
||||||
|
var vector = (godot_stack_info_vector*)destVector;
|
||||||
|
var stackTrace = new StackTrace(skipFrames: 1, fNeedFileInfo: true);
|
||||||
|
int frameCount = stackTrace.FrameCount;
|
||||||
|
|
||||||
MethodBase methodBase = frame.GetMethod();
|
if (frameCount == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
vector->Resize(frameCount);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
foreach (StackFrame frame in stackTrace.GetFrames())
|
||||||
|
{
|
||||||
|
string? fileName = frame.GetFileName();
|
||||||
|
int fileLineNumber = frame.GetFileLineNumber();
|
||||||
|
|
||||||
|
GetStackFrameMethodDecl(frame, out string methodDecl);
|
||||||
|
|
||||||
|
godot_stack_info* stackInfo = &vector->Elements[i];
|
||||||
|
|
||||||
|
// Assign directly to element in Vector. This way we don't need to worry
|
||||||
|
// about disposal if an exception is thrown. The Vector takes care of it.
|
||||||
|
stackInfo->File = Marshaling.ConvertStringToNative(fileName);
|
||||||
|
stackInfo->Func = Marshaling.ConvertStringToNative(methodDecl);
|
||||||
|
stackInfo->Line = fileLineNumber;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
ExceptionUtils.LogException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void GetStackFrameMethodDecl(StackFrame frame, out string methodDecl)
|
||||||
|
{
|
||||||
|
MethodBase? methodBase = frame.GetMethod();
|
||||||
|
|
||||||
if (methodBase == null)
|
if (methodBase == null)
|
||||||
{
|
{
|
||||||
|
@ -22,7 +22,7 @@ namespace Godot
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
return false.ToGodotBool();
|
return false.ToGodotBool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,7 +58,7 @@ namespace Godot
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
*outRet = default;
|
*outRet = default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,18 +8,8 @@ namespace Godot
|
|||||||
{
|
{
|
||||||
internal static GodotTaskScheduler DefaultGodotTaskScheduler;
|
internal static GodotTaskScheduler DefaultGodotTaskScheduler;
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
|
||||||
internal static void InitializeDefaultGodotTaskScheduler()
|
internal static void InitializeDefaultGodotTaskScheduler()
|
||||||
{
|
=> DefaultGodotTaskScheduler = new GodotTaskScheduler();
|
||||||
try
|
|
||||||
{
|
|
||||||
DefaultGodotTaskScheduler = new GodotTaskScheduler();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
ExceptionUtils.DebugUnhandledException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GodotSynchronizationContext SynchronizationContext => DefaultGodotTaskScheduler.Context;
|
public static GodotSynchronizationContext SynchronizationContext => DefaultGodotTaskScheduler.Context;
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ namespace Godot
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,17 +1,33 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Godot.NativeInterop;
|
||||||
|
|
||||||
namespace Godot
|
namespace Godot
|
||||||
{
|
{
|
||||||
public static partial class GD
|
public static partial class GD
|
||||||
{
|
{
|
||||||
/// <summary>
|
[UnmanagedCallersOnly]
|
||||||
/// Fires when an unhandled exception occurs, regardless of project settings.
|
internal static void OnCoreApiAssemblyLoaded(godot_bool isDebug)
|
||||||
/// </summary>
|
|
||||||
public static event EventHandler<UnhandledExceptionArgs> UnhandledException;
|
|
||||||
|
|
||||||
private static void OnUnhandledException(Exception e)
|
|
||||||
{
|
{
|
||||||
UnhandledException?.Invoke(null, new UnhandledExceptionArgs(e));
|
try
|
||||||
|
{
|
||||||
|
Dispatcher.InitializeDefaultGodotTaskScheduler();
|
||||||
|
|
||||||
|
if (isDebug.ToBool())
|
||||||
|
{
|
||||||
|
DebuggingUtils.InstallTraceListener();
|
||||||
|
|
||||||
|
AppDomain.CurrentDomain.UnhandledException += (_, e) =>
|
||||||
|
{
|
||||||
|
// Exception.ToString() includes the inner exception
|
||||||
|
ExceptionUtils.LogUnhandledException((Exception)e.ExceptionObject);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
ExceptionUtils.LogException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
namespace Godot.NativeInterop
|
namespace Godot.NativeInterop
|
||||||
{
|
{
|
||||||
@ -11,20 +16,101 @@ namespace Godot.NativeInterop
|
|||||||
|
|
||||||
private static void OnExceptionLoggerException(Exception loggerException, Exception exceptionToLog)
|
private static void OnExceptionLoggerException(Exception loggerException, Exception exceptionToLog)
|
||||||
{
|
{
|
||||||
// This better not throw
|
try
|
||||||
PushError("Exception thrown when trying to log another exception...");
|
{
|
||||||
PushError("Exception:");
|
// This better not throw
|
||||||
PushError(exceptionToLog.ToString());
|
PushError(string.Concat("Exception thrown while trying to log another exception...",
|
||||||
PushError("Logger exception:");
|
"\n### Exception ###\n", exceptionToLog.ToString(),
|
||||||
PushError(loggerException.ToString());
|
"\n### Logger exception ###\n", loggerException.ToString()));
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// Well, too bad...
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DebugPrintUnhandledException(Exception e)
|
private record struct StackInfoTuple(string? File, string Func, int Line);
|
||||||
|
|
||||||
|
private static void CollectExceptionInfo(Exception exception, List<StackInfoTuple> globalFrames,
|
||||||
|
StringBuilder excMsg)
|
||||||
|
{
|
||||||
|
if (excMsg.Length > 0)
|
||||||
|
excMsg.Append(" ---> ");
|
||||||
|
excMsg.Append(exception.GetType().FullName);
|
||||||
|
excMsg.Append(": ");
|
||||||
|
excMsg.Append(exception.Message);
|
||||||
|
|
||||||
|
var innerExc = exception.InnerException;
|
||||||
|
|
||||||
|
if (innerExc != null)
|
||||||
|
{
|
||||||
|
CollectExceptionInfo(innerExc, globalFrames, excMsg);
|
||||||
|
globalFrames.Add(new("", "--- End of inner exception stack trace ---", 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
var stackTrace = new StackTrace(exception, fNeedFileInfo: true);
|
||||||
|
|
||||||
|
foreach (StackFrame frame in stackTrace.GetFrames())
|
||||||
|
{
|
||||||
|
DebuggingUtils.GetStackFrameMethodDecl(frame, out string methodDecl);
|
||||||
|
globalFrames.Add(new(frame.GetFileName(), methodDecl, frame.GetFileLineNumber()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SendToScriptDebugger(Exception e)
|
||||||
|
{
|
||||||
|
var globalFrames = new List<StackInfoTuple>();
|
||||||
|
|
||||||
|
var excMsg = new StringBuilder();
|
||||||
|
|
||||||
|
CollectExceptionInfo(e, globalFrames, excMsg);
|
||||||
|
|
||||||
|
string file = globalFrames.Count > 0 ? globalFrames[0].File ?? "" : "";
|
||||||
|
string func = globalFrames.Count > 0 ? globalFrames[0].Func : "";
|
||||||
|
int line = globalFrames.Count > 0 ? globalFrames[0].Line : 0;
|
||||||
|
string errorMsg = "Exception";
|
||||||
|
|
||||||
|
using godot_string nFile = Marshaling.ConvertStringToNative(file);
|
||||||
|
using godot_string nFunc = Marshaling.ConvertStringToNative(func);
|
||||||
|
using godot_string nErrorMsg = Marshaling.ConvertStringToNative(errorMsg);
|
||||||
|
using godot_string nExcMsg = Marshaling.ConvertStringToNative(excMsg.ToString());
|
||||||
|
|
||||||
|
using DebuggingUtils.godot_stack_info_vector stackInfoVector = default;
|
||||||
|
|
||||||
|
stackInfoVector.Resize(globalFrames.Count);
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
for (int i = 0; i < globalFrames.Count; i++)
|
||||||
|
{
|
||||||
|
DebuggingUtils.godot_stack_info* stackInfo = &stackInfoVector.Elements[i];
|
||||||
|
|
||||||
|
var globalFrame = globalFrames[i];
|
||||||
|
|
||||||
|
// Assign directly to element in Vector. This way we don't need to worry
|
||||||
|
// about disposal if an exception is thrown. The Vector takes care of it.
|
||||||
|
stackInfo->File = Marshaling.ConvertStringToNative(globalFrame.File);
|
||||||
|
stackInfo->Func = Marshaling.ConvertStringToNative(globalFrame.Func);
|
||||||
|
stackInfo->Line = globalFrame.Line;
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeFuncs.godotsharp_internal_script_debugger_send_error(nFunc, nFile, line,
|
||||||
|
nErrorMsg, nExcMsg, p_warning: false.ToGodotBool(), stackInfoVector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogException(Exception e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// TODO Not implemented (debug_print_unhandled_exception)
|
if (NativeFuncs.godotsharp_internal_script_debugger_is_active())
|
||||||
GD.PushError(e.ToString());
|
{
|
||||||
|
SendToScriptDebugger(e);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GD.PushError(e.ToString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception unexpected)
|
catch (Exception unexpected)
|
||||||
{
|
{
|
||||||
@ -32,38 +118,17 @@ namespace Godot.NativeInterop
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DebugSendUnhandledExceptionError(Exception e)
|
public static void LogUnhandledException(Exception e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// TODO Not implemented (debug_send_unhandled_exception_error)
|
if (NativeFuncs.godotsharp_internal_script_debugger_is_active())
|
||||||
GD.PushError(e.ToString());
|
{
|
||||||
}
|
SendToScriptDebugger(e);
|
||||||
catch (Exception unexpected)
|
}
|
||||||
{
|
|
||||||
OnExceptionLoggerException(unexpected, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void DebugUnhandledException(Exception e)
|
// In this case, print it as well in addition to sending it to the script debugger
|
||||||
{
|
GD.PushError("Unhandled exception\n" + e);
|
||||||
try
|
|
||||||
{
|
|
||||||
// TODO Not implemented (debug_unhandled_exception)
|
|
||||||
GD.PushError(e.ToString());
|
|
||||||
}
|
|
||||||
catch (Exception unexpected)
|
|
||||||
{
|
|
||||||
OnExceptionLoggerException(unexpected, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void PrintUnhandledException(Exception e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// TODO Not implemented (print_unhandled_exception)
|
|
||||||
GD.PushError(e.ToString());
|
|
||||||
}
|
}
|
||||||
catch (Exception unexpected)
|
catch (Exception unexpected)
|
||||||
{
|
{
|
||||||
|
@ -35,6 +35,23 @@ namespace Godot.NativeInterop
|
|||||||
[DllImport(GodotDllName)]
|
[DllImport(GodotDllName)]
|
||||||
public static extern IntPtr godotsharp_engine_get_singleton(in godot_string p_name);
|
public static extern IntPtr godotsharp_engine_get_singleton(in godot_string p_name);
|
||||||
|
|
||||||
|
|
||||||
|
[DllImport(GodotDllName)]
|
||||||
|
internal static extern Error godotsharp_stack_info_vector_resize(
|
||||||
|
ref DebuggingUtils.godot_stack_info_vector p_stack_info_vector, int p_size);
|
||||||
|
|
||||||
|
[DllImport(GodotDllName)]
|
||||||
|
internal static extern void godotsharp_stack_info_vector_destroy(
|
||||||
|
ref DebuggingUtils.godot_stack_info_vector p_stack_info_vector);
|
||||||
|
|
||||||
|
[DllImport(GodotDllName)]
|
||||||
|
internal static extern void godotsharp_internal_script_debugger_send_error(in godot_string p_func,
|
||||||
|
in godot_string p_file, int p_line, in godot_string p_err, in godot_string p_descr,
|
||||||
|
godot_bool p_warning, in DebuggingUtils.godot_stack_info_vector p_stack_info_vector);
|
||||||
|
|
||||||
|
[DllImport(GodotDllName)]
|
||||||
|
internal static extern bool godotsharp_internal_script_debugger_is_active();
|
||||||
|
|
||||||
[DllImport(GodotDllName)]
|
[DllImport(GodotDllName)]
|
||||||
internal static extern IntPtr godotsharp_internal_object_get_associated_gchandle(IntPtr ptr);
|
internal static extern IntPtr godotsharp_internal_object_get_associated_gchandle(IntPtr ptr);
|
||||||
|
|
||||||
@ -92,7 +109,8 @@ namespace Godot.NativeInterop
|
|||||||
out godot_array r_output);
|
out godot_array r_output);
|
||||||
|
|
||||||
[DllImport(GodotDllName)]
|
[DllImport(GodotDllName)]
|
||||||
public static extern void godotsharp_ref_new_from_ref_counted_ptr(out godot_ref r_dest, IntPtr p_ref_counted_ptr);
|
public static extern void godotsharp_ref_new_from_ref_counted_ptr(out godot_ref r_dest,
|
||||||
|
IntPtr p_ref_counted_ptr);
|
||||||
|
|
||||||
[DllImport(GodotDllName)]
|
[DllImport(GodotDllName)]
|
||||||
public static extern void godotsharp_ref_destroy(ref godot_ref p_instance);
|
public static extern void godotsharp_ref_destroy(ref godot_ref p_instance);
|
||||||
|
@ -58,7 +58,7 @@ namespace Godot
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ExceptionUtils.DebugPrintUnhandledException(e);
|
ExceptionUtils.LogException(e);
|
||||||
*outAwaiterIsNull = false.ToGodotBool();
|
*outAwaiterIsNull = false.ToGodotBool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Godot
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Event arguments for when unhandled exceptions occur.
|
|
||||||
/// </summary>
|
|
||||||
public class UnhandledExceptionArgs
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Exception object.
|
|
||||||
/// </summary>
|
|
||||||
public Exception Exception { get; private set; }
|
|
||||||
|
|
||||||
internal UnhandledExceptionArgs(Exception exception)
|
|
||||||
{
|
|
||||||
Exception = exception;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -8,7 +8,7 @@
|
|||||||
<DocumentationFile>$(OutputPath)/$(AssemblyName).xml</DocumentationFile>
|
<DocumentationFile>$(OutputPath)/$(AssemblyName).xml</DocumentationFile>
|
||||||
<EnableDefaultItems>false</EnableDefaultItems>
|
<EnableDefaultItems>false</EnableDefaultItems>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<LangVersion>9</LangVersion>
|
<LangVersion>10</LangVersion>
|
||||||
|
|
||||||
<AnalysisMode>Recommended</AnalysisMode>
|
<AnalysisMode>Recommended</AnalysisMode>
|
||||||
|
|
||||||
@ -91,7 +91,6 @@
|
|||||||
<Compile Include="Core\StringName.cs" />
|
<Compile Include="Core\StringName.cs" />
|
||||||
<Compile Include="Core\Transform2D.cs" />
|
<Compile Include="Core\Transform2D.cs" />
|
||||||
<Compile Include="Core\Transform3D.cs" />
|
<Compile Include="Core\Transform3D.cs" />
|
||||||
<Compile Include="Core\UnhandledExceptionArgs.cs" />
|
|
||||||
<Compile Include="Core\Vector2.cs" />
|
<Compile Include="Core\Vector2.cs" />
|
||||||
<Compile Include="Core\Vector2i.cs" />
|
<Compile Include="Core\Vector2i.cs" />
|
||||||
<Compile Include="Core\Vector3.cs" />
|
<Compile Include="Core\Vector3.cs" />
|
||||||
|
@ -29,6 +29,8 @@
|
|||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
|
|
||||||
#include "core/config/engine.h"
|
#include "core/config/engine.h"
|
||||||
|
#include "core/debugger/engine_debugger.h"
|
||||||
|
#include "core/debugger/script_debugger.h"
|
||||||
#include "core/io/marshalls.h"
|
#include "core/io/marshalls.h"
|
||||||
#include "core/object/class_db.h"
|
#include "core/object/class_db.h"
|
||||||
#include "core/object/method_bind.h"
|
#include "core/object/method_bind.h"
|
||||||
@ -81,6 +83,27 @@ GD_PINVOKE_EXPORT Object *godotsharp_engine_get_singleton(const String *p_name)
|
|||||||
return Engine::get_singleton()->get_singleton_object(*p_name);
|
return Engine::get_singleton()->get_singleton_object(*p_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GD_PINVOKE_EXPORT int32_t godotsharp_stack_info_vector_resize(
|
||||||
|
Vector<ScriptLanguage::StackInfo> *p_stack_info_vector, int p_size) {
|
||||||
|
return (int32_t)p_stack_info_vector->resize(p_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
GD_PINVOKE_EXPORT void godotsharp_stack_info_vector_destroy(
|
||||||
|
Vector<ScriptLanguage::StackInfo> *p_stack_info_vector) {
|
||||||
|
p_stack_info_vector->~Vector();
|
||||||
|
}
|
||||||
|
|
||||||
|
GD_PINVOKE_EXPORT void godotsharp_internal_script_debugger_send_error(const String *p_func,
|
||||||
|
const String *p_file, int32_t p_line, const String *p_err, const String *p_descr,
|
||||||
|
bool p_warning, const Vector<ScriptLanguage::StackInfo> *p_stack_info_vector) {
|
||||||
|
EngineDebugger::get_script_debugger()->send_error(*p_func, *p_file, p_line, *p_err, *p_descr,
|
||||||
|
true, p_warning ? ERR_HANDLER_WARNING : ERR_HANDLER_ERROR, *p_stack_info_vector);
|
||||||
|
}
|
||||||
|
|
||||||
|
GD_PINVOKE_EXPORT bool godotsharp_internal_script_debugger_is_active() {
|
||||||
|
return EngineDebugger::is_active();
|
||||||
|
}
|
||||||
|
|
||||||
GD_PINVOKE_EXPORT GCHandleIntPtr godotsharp_internal_object_get_associated_gchandle(Object *p_ptr) {
|
GD_PINVOKE_EXPORT GCHandleIntPtr godotsharp_internal_object_get_associated_gchandle(Object *p_ptr) {
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
CRASH_COND(p_ptr == nullptr);
|
CRASH_COND(p_ptr == nullptr);
|
||||||
@ -1288,10 +1311,14 @@ GD_PINVOKE_EXPORT void godotsharp_object_to_string(Object *p_ptr, godot_string *
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// We need this to prevent the functions from being stripped.
|
// We need this to prevent the functions from being stripped.
|
||||||
void *godotsharp_pinvoke_funcs[181] = {
|
void *godotsharp_pinvoke_funcs[185] = {
|
||||||
(void *)godotsharp_method_bind_get_method,
|
(void *)godotsharp_method_bind_get_method,
|
||||||
(void *)godotsharp_get_class_constructor,
|
(void *)godotsharp_get_class_constructor,
|
||||||
(void *)godotsharp_engine_get_singleton,
|
(void *)godotsharp_engine_get_singleton,
|
||||||
|
(void *)godotsharp_stack_info_vector_resize,
|
||||||
|
(void *)godotsharp_stack_info_vector_destroy,
|
||||||
|
(void *)godotsharp_internal_script_debugger_send_error,
|
||||||
|
(void *)godotsharp_internal_script_debugger_is_active,
|
||||||
(void *)godotsharp_internal_object_get_associated_gchandle,
|
(void *)godotsharp_internal_object_get_associated_gchandle,
|
||||||
(void *)godotsharp_internal_object_disposed,
|
(void *)godotsharp_internal_object_disposed,
|
||||||
(void *)godotsharp_internal_refcounted_disposed,
|
(void *)godotsharp_internal_refcounted_disposed,
|
||||||
|
@ -360,13 +360,15 @@ static bool _on_core_api_assembly_loaded() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
GDMonoCache::managed_callbacks.Dispatcher_InitializeDefaultGodotTaskScheduler();
|
bool debug;
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
// Install the trace listener now before the project assembly is loaded
|
debug = true;
|
||||||
GDMonoCache::managed_callbacks.DebuggingUtils_InstallTraceListener();
|
#else
|
||||||
|
debug = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
GDMonoCache::managed_callbacks.GD_OnCoreApiAssemblyLoaded(debug);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,26 +536,6 @@ Error GDMono::reload_scripts_domain() {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#warning TODO Reimplement in C#
|
|
||||||
#if 0
|
|
||||||
void GDMono::unhandled_exception_hook(MonoObject *p_exc, void *) {
|
|
||||||
// This method will be called by the runtime when a thrown exception is not handled.
|
|
||||||
// It won't be called when we manually treat a thrown exception as unhandled.
|
|
||||||
// We assume the exception was already printed before calling this hook.
|
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
|
||||||
GDMonoUtils::debug_send_unhandled_exception_error((MonoException *)p_exc);
|
|
||||||
if (EngineDebugger::is_active()) {
|
|
||||||
EngineDebugger::get_singleton()->poll_events(false);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
exit(mono_environment_exitcode_get());
|
|
||||||
|
|
||||||
GD_UNREACHABLE();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
GDMono::GDMono() {
|
GDMono::GDMono() {
|
||||||
singleton = this;
|
singleton = this;
|
||||||
|
|
||||||
|
@ -38,8 +38,14 @@ ManagedCallbacks managed_callbacks;
|
|||||||
bool godot_api_cache_updated = false;
|
bool godot_api_cache_updated = false;
|
||||||
|
|
||||||
void update_godot_api_cache(const ManagedCallbacks &p_managed_callbacks) {
|
void update_godot_api_cache(const ManagedCallbacks &p_managed_callbacks) {
|
||||||
#define CHECK_CALLBACK_NOT_NULL_IMPL(m_var, m_class, m_method) ERR_FAIL_COND_MSG(m_var == nullptr, \
|
int checked_count = 0;
|
||||||
"Mono Cache: Managed callback for '" #m_class "_" #m_method "' is null.")
|
|
||||||
|
#define CHECK_CALLBACK_NOT_NULL_IMPL(m_var, m_class, m_method) \
|
||||||
|
{ \
|
||||||
|
ERR_FAIL_COND_MSG(m_var == nullptr, \
|
||||||
|
"Mono Cache: Managed callback for '" #m_class "_" #m_method "' is null."); \
|
||||||
|
checked_count += 1; \
|
||||||
|
}
|
||||||
|
|
||||||
#define CHECK_CALLBACK_NOT_NULL(m_class, m_method) CHECK_CALLBACK_NOT_NULL_IMPL(p_managed_callbacks.m_class##_##m_method, m_class, m_method)
|
#define CHECK_CALLBACK_NOT_NULL(m_class, m_method) CHECK_CALLBACK_NOT_NULL_IMPL(p_managed_callbacks.m_class##_##m_method, m_class, m_method)
|
||||||
|
|
||||||
@ -56,9 +62,12 @@ void update_godot_api_cache(const ManagedCallbacks &p_managed_callbacks) {
|
|||||||
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, HasScriptSignal);
|
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, HasScriptSignal);
|
||||||
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, ScriptIsOrInherits);
|
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, ScriptIsOrInherits);
|
||||||
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, AddScriptBridge);
|
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, AddScriptBridge);
|
||||||
|
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, GetOrCreateScriptBridgeForPath);
|
||||||
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, RemoveScriptBridge);
|
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, RemoveScriptBridge);
|
||||||
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, UpdateScriptClassInfo);
|
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, UpdateScriptClassInfo);
|
||||||
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, SwapGCHandleForType);
|
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, SwapGCHandleForType);
|
||||||
|
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, GetPropertyInfoList);
|
||||||
|
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, GetPropertyDefaultValues);
|
||||||
CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, Call);
|
CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, Call);
|
||||||
CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, Set);
|
CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, Set);
|
||||||
CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, Get);
|
CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, Get);
|
||||||
@ -66,12 +75,18 @@ void update_godot_api_cache(const ManagedCallbacks &p_managed_callbacks) {
|
|||||||
CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, CallToString);
|
CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, CallToString);
|
||||||
CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, HasMethodUnknownParams);
|
CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, HasMethodUnknownParams);
|
||||||
CHECK_CALLBACK_NOT_NULL(GCHandleBridge, FreeGCHandle);
|
CHECK_CALLBACK_NOT_NULL(GCHandleBridge, FreeGCHandle);
|
||||||
CHECK_CALLBACK_NOT_NULL(DebuggingUtils, InstallTraceListener);
|
CHECK_CALLBACK_NOT_NULL(DebuggingUtils, GetCurrentStackInfo);
|
||||||
CHECK_CALLBACK_NOT_NULL(Dispatcher, InitializeDefaultGodotTaskScheduler);
|
|
||||||
CHECK_CALLBACK_NOT_NULL(DisposablesTracker, OnGodotShuttingDown);
|
CHECK_CALLBACK_NOT_NULL(DisposablesTracker, OnGodotShuttingDown);
|
||||||
|
CHECK_CALLBACK_NOT_NULL(GD, OnCoreApiAssemblyLoaded);
|
||||||
|
|
||||||
managed_callbacks = p_managed_callbacks;
|
managed_callbacks = p_managed_callbacks;
|
||||||
|
|
||||||
|
// It's easy to forget to add new callbacks here, so this should help
|
||||||
|
if (checked_count * sizeof(void *) != sizeof(ManagedCallbacks)) {
|
||||||
|
int missing_count = (sizeof(ManagedCallbacks) / sizeof(void *)) - checked_count;
|
||||||
|
WARN_PRINT("The presence of " + itos(missing_count) + " callback(s) was not validated");
|
||||||
|
}
|
||||||
|
|
||||||
godot_api_cache_updated = true;
|
godot_api_cache_updated = true;
|
||||||
}
|
}
|
||||||
} // namespace GDMonoCache
|
} // namespace GDMonoCache
|
||||||
|
@ -97,9 +97,9 @@ struct ManagedCallbacks {
|
|||||||
using FuncCSharpInstanceBridge_CallToString = void(GD_CLR_STDCALL *)(GCHandleIntPtr, String *, bool *);
|
using FuncCSharpInstanceBridge_CallToString = void(GD_CLR_STDCALL *)(GCHandleIntPtr, String *, bool *);
|
||||||
using FuncCSharpInstanceBridge_HasMethodUnknownParams = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *);
|
using FuncCSharpInstanceBridge_HasMethodUnknownParams = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *);
|
||||||
using FuncGCHandleBridge_FreeGCHandle = void(GD_CLR_STDCALL *)(GCHandleIntPtr);
|
using FuncGCHandleBridge_FreeGCHandle = void(GD_CLR_STDCALL *)(GCHandleIntPtr);
|
||||||
using FuncDebuggingUtils_InstallTraceListener = void(GD_CLR_STDCALL *)();
|
using FuncDebuggingUtils_GetCurrentStackInfo = void(GD_CLR_STDCALL *)(Vector<ScriptLanguage::StackInfo> *);
|
||||||
using FuncDispatcher_InitializeDefaultGodotTaskScheduler = void(GD_CLR_STDCALL *)();
|
|
||||||
using FuncDisposablesTracker_OnGodotShuttingDown = void(GD_CLR_STDCALL *)();
|
using FuncDisposablesTracker_OnGodotShuttingDown = void(GD_CLR_STDCALL *)();
|
||||||
|
using FuncGD_OnCoreApiAssemblyLoaded = void(GD_CLR_STDCALL *)(bool);
|
||||||
|
|
||||||
FuncSignalAwaiter_SignalCallback SignalAwaiter_SignalCallback;
|
FuncSignalAwaiter_SignalCallback SignalAwaiter_SignalCallback;
|
||||||
FuncDelegateUtils_InvokeWithVariantArgs DelegateUtils_InvokeWithVariantArgs;
|
FuncDelegateUtils_InvokeWithVariantArgs DelegateUtils_InvokeWithVariantArgs;
|
||||||
@ -127,9 +127,9 @@ struct ManagedCallbacks {
|
|||||||
FuncCSharpInstanceBridge_CallToString CSharpInstanceBridge_CallToString;
|
FuncCSharpInstanceBridge_CallToString CSharpInstanceBridge_CallToString;
|
||||||
FuncCSharpInstanceBridge_HasMethodUnknownParams CSharpInstanceBridge_HasMethodUnknownParams;
|
FuncCSharpInstanceBridge_HasMethodUnknownParams CSharpInstanceBridge_HasMethodUnknownParams;
|
||||||
FuncGCHandleBridge_FreeGCHandle GCHandleBridge_FreeGCHandle;
|
FuncGCHandleBridge_FreeGCHandle GCHandleBridge_FreeGCHandle;
|
||||||
FuncDebuggingUtils_InstallTraceListener DebuggingUtils_InstallTraceListener;
|
FuncDebuggingUtils_GetCurrentStackInfo DebuggingUtils_GetCurrentStackInfo;
|
||||||
FuncDispatcher_InitializeDefaultGodotTaskScheduler Dispatcher_InitializeDefaultGodotTaskScheduler;
|
|
||||||
FuncDisposablesTracker_OnGodotShuttingDown DisposablesTracker_OnGodotShuttingDown;
|
FuncDisposablesTracker_OnGodotShuttingDown DisposablesTracker_OnGodotShuttingDown;
|
||||||
|
FuncGD_OnCoreApiAssemblyLoaded GD_OnCoreApiAssemblyLoaded;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern ManagedCallbacks managed_callbacks;
|
extern ManagedCallbacks managed_callbacks;
|
||||||
|
Loading…
Reference in New Issue
Block a user