fr.jeanf.scenemanagement 0.3.1 → 0.3.2

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.
@@ -24,8 +24,9 @@ namespace jeanf.scenemanagement
24
24
  private List<Region> _activeRegions = new List<Region>();
25
25
  private bool _mappingInitialized = false;
26
26
 
27
- private List<string> _tempSceneNames = new List<string>();
28
- private List<Region> _tempRegionsToRemove = new List<Region>();
27
+ // GC ALLOCATION FIX: Pre-allocate reusable collections
28
+ private readonly List<string> _tempSceneNames = new List<string>();
29
+ private readonly List<Region> _tempRegionsToRemove = new List<Region>();
29
30
 
30
31
  [SerializeField] private StringEventChannelSO regionChangeRequestChannel;
31
32
  [SerializeField] private SendTeleportTarget sendTeleportTarget;
@@ -126,6 +127,8 @@ namespace jeanf.scenemanagement
126
127
  _compiledSceneLists.Clear();
127
128
  _landingZoneIds.Clear();
128
129
  _activeRegions.Clear();
130
+
131
+ // GC ALLOCATION FIX: Clear reusable collections instead of creating new ones
129
132
  _tempSceneNames.Clear();
130
133
  _tempRegionsToRemove.Clear();
131
134
  _mappingInitialized = false;
@@ -138,8 +141,10 @@ namespace jeanf.scenemanagement
138
141
  var regionCount = ListOfRegions?.Count ?? 0;
139
142
  if (regionCount == 0) return;
140
143
 
