-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #18 from theowiik/get-node-unique
Add GetUniqueNode attribute
- Loading branch information
Showing
4 changed files
with
110 additions
and
50 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
using System.Reflection; | ||
using Godot; | ||
using GodotSharper.Exceptions; | ||
|
||
namespace GodotSharper.AutoGetNode; | ||
|
||
public abstract class BaseGetNode : Attribute | ||
{ | ||
private readonly string _nodeIdentifier; | ||
|
||
protected BaseGetNode(string nodeIdentifier) | ||
{ | ||
_nodeIdentifier = nodeIdentifier; | ||
} | ||
|
||
/// <summary> | ||
/// Sets the node specified by the attribute on the given member of the provided node. | ||
/// </summary> | ||
/// <param name="memberInfo">The member to set the node on.</param> | ||
/// <param name="node">The node to get the child node from.</param> | ||
/// <exception cref="NodeNotFoundException">Thrown if the child node cannot be found.</exception> | ||
/// <exception cref="ArgumentException">Thrown if the child node is not of the expected type.</exception> | ||
public void SetNode(MemberInfo memberInfo, Node node) | ||
{ | ||
var childNode = GetNode(node, _nodeIdentifier); | ||
|
||
if (childNode == null) | ||
{ | ||
node.GetTree().Quit(); | ||
throw new NodeNotFoundException($"Cannot find Node for NodePath '{_nodeIdentifier}'"); | ||
} | ||
|
||
var expectedType = memberInfo is FieldInfo fieldInfo | ||
? fieldInfo.FieldType | ||
: ((PropertyInfo)memberInfo).PropertyType; | ||
|
||
if (childNode.GetType() != expectedType && !childNode.GetType().IsSubclassOf(expectedType)) | ||
{ | ||
node.GetTree().Quit(); | ||
throw new ArgumentException( | ||
$"Node is not a valid type. Expected {expectedType} got {childNode.GetType()}" | ||
); | ||
} | ||
|
||
switch (memberInfo) | ||
{ | ||
case FieldInfo fieldInformation: | ||
fieldInformation.SetValue(node, childNode); | ||
break; | ||
case PropertyInfo propertyInformation: | ||
propertyInformation.SetValue(node, childNode); | ||
break; | ||
default: | ||
throw new ArgumentException( | ||
$"MemberInfo is not a valid type. Expected {nameof(FieldInfo)} or {nameof(PropertyInfo)} got {memberInfo.GetType()}" | ||
); | ||
} | ||
} | ||
|
||
protected abstract Node GetNode(Node node, string path); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,63 +1,19 @@ | ||
using System.Reflection; | ||
using Godot; | ||
using GodotSharper.Exceptions; | ||
using Godot; | ||
|
||
namespace GodotSharper.AutoGetNode; | ||
|
||
/// <summary> | ||
/// Attribute used to automatically get a node from the scene tree. | ||
/// Attribute used to automatically get a node from the scene tree via the path to the Node. | ||
/// </summary> | ||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] | ||
public sealed class GetNodeAttribute : Attribute | ||
public sealed class GetNodeAttribute : BaseGetNode | ||
{ | ||
private readonly string _path; | ||
|
||
public GetNodeAttribute(string nodePath) | ||
public GetNodeAttribute(string nodeNodeIdentifier) : base(nodeNodeIdentifier) | ||
{ | ||
_path = nodePath; | ||
} | ||
|
||
/// <summary> | ||
/// Sets the node specified by the attribute on the given member of the provided node. | ||
/// </summary> | ||
/// <param name="memberInfo">The member to set the node on.</param> | ||
/// <param name="node">The node to get the child node from.</param> | ||
/// <exception cref="NodeNotFoundException">Thrown if the child node cannot be found.</exception> | ||
/// <exception cref="ArgumentException">Thrown if the child node is not of the expected type.</exception> | ||
public void SetNode(MemberInfo memberInfo, Node node) | ||
protected override Node GetNode(Node node, string path) | ||
{ | ||
var childNode = node.GetNodeOrNull(_path); | ||
|
||
if (childNode == null) | ||
{ | ||
node.GetTree().Quit(); | ||
throw new NodeNotFoundException($"Cannot find Node for NodePath '{_path}'"); | ||
} | ||
|
||
var expectedType = memberInfo is FieldInfo fieldInfo | ||
? fieldInfo.FieldType | ||
: ((PropertyInfo)memberInfo).PropertyType; | ||
|
||
if (childNode.GetType() != expectedType && !childNode.GetType().IsSubclassOf(expectedType)) | ||
{ | ||
node.GetTree().Quit(); | ||
throw new ArgumentException( | ||
$"Node is not a valid type. Expected {expectedType} got {childNode.GetType()}" | ||
); | ||
} | ||
|
||
switch (memberInfo) | ||
{ | ||
case FieldInfo fieldInformation: | ||
fieldInformation.SetValue(node, childNode); | ||
break; | ||
case PropertyInfo propertyInformation: | ||
propertyInformation.SetValue(node, childNode); | ||
break; | ||
default: | ||
throw new ArgumentException( | ||
$"MemberInfo is not a valid type. Expected {nameof(FieldInfo)} or {nameof(PropertyInfo)} got {memberInfo.GetType()}" | ||
); | ||
} | ||
return node.GetNodeOrNull(path); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
using Godot; | ||
|
||
namespace GodotSharper.AutoGetNode; | ||
|
||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] | ||
public sealed class GetUniqueNodeAttribute : BaseGetNode | ||
{ | ||
public GetUniqueNodeAttribute(string path) : base(path) | ||
{ | ||
} | ||
|
||
/// <summary> | ||
/// Recursively searches for a child node with the given path, starting from the given node. | ||
/// </summary> | ||
/// <param name="node">The node to start the search from.</param> | ||
/// <param name="path">The path of the child node to search for.</param> | ||
/// <returns>The child node with the given path, or null if it was not found.</returns> | ||
protected override Node GetNode(Node node, string path) | ||
{ | ||
var directChild = node.GetNodeOrNull(path); | ||
if (directChild != null) | ||
return directChild; | ||
|
||
var children = node.GetChildren(); | ||
|
||
// Base case | ||
if (!children.Any()) | ||
return null; | ||
|
||
foreach (var c in children) | ||
{ | ||
var childNode = GetNode(c, path); | ||
|
||
if (childNode != null) | ||
return childNode; | ||
} | ||
|
||
return null; | ||
} | ||
} |