C#: Add source generator for signals as events
Changed the signal declaration signal to: ``` // The following generates a MySignal event [Signal] public delegate void MySignalEventHandler(int param); ```
This commit is contained in:
parent
f033764ffe
commit
97713ff77a
@ -104,7 +104,7 @@ Error CSharpLanguage::execute_file(const String &p_path) {
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void *godotsharp_pinvoke_funcs[186];
|
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];
|
||||||
@ -1452,6 +1452,8 @@ void CSharpLanguage::tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_int
|
|||||||
CSharpInstance *csharp_instance = CSharpInstance::create_for_managed_type(p_unmanaged, script.ptr(), gchandle);
|
CSharpInstance *csharp_instance = CSharpInstance::create_for_managed_type(p_unmanaged, script.ptr(), gchandle);
|
||||||
|
|
||||||
p_unmanaged->set_script_and_instance(script, csharp_instance);
|
p_unmanaged->set_script_and_instance(script, csharp_instance);
|
||||||
|
|
||||||
|
csharp_instance->connect_event_signals();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSharpLanguage::tie_managed_to_unmanaged_with_pre_setup(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged) {
|
void CSharpLanguage::tie_managed_to_unmanaged_with_pre_setup(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged) {
|
||||||
@ -1480,6 +1482,8 @@ void CSharpLanguage::tie_managed_to_unmanaged_with_pre_setup(GCHandleIntPtr p_gc
|
|||||||
// instances is a set, so it's safe to insert multiple times (e.g.: from _internal_new_managed)
|
// instances is a set, so it's safe to insert multiple times (e.g.: from _internal_new_managed)
|
||||||
instance->script->instances.insert(instance->owner);
|
instance->script->instances.insert(instance->owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
instance->connect_event_signals();
|
||||||
}
|
}
|
||||||
|
|
||||||
CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpScript *p_script, const MonoGCHandleData &p_gchandle) {
|
CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpScript *p_script, const MonoGCHandleData &p_gchandle) {
|
||||||
@ -1774,13 +1778,22 @@ void CSharpInstance::mono_object_disposed_baseref(GCHandleIntPtr p_gchandle_to_f
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSharpInstance::connect_event_signal(const StringName &p_event_signal) {
|
void CSharpInstance::connect_event_signals() {
|
||||||
// TODO: Use pooling for ManagedCallable instances.
|
CSharpScript *top = script.ptr();
|
||||||
EventSignalCallable *event_signal_callable = memnew(EventSignalCallable(owner, p_event_signal));
|
while (top != nullptr) {
|
||||||
|
for (CSharpScript::EventSignalInfo &signal : top->get_script_event_signals()) {
|
||||||
|
String signal_name = signal.name;
|
||||||
|
|
||||||
Callable callable(event_signal_callable);
|
// TODO: Use pooling for ManagedCallable instances.
|
||||||
connected_event_signals.push_back(callable);
|
EventSignalCallable *event_signal_callable = memnew(EventSignalCallable(owner, signal_name));
|
||||||
owner->connect(p_event_signal, callable);
|
|
||||||
|
Callable callable(event_signal_callable);
|
||||||
|
connected_event_signals.push_back(callable);
|
||||||
|
owner->connect(signal_name, callable);
|
||||||
|
}
|
||||||
|
|
||||||
|
top = top->base_script.ptr();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSharpInstance::disconnect_event_signals() {
|
void CSharpInstance::disconnect_event_signals() {
|
||||||
@ -2169,20 +2182,56 @@ void CSharpScript::reload_registered_script(Ref<CSharpScript> p_script) {
|
|||||||
// Extract information about the script using the mono class.
|
// Extract information about the script using the mono class.
|
||||||
void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
|
void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
|
||||||
bool tool = false;
|
bool tool = false;
|
||||||
|
|
||||||
Dictionary rpc_functions_dict;
|
Dictionary rpc_functions_dict;
|
||||||
// Destructor won't be called from C#, and I don't want to include the GDNative header
|
// Destructor won't be called from C#, and I don't want to include the GDNative header
|
||||||
// only for this, so need to call the destructor manually before passing this to C#.
|
// only for this, so need to call the destructor manually before passing this to C#.
|
||||||
rpc_functions_dict.~Dictionary();
|
rpc_functions_dict.~Dictionary();
|
||||||
|
|
||||||
|
Dictionary signals_dict;
|
||||||
|
// Destructor won't be called from C#, and I don't want to include the GDNative header
|
||||||
|
// only for this, so need to call the destructor manually before passing this to C#.
|
||||||
|
signals_dict.~Dictionary();
|
||||||
|
|
||||||
Ref<CSharpScript> base_script;
|
Ref<CSharpScript> base_script;
|
||||||
GDMonoCache::managed_callbacks.ScriptManagerBridge_UpdateScriptClassInfo(
|
GDMonoCache::managed_callbacks.ScriptManagerBridge_UpdateScriptClassInfo(
|
||||||
p_script.ptr(), &tool, &rpc_functions_dict, &base_script);
|
p_script.ptr(), &tool, &rpc_functions_dict, &signals_dict, &base_script);
|
||||||
|
|
||||||
p_script->tool = tool;
|
p_script->tool = tool;
|
||||||
|
|
||||||
p_script->rpc_config.clear();
|
p_script->rpc_config.clear();
|
||||||
p_script->rpc_config = rpc_functions_dict;
|
p_script->rpc_config = rpc_functions_dict;
|
||||||
|
|
||||||
|
// Event signals
|
||||||
|
|
||||||
|
// Performance is not critical here as this will be replaced with source generators.
|
||||||
|
|
||||||
|
p_script->event_signals.clear();
|
||||||
|
|
||||||
|
// Sigh... can't we just have capacity?
|
||||||
|
p_script->event_signals.resize(signals_dict.size());
|
||||||
|
int push_index = 0;
|
||||||
|
|
||||||
|
for (const Variant *s = signals_dict.next(nullptr); s != nullptr; s = signals_dict.next(s)) {
|
||||||
|
StringName name = *s;
|
||||||
|
|
||||||
|
MethodInfo mi;
|
||||||
|
mi.name = name;
|
||||||
|
|
||||||
|
Array params = signals_dict[*s];
|
||||||
|
|
||||||
|
for (int i = 0; i < params.size(); i++) {
|
||||||
|
Dictionary param = params[i];
|
||||||
|
|
||||||
|
Variant::Type param_type = (Variant::Type)(int)param["type"];
|
||||||
|
PropertyInfo arg_info = PropertyInfo(param_type, (String)param["name"]);
|
||||||
|
arg_info.usage = (uint32_t)param["usage"];
|
||||||
|
mi.arguments.push_back(arg_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
p_script->event_signals.set(push_index++, EventSignalInfo{ name, mi });
|
||||||
|
}
|
||||||
|
|
||||||
p_script->base_script = base_script;
|
p_script->base_script = base_script;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2467,9 +2516,13 @@ bool CSharpScript::has_script_signal(const StringName &p_signal) const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String signal = p_signal;
|
for (const EventSignalInfo &signal : event_signals) {
|
||||||
|
if (signal.name == p_signal) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return GDMonoCache::managed_callbacks.ScriptManagerBridge_HasScriptSignal(this, &signal);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
|
void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
|
||||||
@ -2477,38 +2530,17 @@ void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Performance is not critical here as this will be replaced with source generators.
|
for (const EventSignalInfo &signal : get_script_event_signals()) {
|
||||||
|
r_signals->push_back(signal.method_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!GDMonoCache::godot_api_cache_updated) {
|
Vector<CSharpScript::EventSignalInfo> CSharpScript::get_script_event_signals() const {
|
||||||
return;
|
if (!valid) {
|
||||||
|
return Vector<EventSignalInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary signals_dict;
|
return event_signals;
|
||||||
// Destructor won't be called from C#, and I don't want to include the GDNative header
|
|
||||||
// only for this, so need to call the destructor manually before passing this to C#.
|
|
||||||
signals_dict.~Dictionary();
|
|
||||||
|
|
||||||
GDMonoCache::managed_callbacks.ScriptManagerBridge_GetScriptSignalList(this, &signals_dict);
|
|
||||||
|
|
||||||
for (const Variant *s = signals_dict.next(nullptr); s != nullptr; s = signals_dict.next(s)) {
|
|
||||||
MethodInfo mi;
|
|
||||||
mi.name = *s;
|
|
||||||
|
|
||||||
Array params = signals_dict[*s];
|
|
||||||
|
|
||||||
for (int i = 0; i < params.size(); i++) {
|
|
||||||
Dictionary param = params[i];
|
|
||||||
|
|
||||||
Variant::Type param_type = (Variant::Type)(int)param["type"];
|
|
||||||
PropertyInfo arg_info = PropertyInfo(param_type, (String)param["name"]);
|
|
||||||
if (param_type == Variant::NIL && (bool)param["nil_is_variant"]) {
|
|
||||||
arg_info.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
|
|
||||||
}
|
|
||||||
mi.arguments.push_back(arg_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
r_signals->push_back(mi);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CSharpScript::inherits_script(const Ref<Script> &p_script) const {
|
bool CSharpScript::inherits_script(const Ref<Script> &p_script) const {
|
||||||
|
@ -98,6 +98,13 @@ class CSharpScript : public Script {
|
|||||||
|
|
||||||
Dictionary rpc_config;
|
Dictionary rpc_config;
|
||||||
|
|
||||||
|
struct EventSignalInfo {
|
||||||
|
StringName name; // MethodInfo stores a string...
|
||||||
|
MethodInfo method_info;
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector<EventSignalInfo> event_signals;
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
List<PropertyInfo> exported_members_cache; // members_cache
|
List<PropertyInfo> exported_members_cache; // members_cache
|
||||||
HashMap<StringName, Variant> exported_members_defval_cache; // member_default_values_cache
|
HashMap<StringName, Variant> exported_members_defval_cache; // member_default_values_cache
|
||||||
@ -158,6 +165,8 @@ public:
|
|||||||
bool has_script_signal(const StringName &p_signal) const override;
|
bool has_script_signal(const StringName &p_signal) const override;
|
||||||
void get_script_signal_list(List<MethodInfo> *r_signals) const override;
|
void get_script_signal_list(List<MethodInfo> *r_signals) const override;
|
||||||
|
|
||||||
|
Vector<EventSignalInfo> get_script_event_signals() const;
|
||||||
|
|
||||||
bool get_property_default_value(const StringName &p_property, Variant &r_value) const override;
|
bool get_property_default_value(const StringName &p_property, Variant &r_value) const override;
|
||||||
void get_script_property_list(List<PropertyInfo> *r_list) const override;
|
void get_script_property_list(List<PropertyInfo> *r_list) const override;
|
||||||
void update_exports() override;
|
void update_exports() override;
|
||||||
@ -254,7 +263,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
void mono_object_disposed_baseref(GCHandleIntPtr p_gchandle_to_free, bool p_is_finalizer, bool &r_delete_owner, bool &r_remove_script_instance);
|
void mono_object_disposed_baseref(GCHandleIntPtr p_gchandle_to_free, bool p_is_finalizer, bool &r_delete_owner, bool &r_remove_script_instance);
|
||||||
|
|
||||||
void connect_event_signal(const StringName &p_event_signal);
|
void connect_event_signals();
|
||||||
void disconnect_event_signals();
|
void disconnect_event_signals();
|
||||||
|
|
||||||
void refcount_incremented() override;
|
void refcount_incremented() override;
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
namespace Godot.SourceGenerators.Sample;
|
||||||
|
|
||||||
|
public partial class EventSignals : Godot.Object
|
||||||
|
{
|
||||||
|
[Signal]
|
||||||
|
public delegate void MySignalEventHandler(string str, int num);
|
||||||
|
}
|
@ -166,5 +166,54 @@ namespace Godot.SourceGenerators
|
|||||||
location,
|
location,
|
||||||
location?.SourceTree?.FilePath));
|
location?.SourceTree?.FilePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void ReportSignalDelegateMissingSuffix(
|
||||||
|
GeneratorExecutionContext context,
|
||||||
|
INamedTypeSymbol delegateSymbol)
|
||||||
|
{
|
||||||
|
var locations = delegateSymbol.Locations;
|
||||||
|
var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault();
|
||||||
|
|
||||||
|
string message = "The name of the delegate must end with 'EventHandler': " +
|
||||||
|
delegateSymbol.ToDisplayString() +
|
||||||
|
$". Did you mean '{delegateSymbol.Name}EventHandler'?";
|
||||||
|
|
||||||
|
string description = $"{message}. Rename the delegate accordingly or remove the '[Signal]' attribute.";
|
||||||
|
|
||||||
|
context.ReportDiagnostic(Diagnostic.Create(
|
||||||
|
new DiagnosticDescriptor(id: "GODOT-G0201",
|
||||||
|
title: message,
|
||||||
|
messageFormat: message,
|
||||||
|
category: "Usage",
|
||||||
|
DiagnosticSeverity.Error,
|
||||||
|
isEnabledByDefault: true,
|
||||||
|
description),
|
||||||
|
location,
|
||||||
|
location?.SourceTree?.FilePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ReportSignalDelegateSignatureNotSupported(
|
||||||
|
GeneratorExecutionContext context,
|
||||||
|
INamedTypeSymbol delegateSymbol)
|
||||||
|
{
|
||||||
|
var locations = delegateSymbol.Locations;
|
||||||
|
var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault();
|
||||||
|
|
||||||
|
string message = "The delegate signature of the signal " +
|
||||||
|
$"is not supported: '{delegateSymbol.ToDisplayString()}'";
|
||||||
|
|
||||||
|
string description = $"{message}. Use supported types only or remove the '[Signal]' attribute.";
|
||||||
|
|
||||||
|
context.ReportDiagnostic(Diagnostic.Create(
|
||||||
|
new DiagnosticDescriptor(id: "GODOT-G0202",
|
||||||
|
title: message,
|
||||||
|
messageFormat: message,
|
||||||
|
category: "Usage",
|
||||||
|
DiagnosticSeverity.Error,
|
||||||
|
isEnabledByDefault: true,
|
||||||
|
description),
|
||||||
|
location,
|
||||||
|
location?.SourceTree?.FilePath));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,12 +174,49 @@ namespace Godot.SourceGenerators
|
|||||||
public static bool IsGodotExportAttribute(this INamedTypeSymbol symbol)
|
public static bool IsGodotExportAttribute(this INamedTypeSymbol symbol)
|
||||||
=> symbol.ToString() == GodotClasses.ExportAttr;
|
=> symbol.ToString() == GodotClasses.ExportAttr;
|
||||||
|
|
||||||
|
public static bool IsGodotSignalAttribute(this INamedTypeSymbol symbol)
|
||||||
|
=> symbol.ToString() == GodotClasses.SignalAttr;
|
||||||
|
|
||||||
public static bool IsGodotClassNameAttribute(this INamedTypeSymbol symbol)
|
public static bool IsGodotClassNameAttribute(this INamedTypeSymbol symbol)
|
||||||
=> symbol.ToString() == GodotClasses.GodotClassNameAttr;
|
=> symbol.ToString() == GodotClasses.GodotClassNameAttr;
|
||||||
|
|
||||||
public static bool IsSystemFlagsAttribute(this INamedTypeSymbol symbol)
|
public static bool IsSystemFlagsAttribute(this INamedTypeSymbol symbol)
|
||||||
=> symbol.ToString() == GodotClasses.SystemFlagsAttr;
|
=> symbol.ToString() == GodotClasses.SystemFlagsAttr;
|
||||||
|
|
||||||
|
public static GodotMethodData? HasGodotCompatibleSignature(
|
||||||
|
this IMethodSymbol method,
|
||||||
|
MarshalUtils.TypeCache typeCache
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (method.IsGenericMethod)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var retSymbol = method.ReturnType;
|
||||||
|
var retType = method.ReturnsVoid ?
|
||||||
|
null :
|
||||||
|
MarshalUtils.ConvertManagedTypeToMarshalType(method.ReturnType, typeCache);
|
||||||
|
|
||||||
|
if (retType == null && !method.ReturnsVoid)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var parameters = method.Parameters;
|
||||||
|
|
||||||
|
var paramTypes = parameters
|
||||||
|
// Currently we don't support `ref`, `out`, `in`, `ref readonly` parameters (and we never may)
|
||||||
|
.Where(p => p.RefKind == RefKind.None)
|
||||||
|
// Attempt to determine the variant type
|
||||||
|
.Select(p => MarshalUtils.ConvertManagedTypeToMarshalType(p.Type, typeCache))
|
||||||
|
// Discard parameter types that couldn't be determined (null entries)
|
||||||
|
.Where(t => t != null).Cast<MarshalType>().ToImmutableArray();
|
||||||
|
|
||||||
|
// If any parameter type was incompatible, it was discarded so the length won't match
|
||||||
|
if (parameters.Length > paramTypes.Length)
|
||||||
|
return null; // Ignore incompatible method
|
||||||
|
|
||||||
|
return new GodotMethodData(method, paramTypes, parameters
|
||||||
|
.Select(p => p.Type).ToImmutableArray(), retType, retSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
public static IEnumerable<GodotMethodData> WhereHasGodotCompatibleSignature(
|
public static IEnumerable<GodotMethodData> WhereHasGodotCompatibleSignature(
|
||||||
this IEnumerable<IMethodSymbol> methods,
|
this IEnumerable<IMethodSymbol> methods,
|
||||||
MarshalUtils.TypeCache typeCache
|
MarshalUtils.TypeCache typeCache
|
||||||
@ -187,33 +224,10 @@ namespace Godot.SourceGenerators
|
|||||||
{
|
{
|
||||||
foreach (var method in methods)
|
foreach (var method in methods)
|
||||||
{
|
{
|
||||||
if (method.IsGenericMethod)
|
var methodData = HasGodotCompatibleSignature(method, typeCache);
|
||||||
continue;
|
|
||||||
|
|
||||||
var retSymbol = method.ReturnType;
|
if (methodData != null)
|
||||||
var retType = method.ReturnsVoid ?
|
yield return methodData.Value;
|
||||||
null :
|
|
||||||
MarshalUtils.ConvertManagedTypeToMarshalType(method.ReturnType, typeCache);
|
|
||||||
|
|
||||||
if (retType == null && !method.ReturnsVoid)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var parameters = method.Parameters;
|
|
||||||
|
|
||||||
var paramTypes = parameters
|
|
||||||
// Currently we don't support `ref`, `out`, `in`, `ref readonly` parameters (and we never may)
|
|
||||||
.Where(p => p.RefKind == RefKind.None)
|
|
||||||
// Attempt to determine the variant type
|
|
||||||
.Select(p => MarshalUtils.ConvertManagedTypeToMarshalType(p.Type, typeCache))
|
|
||||||
// Discard parameter types that couldn't be determined (null entries)
|
|
||||||
.Where(t => t != null).Cast<MarshalType>().ToImmutableArray();
|
|
||||||
|
|
||||||
// If any parameter type was incompatible, it was discarded so the length won't match
|
|
||||||
if (parameters.Length > paramTypes.Length)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
yield return new GodotMethodData(method, paramTypes, parameters
|
|
||||||
.Select(p => p.Type).ToImmutableArray(), retType, retSymbol);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ namespace Godot.SourceGenerators
|
|||||||
public const string Object = "Godot.Object";
|
public const string Object = "Godot.Object";
|
||||||
public const string AssemblyHasScriptsAttr = "Godot.AssemblyHasScriptsAttribute";
|
public const string AssemblyHasScriptsAttr = "Godot.AssemblyHasScriptsAttribute";
|
||||||
public const string ExportAttr = "Godot.ExportAttribute";
|
public const string ExportAttr = "Godot.ExportAttribute";
|
||||||
|
public const string SignalAttr = "Godot.SignalAttribute";
|
||||||
public const string GodotClassNameAttr = "Godot.GodotClassName";
|
public const string GodotClassNameAttr = "Godot.GodotClassName";
|
||||||
public const string SystemFlagsAttr = "System.FlagsAttribute";
|
public const string SystemFlagsAttr = "System.FlagsAttribute";
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ using System;
|
|||||||
|
|
||||||
namespace Godot.SourceGenerators
|
namespace Godot.SourceGenerators
|
||||||
{
|
{
|
||||||
|
// TODO: May need to think about compatibility here. Could Godot change these values between minor versions?
|
||||||
|
|
||||||
internal enum VariantType
|
internal enum VariantType
|
||||||
{
|
{
|
||||||
Nil = 0,
|
Nil = 0,
|
||||||
@ -131,4 +133,16 @@ namespace Godot.SourceGenerators
|
|||||||
DefaultIntl = 38,
|
DefaultIntl = 38,
|
||||||
NoEditor = 2
|
NoEditor = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum MethodFlags
|
||||||
|
{
|
||||||
|
Normal = 1,
|
||||||
|
Editor = 2,
|
||||||
|
Const = 4,
|
||||||
|
Virtual = 8,
|
||||||
|
Vararg = 16,
|
||||||
|
Static = 32,
|
||||||
|
ObjectCore = 64,
|
||||||
|
Default = 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,20 @@ namespace Godot.SourceGenerators
|
|||||||
public ITypeSymbol? RetSymbol { get; }
|
public ITypeSymbol? RetSymbol { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct GodotSignalDelegateData
|
||||||
|
{
|
||||||
|
public GodotSignalDelegateData(string name, INamedTypeSymbol delegateSymbol, GodotMethodData invokeMethodData)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
DelegateSymbol = delegateSymbol;
|
||||||
|
InvokeMethodData = invokeMethodData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
public INamedTypeSymbol DelegateSymbol { get; }
|
||||||
|
public GodotMethodData InvokeMethodData { get; }
|
||||||
|
}
|
||||||
|
|
||||||
public struct GodotPropertyData
|
public struct GodotPropertyData
|
||||||
{
|
{
|
||||||
public GodotPropertyData(IPropertySymbol propertySymbol, MarshalType type)
|
public GodotPropertyData(IPropertySymbol propertySymbol, MarshalType type)
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Godot.SourceGenerators
|
||||||
|
{
|
||||||
|
internal struct MethodInfo
|
||||||
|
{
|
||||||
|
public MethodInfo(string name, PropertyInfo returnVal, MethodFlags flags,
|
||||||
|
List<PropertyInfo>? arguments,
|
||||||
|
List<string?>? defaultArguments)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
ReturnVal = returnVal;
|
||||||
|
Flags = flags;
|
||||||
|
Arguments = arguments;
|
||||||
|
DefaultArguments = defaultArguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
public PropertyInfo ReturnVal { get; }
|
||||||
|
public MethodFlags Flags { get; }
|
||||||
|
public List<PropertyInfo>? Arguments { get; }
|
||||||
|
public List<string?>? DefaultArguments { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
namespace Godot.SourceGenerators
|
||||||
|
{
|
||||||
|
internal struct PropertyInfo
|
||||||
|
{
|
||||||
|
public PropertyInfo(VariantType type, string name, PropertyHint hint,
|
||||||
|
string? hintString, PropertyUsageFlags usage, bool exported)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
Name = name;
|
||||||
|
Hint = hint;
|
||||||
|
HintString = hintString;
|
||||||
|
Usage = usage;
|
||||||
|
Exported = exported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VariantType Type { get; }
|
||||||
|
public string Name { get; }
|
||||||
|
public PropertyHint Hint { get; }
|
||||||
|
public string? HintString { get; }
|
||||||
|
public PropertyUsageFlags Usage { get; }
|
||||||
|
public bool Exported { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
@ -122,6 +123,33 @@ namespace Godot.SourceGenerators
|
|||||||
var godotClassProperties = propertySymbols.WhereIsGodotCompatibleType(typeCache).ToArray();
|
var godotClassProperties = propertySymbols.WhereIsGodotCompatibleType(typeCache).ToArray();
|
||||||
var godotClassFields = fieldSymbols.WhereIsGodotCompatibleType(typeCache).ToArray();
|
var godotClassFields = fieldSymbols.WhereIsGodotCompatibleType(typeCache).ToArray();
|
||||||
|
|
||||||
|
var signalDelegateSymbols = members
|
||||||
|
.Where(s => s.Kind == SymbolKind.NamedType)
|
||||||
|
.Cast<INamedTypeSymbol>()
|
||||||
|
.Where(namedTypeSymbol => namedTypeSymbol.TypeKind == TypeKind.Delegate)
|
||||||
|
.Where(s => s.GetAttributes()
|
||||||
|
.Any(a => a.AttributeClass?.IsGodotSignalAttribute() ?? false));
|
||||||
|
|
||||||
|
List<GodotSignalDelegateData> godotSignalDelegates = new();
|
||||||
|
|
||||||
|
foreach (var signalDelegateSymbol in signalDelegateSymbols)
|
||||||
|
{
|
||||||
|
if (!signalDelegateSymbol.Name.EndsWith(ScriptSignalsGenerator.SignalDelegateSuffix))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
string signalName = signalDelegateSymbol.Name;
|
||||||
|
signalName = signalName.Substring(0,
|
||||||
|
signalName.Length - ScriptSignalsGenerator.SignalDelegateSuffix.Length);
|
||||||
|
|
||||||
|
var invokeMethodData = signalDelegateSymbol
|
||||||
|
.DelegateInvokeMethod?.HasGodotCompatibleSignature(typeCache);
|
||||||
|
|
||||||
|
if (invokeMethodData == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
godotSignalDelegates.Add(new(signalName, signalDelegateSymbol, invokeMethodData.Value));
|
||||||
|
}
|
||||||
|
|
||||||
source.Append(" private partial class GodotInternal {\n");
|
source.Append(" private partial class GodotInternal {\n");
|
||||||
|
|
||||||
// Generate cached StringNames for methods and properties, for fast lookup
|
// Generate cached StringNames for methods and properties, for fast lookup
|
||||||
@ -157,6 +185,42 @@ namespace Godot.SourceGenerators
|
|||||||
source.Append(" }\n");
|
source.Append(" }\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate HasGodotClassMethod
|
||||||
|
|
||||||
|
if (godotClassMethods.Length > 0)
|
||||||
|
{
|
||||||
|
source.Append(" protected override bool HasGodotClassMethod(in godot_string_name method)\n {\n");
|
||||||
|
|
||||||
|
bool isFirstEntry = true;
|
||||||
|
foreach (var method in godotClassMethods)
|
||||||
|
{
|
||||||
|
GenerateHasMethodEntry(method, source, isFirstEntry);
|
||||||
|
isFirstEntry = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
source.Append(" return base.HasGodotClassMethod(method);\n");
|
||||||
|
|
||||||
|
source.Append(" }\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate RaiseGodotClassSignalCallbacks
|
||||||
|
|
||||||
|
if (godotSignalDelegates.Count > 0)
|
||||||
|
{
|
||||||
|
source.Append(
|
||||||
|
" protected override void RaiseGodotClassSignalCallbacks(in godot_string_name signal, ");
|
||||||
|
source.Append("NativeVariantPtrArgs args, int argCount)\n {\n");
|
||||||
|
|
||||||
|
foreach (var signal in godotSignalDelegates)
|
||||||
|
{
|
||||||
|
GenerateSignalEventInvoker(signal, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
source.Append(" base.RaiseGodotClassSignalCallbacks(signal, args, argCount);\n");
|
||||||
|
|
||||||
|
source.Append(" }\n");
|
||||||
|
}
|
||||||
|
|
||||||
// Generate Set/GetGodotClassPropertyValue
|
// Generate Set/GetGodotClassPropertyValue
|
||||||
|
|
||||||
if (godotClassProperties.Length > 0 || godotClassFields.Length > 0)
|
if (godotClassProperties.Length > 0 || godotClassFields.Length > 0)
|
||||||
@ -224,24 +288,6 @@ namespace Godot.SourceGenerators
|
|||||||
source.Append(" }\n");
|
source.Append(" }\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate HasGodotClassMethod
|
|
||||||
|
|
||||||
if (godotClassMethods.Length > 0)
|
|
||||||
{
|
|
||||||
source.Append(" protected override bool HasGodotClassMethod(in godot_string_name method)\n {\n");
|
|
||||||
|
|
||||||
bool isFirstEntry = true;
|
|
||||||
foreach (var method in godotClassMethods)
|
|
||||||
{
|
|
||||||
GenerateHasMethodEntry(method, source, isFirstEntry);
|
|
||||||
isFirstEntry = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
source.Append(" return base.HasGodotClassMethod(method);\n");
|
|
||||||
|
|
||||||
source.Append(" }\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
source.Append("}\n"); // partial class
|
source.Append("}\n"); // partial class
|
||||||
|
|
||||||
if (isInnerClass)
|
if (isInnerClass)
|
||||||
@ -314,6 +360,39 @@ namespace Godot.SourceGenerators
|
|||||||
source.Append(" }\n");
|
source.Append(" }\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void GenerateSignalEventInvoker(
|
||||||
|
GodotSignalDelegateData signal,
|
||||||
|
StringBuilder source
|
||||||
|
)
|
||||||
|
{
|
||||||
|
string signalName = signal.Name;
|
||||||
|
var invokeMethodData = signal.InvokeMethodData;
|
||||||
|
|
||||||
|
source.Append(" if (signal == GodotInternal.SignalName_");
|
||||||
|
source.Append(signalName);
|
||||||
|
source.Append(" && argCount == ");
|
||||||
|
source.Append(invokeMethodData.ParamTypes.Length);
|
||||||
|
source.Append(") {\n");
|
||||||
|
source.Append(" backing_");
|
||||||
|
source.Append(signalName);
|
||||||
|
source.Append("?.Invoke(");
|
||||||
|
|
||||||
|
for (int i = 0; i < invokeMethodData.ParamTypes.Length; i++)
|
||||||
|
{
|
||||||
|
if (i != 0)
|
||||||
|
source.Append(", ");
|
||||||
|
|
||||||
|
source.AppendVariantToManagedExpr(string.Concat("args[", i.ToString(), "]"),
|
||||||
|
invokeMethodData.ParamTypeSymbols[i], invokeMethodData.ParamTypes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
source.Append(");\n");
|
||||||
|
|
||||||
|
source.Append(" return;\n");
|
||||||
|
|
||||||
|
source.Append(" }\n");
|
||||||
|
}
|
||||||
|
|
||||||
private static void GeneratePropertySetter(
|
private static void GeneratePropertySetter(
|
||||||
string propertyMemberName,
|
string propertyMemberName,
|
||||||
ITypeSymbol propertyTypeSymbol,
|
ITypeSymbol propertyTypeSymbol,
|
||||||
|
@ -146,7 +146,7 @@ namespace Godot.SourceGenerators
|
|||||||
|
|
||||||
source.Append(" }\n"); // class GodotInternal
|
source.Append(" }\n"); // class GodotInternal
|
||||||
|
|
||||||
// Generate GetGodotPropertiesMetadata
|
// Generate GetGodotPropertyList
|
||||||
|
|
||||||
if (godotClassProperties.Length > 0 || godotClassFields.Length > 0)
|
if (godotClassProperties.Length > 0 || godotClassFields.Length > 0)
|
||||||
{
|
{
|
||||||
@ -156,7 +156,7 @@ namespace Godot.SourceGenerators
|
|||||||
|
|
||||||
source.Append(" internal new static ")
|
source.Append(" internal new static ")
|
||||||
.Append(dictionaryType)
|
.Append(dictionaryType)
|
||||||
.Append(" GetGodotPropertiesMetadata()\n {\n");
|
.Append(" GetGodotPropertyList()\n {\n");
|
||||||
|
|
||||||
source.Append(" var properties = new ")
|
source.Append(" var properties = new ")
|
||||||
.Append(dictionaryType)
|
.Append(dictionaryType)
|
||||||
@ -164,7 +164,7 @@ namespace Godot.SourceGenerators
|
|||||||
|
|
||||||
foreach (var property in godotClassProperties)
|
foreach (var property in godotClassProperties)
|
||||||
{
|
{
|
||||||
var propertyInfo = GetPropertyMetadata(context, typeCache,
|
var propertyInfo = DeterminePropertyInfo(context, typeCache,
|
||||||
property.PropertySymbol, property.Type);
|
property.PropertySymbol, property.Type);
|
||||||
|
|
||||||
if (propertyInfo == null)
|
if (propertyInfo == null)
|
||||||
@ -175,7 +175,7 @@ namespace Godot.SourceGenerators
|
|||||||
|
|
||||||
foreach (var field in godotClassFields)
|
foreach (var field in godotClassFields)
|
||||||
{
|
{
|
||||||
var propertyInfo = GetPropertyMetadata(context, typeCache,
|
var propertyInfo = DeterminePropertyInfo(context, typeCache,
|
||||||
field.FieldSymbol, field.Type);
|
field.FieldSymbol, field.Type);
|
||||||
|
|
||||||
if (propertyInfo == null)
|
if (propertyInfo == null)
|
||||||
@ -229,28 +229,7 @@ namespace Godot.SourceGenerators
|
|||||||
.Append("));\n");
|
.Append("));\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct PropertyInfo
|
private static PropertyInfo? DeterminePropertyInfo(
|
||||||
{
|
|
||||||
public PropertyInfo(VariantType type, string name, PropertyHint hint,
|
|
||||||
string? hintString, PropertyUsageFlags usage, bool exported)
|
|
||||||
{
|
|
||||||
Type = type;
|
|
||||||
Name = name;
|
|
||||||
Hint = hint;
|
|
||||||
HintString = hintString;
|
|
||||||
Usage = usage;
|
|
||||||
Exported = exported;
|
|
||||||
}
|
|
||||||
|
|
||||||
public VariantType Type { get; }
|
|
||||||
public string Name { get; }
|
|
||||||
public PropertyHint Hint { get; }
|
|
||||||
public string? HintString { get; }
|
|
||||||
public PropertyUsageFlags Usage { get; }
|
|
||||||
public bool Exported { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private static PropertyInfo? GetPropertyMetadata(
|
|
||||||
GeneratorExecutionContext context,
|
GeneratorExecutionContext context,
|
||||||
MarshalUtils.TypeCache typeCache,
|
MarshalUtils.TypeCache typeCache,
|
||||||
ISymbol memberSymbol,
|
ISymbol memberSymbol,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
@ -120,10 +121,39 @@ namespace Godot.SourceGenerators
|
|||||||
var godotClassProperties = propertySymbols.WhereIsGodotCompatibleType(typeCache).ToArray();
|
var godotClassProperties = propertySymbols.WhereIsGodotCompatibleType(typeCache).ToArray();
|
||||||
var godotClassFields = fieldSymbols.WhereIsGodotCompatibleType(typeCache).ToArray();
|
var godotClassFields = fieldSymbols.WhereIsGodotCompatibleType(typeCache).ToArray();
|
||||||
|
|
||||||
|
var signalDelegateSymbols = members
|
||||||
|
.Where(s => s.Kind == SymbolKind.NamedType)
|
||||||
|
.Cast<INamedTypeSymbol>()
|
||||||
|
.Where(namedTypeSymbol => namedTypeSymbol.TypeKind == TypeKind.Delegate)
|
||||||
|
.Where(s => s.GetAttributes()
|
||||||
|
.Any(a => a.AttributeClass?.IsGodotSignalAttribute() ?? false));
|
||||||
|
|
||||||
|
List<GodotSignalDelegateData> godotSignalDelegates = new();
|
||||||
|
|
||||||
|
foreach (var signalDelegateSymbol in signalDelegateSymbols)
|
||||||
|
{
|
||||||
|
if (!signalDelegateSymbol.Name.EndsWith(ScriptSignalsGenerator.SignalDelegateSuffix))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
string signalName = signalDelegateSymbol.Name;
|
||||||
|
signalName = signalName.Substring(0,
|
||||||
|
signalName.Length - ScriptSignalsGenerator.SignalDelegateSuffix.Length);
|
||||||
|
|
||||||
|
var invokeMethodData = signalDelegateSymbol
|
||||||
|
.DelegateInvokeMethod?.HasGodotCompatibleSignature(typeCache);
|
||||||
|
|
||||||
|
if (invokeMethodData == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
godotSignalDelegates.Add(new(signalName, signalDelegateSymbol, invokeMethodData.Value));
|
||||||
|
}
|
||||||
|
|
||||||
source.Append(
|
source.Append(
|
||||||
" protected override void SaveGodotObjectData(global::Godot.Bridge.GodotSerializationInfo info)\n {\n");
|
" protected override void SaveGodotObjectData(global::Godot.Bridge.GodotSerializationInfo info)\n {\n");
|
||||||
source.Append(" base.SaveGodotObjectData(info);\n");
|
source.Append(" base.SaveGodotObjectData(info);\n");
|
||||||
|
|
||||||
|
// Save properties
|
||||||
|
|
||||||
foreach (var property in godotClassProperties)
|
foreach (var property in godotClassProperties)
|
||||||
{
|
{
|
||||||
string propertyName = property.PropertySymbol.Name;
|
string propertyName = property.PropertySymbol.Name;
|
||||||
@ -135,6 +165,8 @@ namespace Godot.SourceGenerators
|
|||||||
.Append(");\n");
|
.Append(");\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save fields
|
||||||
|
|
||||||
foreach (var field in godotClassFields)
|
foreach (var field in godotClassFields)
|
||||||
{
|
{
|
||||||
string fieldName = field.FieldSymbol.Name;
|
string fieldName = field.FieldSymbol.Name;
|
||||||
@ -146,12 +178,27 @@ namespace Godot.SourceGenerators
|
|||||||
.Append(");\n");
|
.Append(");\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save signal events
|
||||||
|
|
||||||
|
foreach (var signalDelegate in godotSignalDelegates)
|
||||||
|
{
|
||||||
|
string signalName = signalDelegate.Name;
|
||||||
|
|
||||||
|
source.Append(" info.AddSignalEventDelegate(GodotInternal.SignalName_")
|
||||||
|
.Append(signalName)
|
||||||
|
.Append(", this.backing_")
|
||||||
|
.Append(signalName)
|
||||||
|
.Append(");\n");
|
||||||
|
}
|
||||||
|
|
||||||
source.Append(" }\n");
|
source.Append(" }\n");
|
||||||
|
|
||||||
source.Append(
|
source.Append(
|
||||||
" protected override void RestoreGodotObjectData(global::Godot.Bridge.GodotSerializationInfo info)\n {\n");
|
" protected override void RestoreGodotObjectData(global::Godot.Bridge.GodotSerializationInfo info)\n {\n");
|
||||||
source.Append(" base.RestoreGodotObjectData(info);\n");
|
source.Append(" base.RestoreGodotObjectData(info);\n");
|
||||||
|
|
||||||
|
// Restore properties
|
||||||
|
|
||||||
foreach (var property in godotClassProperties)
|
foreach (var property in godotClassProperties)
|
||||||
{
|
{
|
||||||
string propertyName = property.PropertySymbol.Name;
|
string propertyName = property.PropertySymbol.Name;
|
||||||
@ -171,6 +218,8 @@ namespace Godot.SourceGenerators
|
|||||||
.Append(";\n");
|
.Append(";\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore fields
|
||||||
|
|
||||||
foreach (var field in godotClassFields)
|
foreach (var field in godotClassFields)
|
||||||
{
|
{
|
||||||
string fieldName = field.FieldSymbol.Name;
|
string fieldName = field.FieldSymbol.Name;
|
||||||
@ -190,6 +239,27 @@ namespace Godot.SourceGenerators
|
|||||||
.Append(";\n");
|
.Append(";\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restore signal events
|
||||||
|
|
||||||
|
foreach (var signalDelegate in godotSignalDelegates)
|
||||||
|
{
|
||||||
|
string signalName = signalDelegate.Name;
|
||||||
|
string signalDelegateQualifiedName = signalDelegate.DelegateSymbol.FullQualifiedName();
|
||||||
|
|
||||||
|
source.Append(" if (info.TryGetSignalEventDelegate<")
|
||||||
|
.Append(signalDelegateQualifiedName)
|
||||||
|
.Append(">(GodotInternal.SignalName_")
|
||||||
|
.Append(signalName)
|
||||||
|
.Append(", out var _value_")
|
||||||
|
.Append(signalName)
|
||||||
|
.Append("))\n")
|
||||||
|
.Append(" this.backing_")
|
||||||
|
.Append(signalName)
|
||||||
|
.Append(" = _value_")
|
||||||
|
.Append(signalName)
|
||||||
|
.Append(";\n");
|
||||||
|
}
|
||||||
|
|
||||||
source.Append(" }\n");
|
source.Append(" }\n");
|
||||||
|
|
||||||
source.Append("}\n"); // partial class
|
source.Append("}\n"); // partial class
|
||||||
|
@ -0,0 +1,360 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
|
using Microsoft.CodeAnalysis.Text;
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// Determine a proper way to emit the signal.
|
||||||
|
// 'Emit(nameof(TheEvent))' creates a StringName everytime and has the overhead of string marshaling.
|
||||||
|
// I haven't decided on the best option yet. Some possibilities:
|
||||||
|
// - Expose the generated StringName fields to the user, for use with 'Emit(...)'.
|
||||||
|
// - Generate a 'EmitSignalName' method for each event signal.
|
||||||
|
|
||||||
|
namespace Godot.SourceGenerators
|
||||||
|
{
|
||||||
|
[Generator]
|
||||||
|
public class ScriptSignalsGenerator : ISourceGenerator
|
||||||
|
{
|
||||||
|
public void Initialize(GeneratorInitializationContext context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(GeneratorExecutionContext context)
|
||||||
|
{
|
||||||
|
if (context.AreGodotSourceGeneratorsDisabled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
INamedTypeSymbol[] godotClasses = context
|
||||||
|
.Compilation.SyntaxTrees
|
||||||
|
.SelectMany(tree =>
|
||||||
|
tree.GetRoot().DescendantNodes()
|
||||||
|
.OfType<ClassDeclarationSyntax>()
|
||||||
|
.SelectGodotScriptClasses(context.Compilation)
|
||||||
|
// Report and skip non-partial classes
|
||||||
|
.Where(x =>
|
||||||
|
{
|
||||||
|
if (x.cds.IsPartial())
|
||||||
|
{
|
||||||
|
if (x.cds.IsNested() && !x.cds.AreAllOuterTypesPartial(out var typeMissingPartial))
|
||||||
|
{
|
||||||
|
Common.ReportNonPartialGodotScriptOuterClass(context, typeMissingPartial!);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common.ReportNonPartialGodotScriptClass(context, x.cds, x.symbol);
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
.Select(x => x.symbol)
|
||||||
|
)
|
||||||
|
.Distinct<INamedTypeSymbol>(SymbolEqualityComparer.Default)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
if (godotClasses.Length > 0)
|
||||||
|
{
|
||||||
|
var typeCache = new MarshalUtils.TypeCache(context);
|
||||||
|
|
||||||
|
foreach (var godotClass in godotClasses)
|
||||||
|
{
|
||||||
|
VisitGodotScriptClass(context, typeCache, godotClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string SignalDelegateSuffix = "EventHandler";
|
||||||
|
|
||||||
|
private static void VisitGodotScriptClass(
|
||||||
|
GeneratorExecutionContext context,
|
||||||
|
MarshalUtils.TypeCache typeCache,
|
||||||
|
INamedTypeSymbol symbol
|
||||||
|
)
|
||||||
|
{
|
||||||
|
INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace;
|
||||||
|
string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ?
|
||||||
|
namespaceSymbol.FullQualifiedName() :
|
||||||
|
string.Empty;
|
||||||
|
bool hasNamespace = classNs.Length != 0;
|
||||||
|
|
||||||
|
bool isInnerClass = symbol.ContainingType != null;
|
||||||
|
|
||||||
|
string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
|
||||||
|
+ "_ScriptSignals_Generated";
|
||||||
|
|
||||||
|
var source = new StringBuilder();
|
||||||
|
|
||||||
|
source.Append("using Godot;\n");
|
||||||
|
source.Append("using Godot.NativeInterop;\n");
|
||||||
|
source.Append("\n");
|
||||||
|
|
||||||
|
if (hasNamespace)
|
||||||
|
{
|
||||||
|
source.Append("namespace ");
|
||||||
|
source.Append(classNs);
|
||||||
|
source.Append(" {\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isInnerClass)
|
||||||
|
{
|
||||||
|
var containingType = symbol.ContainingType;
|
||||||
|
|
||||||
|
while (containingType != null)
|
||||||
|
{
|
||||||
|
source.Append("partial ");
|
||||||
|
source.Append(containingType.GetDeclarationKeyword());
|
||||||
|
source.Append(" ");
|
||||||
|
source.Append(containingType.NameWithTypeParameters());
|
||||||
|
source.Append("\n{\n");
|
||||||
|
|
||||||
|
containingType = containingType.ContainingType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
source.Append("partial class ");
|
||||||
|
source.Append(symbol.NameWithTypeParameters());
|
||||||
|
source.Append("\n{\n");
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// The delegate name already needs to end with 'Signal' to avoid collision with the event name.
|
||||||
|
// Requiring SignalAttribute is redundant. Should we remove it to make declaration shorter?
|
||||||
|
|
||||||
|
var members = symbol.GetMembers();
|
||||||
|
|
||||||
|
var signalDelegateSymbols = members
|
||||||
|
.Where(s => s.Kind == SymbolKind.NamedType)
|
||||||
|
.Cast<INamedTypeSymbol>()
|
||||||
|
.Where(namedTypeSymbol => namedTypeSymbol.TypeKind == TypeKind.Delegate)
|
||||||
|
.Where(s => s.GetAttributes()
|
||||||
|
.Any(a => a.AttributeClass?.IsGodotSignalAttribute() ?? false));
|
||||||
|
|
||||||
|
List<GodotSignalDelegateData> godotSignalDelegates = new();
|
||||||
|
|
||||||
|
foreach (var signalDelegateSymbol in signalDelegateSymbols)
|
||||||
|
{
|
||||||
|
if (!signalDelegateSymbol.Name.EndsWith(SignalDelegateSuffix))
|
||||||
|
{
|
||||||
|
Common.ReportSignalDelegateMissingSuffix(context, signalDelegateSymbol);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
string signalName = signalDelegateSymbol.Name;
|
||||||
|
signalName = signalName.Substring(0, signalName.Length - SignalDelegateSuffix.Length);
|
||||||
|
|
||||||
|
var invokeMethodData = signalDelegateSymbol
|
||||||
|
.DelegateInvokeMethod?.HasGodotCompatibleSignature(typeCache);
|
||||||
|
|
||||||
|
if (invokeMethodData == null)
|
||||||
|
{
|
||||||
|
// TODO: Better error for incompatible signature. We should indicate incompatible argument types, as we do with exported properties.
|
||||||
|
Common.ReportSignalDelegateSignatureNotSupported(context, signalDelegateSymbol);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
godotSignalDelegates.Add(new(signalName, signalDelegateSymbol, invokeMethodData.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
source.Append(" private partial class GodotInternal {\n");
|
||||||
|
|
||||||
|
// Generate cached StringNames for methods and properties, for fast lookup
|
||||||
|
|
||||||
|
foreach (var signalDelegate in godotSignalDelegates)
|
||||||
|
{
|
||||||
|
string signalName = signalDelegate.Name;
|
||||||
|
source.Append(" public static readonly StringName SignalName_");
|
||||||
|
source.Append(signalName);
|
||||||
|
source.Append(" = \"");
|
||||||
|
source.Append(signalName);
|
||||||
|
source.Append("\";\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
source.Append(" }\n"); // class GodotInternal
|
||||||
|
|
||||||
|
// Generate GetGodotSignalList
|
||||||
|
|
||||||
|
if (godotSignalDelegates.Count > 0)
|
||||||
|
{
|
||||||
|
source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
|
||||||
|
|
||||||
|
const string listType = "System.Collections.Generic.List<global::Godot.Bridge.MethodInfo>";
|
||||||
|
|
||||||
|
source.Append(" internal new static ")
|
||||||
|
.Append(listType)
|
||||||
|
.Append(" GetGodotSignalList()\n {\n");
|
||||||
|
|
||||||
|
source.Append(" var signals = new ")
|
||||||
|
.Append(listType)
|
||||||
|
.Append("(")
|
||||||
|
.Append(godotSignalDelegates.Count)
|
||||||
|
.Append(");\n");
|
||||||
|
|
||||||
|
foreach (var signalDelegateData in godotSignalDelegates)
|
||||||
|
{
|
||||||
|
var methodInfo = DetermineMethodInfo(signalDelegateData);
|
||||||
|
AppendMethodInfo(source, methodInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
source.Append(" return signals;\n");
|
||||||
|
source.Append(" }\n");
|
||||||
|
|
||||||
|
source.Append("#pragma warning restore CS0109\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate signal event
|
||||||
|
|
||||||
|
foreach (var signalDelegate in godotSignalDelegates)
|
||||||
|
{
|
||||||
|
string signalName = signalDelegate.Name;
|
||||||
|
|
||||||
|
// TODO: Hide backing event from code-completion and debugger
|
||||||
|
// The reason we have a backing field is to hide the invoke method from the event,
|
||||||
|
// as it doesn't emit the signal, only the event delegates. This can confuse users.
|
||||||
|
// Maybe we should directly connect the delegates, as we do with native signals?
|
||||||
|
source.Append(" private ")
|
||||||
|
.Append(signalDelegate.DelegateSymbol.FullQualifiedName())
|
||||||
|
.Append(" backing_")
|
||||||
|
.Append(signalName)
|
||||||
|
.Append(";\n");
|
||||||
|
|
||||||
|
source.Append(" public event ")
|
||||||
|
.Append(signalDelegate.DelegateSymbol.FullQualifiedName())
|
||||||
|
.Append(" ")
|
||||||
|
.Append(signalName)
|
||||||
|
.Append(" {\n")
|
||||||
|
.Append(" add => backing_")
|
||||||
|
.Append(signalName)
|
||||||
|
.Append(" += value;\n")
|
||||||
|
.Append(" remove => backing_")
|
||||||
|
.Append(signalName)
|
||||||
|
.Append(" -= value;\n")
|
||||||
|
.Append("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
source.Append("}\n"); // partial class
|
||||||
|
|
||||||
|
if (isInnerClass)
|
||||||
|
{
|
||||||
|
var containingType = symbol.ContainingType;
|
||||||
|
|
||||||
|
while (containingType != null)
|
||||||
|
{
|
||||||
|
source.Append("}\n"); // outer class
|
||||||
|
|
||||||
|
containingType = containingType.ContainingType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasNamespace)
|
||||||
|
{
|
||||||
|
source.Append("\n}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
context.AddSource(uniqueHint, SourceText.From(source.ToString(), Encoding.UTF8));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AppendMethodInfo(StringBuilder source, MethodInfo methodInfo)
|
||||||
|
{
|
||||||
|
source.Append(" signals.Add(new(name: GodotInternal.SignalName_")
|
||||||
|
.Append(methodInfo.Name)
|
||||||
|
.Append(", returnVal: ");
|
||||||
|
|
||||||
|
AppendPropertyInfo(source, methodInfo.ReturnVal);
|
||||||
|
|
||||||
|
source.Append(", flags: (Godot.MethodFlags)")
|
||||||
|
.Append((int)methodInfo.Flags)
|
||||||
|
.Append(", arguments: ");
|
||||||
|
|
||||||
|
if (methodInfo.Arguments is { Count: > 0 })
|
||||||
|
{
|
||||||
|
source.Append("new() { ");
|
||||||
|
|
||||||
|
foreach (var param in methodInfo.Arguments)
|
||||||
|
{
|
||||||
|
AppendPropertyInfo(source, param);
|
||||||
|
|
||||||
|
// C# allows colon after the last element
|
||||||
|
source.Append(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
source.Append(" }");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
source.Append("null");
|
||||||
|
}
|
||||||
|
|
||||||
|
source.Append(", defaultArguments: null));\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AppendPropertyInfo(StringBuilder source, PropertyInfo propertyInfo)
|
||||||
|
{
|
||||||
|
source.Append("new(type: (Godot.Variant.Type)")
|
||||||
|
.Append((int)propertyInfo.Type)
|
||||||
|
.Append(", name: \"")
|
||||||
|
.Append(propertyInfo.Name)
|
||||||
|
.Append("\", hint: (Godot.PropertyHint)")
|
||||||
|
.Append((int)propertyInfo.Hint)
|
||||||
|
.Append(", hintString: \"")
|
||||||
|
.Append(propertyInfo.HintString)
|
||||||
|
.Append("\", usage: (Godot.PropertyUsageFlags)")
|
||||||
|
.Append((int)propertyInfo.Usage)
|
||||||
|
.Append(", exported: ")
|
||||||
|
.Append(propertyInfo.Exported ? "true" : "false")
|
||||||
|
.Append(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MethodInfo DetermineMethodInfo(GodotSignalDelegateData signalDelegateData)
|
||||||
|
{
|
||||||
|
var invokeMethodData = signalDelegateData.InvokeMethodData;
|
||||||
|
|
||||||
|
PropertyInfo returnVal;
|
||||||
|
|
||||||
|
if (invokeMethodData.RetType != null)
|
||||||
|
{
|
||||||
|
returnVal = DeterminePropertyInfo(invokeMethodData.RetType.Value, name: string.Empty);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
returnVal = new PropertyInfo(VariantType.Nil, string.Empty, PropertyHint.None,
|
||||||
|
hintString: null, PropertyUsageFlags.Default, exported: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
int paramCount = invokeMethodData.ParamTypes.Length;
|
||||||
|
|
||||||
|
List<PropertyInfo>? arguments;
|
||||||
|
|
||||||
|
if (paramCount > 0)
|
||||||
|
{
|
||||||
|
arguments = new(capacity: paramCount);
|
||||||
|
|
||||||
|
for (int i = 0; i < paramCount; i++)
|
||||||
|
{
|
||||||
|
arguments.Add(DeterminePropertyInfo(invokeMethodData.ParamTypes[i],
|
||||||
|
name: invokeMethodData.Method.Parameters[i].Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arguments = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MethodInfo(signalDelegateData.Name, returnVal, MethodFlags.Default, arguments,
|
||||||
|
defaultArguments: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PropertyInfo DeterminePropertyInfo(MarshalType marshalType, string name)
|
||||||
|
{
|
||||||
|
var memberVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(marshalType)!.Value;
|
||||||
|
|
||||||
|
var propUsage = PropertyUsageFlags.Default;
|
||||||
|
|
||||||
|
if (memberVariantType == VariantType.Nil)
|
||||||
|
propUsage |= PropertyUsageFlags.NilIsVariant;
|
||||||
|
|
||||||
|
return new PropertyInfo(memberVariantType, name,
|
||||||
|
PropertyHint.None, string.Empty, propUsage, exported: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,7 +22,8 @@ namespace GodotTools.Build
|
|||||||
public string ProjectFile { get; set; }
|
public string ProjectFile { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Signal] public event Action BuildStateChanged;
|
[Signal]
|
||||||
|
public delegate void BuildStateChangedEventHandler();
|
||||||
|
|
||||||
public bool HasBuildExited { get; private set; } = false;
|
public bool HasBuildExited { get; private set; } = false;
|
||||||
|
|
||||||
|
@ -98,7 +98,11 @@ namespace Godot.Collections
|
|||||||
{
|
{
|
||||||
// Always dispose `NativeValue` even if disposing is true
|
// Always dispose `NativeValue` even if disposing is true
|
||||||
NativeValue.DangerousSelfRef.Dispose();
|
NativeValue.DangerousSelfRef.Dispose();
|
||||||
DisposablesTracker.UnregisterDisposable(_weakReferenceToSelf);
|
|
||||||
|
if (_weakReferenceToSelf != null)
|
||||||
|
{
|
||||||
|
DisposablesTracker.UnregisterDisposable(_weakReferenceToSelf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -46,22 +46,34 @@ public class GodotSerializationInfo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Delegate GetSignalEventDelegate(StringName name)
|
public bool TryGetSignalEventDelegate<T>(StringName name, [MaybeNullWhen(false)] out T value)
|
||||||
|
where T : Delegate
|
||||||
{
|
{
|
||||||
if (DelegateUtils.TryDeserializeDelegate(_signalEvents[name], out var eventDelegate))
|
if (_signalEvents.TryGetValue(name, out Collections.Array serializedData))
|
||||||
{
|
{
|
||||||
return eventDelegate;
|
if (DelegateUtils.TryDeserializeDelegate(serializedData, out var eventDelegate))
|
||||||
}
|
{
|
||||||
else if (OS.IsStdoutVerbose())
|
value = eventDelegate as T;
|
||||||
{
|
|
||||||
Console.WriteLine($"Failed to deserialize event signal delegate: {name}");
|
if (value == null)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Cannot cast the deserialized event signal delegate: {name}. " +
|
||||||
|
$"Expected '{typeof(T).FullName}'; got '{eventDelegate.GetType().FullName}'.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (OS.IsStdoutVerbose())
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Failed to deserialize event signal delegate: {name}");
|
||||||
|
}
|
||||||
|
|
||||||
|
value = null;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
value = null;
|
||||||
}
|
return false;
|
||||||
|
|
||||||
public IEnumerable<StringName> GetSignalEventsList()
|
|
||||||
{
|
|
||||||
return _signalEvents.Keys;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,14 +19,12 @@ namespace Godot.Bridge
|
|||||||
public delegate* unmanaged<IntPtr, godot_string_name*, void> ScriptManagerBridge_GetScriptNativeName;
|
public delegate* unmanaged<IntPtr, godot_string_name*, void> ScriptManagerBridge_GetScriptNativeName;
|
||||||
public delegate* unmanaged<IntPtr, IntPtr, void> ScriptManagerBridge_SetGodotObjectPtr;
|
public delegate* unmanaged<IntPtr, IntPtr, void> ScriptManagerBridge_SetGodotObjectPtr;
|
||||||
public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant**, int, godot_bool*, void> ScriptManagerBridge_RaiseEventSignal;
|
public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant**, int, godot_bool*, void> ScriptManagerBridge_RaiseEventSignal;
|
||||||
public delegate* unmanaged<IntPtr, godot_dictionary*, void> ScriptManagerBridge_GetScriptSignalList;
|
|
||||||
public delegate* unmanaged<IntPtr, godot_string*, godot_bool> ScriptManagerBridge_HasScriptSignal;
|
|
||||||
public delegate* unmanaged<IntPtr, IntPtr, godot_bool> ScriptManagerBridge_ScriptIsOrInherits;
|
public delegate* unmanaged<IntPtr, IntPtr, godot_bool> ScriptManagerBridge_ScriptIsOrInherits;
|
||||||
public delegate* unmanaged<IntPtr, godot_string*, godot_bool> ScriptManagerBridge_AddScriptBridge;
|
public delegate* unmanaged<IntPtr, godot_string*, godot_bool> ScriptManagerBridge_AddScriptBridge;
|
||||||
public delegate* unmanaged<godot_string*, godot_ref*, void> ScriptManagerBridge_GetOrCreateScriptBridgeForPath;
|
public delegate* unmanaged<godot_string*, godot_ref*, void> ScriptManagerBridge_GetOrCreateScriptBridgeForPath;
|
||||||
public delegate* unmanaged<IntPtr, void> ScriptManagerBridge_RemoveScriptBridge;
|
public delegate* unmanaged<IntPtr, void> ScriptManagerBridge_RemoveScriptBridge;
|
||||||
public delegate* unmanaged<IntPtr, godot_bool> ScriptManagerBridge_TryReloadRegisteredScriptWithClass;
|
public delegate* unmanaged<IntPtr, godot_bool> ScriptManagerBridge_TryReloadRegisteredScriptWithClass;
|
||||||
public delegate* unmanaged<IntPtr, godot_bool*, godot_dictionary*, godot_ref*, void> ScriptManagerBridge_UpdateScriptClassInfo;
|
public delegate* unmanaged<IntPtr, godot_bool*, godot_dictionary*, godot_dictionary*, godot_ref*, void> ScriptManagerBridge_UpdateScriptClassInfo;
|
||||||
public delegate* unmanaged<IntPtr, IntPtr*, godot_bool, godot_bool> ScriptManagerBridge_SwapGCHandleForType;
|
public delegate* unmanaged<IntPtr, IntPtr*, godot_bool, godot_bool> ScriptManagerBridge_SwapGCHandleForType;
|
||||||
public delegate* unmanaged<IntPtr, delegate* unmanaged<IntPtr, godot_string*, void*, int, void>, void> ScriptManagerBridge_GetPropertyInfoList;
|
public delegate* unmanaged<IntPtr, delegate* unmanaged<IntPtr, godot_string*, void*, int, void>, void> ScriptManagerBridge_GetPropertyInfoList;
|
||||||
public delegate* unmanaged<IntPtr, delegate* unmanaged<IntPtr, void*, int, void>, void> ScriptManagerBridge_GetPropertyDefaultValues;
|
public delegate* unmanaged<IntPtr, delegate* unmanaged<IntPtr, void*, int, void>, void> ScriptManagerBridge_GetPropertyDefaultValues;
|
||||||
@ -60,8 +58,6 @@ namespace Godot.Bridge
|
|||||||
ScriptManagerBridge_GetScriptNativeName = &ScriptManagerBridge.GetScriptNativeName,
|
ScriptManagerBridge_GetScriptNativeName = &ScriptManagerBridge.GetScriptNativeName,
|
||||||
ScriptManagerBridge_SetGodotObjectPtr = &ScriptManagerBridge.SetGodotObjectPtr,
|
ScriptManagerBridge_SetGodotObjectPtr = &ScriptManagerBridge.SetGodotObjectPtr,
|
||||||
ScriptManagerBridge_RaiseEventSignal = &ScriptManagerBridge.RaiseEventSignal,
|
ScriptManagerBridge_RaiseEventSignal = &ScriptManagerBridge.RaiseEventSignal,
|
||||||
ScriptManagerBridge_GetScriptSignalList = &ScriptManagerBridge.GetScriptSignalList,
|
|
||||||
ScriptManagerBridge_HasScriptSignal = &ScriptManagerBridge.HasScriptSignal,
|
|
||||||
ScriptManagerBridge_ScriptIsOrInherits = &ScriptManagerBridge.ScriptIsOrInherits,
|
ScriptManagerBridge_ScriptIsOrInherits = &ScriptManagerBridge.ScriptIsOrInherits,
|
||||||
ScriptManagerBridge_AddScriptBridge = &ScriptManagerBridge.AddScriptBridge,
|
ScriptManagerBridge_AddScriptBridge = &ScriptManagerBridge.AddScriptBridge,
|
||||||
ScriptManagerBridge_GetOrCreateScriptBridgeForPath = &ScriptManagerBridge.GetOrCreateScriptBridgeForPath,
|
ScriptManagerBridge_GetOrCreateScriptBridgeForPath = &ScriptManagerBridge.GetOrCreateScriptBridgeForPath,
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Godot.Bridge;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
public struct MethodInfo
|
||||||
|
{
|
||||||
|
public StringName Name { get; init; }
|
||||||
|
public PropertyInfo ReturnVal { get; init; }
|
||||||
|
public MethodFlags Flags { get; init; }
|
||||||
|
public int Id { get; init; } = 0;
|
||||||
|
public List<PropertyInfo>? Arguments { get; init; }
|
||||||
|
public List<object>? DefaultArguments { get; init; }
|
||||||
|
|
||||||
|
public MethodInfo(StringName name, PropertyInfo returnVal, MethodFlags flags, List<PropertyInfo>? arguments,
|
||||||
|
List<object>? defaultArguments)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
ReturnVal = returnVal;
|
||||||
|
Flags = flags;
|
||||||
|
Arguments = arguments;
|
||||||
|
DefaultArguments = defaultArguments;
|
||||||
|
}
|
||||||
|
}
|
@ -1,26 +1,24 @@
|
|||||||
using System;
|
namespace Godot.Bridge;
|
||||||
using Godot.NativeInterop;
|
|
||||||
|
|
||||||
namespace Godot.Bridge
|
#nullable enable
|
||||||
|
|
||||||
|
public struct PropertyInfo
|
||||||
{
|
{
|
||||||
public struct PropertyInfo
|
public Variant.Type Type { get; init; }
|
||||||
{
|
public StringName Name { get; init; }
|
||||||
public Variant.Type Type { get; init; }
|
public PropertyHint Hint { get; init; }
|
||||||
public StringName Name { get; init; }
|
public string HintString { get; init; }
|
||||||
public PropertyHint Hint { get; init; }
|
public PropertyUsageFlags Usage { get; init; }
|
||||||
public string HintString { get; init; }
|
public bool Exported { get; init; }
|
||||||
public PropertyUsageFlags Usage { get; init; }
|
|
||||||
public bool Exported { get; init; }
|
|
||||||
|
|
||||||
public PropertyInfo(Variant.Type type, StringName name, PropertyHint hint, string hintString,
|
public PropertyInfo(Variant.Type type, StringName name, PropertyHint hint, string hintString,
|
||||||
PropertyUsageFlags usage, bool exported)
|
PropertyUsageFlags usage, bool exported)
|
||||||
{
|
{
|
||||||
Type = type;
|
Type = type;
|
||||||
Name = name;
|
Name = name;
|
||||||
Hint = hint;
|
Hint = hint;
|
||||||
HintString = hintString;
|
HintString = hintString;
|
||||||
Usage = usage;
|
Usage = usage;
|
||||||
Exported = exported;
|
Exported = exported;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@ -9,7 +10,6 @@ using System.Runtime.CompilerServices;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Loader;
|
using System.Runtime.Loader;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using Godot.Collections;
|
|
||||||
using Godot.NativeInterop;
|
using Godot.NativeInterop;
|
||||||
|
|
||||||
namespace Godot.Bridge
|
namespace Godot.Bridge
|
||||||
@ -337,7 +337,7 @@ namespace Godot.Bridge
|
|||||||
|
|
||||||
*outOwnerIsNull = godot_bool.False;
|
*outOwnerIsNull = godot_bool.False;
|
||||||
|
|
||||||
owner.InternalRaiseEventSignal(CustomUnsafe.AsRef(eventSignalName),
|
owner.RaiseGodotClassSignalCallbacks(CustomUnsafe.AsRef(eventSignalName),
|
||||||
new NativeVariantPtrArgs(args), argCount);
|
new NativeVariantPtrArgs(args), argCount);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -347,151 +347,6 @@ namespace Godot.Bridge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
|
||||||
internal static unsafe void GetScriptSignalList(IntPtr scriptPtr, godot_dictionary* outRetSignals)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Performance is not critical here as this will be replaced with source generators.
|
|
||||||
using var signals = new Dictionary();
|
|
||||||
|
|
||||||
Type? top = _scriptTypeBiMap.GetScriptType(scriptPtr);
|
|
||||||
Type native = Object.InternalGetClassNativeBase(top);
|
|
||||||
|
|
||||||
while (top != null && top != native)
|
|
||||||
{
|
|
||||||
// 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()))
|
|
||||||
{
|
|
||||||
var invokeMethod = signalDelegate.GetMethod("Invoke");
|
|
||||||
|
|
||||||
if (invokeMethod == null)
|
|
||||||
throw new MissingMethodException(signalDelegate.FullName, "Invoke");
|
|
||||||
|
|
||||||
var signalParams = new Collections.Array();
|
|
||||||
|
|
||||||
foreach (var parameters in invokeMethod.GetParameters())
|
|
||||||
{
|
|
||||||
var paramType = Marshaling.ConvertManagedTypeToVariantType(
|
|
||||||
parameters.ParameterType, out bool nilIsVariant);
|
|
||||||
signalParams.Add(new Dictionary()
|
|
||||||
{
|
|
||||||
{ "name", parameters.Name },
|
|
||||||
{ "type", paramType },
|
|
||||||
{ "nil_is_variant", nilIsVariant }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
signals.Add(signalDelegate.Name, signalParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Event signals
|
|
||||||
|
|
||||||
var foundEventSignals = top.GetEvents(
|
|
||||||
BindingFlags.DeclaredOnly | BindingFlags.Instance |
|
|
||||||
BindingFlags.NonPublic | BindingFlags.Public)
|
|
||||||
.Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any())
|
|
||||||
.Select(ev => ev.Name);
|
|
||||||
|
|
||||||
var fields = top.GetFields(
|
|
||||||
BindingFlags.DeclaredOnly | BindingFlags.Instance |
|
|
||||||
BindingFlags.NonPublic | BindingFlags.Public);
|
|
||||||
|
|
||||||
foreach (var eventSignalField in fields
|
|
||||||
.Where(f => typeof(Delegate).IsAssignableFrom(f.FieldType))
|
|
||||||
.Where(f => foundEventSignals.Contains(f.Name)))
|
|
||||||
{
|
|
||||||
var delegateType = eventSignalField.FieldType;
|
|
||||||
var invokeMethod = delegateType.GetMethod("Invoke");
|
|
||||||
|
|
||||||
if (invokeMethod == null)
|
|
||||||
throw new MissingMethodException(delegateType.FullName, "Invoke");
|
|
||||||
|
|
||||||
var signalParams = new Collections.Array();
|
|
||||||
|
|
||||||
foreach (var parameters in invokeMethod.GetParameters())
|
|
||||||
{
|
|
||||||
var paramType = Marshaling.ConvertManagedTypeToVariantType(
|
|
||||||
parameters.ParameterType, out bool nilIsVariant);
|
|
||||||
signalParams.Add(new Dictionary()
|
|
||||||
{
|
|
||||||
{ "name", parameters.Name },
|
|
||||||
{ "type", paramType },
|
|
||||||
{ "nil_is_variant", nilIsVariant }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
signals.Add(eventSignalField.Name, signalParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
top = top.BaseType;
|
|
||||||
}
|
|
||||||
|
|
||||||
*outRetSignals = NativeFuncs.godotsharp_dictionary_new_copy((godot_dictionary)signals.NativeValue);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
ExceptionUtils.LogException(e);
|
|
||||||
*outRetSignals = NativeFuncs.godotsharp_dictionary_new();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
|
||||||
internal static unsafe godot_bool HasScriptSignal(IntPtr scriptPtr, godot_string* signalName)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Performance is not critical here as this will be replaced with source generators.
|
|
||||||
using var signals = new Dictionary();
|
|
||||||
|
|
||||||
string signalNameStr = Marshaling.ConvertStringToManaged(*signalName);
|
|
||||||
|
|
||||||
Type? top = _scriptTypeBiMap.GetScriptType(scriptPtr);
|
|
||||||
Type native = Object.InternalGetClassNativeBase(top);
|
|
||||||
|
|
||||||
while (top != null && top != native)
|
|
||||||
{
|
|
||||||
// Legacy signals
|
|
||||||
|
|
||||||
if (top
|
|
||||||
.GetNestedTypes(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public)
|
|
||||||
.Where(nestedType => typeof(Delegate).IsAssignableFrom(nestedType))
|
|
||||||
.Where(@delegate => @delegate.GetCustomAttributes().OfType<SignalAttribute>().Any())
|
|
||||||
.Any(signalDelegate => signalDelegate.Name == signalNameStr)
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return godot_bool.True;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Event signals
|
|
||||||
|
|
||||||
if (top.GetEvents(
|
|
||||||
BindingFlags.DeclaredOnly | BindingFlags.Instance |
|
|
||||||
BindingFlags.NonPublic | BindingFlags.Public)
|
|
||||||
.Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any())
|
|
||||||
.Any(eventSignal => eventSignal.Name == signalNameStr)
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return godot_bool.True;
|
|
||||||
}
|
|
||||||
|
|
||||||
top = top.BaseType;
|
|
||||||
}
|
|
||||||
|
|
||||||
return godot_bool.False;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
ExceptionUtils.LogException(e);
|
|
||||||
return godot_bool.False;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static godot_bool ScriptIsOrInherits(IntPtr scriptPtr, IntPtr scriptPtrMaybeBase)
|
internal static godot_bool ScriptIsOrInherits(IntPtr scriptPtr, IntPtr scriptPtrMaybeBase)
|
||||||
{
|
{
|
||||||
@ -702,7 +557,7 @@ namespace Godot.Bridge
|
|||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static unsafe void UpdateScriptClassInfo(IntPtr scriptPtr, godot_bool* outTool,
|
internal static unsafe void UpdateScriptClassInfo(IntPtr scriptPtr, godot_bool* outTool,
|
||||||
godot_dictionary* outRpcFunctionsDest, godot_ref* outBaseScript)
|
godot_dictionary* outRpcFunctionsDest, godot_dictionary* outEventSignalsDest, godot_ref* outBaseScript)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -725,7 +580,7 @@ namespace Godot.Bridge
|
|||||||
|
|
||||||
// RPC functions
|
// RPC functions
|
||||||
|
|
||||||
Dictionary<string, Dictionary> rpcFunctions = new();
|
Collections.Dictionary<string, Collections.Dictionary> rpcFunctions = new();
|
||||||
|
|
||||||
Type? top = scriptType;
|
Type? top = scriptType;
|
||||||
Type native = Object.InternalGetClassNativeBase(top);
|
Type native = Object.InternalGetClassNativeBase(top);
|
||||||
@ -749,7 +604,7 @@ namespace Godot.Bridge
|
|||||||
if (rpcAttr == null)
|
if (rpcAttr == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var rpcConfig = new Dictionary();
|
var rpcConfig = new Collections.Dictionary();
|
||||||
|
|
||||||
rpcConfig["rpc_mode"] = (long)rpcAttr.Mode;
|
rpcConfig["rpc_mode"] = (long)rpcAttr.Mode;
|
||||||
rpcConfig["call_local"] = rpcAttr.CallLocal;
|
rpcConfig["call_local"] = rpcAttr.CallLocal;
|
||||||
@ -764,7 +619,54 @@ namespace Godot.Bridge
|
|||||||
|
|
||||||
*outRpcFunctionsDest =
|
*outRpcFunctionsDest =
|
||||||
NativeFuncs.godotsharp_dictionary_new_copy(
|
NativeFuncs.godotsharp_dictionary_new_copy(
|
||||||
(godot_dictionary)((Dictionary)rpcFunctions).NativeValue);
|
(godot_dictionary)((Collections.Dictionary)rpcFunctions).NativeValue);
|
||||||
|
|
||||||
|
// Event signals
|
||||||
|
|
||||||
|
// Performance is not critical here as this will be replaced with source generators.
|
||||||
|
using var signals = new Collections.Dictionary();
|
||||||
|
|
||||||
|
top = scriptType;
|
||||||
|
|
||||||
|
while (top != null && top != native)
|
||||||
|
{
|
||||||
|
var signalList = GetSignalListForType(top);
|
||||||
|
|
||||||
|
if (signalList != null)
|
||||||
|
{
|
||||||
|
foreach (var signal in signalList)
|
||||||
|
{
|
||||||
|
string signalName = signal.Name;
|
||||||
|
|
||||||
|
if (signals.ContainsKey(signalName))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var signalParams = new Collections.Array();
|
||||||
|
|
||||||
|
if (signal.Arguments != null)
|
||||||
|
{
|
||||||
|
foreach (var param in signal.Arguments)
|
||||||
|
{
|
||||||
|
signalParams.Add(new Collections.Dictionary()
|
||||||
|
{
|
||||||
|
{ "name", param.Name },
|
||||||
|
{ "type", param.Type },
|
||||||
|
{ "usage", param.Usage }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signals.Add(signalName, signalParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
top = top.BaseType;
|
||||||
|
}
|
||||||
|
|
||||||
|
*outEventSignalsDest =
|
||||||
|
NativeFuncs.godotsharp_dictionary_new_copy((godot_dictionary)signals.NativeValue);
|
||||||
|
|
||||||
|
// Base script
|
||||||
|
|
||||||
var baseType = scriptType.BaseType;
|
var baseType = scriptType.BaseType;
|
||||||
if (baseType != null && baseType != native)
|
if (baseType != null && baseType != native)
|
||||||
@ -781,41 +683,22 @@ namespace Godot.Bridge
|
|||||||
ExceptionUtils.LogException(e);
|
ExceptionUtils.LogException(e);
|
||||||
*outTool = godot_bool.False;
|
*outTool = godot_bool.False;
|
||||||
*outRpcFunctionsDest = NativeFuncs.godotsharp_dictionary_new();
|
*outRpcFunctionsDest = NativeFuncs.godotsharp_dictionary_new();
|
||||||
|
*outEventSignalsDest = NativeFuncs.godotsharp_dictionary_new();
|
||||||
|
*outBaseScript = default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
private static List<MethodInfo>? GetSignalListForType(Type type)
|
||||||
internal static unsafe godot_bool SwapGCHandleForType(IntPtr oldGCHandlePtr, IntPtr* outNewGCHandlePtr,
|
|
||||||
godot_bool createWeak)
|
|
||||||
{
|
{
|
||||||
try
|
var getGodotSignalListMethod = type.GetMethod(
|
||||||
{
|
"GetGodotSignalList",
|
||||||
var oldGCHandle = GCHandle.FromIntPtr(oldGCHandlePtr);
|
BindingFlags.DeclaredOnly | BindingFlags.Static |
|
||||||
|
BindingFlags.NonPublic | BindingFlags.Public);
|
||||||
|
|
||||||
object? target = oldGCHandle.Target;
|
if (getGodotSignalListMethod == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
if (target == null)
|
return (List<MethodInfo>?)getGodotSignalListMethod.Invoke(null, null);
|
||||||
{
|
|
||||||
CustomGCHandle.Free(oldGCHandle);
|
|
||||||
*outNewGCHandlePtr = IntPtr.Zero;
|
|
||||||
return godot_bool.False; // Called after the managed side was collected, so nothing to do here
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release the current weak handle and replace it with a strong handle.
|
|
||||||
var newGCHandle = createWeak.ToBool() ?
|
|
||||||
CustomGCHandle.AllocWeak(target) :
|
|
||||||
CustomGCHandle.AllocStrong(target);
|
|
||||||
|
|
||||||
CustomGCHandle.Free(oldGCHandle);
|
|
||||||
*outNewGCHandlePtr = GCHandle.ToIntPtr(newGCHandle);
|
|
||||||
return godot_bool.True;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
ExceptionUtils.LogException(e);
|
|
||||||
*outNewGCHandlePtr = IntPtr.Zero;
|
|
||||||
return godot_bool.False;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReSharper disable once InconsistentNaming
|
// ReSharper disable once InconsistentNaming
|
||||||
@ -857,16 +740,16 @@ namespace Godot.Bridge
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var getGodotPropertiesMetadataMethod = type.GetMethod(
|
var getGodotPropertyListMethod = type.GetMethod(
|
||||||
"GetGodotPropertiesMetadata",
|
"GetGodotPropertyList",
|
||||||
BindingFlags.DeclaredOnly | BindingFlags.Static |
|
BindingFlags.DeclaredOnly | BindingFlags.Static |
|
||||||
BindingFlags.NonPublic | BindingFlags.Public);
|
BindingFlags.NonPublic | BindingFlags.Public);
|
||||||
|
|
||||||
if (getGodotPropertiesMetadataMethod == null)
|
if (getGodotPropertyListMethod == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var properties = (System.Collections.Generic.List<PropertyInfo>?)
|
var properties = (List<PropertyInfo>?)
|
||||||
getGodotPropertiesMetadataMethod.Invoke(null, null);
|
getGodotPropertyListMethod.Invoke(null, null);
|
||||||
|
|
||||||
if (properties == null || properties.Count <= 0)
|
if (properties == null || properties.Count <= 0)
|
||||||
return;
|
return;
|
||||||
@ -985,7 +868,7 @@ namespace Godot.Bridge
|
|||||||
if (getGodotPropertyDefaultValuesMethod == null)
|
if (getGodotPropertyDefaultValuesMethod == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var defaultValues = (System.Collections.Generic.Dictionary<StringName, object>?)
|
var defaultValues = (Dictionary<StringName, object>?)
|
||||||
getGodotPropertyDefaultValuesMethod.Invoke(null, null);
|
getGodotPropertyDefaultValuesMethod.Invoke(null, null);
|
||||||
|
|
||||||
if (defaultValues == null || defaultValues.Count <= 0)
|
if (defaultValues == null || defaultValues.Count <= 0)
|
||||||
@ -1048,5 +931,39 @@ namespace Godot.Bridge
|
|||||||
ExceptionUtils.LogException(e);
|
ExceptionUtils.LogException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
internal static unsafe godot_bool SwapGCHandleForType(IntPtr oldGCHandlePtr, IntPtr* outNewGCHandlePtr,
|
||||||
|
godot_bool createWeak)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var oldGCHandle = GCHandle.FromIntPtr(oldGCHandlePtr);
|
||||||
|
|
||||||
|
object? target = oldGCHandle.Target;
|
||||||
|
|
||||||
|
if (target == null)
|
||||||
|
{
|
||||||
|
CustomGCHandle.Free(oldGCHandle);
|
||||||
|
*outNewGCHandlePtr = IntPtr.Zero;
|
||||||
|
return godot_bool.False; // Called after the managed side was collected, so nothing to do here
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release the current weak handle and replace it with a strong handle.
|
||||||
|
var newGCHandle = createWeak.ToBool() ?
|
||||||
|
CustomGCHandle.AllocWeak(target) :
|
||||||
|
CustomGCHandle.AllocStrong(target);
|
||||||
|
|
||||||
|
CustomGCHandle.Free(oldGCHandle);
|
||||||
|
*outNewGCHandlePtr = GCHandle.ToIntPtr(newGCHandle);
|
||||||
|
return godot_bool.True;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
ExceptionUtils.LogException(e);
|
||||||
|
*outNewGCHandlePtr = IntPtr.Zero;
|
||||||
|
return godot_bool.False;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,11 @@ namespace Godot.Collections
|
|||||||
{
|
{
|
||||||
// Always dispose `NativeValue` even if disposing is true
|
// Always dispose `NativeValue` even if disposing is true
|
||||||
NativeValue.DangerousSelfRef.Dispose();
|
NativeValue.DangerousSelfRef.Dispose();
|
||||||
DisposablesTracker.UnregisterDisposable(_weakReferenceToSelf);
|
|
||||||
|
if (_weakReferenceToSelf != null)
|
||||||
|
{
|
||||||
|
DisposablesTracker.UnregisterDisposable(_weakReferenceToSelf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -704,7 +708,7 @@ namespace Godot.Collections
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This is temporary. It's needed for the serialization generator. It won't be needed once we replace Sysme.Object with a Variant type.
|
// TODO: This is temporary. It's needed for the serialization generator. It won't be needed once we replace System.Object with a Variant type.
|
||||||
internal bool TryGetValueAsType<TValueCustom>(TKey key, [MaybeNullWhen(false)] out TValueCustom value)
|
internal bool TryGetValueAsType<TValueCustom>(TKey key, [MaybeNullWhen(false)] out TValueCustom value)
|
||||||
{
|
{
|
||||||
using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key);
|
using godot_variant variantKey = Marshaling.ConvertManagedObjectToVariant(key);
|
||||||
|
@ -62,10 +62,6 @@ namespace Godot.NativeInterop
|
|||||||
internal static extern void godotsharp_internal_refcounted_disposed(IntPtr ptr, IntPtr gcHandleToFree,
|
internal static extern void godotsharp_internal_refcounted_disposed(IntPtr ptr, IntPtr gcHandleToFree,
|
||||||
godot_bool isFinalizer);
|
godot_bool isFinalizer);
|
||||||
|
|
||||||
[DllImport(GodotDllName)]
|
|
||||||
internal static extern void godotsharp_internal_object_connect_event_signal(IntPtr obj,
|
|
||||||
in godot_string_name eventSignal);
|
|
||||||
|
|
||||||
[DllImport(GodotDllName)]
|
[DllImport(GodotDllName)]
|
||||||
internal static extern Error godotsharp_internal_signal_awaiter_connect(IntPtr source,
|
internal static extern Error godotsharp_internal_signal_awaiter_connect(IntPtr source,
|
||||||
in godot_string_name signal,
|
in godot_string_name signal,
|
||||||
|
@ -63,7 +63,11 @@ namespace Godot
|
|||||||
{
|
{
|
||||||
// Always dispose `NativeValue` even if disposing is true
|
// Always dispose `NativeValue` even if disposing is true
|
||||||
NativeValue.DangerousSelfRef.Dispose();
|
NativeValue.DangerousSelfRef.Dispose();
|
||||||
DisposablesTracker.UnregisterDisposable(_weakReferenceToSelf);
|
|
||||||
|
if (_weakReferenceToSelf != null)
|
||||||
|
{
|
||||||
|
DisposablesTracker.UnregisterDisposable(_weakReferenceToSelf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private NodePath(godot_node_path nativeValueToOwn)
|
private NodePath(godot_node_path nativeValueToOwn)
|
||||||
|
@ -49,30 +49,6 @@ namespace Godot
|
|||||||
}
|
}
|
||||||
|
|
||||||
_weakReferenceToSelf = DisposablesTracker.RegisterGodotObject(this);
|
_weakReferenceToSelf = DisposablesTracker.RegisterGodotObject(this);
|
||||||
|
|
||||||
_InitializeGodotScriptInstanceInternals();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void _InitializeGodotScriptInstanceInternals()
|
|
||||||
{
|
|
||||||
// Performance is not critical here as this will be replaced with source generators.
|
|
||||||
Type top = GetType();
|
|
||||||
Type native = InternalGetClassNativeBase(top);
|
|
||||||
|
|
||||||
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()))
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Object(bool memoryOwn)
|
internal Object(bool memoryOwn)
|
||||||
@ -238,72 +214,10 @@ namespace Godot
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void InternalRaiseEventSignal(in godot_string_name eventSignalName, NativeVariantPtrArgs args,
|
// ReSharper disable once VirtualMemberNeverOverridden.Global
|
||||||
int argc)
|
protected internal virtual void RaiseGodotClassSignalCallbacks(in godot_string_name signal,
|
||||||
|
NativeVariantPtrArgs args, int argCount)
|
||||||
{
|
{
|
||||||
// Performance is not critical here as this will be replaced with source generators.
|
|
||||||
|
|
||||||
using var stringName = StringName.CreateTakingOwnershipOfDisposableValue(
|
|
||||||
NativeFuncs.godotsharp_string_name_new_copy(eventSignalName));
|
|
||||||
string eventSignalNameStr = stringName.ToString();
|
|
||||||
|
|
||||||
Type top = GetType();
|
|
||||||
Type native = InternalGetClassNativeBase(top);
|
|
||||||
|
|
||||||
while (top != null && top != native)
|
|
||||||
{
|
|
||||||
var foundEventSignals = top.GetEvents(
|
|
||||||
BindingFlags.DeclaredOnly | BindingFlags.Instance |
|
|
||||||
BindingFlags.NonPublic | BindingFlags.Public)
|
|
||||||
.Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any())
|
|
||||||
.Select(ev => ev.Name);
|
|
||||||
|
|
||||||
var fields = top.GetFields(
|
|
||||||
BindingFlags.DeclaredOnly | BindingFlags.Instance |
|
|
||||||
BindingFlags.NonPublic | BindingFlags.Public);
|
|
||||||
|
|
||||||
var eventSignalField = fields
|
|
||||||
.Where(f => typeof(Delegate).IsAssignableFrom(f.FieldType))
|
|
||||||
.Where(f => foundEventSignals.Contains(f.Name))
|
|
||||||
.FirstOrDefault(f => f.Name == eventSignalNameStr);
|
|
||||||
|
|
||||||
if (eventSignalField != null)
|
|
||||||
{
|
|
||||||
var @delegate = (Delegate)eventSignalField.GetValue(this);
|
|
||||||
|
|
||||||
if (@delegate == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var delegateType = eventSignalField.FieldType;
|
|
||||||
|
|
||||||
var invokeMethod = delegateType.GetMethod("Invoke");
|
|
||||||
|
|
||||||
if (invokeMethod == null)
|
|
||||||
throw new MissingMethodException(delegateType.FullName, "Invoke");
|
|
||||||
|
|
||||||
var parameterInfos = invokeMethod.GetParameters();
|
|
||||||
var paramsLength = parameterInfos.Length;
|
|
||||||
|
|
||||||
if (argc != paramsLength)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(
|
|
||||||
$"The event delegate expects {paramsLength} arguments, but received {argc}.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var managedArgs = new object[argc];
|
|
||||||
|
|
||||||
for (int i = 0; i < argc; i++)
|
|
||||||
{
|
|
||||||
managedArgs[i] = Marshaling.ConvertVariantToManagedObjectOfType(
|
|
||||||
args[i], parameterInfos[i].ParameterType);
|
|
||||||
}
|
|
||||||
|
|
||||||
invokeMethod.Invoke(@delegate, managedArgs);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
top = top.BaseType;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IntPtr ClassDB_get_method(StringName type, StringName method)
|
internal static IntPtr ClassDB_get_method(StringName type, StringName method)
|
||||||
@ -332,74 +246,11 @@ namespace Godot
|
|||||||
|
|
||||||
protected internal virtual void SaveGodotObjectData(GodotSerializationInfo info)
|
protected internal virtual void SaveGodotObjectData(GodotSerializationInfo info)
|
||||||
{
|
{
|
||||||
// Temporary solution via reflection until we add a signals events source generator
|
|
||||||
|
|
||||||
Type top = GetType();
|
|
||||||
Type native = InternalGetClassNativeBase(top);
|
|
||||||
|
|
||||||
while (top != null && top != native)
|
|
||||||
{
|
|
||||||
var foundEventSignals = top.GetEvents(
|
|
||||||
BindingFlags.DeclaredOnly | BindingFlags.Instance |
|
|
||||||
BindingFlags.NonPublic | BindingFlags.Public)
|
|
||||||
.Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any())
|
|
||||||
.Select(ev => ev.Name);
|
|
||||||
|
|
||||||
var fields = top.GetFields(
|
|
||||||
BindingFlags.DeclaredOnly | BindingFlags.Instance |
|
|
||||||
BindingFlags.NonPublic | BindingFlags.Public);
|
|
||||||
|
|
||||||
foreach (var eventSignalField in fields
|
|
||||||
.Where(f => typeof(Delegate).IsAssignableFrom(f.FieldType))
|
|
||||||
.Where(f => foundEventSignals.Contains(f.Name)))
|
|
||||||
{
|
|
||||||
var eventSignalDelegate = (Delegate)eventSignalField.GetValue(this);
|
|
||||||
info.AddSignalEventDelegate(eventSignalField.Name, eventSignalDelegate);
|
|
||||||
}
|
|
||||||
|
|
||||||
top = top.BaseType;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Should this be a constructor overload?
|
// TODO: Should this be a constructor overload?
|
||||||
protected internal virtual void RestoreGodotObjectData(GodotSerializationInfo info)
|
protected internal virtual void RestoreGodotObjectData(GodotSerializationInfo info)
|
||||||
{
|
{
|
||||||
// Temporary solution via reflection until we add a signals events source generator
|
|
||||||
|
|
||||||
void RestoreSignalEvent(StringName signalEventName)
|
|
||||||
{
|
|
||||||
Type top = GetType();
|
|
||||||
Type native = InternalGetClassNativeBase(top);
|
|
||||||
|
|
||||||
while (top != null && top != native)
|
|
||||||
{
|
|
||||||
var foundEventSignal = top.GetEvent(signalEventName,
|
|
||||||
BindingFlags.DeclaredOnly | BindingFlags.Instance |
|
|
||||||
BindingFlags.NonPublic | BindingFlags.Public);
|
|
||||||
|
|
||||||
if (foundEventSignal != null &&
|
|
||||||
foundEventSignal.GetCustomAttributes().OfType<SignalAttribute>().Any())
|
|
||||||
{
|
|
||||||
var field = top.GetField(foundEventSignal.Name,
|
|
||||||
BindingFlags.DeclaredOnly | BindingFlags.Instance |
|
|
||||||
BindingFlags.NonPublic | BindingFlags.Public);
|
|
||||||
|
|
||||||
if (field != null && typeof(Delegate).IsAssignableFrom(field.FieldType))
|
|
||||||
{
|
|
||||||
var eventSignalDelegate = info.GetSignalEventDelegate(signalEventName);
|
|
||||||
field.SetValue(this, eventSignalDelegate);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
top = top.BaseType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var signalEventName in info.GetSignalEventsList())
|
|
||||||
{
|
|
||||||
RestoreSignalEvent(signalEventName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,11 @@ namespace Godot
|
|||||||
{
|
{
|
||||||
// Always dispose `NativeValue` even if disposing is true
|
// Always dispose `NativeValue` even if disposing is true
|
||||||
NativeValue.DangerousSelfRef.Dispose();
|
NativeValue.DangerousSelfRef.Dispose();
|
||||||
DisposablesTracker.UnregisterDisposable(_weakReferenceToSelf);
|
|
||||||
|
if (_weakReferenceToSelf != null)
|
||||||
|
{
|
||||||
|
DisposablesTracker.UnregisterDisposable(_weakReferenceToSelf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private StringName(godot_string_name nativeValueToOwn)
|
private StringName(godot_string_name nativeValueToOwn)
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Core\AABB.cs" />
|
<Compile Include="Core\AABB.cs" />
|
||||||
<Compile Include="Core\Bridge\GodotSerializationInfo.cs" />
|
<Compile Include="Core\Bridge\GodotSerializationInfo.cs" />
|
||||||
|
<Compile Include="Core\Bridge\MethodInfo.cs" />
|
||||||
<Compile Include="Core\CustomGCHandle.cs" />
|
<Compile Include="Core\CustomGCHandle.cs" />
|
||||||
<Compile Include="Core\Array.cs" />
|
<Compile Include="Core\Array.cs" />
|
||||||
<Compile Include="Core\Attributes\AssemblyHasScriptsAttribute.cs" />
|
<Compile Include="Core\Attributes\AssemblyHasScriptsAttribute.cs" />
|
||||||
|
@ -208,13 +208,6 @@ GD_PINVOKE_EXPORT void godotsharp_internal_refcounted_disposed(Object *p_ptr, GC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GD_PINVOKE_EXPORT void godotsharp_internal_object_connect_event_signal(Object *p_ptr, const StringName *p_event_signal) {
|
|
||||||
CSharpInstance *csharp_instance = CAST_CSHARP_INSTANCE(p_ptr->get_script_instance());
|
|
||||||
if (csharp_instance) {
|
|
||||||
csharp_instance->connect_event_signal(*p_event_signal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GD_PINVOKE_EXPORT int32_t godotsharp_internal_signal_awaiter_connect(Object *p_source, StringName *p_signal, Object *p_target, GCHandleIntPtr p_awaiter_handle_ptr) {
|
GD_PINVOKE_EXPORT int32_t godotsharp_internal_signal_awaiter_connect(Object *p_source, StringName *p_signal, Object *p_target, GCHandleIntPtr p_awaiter_handle_ptr) {
|
||||||
StringName signal = p_signal ? *p_signal : StringName();
|
StringName signal = p_signal ? *p_signal : StringName();
|
||||||
return (int32_t)gd_mono_connect_signal_awaiter(p_source, signal, p_target, p_awaiter_handle_ptr);
|
return (int32_t)gd_mono_connect_signal_awaiter(p_source, signal, p_target, p_awaiter_handle_ptr);
|
||||||
@ -1322,7 +1315,7 @@ 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[186] = {
|
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,
|
||||||
@ -1333,7 +1326,6 @@ void *godotsharp_pinvoke_funcs[186] = {
|
|||||||
(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,
|
||||||
(void *)godotsharp_internal_object_connect_event_signal,
|
|
||||||
(void *)godotsharp_internal_signal_awaiter_connect,
|
(void *)godotsharp_internal_signal_awaiter_connect,
|
||||||
(void *)godotsharp_internal_unmanaged_get_script_instance_managed,
|
(void *)godotsharp_internal_unmanaged_get_script_instance_managed,
|
||||||
(void *)godotsharp_internal_unmanaged_get_instance_binding_managed,
|
(void *)godotsharp_internal_unmanaged_get_instance_binding_managed,
|
||||||
|
@ -299,16 +299,6 @@ using godot_plugins_initialize_fn = bool (*)(void *, bool, gdmono::PluginCallbac
|
|||||||
using godot_plugins_initialize_fn = bool (*)(void *, GDMonoCache::ManagedCallbacks *);
|
using godot_plugins_initialize_fn = bool (*)(void *, GDMonoCache::ManagedCallbacks *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static String get_assembly_name() {
|
|
||||||
String appname = ProjectSettings::get_singleton()->get("application/config/name");
|
|
||||||
String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
|
|
||||||
if (appname_safe.is_empty()) {
|
|
||||||
appname_safe = "UnnamedProject";
|
|
||||||
}
|
|
||||||
|
|
||||||
return appname_safe;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime_initialized) {
|
godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime_initialized) {
|
||||||
godot_plugins_initialize_fn godot_plugins_initialize = nullptr;
|
godot_plugins_initialize_fn godot_plugins_initialize = nullptr;
|
||||||
@ -338,6 +328,16 @@ godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime
|
|||||||
return godot_plugins_initialize;
|
return godot_plugins_initialize;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
static String get_assembly_name() {
|
||||||
|
String appname = ProjectSettings::get_singleton()->get("application/config/name");
|
||||||
|
String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
|
||||||
|
if (appname_safe.is_empty()) {
|
||||||
|
appname_safe = "UnnamedProject";
|
||||||
|
}
|
||||||
|
|
||||||
|
return appname_safe;
|
||||||
|
}
|
||||||
|
|
||||||
godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime_initialized) {
|
godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime_initialized) {
|
||||||
godot_plugins_initialize_fn godot_plugins_initialize = nullptr;
|
godot_plugins_initialize_fn godot_plugins_initialize = nullptr;
|
||||||
|
|
||||||
|
@ -60,8 +60,6 @@ void update_godot_api_cache(const ManagedCallbacks &p_managed_callbacks) {
|
|||||||
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, GetScriptNativeName);
|
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, GetScriptNativeName);
|
||||||
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, SetGodotObjectPtr);
|
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, SetGodotObjectPtr);
|
||||||
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, RaiseEventSignal);
|
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, RaiseEventSignal);
|
||||||
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, GetScriptSignalList);
|
|
||||||
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, GetOrCreateScriptBridgeForPath);
|
||||||
|
@ -82,14 +82,12 @@ struct ManagedCallbacks {
|
|||||||
using FuncScriptManagerBridge_GetScriptNativeName = void(GD_CLR_STDCALL *)(const CSharpScript *, StringName *);
|
using FuncScriptManagerBridge_GetScriptNativeName = void(GD_CLR_STDCALL *)(const CSharpScript *, StringName *);
|
||||||
using FuncScriptManagerBridge_SetGodotObjectPtr = void(GD_CLR_STDCALL *)(GCHandleIntPtr, Object *);
|
using FuncScriptManagerBridge_SetGodotObjectPtr = void(GD_CLR_STDCALL *)(GCHandleIntPtr, Object *);
|
||||||
using FuncScriptManagerBridge_RaiseEventSignal = void(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *, const Variant **, int32_t, bool *);
|
using FuncScriptManagerBridge_RaiseEventSignal = void(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *, const Variant **, int32_t, bool *);
|
||||||
using FuncScriptManagerBridge_GetScriptSignalList = void(GD_CLR_STDCALL *)(const CSharpScript *, Dictionary *);
|
|
||||||
using FuncScriptManagerBridge_HasScriptSignal = bool(GD_CLR_STDCALL *)(const CSharpScript *, const String *);
|
|
||||||
using FuncScriptManagerBridge_ScriptIsOrInherits = bool(GD_CLR_STDCALL *)(const CSharpScript *, const CSharpScript *);
|
using FuncScriptManagerBridge_ScriptIsOrInherits = bool(GD_CLR_STDCALL *)(const CSharpScript *, const CSharpScript *);
|
||||||
using FuncScriptManagerBridge_AddScriptBridge = bool(GD_CLR_STDCALL *)(const CSharpScript *, const String *);
|
using FuncScriptManagerBridge_AddScriptBridge = bool(GD_CLR_STDCALL *)(const CSharpScript *, const String *);
|
||||||
using FuncScriptManagerBridge_GetOrCreateScriptBridgeForPath = void(GD_CLR_STDCALL *)(const String *, Ref<CSharpScript> *);
|
using FuncScriptManagerBridge_GetOrCreateScriptBridgeForPath = void(GD_CLR_STDCALL *)(const String *, Ref<CSharpScript> *);
|
||||||
using FuncScriptManagerBridge_RemoveScriptBridge = void(GD_CLR_STDCALL *)(const CSharpScript *);
|
using FuncScriptManagerBridge_RemoveScriptBridge = void(GD_CLR_STDCALL *)(const CSharpScript *);
|
||||||
using FuncScriptManagerBridge_TryReloadRegisteredScriptWithClass = bool(GD_CLR_STDCALL *)(const CSharpScript *);
|
using FuncScriptManagerBridge_TryReloadRegisteredScriptWithClass = bool(GD_CLR_STDCALL *)(const CSharpScript *);
|
||||||
using FuncScriptManagerBridge_UpdateScriptClassInfo = void(GD_CLR_STDCALL *)(const CSharpScript *, bool *, Dictionary *, Ref<CSharpScript> *);
|
using FuncScriptManagerBridge_UpdateScriptClassInfo = void(GD_CLR_STDCALL *)(const CSharpScript *, bool *, Dictionary *, Dictionary *, Ref<CSharpScript> *);
|
||||||
using FuncScriptManagerBridge_SwapGCHandleForType = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, GCHandleIntPtr *, bool);
|
using FuncScriptManagerBridge_SwapGCHandleForType = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, GCHandleIntPtr *, bool);
|
||||||
using FuncScriptManagerBridge_GetPropertyInfoList = void(GD_CLR_STDCALL *)(CSharpScript *, Callback_ScriptManagerBridge_GetPropertyInfoList_Add);
|
using FuncScriptManagerBridge_GetPropertyInfoList = void(GD_CLR_STDCALL *)(CSharpScript *, Callback_ScriptManagerBridge_GetPropertyInfoList_Add);
|
||||||
using FuncScriptManagerBridge_GetPropertyDefaultValues = void(GD_CLR_STDCALL *)(CSharpScript *, Callback_ScriptManagerBridge_GetPropertyDefaultValues_Add);
|
using FuncScriptManagerBridge_GetPropertyDefaultValues = void(GD_CLR_STDCALL *)(CSharpScript *, Callback_ScriptManagerBridge_GetPropertyDefaultValues_Add);
|
||||||
@ -117,8 +115,6 @@ struct ManagedCallbacks {
|
|||||||
FuncScriptManagerBridge_GetScriptNativeName ScriptManagerBridge_GetScriptNativeName;
|
FuncScriptManagerBridge_GetScriptNativeName ScriptManagerBridge_GetScriptNativeName;
|
||||||
FuncScriptManagerBridge_SetGodotObjectPtr ScriptManagerBridge_SetGodotObjectPtr;
|
FuncScriptManagerBridge_SetGodotObjectPtr ScriptManagerBridge_SetGodotObjectPtr;
|
||||||
FuncScriptManagerBridge_RaiseEventSignal ScriptManagerBridge_RaiseEventSignal;
|
FuncScriptManagerBridge_RaiseEventSignal ScriptManagerBridge_RaiseEventSignal;
|
||||||
FuncScriptManagerBridge_GetScriptSignalList ScriptManagerBridge_GetScriptSignalList;
|
|
||||||
FuncScriptManagerBridge_HasScriptSignal ScriptManagerBridge_HasScriptSignal;
|
|
||||||
FuncScriptManagerBridge_ScriptIsOrInherits ScriptManagerBridge_ScriptIsOrInherits;
|
FuncScriptManagerBridge_ScriptIsOrInherits ScriptManagerBridge_ScriptIsOrInherits;
|
||||||
FuncScriptManagerBridge_AddScriptBridge ScriptManagerBridge_AddScriptBridge;
|
FuncScriptManagerBridge_AddScriptBridge ScriptManagerBridge_AddScriptBridge;
|
||||||
FuncScriptManagerBridge_GetOrCreateScriptBridgeForPath ScriptManagerBridge_GetOrCreateScriptBridgeForPath;
|
FuncScriptManagerBridge_GetOrCreateScriptBridgeForPath ScriptManagerBridge_GetOrCreateScriptBridgeForPath;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user