141
- foreach (var region in ListOfRegions)
144
+ // GC ALLOCATION FIX: Use for loop instead of foreach to avoid enumerator allocation
145
+ for (int i = 0; i < ListOfRegions.Count; i++)
142
146
  {
147
+ var region = ListOfRegions[i];
143
148
  if (region == null) continue;
144
149
  if (!_regionDictionary.TryAdd(region.id, region)) continue;
145
150
 
@@ -148,8 +153,10 @@ namespace jeanf.scenemanagement
148
153
 
149
154
  if (region.scenariosInThisRegion != null)
150
155
  {
151
- foreach (var scenario in region.scenariosInThisRegion)
156
+ // GC ALLOCATION FIX: Use for loop instead of foreach
157
+ for (int j = 0; j < region.scenariosInThisRegion.Count; j++)
152
158
  {
159
+ var scenario = region.scenariosInThisRegion[j];
153
160
  if (scenario != null)
154
161
  {
155
162
  ScenarioManager.ScenarioDictionary.TryAdd(scenario.id, scenario);
@@ -159,8 +166,10 @@ namespace jeanf.scenemanagement
159
166
 
160
167
  if (region.zonesInThisRegion != null)
161
168
  {
162
- foreach (var zone in region.zonesInThisRegion)
169
+ // GC ALLOCATION FIX: Use for loop instead of foreach
170
+ for (int j = 0; j < region.zonesInThisRegion.Count; j++)
163
171
  {
172
+ var zone = region.zonesInThisRegion[j];
164
173
  if (zone != null)
165
174
  {
166
175
  _zoneDictionary.TryAdd(zone.id, zone);
@@ -176,10 +185,13 @@ namespace jeanf.scenemanagement
176
185
 
177
186
  private void PrecompileSceneList(Region region)
178
187
  {
188
+ // GC ALLOCATION FIX: Use capacity to avoid List resizing
179
189
  var sceneNames = new List<string>(region.dependenciesInThisRegion.Count);
180
- foreach (var dependency in region.dependenciesInThisRegion)
190
+
191
+ // GC ALLOCATION FIX: Use for loop instead of foreach
192
+ for (int i = 0; i < region.dependenciesInThisRegion.Count; i++)
181
193
  {
182
- sceneNames.Add(dependency.SceneName);
194
+ sceneNames.Add(region.dependenciesInThisRegion[i].SceneName);
183
195
  }
184
196
  _compiledSceneLists[region.id] = sceneNames;
185
197
  }
@@ -189,8 +201,10 @@ namespace jeanf.scenemanagement
189
201
  var connectivity = FindObjectOfType<RegionConnectivityAuthoring>();
190
202
  if (connectivity?.regionConnectivity?.landingZones == null) return;
191
203
 
192
- foreach (var landing in connectivity.regionConnectivity.landingZones)
204
+ // GC ALLOCATION FIX: Use for loop instead of foreach
205
+ for (int i = 0; i < connectivity.regionConnectivity.landingZones.Count; i++)
193
206
  {
207
+ var landing = connectivity.regionConnectivity.landingZones[i];
194
208
  if (landing?.landingZone != null)
195
209
  {
196
210
  _landingZoneIds.Add(landing.landingZone.id);
@@ -216,6 +230,7 @@ namespace jeanf.scenemanagement
216
230
 
217
231
  private void OnZoneChangedFromECS(string zoneId)
218
232
  {
233
+ // GC ALLOCATION FIX: Early exit to avoid string operations
219
234
  if (string.IsNullOrEmpty(zoneId) || _lastNotifiedZone == zoneId) return;
220
235
 
221
236
  if (!_zoneDictionary.TryGetValue(zoneId, out var zone)) return;
@@ -223,12 +238,14 @@ namespace jeanf.scenemanagement
223
238
  _lastNotifiedZone = zoneId;
224
239
  _currentPlayerZone = zone;
225
240
 
241
+ // GC ALLOCATION FIX: Only invoke if delegates are not null
226
242
  PublishCurrentZoneId?.Invoke(zone.id);
227
243
  PublishAppList(zone);
228
244
  }
229
245
 
230
246
  private void OnRegionChangedFromECS(string regionId)
231
247
  {
248
+ // GC ALLOCATION FIX: Early exit to avoid unnecessary operations
232
249
  if (string.IsNullOrEmpty(regionId) || _lastNotifiedRegion == regionId) return;
233
250
 
234
251
  if (!_regionDictionary.TryGetValue(regionId, out var region)) return;
@@ -260,18 +277,23 @@ namespace jeanf.scenemanagement
260
277
  _currentPlayerRegion = region;
261
278
  _lastNotifiedRegion = region.id;
262
279
 
280
+ // GC ALLOCATION FIX: Only invoke if delegate is not null
263
281
  PublishCurrentRegionId?.Invoke(_currentPlayerRegion.id);
264
282
 
283
+ // GC ALLOCATION FIX: Clear and reuse collection instead of creating new
265
284
  _tempRegionsToRemove.Clear();
266
- foreach (var activeRegion in _activeRegions)
285
+
286
+ // GC ALLOCATION FIX: Use for loop instead of foreach
287
+ for (int i = 0; i < _activeRegions.Count; i++)
267
288
  {
268
- var removedRegion = RequestUnLoadForObsoleteRegion(activeRegion);
289
+ var removedRegion = RequestUnLoadForObsoleteRegion(_activeRegions[i]);
269
290
  _tempRegionsToRemove.Add(removedRegion);
270
291
  }
271
292
 
272
- foreach (var r in _tempRegionsToRemove)
293
+ // GC ALLOCATION FIX: Use for loop instead of foreach
294
+ for (int i = 0; i < _tempRegionsToRemove.Count; i++)
273
295
  {
274
- _activeRegions.Remove(r);
296
+ _activeRegions.Remove(_tempRegionsToRemove[i]);
275
297
  }
276
298
 
277
299
  RequestLoadForRegionDependencies(region);
@@ -304,6 +326,8 @@ namespace jeanf.scenemanagement
304
326
  {
305
327
  _currentPlayerZone = firstZone;
306
328
  _lastNotifiedZone = firstZone.id;
329
+
330
+ // GC ALLOCATION FIX: Only invoke if delegates are not null
307
331
  PublishCurrentZoneId?.Invoke(firstZone.id);
308
332
  PublishAppList(firstZone);
309
333
  }
@@ -330,6 +354,7 @@ namespace jeanf.scenemanagement
330
354
  listToBroadcast = value;
331
355
  }
332
356
 
357
+ // GC ALLOCATION FIX: Only invoke if delegate is not null
333
358
  _broadcastAppList?.Invoke(listToBroadcast);
334
359
  }
335
360
 
@@ -337,9 +362,10 @@ namespace jeanf.scenemanagement
337
362
  {
338
363
  if (!_compiledSceneLists.TryGetValue(region.id, out var sceneNames) || sceneNames.Count <= 0) return;
339
364
 
340
- foreach (var sceneName in sceneNames)
365
+ // GC ALLOCATION FIX: Use for loop instead of foreach
366
+ for (int i = 0; i < sceneNames.Count; i++)
341
367
  {
342
- _sceneLoader.LoadSceneRequest(sceneName);
368
+ _sceneLoader.LoadSceneRequest(sceneNames[i]);
343
369
  }
344
370
  }
345
371
 
@@ -347,9 +373,10 @@ namespace jeanf.scenemanagement
347
373
  {
348
374
  if (_compiledSceneLists.TryGetValue(region.id, out var sceneNames))
349
375
  {
350
- foreach (var sceneName in sceneNames)
376
+ // GC ALLOCATION FIX: Use for loop instead of foreach
377
+ for (int i = 0; i < sceneNames.Count; i++)
351
378
  {
352
- _sceneLoader.UnLoadSceneRequest(sceneName);
379
+ _sceneLoader.UnLoadSceneRequest(sceneNames[i]);
353
380
  }
354
381
  }
355
382
  return region;
@@ -0,0 +1,360 @@
1
+ #if UNITY_EDITOR
2
+ using UnityEngine;
3
+ using UnityEditor;
4
+ using System.Collections.Generic;
5
+ using System.IO;
6
+
7
+ namespace jeanf.scenemanagement
8
+ {
9
+ public class VolumeDataGenerator : EditorWindow
10
+ {
11
+ private RegionConnectivity sourceRegionConnectivity;
12
+ private PrecomputedVolumeData targetPrecomputedData;
13
+ private string savePath = "Assets/ScriptableObjects/";
14
+ private string fileName = "PrecomputedVolumeData";
15
+
16
+ private Vector2 scrollPosition;
17
+ private bool showPreview = false;
18
+ private Dictionary<string, List<string>> previewData = new Dictionary<string, List<string>>();
19
+
20
+ [MenuItem("Tools/Scene Management/Volume Data Generator")]
21
+ public static void ShowWindow()
22
+ {
23
+ GetWindow<VolumeDataGenerator>("Volume Data Generator");
24
+ }
25
+
26
+ private void OnGUI()
27
+ {
28
+ EditorGUILayout.LabelField("Volume Data Generator", EditorStyles.boldLabel);
29
+ EditorGUILayout.HelpBox("Generate pre-computed volume connectivity data from RegionConnectivity for maximum runtime performance.", MessageType.Info);
30
+ EditorGUILayout.Space();
31
+
32
+ DrawSourceSelection();
33
+ EditorGUILayout.Space();
34
+
35
+ DrawTargetSelection();
36
+ EditorGUILayout.Space();
37
+
38
+ DrawGenerationControls();
39
+ EditorGUILayout.Space();
40
+
41
+ if (showPreview && previewData.Count > 0)
42
+ {
43
+ DrawPreview();
44
+ }
45
+ }
46
+
47
+ private void DrawSourceSelection()
48
+ {
49
+ EditorGUILayout.LabelField("Source Data", EditorStyles.boldLabel);
50
+
51
+ sourceRegionConnectivity = (RegionConnectivity)EditorGUILayout.ObjectField(
52
+ "Region Connectivity",
53
+ sourceRegionConnectivity,
54
+ typeof(RegionConnectivity),
55
+ false);
56
+
57
+ if (sourceRegionConnectivity == null)
58
+ {
59
+ EditorGUILayout.HelpBox("Select a RegionConnectivity asset to generate from.", MessageType.Warning);
60
+ return;
61
+ }
62
+
63
+ EditorGUILayout.BeginVertical(GUI.skin.box);
64
+ EditorGUILayout.LabelField("Source Analysis:", EditorStyles.boldLabel);
65
+ EditorGUILayout.LabelField($"• Active Regions: {sourceRegionConnectivity.activeRegions.Count}");
66
+ EditorGUILayout.LabelField($"• Landing Zones: {sourceRegionConnectivity.landingZones.Count}");
67
+ EditorGUILayout.LabelField($"• Zone Connections: {sourceRegionConnectivity.zoneConnections.Count}");
68
+
69
+ int totalZones = 0;
70
+ foreach (var region in sourceRegionConnectivity.activeRegions)
71
+ {
72
+ if (region?.zonesInThisRegion != null)
73
+ totalZones += region.zonesInThisRegion.Count;
74
+ }
75
+ EditorGUILayout.LabelField($"• Total Zones: {totalZones}");
76
+ EditorGUILayout.EndVertical();
77
+ }
78
+
79
+ private void DrawTargetSelection()
80
+ {
81
+ EditorGUILayout.LabelField("Target Asset", EditorStyles.boldLabel);
82
+
83
+ targetPrecomputedData = (PrecomputedVolumeData)EditorGUILayout.ObjectField(
84
+ "Precomputed Volume Data",
85
+ targetPrecomputedData,
86
+ typeof(PrecomputedVolumeData),
87
+ false);
88
+
89
+ EditorGUILayout.BeginHorizontal();
90
+ savePath = EditorGUILayout.TextField("Save Path", savePath);
91
+ if (GUILayout.Button("Browse", GUILayout.Width(60)))
92
+ {
93
+ string selectedPath = EditorUtility.SaveFolderPanel("Select Save Folder", savePath, "");
94
+ if (!string.IsNullOrEmpty(selectedPath))
95
+ {
96
+ savePath = FileUtil.GetProjectRelativePath(selectedPath) + "/";
97
+ }
98
+ }
99
+ EditorGUILayout.EndHorizontal();
100
+
101
+ fileName = EditorGUILayout.TextField("File Name", fileName);
102
+ }
103
+
104
+ private void DrawGenerationControls()
105
+ {
106
+ EditorGUILayout.LabelField("Generation Options", EditorStyles.boldLabel);
107
+
108
+ showPreview = EditorGUILayout.Toggle("Show Preview", showPreview);
109
+
110
+ EditorGUILayout.BeginHorizontal();
111
+
112
+ GUI.enabled = sourceRegionConnectivity != null;
113
+ if (GUILayout.Button("Preview Data"))
114
+ {
115
+ GeneratePreviewData();
116
+ }
117
+
118
+ if (GUILayout.Button("Generate New Asset"))
119
+ {
120
+ GenerateNewAsset();
121
+ }
122
+
123
+ GUI.enabled = sourceRegionConnectivity != null && targetPrecomputedData != null;
124
+ if (GUILayout.Button("Update Existing"))
125
+ {
126
+ UpdateExistingAsset();
127
+ }
128
+
129
+ GUI.enabled = true;
130
+ EditorGUILayout.EndHorizontal();
131
+ }
132
+
133
+ private void DrawPreview()
134
+ {
135
+ EditorGUILayout.LabelField("Preview Generated Data", EditorStyles.boldLabel);
136
+
137
+ scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, GUILayout.Height(300));
138
+
139
+ foreach (var kvp in previewData)
140
+ {
141
+ EditorGUILayout.LabelField($"Zone: {kvp.Key}", EditorStyles.boldLabel);
142
+ EditorGUI.indentLevel++;
143
+ EditorGUILayout.LabelField($"Checkable zones ({kvp.Value.Count}):");
144
+ foreach (var checkable in kvp.Value)
145
+ {
146
+ EditorGUILayout.LabelField($"• {checkable}");
147
+ }
148
+ EditorGUI.indentLevel--;
149
+ EditorGUILayout.Space();
150
+ }
151
+
152
+ EditorGUILayout.EndScrollView();
153
+ }
154
+
155
+ private void GeneratePreviewData()
156
+ {
157
+ if (sourceRegionConnectivity == null) return;
158
+
159
+ previewData.Clear();
160
+ var generator = new VolumeDataProcessor(sourceRegionConnectivity);
161
+
162
+ foreach (var region in sourceRegionConnectivity.activeRegions)
163
+ {
164
+ if (region?.zonesInThisRegion == null) continue;
165
+
166
+ foreach (var zone in region.zonesInThisRegion)
167
+ {
168
+ if (zone == null) continue;
169
+
170
+ var checkableZones = generator.GetCheckableZonesForZone(zone.id.ToString());
171
+ previewData[zone.id.ToString()] = new List<string>(checkableZones);
172
+ }
173
+ }
174
+
175
+ showPreview = true;
176
+ Repaint();
177
+ }
178
+
179
+ private void GenerateNewAsset()
180
+ {
181
+ if (sourceRegionConnectivity == null) return;
182
+
183
+ var asset = CreateInstance<PrecomputedVolumeData>();
184
+ var generator = new VolumeDataProcessor(sourceRegionConnectivity);
185
+ generator.PopulatePrecomputedData(asset);
186
+
187
+ string fullPath = $"{savePath}{fileName}.asset";
188
+ AssetDatabase.CreateAsset(asset, fullPath);
189
+ AssetDatabase.SaveAssets();
190
+ AssetDatabase.Refresh();
191
+
192
+ targetPrecomputedData = asset;
193
+ EditorUtility.FocusProjectWindow();
194
+ Selection.activeObject = asset;
195
+
196
+ Debug.Log($"Created PrecomputedVolumeData asset at: {fullPath}");
197
+ }
198
+
199
+ private void UpdateExistingAsset()
200
+ {
201
+ if (sourceRegionConnectivity == null || targetPrecomputedData == null) return;
202
+
203
+ var generator = new VolumeDataProcessor(sourceRegionConnectivity);
204
+ generator.PopulatePrecomputedData(targetPrecomputedData);
205
+
206
+ EditorUtility.SetDirty(targetPrecomputedData);
207
+ AssetDatabase.SaveAssets();
208
+
209
+ Debug.Log($"Updated PrecomputedVolumeData asset: {AssetDatabase.GetAssetPath(targetPrecomputedData)}");
210
+ }
211
+ }
212
+
213
+ public class VolumeDataProcessor
214
+ {
215
+ private RegionConnectivity sourceData;
216
+ private Dictionary<string, string> zoneToRegionMap = new Dictionary<string, string>();
217
+ private Dictionary<string, HashSet<string>> zoneNeighborsMap = new Dictionary<string, HashSet<string>>();
218
+ private HashSet<string> landingZoneIds = new HashSet<string>();
219
+
220
+ public VolumeDataProcessor(RegionConnectivity source)
221
+ {
222
+ sourceData = source;
223
+ BuildMappings();
224
+ }
225
+
226
+ private void BuildMappings()
227
+ {
228
+ BuildZoneToRegionMapping();
229
+ BuildZoneNeighborsMapping();
230
+ BuildLandingZoneMapping();
231
+ }
232
+
233
+ private void BuildZoneToRegionMapping()
234
+ {
235
+ foreach (var region in sourceData.activeRegions)
236
+ {
237
+ if (region?.zonesInThisRegion == null) continue;
238
+
239
+ foreach (var zone in region.zonesInThisRegion)
240
+ {
241
+ if (zone != null)
242
+ {
243
+ zoneToRegionMap[zone.id.ToString()] = region.id.ToString();
244
+ }
245
+ }
246
+ }
247
+ }
248
+
249
+ private void BuildZoneNeighborsMapping()
250
+ {
251
+ // Build neighbors from region membership
252
+ foreach (var region in sourceData.activeRegions)
253
+ {
254
+ if (region?.zonesInThisRegion == null) continue;
255
+
256
+ foreach (var zoneA in region.zonesInThisRegion)
257
+ {
258
+ if (zoneA == null) continue;
259
+
260
+ var zoneAId = zoneA.id.ToString();
261
+ if (!zoneNeighborsMap.ContainsKey(zoneAId))
262
+ {
263
+ zoneNeighborsMap[zoneAId] = new HashSet<string>();
264
+ }
265
+
266
+ foreach (var zoneB in region.zonesInThisRegion)
267
+ {
268
+ if (zoneB == null || zoneA.id.ToString() == zoneB.id.ToString()) continue;
269
+ zoneNeighborsMap[zoneAId].Add(zoneB.id.ToString());
270
+ }
271
+ }
272
+ }
273
+
274
+ // Add explicit zone connections
275
+ foreach (var connection in sourceData.zoneConnections)
276
+ {
277
+ if (connection.zoneA == null || connection.zoneB == null) continue;
278
+
279
+ var zoneAId = connection.zoneA.id.ToString();
280
+ var zoneBId = connection.zoneB.id.ToString();
281
+
282
+ if (!zoneNeighborsMap.ContainsKey(zoneAId))
283
+ zoneNeighborsMap[zoneAId] = new HashSet<string>();
284
+ if (!zoneNeighborsMap.ContainsKey(zoneBId))
285
+ zoneNeighborsMap[zoneBId] = new HashSet<string>();
286
+
287
+ zoneNeighborsMap[zoneAId].Add(zoneBId);
288
+
289
+ if (connection.isBidirectional)
290
+ {
291
+ zoneNeighborsMap[zoneBId].Add(zoneAId);
292
+ }
293
+ }
294
+ }
295
+
296
+ private void BuildLandingZoneMapping()
297
+ {
298
+ foreach (var landing in sourceData.landingZones)
299
+ {
300
+ if (landing?.landingZone != null)
301
+ {
302
+ landingZoneIds.Add(landing.landingZone.id.ToString());
303
+ }
304
+ }
305
+ }
306
+
307
+ public HashSet<string> GetCheckableZonesForZone(string zoneId)
308
+ {
309
+ var result = new HashSet<string> { zoneId };
310
+
311
+ if (zoneNeighborsMap.TryGetValue(zoneId, out var neighbors))
312
+ {
313
+ foreach (var neighbor in neighbors)
314
+ {
315
+ result.Add(neighbor);
316
+ }
317
+ }
318
+
319
+ foreach (var landingZoneId in landingZoneIds)
320
+ {
321
+ result.Add(landingZoneId);
322
+ }
323
+
324
+ return result;
325
+ }
326
+
327
+ public void PopulatePrecomputedData(PrecomputedVolumeData target)
328
+ {
329
+ target.Clear();
330
+
331
+ // Generate zone checkable sets
332
+ foreach (var kvp in zoneToRegionMap)
333
+ {
334
+ var zoneId = kvp.Key;
335
+ var checkableZones = GetCheckableZonesForZone(zoneId);
336
+
337
+ var checkableSet = new ZoneCheckableSet(zoneId);
338
+ checkableSet.checkableZoneIds.AddRange(checkableZones);
339
+
340
+ target.zoneCheckableSets.Add(checkableSet);
341
+ }
342
+
343
+ // Add landing zones
344
+ target.landingZoneIds.AddRange(landingZoneIds);
345
+
346
+ // Add zone-region mappings
347
+ foreach (var kvp in zoneToRegionMap)
348
+ {
349
+ target.zoneRegionMappings.Add(new ZoneRegionMapping(kvp.Key, kvp.Value));
350
+ }
351
+
352
+ // Add generation metadata
353
+ target.sourceRegionConnectivityAsset = AssetDatabase.GetAssetPath(sourceData);
354
+ target.generatedDateTime = System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
355
+ target.totalZones = zoneToRegionMap.Count;
356
+ target.totalRegions = sourceData.activeRegions.Count;
357
+ }
358
+ }
359
+ }
360
+ #endif
@@ -0,0 +1,2 @@
1
+ fileFormatVersion: 2
2
+ guid: 7e55684fae4f6ea47b8f442cfad75620
@@ -0,0 +1,123 @@
1
+ using System.Collections.Generic;
2
+ using UnityEngine;
3
+ using jeanf.propertyDrawer;
4
+
5
+ namespace jeanf.scenemanagement
6
+ {
7
+ [ScriptableObjectDrawer]
8
+ [CreateAssetMenu(fileName = "PrecomputedVolumeData", menuName = "LoadingSystem/PrecomputedVolumeData")]
9
+ public class PrecomputedVolumeData : ScriptableObject
10
+ {
11
+ [Header("Pre-computed Connectivity Data")]
12
+ [Tooltip("Generated from RegionConnectivity - do not edit manually")]
13
+ public List<ZoneCheckableSet> zoneCheckableSets = new List<ZoneCheckableSet>();
14
+
15
+ [Header("Landing Zones")]
16
+ [Tooltip("Zones that are always checkable regardless of current zone")]
17
+ public List<string> landingZoneIds = new List<string>();
18
+
19
+ [Header("Zone to Region Mapping")]
20
+ [Tooltip("Maps each zone ID to its region ID")]
21
+ public List<ZoneRegionMapping> zoneRegionMappings = new List<ZoneRegionMapping>();
22
+
23
+ [Header("Generation Info")]
24
+ [Tooltip("Information about when this data was generated")]
25
+ public string sourceRegionConnectivityAsset;
26
+ public string generatedDateTime;
27
+ public int totalZones;
28
+ public int totalRegions;
29
+
30
+ // Runtime lookup methods
31
+ public HashSet<string> GetCheckableZoneIds(string currentZone)
32
+ {
33
+ var result = new HashSet<string>();
34
+
35
+ if (string.IsNullOrEmpty(currentZone))
36
+ {
37
+ // Bootstrap state - return all zones
38
+ foreach (var mapping in zoneRegionMappings)
39
+ {
40
+ result.Add(mapping.zoneId);
41
+ }
42
+ return result;
43
+ }
44
+
45
+ // Find the checkable set for this zone
46
+ foreach (var checkableSet in zoneCheckableSets)
47
+ {
48
+ if (checkableSet.primaryZoneId == currentZone)
49
+ {
50
+ foreach (var checkableZone in checkableSet.checkableZoneIds)
51
+ {
52
+ result.Add(checkableZone);
53
+ }
54
+ break;
55
+ }
56
+ }
57
+
58
+ // Always add landing zones
59
+ foreach (var landingZone in landingZoneIds)
60
+ {
61
+ result.Add(landingZone);
62
+ }
63
+
64
+ return result;
65
+ }
66
+
67
+ public string GetRegionForZone(string zoneId)
68
+ {
69
+ foreach (var mapping in zoneRegionMappings)
70
+ {
71
+ if (mapping.zoneId == zoneId)
72
+ {
73
+ return mapping.regionId;
74
+ }
75
+ }
76
+ return "";
77
+ }
78
+
79
+ public bool IsLandingZone(string zoneId)
80
+ {
81
+ return landingZoneIds.Contains(zoneId);
82
+ }
83
+
84
+ public void Clear()
85
+ {
86
+ zoneCheckableSets.Clear();
87
+ landingZoneIds.Clear();
88
+ zoneRegionMappings.Clear();
89
+ sourceRegionConnectivityAsset = "";
90
+ generatedDateTime = "";
91
+ totalZones = 0;
92
+ totalRegions = 0;
93
+ }
94
+ }
95
+
96
+ [System.Serializable]
97
+ public class ZoneCheckableSet
98
+ {
99
+ [Tooltip("The zone that this checkable set applies to")]
100
+ public string primaryZoneId;
101
+
102
+ [Tooltip("All zones that should be checked when in the primary zone")]
103
+ public List<string> checkableZoneIds = new List<string>();
104
+
105
+ public ZoneCheckableSet(string primaryZone)
106
+ {
107
+ primaryZoneId = primaryZone;
108
+ }
109
+ }
110
+
111
+ [System.Serializable]
112
+ public class ZoneRegionMapping
113
+ {
114
+ public string zoneId;
115
+ public string regionId;
116
+
117
+ public ZoneRegionMapping(string zone, string region)
118
+ {
119
+ zoneId = zone;
120
+ regionId = region;
121
+ }
122
+ }
123
+ }
@@ -0,0 +1,2 @@
1
+ fileFormatVersion: 2
2
+ guid: be367183df17c9841aa12aaf3830317d