Skip to content

Commit 384fc09

Browse files
committed
Added SharedData
1 parent 1ba8e06 commit 384fc09

File tree

12 files changed

+162
-15
lines changed

12 files changed

+162
-15
lines changed

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
# Change Log
22

3+
## [0.8.0-beta] - Aug 25, 2024
4+
- Added support for shared data between states. The SharedData object is a generic data store.
5+
- States can access shared data via `this.SharedData`
6+
- Shared data is exposed externally to the statemachine via StateMachineController.SharedData.
7+
38
## [0.7.2-beta] - Aug 24, 2024
49
- Exposed the JumpTo method on the StateMachineController
510
- This allows users to manually trigger a JumpIn node externally broadening the use-cases for the VSM
611
- Exposed the State member of the StateMachine through a public State member of the StateMachineController
7-
- This allows users to determine the current state and to directly call methods upon externally.
12+
- This allows users to determine the current state and to directly call methods upon it externally.
813
- I experimented with implementing a StatePattern with all States implementing a common interface.
914

1015
## [0.7.1-beta] - Aug 21, 2024

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,46 @@ The State Machine Editor supports copy and paste within and between state machin
8181

8282
https://github.com/user-attachments/assets/09c1b644-c519-4bfd-8c29-4b0771d8d8b6
8383

84+
## Shared Data
85+
States have access to a shared data store
86+
87+
```cs
88+
public class StateOne : State
89+
{
90+
[Transition] public event Action OnComplete;
91+
92+
public override void OnEnterState()
93+
{
94+
SharedData.SetData("age", 42);
95+
OnComplete?.Invoke();
96+
}
97+
98+
public override void OnExitState()
99+
{
100+
//...
101+
}
102+
}
103+
104+
public class StateTwo : State
105+
{
106+
[Transition] public event Action OnComplete;
107+
108+
public override void OnEnterState()
109+
{
110+
var age = SharedData.GetData<int>("age");
111+
Debug.Log($"StateTwo - Age:{age}");
112+
113+
OnComplete?.Invoke();
114+
}
115+
116+
public override void OnExitState()
117+
{
118+
//...
119+
}
120+
}
121+
```
122+
123+
This same data store is exposed externally to the state machine through the StateMachineController.SharedData
84124

85125
## License
86126
VisualStateMachineV2 is licensed under the MIT license

Runtime/Data.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime/Data/SharedData.cs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading;
4+
5+
namespace Nonatomic.VSM2.Data
6+
{
7+
public interface ISharedData
8+
{
9+
event Action<string, object> OnDataChanged;
10+
event Action OnDataCleared;
11+
12+
T GetData<T>(string key);
13+
void SetData<T>(string key, T value);
14+
void ClearData();
15+
}
16+
17+
public class SharedData : ISharedData
18+
{
19+
public event Action<string, object> OnDataChanged;
20+
public event Action OnDataCleared;
21+
22+
private readonly Dictionary<string, object> _data = new Dictionary<string, object>();
23+
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
24+
25+
public T GetData<T>(string key)
26+
{
27+
_lock.EnterReadLock();
28+
29+
try
30+
{
31+
if (!_data.TryGetValue(key, out var value)) return default;
32+
33+
if (value is T tValue)
34+
{
35+
return tValue;
36+
}
37+
38+
throw new InvalidOperationException($"Attempted to retrieve type {typeof(T)} but data is of type {value.GetType()}");
39+
}
40+
finally
41+
{
42+
_lock.ExitReadLock();
43+
}
44+
}
45+
46+
public void SetData<T>(string key, T value)
47+
{
48+
_lock.EnterWriteLock();
49+
50+
try
51+
{
52+
_data[key] = value;
53+
OnDataChanged?.Invoke(key, value);
54+
}
55+
finally
56+
{
57+
_lock.ExitWriteLock();
58+
}
59+
}
60+
61+
public void ClearData()
62+
{
63+
_lock.EnterWriteLock();
64+
try
65+
{
66+
_data.Clear();
67+
OnDataCleared?.Invoke();
68+
}
69+
finally
70+
{
71+
_lock.ExitWriteLock();
72+
}
73+
}
74+
}
75+
}

Runtime/Data/SharedData.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime/StateGraph/State.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma warning disable 0067
22

3+
using Nonatomic.VSM2.Data;
34
using Nonatomic.VSM2.StateGraph.Attributes;
45
using UnityEngine;
56

