mirror of
https://github.com/godotengine/godot
synced 2024-09-05 20:19:49 +00:00
C#: Ensure we only create one CSharpScript per type
Previously, for each scripts class instance that was created from code rather than by the engine, we were constructing, configuring and assigning a new CSharpScript. This has changed now and we make sure there's only one CSharpScript associated to each type.
This commit is contained in:
parent
92503ae8db
commit
67db89988d
|
@ -104,7 +104,7 @@ Error CSharpLanguage::execute_file(const String &p_path) {
|
|||
return OK;
|
||||
}
|
||||
|
||||
extern void *godotsharp_pinvoke_funcs[179];
|
||||
extern void *godotsharp_pinvoke_funcs[181];
|
||||
[[maybe_unused]] volatile void **do_not_strip_godotsharp_pinvoke_funcs;
|
||||
#ifdef TOOLS_ENABLED
|
||||
extern void *godotsharp_editor_pinvoke_funcs[30];
|
||||
|
@ -793,6 +793,20 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
|
|||
// (while hot-reload is not yet implemented)
|
||||
gdmono->initialize_load_assemblies();
|
||||
|
||||
{
|
||||
MutexLock lock(script_instances_mutex);
|
||||
|
||||
for (SelfList<CSharpScript> *elem = script_list.first(); elem; elem = elem->next()) {
|
||||
Ref<CSharpScript> script(elem->self());
|
||||
|
||||
script->exports_invalidated = true;
|
||||
|
||||
if (!script->get_path().is_empty()) {
|
||||
script->reload(p_soft_reload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// There is no soft reloading with Mono. It's always hard reloading.
|
||||
|
||||
|
@ -1010,7 +1024,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
|
|||
|
||||
GDMonoClass *native = GDMonoUtils::get_class_native_base(script_class);
|
||||
|
||||
CSharpScript::initialize_for_managed_type(script, script_class, native);
|
||||
CSharpScript::reload_registered_script(script, script_class, native);
|
||||
}
|
||||
|
||||
StringName native_name = NATIVE_GDMONOCLASS_NAME(script->native);
|
||||
|
@ -1563,9 +1577,13 @@ void CSharpLanguage::tie_native_managed_to_unmanaged(GCHandleIntPtr p_gchandle_i
|
|||
CSharpLanguage::set_instance_binding(p_unmanaged, data);
|
||||
}
|
||||
|
||||
void CSharpLanguage::tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, CSharpScript *p_script, bool p_ref_counted) {
|
||||
void CSharpLanguage::tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, Ref<CSharpScript> *p_script, bool p_ref_counted) {
|
||||
// This method should not fail
|
||||
|
||||
Ref<CSharpScript> script = *p_script;
|
||||
// We take care of destructing this reference here, so the managed code won't need to do another P/Invoke call
|
||||
p_script->~Ref();
|
||||
|
||||
CRASH_COND(!p_unmanaged);
|
||||
|
||||
// All mono objects created from the managed world (e.g.: 'new Player()')
|
||||
|
@ -1578,12 +1596,8 @@ void CSharpLanguage::tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_int
|
|||
MonoGCHandleData gchandle = MonoGCHandleData(p_gchandle_intptr,
|
||||
p_ref_counted ? gdmono::GCHandleType::WEAK_HANDLE : gdmono::GCHandleType::STRONG_HANDLE);
|
||||
|
||||
Ref<CSharpScript> script = p_script;
|
||||
|
||||
CRASH_COND(script.is_null());
|
||||
|
||||
CSharpScript::initialize_for_managed_type(script);
|
||||
|
||||
CSharpInstance *csharp_instance = CSharpInstance::create_for_managed_type(p_unmanaged, script.ptr(), gchandle);
|
||||
|
||||
p_unmanaged->set_script_and_instance(script, csharp_instance);
|
||||
|
@ -2345,12 +2359,17 @@ void CSharpScript::_bind_methods() {
|
|||
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &CSharpScript::_new, MethodInfo("new"));
|
||||
}
|
||||
|
||||
void CSharpScript::initialize_for_managed_type(Ref<CSharpScript> p_script) {
|
||||
void CSharpScript::reload_registered_script(Ref<CSharpScript> p_script) {
|
||||
// IMPORTANT:
|
||||
// This method must be called only after the CSharpScript and its associated type
|
||||
// have been added to the script bridge map in the ScriptManagerBridge C# class.
|
||||
// Other than that, it's the same as `CSharpScript::reload`.
|
||||
|
||||
// This method should not fail, only assertions allowed
|
||||
// This method should not fail, only assertions allowed.
|
||||
|
||||
// Unlike `reload`, we print an error rather than silently returning,
|
||||
// as we can assert this won't be called a second time until invalidated.
|
||||
ERR_FAIL_COND(!p_script->reload_invalidated);
|
||||
|
||||
p_script->valid = true;
|
||||
p_script->reload_invalidated = false;
|
||||
|
@ -2607,9 +2626,6 @@ Error CSharpScript::reload(bool p_keep_state) {
|
|||
|
||||
String script_path = get_path();
|
||||
|
||||
// In case it was already added by a previous reload
|
||||
GDMonoCache::managed_callbacks.ScriptManagerBridge_RemoveScriptBridge(this);
|
||||
|
||||
valid = GDMonoCache::managed_callbacks.ScriptManagerBridge_AddScriptBridge(this, &script_path);
|
||||
|
||||
if (valid) {
|
||||
|
@ -2817,9 +2833,13 @@ Ref<Resource> ResourceFormatLoaderCSharpScript::load(const String &p_path, const
|
|||
|
||||
// TODO ignore anything inside bin/ and obj/ in tools builds?
|
||||
|
||||
CSharpScript *script = memnew(CSharpScript);
|
||||
Ref<CSharpScript> script;
|
||||
|
||||
Ref<CSharpScript> scriptres(script);
|
||||
if (GDMonoCache::godot_api_cache_updated) {
|
||||
GDMonoCache::managed_callbacks.ScriptManagerBridge_GetOrCreateScriptBridgeForPath(&p_path, &script);
|
||||
} else {
|
||||
script = Ref<CSharpScript>(memnew(CSharpScript));
|
||||
}
|
||||
|
||||
#if defined(DEBUG_ENABLED) || defined(TOOLS_ENABLED)
|
||||
Error err = script->load_source_code(p_path);
|
||||
|
@ -2834,7 +2854,7 @@ Ref<Resource> ResourceFormatLoaderCSharpScript::load(const String &p_path, const
|
|||
*r_error = OK;
|
||||
}
|
||||
|
||||
return scriptres;
|
||||
return script;
|
||||
}
|
||||
|
||||
void ResourceFormatLoaderCSharpScript::get_recognized_extensions(List<String> *p_extensions) const {
|
||||
|
|
|
@ -134,7 +134,6 @@ private:
|
|||
|
||||
// Do not use unless you know what you are doing
|
||||
static void update_script_class_info(Ref<CSharpScript> p_script);
|
||||
static void initialize_for_managed_type(Ref<CSharpScript> p_script);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
@ -144,6 +143,8 @@ protected:
|
|||
void _get_property_list(List<PropertyInfo> *p_properties) const;
|
||||
|
||||
public:
|
||||
static void reload_registered_script(Ref<CSharpScript> p_script);
|
||||
|
||||
bool can_instantiate() const override;
|
||||
StringName get_instance_base_type() const override;
|
||||
ScriptInstance *instance_create(Object *p_this) override;
|
||||
|
@ -460,7 +461,7 @@ public:
|
|||
bool setup_csharp_script_binding(CSharpScriptBinding &r_script_binding, Object *p_object);
|
||||
|
||||
static void tie_native_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, const StringName *p_native_name, bool p_ref_counted);
|
||||
static void tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, 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);
|
||||
|
||||
#warning TODO
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace Godot.Bridge
|
|||
public delegate* unmanaged<IntPtr, godot_string*, godot_bool> ScriptManagerBridge_HasScriptSignal;
|
||||
public delegate* unmanaged<IntPtr, IntPtr, godot_bool> ScriptManagerBridge_ScriptIsOrInherits;
|
||||
public delegate* unmanaged<IntPtr, godot_string*, godot_bool> ScriptManagerBridge_AddScriptBridge;
|
||||
public delegate* unmanaged<godot_string*, godot_ref*, void> ScriptManagerBridge_GetOrCreateScriptBridgeForPath;
|
||||
public delegate* unmanaged<IntPtr, void> ScriptManagerBridge_RemoveScriptBridge;
|
||||
public delegate* unmanaged<IntPtr, godot_bool*, godot_dictionary*, void> ScriptManagerBridge_UpdateScriptClassInfo;
|
||||
public delegate* unmanaged<IntPtr, IntPtr*, godot_bool, godot_bool> ScriptManagerBridge_SwapGCHandleForType;
|
||||
|
@ -56,6 +57,7 @@ namespace Godot.Bridge
|
|||
ScriptManagerBridge_HasScriptSignal = &ScriptManagerBridge.HasScriptSignal,
|
||||
ScriptManagerBridge_ScriptIsOrInherits = &ScriptManagerBridge.ScriptIsOrInherits,
|
||||
ScriptManagerBridge_AddScriptBridge = &ScriptManagerBridge.AddScriptBridge,
|
||||
ScriptManagerBridge_GetOrCreateScriptBridgeForPath = &ScriptManagerBridge.GetOrCreateScriptBridgeForPath,
|
||||
ScriptManagerBridge_RemoveScriptBridge = &ScriptManagerBridge.RemoveScriptBridge,
|
||||
ScriptManagerBridge_UpdateScriptClassInfo = &ScriptManagerBridge.UpdateScriptClassInfo,
|
||||
ScriptManagerBridge_SwapGCHandleForType = &ScriptManagerBridge.SwapGCHandleForType,
|
||||
|
|
|
@ -12,22 +12,11 @@ namespace Godot.Bridge
|
|||
{
|
||||
public static class ScriptManagerBridge
|
||||
{
|
||||
private static System.Collections.Generic.Dictionary<string, ScriptLookupInfo> _scriptLookupMap = new();
|
||||
private static System.Collections.Generic.Dictionary<IntPtr, Type> _scriptBridgeMap = new();
|
||||
private static System.Collections.Generic.Dictionary<string, Type> _pathScriptMap = new();
|
||||
|
||||
private struct ScriptLookupInfo
|
||||
{
|
||||
public string ClassNamespace { get; private set; }
|
||||
public string ClassName { get; private set; }
|
||||
public Type ScriptType { get; private set; }
|
||||
|
||||
public ScriptLookupInfo(string classNamespace, string className, Type scriptType)
|
||||
{
|
||||
ClassNamespace = classNamespace;
|
||||
ClassName = className;
|
||||
ScriptType = scriptType;
|
||||
}
|
||||
};
|
||||
private static readonly object ScriptBridgeLock = new();
|
||||
private static System.Collections.Generic.Dictionary<IntPtr, Type> _scriptTypeMap = new();
|
||||
private static System.Collections.Generic.Dictionary<Type, IntPtr> _typeScriptMap = new();
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void FrameCallback()
|
||||
|
@ -80,7 +69,7 @@ namespace Godot.Bridge
|
|||
try
|
||||
{
|
||||
// Performance is not critical here as this will be replaced with source generators.
|
||||
Type scriptType = _scriptBridgeMap[scriptPtr];
|
||||
Type scriptType = _scriptTypeMap[scriptPtr];
|
||||
var obj = (Object)FormatterServices.GetUninitializedObject(scriptType);
|
||||
|
||||
var ctor = scriptType
|
||||
|
@ -133,7 +122,7 @@ namespace Godot.Bridge
|
|||
try
|
||||
{
|
||||
// Performance is not critical here as this will be replaced with source generators.
|
||||
if (!_scriptBridgeMap.TryGetValue(scriptPtr, out var scriptType))
|
||||
if (!_scriptTypeMap.TryGetValue(scriptPtr, out var scriptType))
|
||||
{
|
||||
*outRes = default;
|
||||
return;
|
||||
|
@ -225,7 +214,7 @@ namespace Godot.Bridge
|
|||
if (scriptPathAttr == null)
|
||||
return;
|
||||
|
||||
_scriptLookupMap[scriptPathAttr.Path] = new ScriptLookupInfo(type.Namespace, type.Name, type);
|
||||
_pathScriptMap[scriptPathAttr.Path] = type;
|
||||
}
|
||||
|
||||
var assemblyHasScriptsAttr = assembly.GetCustomAttributes(inherit: false)
|
||||
|
@ -304,7 +293,7 @@ namespace Godot.Bridge
|
|||
// Performance is not critical here as this will be replaced with source generators.
|
||||
using var signals = new Dictionary();
|
||||
|
||||
Type top = _scriptBridgeMap[scriptPtr];
|
||||
Type top = _scriptTypeMap[scriptPtr];
|
||||
Type native = Object.InternalGetClassNativeBase(top);
|
||||
|
||||
while (top != null && top != native)
|
||||
|
@ -400,7 +389,7 @@ namespace Godot.Bridge
|
|||
|
||||
string signalNameStr = Marshaling.ConvertStringToManaged(*signalName);
|
||||
|
||||
Type top = _scriptBridgeMap[scriptPtr];
|
||||
Type top = _scriptTypeMap[scriptPtr];
|
||||
Type native = Object.InternalGetClassNativeBase(top);
|
||||
|
||||
while (top != null && top != native)
|
||||
|
@ -446,10 +435,10 @@ namespace Godot.Bridge
|
|||
{
|
||||
try
|
||||
{
|
||||
if (!_scriptBridgeMap.TryGetValue(scriptPtr, out var scriptType))
|
||||
if (!_scriptTypeMap.TryGetValue(scriptPtr, out var scriptType))
|
||||
return false.ToGodotBool();
|
||||
|
||||
if (!_scriptBridgeMap.TryGetValue(scriptPtrMaybeBase, out var maybeBaseType))
|
||||
if (!_scriptTypeMap.TryGetValue(scriptPtrMaybeBase, out var maybeBaseType))
|
||||
return false.ToGodotBool();
|
||||
|
||||
return (scriptType == maybeBaseType || maybeBaseType.IsAssignableFrom(scriptType)).ToGodotBool();
|
||||
|
@ -466,12 +455,19 @@ namespace Godot.Bridge
|
|||
{
|
||||
try
|
||||
{
|
||||
string scriptPathStr = Marshaling.ConvertStringToManaged(*scriptPath);
|
||||
lock (ScriptBridgeLock)
|
||||
{
|
||||
if (!_scriptTypeMap.ContainsKey(scriptPtr))
|
||||
{
|
||||
string scriptPathStr = Marshaling.ConvertStringToManaged(*scriptPath);
|
||||
|
||||
if (!_scriptLookupMap.TryGetValue(scriptPathStr, out var lookupInfo))
|
||||
return false.ToGodotBool();
|
||||
if (!_pathScriptMap.TryGetValue(scriptPathStr, out Type scriptType))
|
||||
return false.ToGodotBool();
|
||||
|
||||
_scriptBridgeMap.Add(scriptPtr, lookupInfo.ScriptType);
|
||||
_scriptTypeMap.Add(scriptPtr, scriptType);
|
||||
_typeScriptMap.Add(scriptType, scriptPtr);
|
||||
}
|
||||
}
|
||||
|
||||
return true.ToGodotBool();
|
||||
}
|
||||
|
@ -482,15 +478,49 @@ namespace Godot.Bridge
|
|||
}
|
||||
}
|
||||
|
||||
internal static void AddScriptBridgeWithType(IntPtr scriptPtr, Type scriptType)
|
||||
=> _scriptBridgeMap.Add(scriptPtr, scriptType);
|
||||
[UnmanagedCallersOnly]
|
||||
internal static unsafe void GetOrCreateScriptBridgeForPath(godot_string* scriptPath, godot_ref* outScript)
|
||||
{
|
||||
string scriptPathStr = Marshaling.ConvertStringToManaged(*scriptPath);
|
||||
|
||||
if (!_pathScriptMap.TryGetValue(scriptPathStr, out Type scriptType))
|
||||
{
|
||||
NativeFuncs.godotsharp_internal_new_csharp_script(outScript);
|
||||
return;
|
||||
}
|
||||
|
||||
GetOrCreateScriptBridgeForType(scriptType, outScript);
|
||||
}
|
||||
|
||||
internal static unsafe void GetOrCreateScriptBridgeForType(Type scriptType, godot_ref* outScript)
|
||||
{
|
||||
lock (ScriptBridgeLock)
|
||||
{
|
||||
if (_typeScriptMap.TryGetValue(scriptType, out IntPtr scriptPtr))
|
||||
{
|
||||
NativeFuncs.godotsharp_ref_new_from_ref_counted_ptr(out *outScript, scriptPtr);
|
||||
return;
|
||||
}
|
||||
|
||||
NativeFuncs.godotsharp_internal_new_csharp_script(outScript);
|
||||
scriptPtr = outScript->Reference;
|
||||
|
||||
_scriptTypeMap.Add(scriptPtr, scriptType);
|
||||
_typeScriptMap.Add(scriptType, scriptPtr);
|
||||
|
||||
NativeFuncs.godotsharp_internal_reload_registered_script(scriptPtr);
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void RemoveScriptBridge(IntPtr scriptPtr)
|
||||
{
|
||||
try
|
||||
{
|
||||
_scriptBridgeMap.Remove(scriptPtr);
|
||||
lock (ScriptBridgeLock)
|
||||
{
|
||||
_ = _scriptTypeMap.Remove(scriptPtr);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -505,7 +535,7 @@ namespace Godot.Bridge
|
|||
try
|
||||
{
|
||||
// Performance is not critical here as this will be replaced with source generators.
|
||||
var scriptType = _scriptBridgeMap[scriptPtr];
|
||||
var scriptType = _scriptTypeMap[scriptPtr];
|
||||
|
||||
*outTool = scriptType.GetCustomAttributes(inherit: false)
|
||||
.OfType<ToolAttribute>()
|
||||
|
@ -630,7 +660,7 @@ namespace Godot.Bridge
|
|||
{
|
||||
try
|
||||
{
|
||||
Type scriptType = _scriptBridgeMap[scriptPtr];
|
||||
Type scriptType = _scriptTypeMap[scriptPtr];
|
||||
GetPropertyInfoListForType(scriptType, scriptPtr, addPropInfoFunc);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -752,7 +782,7 @@ namespace Godot.Bridge
|
|||
{
|
||||
try
|
||||
{
|
||||
Type top = _scriptBridgeMap[scriptPtr];
|
||||
Type top = _scriptTypeMap[scriptPtr];
|
||||
Type native = Object.InternalGetClassNativeBase(top);
|
||||
|
||||
while (top != null && top != native)
|
||||
|
|
|
@ -60,13 +60,17 @@ namespace Godot.NativeInterop
|
|||
}
|
||||
else
|
||||
{
|
||||
IntPtr scriptPtr = NativeFuncs.godotsharp_internal_new_csharp_script();
|
||||
unsafe
|
||||
{
|
||||
// We don't dispose `script` ourselves here.
|
||||
// `tie_user_managed_to_unmanaged` does it for us to avoid another P/Invoke call.
|
||||
godot_ref script;
|
||||
ScriptManagerBridge.GetOrCreateScriptBridgeForType(type, &script);
|
||||
|
||||
ScriptManagerBridge.AddScriptBridgeWithType(scriptPtr, type);
|
||||
|
||||
// IMPORTANT: This must be called after AddScriptWithTypeBridge
|
||||
NativeFuncs.godotsharp_internal_tie_user_managed_to_unmanaged(
|
||||
GCHandle.ToIntPtr(gcHandle), unmanaged, scriptPtr, refCounted.ToGodotBool());
|
||||
// IMPORTANT: This must be called after GetOrCreateScriptBridgeForType
|
||||
NativeFuncs.godotsharp_internal_tie_user_managed_to_unmanaged(
|
||||
GCHandle.ToIntPtr(gcHandle), unmanaged, &script, refCounted.ToGodotBool());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,8 @@ namespace Godot.NativeInterop
|
|||
internal static extern void godotsharp_internal_object_disposed(IntPtr ptr, IntPtr gcHandleToFree);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
internal static extern void godotsharp_internal_refcounted_disposed(IntPtr ptr, IntPtr gcHandleToFree, godot_bool isFinalizer);
|
||||
internal static extern void godotsharp_internal_refcounted_disposed(IntPtr ptr, IntPtr gcHandleToFree,
|
||||
godot_bool isFinalizer);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
internal static extern void godotsharp_internal_object_connect_event_signal(IntPtr obj,
|
||||
|
@ -59,7 +60,7 @@ namespace Godot.NativeInterop
|
|||
|
||||
[DllImport(GodotDllName)]
|
||||
internal static extern void godotsharp_internal_tie_user_managed_to_unmanaged(IntPtr gcHandleIntPtr,
|
||||
IntPtr unmanaged, IntPtr scriptPtr, godot_bool refCounted);
|
||||
IntPtr unmanaged, godot_ref* scriptPtr, godot_bool refCounted);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
internal static extern void godotsharp_internal_tie_managed_to_unmanaged_with_pre_setup(
|
||||
|
@ -77,7 +78,10 @@ namespace Godot.NativeInterop
|
|||
IntPtr oldGCHandlePtr);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
internal static extern IntPtr godotsharp_internal_new_csharp_script();
|
||||
internal static extern void godotsharp_internal_new_csharp_script(godot_ref* r_script);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
internal static extern void godotsharp_internal_reload_registered_script(IntPtr scriptPtr);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
internal static extern void godotsharp_array_filter_godot_objects_by_native(in godot_string_name p_native_name,
|
||||
|
@ -87,6 +91,9 @@ namespace Godot.NativeInterop
|
|||
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_new_from_ref_counted_ptr(out godot_ref r_dest, IntPtr p_ref_counted_ptr);
|
||||
|
||||
[DllImport(GodotDllName)]
|
||||
public static extern void godotsharp_ref_destroy(ref godot_ref p_instance);
|
||||
|
||||
|
|
|
@ -285,7 +285,7 @@ GD_PINVOKE_EXPORT void godotsharp_internal_tie_native_managed_to_unmanaged(GCHan
|
|||
CSharpLanguage::tie_native_managed_to_unmanaged(p_gchandle_intptr, p_unmanaged, p_native_name, p_ref_counted);
|
||||
}
|
||||
|
||||
GD_PINVOKE_EXPORT void godotsharp_internal_tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, CSharpScript *p_script, bool p_ref_counted) {
|
||||
GD_PINVOKE_EXPORT void godotsharp_internal_tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, Ref<CSharpScript> *p_script, bool p_ref_counted) {
|
||||
CSharpLanguage::tie_user_managed_to_unmanaged(p_gchandle_intptr, p_unmanaged, p_script, p_ref_counted);
|
||||
}
|
||||
|
||||
|
@ -293,10 +293,13 @@ GD_PINVOKE_EXPORT void godotsharp_internal_tie_managed_to_unmanaged_with_pre_set
|
|||
CSharpLanguage::tie_managed_to_unmanaged_with_pre_setup(p_gchandle_intptr, p_unmanaged);
|
||||
}
|
||||
|
||||
GD_PINVOKE_EXPORT CSharpScript *godotsharp_internal_new_csharp_script() {
|
||||
CSharpScript *script = memnew(CSharpScript);
|
||||
CRASH_COND(!script);
|
||||
return script;
|
||||
GD_PINVOKE_EXPORT void godotsharp_internal_new_csharp_script(Ref<CSharpScript> *r_dest) {
|
||||
memnew_placement(r_dest, Ref<CSharpScript>(memnew(CSharpScript)));
|
||||
}
|
||||
|
||||
GD_PINVOKE_EXPORT void godotsharp_internal_reload_registered_script(CSharpScript *p_script) {
|
||||
CRASH_COND(!p_script);
|
||||
CSharpScript::reload_registered_script(Ref<CSharpScript>(p_script));
|
||||
}
|
||||
|
||||
GD_PINVOKE_EXPORT void godotsharp_array_filter_godot_objects_by_native(StringName *p_native_name, const Array *p_input, Array *r_output) {
|
||||
|
@ -321,6 +324,10 @@ GD_PINVOKE_EXPORT void godotsharp_array_filter_godot_objects_by_non_native(const
|
|||
}
|
||||
}
|
||||
|
||||
GD_PINVOKE_EXPORT void godotsharp_ref_new_from_ref_counted_ptr(Ref<RefCounted> *r_dest, RefCounted *p_ref_counted_ptr) {
|
||||
memnew_placement(r_dest, Ref<RefCounted>(p_ref_counted_ptr));
|
||||
}
|
||||
|
||||
GD_PINVOKE_EXPORT void godotsharp_ref_destroy(Ref<RefCounted> *p_instance) {
|
||||
p_instance->~Ref();
|
||||
}
|
||||
|
@ -1281,7 +1288,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[179] = {
|
||||
void *godotsharp_pinvoke_funcs[181] = {
|
||||
(void *)godotsharp_method_bind_get_method,
|
||||
(void *)godotsharp_get_class_constructor,
|
||||
(void *)godotsharp_engine_get_singleton,
|
||||
|
@ -1297,8 +1304,10 @@ void *godotsharp_pinvoke_funcs[179] = {
|
|||
(void *)godotsharp_internal_tie_user_managed_to_unmanaged,
|
||||
(void *)godotsharp_internal_tie_managed_to_unmanaged_with_pre_setup,
|
||||
(void *)godotsharp_internal_new_csharp_script,
|
||||
(void *)godotsharp_internal_reload_registered_script,
|
||||
(void *)godotsharp_array_filter_godot_objects_by_native,
|
||||
(void *)godotsharp_array_filter_godot_objects_by_non_native,
|
||||
(void *)godotsharp_ref_new_from_ref_counted_ptr,
|
||||
(void *)godotsharp_ref_destroy,
|
||||
(void *)godotsharp_string_name_new_from_string,
|
||||
(void *)godotsharp_node_path_new_from_string,
|
||||
|
|
|
@ -49,10 +49,9 @@
|
|||
#include <coreclr_delegates.h>
|
||||
#include <hostfxr.h>
|
||||
|
||||
#warning TODO mobile
|
||||
// TODO mobile
|
||||
#if 0
|
||||
#ifdef ANDROID_ENABLED
|
||||
#include "android_mono_config.h"
|
||||
#include "support/android_support.h"
|
||||
#elif defined(IOS_ENABLED)
|
||||
#include "support/ios_support.h"
|
||||
|
@ -61,75 +60,6 @@
|
|||
|
||||
GDMono *GDMono::singleton = nullptr;
|
||||
|
||||
namespace {
|
||||
|
||||
#warning "TODO .NET debugging and profiling. What's needed?"
|
||||
#if 0
|
||||
void gd_mono_profiler_init() {
|
||||
String profiler_args = GLOBAL_DEF("mono/profiler/args", "log:calls,alloc,sample,output=output.mlpd");
|
||||
bool profiler_enabled = GLOBAL_DEF("mono/profiler/enabled", false);
|
||||
if (profiler_enabled) {
|
||||
mono_profiler_load(profiler_args.utf8());
|
||||
return;
|
||||
}
|
||||
|
||||
const String env_var_name = "MONO_ENV_OPTIONS";
|
||||
if (OS::get_singleton()->has_environment(env_var_name)) {
|
||||
const String mono_env_ops = OS::get_singleton()->get_environment(env_var_name);
|
||||
// Usually MONO_ENV_OPTIONS looks like: --profile=jb:prof=timeline,ctl=remote,host=127.0.0.1:55467
|
||||
const String prefix = "--profile=";
|
||||
if (mono_env_ops.begins_with(prefix)) {
|
||||
const String ops = mono_env_ops.substr(prefix.length(), mono_env_ops.length());
|
||||
mono_profiler_load(ops.utf8());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gd_mono_debug_init() {
|
||||
CharString da_args = OS::get_singleton()->get_environment("GODOT_MONO_DEBUGGER_AGENT").utf8();
|
||||
|
||||
if (da_args.length()) {
|
||||
OS::get_singleton()->set_environment("GODOT_MONO_DEBUGGER_AGENT", String());
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
int da_port = GLOBAL_DEF("mono/debugger_agent/port", 23685);
|
||||
bool da_suspend = GLOBAL_DEF("mono/debugger_agent/wait_for_debugger", false);
|
||||
int da_timeout = GLOBAL_DEF("mono/debugger_agent/wait_timeout", 3000);
|
||||
|
||||
if (Engine::get_singleton()->is_editor_hint() ||
|
||||
ProjectSettings::get_singleton()->get_resource_path().is_empty() ||
|
||||
Engine::get_singleton()->is_project_manager_hint()) {
|
||||
if (da_args.size() == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (da_args.length() == 0) {
|
||||
da_args = String("--debugger-agent=transport=dt_socket,address=127.0.0.1:" + itos(da_port) +
|
||||
",embedding=1,server=y,suspend=" + (da_suspend ? "y,timeout=" + itos(da_timeout) : "n"))
|
||||
.utf8();
|
||||
}
|
||||
#else
|
||||
if (da_args.length() == 0) {
|
||||
return; // Exported games don't use the project settings to setup the debugger agent
|
||||
}
|
||||
#endif
|
||||
|
||||
// Debugging enabled
|
||||
|
||||
mono_debug_init(MONO_DEBUG_FORMAT_MONO);
|
||||
|
||||
// --debugger-agent=help
|
||||
const char *options[] = {
|
||||
"--soft-breakpoints",
|
||||
da_args.get_data()
|
||||
};
|
||||
mono_jit_parse_options(2, (char **)options);
|
||||
}
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
hostfxr_initialize_for_dotnet_command_line_fn hostfxr_initialize_for_dotnet_command_line = nullptr;
|
||||
hostfxr_initialize_for_runtime_config_fn hostfxr_initialize_for_runtime_config = nullptr;
|
||||
|
|
|
@ -84,6 +84,7 @@ struct ManagedCallbacks {
|
|||
using FuncScriptManagerBridge_HasScriptSignal = bool(GD_CLR_STDCALL *)(const CSharpScript *, const String *);
|
||||
using FuncScriptManagerBridge_ScriptIsOrInherits = bool(GD_CLR_STDCALL *)(const CSharpScript *, const CSharpScript *);
|
||||
using FuncScriptManagerBridge_AddScriptBridge = bool(GD_CLR_STDCALL *)(const CSharpScript *, const String *);
|
||||
using FuncScriptManagerBridge_GetOrCreateScriptBridgeForPath = void(GD_CLR_STDCALL *)(const String *, Ref<CSharpScript> *);
|
||||
using FuncScriptManagerBridge_RemoveScriptBridge = void(GD_CLR_STDCALL *)(const CSharpScript *);
|
||||
using FuncScriptManagerBridge_UpdateScriptClassInfo = void(GD_CLR_STDCALL *)(const CSharpScript *, bool *, Dictionary *);
|
||||
using FuncScriptManagerBridge_SwapGCHandleForType = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, GCHandleIntPtr *, bool);
|
||||
|
@ -113,6 +114,7 @@ struct ManagedCallbacks {
|
|||
FuncScriptManagerBridge_HasScriptSignal ScriptManagerBridge_HasScriptSignal;
|
||||
FuncScriptManagerBridge_ScriptIsOrInherits ScriptManagerBridge_ScriptIsOrInherits;
|
||||
FuncScriptManagerBridge_AddScriptBridge ScriptManagerBridge_AddScriptBridge;
|
||||
FuncScriptManagerBridge_GetOrCreateScriptBridgeForPath ScriptManagerBridge_GetOrCreateScriptBridgeForPath;
|
||||
FuncScriptManagerBridge_RemoveScriptBridge ScriptManagerBridge_RemoveScriptBridge;
|
||||
FuncScriptManagerBridge_UpdateScriptClassInfo ScriptManagerBridge_UpdateScriptClassInfo;
|
||||
FuncScriptManagerBridge_SwapGCHandleForType ScriptManagerBridge_SwapGCHandleForType;
|
||||
|
|
Loading…
Reference in a new issue