com.wallstop-studios.unity-helpers 2.0.0 → 2.0.1
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/.github/workflows/format-on-demand.yml +2 -2
- package/.github/workflows/markdown-json.yml +1 -1
- package/.github/workflows/npm-publish.yml +1 -1
- package/.github/workflows/prettier-autofix.yml +4 -4
- package/.github/workflows/yaml-format-lint.yml +1 -1
- package/Docs/EFFECTS_SYSTEM.md +1316 -0
- package/{EFFECTS_SYSTEM_TUTORIAL.md → Docs/EFFECTS_SYSTEM_TUTORIAL.md} +1 -1
- package/{GETTING_STARTED.md → Docs/GETTING_STARTED.md} +10 -8
- package/{GLOSSARY.md → Docs/GLOSSARY.md} +4 -4
- package/Docs/HELPER_UTILITIES.md +885 -0
- package/Docs/HELPER_UTILITIES.md.meta +7 -0
- package/{INDEX.md → Docs/INDEX.md} +107 -62
- package/Docs/MATH_AND_EXTENSIONS.md +1039 -0
- package/{RANDOM_PERFORMANCE.md → Docs/RANDOM_PERFORMANCE.md} +15 -15
- package/{RELATIONAL_COMPONENTS.md → Docs/RELATIONAL_COMPONENTS.md} +21 -3
- package/{SPATIAL_TREES_2D_GUIDE.md → Docs/SPATIAL_TREES_2D_GUIDE.md} +2 -2
- package/{SPATIAL_TREES_3D_GUIDE.md → Docs/SPATIAL_TREES_3D_GUIDE.md} +1 -1
- package/{SPATIAL_TREE_2D_PERFORMANCE.md → Docs/SPATIAL_TREE_2D_PERFORMANCE.md} +64 -64
- package/{SPATIAL_TREE_3D_PERFORMANCE.md → Docs/SPATIAL_TREE_3D_PERFORMANCE.md} +64 -64
- package/Docs/UTILITY_COMPONENTS.md +906 -0
- package/Docs/UTILITY_COMPONENTS.md.meta +7 -0
- package/Docs/VISUAL_COMPONENTS.md +337 -0
- package/Docs/VISUAL_COMPONENTS.md.meta +7 -0
- package/Editor/Sprites/AnimationCopier.cs +3 -3
- package/README.md +69 -62
- package/Runtime/AssemblyInfo.cs +2 -0
- package/Runtime/Core/DataStructure/KDTree3D.cs +1 -1
- package/Runtime/Core/DataStructure/OctTree3D.cs +1 -1
- package/Runtime/Core/Extension/AsyncOperationExtensions.cs +122 -0
- package/Runtime/Core/Serialization/ProtobufUnitySurrogates.cs +24 -29
- package/Runtime/Integrations/Reflex/AssemblyInfo.cs +7 -0
- package/Runtime/Integrations/Reflex/AssemblyInfo.cs.meta +11 -0
- package/Runtime/Integrations/Reflex/ContainerRelationalExtensions.cs +198 -0
- package/Runtime/Integrations/Reflex/ContainerRelationalExtensions.cs.meta +11 -0
- package/Runtime/Integrations/Reflex/RelationalComponentsInstaller.cs +86 -0
- package/Runtime/Integrations/Reflex/RelationalComponentsInstaller.cs.meta +11 -0
- package/Runtime/Integrations/Reflex/RelationalReflexSceneBootstrapper.cs +316 -0
- package/Runtime/Integrations/Reflex/RelationalReflexSceneBootstrapper.cs.meta +11 -0
- package/Runtime/Integrations/Reflex/RelationalSceneAssignmentOptions.cs +86 -0
- package/Runtime/Integrations/Reflex/RelationalSceneAssignmentOptions.cs.meta +11 -0
- package/Runtime/Integrations/Reflex/WallstopStudios.UnityHelpers.Integration.Reflex.asmdef +20 -0
- package/Runtime/Integrations/Reflex/WallstopStudios.UnityHelpers.Integration.Reflex.asmdef.meta +7 -0
- package/Runtime/Integrations/Reflex.meta +8 -0
- package/Runtime/Utils/ScriptableObjectSingleton.cs +1 -1
- package/Samples~/DI - Reflex/README.md +527 -0
- package/Samples~/DI - Reflex/README.md.meta +7 -0
- package/Samples~/DI - Reflex/Scripts/ReflexPaletteService.cs +36 -0
- package/Samples~/DI - Reflex/Scripts/ReflexPaletteService.cs.meta +11 -0
- package/Samples~/DI - Reflex/Scripts/ReflexRelationalConsumer.cs +79 -0
- package/Samples~/DI - Reflex/Scripts/ReflexRelationalConsumer.cs.meta +11 -0
- package/Samples~/DI - Reflex/Scripts/ReflexSampleInstaller.cs +30 -0
- package/Samples~/DI - Reflex/Scripts/ReflexSampleInstaller.cs.meta +11 -0
- package/Samples~/DI - Reflex/Scripts/ReflexSpawner.cs +79 -0
- package/Samples~/DI - Reflex/Scripts/ReflexSpawner.cs.meta +11 -0
- package/Samples~/DI - Reflex/Scripts/Samples.UnityHelpers.DI.Reflex.asmdef +26 -0
- package/Samples~/DI - Reflex/Scripts/Samples.UnityHelpers.DI.Reflex.asmdef.meta +9 -0
- package/Samples~/DI - Reflex/Scripts.meta +8 -0
- package/Samples~/DI - Reflex.meta +8 -0
- package/Samples~/DI - VContainer/README.md +6 -5
- package/Samples~/DI - Zenject/README.md +6 -5
- package/Tests/Editor/Core/Attributes/RelationalComponentAssignerTests.cs +29 -31
- package/Tests/Editor/Integrations/Reflex/ReflexIntegrationCompilationTests.cs +41 -0
- package/Tests/Editor/Integrations/Reflex/ReflexIntegrationCompilationTests.cs.meta +11 -0
- package/Tests/Editor/Integrations/Reflex/WallstopStudios.UnityHelpers.Tests.Editor.Reflex.asmdef +27 -0
- package/Tests/Editor/Integrations/Reflex/WallstopStudios.UnityHelpers.Tests.Editor.Reflex.asmdef.meta +7 -0
- package/Tests/Editor/Integrations/Reflex.meta +8 -0
- package/Tests/Editor/Integrations/VContainer/VContainerRelationalEntryPointTests.cs +15 -16
- package/Tests/Editor/Integrations/VContainer/VContainerRelationalHelpersTests.cs +7 -13
- package/Tests/Editor/Integrations/Zenject/ZenjectRelationalHelpersTests.cs +7 -11
- package/Tests/Editor/Integrations/Zenject/ZenjectRelationalInitializerTests.cs +19 -21
- package/Tests/Editor/PersistentDirectorySettingsTests.cs +0 -1
- package/Tests/Editor/Sprites/AnimationCopierFilterTests.cs +0 -1
- package/Tests/Editor/Sprites/AnimationViewerWindowTests.cs +2 -2
- package/Tests/Editor/Tools/ImageBlurToolTests.cs +1 -1
- package/Tests/Editor/Utils/CommonTestBase.cs +17 -0
- package/Tests/Editor/Utils/ScriptableObjectSingletonCreatorTests.cs +1 -1
- package/Tests/Runtime/Extensions/AsyncOperationExtensionsTests.cs +179 -0
- package/Tests/Runtime/Extensions/RandomExtensionTests.cs +55 -0
- package/Tests/Runtime/Integrations/Reflex/RelationalComponentsReflexTests.cs +445 -0
- package/Tests/Runtime/Integrations/Reflex/RelationalComponentsReflexTests.cs.meta +11 -0
- package/Tests/Runtime/Integrations/Reflex/WallstopStudios.UnityHelpers.Tests.Runtime.Reflex.asmdef +28 -0
- package/Tests/Runtime/Integrations/Reflex/WallstopStudios.UnityHelpers.Tests.Runtime.Reflex.asmdef.meta +7 -0
- package/Tests/Runtime/Integrations/Reflex.meta +8 -0
- package/Tests/Runtime/Integrations/VContainer/RelationalComponentsVContainerTests.cs +24 -29
- package/Tests/Runtime/Integrations/VContainer/RelationalObjectPoolsVContainerTests.cs +8 -3
- package/Tests/Runtime/Integrations/Zenject/RelationalComponentsZenjectTests.cs +10 -20
- package/Tests/Runtime/Performance/RandomPerformanceTests.cs +1 -1
- package/Tests/Runtime/Performance/SpatialTree2DPerformanceTests.cs +1 -1
- package/Tests/Runtime/Performance/SpatialTree3DPerformanceTests.cs +1 -1
- package/Tests/Runtime/Serialization/JsonRoundtripComprehensiveTests.cs +4 -9
- package/Tests/Runtime/Serialization/ProtoRoundtripComprehensiveTests.cs +13 -13
- package/Tests/Runtime/TestUtils/CommonTestBase.cs +11 -0
- package/Tests/Runtime/TestUtils/ReflexTestSupport.cs +111 -0
- package/Tests/Runtime/TestUtils/ReflexTestSupport.cs.meta +12 -0
- package/Tests/Runtime/Utils/MatchColliderToSpriteTests.cs +4 -4
- package/Tests/TestUtils.meta +8 -0
- package/package.json +6 -1
- package/EFFECTS_SYSTEM.md +0 -242
- package/MATH_AND_EXTENSIONS.md +0 -316
- /package/{CHANGELOG.md → Docs/CHANGELOG.md} +0 -0
- /package/{CHANGELOG.md.meta → Docs/CHANGELOG.md.meta} +0 -0
- /package/{CONTRIBUTING.md → Docs/CONTRIBUTING.md} +0 -0
- /package/{CONTRIBUTING.md.meta → Docs/CONTRIBUTING.md.meta} +0 -0
- /package/{DATA_STRUCTURES.md → Docs/DATA_STRUCTURES.md} +0 -0
- /package/{DATA_STRUCTURES.md.meta → Docs/DATA_STRUCTURES.md.meta} +0 -0
- /package/{EDITOR_TOOLS_GUIDE.md → Docs/EDITOR_TOOLS_GUIDE.md} +0 -0
- /package/{EDITOR_TOOLS_GUIDE.md.meta → Docs/EDITOR_TOOLS_GUIDE.md.meta} +0 -0
- /package/{EFFECTS_SYSTEM.md.meta → Docs/EFFECTS_SYSTEM.md.meta} +0 -0
- /package/{EFFECTS_SYSTEM_TUTORIAL.md.meta → Docs/EFFECTS_SYSTEM_TUTORIAL.md.meta} +0 -0
- /package/{GETTING_STARTED.md.meta → Docs/GETTING_STARTED.md.meta} +0 -0
- /package/{GLOSSARY.md.meta → Docs/GLOSSARY.md.meta} +0 -0
- /package/{HULLS.md → Docs/HULLS.md} +0 -0
- /package/{HULLS.md.meta → Docs/HULLS.md.meta} +0 -0
- /package/{INDEX.md.meta → Docs/INDEX.md.meta} +0 -0
- /package/{LICENSE.md → Docs/LICENSE.md} +0 -0
- /package/{LICENSE.md.meta → Docs/LICENSE.md.meta} +0 -0
- /package/{MATH_AND_EXTENSIONS.md.meta → Docs/MATH_AND_EXTENSIONS.md.meta} +0 -0
- /package/{RANDOM_PERFORMANCE.md.meta → Docs/RANDOM_PERFORMANCE.md.meta} +0 -0
- /package/{REFLECTION_HELPERS.md → Docs/REFLECTION_HELPERS.md} +0 -0
- /package/{REFLECTION_HELPERS.md.meta → Docs/REFLECTION_HELPERS.md.meta} +0 -0
- /package/{RELATIONAL_COMPONENTS.md.meta → Docs/RELATIONAL_COMPONENTS.md.meta} +0 -0
- /package/{SERIALIZATION.md → Docs/SERIALIZATION.md} +0 -0
- /package/{SERIALIZATION.md.meta → Docs/SERIALIZATION.md.meta} +0 -0
- /package/{SINGLETONS.md → Docs/SINGLETONS.md} +0 -0
- /package/{SINGLETONS.md.meta → Docs/SINGLETONS.md.meta} +0 -0
- /package/{SPATIAL_TREES_2D_GUIDE.md.meta → Docs/SPATIAL_TREES_2D_GUIDE.md.meta} +0 -0
- /package/{SPATIAL_TREES_3D_GUIDE.md.meta → Docs/SPATIAL_TREES_3D_GUIDE.md.meta} +0 -0
- /package/{SPATIAL_TREE_2D_PERFORMANCE.md.meta → Docs/SPATIAL_TREE_2D_PERFORMANCE.md.meta} +0 -0
- /package/{SPATIAL_TREE_3D_PERFORMANCE.md.meta → Docs/SPATIAL_TREE_3D_PERFORMANCE.md.meta} +0 -0
- /package/{SPATIAL_TREE_SEMANTICS.md → Docs/SPATIAL_TREE_SEMANTICS.md} +0 -0
- /package/{SPATIAL_TREE_SEMANTICS.md.meta → Docs/SPATIAL_TREE_SEMANTICS.md.meta} +0 -0
- /package/{THIRD_PARTY_NOTICES.md → Docs/THIRD_PARTY_NOTICES.md} +0 -0
- /package/{THIRD_PARTY_NOTICES.md.meta → Docs/THIRD_PARTY_NOTICES.md.meta} +0 -0
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
# Reflex Integration - Unity Helpers
|
|
2
|
+
|
|
3
|
+
## Why This Integration Matters
|
|
4
|
+
|
|
5
|
+
**Stop Writing GetComponent Boilerplate in Every Single Script**
|
|
6
|
+
|
|
7
|
+
When using dependency injection with Reflex, you've solved half the problem - your service dependencies get injected cleanly. But you're **still stuck** writing repetitive `GetComponent` boilerplate for hierarchy references in every. single. MonoBehaviour.
|
|
8
|
+
|
|
9
|
+
**The Painful Reality:**
|
|
10
|
+
|
|
11
|
+
1. **Dependencies** → ✅ Handled by Reflex (IHealthSystem, IAudioService, etc.)
|
|
12
|
+
2. **Hierarchy references** → ❌ Still manual hell (SpriteRenderer, Rigidbody2D, child colliders, etc.)
|
|
13
|
+
|
|
14
|
+
You're using a modern DI framework but still writing 2008-era Unity boilerplate. **Unity Helpers fixes this.**
|
|
15
|
+
|
|
16
|
+
**The Solution:** This integration automatically wires up relational component fields **right after** DI injection completes - giving you the best of both worlds with **literally zero extra code per component**.
|
|
17
|
+
|
|
18
|
+
### ⚡ Quick Example: Before vs After
|
|
19
|
+
|
|
20
|
+
**Before (Manual):**
|
|
21
|
+
|
|
22
|
+
```csharp
|
|
23
|
+
public class Enemy : MonoBehaviour
|
|
24
|
+
{
|
|
25
|
+
[Inject] private IHealthSystem _healthSystem;
|
|
26
|
+
private Animator _animator;
|
|
27
|
+
private Rigidbody2D _rigidbody;
|
|
28
|
+
private Collider2D[] _childColliders;
|
|
29
|
+
|
|
30
|
+
void Awake()
|
|
31
|
+
{
|
|
32
|
+
_animator = GetComponent<Animator>();
|
|
33
|
+
_rigidbody = GetComponent<Rigidbody2D>();
|
|
34
|
+
_childColliders = GetComponentsInChildren<Collider2D>();
|
|
35
|
+
// 10+ more lines of GetComponent calls...
|
|
36
|
+
|
|
37
|
+
if (_animator == null) Debug.LogError("Missing Animator!");
|
|
38
|
+
if (_rigidbody == null) Debug.LogError("Missing Rigidbody2D!");
|
|
39
|
+
// More validation...
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**After (With Integration):**
|
|
45
|
+
|
|
46
|
+
```csharp
|
|
47
|
+
public class Enemy : MonoBehaviour
|
|
48
|
+
{
|
|
49
|
+
[Inject] private IHealthSystem _healthSystem;
|
|
50
|
+
|
|
51
|
+
[SiblingComponent] private Animator _animator;
|
|
52
|
+
[SiblingComponent] private Rigidbody2D _rigidbody;
|
|
53
|
+
[ChildComponent] private Collider2D[] _childColliders;
|
|
54
|
+
|
|
55
|
+
// That's it! No Awake() needed - both DI and relational fields are auto-wired
|
|
56
|
+
// Automatic validation with helpful error messages included
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**⏱️ Time Saved:** 10-20 lines of boilerplate per component × hundreds of components = **weeks** of development time.
|
|
61
|
+
**🧠 Mental Load Eliminated:** No more context-switching between DI patterns and Unity hierarchy patterns.
|
|
62
|
+
**🐛 Bugs Prevented:** Automatic validation catches missing references **before** they cause runtime errors.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 🚀 Quick Setup (2 Minutes)
|
|
67
|
+
|
|
68
|
+
### Step 1: Add the Installer to Your SceneScope
|
|
69
|
+
|
|
70
|
+
1. Add a `SceneScope` to your scene (Reflex component)
|
|
71
|
+
2. Add the `RelationalComponentsInstaller` component to the same GameObject
|
|
72
|
+
3. Enable **"Assign Scene On Initialize"** to automatically wire all scene components after the container builds (recommended)
|
|
73
|
+
|
|
74
|
+
> 💡 **Beginner tip:** Enable all checkboxes in the inspector:
|
|
75
|
+
>
|
|
76
|
+
> - ✅ **Assign Scene On Initialize** → Auto-wires all scene objects (saves you from calling it manually)
|
|
77
|
+
> - ✅ **Include Inactive Objects** → Scans disabled GameObjects too
|
|
78
|
+
> - ✅ **Listen For Additive Scenes** → Auto-wires newly loaded scenes (great for multi-scene setups)
|
|
79
|
+
> - ✅ **Use Single Pass Scan** → Faster scanning (always leave this on)
|
|
80
|
+
|
|
81
|
+
### Step 2: Use With Prefab Instantiation
|
|
82
|
+
|
|
83
|
+
When spawning prefabs at runtime, use the helpers that combine instantiation, DI, and relational assignment:
|
|
84
|
+
|
|
85
|
+
```csharp
|
|
86
|
+
using UnityEngine;
|
|
87
|
+
using Reflex.Core;
|
|
88
|
+
using Reflex.Extensions;
|
|
89
|
+
using WallstopStudios.UnityHelpers.Integrations.Reflex;
|
|
90
|
+
|
|
91
|
+
public sealed class EnemySpawner : MonoBehaviour
|
|
92
|
+
{
|
|
93
|
+
[SerializeField] private Enemy _enemyPrefab;
|
|
94
|
+
[SerializeField] private GameObject _enemySquadPrefab;
|
|
95
|
+
|
|
96
|
+
private Container _container;
|
|
97
|
+
|
|
98
|
+
private void Awake()
|
|
99
|
+
{
|
|
100
|
+
_container = gameObject.scene.GetSceneContainer();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
public Enemy SpawnEnemy(Transform parent)
|
|
104
|
+
{
|
|
105
|
+
return _container.InstantiateComponentWithRelations(_enemyPrefab, parent);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public GameObject SpawnEnemySquad(Transform parent)
|
|
109
|
+
{
|
|
110
|
+
return _container.InstantiateGameObjectWithRelations(
|
|
111
|
+
_enemySquadPrefab,
|
|
112
|
+
parent,
|
|
113
|
+
includeInactiveChildren: true
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
public void HydrateExisting(GameObject root)
|
|
118
|
+
{
|
|
119
|
+
_container.InjectGameObjectWithRelations(root, includeInactiveChildren: true);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**That's it!** Both DI injection and relational component wiring happen automatically.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## 📦 What's Included in This Sample
|
|
129
|
+
|
|
130
|
+
This sample provides a complete working example:
|
|
131
|
+
|
|
132
|
+
- **Scripts/ReflexSampleInstaller.cs** - Registers a palette service to demonstrate DI working alongside relational attributes
|
|
133
|
+
- **Scripts/ReflexRelationalConsumer.cs** - Component demonstrating relational attributes working with Reflex injection
|
|
134
|
+
- **Scripts/ReflexSpawner.cs** - Demonstrates `InstantiateComponentWithRelations`, `InstantiateGameObjectWithRelations`, and hierarchy hydration
|
|
135
|
+
- **Scripts/ReflexPaletteService.cs** - Sample service showing DI pathway is active
|
|
136
|
+
- **Prefabs/** - Example prefabs with relational fields
|
|
137
|
+
- **Scenes/Reflex_Sample.unity** - Complete working scene with SceneScope
|
|
138
|
+
|
|
139
|
+
### How to Import This Sample
|
|
140
|
+
|
|
141
|
+
1. Open Unity Package Manager
|
|
142
|
+
2. Find **Unity Helpers** in the package list
|
|
143
|
+
3. Expand the **Samples** section
|
|
144
|
+
4. Click **Import** next to "DI - Reflex"
|
|
145
|
+
5. Open `Scenes/Reflex_Sample.unity` and press Play
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## 🎯 Common Use Cases (By Experience Level)
|
|
150
|
+
|
|
151
|
+
### 🟢 Beginner: "I just want my components to work"
|
|
152
|
+
|
|
153
|
+
**Perfect for:** Player controllers, enemy AI, simple gameplay scripts
|
|
154
|
+
|
|
155
|
+
**What you get:** No more `GetComponent` calls, no more null reference exceptions from missing components
|
|
156
|
+
|
|
157
|
+
**Example:**
|
|
158
|
+
|
|
159
|
+
```csharp
|
|
160
|
+
public class PlayerController : MonoBehaviour
|
|
161
|
+
{
|
|
162
|
+
// Injected dependencies
|
|
163
|
+
[Inject] private IInputService _input;
|
|
164
|
+
[Inject] private IAudioService _audio;
|
|
165
|
+
|
|
166
|
+
// Hierarchy references (auto-wired)
|
|
167
|
+
[SiblingComponent] private Animator _animator;
|
|
168
|
+
[SiblingComponent] private Rigidbody2D _rigidbody;
|
|
169
|
+
[ChildComponent(TagFilter = "Weapon")] private Weapon _weapon;
|
|
170
|
+
|
|
171
|
+
// Everything wired automatically when scene loads!
|
|
172
|
+
|
|
173
|
+
void Update()
|
|
174
|
+
{
|
|
175
|
+
Vector2 input = _input.GetMovementInput();
|
|
176
|
+
_rigidbody.velocity = input * moveSpeed;
|
|
177
|
+
_animator.SetFloat("Speed", input.magnitude);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Important:** Enable **"Assign Scene On Initialize"** in the `RelationalComponentsInstaller` for automatic scene wiring.
|
|
183
|
+
|
|
184
|
+
### 🟡 Intermediate: "I'm spawning objects at runtime"
|
|
185
|
+
|
|
186
|
+
**Perfect for:** Enemy spawners, projectile systems, object pooling
|
|
187
|
+
|
|
188
|
+
**What you get:** One-line instantiation that handles DI injection + hierarchy wiring automatically
|
|
189
|
+
|
|
190
|
+
**Example:**
|
|
191
|
+
|
|
192
|
+
```csharp
|
|
193
|
+
public sealed class ProjectileSpawner : MonoBehaviour
|
|
194
|
+
{
|
|
195
|
+
private Container _container;
|
|
196
|
+
[SerializeField] private Projectile _projectilePrefab;
|
|
197
|
+
|
|
198
|
+
private void Awake()
|
|
199
|
+
{
|
|
200
|
+
_container = gameObject.scene.GetSceneContainer();
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
public Projectile Fire(Vector3 position, Vector3 direction)
|
|
204
|
+
{
|
|
205
|
+
Projectile projectile = _container.InstantiateComponentWithRelations(_projectilePrefab);
|
|
206
|
+
projectile.transform.SetPositionAndRotation(position, Quaternion.LookRotation(direction));
|
|
207
|
+
projectile.Launch(direction);
|
|
208
|
+
return projectile;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### 🔴 Advanced: "I have complex hierarchies and custom workflows"
|
|
214
|
+
|
|
215
|
+
**Perfect for:** UI systems, vehicles with multiple parts, procedural generation
|
|
216
|
+
|
|
217
|
+
**What you get:** Full control over when and how wiring happens, with helpers for every scenario
|
|
218
|
+
|
|
219
|
+
**Example - Complex Prefabs:**
|
|
220
|
+
|
|
221
|
+
```csharp
|
|
222
|
+
public sealed class VehicleFactory : MonoBehaviour
|
|
223
|
+
{
|
|
224
|
+
private Container _container;
|
|
225
|
+
[SerializeField] private GameObject _vehiclePrefab;
|
|
226
|
+
|
|
227
|
+
private void Awake()
|
|
228
|
+
{
|
|
229
|
+
_container = gameObject.scene.GetSceneContainer();
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
public GameObject CreateVehicle()
|
|
233
|
+
{
|
|
234
|
+
return _container.InstantiateGameObjectWithRelations(
|
|
235
|
+
_vehiclePrefab,
|
|
236
|
+
parent: null,
|
|
237
|
+
includeInactiveChildren: true
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## 💡 Real-World Impact: A Day in the Life
|
|
246
|
+
|
|
247
|
+
### Without This Integration
|
|
248
|
+
|
|
249
|
+
**Morning:** You start work on a new enemy type.
|
|
250
|
+
|
|
251
|
+
```csharp
|
|
252
|
+
public class FlyingEnemy : MonoBehaviour
|
|
253
|
+
{
|
|
254
|
+
[Inject] private IHealthSystem _health;
|
|
255
|
+
[Inject] private IAudioService _audio;
|
|
256
|
+
|
|
257
|
+
private Animator _animator;
|
|
258
|
+
private Rigidbody2D _rigidbody;
|
|
259
|
+
private SpriteRenderer _sprite;
|
|
260
|
+
private Collider2D[] _hitboxes;
|
|
261
|
+
private Transform _weaponMount;
|
|
262
|
+
|
|
263
|
+
void Awake()
|
|
264
|
+
{
|
|
265
|
+
_animator = GetComponent<Animator>();
|
|
266
|
+
if (_animator == null) Debug.LogError("Missing Animator on FlyingEnemy!");
|
|
267
|
+
|
|
268
|
+
_rigidbody = GetComponent<Rigidbody2D>();
|
|
269
|
+
if (_rigidbody == null) Debug.LogError("Missing Rigidbody2D on FlyingEnemy!");
|
|
270
|
+
|
|
271
|
+
_sprite = GetComponent<SpriteRenderer>();
|
|
272
|
+
if (_sprite == null) Debug.LogError("Missing SpriteRenderer on FlyingEnemy!");
|
|
273
|
+
|
|
274
|
+
_hitboxes = GetComponentsInChildren<Collider2D>();
|
|
275
|
+
if (_hitboxes.Length == 0) Debug.LogWarning("No hitboxes found on FlyingEnemy!");
|
|
276
|
+
|
|
277
|
+
_weaponMount = transform.Find("WeaponMount");
|
|
278
|
+
if (_weaponMount == null) Debug.LogError("Missing WeaponMount on FlyingEnemy!");
|
|
279
|
+
|
|
280
|
+
// Finally, actual game logic can start...
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
**10 minutes later:** You've written 20+ lines of boilerplate before writing any actual game logic.
|
|
286
|
+
|
|
287
|
+
**30 minutes later:** Null reference exception in the build! You forgot to add the SpriteRenderer to the prefab.
|
|
288
|
+
|
|
289
|
+
**60 minutes later:** You're manually wiring up the 8th enemy variant of the day...
|
|
290
|
+
|
|
291
|
+
### With This Integration
|
|
292
|
+
|
|
293
|
+
**Morning:** You start work on a new enemy type.
|
|
294
|
+
|
|
295
|
+
```csharp
|
|
296
|
+
public class FlyingEnemy : MonoBehaviour
|
|
297
|
+
{
|
|
298
|
+
[Inject] private IHealthSystem _health;
|
|
299
|
+
[Inject] private IAudioService _audio;
|
|
300
|
+
|
|
301
|
+
[SiblingComponent] private Animator _animator;
|
|
302
|
+
[SiblingComponent] private Rigidbody2D _rigidbody;
|
|
303
|
+
[SiblingComponent] private SpriteRenderer _sprite;
|
|
304
|
+
[ChildComponent] private Collider2D[] _hitboxes;
|
|
305
|
+
[ChildComponent(NameFilter = "WeaponMount")] private Transform _weaponMount;
|
|
306
|
+
|
|
307
|
+
// Start writing game logic immediately
|
|
308
|
+
void Start() => _animator.Play("Idle");
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
**2 minutes later:** You're done with wiring and writing game logic.
|
|
313
|
+
|
|
314
|
+
**10 minutes later:** You've shipped 5 enemy variants with zero boilerplate.
|
|
315
|
+
|
|
316
|
+
**Never:** You never see "Missing component" runtime errors because validation happens automatically with helpful messages.
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## 🔧 Advanced Configuration
|
|
321
|
+
|
|
322
|
+
### RelationalComponentsInstaller Options
|
|
323
|
+
|
|
324
|
+
The installer component provides these settings:
|
|
325
|
+
|
|
326
|
+
**Assign Scene On Initialize** *(default: true)*
|
|
327
|
+
|
|
328
|
+
- When enabled, automatically wires all scene components with relational attributes after the container builds
|
|
329
|
+
- Disable if you want to manually control when scene wiring happens
|
|
330
|
+
|
|
331
|
+
**Include Inactive Objects** *(default: true)*
|
|
332
|
+
|
|
333
|
+
- When enabled, scans inactive GameObjects and disabled components
|
|
334
|
+
- Disable to only wire active objects
|
|
335
|
+
|
|
336
|
+
**Listen For Additive Scenes** *(default: false)*
|
|
337
|
+
|
|
338
|
+
- When enabled, automatically wires components in additively loaded scenes
|
|
339
|
+
- Essential for multi-scene workflows
|
|
340
|
+
|
|
341
|
+
**Use Single Pass Scan** *(default: true)*
|
|
342
|
+
|
|
343
|
+
- Uses optimized metadata-driven scanning (faster)
|
|
344
|
+
- Leave enabled unless debugging scan issues
|
|
345
|
+
|
|
346
|
+
### Manual Hierarchy Wiring
|
|
347
|
+
|
|
348
|
+
For dynamic hierarchies or pooled objects:
|
|
349
|
+
|
|
350
|
+
```csharp
|
|
351
|
+
private Container _container;
|
|
352
|
+
|
|
353
|
+
void Awake()
|
|
354
|
+
{
|
|
355
|
+
_container = gameObject.scene.GetSceneContainer();
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
void SetupComplexHierarchy(GameObject root)
|
|
359
|
+
{
|
|
360
|
+
// Wire all components in hierarchy
|
|
361
|
+
_container.AssignRelationalHierarchy(root, includeInactiveChildren: false);
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Performance: Prewarming Reflection Caches
|
|
366
|
+
|
|
367
|
+
For large projects, prewarm reflection caches during loading to avoid first-use stalls:
|
|
368
|
+
|
|
369
|
+
```csharp
|
|
370
|
+
using WallstopStudios.UnityHelpers.Core.Attributes;
|
|
371
|
+
|
|
372
|
+
public class GameBootstrap : MonoBehaviour
|
|
373
|
+
{
|
|
374
|
+
void Awake()
|
|
375
|
+
{
|
|
376
|
+
// Call once during bootstrap/loading screen
|
|
377
|
+
RelationalComponentInitializer.Initialize();
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
Or enable auto-prewarm on the `AttributeMetadataCache` asset:
|
|
383
|
+
|
|
384
|
+
1. Create: `Assets > Create > Wallstop Studios > Unity Helpers > Attribute Metadata Cache`
|
|
385
|
+
2. Enable **"Prewarm Relational On Load"** in the Inspector
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## 🧰 Additional Helpers & Recipes
|
|
390
|
+
|
|
391
|
+
### One-liners for DI + Relational Wiring
|
|
392
|
+
|
|
393
|
+
```csharp
|
|
394
|
+
// Inject + assign a single component
|
|
395
|
+
container.InjectWithRelations(component);
|
|
396
|
+
|
|
397
|
+
// Instantiate a component prefab + assign
|
|
398
|
+
var comp = container.InstantiateComponentWithRelations(prefabComp, parent);
|
|
399
|
+
|
|
400
|
+
// Inject + assign a whole hierarchy
|
|
401
|
+
container.InjectGameObjectWithRelations(root, includeInactiveChildren: true);
|
|
402
|
+
|
|
403
|
+
// Instantiate a GameObject prefab + inject + assign hierarchy
|
|
404
|
+
var go = container.InstantiateGameObjectWithRelations(prefabGo, parent);
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Additive Scenes & Options
|
|
408
|
+
|
|
409
|
+
Enable "Listen For Additive Scenes" in the installer, or manually control scene assignment:
|
|
410
|
+
|
|
411
|
+
```csharp
|
|
412
|
+
private Container _container;
|
|
413
|
+
|
|
414
|
+
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
|
|
415
|
+
{
|
|
416
|
+
if (mode == LoadSceneMode.Additive)
|
|
417
|
+
{
|
|
418
|
+
// Manually wire additive scene
|
|
419
|
+
_container.AssignRelationalScene(scene, includeInactive: true);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## ❓ Troubleshooting
|
|
427
|
+
|
|
428
|
+
### My relational fields are null even with the integration
|
|
429
|
+
|
|
430
|
+
**Check these common issues:**
|
|
431
|
+
|
|
432
|
+
1. **Did you add the installer?**
|
|
433
|
+
- Ensure `RelationalComponentsInstaller` is on your `SceneScope` GameObject
|
|
434
|
+
- Check that it's enabled in the Inspector
|
|
435
|
+
|
|
436
|
+
2. **Scene components not wired?**
|
|
437
|
+
- Enable **"Assign Scene On Initialize"** in the `RelationalComponentsInstaller`
|
|
438
|
+
- Or manually call `_container.AssignRelationalHierarchy(gameObject, includeInactiveChildren: true)` at bootstrap time
|
|
439
|
+
|
|
440
|
+
3. **Are you using the right attributes?**
|
|
441
|
+
- Fields need `[SiblingComponent]`, `[ParentComponent]`, or `[ChildComponent]` attributes
|
|
442
|
+
- These are different from `[Inject]` - you can use both on the same component
|
|
443
|
+
|
|
444
|
+
4. **Runtime instantiation not working?**
|
|
445
|
+
- Use `_container.InstantiateComponentWithRelations(...)`, `_container.InstantiateGameObjectWithRelations(...)`, or `_container.InjectGameObjectWithRelations(...)`
|
|
446
|
+
- Regular `Instantiate()` won't trigger relational wiring without these helpers
|
|
447
|
+
|
|
448
|
+
5. **Check your filters:**
|
|
449
|
+
- `TagFilter` must match an existing Unity tag exactly
|
|
450
|
+
- `NameFilter` is case-sensitive
|
|
451
|
+
|
|
452
|
+
### Do I need to call AssignRelationalComponents() in Awake()?
|
|
453
|
+
|
|
454
|
+
**No!** The integration handles this automatically:
|
|
455
|
+
|
|
456
|
+
- **Scene objects:** Wired when you enable "Assign Scene On Initialize" (recommended)
|
|
457
|
+
- **Runtime objects:** Wired when you call any of the helper methods (`InstantiateComponentWithRelations`, `InstantiateGameObjectWithRelations`, or `InjectGameObjectWithRelations`)
|
|
458
|
+
|
|
459
|
+
Only call `AssignRelationalComponents()` manually if you need fine-grained control.
|
|
460
|
+
|
|
461
|
+
### Does this work without Reflex?
|
|
462
|
+
|
|
463
|
+
**Yes!** The integration gracefully falls back to standard Unity Helpers behavior if Reflex isn't detected. You can:
|
|
464
|
+
|
|
465
|
+
- Adopt incrementally without breaking existing code
|
|
466
|
+
- Use in projects that mix DI and non-DI components
|
|
467
|
+
- Remove Reflex later without refactoring all your components
|
|
468
|
+
|
|
469
|
+
### Performance impact?
|
|
470
|
+
|
|
471
|
+
**Minimal:** Relational component assignment happens once per component at initialization time. After that, there's zero runtime overhead - the references are just regular fields.
|
|
472
|
+
|
|
473
|
+
**Optimization tips:**
|
|
474
|
+
|
|
475
|
+
- Use `MaxDepth` to limit hierarchy traversal
|
|
476
|
+
- Use `TagFilter` or `NameFilter` to narrow searches
|
|
477
|
+
- Use `OnlyDescendants`/`OnlyAncestors` to exclude self when appropriate
|
|
478
|
+
|
|
479
|
+
---
|
|
480
|
+
|
|
481
|
+
## 📚 Learn More
|
|
482
|
+
|
|
483
|
+
**Unity Helpers Documentation:**
|
|
484
|
+
|
|
485
|
+
- [Relational Components Guide](../../Docs/RELATIONAL_COMPONENTS.md) - Complete attribute reference and recipes
|
|
486
|
+
- [Getting Started](../../Docs/GETTING_STARTED.md) - Unity Helpers quick start guide
|
|
487
|
+
- [Main README](../../README.md) - Full feature overview
|
|
488
|
+
|
|
489
|
+
**Reflex Documentation:**
|
|
490
|
+
|
|
491
|
+
- [Reflex GitHub](https://github.com/gustavopsantos/reflex) - Official Reflex documentation and source code
|
|
492
|
+
|
|
493
|
+
**Troubleshooting:**
|
|
494
|
+
|
|
495
|
+
- [Relational Components Troubleshooting](../../Docs/RELATIONAL_COMPONENTS.md#troubleshooting) - Detailed solutions
|
|
496
|
+
- [DI Integration Testing Guide](../../Docs/RELATIONAL_COMPONENTS.md#di-integrations-testing-and-edge-cases) - Advanced scenarios
|
|
497
|
+
|
|
498
|
+
---
|
|
499
|
+
|
|
500
|
+
## 🎓 Next Steps
|
|
501
|
+
|
|
502
|
+
1. **Try the sample scene:** Open `Reflex_Sample.unity` and press Play
|
|
503
|
+
2. **Read the scripts:** See how `ReflexSpawner` and `ReflexRelationalConsumer` work
|
|
504
|
+
3. **Add to your project:** Add `RelationalComponentsInstaller` to your `SceneScope`
|
|
505
|
+
4. **Explore attributes:** Check out the [Relational Components Guide](../../Docs/RELATIONAL_COMPONENTS.md) for all options
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
## 🔄 Comparison: Reflex vs VContainer vs Zenject Integration
|
|
510
|
+
|
|
511
|
+
If you're choosing between DI frameworks, here's how the integrations differ:
|
|
512
|
+
|
|
513
|
+
| Feature | Reflex | VContainer | Zenject |
|
|
514
|
+
|---------|--------|------------|---------|
|
|
515
|
+
| Setup | Add installer to SceneScope | Call in LifetimeScope.Configure() | Add installer to SceneContext |
|
|
516
|
+
| Scene wiring | Toggle on installer | Automatic | Toggle on installer |
|
|
517
|
+
| Runtime instantiation | `InstantiateComponentWithRelations()`, `InstantiateGameObjectWithRelations()` | `InstantiateComponentWithRelations()`, `InstantiateGameObjectWithRelations()`, `BuildUpWithRelations()` | `InstantiateComponentWithRelations()`, `InstantiateGameObjectWithRelations()` |
|
|
518
|
+
| Performance | Fast | Slightly faster | Good |
|
|
519
|
+
| Maintenance | Actively developed | Actively developed | Community-maintained |
|
|
520
|
+
|
|
521
|
+
All three integrations provide the same relational component features - choose based on your DI framework preference.
|
|
522
|
+
|
|
523
|
+
---
|
|
524
|
+
|
|
525
|
+
## Made with ❤️ by Wallstop Studios
|
|
526
|
+
|
|
527
|
+
*Unity Helpers is production-ready and actively maintained. [Star the repo](https://github.com/wallstop/unity-helpers) if you find it useful!*
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
namespace Samples.UnityHelpers.DI.Reflex
|
|
2
|
+
{
|
|
3
|
+
using UnityEngine;
|
|
4
|
+
|
|
5
|
+
/// <summary>
|
|
6
|
+
/// Small service registered in the Reflex container so relational components receive dependencies.
|
|
7
|
+
/// </summary>
|
|
8
|
+
public sealed class ReflexPaletteService
|
|
9
|
+
{
|
|
10
|
+
private readonly Color _accentColor;
|
|
11
|
+
private readonly Color _inactiveColor;
|
|
12
|
+
private readonly Color _warningColor;
|
|
13
|
+
|
|
14
|
+
public ReflexPaletteService(Color accentColor, Color inactiveColor, Color warningColor)
|
|
15
|
+
{
|
|
16
|
+
_accentColor = accentColor;
|
|
17
|
+
_inactiveColor = inactiveColor;
|
|
18
|
+
_warningColor = warningColor;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public Color AccentColor
|
|
22
|
+
{
|
|
23
|
+
get { return _accentColor; }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public Color InactiveColor
|
|
27
|
+
{
|
|
28
|
+
get { return _inactiveColor; }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public Color WarningColor
|
|
32
|
+
{
|
|
33
|
+
get { return _warningColor; }
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
namespace Samples.UnityHelpers.DI.Reflex
|
|
2
|
+
{
|
|
3
|
+
using Reflex.Attributes;
|
|
4
|
+
using UnityEngine;
|
|
5
|
+
using WallstopStudios.UnityHelpers.Core.Attributes;
|
|
6
|
+
|
|
7
|
+
/// <summary>
|
|
8
|
+
/// Simple MonoBehaviour that receives a Reflex dependency and relational components at runtime.
|
|
9
|
+
/// </summary>
|
|
10
|
+
public sealed class ReflexRelationalConsumer : MonoBehaviour
|
|
11
|
+
{
|
|
12
|
+
[Inject]
|
|
13
|
+
private ReflexPaletteService _paletteService;
|
|
14
|
+
|
|
15
|
+
[SiblingComponent]
|
|
16
|
+
private SpriteRenderer _spriteRenderer;
|
|
17
|
+
|
|
18
|
+
[ChildComponent(OnlyDescendants = true)]
|
|
19
|
+
private ParticleSystem[] _childParticles;
|
|
20
|
+
|
|
21
|
+
private void Awake()
|
|
22
|
+
{
|
|
23
|
+
WarmUpParticles();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private void OnEnable()
|
|
27
|
+
{
|
|
28
|
+
ApplyAccentColor();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
private void OnDisable()
|
|
32
|
+
{
|
|
33
|
+
ApplyInactiveColor();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public void ApplyAccentColor()
|
|
37
|
+
{
|
|
38
|
+
if (_spriteRenderer != null && _paletteService != null)
|
|
39
|
+
{
|
|
40
|
+
_spriteRenderer.color = _paletteService.AccentColor;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public void ApplyInactiveColor()
|
|
45
|
+
{
|
|
46
|
+
if (_spriteRenderer != null && _paletteService != null)
|
|
47
|
+
{
|
|
48
|
+
_spriteRenderer.color = _paletteService.InactiveColor;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public void FlashWarningColor()
|
|
53
|
+
{
|
|
54
|
+
if (_spriteRenderer != null && _paletteService != null)
|
|
55
|
+
{
|
|
56
|
+
_spriteRenderer.color = _paletteService.WarningColor;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private void WarmUpParticles()
|
|
61
|
+
{
|
|
62
|
+
if (_childParticles == null)
|
|
63
|
+
{
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
for (int i = 0; i < _childParticles.Length; i++)
|
|
68
|
+
{
|
|
69
|
+
ParticleSystem system = _childParticles[i];
|
|
70
|
+
if (system == null)
|
|
71
|
+
{
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
system.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
namespace Samples.UnityHelpers.DI.Reflex
|
|
2
|
+
{
|
|
3
|
+
using Reflex.Core;
|
|
4
|
+
using UnityEngine;
|
|
5
|
+
|
|
6
|
+
/// <summary>
|
|
7
|
+
/// Installs lightweight sample services so the scene demonstrates Reflex + relational wiring.
|
|
8
|
+
/// </summary>
|
|
9
|
+
public sealed class ReflexSampleInstaller : MonoBehaviour, IInstaller
|
|
10
|
+
{
|
|
11
|
+
[SerializeField]
|
|
12
|
+
private Color _accentColor = new Color(0.156f, 0.768f, 0.972f, 1.0f);
|
|
13
|
+
|
|
14
|
+
[SerializeField]
|
|
15
|
+
private Color _inactiveColor = new Color(0.196f, 0.196f, 0.196f, 1.0f);
|
|
16
|
+
|
|
17
|
+
[SerializeField]
|
|
18
|
+
private Color _warningColor = new Color(0.949f, 0.419f, 0.270f, 1.0f);
|
|
19
|
+
|
|
20
|
+
public void InstallBindings(ContainerBuilder builder)
|
|
21
|
+
{
|
|
22
|
+
builder.AddSingleton(CreatePaletteService, typeof(ReflexPaletteService));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private ReflexPaletteService CreatePaletteService(Container container)
|
|
26
|
+
{
|
|
27
|
+
return new ReflexPaletteService(_accentColor, _inactiveColor, _warningColor);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|