commit 8f1ce37f3b2aae237d9995f7ecc30577fc0dd8f0 Author: Josef Date: Sat May 4 10:26:16 2024 +0200 Initial Commit diff --git a/Runtime/Actions/ActionList.cs b/Runtime/Actions/ActionList.cs new file mode 100644 index 0000000..2c2fb47 --- /dev/null +++ b/Runtime/Actions/ActionList.cs @@ -0,0 +1,26 @@ + +using Godot; + + +namespace Rokojori +{ + [GlobalClass] + public partial class ActionList : RJAction + { + [Export] + public RJAction[] actions; + [Export] + public bool triggerDirectChildren = true; + + protected override void _OnTrigger() + { + for ( int i = 0; i < actions.Length; i++ ) + { + Actions.Trigger( actions[ i ] ); + } + + + + } + } +} \ No newline at end of file diff --git a/Runtime/Actions/Actions.cs b/Runtime/Actions/Actions.cs new file mode 100644 index 0000000..51e522a --- /dev/null +++ b/Runtime/Actions/Actions.cs @@ -0,0 +1,19 @@ + +using Godot; + + +namespace Rokojori +{ + public class Actions + { + public static Trigger( RJAction action ) + { + if ( action == null ) + { + return; + } + + action.Trigger(); + } + } +} \ No newline at end of file diff --git a/Runtime/Events/EventProperty.cs b/Runtime/Events/EventProperty.cs new file mode 100644 index 0000000..277a701 --- /dev/null +++ b/Runtime/Events/EventProperty.cs @@ -0,0 +1,74 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System; +using System.Linq; + + +namespace Rokojori +{ + + public class ReadonlyEventProperty: EventSlot + { + protected T _value; + public T value + { + get { return _value; } + protected set { } + } + } + + public class EventProperty:ReadonlyEventProperty + { + public new T value + { + get { return _value; } + set + { + if ( IsEqual( _value, value ) ) + { + return; + } + + _value = value; + DispatchEvent(); + } + } + + public virtual void DispatchEvent() + { + _actions.ForEach( a => { if ( a != null ){ a( _value ); } } ); + + _ClearOnceActions(); + + } + + + protected bool IsEqual( T oldValue, T newValue ) + { + if ( oldValue == null && newValue == null ) + { + return true; + } + + if ( oldValue == null || newValue == null ) + { + return false; + } + + if ( EqualityComparer.Default.Equals( oldValue , newValue ) ) + { + return true; + } + + return false; + } + + public void SetSilent( T value ) + { + _value = value; + } + } + + +} diff --git a/Runtime/Events/EventSlot.cs b/Runtime/Events/EventSlot.cs new file mode 100644 index 0000000..41c3a56 --- /dev/null +++ b/Runtime/Events/EventSlot.cs @@ -0,0 +1,48 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System; +using System.Linq; + + +namespace Rokojori +{ + public class EventSlot + { + protected List> _actions = new List>(); + List> _once = new List>(); + + public bool hasListeners => _once.Count > 0 || _actions.Count > 0; + + public void AddAction( Action action ) + { + _actions.Add( action ); + } + + public void RemoveAction( Action action ) + { + _actions.Remove( action ); + } + + public void Once( Action action ) + { + _actions.Add( action ); + _once.Add( action ); + } + + protected void _ClearOnceActions() + { + _once.ForEach( a => { _actions.Remove( a ); } ); + _once.Clear(); + } + + public void DispatchEvent( T t ) + { + _actions.ForEach( a => { if ( a != null ){ a( t ); } } ); + + _ClearOnceActions(); + + } + } + +} diff --git a/Runtime/Events/Null.cs b/Runtime/Events/Null.cs new file mode 100644 index 0000000..038a736 --- /dev/null +++ b/Runtime/Events/Null.cs @@ -0,0 +1,15 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System; +using System.Linq; + + +namespace Rokojori +{ + public class Null + { + private Null(){} + } + +} \ No newline at end of file diff --git a/Runtime/Godot/HierarchyName.cs b/Runtime/Godot/HierarchyName.cs new file mode 100644 index 0000000..9a80531 --- /dev/null +++ b/Runtime/Godot/HierarchyName.cs @@ -0,0 +1,45 @@ +using Godot; +using System.Text; +using System.Collections.Generic; + +namespace Rokojori +{ + public class HierarchyName + { + public static string Of( Node node, string seperator = "/" ) + { + if ( node == null ) + { + return "null"; + } + + var list = new List(); + + var it = node; + + while ( it != null ) + { + list.Add( it.Name ); + it = it.GetParent(); + } + + list.Reverse(); + + + var sb = new StringBuilder(); + + for ( int i = 0; i < list.Count; i++) + { + if ( i != 0 ) + { + sb.Append( seperator ); + } + + sb.Append( list[ i ] ); + } + + return sb.ToString(); + } + } + +} diff --git a/Runtime/Godot/Nodes.cs b/Runtime/Godot/Nodes.cs new file mode 100644 index 0000000..2c2992b --- /dev/null +++ b/Runtime/Godot/Nodes.cs @@ -0,0 +1,73 @@ +using Godot; + + +namespace Rokojori +{ + public class Nodes + { + public static T GetSibling( Node node ) where T:Node + { + if ( node == null ) + { + return null; + } + + var parent = node.GetParent(); + + if ( parent == null ) + { + return null; + } + + return GetDirectChild( parent ); + } + + public static T GetDirectChild( Node parent ) where T:Node + { + if ( parent == null ) + { + return null; + } + + var numChildren = parent.GetChildCount(); + + for ( int i = 0; i < numChildren; i++ ) + { + var node = parent.GetChild( i ); + + if ( node is T ) + { + return (T)node; + } + } + + return null; + } + + static NodesWalker nodesWalker = new NodesWalker(); + + public static T GetAnyChild( Node parent ) where T:Node + { + return (T) nodesWalker.Find( parent, ( n )=> n is T, true ); + } + + public static void Enable( Node n, bool affectProcess = true, bool affectPhysicsProcess = true, bool affectInput = true ) + { + SetState.SetStateOfNode( NodeStateType.Enabled, n, affectProcess, affectPhysicsProcess, affectInput ); + } + + public static void Disable( Node n, bool affectProcess = true, bool affectPhysicsProcess = true, bool affectInput = true ) + { + SetState.SetStateOfNode( NodeStateType.Disabled, n, affectProcess, affectPhysicsProcess, affectInput ); + } + + public static void Iterate( Node[] nodes, System.Action callback ) + { + for ( int i = 0; i < nodes.Length; i++ ) + { + nodesWalker.Iterate( nodes[ i ], callback ); + } + } + } + +} diff --git a/Runtime/Godot/NodesWalker.cs b/Runtime/Godot/NodesWalker.cs new file mode 100644 index 0000000..d84a848 --- /dev/null +++ b/Runtime/Godot/NodesWalker.cs @@ -0,0 +1,44 @@ +using Godot; + + +namespace Rokojori +{ + public class NodesWalker: TreeWalker + { + static NodesWalker _singleton = new NodesWalker(); + public static NodesWalker Get() + { + return _singleton; + } + + public override Node Parent( Node n ) + { + if ( n == null ) + { + return null; + } + + return n.GetParent(); + } + + public override Node ChildAt( Node n, int index ) + { + if ( n == null ) + { + return null; + } + + return n.GetChild( index ); + } + + public override int NumChildren( Node n ) + { + if ( n == null ) + { + return 0; + } + + return n.GetChildCount(); + } + } +} \ No newline at end of file diff --git a/Runtime/Godot/Root.cs b/Runtime/Godot/Root.cs new file mode 100644 index 0000000..6a15395 --- /dev/null +++ b/Runtime/Godot/Root.cs @@ -0,0 +1,31 @@ +using Godot; + + +namespace Rokojori +{ + public partial class Root:Node + { + private static Root _singleton; + + public override void _Ready() + { + _singleton = this; + } + + public static SceneTree Tree() + { + return _singleton.GetTree(); + } + + public static Window Window() + { + return Tree().Root; + } + + public static Root Get() + { + var r = Window(); + return _singleton; + } + } +} \ No newline at end of file diff --git a/Runtime/Godot/Unique.cs b/Runtime/Godot/Unique.cs new file mode 100644 index 0000000..9c18488 --- /dev/null +++ b/Runtime/Godot/Unique.cs @@ -0,0 +1,24 @@ +using System.Collections; +using System.Collections.Generic; + +using Godot; + +namespace Rokojori +{ + public class Unique where N:Node + { + private static N _singleton; + + public static N Get() + { + if ( _singleton != null ) + { + return _singleton; + } + + _singleton = Nodes.GetAnyChild( Root.Window() ); + + return _singleton; + } + } +} \ No newline at end of file diff --git a/Runtime/Graphs/Trees/Iterators/ChildrenIterator.cs b/Runtime/Graphs/Trees/Iterators/ChildrenIterator.cs new file mode 100644 index 0000000..aef9758 --- /dev/null +++ b/Runtime/Graphs/Trees/Iterators/ChildrenIterator.cs @@ -0,0 +1,56 @@ +using System.Collections; +using System.Collections.Generic; + + +namespace Rokojori +{ + public class ChildrenIterator: TreeIterator where N:class + { + N parent; + N current; + N end; + N next; + TreeWalker walker; + + public static ChildrenIterator Create( TreeWalker walker, N node ) + { + var iterator = new ChildrenIterator(); + + iterator.walker = walker; + iterator.current = null; + iterator.parent = node; + iterator.end = walker.IterationEndOf( node ); + iterator.next = walker.NextNode( node ); + + if ( iterator.next == iterator.end ) + { + iterator.next = null; + } + + return iterator; + } + + public override bool HasNext() + { + return next != null; + } + + public override N Current() + { + return current; + } + + protected override void _MoveToNext() + { + current = next; + + next = walker.NextNode( current ); + + if ( next == end ) + { + next = null; + } + } + + } +} \ No newline at end of file diff --git a/Runtime/Graphs/Trees/Iterators/DirectChildrenIterator.cs b/Runtime/Graphs/Trees/Iterators/DirectChildrenIterator.cs new file mode 100644 index 0000000..3032ca6 --- /dev/null +++ b/Runtime/Graphs/Trees/Iterators/DirectChildrenIterator.cs @@ -0,0 +1,42 @@ +using System.Collections; +using System.Collections.Generic; + + +namespace Rokojori +{ + public class DirectChildrenIterator: TreeIterator where N:class + { + N parent; + N current; + int index = 0; + TreeWalker walker; + + public static DirectChildrenIterator Create( TreeWalker walker, N node ) + { + var iterator = new DirectChildrenIterator(); + + iterator.parent = node; + iterator.walker = walker; + iterator.current = null; + iterator.index = -1; + + return iterator; + } + + public override bool HasNext() + { + return ( index + 1 ) < walker.NumChildren( parent ); + } + + public override N Current() + { + return current; + } + + protected override void _MoveToNext() + { + index ++; + current = walker.ChildAt( parent, index ); + } + } +} \ No newline at end of file diff --git a/Runtime/Graphs/Trees/Iterators/NodesIterator.cs b/Runtime/Graphs/Trees/Iterators/NodesIterator.cs new file mode 100644 index 0000000..37ffe5d --- /dev/null +++ b/Runtime/Graphs/Trees/Iterators/NodesIterator.cs @@ -0,0 +1,50 @@ +using System.Collections; +using System.Collections.Generic; + + +namespace Rokojori +{ + public class NodesIterator: TreeIterator where N:class + { + N node; + N current; + bool isForward = true; + TreeWalker walker; + + public static NodesIterator Create( TreeWalker walker, N node, bool forward ) + { + var iterator = new NodesIterator(); + + iterator.walker = walker; + iterator.node = node; + iterator.current = null; + iterator.isForward = forward; + + return iterator; + } + + public override bool HasNext() + { + return node != null; + } + + public override N Current() + { + return current; + } + + protected override void _MoveToNext() + { + if ( isForward ) + { + node = walker.NextNode( node ); + } + else + { + node = walker.PreviousNode( node ); + } + + current = node; + } + } +} \ No newline at end of file diff --git a/Runtime/Graphs/Trees/Iterators/ParentsIterator.cs b/Runtime/Graphs/Trees/Iterators/ParentsIterator.cs new file mode 100644 index 0000000..82099c8 --- /dev/null +++ b/Runtime/Graphs/Trees/Iterators/ParentsIterator.cs @@ -0,0 +1,40 @@ +using System.Collections; +using System.Collections.Generic; + + +namespace Rokojori +{ + public class ParentsIterator: TreeIterator where N:class + { + N iterator; + N current; + TreeWalker walker; + + public static ParentsIterator Create( TreeWalker walker, N start ) + { + var iterator = new ParentsIterator(); + + iterator.current = null; + iterator.iterator = start; + iterator.walker = walker; + + return iterator; + } + + public override bool HasNext() + { + return walker.HasParent( iterator ); + } + + public override N Current() + { + return current; + } + + protected override void _MoveToNext() + { + iterator = walker.Parent( iterator ); + current = iterator; + } + } +} \ No newline at end of file diff --git a/Runtime/Graphs/Trees/Iterators/SiblingsIterator.cs b/Runtime/Graphs/Trees/Iterators/SiblingsIterator.cs new file mode 100644 index 0000000..f0284ef --- /dev/null +++ b/Runtime/Graphs/Trees/Iterators/SiblingsIterator.cs @@ -0,0 +1,66 @@ +using System.Collections; +using System.Collections.Generic; + + +namespace Rokojori +{ + public class SiblingsIterator: TreeIterator where N:class + { + bool nextSiblings = true; + + N parent; + N current; + int index = 0; + int nodeIndex = 0; + TreeWalker walker; + + public static SiblingsIterator Create( TreeWalker walker, N node, bool previous = true, bool next = true ) + { + var iterator = new SiblingsIterator(); + + iterator.parent = node; + iterator.walker = walker; + iterator.current = null; + iterator.nodeIndex = walker.ChildIndexOf( node ); + iterator.index = previous ? -1 : iterator.nodeIndex; + + return iterator; + } + + public override bool HasNext() + { + if ( ! nextSiblings ) + { + return ( index + 1 ) < nodeIndex; + } + + var nextIndex = index + 1; + + if ( nextIndex == nodeIndex ) + { + nextIndex ++; + } + + return nextIndex < walker.NumChildren( parent ); + + } + + public override N Current() + { + return current; + } + + protected override void _MoveToNext() + { + index ++; + + if ( index == nodeIndex ) + { + index ++; + } + + current = walker.ChildAt( parent, index ); + } + } + +} \ No newline at end of file diff --git a/Runtime/Graphs/Trees/Iterators/SingleIterator.cs b/Runtime/Graphs/Trees/Iterators/SingleIterator.cs new file mode 100644 index 0000000..b744115 --- /dev/null +++ b/Runtime/Graphs/Trees/Iterators/SingleIterator.cs @@ -0,0 +1,38 @@ +using System.Collections; +using System.Collections.Generic; + + +namespace Rokojori.Core +{ + public class SinlgeIterator: TreeIterator where N:class + { + N node; + N current; + + public static SinlgeIterator Create( N node ) + { + var iterator = new SinlgeIterator(); + + iterator.node = node; + iterator.current = null; + + return iterator; + } + + public override bool HasNext() + { + return node != null; + } + + public override N Current() + { + return current; + } + + protected override void _MoveToNext() + { + current = node; + node = null; + } + } +} \ No newline at end of file diff --git a/Runtime/Graphs/Trees/TreeIterator.cs b/Runtime/Graphs/Trees/TreeIterator.cs new file mode 100644 index 0000000..c9689d0 --- /dev/null +++ b/Runtime/Graphs/Trees/TreeIterator.cs @@ -0,0 +1,165 @@ +using System.Collections; +using System.Collections.Generic; + + +namespace Rokojori +{ + public enum TreeIteratorType + { + Parent, + + NextSibling, + PreviousSibling, + + FirstChild, + LastChild, + LastGrandChild, + + NextNode, + PreviousNode, + + Parents, + + DirectChildren, + Children, + + Siblings, + PreviousSiblings, + NextSiblings, + + PreviousNodes, + NextNodes + } + + public abstract class TreeIterator where N:class + { + public abstract bool HasNext(); + public abstract N Current(); + protected abstract void _MoveToNext(); + bool safeMoving = true; + + public void MoveToNext() + { + if ( safeMoving && ! HasNext() ) + { + throw new System.Exception( "Has no more elements" ); + } + + _MoveToNext(); + } + + public void ForEach( System.Action callback ) + { + while ( HasNext() ) + { + _MoveToNext(); + callback( Current() ); + } + } + + public N Get( System.Func predicate ) + { + while ( HasNext() ) + { + _MoveToNext(); + + var current = Current(); + var result = predicate( current ); + + if ( result ) + { + return current; + } + } + + return null; + } + + public bool Has( System.Func predicate ) + { + return Get( predicate ) != null; + } + + public List All( System.Func predicate ) + { + var list = new List(); + + while ( HasNext() ) + { + _MoveToNext(); + + var current = Current(); + var result = predicate( current ); + + if ( result ) + { + list.Add( current ); + } + } + + return list; + } + + public static TreeIterator GetIterator( TreeIteratorType type, N node, TreeWalker walker ) + { + + switch ( type ) + { + case TreeIteratorType.Parent: + return SinlgeIterator.Create( walker.Parent( node ) ); + + case TreeIteratorType.NextSibling: + return SinlgeIterator.Create( walker.NextSibling( node ) ); + + case TreeIteratorType.PreviousSibling: + return SinlgeIterator.Create( walker.PreviousSibling( node ) ); + + case TreeIteratorType.FirstChild: + return SinlgeIterator.Create( walker.ChildAt( node, 0 ) ); + + case TreeIteratorType.LastChild: + return SinlgeIterator.Create( walker.ChildAt( node, walker.NumChildren( node ) - 1 ) ); + + case TreeIteratorType.LastGrandChild: + return SinlgeIterator.Create( walker.LastGrandChild( node ) ); + + case TreeIteratorType.NextNode: + return SinlgeIterator.Create( walker.NextNode( node ) ); + + case TreeIteratorType.PreviousNode: + return SinlgeIterator.Create( walker.PreviousNode( node ) ); + + + case TreeIteratorType.Parents: + return ParentsIterator.Create( walker, node ); + + + case TreeIteratorType.DirectChildren: + return DirectChildrenIterator.Create( walker, node ); + + case TreeIteratorType.Children: + return ChildrenIterator.Create( walker, node ); + + + case TreeIteratorType.Siblings: + return SiblingsIterator.Create( walker, node, true, true ); + + case TreeIteratorType.PreviousSiblings: + return SiblingsIterator.Create( walker, node, true, false ); + + case TreeIteratorType.NextSiblings: + return SiblingsIterator.Create( walker, node, false, true ); + + + case TreeIteratorType.NextNodes: + return NodesIterator.Create( walker, node, true ); + + case TreeIteratorType.PreviousNodes: + return NodesIterator.Create( walker, node, false ); + + } + + return null; + } + } +} \ No newline at end of file diff --git a/Runtime/Graphs/Trees/TreeWalker.cs b/Runtime/Graphs/Trees/TreeWalker.cs new file mode 100644 index 0000000..7b5a8c3 --- /dev/null +++ b/Runtime/Graphs/Trees/TreeWalker.cs @@ -0,0 +1,322 @@ +using System.Collections; +using System.Collections.Generic; + + +namespace Rokojori +{ + public abstract class TreeWalker where N:class + { + public abstract N Parent( N node ); + + public abstract N ChildAt( N node, int index ); + + public abstract int NumChildren( N node ); + + public bool HasChildren( N node ) + { + return NumChildren( node ) > 0; + } + + public bool HasParent( N node ) + { + return Parent( node ) != null; + } + + + public int ChildIndexOf( N node ) + { + var p = Parent( node ); + + if ( p == null ) + { + return -1; + } + + var numKids = NumChildren( p ); + + for ( var i = 0; i= NumChildren( p ) ) + { return null; } + + return ChildAt( p, index ); + } + + + public N NextSibling( N node ) + { + var index = ChildIndexOf( node ); + return SiblingAt( node, index+1 ); + } + + + public N PreviousSibling( N node ) + { + var index = ChildIndexOf( node ); + return SiblingAt( node, index-1 ); + } + + + public bool HasSiblingAt( N node, int index ) + { + var p = Parent( node ); + if ( p == null || index<0 || index >= NumChildren( p ) ) + { return false; } + return true; + } + + + public N FirstChild( N node ) + { + return NumChildren( node )<=0?null:ChildAt( node, 0 ); + } + + + public N LastChild( N node ) + { + var num = NumChildren( node ); + return num <= 0 ? null : ChildAt( node, num - 1 ); + } + + + public N NextNode( N node ) + { + if ( HasChildren( node ) ) + { + return FirstChild( node ); + } + + var next = NextSibling( node ); + + if ( next != null ) + { + return next; + } + + var parent = Parent( node ); + + while ( parent != null ) + { + var n = NextSibling( parent ); + + if ( n != null ) + { + return n; + } + + parent = Parent( parent ); + } + return null; + } + + + public N PreviousNode( N node ) + { + var prev = PreviousSibling( node ); + + if ( prev != null ) + { + while ( HasChildren( prev ) ) + { + prev = LastChild( prev ); + } + return prev; + } + + return Parent( node ); + } + + + public N RootParent( N node ) + { + node = Parent( node ); + + if ( node == null ) + { + return null; + } + + while ( HasParent( node ) ) + { + node = Parent( node ); + } + + return node; + } + + + public N LastGrandChild( N node ) + { + if ( HasChildren( node ) ) + { + node = LastChild( node ); + + while ( HasChildren( node ) ) + { + node = LastChild( node ); + } + + return node; + } + + return null; + } + + + public bool IsChildOf( N child, N parent ) + { + var p = Parent( child ); + + while ( p != null ) + { + if ( p == parent ) + { + return true; + } + p = Parent( p ); + } + + return false; + } + + + public int NumParents( N node ) + { + var num = 0; + var p = Parent( node ); + + while ( p != null ) + { + num++; + p = Parent( p ); + } + + return num; + } + + + public N LastOuterNode( N node ) + { + var its = 0; + var max = 10000; + + while ( HasChildren( node ) ) + { + its++; + + if ( its > max ) + { + throw new System.Exception(); + } + + node = LastChild( node ); + } + + return node; + } + + + public N NextNonChild( N node ) + { + return NextNode( LastOuterNode( node ) ); + } + + public N IterationEndOf( N node ) + { + return NextNonChild( node ); + } + + public void Iterate( N node, System.Action callback, bool childrenOnly = false ) + { + var end = IterationEndOf( node ); + var it = node; + + if ( childrenOnly ) + { + it = NextNode( it ); + } + + while ( it != end ) + { + callback( it ); + it = NextNode( it ); + } + } + + public N Find( N node, System.Predicate predicate, bool childrenOnly ) + { + var end = IterationEndOf( node ); + var it = node; + + if ( childrenOnly ) + { + it = NextNode( it ); + } + + while ( it != end ) + { + if ( predicate( it ) ) + { + return it; + } + + it = NextNode( it ); + } + + return null; + } + + public void Filter( List list, N node, System.Predicate predicate, bool childrenOnly ) + { + System.Action addToList = ( N n ) => + { + if ( predicate( n ) ) + { + list.Add( n ); + } + }; + + Iterate( node, addToList, childrenOnly ); + } + + public void FilterAndMap( List list, N node, System.Predicate predicate, System.Func mapper, bool childrenOnly ) + { + System.Action addToList = ( N n ) => + { + if ( predicate( n ) ) + { + list.Add( mapper( n ) ); + } + }; + + Iterate( node, addToList, childrenOnly ); + } + + public void Map( List list, N node, System.Predicate predicate, System.Func mapper, bool childrenOnly ) + { + System.Action addToList = ( N n ) => + { + list.Add( mapper( n ) ); + }; + + Iterate( node, addToList, childrenOnly ); + } + + + } + +} \ No newline at end of file