@@ -10,7 +11,8 @@ public abstract class State : ScriptableObject
1011
{
1112
public GameObject GameObject { get; set; }
1213
public StateMachine StateMachine { get; set; }
13-
14+
public ISharedData SharedData { get; set; }
15+
1416
public abstract void OnEnterState();
1517
public abstract void OnExitState();
1618

Runtime/StateGraph/StateMachine.cs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Threading;
55
using System.Threading.Tasks;
66
using JetBrains.Annotations;
7+
using Nonatomic.VSM2.Data;
78
using Nonatomic.VSM2.Logging;
89
using Nonatomic.VSM2.NodeGraph;
910
using Nonatomic.VSM2.StateGraph.States;
@@ -14,7 +15,9 @@ namespace Nonatomic.VSM2.StateGraph
1415
public class StateMachine
1516
{
1617
public event Action<State, StateMachineModel> OnComplete;
17-
18+
19+
public ISharedData SharedData { get; }
20+
1821
public State State => _currentNode?.State;
1922
public StateMachineModel Model { get; private set; }
2023
public bool IsComplete { get; private set; }
@@ -24,14 +27,17 @@ public class StateMachine
2427
private Dictionary<string, List<StateTransitionModel>> _transitionLookup = new();
2528
private Dictionary<JumpId, StateNodeModel> _jumpNodeLookup = new();
2629
private CancellationTokenSource _cancellationTokenSource = new();
27-
30+
2831
public StateMachine(StateMachineModel model, GameObject gameObject)
2932
{
30-
Model = StateMachineModel.CreateInstance(model);
31-
Model.Initialize(gameObject, this);
32-
33-
CreateNodeLookupTable();
34-
CreateTransitionLookupTable();
33+
SharedData = new SharedData();
34+
Initialize(model, gameObject);
35+
}
36+
37+
public StateMachine(StateMachineModel model, GameObject gameObject, ISharedData sharedData = null)
38+
{
39+
SharedData = sharedData ?? new SharedData();
40+
Initialize(model, gameObject);
3541
}
3642

3743
public void Update()
@@ -80,7 +86,7 @@ public void Exit()
8086
_currentNode.Exit();
8187
IsComplete = true;
8288
}
83-
89+
8490
public void JumpTo(JumpId jumpId)
8591
{
8692
if (!_jumpNodeLookup.TryGetValue(jumpId, out var nextNode))
@@ -113,6 +119,15 @@ public void OnDestroy()
113119
Model = null;
114120
}
115121

122+
private void Initialize(StateMachineModel model, GameObject gameObject)
123+
{
124+
Model = StateMachineModel.CreateInstance(model);
125+
Model.Initialize(gameObject, this, SharedData);
126+
127+
CreateNodeLookupTable();
128+
CreateTransitionLookupTable();
129+
}
130+
116131
private void CreateTransitionLookupTable()
117132
{
118133
_transitionLookup.Clear();
@@ -127,7 +142,7 @@ private void CreateTransitionLookupTable()
127142
_transitionLookup[transition.OriginNodeId].Add(transition);
128143
}
129144
}
130-
145+
131146
private void CreateNodeLookupTable()
132147
{
133148
_nodeLookup.Clear();

Runtime/StateGraph/StateMachineController.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using Nonatomic.VSM2.Data;
23
using Nonatomic.VSM2.StateGraph.States;
34
using UnityEngine;
45

@@ -15,6 +16,7 @@ public class StateMachineController : MonoBehaviour
1516
public string Id => _id;
1617

1718
public State State => _stateMachine?.State;
19+
public ISharedData SharedData => _stateMachine.SharedData;
1820

1921
/// <summary>
2022
/// Gets the current StateMachineModel, either from the active state machine or the serialized field.

Runtime/StateGraph/StateMachineModel.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Linq;
2+
using Nonatomic.VSM2.Data;
23
using Nonatomic.VSM2.Logging;
34
using Nonatomic.VSM2.NodeGraph;
45
using Nonatomic.VSM2.Utils;
@@ -178,7 +179,7 @@ private void ValidateNodes()
178179
}
179180
}
180181

181-
public void Initialize(GameObject gameObject, StateMachine stateMachine)
182+
public void Initialize(GameObject gameObject, StateMachine stateMachine, ISharedData sharedData)
182183
{
183184
if (!gameObject || stateMachine == null) return;
184185

@@ -191,6 +192,7 @@ public void Initialize(GameObject gameObject, StateMachine stateMachine)
191192

192193
instantiatedState.GameObject = gameObject;
193194
instantiatedState.StateMachine = stateMachine;
195+
instantiatedState.SharedData = sharedData;
194196
stateNode.State = instantiatedState;
195197
stateNode.Awake();
196198
}

Runtime/StateGraph/States/BaseParallelSubStateMachineState.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ protected virtual void CreateStateMachines()
7878
{
7979
if (model == null) continue;
8080

81-
var subSubStateMachine = new StateMachine(model, this.GameObject);
81+
var subSubStateMachine = new StateMachine(model, GameObject, SharedData);
8282
subSubStateMachine.SetParent(StateMachine);
8383
SubStateMachines.Add(subSubStateMachine);
8484
}

0 commit comments

Comments
 (0)