cz.xprees.variables 1.0.22 → 1.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,29 +2,23 @@
2
2
 
3
3
  [![NPM Version](https://img.shields.io/npm/v/cz.xprees.variables)](https://www.npmjs.com/package/cz.xprees.variables)
4
4
 
5
- This package contains a set of variables based on the ScriptableObjects,
6
- which make it great for storing and simply sharing state without tight coupling.
7
- Moreover, it provides a way to share variables (state) across multiple scenes making it powerful for multi-scene Unity project.
5
+ ScriptableObject-based variable architecture for decoupled state management, event observation, and multi-scene data sharing in Unity.
8
6
 
9
7
  ## Features
10
8
 
11
- - **ScriptableObject Variables** - A set of variables that can be used to store and share state across scenes.
12
- - Simply extend the [`VariableBaseSO<T>`](Runtime/Base/VariableBaseSO.cs) class to create your own variable types, see examples in
13
- the [BoolVariable](Runtime/Primitive/BoolVariable.cs) folder.
14
- - Watchable Variables - You can subscribe to `onValueChanged` event to get notified when the value changes.
15
- - **References** - A way to reference variables or inlined values in the Project (changeable in the Inspector).
16
- - You can directly set the value in the Inspector or reference a variable.
17
- - This makes flexible go to choice how to use the variables or inlined values in your scripts.
18
- - **Variable Modifiers** - Wrapper classes that allow you to modify the value of the variable in a specific way.
19
- - For example, you can use the [`BoolModifier`](Runtime/Modifiers/BoolModifier.cs)
20
- - **Variable Aggregations** - A set of classes that allow you to aggregate multiple variables into one.
21
- - For example, you can use the [`BoolAggregation`](Runtime/Aggregations/BoolAggregation.cs) to aggregate multiple boolean variables into one.
9
+ - **ScriptableObject Variables** - Store and share state without coupling systems together.
10
+ - Extend [`VariableBaseSO<T>`](Runtime/Base/VariableBaseSO.cs) to author custom typed variables.
11
+ - Observe runtime changes via the `onValueChanged` event.
12
+ - **Standalone Default State** - Every variable manages its own authored `defaultValue` and deep-clones it into `currentValue` on `OnEnable()` and
13
+ `ResetToDefault()`.
14
+ - **PlayMode Transition Resets** - Declarative `[ResetOnPlayMode]` attribute controls automatic reset when entering or exiting Play Mode.
15
+ - **State Lifetime Control** - Inherits `DescriptionBaseSO.lifetime` (`Scenario`, `Session`, `Persistent`) for boundary-aware resets.
16
+ - **References** - Inspector-switchable references (`ReferenceBase<T>`) supporting both inlined values and shared variable assets.
17
+ - **Variable Modifiers & Aggregations** - Compose and transform variable streams dynamically.
22
18
 
23
19
  ## Installation
24
20
 
25
- Install the package using npm scoped registry in `Project Settings > Package Manager > Scoped Registries`
26
-
27
- [Unity Docs - Install a UPM package from a Git URL](https://docs.unity3d.com/6000.1/Documentation/Manual/upm-ui-giturl.html)
21
+ Install the package using npm scoped registry in `Project Settings > Package Manager > Scoped Registries`:
28
22
 
29
23
  ```json
30
24
  {
@@ -35,7 +29,58 @@ Install the package using npm scoped registry in `Project Settings > Package Man
35
29
  "com.dbrizov.naughtyattributes"
36
30
  ]
37
31
  }
32
+ ```
33
+
34
+ Then install `cz.xprees.variables` via the Unity Package Manager.
35
+
36
+ ---
37
+
38
+ ## State Lifecycle & PlayMode Reset (DX)
39
+
40
+ Variables are completely self-contained and integrate with the centralized `StateSnapshotService` without requiring bespoke registration systems.
41
+
42
+ ### 1. Default Behavior
43
+
44
+ By default, `VariableBaseSO<T>`:
45
+
46
+ 1. Clones `defaultValue` into `currentValue` on `OnEnable()`.
47
+ 2. Automatically resets to default on entering Play Mode via `[ResetOnPlayMode(PlayModeResetTiming.EnterPlayMode)]`.
48
+ 3. In Unity Editor, captures its baseline snapshot before the first runtime mutation via `StateSnapshotService.EnsureCaptured(this)`.
49
+ 4. Reverts cleanly to baseline upon exiting Play Mode without dirtying asset files on disk.
38
50
 
51
+ ### 2. Customizing PlayMode Resets via `[ResetOnPlayMode]`
52
+
53
+ Use `[ResetOnPlayMode]` to customize when custom variable classes reset:
54
+
55
+ ```csharp
56
+ using Xprees.Core;
57
+ using Xprees.Variables.Base;
58
+
59
+ // 1. Default: resets on Play Mode entry
60
+ public class AmmoVariable : IntVariable { }
61
+
62
+ // 2. Prevent Play Mode reset (e.g. for persistent editor values or external saves)
63
+ [ResetOnPlayMode(PlayModeResetTiming.None)]
64
+ public class PlayerProfileVariable : StringVariable { }
65
+
66
+ // 3. Reset on both entry and exit
67
+ [ResetOnPlayMode(PlayModeResetTiming.Both)]
68
+ public class TransientDebugFlagVariable : BoolVariable { }
39
69
  ```
40
70
 
41
- Then simply install the package using the Unity Package Manager using the _NPM - xprees_ scope or by the package name `cz.xprees.variables`.
71
+ ### 3. Setting State Lifetime per Variable
72
+
73
+ Every variable ScriptableObject exposes the **Lifetime** dropdown in the Inspector (inherited from `DescriptionBaseSO`):
74
+
75
+ - **`Scenario` (Default)**:
76
+ Resets automatically whenever a scenario starts or restarts via `ScenarioStateRegistrySO` and `StateSnapshotService.RestoreAll()`.
77
+ - **`Session`**:
78
+ Persists across scenarios, resetting only when returning to the Main Menu or quitting.
79
+ - **`Persistent`**:
80
+ **Never reset** by scenario resets or Play Mode entry (e.g. Audio volume, resolution settings).
81
+
82
+ ```csharp
83
+ // You can also enforce class-level lifetime via attribute:
84
+ [StatefulLifetime(StateLifetime.Persistent)]
85
+ public class MasterVolumeVariable : FloatVariable { }
86
+ ```
@@ -10,12 +10,10 @@ using Xprees.Variables.Utils;
10
10
 
11
11
  namespace Xprees.Variables.Base
12
12
  {
13
- /// <summary>
14
13
  /// Base class for all variable references used in the game. It can either use an inlined value or reference a VariableBaseSO Scriptable Object. The Value property abstracts this choice away, so users of ReferenceBase don't have to care about it.
15
- /// </summary>
16
14
  /// <typeparam name="T">Unity Serializable</typeparam>
17
15
  [Serializable]
18
- public class ReferenceBase<T> : IResettable, ISerializationCallbackReceiver
16
+ public class ReferenceBase<T> : ISerializationCallbackReceiver
19
17
  {
20
18
  private bool _hasCapturedBaseline; // Used to check if baseline has been captured
21
19
  private T _defaultInlinedValue; // Used to reset state of inlined value
@@ -107,23 +105,14 @@ namespace Xprees.Variables.Base
107
105
 
108
106
  public static implicit operator T(ReferenceBase<T> reference) => reference != null ? reference.Value : default;
109
107
 
110
- public virtual void BackupStartState()
111
- {
112
- if (!useInlined) return; // Variables does that by themselves
113
-
114
- _defaultInlinedValue = CloningTools.Clone(inlinedValue);
115
- _hasCapturedBaseline = true;
116
- }
117
-
118
- public virtual void ResetState()
108
+ /// Resets the inlined value to its baseline value captured at deserialization/initialization.
109
+ /// If this reference points to a VariableBaseSO, it does nothing (the shared variable state is managed by StateSnapshotService).
110
+ public virtual void ResetToDefault()
119
111
  {
120
112
  if (useInlined)
121
113
  {
122
114
  inlinedValue = CloningTools.Clone(_defaultInlinedValue);
123
- return;
124
115
  }
125
-
126
- variable?.ResetState();
127
116
  }
128
117
  }
129
118
  }
@@ -8,12 +8,6 @@ namespace Xprees.Variables.Base
8
8
  [Tooltip("Aggregated variables.")]
9
9
  [SerializeField] protected VariableBaseSO<T>[] variables;
10
10
 
11
- private void OnEnable()
12
- {
13
- hideFlags = HideFlags.DontUnloadUnusedAsset;
14
- ResetState();
15
- }
16
-
17
11
  public override T CurrentValue
18
12
  {
19
13
  get => AggregateValue(variables);
@@ -22,15 +16,14 @@ namespace Xprees.Variables.Base
22
16
 
23
17
  protected abstract T AggregateValue(VariableBaseSO<T>[] variableBases);
24
18
 
25
- public override void ResetState()
19
+ public override void ResetToDefault()
26
20
  {
27
- base.ResetState();
28
- if (variables == null) return;
21
+ // Aggregations do not hold independent state; values are computed dynamically.
22
+ }
29
23
 
30
- foreach (var variable in variables)
31
- {
32
- variable?.ResetState();
33
- }
24
+ public override void ClearTransientState()
25
+ {
26
+ // Aggregations do not hold independent state; values are computed dynamically.
34
27
  }
35
28
  }
36
29
  }
@@ -7,36 +7,36 @@ namespace Xprees.Variables.Base
7
7
  {
8
8
  public abstract class VariableBaseSO : DescriptionBaseSO
9
9
  {
10
- private void OnEnable()
10
+ protected virtual void OnEnable()
11
11
  {
12
12
  hideFlags = HideFlags.DontUnloadUnusedAsset;
13
- ForceResetState();
13
+ ResetToDefault();
14
14
  }
15
15
 
16
- /// Force reset state regardless of any protection settings.
17
- public abstract void ForceResetState();
18
-
19
- public override void ResetState() => ForceResetState();
16
+ /// Resets the variable to its authored default value.
17
+ public abstract void ResetToDefault();
20
18
  }
21
19
 
22
- /// <summary>
23
- /// Base class for all variables ScriptableObjects.
24
- /// Object holds the state on runtime, but reset every time OnEnable to defaultValue.
25
- /// </summary>
20
+ /// Base class for all variable ScriptableObjects.
21
+ /// Manages its own default initialization self-contained, and integrates with StateSnapshotService for scenario boundaries.
22
+ /// By default, resets on EnterPlayMode unless decorated with a custom [ResetOnPlayMode] or marked Persistent.
26
23
  /// <typeparam name="T">Unity Serializable or System.Serializable</typeparam>
27
- public class VariableBaseSO<T> : VariableBaseSO
24
+ [ResetOnPlayMode(PlayModeResetTiming.EnterPlayMode)]
25
+ public class VariableBaseSO<T> : VariableBaseSO, IRuntimeStateOwner
28
26
  {
29
- [Tooltip("Value to which the variable will be reset on OnEnable or ResetState call.")]
27
+ [Tooltip("Authored default value of the variable.")]
30
28
  [SerializeField] protected T defaultValue;
31
29
 
32
- [Tooltip("Current value of variable - Runtime only value.")]
30
+ [Tooltip("Current value of variable - Runtime only value. Replaced with default value on OnEnable/PlayMode start.")]
33
31
  [SerializeField] private T currentValue;
34
32
 
35
- [Header("Settings")]
36
- [Tooltip("If true, the variable will not be reset when calling ResetState()."
37
- + " However, it will still be reset on OnEnable and when ForceResetState() is called. "
38
- + "Useful for game-system variables where runtime value should persist unless explicitly reset.")]
39
- [SerializeField] protected bool protectedDontReset = false;
33
+ #if UNITY_EDITOR
34
+ protected virtual void OnValidate()
35
+ {
36
+ // If not playing, reset current value to default value on validate to ensure that the variable is always in a valid state in Editor.
37
+ if (!Application.isPlaying) currentValue = CloningTools.Clone(defaultValue);
38
+ }
39
+ #endif
40
40
 
41
41
  public virtual T CurrentValue
42
42
  {
@@ -45,10 +45,7 @@ namespace Xprees.Variables.Base
45
45
  {
46
46
  #if UNITY_EDITOR
47
47
  // If not already captured in Editor capture before changing the value
48
- if (PlayModeStateTracker.IsPlaying)
49
- {
50
- StateSnapshotService.EnsureCaptured(this);
51
- }
48
+ if (PlayModeStateTracker.IsPlaying) StateSnapshotService.EnsureCaptured(this);
52
49
  #endif
53
50
  currentValue = value;
54
51
  onValueChanged?.Invoke(value);
@@ -65,13 +62,18 @@ namespace Xprees.Variables.Base
65
62
  public static implicit operator T(VariableBaseSO<T> variable) =>
66
63
  variable != null ? variable.CurrentValue : default;
67
64
 
68
- public override void ResetState()
65
+ /// Resets the variable's current value to a fresh clone of its authored default value and notifies listeners.
66
+ public override void ResetToDefault()
69
67
  {
70
- if (protectedDontReset) return; // skip reset if protected
71
-
72
- ForceResetState();
68
+ currentValue = CloningTools.Clone(defaultValue);
69
+ onValueChanged?.Invoke(currentValue);
73
70
  }
74
71
 
75
- public override void ForceResetState() => CurrentValue = CloningTools.Clone(defaultValue);
72
+ /// Invoked by StateSnapshotService when restoring state at scenario boundaries.
73
+ /// Notifies runtime listeners that the value has reverted to its snapshot baseline.
74
+ public virtual void ClearTransientState()
75
+ {
76
+ onValueChanged?.Invoke(currentValue);
77
+ }
76
78
  }
77
79
  }
@@ -12,13 +12,6 @@ namespace Xprees.Variables.Base
12
12
  [Space]
13
13
  [SerializeField] private BoolReference disableWrite = new(true);
14
14
 
15
- private void OnEnable()
16
- {
17
- hideFlags = HideFlags.DontUnloadUnusedAsset;
18
- disableWrite?.BackupStartState();
19
- ResetState();
20
- }
21
-
22
15
  public override T CurrentValue
23
16
  {
24
17
  get => ModifyValue(variable.CurrentValue);
@@ -36,16 +29,14 @@ namespace Xprees.Variables.Base
36
29
 
37
30
  protected abstract T ModifyValue(T value);
38
31
 
39
- public override void ResetState()
32
+ public override void ResetToDefault()
40
33
  {
41
- if (protectedDontReset) return;
42
- ForceResetState();
34
+ // Modifiers do not hold independent state; state is owned by the wrapped variable.
43
35
  }
44
36
 
45
- public override void ForceResetState()
37
+ public override void ClearTransientState()
46
38
  {
47
- disableWrite?.ResetState();
48
- variable?.ResetState();
39
+ // Modifiers do not hold independent state; state is owned by the wrapped variable.
49
40
  }
50
41
  }
51
42
  }
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "cz.xprees.variables",
3
3
  "displayName": "Variables",
4
- "version": "1.0.22",
4
+ "version": "1.0.23",
5
5
  "unity": "2021.3",
6
6
  "description": "This package contains a system for creating variables based on ScriptableObjects in Editor.",
7
7
  "license": "Apache-2.0",
8
8
  "category": "Core",
9
9
  "dependencies": {
10
- "cz.xprees.core": "1.0.32",
10
+ "cz.xprees.core": "1.0.40",
11
11
  "com.dbrizov.naughtyattributes": "2.1.4"
12
12
  },
13
13
  "keywords": [