com.wallstop-studios.unity-helpers 2.0.0-rc81.9 → 2.0.0
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/.editorconfig +1 -1
- package/.gitattributes +1 -1
- package/.githooks/pre-commit +31 -5
- package/.githooks/pre-push +50 -0
- package/.github/dependabot.yml +24 -2
- package/.github/scripts/check-markdown-links.ps1 +77 -0
- package/.github/scripts/check_markdown_links.py +89 -0
- package/.github/scripts/check_markdown_url_encoding.py +74 -0
- package/.github/scripts/validate_markdown_links.py +194 -0
- package/.github/workflows/csharpier-autofix.yml +152 -0
- package/.github/workflows/format-on-demand.yml +305 -0
- package/.github/workflows/lint-doc-links.yml +8 -5
- package/.github/workflows/markdown-json.yml +6 -2
- package/.github/workflows/prettier-autofix.yml +195 -0
- package/.github/workflows/update-dotnet-tools.yml +80 -0
- package/.github/workflows/yaml-format-lint.yml +41 -0
- package/.lychee.toml +4 -4
- package/.markdownlint.jsonc +21 -0
- package/.pre-commit-config.yaml +11 -3
- package/.yamllint.yaml +31 -0
- package/AGENTS.md +5 -1
- package/CHANGELOG.md +11 -0
- package/CONTRIBUTING.md +49 -0
- package/CONTRIBUTING.md.meta +7 -0
- package/EDITOR_TOOLS_GUIDE.md +4 -0
- package/Editor/AnimationEventEditor.cs +337 -160
- package/Editor/Core/Helper/AnimationEventHelpers.cs +178 -152
- package/Editor/CustomEditors/PersistentDirectoryGUI.cs +20 -11
- package/Editor/CustomEditors/TexturePlatformOverrideEntryDrawer.cs +11 -2
- package/Editor/FitTextureSizeWindow.cs +43 -19
- package/Editor/PersistentDirectorySettings.cs +64 -12
- package/Editor/PrefabChecker.cs +72 -5
- package/Editor/Sprites/AnimationCopier.cs +132 -56
- package/Editor/Sprites/AnimationCreator.cs +63 -22
- package/Editor/Sprites/AnimationViewerWindow.cs +42 -6
- package/Editor/Sprites/TexturePlatformNameHelper.cs +50 -39
- package/Editor/Sprites/TextureResizerWizard.cs +23 -1
- package/Editor/Sprites/TextureSettingsApplierWindow.cs +148 -85
- package/Editor/Tools/ImageBlurTool.cs +81 -10
- package/Editor/Utils/EditorUi.cs +1 -1
- package/Editor/Utils/ScriptableObjectSingletonCreator.cs +1 -1
- package/GETTING_STARTED.md +40 -56
- package/RANDOM_PERFORMANCE.md +12 -12
- package/README.md +395 -2407
- package/RELATIONAL_COMPONENTS.md +92 -83
- package/Runtime/AssemblyInfo.cs +2 -0
- package/Runtime/Core/Attributes/NotNullAttribute.cs +1 -3
- package/Runtime/Core/Attributes/RelationalComponentAssigner.cs +50 -5
- package/Runtime/Core/DataStructure/CyclicBuffer.cs +0 -1
- package/Runtime/Core/Extension/RandomExtensions.cs +68 -0
- package/Runtime/Core/Extension/WallstopStudiosLogger.cs +16 -0
- package/Runtime/Core/Helper/Partials/ObjectHelpers.cs +4 -1
- package/Runtime/Core/Helper/ReflectionHelpers.cs +21 -10
- package/Runtime/Core/Helper/SpriteHelpers.cs +3 -1
- package/Runtime/Core/Helper/UnityMainThreadDispatcher.cs +45 -1
- package/Runtime/Core/Serialization/JsonConverters/GameObjectConverter.cs +13 -5
- package/Runtime/Core/Serialization/JsonConverters/ResolutionConverter.cs +1 -1
- package/Runtime/Core/Serialization/JsonConverters/TypeConverter.cs +1 -1
- package/Runtime/Core/Serialization/Serializer.cs +101 -0
- package/Runtime/Integrations/VContainer/AssemblyInfo.cs +9 -0
- package/Runtime/Integrations/VContainer/AssemblyInfo.cs.meta +3 -0
- package/Runtime/Integrations/VContainer/ObjectResolverRelationalExtensions.cs +96 -0
- package/Runtime/Integrations/VContainer/RelationalComponentEntryPoint.cs +90 -10
- package/Runtime/Integrations/VContainer/RelationalComponentsBuilderExtensions.cs +13 -1
- package/Runtime/Integrations/VContainer/RelationalObjectPools.cs +114 -0
- package/Runtime/Integrations/VContainer/RelationalObjectPools.cs.meta +11 -0
- package/Runtime/Integrations/VContainer/RelationalSceneAssignmentOptions.cs +16 -4
- package/Runtime/Integrations/VContainer/RelationalSceneLoadListener.cs +241 -0
- package/Runtime/Integrations/VContainer/RelationalSceneLoadListener.cs.meta +11 -0
- package/Runtime/Integrations/Zenject/AssemblyInfo.cs +9 -0
- package/Runtime/Integrations/Zenject/AssemblyInfo.cs.meta +3 -0
- package/Runtime/Integrations/Zenject/DiContainerRelationalExtensions.cs +69 -2
- package/Runtime/Integrations/Zenject/RelationalComponentSceneInitializer.cs +89 -12
- package/Runtime/Integrations/Zenject/RelationalComponentsInstaller.cs +23 -1
- package/Runtime/Integrations/Zenject/RelationalMemoryPools.cs +44 -0
- package/Runtime/Integrations/Zenject/RelationalMemoryPools.cs.meta +11 -0
- package/Runtime/Integrations/Zenject/RelationalSceneAssignmentOptions.cs +16 -10
- package/Runtime/Integrations/Zenject/RelationalSceneLoadListener.cs +243 -0
- package/Runtime/Integrations/Zenject/RelationalSceneLoadListener.cs.meta +11 -0
- package/Runtime/Tags/AttributeMetadataCache.cs +1 -4
- package/Runtime/Utils/Buffers.cs +4 -4
- package/Runtime/Utils/ScriptableObjectSingleton.cs +0 -1
- package/Runtime/Utils/SetTextureImportData.cs +3 -1
- package/Runtime/Utils/TextureScale.cs +10 -2
- package/Runtime/Visuals/UGUI/EnhancedImage.cs +6 -0
- package/Runtime/Visuals/UIToolkit/LayeredImage.cs +4 -1
- package/SERIALIZATION.md +15 -0
- package/SPATIAL_TREE_2D_PERFORMANCE.md +85 -82
- package/SPATIAL_TREE_3D_PERFORMANCE.md +94 -91
- package/Samples~/DI - VContainer/README.md +232 -51
- package/Samples~/DI - VContainer/Scripts/GameLifetimeScope.cs +22 -4
- package/Samples~/DI - VContainer/Scripts/RelationalConsumer.cs +5 -2
- package/Samples~/DI - VContainer/Scripts/Spawner.cs +113 -4
- package/Samples~/DI - Zenject/README.md +217 -53
- package/Samples~/DI - Zenject/Scripts/RelationalConsumer.cs +3 -0
- package/Samples~/DI - Zenject/Scripts/RelationalConsumerPool.cs +37 -0
- package/Samples~/DI - Zenject/Scripts/RelationalConsumerPool.cs.meta +12 -0
- package/Samples~/DI - Zenject/Scripts/SpawnerZenject.cs +74 -3
- package/Samples~/Random - PRNG/README.md +2 -1
- package/Samples~/Relational Components - Basic/README.md +3 -1
- package/Samples~/Serialization - JSON/README.md +2 -1
- package/Samples~/Spatial Structures - 2D and 3D/README.md +2 -1
- package/Samples~/UGUI - EnhancedImage/README.md +2 -1
- package/Samples~/UI Toolkit - MultiFile Selector (Editor)/README.md +2 -1
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/Tests/Editor/Attributes/AnimationEventHelpersTests.cs +16 -0
- package/Tests/Editor/Core/Attributes/RelationalComponentAssignerTests.cs +3 -3
- package/Tests/Editor/Integrations/VContainer/VContainerRelationalEntryPointTests.cs +6 -2
- package/Tests/Editor/Integrations/VContainer/VContainerRelationalHelpersTests.cs +170 -0
- package/Tests/Editor/Integrations/VContainer/VContainerRelationalHelpersTests.cs.meta +11 -0
- package/Tests/Editor/Integrations/VContainer/WallstopStudios.UnityHelpers.Tests.Editor.VContainer.asmdef +2 -1
- package/Tests/Editor/Integrations/Zenject/WallstopStudios.UnityHelpers.Tests.Editor.Zenject.asmdef +3 -2
- package/Tests/Editor/Integrations/Zenject/ZenjectRelationalHelpersTests.cs +131 -0
- package/Tests/Editor/Integrations/Zenject/ZenjectRelationalHelpersTests.cs.meta +11 -0
- package/Tests/Editor/Integrations/Zenject/ZenjectRelationalInitializerTests.cs +6 -2
- package/Tests/Editor/PersistentDirectorySettingsTests.cs +59 -0
- package/Tests/Editor/PersistentDirectorySettingsTests.cs.meta +11 -0
- package/Tests/Editor/PrefabCheckerReportTests.cs +32 -0
- package/Tests/Editor/PrefabCheckerReportTests.cs.meta +11 -0
- package/Tests/Editor/Sprites/AnimationCopierFilterTests.cs +64 -0
- package/Tests/Editor/Sprites/AnimationCopierFilterTests.cs.meta +11 -0
- package/Tests/Editor/Sprites/AnimationCopierWindowTests.cs +1 -1
- package/Tests/Editor/Sprites/AnimationViewerWindowTests.cs +38 -0
- package/Tests/Editor/Sprites/AnimationViewerWindowTests.cs.meta +11 -0
- package/Tests/Editor/Sprites/ScriptableSpriteAtlasEditorTests.cs +1 -1
- package/Tests/Editor/Sprites/SpriteCropperAdditionalTests.cs +12 -12
- package/Tests/Editor/Sprites/SpriteCropperTests.cs +9 -9
- package/Tests/Editor/Sprites/SpritePivotAdjusterTests.cs +3 -3
- package/Tests/Editor/Sprites/TexturePlatformNameHelperTests.cs +18 -0
- package/Tests/Editor/Sprites/TextureResizerWizardTests.cs +5 -5
- package/Tests/Editor/Sprites/TextureSettingsApplierAPITests.cs +3 -3
- package/Tests/Editor/Sprites/TextureSettingsApplierWizardAdditionalTests.cs +4 -4
- package/Tests/Editor/Sprites/TextureSettingsApplierWizardTests.cs +4 -4
- package/Tests/Editor/Tools/ImageBlurToolTests.cs +22 -110
- package/Tests/Editor/Utils/CommonTestBase.cs +43 -1
- package/Tests/Editor/Utils/ScriptableObjectSingletonCreatorTests.cs +5 -5
- package/Tests/Editor/Windows/FitTextureSizeWindowTests.cs +66 -74
- package/Tests/Runtime/Attributes/RelationalComponentInitializerTests.cs +4 -15
- package/Tests/Runtime/DataStructures/SpatialTree3DBoundsConsistencyTests.cs +29 -29
- package/Tests/Runtime/Integrations/VContainer/RelationalComponentsVContainerTests.cs +259 -218
- package/Tests/Runtime/Integrations/VContainer/RelationalObjectPoolsVContainerTests.cs +86 -0
- package/Tests/Runtime/Integrations/VContainer/RelationalObjectPoolsVContainerTests.cs.meta +11 -0
- package/Tests/Runtime/Integrations/Zenject/RelationalComponentsZenjectTests.cs +255 -227
- package/Tests/Runtime/Performance/SpatialTree2DPerformanceTests.cs +5 -0
- package/Tests/Runtime/Performance/SpatialTree3DPerformanceTests.cs +3 -0
- package/Tests/Runtime/Serialization/JsonConverterAdditionalTests.cs +30 -0
- package/Tests/Runtime/Serialization/JsonConverterAdditionalTests.cs.meta +11 -0
- package/Tests/Runtime/Serialization/JsonConverterTests.cs +8 -12
- package/Tests/Runtime/Serialization/JsonSerializationTest.cs +16 -5
- package/Tests/Runtime/Serialization/SerializerAdditionalTests.cs +12 -0
- package/Tests/Runtime/Serialization/SerializerFileIoTests.cs +105 -0
- package/Tests/Runtime/Serialization/SerializerFileIoTests.cs.meta +11 -0
- package/Tests/Runtime/Serialization/UnityEngineObjectJsonTests.cs +247 -0
- package/Tests/Runtime/Serialization/UnityEngineObjectJsonTests.cs.meta +11 -0
- package/Tests/Runtime/TestUtils/CommonTestBase.cs +88 -0
- package/Tests/Runtime/Utils/CoroutineHandlerTests.cs +1 -1
- package/Tests/Runtime/Utils/LZMAComprehensiveTests.cs +1 -1
- package/Tests/Runtime/Utils/LZMATests.cs +1 -1
- package/Tests/Runtime/Utils/MatchColliderToSpriteTests.cs +1 -1
- package/Tests/Runtime/Visuals/EnhancedImageTests.cs +25 -56
- package/Tests/Runtime/Visuals/VisualsTestHelpers.cs +1 -8
- package/package-lock.json.meta +7 -0
- package/package.json +8 -4
- package/scripts/check-eol.ps1 +4 -5
- package/scripts/lint-tests.ps1 +156 -0
- package/scripts/lint-tests.ps1.meta +7 -0
- package/scripts/normalize-eol.ps1 +6 -9
- package/.github/workflows/csharpier.yml +0 -135
|
@@ -2,17 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
## Why This Integration Matters
|
|
4
4
|
|
|
5
|
-
**
|
|
6
|
-
1. **Dependencies** (injected via constructor/properties)
|
|
7
|
-
2. **Hierarchy references** (SpriteRenderer, Rigidbody2D, child colliders, etc.)
|
|
5
|
+
**Stop Writing GetComponent Boilerplate in Every Single Script**
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
When using dependency injection with VContainer, 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.
|
|
10
8
|
|
|
11
|
-
**The
|
|
9
|
+
**The Painful Reality:**
|
|
10
|
+
|
|
11
|
+
1. **Dependencies** → ✅ Handled by VContainer (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**.
|
|
12
17
|
|
|
13
18
|
### ⚡ Quick Example: Before vs After
|
|
14
19
|
|
|
15
20
|
**Before (Manual):**
|
|
21
|
+
|
|
16
22
|
```csharp
|
|
17
23
|
public class Enemy : MonoBehaviour
|
|
18
24
|
{
|
|
@@ -36,6 +42,7 @@ public class Enemy : MonoBehaviour
|
|
|
36
42
|
```
|
|
37
43
|
|
|
38
44
|
**After (With Integration):**
|
|
45
|
+
|
|
39
46
|
```csharp
|
|
40
47
|
public class Enemy : MonoBehaviour
|
|
41
48
|
{
|
|
@@ -50,7 +57,9 @@ public class Enemy : MonoBehaviour
|
|
|
50
57
|
}
|
|
51
58
|
```
|
|
52
59
|
|
|
53
|
-
|
|
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.
|
|
54
63
|
|
|
55
64
|
---
|
|
56
65
|
|
|
@@ -58,53 +67,77 @@ public class Enemy : MonoBehaviour
|
|
|
58
67
|
|
|
59
68
|
### Step 1: Register the Integration
|
|
60
69
|
|
|
61
|
-
In your `LifetimeScope`,
|
|
70
|
+
In your `LifetimeScope`, enable the integration (the sample exposes the three toggles below in the inspector so you can experiment without touching code):
|
|
62
71
|
|
|
63
72
|
```csharp
|
|
73
|
+
using UnityEngine;
|
|
64
74
|
using VContainer;
|
|
65
75
|
using VContainer.Unity;
|
|
66
76
|
using WallstopStudios.UnityHelpers.Integrations.VContainer;
|
|
67
77
|
|
|
68
|
-
public class GameLifetimeScope : LifetimeScope
|
|
78
|
+
public sealed class GameLifetimeScope : LifetimeScope
|
|
69
79
|
{
|
|
80
|
+
[SerializeField] private bool _includeInactiveSceneObjects = true;
|
|
81
|
+
[SerializeField] private bool _useSinglePassScan = true;
|
|
82
|
+
[SerializeField] private bool _listenForAdditiveScenes = true;
|
|
83
|
+
|
|
70
84
|
protected override void Configure(IContainerBuilder builder)
|
|
71
85
|
{
|
|
72
86
|
// Your existing registrations...
|
|
73
87
|
builder.Register<PlayerController>(Lifetime.Singleton);
|
|
74
88
|
builder.Register<IHealthSystem, HealthSystem>(Lifetime.Scoped);
|
|
75
89
|
|
|
76
|
-
|
|
77
|
-
|
|
90
|
+
RelationalSceneAssignmentOptions options = new RelationalSceneAssignmentOptions(
|
|
91
|
+
_includeInactiveSceneObjects,
|
|
92
|
+
_useSinglePassScan
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
// ✨ Scene scan + optional additive-scene listener
|
|
96
|
+
builder.RegisterRelationalComponents(options, _listenForAdditiveScenes);
|
|
78
97
|
}
|
|
79
98
|
}
|
|
80
99
|
```
|
|
81
100
|
|
|
82
|
-
**That's it!** All scene components with relational attributes are now automatically wired after DI injection.
|
|
101
|
+
**That's it!** All scene components with relational attributes are now automatically wired after DI injection, and additively loaded scenes can opt-in to the same treatment.
|
|
102
|
+
|
|
103
|
+
> 💡 **Beginner tip:** Not sure what these options do? Leave them all enabled (the defaults). You can always tune them later.
|
|
104
|
+
>
|
|
105
|
+
> - `includeInactiveSceneObjects` → Wires disabled GameObjects too (usually what you want)
|
|
106
|
+
> - `useSinglePassScan` → Faster scanning (always leave this on)
|
|
107
|
+
> - `listenForAdditiveScenes` → Auto-wires newly loaded scenes (great for multi-scene setups)
|
|
83
108
|
|
|
84
109
|
### Step 2: Use With Runtime Instantiation
|
|
85
110
|
|
|
86
|
-
When spawning prefabs at runtime, use
|
|
111
|
+
When spawning prefabs at runtime, use the helpers that combine instantiation, DI, and relational assignment:
|
|
87
112
|
|
|
88
113
|
```csharp
|
|
89
114
|
using UnityEngine;
|
|
90
115
|
using VContainer;
|
|
91
116
|
using WallstopStudios.UnityHelpers.Integrations.VContainer;
|
|
92
117
|
|
|
93
|
-
public class EnemySpawner : MonoBehaviour
|
|
118
|
+
public sealed class EnemySpawner : MonoBehaviour
|
|
94
119
|
{
|
|
95
120
|
[Inject] private IObjectResolver _resolver;
|
|
96
121
|
[SerializeField] private Enemy _enemyPrefab;
|
|
122
|
+
[SerializeField] private GameObject _enemySquadPrefab;
|
|
97
123
|
|
|
98
|
-
public
|
|
124
|
+
public Enemy SpawnEnemy(Transform parent)
|
|
99
125
|
{
|
|
100
|
-
|
|
126
|
+
return _resolver.InstantiateComponentWithRelations(_enemyPrefab, parent);
|
|
127
|
+
}
|
|
101
128
|
|
|
102
|
-
|
|
103
|
-
|
|
129
|
+
public GameObject SpawnEnemySquad(Transform parent)
|
|
130
|
+
{
|
|
131
|
+
return _resolver.InstantiateGameObjectWithRelations(
|
|
132
|
+
_enemySquadPrefab,
|
|
133
|
+
parent,
|
|
134
|
+
includeInactiveChildren: true
|
|
135
|
+
);
|
|
136
|
+
}
|
|
104
137
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
138
|
+
public void HydrateExisting(GameObject root)
|
|
139
|
+
{
|
|
140
|
+
_resolver.AssignRelationalHierarchy(root, includeInactiveChildren: true);
|
|
108
141
|
}
|
|
109
142
|
}
|
|
110
143
|
```
|
|
@@ -115,11 +148,11 @@ public class EnemySpawner : MonoBehaviour
|
|
|
115
148
|
|
|
116
149
|
This sample provides a complete working example:
|
|
117
150
|
|
|
118
|
-
- **Scripts/GameLifetimeScope.cs** -
|
|
119
|
-
- **Scripts/Spawner.cs** -
|
|
151
|
+
- **Scripts/GameLifetimeScope.cs** - LifetimeScope with inspector-driven options for include-inactive, scan strategy, and additive-scene listening
|
|
152
|
+
- **Scripts/Spawner.cs** - Demonstrates `InstantiateComponentWithRelations`, `InstantiateGameObjectWithRelations`, pooling helpers, and hydrating existing hierarchies
|
|
120
153
|
- **Scripts/RelationalConsumer.cs** - Component demonstrating relational attributes
|
|
121
154
|
- **Prefabs/RelationalConsumer.prefab** - Example prefab with relational fields
|
|
122
|
-
- **Prefabs/Spawner.prefab** - Spawner prefab
|
|
155
|
+
- **Prefabs/Spawner.prefab** - Spawner prefab wired to the helper methods above
|
|
123
156
|
- **Scenes/VContainer_Sample.unity** - Complete working scene ready to play
|
|
124
157
|
|
|
125
158
|
### How to Import This Sample
|
|
@@ -132,11 +165,15 @@ This sample provides a complete working example:
|
|
|
132
165
|
|
|
133
166
|
---
|
|
134
167
|
|
|
135
|
-
## 🎯 Common Use Cases
|
|
168
|
+
## 🎯 Common Use Cases (By Experience Level)
|
|
169
|
+
|
|
170
|
+
### 🟢 Beginner: "I just want my components to work"
|
|
171
|
+
|
|
172
|
+
**Perfect for:** Player controllers, enemy AI, simple gameplay scripts
|
|
136
173
|
|
|
137
|
-
|
|
174
|
+
**What you get:** No more `GetComponent` calls, no more null reference exceptions from missing components
|
|
138
175
|
|
|
139
|
-
|
|
176
|
+
**Example:**
|
|
140
177
|
|
|
141
178
|
```csharp
|
|
142
179
|
public class PlayerController : MonoBehaviour
|
|
@@ -161,50 +198,130 @@ public class PlayerController : MonoBehaviour
|
|
|
161
198
|
}
|
|
162
199
|
```
|
|
163
200
|
|
|
164
|
-
###
|
|
201
|
+
### 🟡 Intermediate: "I'm spawning objects at runtime"
|
|
165
202
|
|
|
166
|
-
|
|
203
|
+
**Perfect for:** Enemy spawners, projectile systems, object pooling
|
|
204
|
+
|
|
205
|
+
**What you get:** One-line instantiation that handles DI injection + hierarchy wiring automatically
|
|
206
|
+
|
|
207
|
+
**Example:**
|
|
167
208
|
|
|
168
209
|
```csharp
|
|
169
|
-
public class ProjectileSpawner : MonoBehaviour
|
|
210
|
+
public sealed class ProjectileSpawner : MonoBehaviour
|
|
170
211
|
{
|
|
171
212
|
[Inject] private IObjectResolver _resolver;
|
|
172
213
|
[SerializeField] private Projectile _projectilePrefab;
|
|
173
214
|
|
|
174
|
-
public
|
|
215
|
+
public Projectile Fire(Vector3 position, Vector3 forward)
|
|
175
216
|
{
|
|
176
|
-
Projectile projectile =
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
projectile.Launch(direction);
|
|
217
|
+
Projectile projectile = _resolver.InstantiateComponentWithRelations(_projectilePrefab);
|
|
218
|
+
projectile.transform.SetPositionAndRotation(position, Quaternion.LookRotation(forward));
|
|
219
|
+
projectile.Launch(forward);
|
|
220
|
+
return projectile;
|
|
182
221
|
}
|
|
183
222
|
}
|
|
184
223
|
```
|
|
185
224
|
|
|
186
|
-
###
|
|
225
|
+
### 🔴 Advanced: "I have complex hierarchies and custom workflows"
|
|
226
|
+
|
|
227
|
+
**Perfect for:** UI systems, vehicles with multiple parts, procedural generation, custom object pools
|
|
228
|
+
|
|
229
|
+
**What you get:** Full control over when and how wiring happens, with helpers for every scenario
|
|
187
230
|
|
|
188
|
-
|
|
231
|
+
**Example:**
|
|
189
232
|
|
|
190
233
|
```csharp
|
|
191
|
-
public class VehicleFactory : MonoBehaviour
|
|
234
|
+
public sealed class VehicleFactory : MonoBehaviour
|
|
192
235
|
{
|
|
193
236
|
[Inject] private IObjectResolver _resolver;
|
|
194
237
|
[SerializeField] private GameObject _vehiclePrefab;
|
|
195
238
|
|
|
196
|
-
public GameObject CreateVehicle()
|
|
239
|
+
public GameObject CreateVehicle(Transform parent)
|
|
240
|
+
{
|
|
241
|
+
return _resolver.InstantiateGameObjectWithRelations(
|
|
242
|
+
_vehiclePrefab,
|
|
243
|
+
parent,
|
|
244
|
+
includeInactiveChildren: true
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## 💡 Real-World Impact: A Day in the Life
|
|
253
|
+
|
|
254
|
+
### Without This Integration
|
|
255
|
+
|
|
256
|
+
**Morning:** You start work on a new enemy type.
|
|
257
|
+
|
|
258
|
+
```csharp
|
|
259
|
+
public class FlyingEnemy : MonoBehaviour
|
|
260
|
+
{
|
|
261
|
+
[Inject] private IHealthSystem _health;
|
|
262
|
+
[Inject] private IAudioService _audio;
|
|
263
|
+
|
|
264
|
+
private Animator _animator;
|
|
265
|
+
private Rigidbody2D _rigidbody;
|
|
266
|
+
private SpriteRenderer _sprite;
|
|
267
|
+
private Collider2D[] _hitboxes;
|
|
268
|
+
private Transform _weaponMount;
|
|
269
|
+
|
|
270
|
+
void Awake()
|
|
197
271
|
{
|
|
198
|
-
|
|
272
|
+
_animator = GetComponent<Animator>();
|
|
273
|
+
if (_animator == null) Debug.LogError("Missing Animator on FlyingEnemy!");
|
|
274
|
+
|
|
275
|
+
_rigidbody = GetComponent<Rigidbody2D>();
|
|
276
|
+
if (_rigidbody == null) Debug.LogError("Missing Rigidbody2D on FlyingEnemy!");
|
|
199
277
|
|
|
200
|
-
|
|
201
|
-
|
|
278
|
+
_sprite = GetComponent<SpriteRenderer>();
|
|
279
|
+
if (_sprite == null) Debug.LogError("Missing SpriteRenderer on FlyingEnemy!");
|
|
202
280
|
|
|
203
|
-
|
|
281
|
+
_hitboxes = GetComponentsInChildren<Collider2D>();
|
|
282
|
+
if (_hitboxes.Length == 0) Debug.LogWarning("No hitboxes found on FlyingEnemy!");
|
|
283
|
+
|
|
284
|
+
_weaponMount = transform.Find("WeaponMount");
|
|
285
|
+
if (_weaponMount == null) Debug.LogError("Missing WeaponMount on FlyingEnemy!");
|
|
286
|
+
|
|
287
|
+
// Finally, actual game logic can start...
|
|
204
288
|
}
|
|
205
289
|
}
|
|
206
290
|
```
|
|
207
291
|
|
|
292
|
+
**10 minutes later:** You've written 20+ lines of boilerplate before writing any actual game logic.
|
|
293
|
+
|
|
294
|
+
**30 minutes later:** Null reference exception in the build! You forgot to add the SpriteRenderer to the prefab.
|
|
295
|
+
|
|
296
|
+
**60 minutes later:** You're manually wiring up the 8th enemy variant of the day...
|
|
297
|
+
|
|
298
|
+
### With This Integration
|
|
299
|
+
|
|
300
|
+
**Morning:** You start work on a new enemy type.
|
|
301
|
+
|
|
302
|
+
```csharp
|
|
303
|
+
public class FlyingEnemy : MonoBehaviour
|
|
304
|
+
{
|
|
305
|
+
[Inject] private IHealthSystem _health;
|
|
306
|
+
[Inject] private IAudioService _audio;
|
|
307
|
+
|
|
308
|
+
[SiblingComponent] private Animator _animator;
|
|
309
|
+
[SiblingComponent] private Rigidbody2D _rigidbody;
|
|
310
|
+
[SiblingComponent] private SpriteRenderer _sprite;
|
|
311
|
+
[ChildComponent] private Collider2D[] _hitboxes;
|
|
312
|
+
[ChildComponent(NameFilter = "WeaponMount")] private Transform _weaponMount;
|
|
313
|
+
|
|
314
|
+
// Start writing game logic immediately
|
|
315
|
+
void Start() => _animator.Play("Idle");
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**2 minutes later:** You're done with wiring and writing game logic.
|
|
320
|
+
|
|
321
|
+
**10 minutes later:** You've shipped 5 enemy variants with zero boilerplate.
|
|
322
|
+
|
|
323
|
+
**Never:** You never see "Missing component" runtime errors because validation happens automatically with helpful messages.
|
|
324
|
+
|
|
208
325
|
---
|
|
209
326
|
|
|
210
327
|
## 🔧 Advanced Configuration
|
|
@@ -217,14 +334,15 @@ By default, inactive GameObjects are included in the initial scene scan. To scan
|
|
|
217
334
|
protected override void Configure(IContainerBuilder builder)
|
|
218
335
|
{
|
|
219
336
|
builder.RegisterRelationalComponents(
|
|
220
|
-
new RelationalSceneAssignmentOptions(includeInactive: false)
|
|
337
|
+
new RelationalSceneAssignmentOptions(includeInactive: false),
|
|
338
|
+
enableAdditiveSceneListener: false
|
|
221
339
|
);
|
|
222
340
|
}
|
|
223
341
|
```
|
|
224
342
|
|
|
225
|
-
### Manual
|
|
343
|
+
### Manual Wiring Helpers
|
|
226
344
|
|
|
227
|
-
If you need to
|
|
345
|
+
If you need to hydrate instances that were created outside of the resolver:
|
|
228
346
|
|
|
229
347
|
```csharp
|
|
230
348
|
[Inject] private IObjectResolver _resolver;
|
|
@@ -234,6 +352,11 @@ void WireComponentOnly(MonoBehaviour component)
|
|
|
234
352
|
// Only assigns relational component fields, skips DI injection
|
|
235
353
|
_resolver.AssignRelationalComponents(component);
|
|
236
354
|
}
|
|
355
|
+
|
|
356
|
+
void WireHierarchy(GameObject root)
|
|
357
|
+
{
|
|
358
|
+
_resolver.AssignRelationalHierarchy(root, includeInactiveChildren: true);
|
|
359
|
+
}
|
|
237
360
|
```
|
|
238
361
|
|
|
239
362
|
### Performance: Prewarming Reflection Caches
|
|
@@ -251,11 +374,63 @@ void Start()
|
|
|
251
374
|
```
|
|
252
375
|
|
|
253
376
|
Or enable auto-prewarm on the `AttributeMetadataCache` asset:
|
|
377
|
+
|
|
254
378
|
1. Find the asset: `Assets > Create > Wallstop Studios > Unity Helpers > Attribute Metadata Cache`
|
|
255
379
|
2. Enable **"Prewarm Relational On Load"** in the Inspector
|
|
256
380
|
|
|
257
381
|
---
|
|
258
382
|
|
|
383
|
+
## 🧰 Additional Helpers & Recipes
|
|
384
|
+
|
|
385
|
+
### One-liners for DI + Relational Wiring
|
|
386
|
+
|
|
387
|
+
```csharp
|
|
388
|
+
// Inject + assign a single component
|
|
389
|
+
resolver.InjectWithRelations(component);
|
|
390
|
+
|
|
391
|
+
// Instantiate a component prefab + inject + assign
|
|
392
|
+
var comp = resolver.InstantiateComponentWithRelations(prefabComp, parent);
|
|
393
|
+
|
|
394
|
+
// Inject + assign a whole hierarchy
|
|
395
|
+
resolver.InjectGameObjectWithRelations(root, includeInactiveChildren: true);
|
|
396
|
+
|
|
397
|
+
// Instantiate a GameObject prefab + inject + assign hierarchy
|
|
398
|
+
var go = resolver.InstantiateGameObjectWithRelations(prefabGo, parent);
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
### Additive Scenes & Options
|
|
402
|
+
|
|
403
|
+
The registration can enable an additive-scene listener that hydrates relational fields in newly loaded scenes, and you can customize scan behavior:
|
|
404
|
+
|
|
405
|
+
```csharp
|
|
406
|
+
protected override void Configure(IContainerBuilder builder)
|
|
407
|
+
{
|
|
408
|
+
var options = new RelationalSceneAssignmentOptions(
|
|
409
|
+
includeInactive: true,
|
|
410
|
+
useSinglePassScan: true
|
|
411
|
+
);
|
|
412
|
+
builder.RegisterRelationalComponents(options, enableAdditiveSceneListener: true);
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### Pools
|
|
417
|
+
|
|
418
|
+
Use DI-aware pools to auto-inject and assign on rent:
|
|
419
|
+
|
|
420
|
+
```csharp
|
|
421
|
+
// Component pool
|
|
422
|
+
var pool = RelationalObjectPools.CreatePoolWithRelations(
|
|
423
|
+
createFunc: () => Instantiate(componentPrefab)
|
|
424
|
+
);
|
|
425
|
+
var item = pool.GetWithRelations(resolver);
|
|
426
|
+
|
|
427
|
+
// GameObject pool
|
|
428
|
+
var goPool = RelationalObjectPools.CreateGameObjectPoolWithRelations(prefab);
|
|
429
|
+
var instance = goPool.GetWithRelations(resolver);
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
---
|
|
433
|
+
|
|
259
434
|
## ❓ Troubleshooting
|
|
260
435
|
|
|
261
436
|
### My relational fields are null even with the integration
|
|
@@ -270,8 +445,8 @@ Or enable auto-prewarm on the `AttributeMetadataCache` asset:
|
|
|
270
445
|
- These are different from `[Inject]` - you can use both on the same component
|
|
271
446
|
|
|
272
447
|
3. **Runtime instantiation not working?**
|
|
273
|
-
- Use `_resolver.
|
|
274
|
-
- Regular `Instantiate()` won't trigger
|
|
448
|
+
- Use `_resolver.InstantiateComponentWithRelations(...)`, `_resolver.InstantiateGameObjectWithRelations(...)`, or `_resolver.AssignRelationalHierarchy(...)`
|
|
449
|
+
- Regular `Instantiate()` on its own won't trigger relational wiring
|
|
275
450
|
|
|
276
451
|
4. **Check your filters:**
|
|
277
452
|
- `TagFilter` must match an existing Unity tag exactly
|
|
@@ -280,14 +455,16 @@ Or enable auto-prewarm on the `AttributeMetadataCache` asset:
|
|
|
280
455
|
### Do I need to call AssignRelationalComponents() in Awake()?
|
|
281
456
|
|
|
282
457
|
**No!** The integration handles this automatically:
|
|
458
|
+
|
|
283
459
|
- **Scene objects:** Wired during scene initialization (after container builds)
|
|
284
|
-
- **Runtime objects:** Wired when you call `
|
|
460
|
+
- **Runtime objects:** Wired when you call any of the helper methods (`InstantiateComponentWithRelations`, `InstantiateGameObjectWithRelations`, `AssignRelationalHierarchy`, or the pooling `GetWithRelations` helpers)
|
|
285
461
|
|
|
286
462
|
Only call `AssignRelationalComponents()` manually if you're not using the DI integration.
|
|
287
463
|
|
|
288
464
|
### Does this work without VContainer?
|
|
289
465
|
|
|
290
466
|
**Yes!** The integration gracefully falls back to standard Unity Helpers behavior if VContainer isn't detected. You can:
|
|
467
|
+
|
|
291
468
|
- Adopt incrementally without breaking existing code
|
|
292
469
|
- Use in projects that mix DI and non-DI components
|
|
293
470
|
- Remove VContainer later without refactoring all your components
|
|
@@ -297,6 +474,7 @@ Only call `AssignRelationalComponents()` manually if you're not using the DI int
|
|
|
297
474
|
**Minimal:** Relational component assignment happens once per component at initialization time. After that, there's zero runtime overhead - the references are just regular fields.
|
|
298
475
|
|
|
299
476
|
**Optimization tips:**
|
|
477
|
+
|
|
300
478
|
- Use `MaxDepth` to limit hierarchy traversal
|
|
301
479
|
- Use `TagFilter` or `NameFilter` to narrow searches
|
|
302
480
|
- Use `OnlyDescendants`/`OnlyAncestors` to exclude self when appropriate
|
|
@@ -306,15 +484,18 @@ Only call `AssignRelationalComponents()` manually if you're not using the DI int
|
|
|
306
484
|
## 📚 Learn More
|
|
307
485
|
|
|
308
486
|
**Unity Helpers Documentation:**
|
|
487
|
+
|
|
309
488
|
- [Relational Components Guide](../../RELATIONAL_COMPONENTS.md) - Complete attribute reference and recipes
|
|
310
489
|
- [Getting Started](../../GETTING_STARTED.md) - Unity Helpers quick start guide
|
|
311
490
|
- [Main README](../../README.md) - Full feature overview
|
|
312
491
|
|
|
313
492
|
**VContainer Documentation:**
|
|
493
|
+
|
|
314
494
|
- [VContainer Official Docs](https://vcontainer.hadashikick.jp/) - Complete VContainer guide
|
|
315
495
|
- [VContainer GitHub](https://github.com/hadashiA/VContainer) - Source code and examples
|
|
316
496
|
|
|
317
497
|
**Troubleshooting:**
|
|
498
|
+
|
|
318
499
|
- [Relational Components Troubleshooting](../../RELATIONAL_COMPONENTS.md#troubleshooting) - Detailed solutions
|
|
319
500
|
- [DI Integration Testing Guide](../../RELATIONAL_COMPONENTS.md#di-integrations-testing-and-edge-cases) - Advanced scenarios
|
|
320
501
|
|
|
@@ -329,6 +510,6 @@ Only call `AssignRelationalComponents()` manually if you're not using the DI int
|
|
|
329
510
|
|
|
330
511
|
---
|
|
331
512
|
|
|
332
|
-
|
|
513
|
+
## Made with ❤️ by Wallstop Studios
|
|
333
514
|
|
|
334
515
|
*Unity Helpers is production-ready and actively maintained. [Star the repo](https://github.com/wallstop/unity-helpers) if you find it useful!*
|
|
@@ -3,10 +3,27 @@ namespace Samples.UnityHelpers.DI.VContainer
|
|
|
3
3
|
using System;
|
|
4
4
|
using global::VContainer;
|
|
5
5
|
using global::VContainer.Unity;
|
|
6
|
+
using UnityEngine;
|
|
6
7
|
using WallstopStudios.UnityHelpers.Integrations.VContainer;
|
|
7
8
|
|
|
8
9
|
public sealed class GameLifetimeScope : LifetimeScope
|
|
9
10
|
{
|
|
11
|
+
[SerializeField]
|
|
12
|
+
[Tooltip(
|
|
13
|
+
"Include inactive GameObjects when the integration scans the active scene after the container builds."
|
|
14
|
+
)]
|
|
15
|
+
private bool _includeInactiveSceneObjects = true;
|
|
16
|
+
|
|
17
|
+
[SerializeField]
|
|
18
|
+
[Tooltip("Prefer the optimized single-pass scan when hydrating scene objects.")]
|
|
19
|
+
private bool _useSinglePassScan = true;
|
|
20
|
+
|
|
21
|
+
[SerializeField]
|
|
22
|
+
[Tooltip(
|
|
23
|
+
"Register a listener so additively loaded scenes automatically hydrate relational fields."
|
|
24
|
+
)]
|
|
25
|
+
private bool _listenForAdditiveScenes = true;
|
|
26
|
+
|
|
10
27
|
protected override void Configure(IContainerBuilder builder)
|
|
11
28
|
{
|
|
12
29
|
if (builder == null)
|
|
@@ -14,11 +31,12 @@ namespace Samples.UnityHelpers.DI.VContainer
|
|
|
14
31
|
throw new ArgumentNullException(nameof(builder));
|
|
15
32
|
}
|
|
16
33
|
|
|
17
|
-
|
|
18
|
-
|
|
34
|
+
RelationalSceneAssignmentOptions options = new RelationalSceneAssignmentOptions(
|
|
35
|
+
_includeInactiveSceneObjects,
|
|
36
|
+
_useSinglePassScan
|
|
37
|
+
);
|
|
19
38
|
|
|
20
|
-
|
|
21
|
-
// builder.RegisterRelationalComponents(new RelationalSceneAssignmentOptions(includeInactive: false));
|
|
39
|
+
builder.RegisterRelationalComponents(options, _listenForAdditiveScenes);
|
|
22
40
|
}
|
|
23
41
|
}
|
|
24
42
|
}
|
|
@@ -3,6 +3,9 @@ namespace Samples.UnityHelpers.DI.VContainer
|
|
|
3
3
|
using UnityEngine;
|
|
4
4
|
using WallstopStudios.UnityHelpers.Core.Attributes;
|
|
5
5
|
|
|
6
|
+
/// <summary>
|
|
7
|
+
/// Minimal component that demonstrates how relational attributes are hydrated by the DI integration.
|
|
8
|
+
/// </summary>
|
|
6
9
|
public sealed class RelationalConsumer : MonoBehaviour
|
|
7
10
|
{
|
|
8
11
|
[SiblingComponent]
|
|
@@ -10,8 +13,8 @@ namespace Samples.UnityHelpers.DI.VContainer
|
|
|
10
13
|
|
|
11
14
|
private void Awake()
|
|
12
15
|
{
|
|
13
|
-
// In scenes
|
|
14
|
-
// For runtime instances, see Spawner.
|
|
16
|
+
// In scenes the lifetime scope entry point (or additive-scene listener) hydrates this field.
|
|
17
|
+
// For runtime instances, see the different spawn helpers in Spawner.
|
|
15
18
|
if (_spriteRenderer != null)
|
|
16
19
|
{
|
|
17
20
|
_spriteRenderer.color = Color.cyan;
|
|
@@ -2,20 +2,129 @@ namespace Samples.UnityHelpers.DI.VContainer
|
|
|
2
2
|
{
|
|
3
3
|
using global::VContainer;
|
|
4
4
|
using UnityEngine;
|
|
5
|
+
using UnityEngine.Pool;
|
|
5
6
|
using WallstopStudios.UnityHelpers.Integrations.VContainer;
|
|
6
7
|
|
|
7
8
|
public sealed class Spawner : MonoBehaviour
|
|
8
9
|
{
|
|
9
10
|
[SerializeField]
|
|
10
|
-
private RelationalConsumer
|
|
11
|
+
private RelationalConsumer _componentPrefab;
|
|
12
|
+
|
|
13
|
+
[SerializeField]
|
|
14
|
+
private GameObject _hierarchyPrefab;
|
|
15
|
+
|
|
16
|
+
[SerializeField]
|
|
17
|
+
private Transform _defaultParent;
|
|
11
18
|
|
|
12
19
|
[Inject]
|
|
13
20
|
private IObjectResolver _resolver;
|
|
14
21
|
|
|
15
|
-
|
|
22
|
+
private ObjectPool<RelationalConsumer> _componentPool;
|
|
23
|
+
|
|
24
|
+
private void Awake()
|
|
25
|
+
{
|
|
26
|
+
_componentPool = RelationalObjectPools.CreatePoolWithRelations(
|
|
27
|
+
createFunc: () => Instantiate(_componentPrefab),
|
|
28
|
+
actionOnGet: OnGetFromPool,
|
|
29
|
+
actionOnRelease: OnReleaseToPool
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/// <summary>
|
|
34
|
+
/// Instantiate a component prefab through VContainer so dependencies and relational fields
|
|
35
|
+
/// are populated in one call.
|
|
36
|
+
/// </summary>
|
|
37
|
+
public RelationalConsumer SpawnComponent(Transform parent)
|
|
38
|
+
{
|
|
39
|
+
Transform targetParent = parent != null ? parent : _defaultParent;
|
|
40
|
+
RelationalConsumer instance = _resolver.InstantiateComponentWithRelations(
|
|
41
|
+
_componentPrefab,
|
|
42
|
+
targetParent
|
|
43
|
+
);
|
|
44
|
+
return instance;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/// <summary>
|
|
48
|
+
/// Instantiate a hierarchy prefab and hydrate every attributed component beneath it.
|
|
49
|
+
/// </summary>
|
|
50
|
+
public GameObject SpawnHierarchy(Transform parent)
|
|
51
|
+
{
|
|
52
|
+
Transform targetParent = parent != null ? parent : _defaultParent;
|
|
53
|
+
GameObject root = _resolver.InstantiateGameObjectWithRelations(
|
|
54
|
+
_hierarchyPrefab,
|
|
55
|
+
targetParent,
|
|
56
|
+
includeInactiveChildren: true
|
|
57
|
+
);
|
|
58
|
+
return root;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/// <summary>
|
|
62
|
+
/// Rent a component from a simple pool, then inject and assign it through the resolver.
|
|
63
|
+
/// </summary>
|
|
64
|
+
public RelationalConsumer SpawnFromPool(Transform parent)
|
|
65
|
+
{
|
|
66
|
+
Transform targetParent = parent != null ? parent : _defaultParent;
|
|
67
|
+
RelationalConsumer instance = _componentPool.GetWithRelations(_resolver);
|
|
68
|
+
if (targetParent != null)
|
|
69
|
+
{
|
|
70
|
+
instance.transform.SetParent(targetParent, false);
|
|
71
|
+
}
|
|
72
|
+
return instance;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/// <summary>
|
|
76
|
+
/// Return an instance to the pool.
|
|
77
|
+
/// </summary>
|
|
78
|
+
public void ReturnToPool(RelationalConsumer instance)
|
|
79
|
+
{
|
|
80
|
+
if (instance == null)
|
|
81
|
+
{
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
_componentPool.Release(instance);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/// <summary>
|
|
89
|
+
/// Hydrate an existing hierarchy that was created outside of the resolver (e.g., scene tools).
|
|
90
|
+
/// </summary>
|
|
91
|
+
public void HydrateExistingHierarchy(GameObject root)
|
|
92
|
+
{
|
|
93
|
+
if (root == null)
|
|
94
|
+
{
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
_resolver.AssignRelationalHierarchy(root, includeInactiveChildren: true);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private void OnGetFromPool(RelationalConsumer consumer)
|
|
102
|
+
{
|
|
103
|
+
if (consumer == null)
|
|
104
|
+
{
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
consumer.gameObject.SetActive(true);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private void OnReleaseToPool(RelationalConsumer consumer)
|
|
112
|
+
{
|
|
113
|
+
if (consumer == null)
|
|
114
|
+
{
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
consumer.gameObject.SetActive(false);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private void OnDestroy()
|
|
16
122
|
{
|
|
17
|
-
|
|
18
|
-
|
|
123
|
+
if (_componentPool != null)
|
|
124
|
+
{
|
|
125
|
+
_componentPool.Clear();
|
|
126
|
+
_componentPool = null;
|
|
127
|
+
}
|
|
19
128
|
}
|
|
20
129
|
}
|
|
21
130
|
}
|