NodePath.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. using System;
  2. using System.Runtime.CompilerServices;
  3. namespace Godot
  4. {
  5. /// <summary>
  6. /// A pre-parsed relative or absolute path in a scene tree,
  7. /// for use with <see cref="Node.GetNode(NodePath)"/> and similar functions.
  8. /// It can reference a node, a resource within a node, or a property
  9. /// of a node or resource.
  10. /// For instance, <c>"Path2D/PathFollow2D/Sprite2D:texture:size"</c>
  11. /// would refer to the <c>size</c> property of the <c>texture</c>
  12. /// resource on the node named <c>"Sprite2D"</c> which is a child of
  13. /// the other named nodes in the path.
  14. /// You will usually just pass a string to <see cref="Node.GetNode(NodePath)"/>
  15. /// and it will be automatically converted, but you may occasionally
  16. /// want to parse a path ahead of time with NodePath.
  17. /// Exporting a NodePath variable will give you a node selection widget
  18. /// in the properties panel of the editor, which can often be useful.
  19. /// A NodePath is composed of a list of slash-separated node names
  20. /// (like a filesystem path) and an optional colon-separated list of
  21. /// "subnames" which can be resources or properties.
  22. ///
  23. /// Note: In the editor, NodePath properties are automatically updated when moving,
  24. /// renaming or deleting a node in the scene tree, but they are never updated at runtime.
  25. /// </summary>
  26. /// <example>
  27. /// Some examples of NodePaths include the following:
  28. /// <code>
  29. /// // No leading slash means it is relative to the current node.
  30. /// new NodePath("A"); // Immediate child A.
  31. /// new NodePath("A/B"); // A's child B.
  32. /// new NodePath("."); // The current node.
  33. /// new NodePath(".."); // The parent node.
  34. /// new NodePath("../C"); // A sibling node C.
  35. /// // A leading slash means it is absolute from the SceneTree.
  36. /// new NodePath("/root"); // Equivalent to GetTree().Root
  37. /// new NodePath("/root/Main"); // If your main scene's root node were named "Main".
  38. /// new NodePath("/root/MyAutoload"); // If you have an autoloaded node or scene.
  39. /// </code>
  40. /// </example>
  41. public sealed partial class NodePath : IDisposable
  42. {
  43. private bool _disposed = false;
  44. private IntPtr ptr;
  45. internal static IntPtr GetPtr(NodePath instance)
  46. {
  47. if (instance == null)
  48. throw new NullReferenceException($"The instance of type {nameof(NodePath)} is null.");
  49. if (instance._disposed)
  50. throw new ObjectDisposedException(instance.GetType().FullName);
  51. return instance.ptr;
  52. }
  53. ~NodePath()
  54. {
  55. Dispose(false);
  56. }
  57. /// <summary>
  58. /// Disposes of this <see cref="NodePath"/>.
  59. /// </summary>
  60. public void Dispose()
  61. {
  62. Dispose(true);
  63. GC.SuppressFinalize(this);
  64. }
  65. private void Dispose(bool disposing)
  66. {
  67. if (_disposed)
  68. return;
  69. if (ptr != IntPtr.Zero)
  70. {
  71. godot_icall_NodePath_Dtor(ptr);
  72. ptr = IntPtr.Zero;
  73. }
  74. _disposed = true;
  75. }
  76. internal NodePath(IntPtr ptr)
  77. {
  78. this.ptr = ptr;
  79. }
  80. /// <summary>
  81. /// Constructs an empty <see cref="NodePath"/>.
  82. /// </summary>
  83. public NodePath() : this(string.Empty) { }
  84. /// <summary>
  85. /// Constructs a <see cref="NodePath"/> from a string <paramref name="path"/>,
  86. /// e.g.: <c>"Path2D/PathFollow2D/Sprite2D:texture:size"</c>.
  87. /// A path is absolute if it starts with a slash. Absolute paths
  88. /// are only valid in the global scene tree, not within individual
  89. /// scenes. In a relative path, <c>"."</c> and <c>".."</c> indicate
  90. /// the current node and its parent.
  91. /// The "subnames" optionally included after the path to the target
  92. /// node can point to resources or properties, and can also be nested.
  93. /// </summary>
  94. /// <example>
  95. /// Examples of valid NodePaths (assuming that those nodes exist and
  96. /// have the referenced resources or properties):
  97. /// <code>
  98. /// // Points to the Sprite2D node.
  99. /// "Path2D/PathFollow2D/Sprite2D"
  100. /// // Points to the Sprite2D node and its "texture" resource.
  101. /// // GetNode() would retrieve "Sprite2D", while GetNodeAndResource()
  102. /// // would retrieve both the Sprite2D node and the "texture" resource.
  103. /// "Path2D/PathFollow2D/Sprite2D:texture"
  104. /// // Points to the Sprite2D node and its "position" property.
  105. /// "Path2D/PathFollow2D/Sprite2D:position"
  106. /// // Points to the Sprite2D node and the "x" component of its "position" property.
  107. /// "Path2D/PathFollow2D/Sprite2D:position:x"
  108. /// // Absolute path (from "root")
  109. /// "/root/Level/Path2D"
  110. /// </code>
  111. /// </example>
  112. /// <param name="path"></param>
  113. public NodePath(string path)
  114. {
  115. ptr = godot_icall_NodePath_Ctor(path);
  116. }
  117. /// <summary>
  118. /// Converts a string to a <see cref="NodePath"/>.
  119. /// </summary>
  120. /// <param name="from">The string to convert.</param>
  121. public static implicit operator NodePath(string from) => new NodePath(from);
  122. /// <summary>
  123. /// Converts this <see cref="NodePath"/> to a string.
  124. /// </summary>
  125. /// <param name="from">The <see cref="NodePath"/> to convert.</param>
  126. public static implicit operator string(NodePath from) => from.ToString();
  127. /// <summary>
  128. /// Converts this <see cref="NodePath"/> to a string.
  129. /// </summary>
  130. /// <returns>A string representation of this <see cref="NodePath"/>.</returns>
  131. public override string ToString()
  132. {
  133. return godot_icall_NodePath_operator_String(GetPtr(this));
  134. }
  135. /// <summary>
  136. /// Returns a node path with a colon character (<c>:</c>) prepended,
  137. /// transforming it to a pure property path with no node name (defaults
  138. /// to resolving from the current node).
  139. /// </summary>
  140. /// <example>
  141. /// <code>
  142. /// // This will be parsed as a node path to the "x" property in the "position" node.
  143. /// var nodePath = new NodePath("position:x");
  144. /// // This will be parsed as a node path to the "x" component of the "position" property in the current node.
  145. /// NodePath propertyPath = nodePath.GetAsPropertyPath();
  146. /// GD.Print(propertyPath); // :position:x
  147. /// </code>
  148. /// </example>
  149. /// <returns>The <see cref="NodePath"/> as a pure property path.</returns>
  150. public NodePath GetAsPropertyPath()
  151. {
  152. return new NodePath(godot_icall_NodePath_get_as_property_path(GetPtr(this)));
  153. }
  154. /// <summary>
  155. /// Returns all subnames concatenated with a colon character (<c>:</c>)
  156. /// as separator, i.e. the right side of the first colon in a node path.
  157. /// </summary>
  158. /// <example>
  159. /// <code>
  160. /// var nodepath = new NodePath("Path2D/PathFollow2D/Sprite2D:texture:load_path");
  161. /// GD.Print(nodepath.GetConcatenatedSubnames()); // texture:load_path
  162. /// </code>
  163. /// </example>
  164. /// <returns>The subnames concatenated with <c>:</c>.</returns>
  165. public string GetConcatenatedSubnames()
  166. {
  167. return godot_icall_NodePath_get_concatenated_subnames(GetPtr(this));
  168. }
  169. /// <summary>
  170. /// Gets the node name indicated by <paramref name="idx"/> (0 to <see cref="GetNameCount"/>).
  171. /// </summary>
  172. /// <example>
  173. /// <code>
  174. /// var nodePath = new NodePath("Path2D/PathFollow2D/Sprite2D");
  175. /// GD.Print(nodePath.GetName(0)); // Path2D
  176. /// GD.Print(nodePath.GetName(1)); // PathFollow2D
  177. /// GD.Print(nodePath.GetName(2)); // Sprite
  178. /// </code>
  179. /// </example>
  180. /// <param name="idx">The name index.</param>
  181. /// <returns>The name at the given index <paramref name="idx"/>.</returns>
  182. public string GetName(int idx)
  183. {
  184. return godot_icall_NodePath_get_name(GetPtr(this), idx);
  185. }
  186. /// <summary>
  187. /// Gets the number of node names which make up the path.
  188. /// Subnames (see <see cref="GetSubnameCount"/>) are not included.
  189. /// For example, <c>"Path2D/PathFollow2D/Sprite2D"</c> has 3 names.
  190. /// </summary>
  191. /// <returns>The number of node names which make up the path.</returns>
  192. public int GetNameCount()
  193. {
  194. return godot_icall_NodePath_get_name_count(GetPtr(this));
  195. }
  196. /// <summary>
  197. /// Gets the resource or property name indicated by <paramref name="idx"/> (0 to <see cref="GetSubnameCount"/>).
  198. /// </summary>
  199. /// <param name="idx">The subname index.</param>
  200. /// <returns>The subname at the given index <paramref name="idx"/>.</returns>
  201. public string GetSubname(int idx)
  202. {
  203. return godot_icall_NodePath_get_subname(GetPtr(this), idx);
  204. }
  205. /// <summary>
  206. /// Gets the number of resource or property names ("subnames") in the path.
  207. /// Each subname is listed after a colon character (<c>:</c>) in the node path.
  208. /// For example, <c>"Path2D/PathFollow2D/Sprite2D:texture:load_path"</c> has 2 subnames.
  209. /// </summary>
  210. /// <returns>The number of subnames in the path.</returns>
  211. public int GetSubnameCount()
  212. {
  213. return godot_icall_NodePath_get_subname_count(GetPtr(this));
  214. }
  215. /// <summary>
  216. /// Returns <see langword="true"/> if the node path is absolute (as opposed to relative),
  217. /// which means that it starts with a slash character (<c>/</c>). Absolute node paths can
  218. /// be used to access the root node (<c>"/root"</c>) or autoloads (e.g. <c>"/global"</c>
  219. /// if a "global" autoload was registered).
  220. /// </summary>
  221. /// <returns>If the <see cref="NodePath"/> is an absolute path.</returns>
  222. public bool IsAbsolute()
  223. {
  224. return godot_icall_NodePath_is_absolute(GetPtr(this));
  225. }
  226. /// <summary>
  227. /// Returns <see langword="true"/> if the node path is empty.
  228. /// </summary>
  229. /// <returns>If the <see cref="NodePath"/> is empty.</returns>
  230. public bool IsEmpty()
  231. {
  232. return godot_icall_NodePath_is_empty(GetPtr(this));
  233. }
  234. [MethodImpl(MethodImplOptions.InternalCall)]
  235. private static extern IntPtr godot_icall_NodePath_Ctor(string path);
  236. [MethodImpl(MethodImplOptions.InternalCall)]
  237. private static extern void godot_icall_NodePath_Dtor(IntPtr ptr);
  238. [MethodImpl(MethodImplOptions.InternalCall)]
  239. private static extern string godot_icall_NodePath_operator_String(IntPtr ptr);
  240. [MethodImpl(MethodImplOptions.InternalCall)]
  241. private static extern IntPtr godot_icall_NodePath_get_as_property_path(IntPtr ptr);
  242. [MethodImpl(MethodImplOptions.InternalCall)]
  243. private static extern string godot_icall_NodePath_get_concatenated_subnames(IntPtr ptr);
  244. [MethodImpl(MethodImplOptions.InternalCall)]
  245. private static extern string godot_icall_NodePath_get_name(IntPtr ptr, int arg1);
  246. [MethodImpl(MethodImplOptions.InternalCall)]
  247. private static extern int godot_icall_NodePath_get_name_count(IntPtr ptr);
  248. [MethodImpl(MethodImplOptions.InternalCall)]
  249. private static extern string godot_icall_NodePath_get_subname(IntPtr ptr, int arg1);
  250. [MethodImpl(MethodImplOptions.InternalCall)]
  251. private static extern int godot_icall_NodePath_get_subname_count(IntPtr ptr);
  252. [MethodImpl(MethodImplOptions.InternalCall)]
  253. private static extern bool godot_icall_NodePath_is_absolute(IntPtr ptr);
  254. [MethodImpl(MethodImplOptions.InternalCall)]
  255. private static extern bool godot_icall_NodePath_is_empty(IntPtr ptr);
  256. }
  257. }