Object.base.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. using System;
  2. using System.Linq;
  3. using System.Reflection;
  4. using Godot.NativeInterop;
  5. namespace Godot
  6. {
  7. public partial class Object : IDisposable
  8. {
  9. private bool _disposed = false;
  10. private Type _cachedType = typeof(Object);
  11. internal IntPtr NativePtr;
  12. private bool _memoryOwn;
  13. private WeakReference<Object> _weakReferenceToSelf;
  14. /// <summary>
  15. /// Constructs a new <see cref="Object"/>.
  16. /// </summary>
  17. public Object() : this(false)
  18. {
  19. if (NativePtr == IntPtr.Zero)
  20. {
  21. unsafe
  22. {
  23. NativePtr = NativeCtor();
  24. }
  25. InteropUtils.TieManagedToUnmanaged(this, NativePtr,
  26. NativeName, refCounted: false, GetType(), _cachedType);
  27. }
  28. else
  29. {
  30. InteropUtils.TieManagedToUnmanagedWithPreSetup(this, NativePtr,
  31. GetType(), _cachedType);
  32. }
  33. _weakReferenceToSelf = DisposablesTracker.RegisterGodotObject(this);
  34. _InitializeGodotScriptInstanceInternals();
  35. }
  36. internal void _InitializeGodotScriptInstanceInternals()
  37. {
  38. // Performance is not critical here as this will be replaced with source generators.
  39. Type top = GetType();
  40. Type native = InternalGetClassNativeBase(top);
  41. while (top != null && top != native)
  42. {
  43. foreach (var eventSignal in top.GetEvents(
  44. BindingFlags.DeclaredOnly | BindingFlags.Instance |
  45. BindingFlags.NonPublic | BindingFlags.Public)
  46. .Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any()))
  47. {
  48. using var eventSignalName = new StringName(eventSignal.Name);
  49. var eventSignalNameSelf = (godot_string_name)eventSignalName.NativeValue;
  50. NativeFuncs.godotsharp_internal_object_connect_event_signal(NativePtr, eventSignalNameSelf);
  51. }
  52. top = top.BaseType;
  53. }
  54. }
  55. internal Object(bool memoryOwn)
  56. {
  57. _memoryOwn = memoryOwn;
  58. }
  59. /// <summary>
  60. /// The pointer to the native instance of this <see cref="Object"/>.
  61. /// </summary>
  62. public IntPtr NativeInstance => NativePtr;
  63. internal static IntPtr GetPtr(Object instance)
  64. {
  65. if (instance == null)
  66. return IntPtr.Zero;
  67. // We check if NativePtr is null because this may be called by the debugger.
  68. // If the debugger puts a breakpoint in one of the base constructors, before
  69. // NativePtr is assigned, that would result in UB or crashes when calling
  70. // native functions that receive the pointer, which can happen because the
  71. // debugger calls ToString() and tries to get the value of properties.
  72. if (instance._disposed || instance.NativePtr == IntPtr.Zero)
  73. throw new ObjectDisposedException(instance.GetType().FullName);
  74. return instance.NativePtr;
  75. }
  76. ~Object()
  77. {
  78. Dispose(false);
  79. }
  80. /// <summary>
  81. /// Disposes of this <see cref="Object"/>.
  82. /// </summary>
  83. public void Dispose()
  84. {
  85. Dispose(true);
  86. GC.SuppressFinalize(this);
  87. }
  88. /// <summary>
  89. /// Disposes implementation of this <see cref="Object"/>.
  90. /// </summary>
  91. protected virtual void Dispose(bool disposing)
  92. {
  93. if (_disposed)
  94. return;
  95. if (NativePtr != IntPtr.Zero)
  96. {
  97. if (_memoryOwn)
  98. {
  99. NativeFuncs.godotsharp_internal_refcounted_disposed(NativePtr, (!disposing).ToGodotBool());
  100. }
  101. else
  102. {
  103. NativeFuncs.godotsharp_internal_object_disposed(NativePtr);
  104. }
  105. NativePtr = IntPtr.Zero;
  106. }
  107. DisposablesTracker.UnregisterGodotObject(_weakReferenceToSelf);
  108. _disposed = true;
  109. }
  110. /// <summary>
  111. /// Converts this <see cref="Object"/> to a string.
  112. /// </summary>
  113. /// <returns>A string representation of this object.</returns>
  114. public override string ToString()
  115. {
  116. NativeFuncs.godotsharp_object_to_string(GetPtr(this), out godot_string str);
  117. using (str)
  118. return Marshaling.ConvertStringToManaged(str);
  119. }
  120. /// <summary>
  121. /// Returns a new <see cref="SignalAwaiter"/> awaiter configured to complete when the instance
  122. /// <paramref name="source"/> emits the signal specified by the <paramref name="signal"/> parameter.
  123. /// </summary>
  124. /// <param name="source">
  125. /// The instance the awaiter will be listening to.
  126. /// </param>
  127. /// <param name="signal">
  128. /// The signal the awaiter will be waiting for.
  129. /// </param>
  130. /// <example>
  131. /// This sample prints a message once every frame up to 100 times.
  132. /// <code>
  133. /// public override void _Ready()
  134. /// {
  135. /// for (int i = 0; i &lt; 100; i++)
  136. /// {
  137. /// await ToSignal(GetTree(), "process_frame");
  138. /// GD.Print($"Frame {i}");
  139. /// }
  140. /// }
  141. /// </code>
  142. /// </example>
  143. /// <returns>
  144. /// A <see cref="SignalAwaiter"/> that completes when
  145. /// <paramref name="source"/> emits the <paramref name="signal"/>.
  146. /// </returns>
  147. public SignalAwaiter ToSignal(Object source, StringName signal)
  148. {
  149. return new SignalAwaiter(source, signal, this);
  150. }
  151. internal static Type InternalGetClassNativeBase(Type t)
  152. {
  153. do
  154. {
  155. var assemblyName = t.Assembly.GetName();
  156. if (assemblyName.Name == "GodotSharp")
  157. return t;
  158. if (assemblyName.Name == "GodotSharpEditor")
  159. return t;
  160. } while ((t = t.BaseType) != null);
  161. return null;
  162. }
  163. internal static bool InternalIsClassNativeBase(Type t)
  164. {
  165. var assemblyName = t.Assembly.GetName();
  166. return assemblyName.Name == "GodotSharp" || assemblyName.Name == "GodotSharpEditor";
  167. }
  168. // ReSharper disable once VirtualMemberNeverOverridden.Global
  169. protected internal virtual bool SetGodotClassPropertyValue(in godot_string_name name, in godot_variant value)
  170. {
  171. return false;
  172. }
  173. // ReSharper disable once VirtualMemberNeverOverridden.Global
  174. protected internal virtual bool GetGodotClassPropertyValue(in godot_string_name name, out godot_variant value)
  175. {
  176. value = default;
  177. return false;
  178. }
  179. internal void InternalRaiseEventSignal(in godot_string_name eventSignalName, NativeVariantPtrArgs args,
  180. int argc)
  181. {
  182. // Performance is not critical here as this will be replaced with source generators.
  183. using var stringName = StringName.CreateTakingOwnershipOfDisposableValue(
  184. NativeFuncs.godotsharp_string_name_new_copy(eventSignalName));
  185. string eventSignalNameStr = stringName.ToString();
  186. Type top = GetType();
  187. Type native = InternalGetClassNativeBase(top);
  188. while (top != null && top != native)
  189. {
  190. var foundEventSignals = top.GetEvents(
  191. BindingFlags.DeclaredOnly | BindingFlags.Instance |
  192. BindingFlags.NonPublic | BindingFlags.Public)
  193. .Where(ev => ev.GetCustomAttributes().OfType<SignalAttribute>().Any())
  194. .Select(ev => ev.Name);
  195. var fields = top.GetFields(
  196. BindingFlags.DeclaredOnly | BindingFlags.Instance |
  197. BindingFlags.NonPublic | BindingFlags.Public);
  198. var eventSignalField = fields
  199. .Where(f => typeof(Delegate).IsAssignableFrom(f.FieldType))
  200. .Where(f => foundEventSignals.Contains(f.Name))
  201. .FirstOrDefault(f => f.Name == eventSignalNameStr);
  202. if (eventSignalField != null)
  203. {
  204. var @delegate = (Delegate)eventSignalField.GetValue(this);
  205. if (@delegate == null)
  206. continue;
  207. var delegateType = eventSignalField.FieldType;
  208. var invokeMethod = delegateType.GetMethod("Invoke");
  209. if (invokeMethod == null)
  210. throw new MissingMethodException(delegateType.FullName, "Invoke");
  211. var parameterInfos = invokeMethod.GetParameters();
  212. var paramsLength = parameterInfos.Length;
  213. if (argc != paramsLength)
  214. {
  215. throw new InvalidOperationException(
  216. $"The event delegate expects {paramsLength} arguments, but received {argc}.");
  217. }
  218. var managedArgs = new object[argc];
  219. for (int i = 0; i < argc; i++)
  220. {
  221. managedArgs[i] = Marshaling.ConvertVariantToManagedObjectOfType(
  222. args[i], parameterInfos[i].ParameterType);
  223. }
  224. invokeMethod.Invoke(@delegate, managedArgs);
  225. return;
  226. }
  227. top = top.BaseType;
  228. }
  229. }
  230. internal static IntPtr ClassDB_get_method(StringName type, StringName method)
  231. {
  232. var typeSelf = (godot_string_name)type.NativeValue;
  233. var methodSelf = (godot_string_name)method.NativeValue;
  234. IntPtr methodBind = NativeFuncs.godotsharp_method_bind_get_method(typeSelf, methodSelf);
  235. if (methodBind == IntPtr.Zero)
  236. throw new NativeMethodBindNotFoundException(type + "." + method);
  237. return methodBind;
  238. }
  239. internal static unsafe delegate* unmanaged<IntPtr> ClassDB_get_constructor(StringName type)
  240. {
  241. // for some reason the '??' operator doesn't support 'delegate*'
  242. var typeSelf = (godot_string_name)type.NativeValue;
  243. var nativeConstructor = NativeFuncs.godotsharp_get_class_constructor(typeSelf);
  244. if (nativeConstructor == null)
  245. throw new NativeConstructorNotFoundException(type);
  246. return nativeConstructor;
  247. }
  248. }
  249. }