Compare commits
2 Commits
fe2eb0a280
...
lifecycle_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dcf8c8bb87 | ||
|
|
9a6914b9bd |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -104,3 +104,6 @@ InitTestScene*.unity*
|
|||||||
.vscode/launch.json
|
.vscode/launch.json
|
||||||
.vscode/settings.json
|
.vscode/settings.json
|
||||||
.idea/.idea.AppleHillsProduction/.idea/indexLayout.xml
|
.idea/.idea.AppleHillsProduction/.idea/indexLayout.xml
|
||||||
|
|
||||||
|
# WIP docs
|
||||||
|
/docs/wip/
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: d60f8ff6bf46b494b80e210228c43e61
|
|
||||||
folderAsset: yes
|
|
||||||
DefaultImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 37 KiB |
@@ -1,156 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 57224356af3d045dbbf8b420e13b4b10
|
|
||||||
TextureImporter:
|
|
||||||
internalIDToNameTable:
|
|
||||||
- first:
|
|
||||||
213: 2364528222304962155
|
|
||||||
second: ramasjang_icon_0
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 13
|
|
||||||
mipmaps:
|
|
||||||
mipMapMode: 0
|
|
||||||
enableMipMap: 0
|
|
||||||
sRGBTexture: 1
|
|
||||||
linearTexture: 0
|
|
||||||
fadeOut: 0
|
|
||||||
borderMipMap: 0
|
|
||||||
mipMapsPreserveCoverage: 0
|
|
||||||
alphaTestReferenceValue: 0.5
|
|
||||||
mipMapFadeDistanceStart: 1
|
|
||||||
mipMapFadeDistanceEnd: 3
|
|
||||||
bumpmap:
|
|
||||||
convertToNormalMap: 0
|
|
||||||
externalNormalMap: 0
|
|
||||||
heightScale: 0.25
|
|
||||||
normalMapFilter: 0
|
|
||||||
flipGreenChannel: 0
|
|
||||||
isReadable: 0
|
|
||||||
streamingMipmaps: 0
|
|
||||||
streamingMipmapsPriority: 0
|
|
||||||
vTOnly: 0
|
|
||||||
ignoreMipmapLimit: 0
|
|
||||||
grayScaleToAlpha: 0
|
|
||||||
generateCubemap: 6
|
|
||||||
cubemapConvolution: 0
|
|
||||||
seamlessCubemap: 0
|
|
||||||
textureFormat: 1
|
|
||||||
maxTextureSize: 2048
|
|
||||||
textureSettings:
|
|
||||||
serializedVersion: 2
|
|
||||||
filterMode: 1
|
|
||||||
aniso: 1
|
|
||||||
mipBias: 0
|
|
||||||
wrapU: 1
|
|
||||||
wrapV: 1
|
|
||||||
wrapW: 1
|
|
||||||
nPOTScale: 0
|
|
||||||
lightmap: 0
|
|
||||||
compressionQuality: 50
|
|
||||||
spriteMode: 2
|
|
||||||
spriteExtrude: 1
|
|
||||||
spriteMeshType: 1
|
|
||||||
alignment: 0
|
|
||||||
spritePivot: {x: 0.5, y: 0.5}
|
|
||||||
spritePixelsToUnits: 100
|
|
||||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
|
||||||
spriteGenerateFallbackPhysicsShape: 1
|
|
||||||
alphaUsage: 1
|
|
||||||
alphaIsTransparency: 1
|
|
||||||
spriteTessellationDetail: -1
|
|
||||||
textureType: 8
|
|
||||||
textureShape: 1
|
|
||||||
singleChannelComponent: 0
|
|
||||||
flipbookRows: 1
|
|
||||||
flipbookColumns: 1
|
|
||||||
maxTextureSizeSet: 0
|
|
||||||
compressionQualitySet: 0
|
|
||||||
textureFormatSet: 0
|
|
||||||
ignorePngGamma: 0
|
|
||||||
applyGammaDecoding: 0
|
|
||||||
swizzle: 50462976
|
|
||||||
cookieLightType: 0
|
|
||||||
platformSettings:
|
|
||||||
- serializedVersion: 4
|
|
||||||
buildTarget: DefaultTexturePlatform
|
|
||||||
maxTextureSize: 2048
|
|
||||||
resizeAlgorithm: 0
|
|
||||||
textureFormat: -1
|
|
||||||
textureCompression: 1
|
|
||||||
compressionQuality: 50
|
|
||||||
crunchedCompression: 0
|
|
||||||
allowsAlphaSplitting: 0
|
|
||||||
overridden: 0
|
|
||||||
ignorePlatformSupport: 0
|
|
||||||
androidETC2FallbackOverride: 0
|
|
||||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
|
||||||
- serializedVersion: 4
|
|
||||||
buildTarget: Standalone
|
|
||||||
maxTextureSize: 2048
|
|
||||||
resizeAlgorithm: 0
|
|
||||||
textureFormat: -1
|
|
||||||
textureCompression: 1
|
|
||||||
compressionQuality: 50
|
|
||||||
crunchedCompression: 0
|
|
||||||
allowsAlphaSplitting: 0
|
|
||||||
overridden: 0
|
|
||||||
ignorePlatformSupport: 0
|
|
||||||
androidETC2FallbackOverride: 0
|
|
||||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
|
||||||
- serializedVersion: 4
|
|
||||||
buildTarget: iOS
|
|
||||||
maxTextureSize: 2048
|
|
||||||
resizeAlgorithm: 0
|
|
||||||
textureFormat: -1
|
|
||||||
textureCompression: 1
|
|
||||||
compressionQuality: 50
|
|
||||||
crunchedCompression: 0
|
|
||||||
allowsAlphaSplitting: 0
|
|
||||||
overridden: 0
|
|
||||||
ignorePlatformSupport: 0
|
|
||||||
androidETC2FallbackOverride: 0
|
|
||||||
forceMaximumCompressionQuality_BC6H_BC7: 0
|
|
||||||
spriteSheet:
|
|
||||||
serializedVersion: 2
|
|
||||||
sprites:
|
|
||||||
- serializedVersion: 2
|
|
||||||
name: ramasjang_icon_0
|
|
||||||
rect:
|
|
||||||
serializedVersion: 2
|
|
||||||
x: 4
|
|
||||||
y: 5
|
|
||||||
width: 334
|
|
||||||
height: 334
|
|
||||||
alignment: 0
|
|
||||||
pivot: {x: 0, y: 0}
|
|
||||||
border: {x: 0, y: 0, z: 0, w: 0}
|
|
||||||
customData:
|
|
||||||
outline: []
|
|
||||||
physicsShape: []
|
|
||||||
tessellationDetail: -1
|
|
||||||
bones: []
|
|
||||||
spriteID: b668fdfe3ed70d020800000000000000
|
|
||||||
internalID: 2364528222304962155
|
|
||||||
vertices: []
|
|
||||||
indices:
|
|
||||||
edges: []
|
|
||||||
weights: []
|
|
||||||
outline: []
|
|
||||||
customData:
|
|
||||||
physicsShape: []
|
|
||||||
bones: []
|
|
||||||
spriteID:
|
|
||||||
internalID: 0
|
|
||||||
vertices: []
|
|
||||||
indices:
|
|
||||||
edges: []
|
|
||||||
weights: []
|
|
||||||
secondaryTextures: []
|
|
||||||
spriteCustomMetadata:
|
|
||||||
entries: []
|
|
||||||
nameFileIdTable:
|
|
||||||
ramasjang_icon_0: 2364528222304962155
|
|
||||||
mipmapLimitGroupName:
|
|
||||||
pSDRemoveMatte: 0
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -725,9 +725,10 @@ GameObject:
|
|||||||
m_Component:
|
m_Component:
|
||||||
- component: {fileID: 3864057818161790164}
|
- component: {fileID: 3864057818161790164}
|
||||||
- component: {fileID: 5271824036850954050}
|
- component: {fileID: 5271824036850954050}
|
||||||
|
- component: {fileID: 8081783206361873868}
|
||||||
|
- component: {fileID: 5548642987123338363}
|
||||||
- component: {fileID: 3058107077406709872}
|
- component: {fileID: 3058107077406709872}
|
||||||
- component: {fileID: 587711432829270645}
|
- component: {fileID: 587711432829270645}
|
||||||
- component: {fileID: 4189849640380816173}
|
|
||||||
m_Layer: 5
|
m_Layer: 5
|
||||||
m_Name: Icon
|
m_Name: Icon
|
||||||
m_TagString: Untagged
|
m_TagString: Untagged
|
||||||
@@ -762,6 +763,53 @@ CanvasRenderer:
|
|||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_GameObject: {fileID: 4599222264323240281}
|
m_GameObject: {fileID: 4599222264323240281}
|
||||||
m_CullTransparentMesh: 1
|
m_CullTransparentMesh: 1
|
||||||
|
--- !u!114 &8081783206361873868
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 4599222264323240281}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.RawImage
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
m_RaycastTarget: 1
|
||||||
|
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_Maskable: 1
|
||||||
|
m_OnCullStateChanged:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_UVRect:
|
||||||
|
serializedVersion: 2
|
||||||
|
x: 0
|
||||||
|
y: 0
|
||||||
|
width: 1
|
||||||
|
height: -1
|
||||||
|
--- !u!114 &5548642987123338363
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 4599222264323240281}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 2fd09147b9e9d42a48d6ddc915ddc3d2, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: SkiaSharp.Unity::SkiaSharp.Unity.SkottiePlayerV2
|
||||||
|
lottieFile: {fileID: 4900000, guid: 50e22b5bb8a496840952f2563758c13c, type: 3}
|
||||||
|
customResolution: 0
|
||||||
|
resWidth: 250
|
||||||
|
resHeight: 250
|
||||||
|
stateName: Idle
|
||||||
|
resetAfterFinished: 0
|
||||||
|
autoPlay: 1
|
||||||
|
loop: 1
|
||||||
--- !u!114 &3058107077406709872
|
--- !u!114 &3058107077406709872
|
||||||
MonoBehaviour:
|
MonoBehaviour:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -802,7 +850,7 @@ MonoBehaviour:
|
|||||||
m_SelectedTrigger: Selected
|
m_SelectedTrigger: Selected
|
||||||
m_DisabledTrigger: Disabled
|
m_DisabledTrigger: Disabled
|
||||||
m_Interactable: 1
|
m_Interactable: 1
|
||||||
m_TargetGraphic: {fileID: 0}
|
m_TargetGraphic: {fileID: 8081783206361873868}
|
||||||
m_OnClick:
|
m_OnClick:
|
||||||
m_PersistentCalls:
|
m_PersistentCalls:
|
||||||
m_Calls:
|
m_Calls:
|
||||||
@@ -832,36 +880,6 @@ MonoBehaviour:
|
|||||||
m_EditorClassIdentifier: AppleHillsScripts::UI.HudMenuButton
|
m_EditorClassIdentifier: AppleHillsScripts::UI.HudMenuButton
|
||||||
pagePrefab: {fileID: 1498581815400593087, guid: ccd858c7962d48147b0233c1bf1382f5, type: 3}
|
pagePrefab: {fileID: 1498581815400593087, guid: ccd858c7962d48147b0233c1bf1382f5, type: 3}
|
||||||
buttonName: RamaSjang Button
|
buttonName: RamaSjang Button
|
||||||
--- !u!114 &4189849640380816173
|
|
||||||
MonoBehaviour:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 4599222264323240281}
|
|
||||||
m_Enabled: 1
|
|
||||||
m_EditorHideFlags: 0
|
|
||||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
|
||||||
m_Name:
|
|
||||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
|
|
||||||
m_Material: {fileID: 0}
|
|
||||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
|
||||||
m_RaycastTarget: 1
|
|
||||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
|
||||||
m_Maskable: 1
|
|
||||||
m_OnCullStateChanged:
|
|
||||||
m_PersistentCalls:
|
|
||||||
m_Calls: []
|
|
||||||
m_Sprite: {fileID: 2364528222304962155, guid: 57224356af3d045dbbf8b420e13b4b10, type: 3}
|
|
||||||
m_Type: 0
|
|
||||||
m_PreserveAspect: 0
|
|
||||||
m_FillCenter: 1
|
|
||||||
m_FillMethod: 4
|
|
||||||
m_FillAmount: 1
|
|
||||||
m_FillClockwise: 1
|
|
||||||
m_FillOrigin: 0
|
|
||||||
m_UseSpriteMesh: 0
|
|
||||||
m_PixelsPerUnitMultiplier: 1
|
|
||||||
--- !u!1 &5113586844274188410
|
--- !u!1 &5113586844274188410
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|||||||
@@ -148,6 +148,8 @@ RectTransform:
|
|||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
m_ConstrainProportionsScale: 0
|
m_ConstrainProportionsScale: 0
|
||||||
m_Children:
|
m_Children:
|
||||||
|
- {fileID: 6108475066390421500}
|
||||||
|
- {fileID: 6717870941799174515}
|
||||||
- {fileID: 4136733570236406132}
|
- {fileID: 4136733570236406132}
|
||||||
m_Father: {fileID: 1315170081792486277}
|
m_Father: {fileID: 1315170081792486277}
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
@@ -400,8 +402,8 @@ MonoBehaviour:
|
|||||||
m_EditorClassIdentifier: '::'
|
m_EditorClassIdentifier: '::'
|
||||||
PageName:
|
PageName:
|
||||||
transitionDuration: 0.3
|
transitionDuration: 0.3
|
||||||
rainbowIn: {fileID: 0}
|
rainbowIn: {fileID: 5382650426034128680}
|
||||||
rainbowOut: {fileID: 0}
|
rainbowOut: {fileID: 3983328028282460839}
|
||||||
gameLayoutContainer: {fileID: 904161782565348054}
|
gameLayoutContainer: {fileID: 904161782565348054}
|
||||||
exitButton: {fileID: 8427602740714176801}
|
exitButton: {fileID: 8427602740714176801}
|
||||||
rectMask: {fileID: 7425566603516801919}
|
rectMask: {fileID: 7425566603516801919}
|
||||||
@@ -526,6 +528,99 @@ MonoBehaviour:
|
|||||||
m_OnClick:
|
m_OnClick:
|
||||||
m_PersistentCalls:
|
m_PersistentCalls:
|
||||||
m_Calls: []
|
m_Calls: []
|
||||||
|
--- !u!1 &3983328028282460839
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 6717870941799174515}
|
||||||
|
- component: {fileID: 6334910097310371923}
|
||||||
|
- component: {fileID: 8821021733826365168}
|
||||||
|
- component: {fileID: 9163925342151684341}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: RainbowOut
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &6717870941799174515
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 3983328028282460839}
|
||||||
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 8293076336493130222}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
|
m_AnchorMax: {x: 1, y: 1}
|
||||||
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
|
m_SizeDelta: {x: 0, y: 0}
|
||||||
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
|
--- !u!222 &6334910097310371923
|
||||||
|
CanvasRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 3983328028282460839}
|
||||||
|
m_CullTransparentMesh: 1
|
||||||
|
--- !u!114 &8821021733826365168
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 3983328028282460839}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.RawImage
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
m_RaycastTarget: 1
|
||||||
|
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_Maskable: 1
|
||||||
|
m_OnCullStateChanged:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_UVRect:
|
||||||
|
serializedVersion: 2
|
||||||
|
x: 0
|
||||||
|
y: 0
|
||||||
|
width: 1
|
||||||
|
height: -1
|
||||||
|
--- !u!114 &9163925342151684341
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 3983328028282460839}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 2fd09147b9e9d42a48d6ddc915ddc3d2, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: SkiaSharp.Unity::SkiaSharp.Unity.SkottiePlayerV2
|
||||||
|
lottieFile: {fileID: 4900000, guid: 589505308c5daf449800f30dd4b92ce7, type: 3}
|
||||||
|
customResolution: 0
|
||||||
|
resWidth: 250
|
||||||
|
resHeight: 250
|
||||||
|
stateName:
|
||||||
|
resetAfterFinished: 0
|
||||||
|
autoPlay: 0
|
||||||
|
loop: 0
|
||||||
--- !u!1 &4270065472017787841
|
--- !u!1 &4270065472017787841
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@@ -841,6 +936,99 @@ MonoBehaviour:
|
|||||||
m_OnClick:
|
m_OnClick:
|
||||||
m_PersistentCalls:
|
m_PersistentCalls:
|
||||||
m_Calls: []
|
m_Calls: []
|
||||||
|
--- !u!1 &5382650426034128680
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 6108475066390421500}
|
||||||
|
- component: {fileID: 2398693306920598044}
|
||||||
|
- component: {fileID: 7920249735731934357}
|
||||||
|
- component: {fileID: 3566391948883171773}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: RainbowIn
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &6108475066390421500
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 5382650426034128680}
|
||||||
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 8293076336493130222}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
|
m_AnchorMax: {x: 1, y: 1}
|
||||||
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
|
m_SizeDelta: {x: 0, y: 0}
|
||||||
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
|
--- !u!222 &2398693306920598044
|
||||||
|
CanvasRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 5382650426034128680}
|
||||||
|
m_CullTransparentMesh: 1
|
||||||
|
--- !u!114 &7920249735731934357
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 5382650426034128680}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.RawImage
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
m_RaycastTarget: 1
|
||||||
|
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
m_Maskable: 1
|
||||||
|
m_OnCullStateChanged:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_UVRect:
|
||||||
|
serializedVersion: 2
|
||||||
|
x: 0
|
||||||
|
y: 0
|
||||||
|
width: 1
|
||||||
|
height: -1
|
||||||
|
--- !u!114 &3566391948883171773
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 5382650426034128680}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 2fd09147b9e9d42a48d6ddc915ddc3d2, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: SkiaSharp.Unity::SkiaSharp.Unity.SkottiePlayerV2
|
||||||
|
lottieFile: {fileID: 4900000, guid: 622be2ef9d5e27d45a9deaf7ed805f5f, type: 3}
|
||||||
|
customResolution: 0
|
||||||
|
resWidth: 250
|
||||||
|
resHeight: 250
|
||||||
|
stateName:
|
||||||
|
resetAfterFinished: 0
|
||||||
|
autoPlay: 0
|
||||||
|
loop: 0
|
||||||
--- !u!1 &5867455130109727138
|
--- !u!1 &5867455130109727138
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
"OptimizedRope",
|
"OptimizedRope",
|
||||||
"AudioSourceEvents",
|
"AudioSourceEvents",
|
||||||
"NewAssembly",
|
"NewAssembly",
|
||||||
|
"SkiaSharp.Unity",
|
||||||
|
"SkiaSharp.Editor",
|
||||||
|
"SkiaSharp",
|
||||||
"Unity.Cinemachine"
|
"Unity.Cinemachine"
|
||||||
],
|
],
|
||||||
"includePlatforms": [],
|
"includePlatforms": [],
|
||||||
|
|||||||
@@ -30,8 +30,6 @@ namespace Bootstrap
|
|||||||
private float _sceneLoadingProgress = 0f;
|
private float _sceneLoadingProgress = 0f;
|
||||||
private LogVerbosity _logVerbosity = LogVerbosity.Warning;
|
private LogVerbosity _logVerbosity = LogVerbosity.Warning;
|
||||||
|
|
||||||
// Run very early - need to set up loading screen before other systems initialize
|
|
||||||
public override int ManagedAwakePriority => 5;
|
|
||||||
|
|
||||||
internal override void OnManagedAwake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
@@ -83,10 +81,8 @@ namespace Bootstrap
|
|||||||
Invoke(nameof(StartLoadingMainMenu), minDelayAfterBoot);
|
Invoke(nameof(StartLoadingMainMenu), minDelayAfterBoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Manual cleanup for events
|
// Manual cleanup for events
|
||||||
if (initialLoadingScreen != null)
|
if (initialLoadingScreen != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -37,8 +37,6 @@ namespace Cinematics
|
|||||||
|
|
||||||
public PlayableDirector playableDirector;
|
public PlayableDirector playableDirector;
|
||||||
|
|
||||||
public override int ManagedAwakePriority => 170; // Cinematic systems
|
|
||||||
|
|
||||||
internal override void OnManagedAwake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
// Set instance immediately (early initialization)
|
// Set instance immediately (early initialization)
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ namespace Cinematics
|
|||||||
private float _holdStartTime;
|
private float _holdStartTime;
|
||||||
private bool _isHolding;
|
private bool _isHolding;
|
||||||
private bool _skipPerformed;
|
private bool _skipPerformed;
|
||||||
|
|
||||||
public override int ManagedAwakePriority => 180; // Cinematic UI
|
|
||||||
|
|
||||||
internal override void OnManagedStart()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
@@ -32,10 +30,8 @@ namespace Cinematics
|
|||||||
Logging.Debug("[SkipCinematic] Initialized");
|
Logging.Debug("[SkipCinematic] Initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Clean up subscriptions
|
// Clean up subscriptions
|
||||||
UnsubscribeFromCinematicsEvents();
|
UnsubscribeFromCinematicsEvents();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,8 +34,6 @@ namespace Core
|
|||||||
public event Action OnGamePaused;
|
public event Action OnGamePaused;
|
||||||
public event Action OnGameResumed;
|
public event Action OnGameResumed;
|
||||||
|
|
||||||
// ManagedBehaviour configuration
|
|
||||||
public override int ManagedAwakePriority => 10; // Core infrastructure - runs early
|
|
||||||
|
|
||||||
internal override void OnManagedAwake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -47,8 +47,6 @@ namespace Core
|
|||||||
// Broadcasts when any two items are successfully combined
|
// Broadcasts when any two items are successfully combined
|
||||||
// Args: first item data, second item data, result item data
|
// Args: first item data, second item data, result item data
|
||||||
public event Action<PickupItemData, PickupItemData, PickupItemData> OnItemsCombined;
|
public event Action<PickupItemData, PickupItemData, PickupItemData> OnItemsCombined;
|
||||||
|
|
||||||
public override int ManagedAwakePriority => 75; // Item registry
|
|
||||||
|
|
||||||
internal override void OnManagedAwake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
@@ -67,10 +65,8 @@ namespace Core
|
|||||||
ClearAllRegistrations();
|
ClearAllRegistrations();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Ensure we clean up any subscriptions from registered items when the manager is destroyed
|
// Ensure we clean up any subscriptions from registered items when the manager is destroyed
|
||||||
ClearAllRegistrations();
|
ClearAllRegistrations();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,19 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public enum LifecyclePhase
|
public enum LifecyclePhase
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Called immediately during registration (during Awake).
|
||||||
|
/// Use for early initialization such as setting singleton instances.
|
||||||
|
/// NOT ordered - fires whenever Unity calls this component's Awake().
|
||||||
|
/// </summary>
|
||||||
|
ManagedAwake,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called once per component after bootstrap completes.
|
/// Called once per component after bootstrap completes.
|
||||||
/// Guaranteed to be called after all bootstrap resources are loaded.
|
/// Guaranteed to be called after all bootstrap resources are loaded.
|
||||||
/// For late-registered components, called immediately upon registration.
|
/// For late-registered components, called immediately upon registration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ManagedAwake,
|
ManagedStart,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called before a scene is unloaded.
|
/// Called before a scene is unloaded.
|
||||||
|
|||||||
@@ -59,11 +59,11 @@ namespace Core.Lifecycle
|
|||||||
|
|
||||||
#region State Flags
|
#region State Flags
|
||||||
|
|
||||||
private bool isBootComplete = false;
|
private bool isBootComplete;
|
||||||
private string currentSceneReady = "";
|
private string currentSceneReady = "";
|
||||||
|
|
||||||
// Scene loading state tracking
|
// Scene loading state tracking
|
||||||
private bool isLoadingScene = false;
|
private bool isLoadingScene;
|
||||||
private string sceneBeingLoaded = "";
|
private string sceneBeingLoaded = "";
|
||||||
private List<ManagedBehaviour> pendingSceneComponents = new List<ManagedBehaviour>();
|
private List<ManagedBehaviour> pendingSceneComponents = new List<ManagedBehaviour>();
|
||||||
|
|
||||||
@@ -120,17 +120,13 @@ namespace Core.Lifecycle
|
|||||||
// Track which scene this component belongs to
|
// Track which scene this component belongs to
|
||||||
componentScenes[component] = sceneName;
|
componentScenes[component] = sceneName;
|
||||||
|
|
||||||
// ALWAYS add to managedAwakeList - this is the master list used for save/load
|
// Add to all lifecycle lists (order of registration determines execution order)
|
||||||
InsertSorted(managedAwakeList, component, component.ManagedAwakePriority);
|
managedAwakeList.Add(component);
|
||||||
|
sceneUnloadingList.Add(component);
|
||||||
// Register for all scene lifecycle hooks
|
sceneReadyList.Add(component);
|
||||||
InsertSorted(sceneUnloadingList, component, component.SceneUnloadingPriority);
|
saveRequestedList.Add(component);
|
||||||
InsertSorted(sceneReadyList, component, component.SceneReadyPriority);
|
restoreRequestedList.Add(component);
|
||||||
InsertSorted(saveRequestedList, component, component.SavePriority);
|
destroyList.Add(component);
|
||||||
InsertSorted(restoreRequestedList, component, component.RestorePriority);
|
|
||||||
InsertSorted(destroyList, component, component.DestroyPriority);
|
|
||||||
|
|
||||||
// Call OnManagedAwake immediately after registration (early initialization hook)
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
component.OnManagedAwake();
|
component.OnManagedAwake();
|
||||||
@@ -146,7 +142,7 @@ namespace Core.Lifecycle
|
|||||||
// Check if we're currently loading a scene
|
// Check if we're currently loading a scene
|
||||||
if (isLoadingScene && sceneName == sceneBeingLoaded)
|
if (isLoadingScene && sceneName == sceneBeingLoaded)
|
||||||
{
|
{
|
||||||
// Batch this component - will be processed in priority order when scene load completes
|
// Batch this component - will be processed when scene load completes
|
||||||
pendingSceneComponents.Add(component);
|
pendingSceneComponents.Add(component);
|
||||||
LogDebug($"Batched component for scene load: {component.gameObject.name} (Scene: {sceneName})");
|
LogDebug($"Batched component for scene load: {component.gameObject.name} (Scene: {sceneName})");
|
||||||
}
|
}
|
||||||
@@ -282,10 +278,7 @@ namespace Core.Lifecycle
|
|||||||
|
|
||||||
LogDebug($"Processing {pendingSceneComponents.Count} batched components for scene: {sceneBeingLoaded}");
|
LogDebug($"Processing {pendingSceneComponents.Count} batched components for scene: {sceneBeingLoaded}");
|
||||||
|
|
||||||
// Sort by ManagedAwake priority (lower values first)
|
// Call OnManagedStart in registration order
|
||||||
pendingSceneComponents.Sort((a, b) => a.ManagedAwakePriority.CompareTo(b.ManagedAwakePriority));
|
|
||||||
|
|
||||||
// Call OnManagedStart in priority order
|
|
||||||
foreach (var component in pendingSceneComponents)
|
foreach (var component in pendingSceneComponents)
|
||||||
{
|
{
|
||||||
if (component == null) continue;
|
if (component == null) continue;
|
||||||
@@ -294,7 +287,7 @@ namespace Core.Lifecycle
|
|||||||
{
|
{
|
||||||
component.OnManagedStart();
|
component.OnManagedStart();
|
||||||
HandleAutoRegistrations(component);
|
HandleAutoRegistrations(component);
|
||||||
LogDebug($"Processed batched component: {component.gameObject.name} (Priority: {component.ManagedAwakePriority})");
|
LogDebug($"Processed batched component: {component.gameObject.name}");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -309,7 +302,7 @@ namespace Core.Lifecycle
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Broadcast OnSceneUnloading to components in the specified scene (reverse priority order).
|
/// Broadcast OnSceneUnloading to components in the specified scene.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void BroadcastSceneUnloading(string sceneName)
|
public void BroadcastSceneUnloading(string sceneName)
|
||||||
{
|
{
|
||||||
@@ -336,8 +329,8 @@ namespace Core.Lifecycle
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Broadcast OnSceneReady to components in the specified scene (priority order).
|
/// Broadcast OnSceneReady to components in the specified scene.
|
||||||
/// If scene loading mode is active, processes batched components first.
|
/// Processes batched components first, then calls OnSceneReady on all components in that scene.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void BroadcastSceneReady(string sceneName)
|
public void BroadcastSceneReady(string sceneName)
|
||||||
{
|
{
|
||||||
@@ -621,42 +614,6 @@ namespace Core.Lifecycle
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Helper Methods
|
#region Helper Methods
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Insert component into list maintaining sorted order by priority.
|
|
||||||
/// Uses binary search for efficient insertion.
|
|
||||||
/// </summary>
|
|
||||||
private void InsertSorted(List<ManagedBehaviour> list, ManagedBehaviour component, int priority)
|
|
||||||
{
|
|
||||||
// Simple linear insertion for now (can optimize with binary search later if needed)
|
|
||||||
int index = 0;
|
|
||||||
for (int i = 0; i < list.Count; i++)
|
|
||||||
{
|
|
||||||
int existingPriority = GetPriorityForList(list[i], list);
|
|
||||||
if (priority < existingPriority)
|
|
||||||
{
|
|
||||||
index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
index = i + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
list.Insert(index, component);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the priority value for a component based on which list it's in.
|
|
||||||
/// </summary>
|
|
||||||
private int GetPriorityForList(ManagedBehaviour component, List<ManagedBehaviour> list)
|
|
||||||
{
|
|
||||||
if (list == managedAwakeList) return component.ManagedAwakePriority;
|
|
||||||
if (list == sceneUnloadingList) return component.SceneUnloadingPriority;
|
|
||||||
if (list == sceneReadyList) return component.SceneReadyPriority;
|
|
||||||
if (list == saveRequestedList) return component.SavePriority;
|
|
||||||
if (list == restoreRequestedList) return component.RestorePriority;
|
|
||||||
if (list == destroyList) return component.DestroyPriority;
|
|
||||||
return 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Log debug message if debug logging is enabled.
|
/// Log debug message if debug logging is enabled.
|
||||||
|
|||||||
@@ -8,46 +8,6 @@ namespace Core.Lifecycle
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class ManagedBehaviour : MonoBehaviour
|
public abstract class ManagedBehaviour : MonoBehaviour
|
||||||
{
|
{
|
||||||
#region Priority Properties
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Priority for OnManagedStart (lower values execute first).
|
|
||||||
/// Default: 100
|
|
||||||
/// </summary>
|
|
||||||
public virtual int ManagedAwakePriority => 100;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Priority for OnSceneUnloading (executed in reverse: higher values execute first).
|
|
||||||
/// Default: 100
|
|
||||||
/// </summary>
|
|
||||||
public virtual int SceneUnloadingPriority => 100;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Priority for OnSceneReady (lower values execute first).
|
|
||||||
/// Default: 100
|
|
||||||
/// </summary>
|
|
||||||
public virtual int SceneReadyPriority => 100;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Priority for OnSaveRequested (executed in reverse: higher values execute first).
|
|
||||||
/// Default: 100
|
|
||||||
/// </summary>
|
|
||||||
public virtual int SavePriority => 100;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Priority for OnRestoreRequested (lower values execute first).
|
|
||||||
/// Default: 100
|
|
||||||
/// </summary>
|
|
||||||
public virtual int RestorePriority => 100;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Priority for OnManagedDestroy (executed in reverse: higher values execute first).
|
|
||||||
/// Default: 100
|
|
||||||
/// </summary>
|
|
||||||
public virtual int DestroyPriority => 100;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Configuration Properties
|
#region Configuration Properties
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -67,14 +27,19 @@ namespace Core.Lifecycle
|
|||||||
/// Unique identifier for this component in the save system.
|
/// Unique identifier for this component in the save system.
|
||||||
/// Default: "SceneName/GameObjectName/ComponentType"
|
/// Default: "SceneName/GameObjectName/ComponentType"
|
||||||
/// Override ONLY for special cases (e.g., singletons like "PlayerController", or custom IDs).
|
/// Override ONLY for special cases (e.g., singletons like "PlayerController", or custom IDs).
|
||||||
|
/// Cached on first access to avoid runtime allocation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual string SaveId
|
public virtual string SaveId
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
string sceneName = gameObject.scene.IsValid() ? gameObject.scene.name : "UnknownScene";
|
if (_cachedSaveId == null)
|
||||||
string componentType = GetType().Name;
|
{
|
||||||
return $"{sceneName}/{gameObject.name}/{componentType}";
|
string sceneName = gameObject.scene.IsValid() ? gameObject.scene.name : "UnknownScene";
|
||||||
|
string componentType = GetType().Name;
|
||||||
|
_cachedSaveId = $"{sceneName}/{gameObject.name}/{componentType}";
|
||||||
|
}
|
||||||
|
return _cachedSaveId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,6 +48,7 @@ namespace Core.Lifecycle
|
|||||||
#region Private Fields
|
#region Private Fields
|
||||||
|
|
||||||
private bool _isRegistered;
|
private bool _isRegistered;
|
||||||
|
private string _cachedSaveId;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -107,13 +73,16 @@ namespace Core.Lifecycle
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unity OnDestroy - automatically unregisters and cleans up.
|
/// Unity OnDestroy - automatically unregisters and cleans up.
|
||||||
/// IMPORTANT: Derived classes that override OnDestroy MUST call base.OnDestroy()
|
/// SEALED: Cannot be overridden. Use OnManagedDestroy() for custom cleanup logic.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnDestroy()
|
private void OnDestroy()
|
||||||
{
|
{
|
||||||
if (!_isRegistered)
|
if (!_isRegistered)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Call managed destroy hook
|
||||||
|
OnManagedDestroy();
|
||||||
|
|
||||||
// Unregister from LifecycleManager
|
// Unregister from LifecycleManager
|
||||||
if (LifecycleManager.Instance != null)
|
if (LifecycleManager.Instance != null)
|
||||||
{
|
{
|
||||||
@@ -149,7 +118,7 @@ namespace Core.Lifecycle
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called once per component after bootstrap completes.
|
/// Called once per component after bootstrap completes.
|
||||||
/// GUARANTEE: Bootstrap resources are available, all managers are initialized.
|
/// GUARANTEE: Bootstrap resources are available, all managers are initialized.
|
||||||
/// For boot-time components: Called during LifecycleManager.BroadcastManagedStart (priority ordered).
|
/// For boot-time components: Called during LifecycleManager.BroadcastManagedStart (registration order).
|
||||||
/// For late-registered components: Called immediately upon registration (bootstrap already complete).
|
/// For late-registered components: Called immediately upon registration (bootstrap already complete).
|
||||||
/// Use for initialization that depends on other systems.
|
/// Use for initialization that depends on other systems.
|
||||||
/// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes.
|
/// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes.
|
||||||
@@ -161,7 +130,6 @@ namespace Core.Lifecycle
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called before the scene this component belongs to is unloaded.
|
/// Called before the scene this component belongs to is unloaded.
|
||||||
/// Called in REVERSE priority order (higher values execute first).
|
|
||||||
/// Use for scene-specific cleanup.
|
/// Use for scene-specific cleanup.
|
||||||
/// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes.
|
/// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -172,7 +140,6 @@ namespace Core.Lifecycle
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called after the scene this component belongs to has finished loading.
|
/// Called after the scene this component belongs to has finished loading.
|
||||||
/// Called in priority order (lower values execute first).
|
|
||||||
/// Use for scene-specific initialization.
|
/// Use for scene-specific initialization.
|
||||||
/// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes.
|
/// NOTE: Internal visibility allows LifecycleManager to call directly. Override in derived classes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -312,7 +279,6 @@ namespace Core.Lifecycle
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called during OnDestroy before component is destroyed.
|
/// Called during OnDestroy before component is destroyed.
|
||||||
/// Called in REVERSE priority order (higher values execute first).
|
|
||||||
/// NOTE: Most cleanup is automatic (managed events, auto-registrations).
|
/// NOTE: Most cleanup is automatic (managed events, auto-registrations).
|
||||||
/// Only override if you need custom cleanup logic.
|
/// Only override if you need custom cleanup logic.
|
||||||
/// Internal visibility allows LifecycleManager to call directly. Override in derived classes.
|
/// Internal visibility allows LifecycleManager to call directly. Override in derived classes.
|
||||||
|
|||||||
@@ -24,9 +24,6 @@ namespace AppleHills.Core
|
|||||||
|
|
||||||
#endregion Singleton Setup
|
#endregion Singleton Setup
|
||||||
|
|
||||||
// Very early initialization - QuickAccess should be available immediately
|
|
||||||
public override int ManagedAwakePriority => 5;
|
|
||||||
|
|
||||||
#region Manager Instances
|
#region Manager Instances
|
||||||
|
|
||||||
// Core Managers
|
// Core Managers
|
||||||
|
|||||||
@@ -43,8 +43,6 @@ namespace Core.SaveLoad
|
|||||||
public event Action<string> OnLoadCompleted;
|
public event Action<string> OnLoadCompleted;
|
||||||
public event Action OnParticipantStatesRestored;
|
public event Action OnParticipantStatesRestored;
|
||||||
|
|
||||||
// ManagedBehaviour configuration
|
|
||||||
public override int ManagedAwakePriority => 20; // After GameManager and SceneManagerService
|
|
||||||
|
|
||||||
internal override void OnManagedAwake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
@@ -95,10 +93,8 @@ namespace Core.SaveLoad
|
|||||||
|
|
||||||
// ...existing code...
|
// ...existing code...
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy(); // Important: call base to unregister from LifecycleManager
|
|
||||||
|
|
||||||
if (_instance == this)
|
if (_instance == this)
|
||||||
{
|
{
|
||||||
_instance = null;
|
_instance = null;
|
||||||
|
|||||||
@@ -42,10 +42,8 @@ namespace Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
if (_director != null)
|
if (_director != null)
|
||||||
{
|
{
|
||||||
_director.stopped -= OnDirectorStopped;
|
_director.stopped -= OnDirectorStopped;
|
||||||
|
|||||||
@@ -44,8 +44,6 @@ namespace Core
|
|||||||
private LogVerbosity _logVerbosity = LogVerbosity.Debug;
|
private LogVerbosity _logVerbosity = LogVerbosity.Debug;
|
||||||
private const string BootstrapSceneName = "BootstrapScene";
|
private const string BootstrapSceneName = "BootstrapScene";
|
||||||
|
|
||||||
// ManagedBehaviour configuration
|
|
||||||
public override int ManagedAwakePriority => 15; // Core infrastructure, after GameManager
|
|
||||||
|
|
||||||
internal override void OnManagedAwake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
@@ -369,7 +367,7 @@ namespace Core
|
|||||||
await LoadSceneAsync(newSceneName, progress);
|
await LoadSceneAsync(newSceneName, progress);
|
||||||
CurrentGameplayScene = newSceneName;
|
CurrentGameplayScene = newSceneName;
|
||||||
|
|
||||||
// PHASE 10: Broadcast scene ready - processes batched components in priority order, then calls OnSceneReady
|
// PHASE 10: Broadcast scene ready - processes batched components, then calls OnSceneReady
|
||||||
Logging.Debug($"Broadcasting OnSceneReady for: {newSceneName}");
|
Logging.Debug($"Broadcasting OnSceneReady for: {newSceneName}");
|
||||||
LifecycleManager.Instance?.BroadcastSceneReady(newSceneName);
|
LifecycleManager.Instance?.BroadcastSceneReady(newSceneName);
|
||||||
|
|
||||||
|
|||||||
@@ -18,9 +18,6 @@ namespace Core
|
|||||||
public GameObject orientationPromptPrefab;
|
public GameObject orientationPromptPrefab;
|
||||||
private LogVerbosity _logVerbosity = LogVerbosity.Warning;
|
private LogVerbosity _logVerbosity = LogVerbosity.Warning;
|
||||||
|
|
||||||
// ManagedBehaviour configuration
|
|
||||||
public override int ManagedAwakePriority => 70; // Platform-specific utility
|
|
||||||
|
|
||||||
internal override void OnManagedAwake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
// Set instance immediately (early initialization)
|
// Set instance immediately (early initialization)
|
||||||
@@ -103,15 +100,13 @@ namespace Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
// Unsubscribe from events to prevent memory leaks
|
// Unsubscribe from events to prevent memory leaks
|
||||||
if (SceneManagerService.Instance != null)
|
if (SceneManagerService.Instance != null)
|
||||||
{
|
{
|
||||||
SceneManagerService.Instance.SceneLoadCompleted -= OnSceneLoadCompleted;
|
SceneManagerService.Instance.SceneLoadCompleted -= OnSceneLoadCompleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnDestroy(); // Important: call base
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -43,8 +43,6 @@ namespace Data.CardSystem
|
|||||||
public event Action<int> OnBoosterCountChanged;
|
public event Action<int> OnBoosterCountChanged;
|
||||||
public event Action<CardData> OnPendingCardAdded;
|
public event Action<CardData> OnPendingCardAdded;
|
||||||
public event Action<CardData> OnCardPlacedInAlbum;
|
public event Action<CardData> OnCardPlacedInAlbum;
|
||||||
|
|
||||||
public override int ManagedAwakePriority => 60; // Data systems
|
|
||||||
|
|
||||||
internal override void OnManagedAwake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -32,9 +32,6 @@ namespace Dialogue
|
|||||||
public bool IsCompleted { get; private set; }
|
public bool IsCompleted { get; private set; }
|
||||||
public string CurrentSpeakerName => dialogueGraph?.speakerName;
|
public string CurrentSpeakerName => dialogueGraph?.speakerName;
|
||||||
|
|
||||||
|
|
||||||
public override int ManagedAwakePriority => 150; // Dialogue systems
|
|
||||||
|
|
||||||
internal override void OnManagedStart()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
// Get required components
|
// Get required components
|
||||||
@@ -184,10 +181,8 @@ namespace Dialogue
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Unregister from events
|
// Unregister from events
|
||||||
if (PuzzleManager.Instance != null)
|
if (PuzzleManager.Instance != null)
|
||||||
PuzzleManager.Instance.OnStepCompleted -= OnAnyPuzzleStepCompleted;
|
PuzzleManager.Instance.OnStepCompleted -= OnAnyPuzzleStepCompleted;
|
||||||
|
|||||||
@@ -49,8 +49,6 @@ namespace Input
|
|||||||
private ITouchInputConsumer defaultConsumer;
|
private ITouchInputConsumer defaultConsumer;
|
||||||
private bool isHoldActive;
|
private bool isHoldActive;
|
||||||
private LogVerbosity _logVerbosity = LogVerbosity.Warning;
|
private LogVerbosity _logVerbosity = LogVerbosity.Warning;
|
||||||
|
|
||||||
public override int ManagedAwakePriority => 25; // Input infrastructure
|
|
||||||
|
|
||||||
internal override void OnManagedAwake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
@@ -106,7 +104,7 @@ namespace Input
|
|||||||
SwitchInputOnSceneLoaded(sceneName);
|
SwitchInputOnSceneLoaded(sceneName);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
// Unsubscribe from SceneManagerService events
|
// Unsubscribe from SceneManagerService events
|
||||||
if (SceneManagerService.Instance != null)
|
if (SceneManagerService.Instance != null)
|
||||||
@@ -114,7 +112,6 @@ namespace Input
|
|||||||
SceneManagerService.Instance.SceneLoadCompleted -= OnSceneLoadCompleted;
|
SceneManagerService.Instance.SceneLoadCompleted -= OnSceneLoadCompleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnDestroy();
|
|
||||||
// Input action cleanup happens automatically
|
// Input action cleanup happens automatically
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ namespace Input
|
|||||||
public override bool AutoRegisterForSave => true;
|
public override bool AutoRegisterForSave => true;
|
||||||
// Scene-specific SaveId - each level has its own player state
|
// Scene-specific SaveId - each level has its own player state
|
||||||
public override string SaveId => $"{gameObject.scene.name}/PlayerController";
|
public override string SaveId => $"{gameObject.scene.name}/PlayerController";
|
||||||
public override int ManagedAwakePriority => 100; // Player controller
|
|
||||||
|
|
||||||
internal override void OnManagedStart()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -41,9 +41,6 @@ namespace Interactions
|
|||||||
// Action component system
|
// Action component system
|
||||||
private List<InteractionActionBase> _registeredActions = new List<InteractionActionBase>();
|
private List<InteractionActionBase> _registeredActions = new List<InteractionActionBase>();
|
||||||
|
|
||||||
// ManagedBehaviour configuration
|
|
||||||
public override int ManagedAwakePriority => 100; // Gameplay base classes
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register an action component with this interactable
|
/// Register an action component with this interactable
|
||||||
|
|||||||
@@ -287,10 +287,8 @@ namespace Interactions
|
|||||||
ItemManager.Instance?.RegisterItemSlot(this);
|
ItemManager.Instance?.RegisterItemSlot(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Unregister from slot manager
|
// Unregister from slot manager
|
||||||
ItemManager.Instance?.UnregisterItemSlot(this);
|
ItemManager.Instance?.UnregisterItemSlot(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,10 +50,8 @@ namespace Interactions
|
|||||||
ItemManager.Instance?.RegisterPickup(this);
|
ItemManager.Instance?.RegisterPickup(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Unregister from ItemManager
|
// Unregister from ItemManager
|
||||||
ItemManager.Instance?.UnregisterPickup(this);
|
ItemManager.Instance?.UnregisterPickup(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,10 +80,8 @@ namespace Levels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
if (PuzzleManager.Instance != null)
|
if (PuzzleManager.Instance != null)
|
||||||
{
|
{
|
||||||
PuzzleManager.Instance.OnAllPuzzlesComplete -= HandleAllPuzzlesComplete;
|
PuzzleManager.Instance.OnAllPuzzlesComplete -= HandleAllPuzzlesComplete;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ using UI.Core;
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Events;
|
using UnityEngine.Events;
|
||||||
using UnityEngine.Playables;
|
using UnityEngine.Playables;
|
||||||
|
using Svg;
|
||||||
|
|
||||||
namespace Minigames.DivingForPictures
|
namespace Minigames.DivingForPictures
|
||||||
{
|
{
|
||||||
@@ -103,7 +104,6 @@ namespace Minigames.DivingForPictures
|
|||||||
|
|
||||||
public static DivingGameManager Instance => _instance;
|
public static DivingGameManager Instance => _instance;
|
||||||
|
|
||||||
public override int ManagedAwakePriority => 190;
|
|
||||||
public override bool AutoRegisterPausable => true; // Automatic GameManager registration
|
public override bool AutoRegisterPausable => true; // Automatic GameManager registration
|
||||||
|
|
||||||
internal override void OnManagedAwake()
|
internal override void OnManagedAwake()
|
||||||
@@ -161,10 +161,8 @@ namespace Minigames.DivingForPictures
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy(); // Handles auto-unregister from GameManager
|
|
||||||
|
|
||||||
// Unsubscribe from events when the manager is destroyed
|
// Unsubscribe from events when the manager is destroyed
|
||||||
PlayerCollisionBehavior.OnDamageTaken -= OnPlayerDamageTaken;
|
PlayerCollisionBehavior.OnDamageTaken -= OnPlayerDamageTaken;
|
||||||
OnMonsterSpawned -= DoMonsterSpawned;
|
OnMonsterSpawned -= DoMonsterSpawned;
|
||||||
|
|||||||
@@ -106,8 +106,6 @@ public class FollowerController : ManagedBehaviour
|
|||||||
private bool _hasRestoredHeldItem; // Track if held item restoration completed
|
private bool _hasRestoredHeldItem; // Track if held item restoration completed
|
||||||
private string _expectedHeldItemSaveId; // Expected saveId during restoration
|
private string _expectedHeldItemSaveId; // Expected saveId during restoration
|
||||||
|
|
||||||
public override int ManagedAwakePriority => 110; // Follower after player
|
|
||||||
|
|
||||||
internal override void OnManagedStart()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
_aiPath = GetComponent<AIPath>();
|
_aiPath = GetComponent<AIPath>();
|
||||||
|
|||||||
@@ -83,10 +83,8 @@ namespace PuzzleS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
if (PuzzleManager.Instance != null && stepData != null)
|
if (PuzzleManager.Instance != null && stepData != null)
|
||||||
{
|
{
|
||||||
PuzzleManager.Instance.UnregisterStepBehaviour(this);
|
PuzzleManager.Instance.UnregisterStepBehaviour(this);
|
||||||
|
|||||||
@@ -93,8 +93,6 @@ namespace PuzzleS
|
|||||||
|
|
||||||
// Track pending unlocks for steps that were unlocked before their behavior registered
|
// Track pending unlocks for steps that were unlocked before their behavior registered
|
||||||
private HashSet<string> _pendingUnlocks = new HashSet<string>();
|
private HashSet<string> _pendingUnlocks = new HashSet<string>();
|
||||||
|
|
||||||
public override int ManagedAwakePriority => 80; // Puzzle systems
|
|
||||||
|
|
||||||
internal override void OnManagedAwake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
@@ -138,10 +136,8 @@ namespace PuzzleS
|
|||||||
LoadPuzzlesForScene(sceneName);
|
LoadPuzzlesForScene(sceneName);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Unsubscribe from SceneManagerService events
|
// Unsubscribe from SceneManagerService events
|
||||||
if (SceneManagerService.Instance != null)
|
if (SceneManagerService.Instance != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -40,8 +40,6 @@ public class AudioManager : ManagedBehaviour, IPausable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static AudioManager Instance => _instance;
|
public static AudioManager Instance => _instance;
|
||||||
|
|
||||||
// ManagedBehaviour configuration
|
|
||||||
public override int ManagedAwakePriority => 30; // Audio infrastructure
|
|
||||||
public override bool AutoRegisterPausable => true; // Auto-register as IPausable
|
public override bool AutoRegisterPausable => true; // Auto-register as IPausable
|
||||||
|
|
||||||
internal override void OnManagedAwake()
|
internal override void OnManagedAwake()
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
|
using SkiaSharp.Unity;
|
||||||
using Input;
|
using Input;
|
||||||
using AppleHills.Core;
|
using AppleHills.Core;
|
||||||
using UI.Core;
|
using UI.Core;
|
||||||
@@ -10,6 +11,8 @@ using UI;
|
|||||||
|
|
||||||
public class AppSwitcher : UIPage
|
public class AppSwitcher : UIPage
|
||||||
{
|
{
|
||||||
|
public GameObject rainbowIn;
|
||||||
|
public GameObject rainbowOut;
|
||||||
public GameObject gameLayoutContainer;
|
public GameObject gameLayoutContainer;
|
||||||
public GameObject exitButton;
|
public GameObject exitButton;
|
||||||
public RectMask2D rectMask;
|
public RectMask2D rectMask;
|
||||||
@@ -17,6 +20,8 @@ public class AppSwitcher : UIPage
|
|||||||
[Header("Slide Animation Settings")]
|
[Header("Slide Animation Settings")]
|
||||||
public float slideDuration = 0.5f;
|
public float slideDuration = 0.5f;
|
||||||
|
|
||||||
|
private SkottiePlayerV2 rainbowInPlayer;
|
||||||
|
private SkottiePlayerV2 rainbowOutPlayer;
|
||||||
private TweenBase slideInTween;
|
private TweenBase slideInTween;
|
||||||
private TweenBase slideOutTween;
|
private TweenBase slideOutTween;
|
||||||
|
|
||||||
@@ -25,13 +30,16 @@ public class AppSwitcher : UIPage
|
|||||||
base.OnManagedAwake();
|
base.OnManagedAwake();
|
||||||
|
|
||||||
PageName = "AppSwitcher";
|
PageName = "AppSwitcher";
|
||||||
|
rainbowInPlayer = rainbowIn.GetComponent<SkottiePlayerV2>();
|
||||||
|
rainbowOutPlayer = rainbowOut.GetComponent<SkottiePlayerV2>();
|
||||||
|
|
||||||
if (rectMask == null)
|
if (rectMask == null)
|
||||||
{
|
{
|
||||||
rectMask = GetComponent<RectMask2D>();
|
rectMask = GetComponent<RectMask2D>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initially hide
|
// Initially hide both
|
||||||
|
rainbowIn.SetActive(true);
|
||||||
exitButton.SetActive(false);
|
exitButton.SetActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,19 +49,27 @@ public class AppSwitcher : UIPage
|
|||||||
|
|
||||||
gameLayoutContainer.SetActive(true);
|
gameLayoutContainer.SetActive(true);
|
||||||
|
|
||||||
|
// Hide rainbow out, show rainbow in
|
||||||
|
rainbowOut.SetActive(false);
|
||||||
|
|
||||||
|
// Play animation on rainbow in without resetting state
|
||||||
|
rainbowInPlayer.PlayAnimation(true);
|
||||||
|
|
||||||
// Slide in animation - tween padding.left from 1700 to 0
|
// Slide in animation - tween padding.left from 1700 to 0
|
||||||
slideInTween = TweenPaddingLeft(1700f, 0f, Tween.EaseOut, () =>
|
slideInTween = TweenPaddingLeft(1700f, 0f, Tween.EaseOut, () =>
|
||||||
{
|
{
|
||||||
onComplete?.Invoke();
|
onComplete?.Invoke();
|
||||||
|
rainbowOut.SetActive(true);
|
||||||
exitButton.SetActive(true);
|
exitButton.SetActive(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void DoTransitionOut(Action onComplete)
|
protected override void DoTransitionOut(Action onComplete)
|
||||||
{
|
{
|
||||||
|
rainbowIn.SetActive(false);
|
||||||
|
|
||||||
|
// Play animation on rainbow out with resetting state
|
||||||
|
rainbowOutPlayer.PlayAnimation(true);
|
||||||
|
|
||||||
// Hide the exit button
|
// Hide the exit button
|
||||||
exitButton.SetActive(false);
|
exitButton.SetActive(false);
|
||||||
@@ -61,6 +77,7 @@ public class AppSwitcher : UIPage
|
|||||||
// Slide out animation - tween padding.left from 0 to 1700
|
// Slide out animation - tween padding.left from 0 to 1700
|
||||||
slideOutTween = TweenPaddingLeft(0f, 1700f, Tween.EaseIn, () => {
|
slideOutTween = TweenPaddingLeft(0f, 1700f, Tween.EaseIn, () => {
|
||||||
gameLayoutContainer.SetActive(false);
|
gameLayoutContainer.SetActive(false);
|
||||||
|
rainbowIn.SetActive(true);
|
||||||
onComplete?.Invoke();
|
onComplete?.Invoke();
|
||||||
InputManager.Instance.SetInputMode(InputMode.GameAndUI);
|
InputManager.Instance.SetInputMode(InputMode.GameAndUI);
|
||||||
});
|
});
|
||||||
@@ -93,10 +110,8 @@ public class AppSwitcher : UIPage
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Clean up tweens
|
// Clean up tweens
|
||||||
slideInTween?.Stop();
|
slideInTween?.Stop();
|
||||||
slideOutTween?.Stop();
|
slideOutTween?.Stop();
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ namespace UI.CardSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
// Unsubscribe from CardSystemManager
|
// Unsubscribe from CardSystemManager
|
||||||
if (CardSystemManager.Instance != null)
|
if (CardSystemManager.Instance != null)
|
||||||
@@ -181,9 +181,6 @@ namespace UI.CardSystem
|
|||||||
|
|
||||||
// Clean up active cards
|
// Clean up active cards
|
||||||
CleanupActiveCards();
|
CleanupActiveCards();
|
||||||
|
|
||||||
// Call base implementation
|
|
||||||
base.OnDestroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnExitButtonClicked()
|
private void OnExitButtonClicked()
|
||||||
|
|||||||
@@ -70,16 +70,13 @@ namespace UI.CardSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
// Unsubscribe from CardSystemManager events to prevent memory leaks
|
// Unsubscribe from CardSystemManager events to prevent memory leaks
|
||||||
if (CardSystemManager.Instance != null)
|
if (CardSystemManager.Instance != null)
|
||||||
{
|
{
|
||||||
CardSystemManager.Instance.OnBoosterCountChanged -= OnBoosterCountChanged;
|
CardSystemManager.Instance.OnBoosterCountChanged -= OnBoosterCountChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call base implementation
|
|
||||||
base.OnDestroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -76,10 +76,8 @@ namespace UI.CardSystem
|
|||||||
gameObject.SetActive(false);
|
gameObject.SetActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Unsubscribe from dismiss button
|
// Unsubscribe from dismiss button
|
||||||
if (_dismissButton != null)
|
if (_dismissButton != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -307,7 +307,7 @@ namespace UI.CardSystem.DragDrop
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
protected override void OnDestroy()
|
protected override void OnDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
base.OnDestroy();
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ namespace UI.CardSystem.DragDrop
|
|||||||
base.OnDragEndedVisual();
|
base.OnDragEndedVisual();
|
||||||
// Card-specific visual effects when dragging ends
|
// Card-specific visual effects when dragging ends
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
protected override void OnDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
base.OnDestroy();
|
||||||
|
|||||||
@@ -15,9 +15,6 @@ namespace UI.Core
|
|||||||
[Header("Page Settings")]
|
[Header("Page Settings")]
|
||||||
public string PageName;
|
public string PageName;
|
||||||
|
|
||||||
// UI pages load after UI infrastructure (UIPageController is priority 50)
|
|
||||||
public override int ManagedAwakePriority => 200;
|
|
||||||
|
|
||||||
// Events using System.Action instead of UnityEvents
|
// Events using System.Action instead of UnityEvents
|
||||||
public event Action OnTransitionInStarted;
|
public event Action OnTransitionInStarted;
|
||||||
public event Action OnTransitionInCompleted;
|
public event Action OnTransitionInCompleted;
|
||||||
|
|||||||
@@ -37,8 +37,6 @@ namespace UI.Core
|
|||||||
private PlayerInput _playerInput;
|
private PlayerInput _playerInput;
|
||||||
private InputAction _cancelAction;
|
private InputAction _cancelAction;
|
||||||
|
|
||||||
public override int ManagedAwakePriority => 50; // UI infrastructure
|
|
||||||
|
|
||||||
internal override void OnManagedAwake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
// Set instance immediately (early initialization)
|
// Set instance immediately (early initialization)
|
||||||
@@ -50,10 +48,8 @@ namespace UI.Core
|
|||||||
Logging.Debug("[UIPageController] Initialized");
|
Logging.Debug("[UIPageController] Initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Clean up cached instances
|
// Clean up cached instances
|
||||||
foreach (var cachedPage in _prefabInstanceCache.Values)
|
foreach (var cachedPage in _prefabInstanceCache.Values)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -52,9 +52,6 @@ namespace UI
|
|||||||
/// Singleton instance of the LoadingScreenController. No longer creates an instance if one doesn't exist.
|
/// Singleton instance of the LoadingScreenController. No longer creates an instance if one doesn't exist.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LoadingScreenController Instance => _instance;
|
public static LoadingScreenController Instance => _instance;
|
||||||
|
|
||||||
// ManagedBehaviour configuration
|
|
||||||
public override int ManagedAwakePriority => 45; // UI infrastructure, before UIPageController
|
|
||||||
|
|
||||||
internal override void OnManagedAwake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -27,9 +27,6 @@ namespace UI
|
|||||||
[SerializeField] private UnityEngine.UI.Button devOptionsButton;
|
[SerializeField] private UnityEngine.UI.Button devOptionsButton;
|
||||||
[SerializeField] private GameObject mainOptionsContainer;
|
[SerializeField] private GameObject mainOptionsContainer;
|
||||||
[SerializeField] private GameObject devOptionsContainer;
|
[SerializeField] private GameObject devOptionsContainer;
|
||||||
|
|
||||||
// After UIPageController (50)
|
|
||||||
public override int ManagedAwakePriority => 55;
|
|
||||||
|
|
||||||
internal override void OnManagedAwake()
|
internal override void OnManagedAwake()
|
||||||
{
|
{
|
||||||
@@ -76,10 +73,8 @@ namespace UI
|
|||||||
// This only fires once for DontDestroyOnLoad objects, so we handle scene loads in OnManagedAwake
|
// This only fires once for DontDestroyOnLoad objects, so we handle scene loads in OnManagedAwake
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Unsubscribe when destroyed
|
// Unsubscribe when destroyed
|
||||||
if (SceneManagerService.Instance != null)
|
if (SceneManagerService.Instance != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -172,10 +172,8 @@ namespace UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDestroy()
|
internal override void OnManagedDestroy()
|
||||||
{
|
{
|
||||||
base.OnDestroy();
|
|
||||||
|
|
||||||
// Unsubscribe from events
|
// Unsubscribe from events
|
||||||
if (_uiPageController != null)
|
if (_uiPageController != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ namespace UI.Tutorial
|
|||||||
private bool _canAcceptInput;
|
private bool _canAcceptInput;
|
||||||
private Coroutine _waitLoopCoroutine;
|
private Coroutine _waitLoopCoroutine;
|
||||||
|
|
||||||
public override int ManagedAwakePriority => 200; // Tutorial runs late, after other systems
|
|
||||||
|
|
||||||
internal override void OnManagedStart()
|
internal override void OnManagedStart()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"com.ammariqais.skiaforunity": "https://github.com/ammariqais/SkiaForUnity.git?path=SkiaUnity/Assets/SkiaSharp",
|
||||||
"com.coplaydev.unity-mcp": "https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity",
|
"com.coplaydev.unity-mcp": "https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity",
|
||||||
"com.moolt.packages.net": "git+https://github.com/Moolt/UnityAudioSourceEvents?path=Packages/AudioSourceEvents",
|
"com.moolt.packages.net": "git+https://github.com/Moolt/UnityAudioSourceEvents?path=Packages/AudioSourceEvents",
|
||||||
"com.unity.2d.sprite": "1.0.0",
|
"com.unity.2d.sprite": "1.0.0",
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"com.ammariqais.skiaforunity": {
|
||||||
|
"version": "https://github.com/ammariqais/SkiaForUnity.git?path=SkiaUnity/Assets/SkiaSharp",
|
||||||
|
"depth": 0,
|
||||||
|
"source": "git",
|
||||||
|
"dependencies": {
|
||||||
|
"com.unity.nuget.newtonsoft-json": "3.2.0"
|
||||||
|
},
|
||||||
|
"hash": "11e82b71012bf8b4f68172080d6e4969d42120ef"
|
||||||
|
},
|
||||||
"com.coplaydev.unity-mcp": {
|
"com.coplaydev.unity-mcp": {
|
||||||
"version": "https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity",
|
"version": "https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity",
|
||||||
"depth": 0,
|
"depth": 0,
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ PlayerSettings:
|
|||||||
targetDevice: 2
|
targetDevice: 2
|
||||||
useOnDemandResources: 0
|
useOnDemandResources: 0
|
||||||
accelerometerFrequency: 60
|
accelerometerFrequency: 60
|
||||||
companyName: DR
|
companyName: DefaultCompany
|
||||||
productName: "DR \xC6blerup"
|
productName: AppleHills
|
||||||
defaultCursor: {fileID: 0}
|
defaultCursor: {fileID: 0}
|
||||||
cursorHotspot: {x: 0, y: 0}
|
cursorHotspot: {x: 0, y: 0}
|
||||||
m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1}
|
m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1}
|
||||||
@@ -142,7 +142,7 @@ PlayerSettings:
|
|||||||
loadStoreDebugModeEnabled: 0
|
loadStoreDebugModeEnabled: 0
|
||||||
visionOSBundleVersion: 1.0
|
visionOSBundleVersion: 1.0
|
||||||
tvOSBundleVersion: 1.0
|
tvOSBundleVersion: 1.0
|
||||||
bundleVersion: 1.1
|
bundleVersion: 1.0.2
|
||||||
preloadedAssets: []
|
preloadedAssets: []
|
||||||
metroInputSource: 0
|
metroInputSource: 0
|
||||||
wsaTransparentSwapchain: 0
|
wsaTransparentSwapchain: 0
|
||||||
@@ -168,7 +168,7 @@ PlayerSettings:
|
|||||||
Android: com.DefaultCompany.com.unity.template.mobile2D
|
Android: com.DefaultCompany.com.unity.template.mobile2D
|
||||||
Lumin: com.DefaultCompany.com.unity.template.mobile2D
|
Lumin: com.DefaultCompany.com.unity.template.mobile2D
|
||||||
Standalone: com.DefaultCompany.com.unity.template.mobile2D
|
Standalone: com.DefaultCompany.com.unity.template.mobile2D
|
||||||
iPhone: dk.dr.ramasjang.aeblerup
|
iPhone: com.DefaultCompany.com.unity.template.mobile2D
|
||||||
tvOS: com.DefaultCompany.com.unity.template.mobile2D
|
tvOS: com.DefaultCompany.com.unity.template.mobile2D
|
||||||
buildNumber:
|
buildNumber:
|
||||||
Standalone: 0
|
Standalone: 0
|
||||||
@@ -403,31 +403,25 @@ PlayerSettings:
|
|||||||
m_SubKind:
|
m_SubKind:
|
||||||
- m_BuildTarget: iPhone
|
- m_BuildTarget: iPhone
|
||||||
m_Icons:
|
m_Icons:
|
||||||
- m_Textures:
|
|
||||||
- {fileID: 2800000, guid: a8ae11f948f0cfa4791e954c315376ee, type: 3}
|
|
||||||
m_Width: 1024
|
|
||||||
m_Height: 1024
|
|
||||||
m_Kind: 4
|
|
||||||
m_SubKind: App Store
|
|
||||||
- m_Textures: []
|
- m_Textures: []
|
||||||
m_Width: 60
|
m_Width: 120
|
||||||
m_Height: 60
|
m_Height: 120
|
||||||
m_Kind: 2
|
m_Kind: 3
|
||||||
m_SubKind: iPhone
|
m_SubKind: iPhone
|
||||||
- m_Textures: []
|
- m_Textures: []
|
||||||
m_Width: 40
|
m_Width: 80
|
||||||
m_Height: 40
|
m_Height: 80
|
||||||
m_Kind: 2
|
m_Kind: 3
|
||||||
m_SubKind: iPhone
|
m_SubKind: iPhone
|
||||||
- m_Textures: []
|
- m_Textures: []
|
||||||
m_Width: 40
|
m_Width: 80
|
||||||
m_Height: 40
|
m_Height: 80
|
||||||
m_Kind: 2
|
m_Kind: 3
|
||||||
m_SubKind: iPad
|
m_SubKind: iPad
|
||||||
- m_Textures: []
|
- m_Textures: []
|
||||||
m_Width: 20
|
m_Width: 40
|
||||||
m_Height: 20
|
m_Height: 40
|
||||||
m_Kind: 2
|
m_Kind: 3
|
||||||
m_SubKind: iPad
|
m_SubKind: iPad
|
||||||
- m_Textures: []
|
- m_Textures: []
|
||||||
m_Width: 87
|
m_Width: 87
|
||||||
@@ -455,25 +449,30 @@ PlayerSettings:
|
|||||||
m_Kind: 1
|
m_Kind: 1
|
||||||
m_SubKind: iPad
|
m_SubKind: iPad
|
||||||
- m_Textures: []
|
- m_Textures: []
|
||||||
m_Width: 120
|
m_Width: 60
|
||||||
m_Height: 120
|
m_Height: 60
|
||||||
m_Kind: 3
|
m_Kind: 2
|
||||||
m_SubKind: iPhone
|
m_SubKind: iPhone
|
||||||
- m_Textures: []
|
|
||||||
m_Width: 80
|
|
||||||
m_Height: 80
|
|
||||||
m_Kind: 3
|
|
||||||
m_SubKind: iPhone
|
|
||||||
- m_Textures: []
|
|
||||||
m_Width: 80
|
|
||||||
m_Height: 80
|
|
||||||
m_Kind: 3
|
|
||||||
m_SubKind: iPad
|
|
||||||
- m_Textures: []
|
- m_Textures: []
|
||||||
m_Width: 40
|
m_Width: 40
|
||||||
m_Height: 40
|
m_Height: 40
|
||||||
m_Kind: 3
|
m_Kind: 2
|
||||||
|
m_SubKind: iPhone
|
||||||
|
- m_Textures: []
|
||||||
|
m_Width: 40
|
||||||
|
m_Height: 40
|
||||||
|
m_Kind: 2
|
||||||
m_SubKind: iPad
|
m_SubKind: iPad
|
||||||
|
- m_Textures: []
|
||||||
|
m_Width: 20
|
||||||
|
m_Height: 20
|
||||||
|
m_Kind: 2
|
||||||
|
m_SubKind: iPad
|
||||||
|
- m_Textures: []
|
||||||
|
m_Width: 1024
|
||||||
|
m_Height: 1024
|
||||||
|
m_Kind: 4
|
||||||
|
m_SubKind: App Store
|
||||||
- m_Textures:
|
- m_Textures:
|
||||||
- {fileID: 2800000, guid: a8ae11f948f0cfa4791e954c315376ee, type: 3}
|
- {fileID: 2800000, guid: a8ae11f948f0cfa4791e954c315376ee, type: 3}
|
||||||
m_Width: 180
|
m_Width: 180
|
||||||
@@ -508,9 +507,6 @@ PlayerSettings:
|
|||||||
- m_BuildTarget: Android
|
- m_BuildTarget: Android
|
||||||
m_StaticBatching: 1
|
m_StaticBatching: 1
|
||||||
m_DynamicBatching: 0
|
m_DynamicBatching: 0
|
||||||
- m_BuildTarget: iPhone
|
|
||||||
m_StaticBatching: 1
|
|
||||||
m_DynamicBatching: 0
|
|
||||||
m_BuildTargetShaderSettings: []
|
m_BuildTargetShaderSettings: []
|
||||||
m_BuildTargetGraphicsJobs:
|
m_BuildTargetGraphicsJobs:
|
||||||
- m_BuildTarget: MacStandaloneSupport
|
- m_BuildTarget: MacStandaloneSupport
|
||||||
@@ -840,7 +836,7 @@ PlayerSettings:
|
|||||||
webEnableSubmoduleStrippingCompatibility: 0
|
webEnableSubmoduleStrippingCompatibility: 0
|
||||||
scriptingDefineSymbols:
|
scriptingDefineSymbols:
|
||||||
Android: ENABLE_LOG
|
Android: ENABLE_LOG
|
||||||
iPhone:
|
iPhone: __UNIFIED__;__IOS__
|
||||||
additionalCompilerArguments: {}
|
additionalCompilerArguments: {}
|
||||||
platformArchitecture: {}
|
platformArchitecture: {}
|
||||||
scriptingBackend:
|
scriptingBackend:
|
||||||
|
|||||||
93
docs/managed_behavior/architecture_overview.md
Normal file
93
docs/managed_behavior/architecture_overview.md
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
# ManagedBehaviour System - Architecture Overview
|
||||||
|
|
||||||
|
**Version:** 2.0 <br>
|
||||||
|
**Updated:** 11.11.2025
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What is the ManagedBehaviour System?
|
||||||
|
|
||||||
|
Lifecycle orchestration framework that provides guaranteed execution order and deterministic lifecycle management for Unity components.
|
||||||
|
|
||||||
|
### Problems Solved
|
||||||
|
|
||||||
|
We've had quite a few things shoe-stringed together in various ways and dependant on references to each other.
|
||||||
|
Due to undefined initialization order - null references during access to yet uninitialized resources was becoming a problem.
|
||||||
|
|
||||||
|
### What You Get
|
||||||
|
|
||||||
|
- **Guaranteed Initialization Order** - Managers ready before components that depend on them
|
||||||
|
- **Deterministic Lifecycle Hooks** - Predictable callbacks at key moments
|
||||||
|
- **Automatic Registration** - No boilerplate for wiring up systems
|
||||||
|
- **Scene Lifecycle Events** - Built-in hooks for scene load/unload
|
||||||
|
- **Save/Load Coordination** - Centralized collection of save data
|
||||||
|
- **Bootstrap Integration** - Components know when bootstrap completes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture Principles
|
||||||
|
|
||||||
|
### 1. Centralized Orchestration
|
||||||
|
|
||||||
|
Single `LifecycleManager` singleton coordinates all lifecycle events. Components auto-register and receive callbacks at appropriate times.
|
||||||
|
|
||||||
|
### 2. Sealed Framework Methods
|
||||||
|
|
||||||
|
`Awake()` and `OnDestroy()` are sealed. Use `OnManagedAwake()` and `OnManagedDestroy()` instead. Prevents forgetting to call `base.Awake()`.
|
||||||
|
|
||||||
|
### 3. Two-Phase Initialization
|
||||||
|
|
||||||
|
- **Early (`OnManagedAwake()`)**: During Unity's Awake, before bootstrap. Use for singleton setup.
|
||||||
|
- **Late (`OnManagedStart()`)**: After bootstrap completes. All managers guaranteed ready.
|
||||||
|
|
||||||
|
### 4. Registration Order Execution
|
||||||
|
|
||||||
|
Execution follows Unity's natural Awake order. No priority numbers to manage.
|
||||||
|
|
||||||
|
### 5. Automatic Cleanup
|
||||||
|
|
||||||
|
Framework handles unregistration automatically. Override `OnManagedDestroy()` only if you need custom cleanup.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Lifecycle Flow Diagrams
|
||||||
|
|
||||||
|
### Boot Sequence
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Scene Transition Flow
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Component Lifecycle (Individual Component)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Class Diagram
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
## Key Guarantees
|
||||||
|
|
||||||
|
### Guaranteed
|
||||||
|
|
||||||
|
1. **Bootstrap Completion** - `OnManagedStart()` always fires after bootstrap completes
|
||||||
|
2. **Manager Availability** - All manager singletons exist when `OnManagedStart()` is called
|
||||||
|
3. **Scene Lifecycle** - `OnSceneReady()` fires after scene load, `OnSceneUnloading()` before unload
|
||||||
|
4. **Automatic Registration** - Can't forget to register (Awake is sealed)
|
||||||
|
5. **Automatic Cleanup** - Can't forget to unregister (OnDestroy is sealed)
|
||||||
|
6. **Save/Load Coordination** - All save participants called in one pass
|
||||||
|
|
||||||
|
### Not Guaranteed
|
||||||
|
|
||||||
|
1. **Initialization Order Between Components** - `OnManagedAwake()` follows Unity's unpredictable Awake order
|
||||||
|
2. **Thread Safety** - All methods must run on main thread
|
||||||
|
3. **Performance** - Broadcasting to 1000+ components may have overhead
|
||||||
|
4. **SaveId Uniqueness** - Developer responsible for unique SaveIds
|
||||||
|
|
||||||
|
|
||||||
377
docs/managed_behavior/technical_reference.md
Normal file
377
docs/managed_behavior/technical_reference.md
Normal file
@@ -0,0 +1,377 @@
|
|||||||
|
# ManagedBehaviour System - Technical Reference
|
||||||
|
|
||||||
|
**Version:** 2.0 <br>
|
||||||
|
**Updated:** 11.11.2025
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The ManagedBehaviour system provides a deterministic, ordered lifecycle management framework for Unity MonoBehaviours. This document provides complete technical documentation of all classes, methods, and APIs.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Core Classes
|
||||||
|
|
||||||
|
### ManagedBehaviour (Abstract Base Class)
|
||||||
|
|
||||||
|
**Namespace:** `Core.Lifecycle`
|
||||||
|
**Inherits:** `MonoBehaviour`
|
||||||
|
**Location:** `Assets/Scripts/Core/Lifecycle/ManagedBehaviour.cs` → [View Source](../../Assets/Scripts/Core/Lifecycle/ManagedBehaviour.cs)
|
||||||
|
|
||||||
|
Abstract base class that all managed components must inherit from. Provides automatic registration with LifecycleManager and ordered lifecycle callbacks.
|
||||||
|
|
||||||
|
#### Lifecycle Hook Methods
|
||||||
|
|
||||||
|
Override these `internal virtual` methods to customize component behavior at different lifecycle stages. Called automatically by `LifecycleManager`.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Click to see more details</summary>
|
||||||
|
|
||||||
|
##### `OnManagedAwake()`
|
||||||
|
```csharp
|
||||||
|
internal virtual void OnManagedAwake()
|
||||||
|
```
|
||||||
|
**Called:** During registration (within Unity's Awake phase)
|
||||||
|
**Execution Order:** Natural Unity script execution order (not guaranteed between components)
|
||||||
|
**Use For:**
|
||||||
|
- Setting singleton instances (`_instance = this`)
|
||||||
|
- Early GetComponent calls
|
||||||
|
- One-time initialization that doesn't depend on other systems
|
||||||
|
|
||||||
|
**Timing Guarantees:**
|
||||||
|
- ✅ GameObject and component exist
|
||||||
|
- ✅ Scene is loaded
|
||||||
|
- ❌ Other components may not be initialized yet
|
||||||
|
- ❌ Bootstrap may not be complete
|
||||||
|
|
||||||
|
##### `OnManagedStart()`
|
||||||
|
```csharp
|
||||||
|
internal virtual void OnManagedStart()
|
||||||
|
```
|
||||||
|
**Called:** After bootstrap completes (for boot components) or immediately after registration (for late-registered components)
|
||||||
|
**Execution Order:** Registration order
|
||||||
|
**Use For:**
|
||||||
|
- Initialization that depends on other managers
|
||||||
|
- Accessing singleton instances safely
|
||||||
|
- Setting up cross-system dependencies
|
||||||
|
|
||||||
|
**Timing Guarantees:**
|
||||||
|
- ✅ All managers are initialized
|
||||||
|
- ✅ Bootstrap resources are available
|
||||||
|
- ✅ Safe to access `GameManager.Instance`, `AudioManager.Instance`, etc.
|
||||||
|
|
||||||
|
##### `OnSceneUnloading()`
|
||||||
|
```csharp
|
||||||
|
internal virtual void OnSceneUnloading()
|
||||||
|
```
|
||||||
|
**Called:** Before scene unload
|
||||||
|
**Execution Order:** Registration order
|
||||||
|
**Use For:**
|
||||||
|
- Scene-specific cleanup
|
||||||
|
- Saving temporary scene state
|
||||||
|
|
||||||
|
**Timing Guarantees:**
|
||||||
|
- ✅ Scene is still loaded
|
||||||
|
- ✅ Other components in scene still exist
|
||||||
|
|
||||||
|
##### `OnSceneReady()`
|
||||||
|
```csharp
|
||||||
|
internal virtual void OnSceneReady()
|
||||||
|
```
|
||||||
|
**Called:** After scene load completes
|
||||||
|
**Execution Order:** Registration order
|
||||||
|
**Use For:**
|
||||||
|
- Scene-specific initialization
|
||||||
|
- Finding scene objects
|
||||||
|
- Setting up scene-specific state
|
||||||
|
|
||||||
|
**Timing Guarantees:**
|
||||||
|
- ✅ All scene GameObjects are loaded
|
||||||
|
- ✅ Batched components have received `OnManagedStart()`
|
||||||
|
|
||||||
|
##### `OnSceneSaveRequested()`
|
||||||
|
```csharp
|
||||||
|
internal virtual string OnSceneSaveRequested()
|
||||||
|
```
|
||||||
|
**Called:** Before scene unload during scene transitions
|
||||||
|
**Returns:** Serialized scene-specific data (JSON string), or `null` if nothing to save
|
||||||
|
**Use For:**
|
||||||
|
- Level progress
|
||||||
|
- Object positions
|
||||||
|
- Puzzle states
|
||||||
|
- Temporary scene data
|
||||||
|
|
||||||
|
**⚠️ Important:** Must return synchronously.
|
||||||
|
|
||||||
|
##### `OnSceneRestoreRequested(string serializedData)`
|
||||||
|
```csharp
|
||||||
|
internal virtual void OnSceneRestoreRequested(string serializedData)
|
||||||
|
```
|
||||||
|
**Called:** After scene load, during `OnSceneReady` phase
|
||||||
|
**Parameters:**
|
||||||
|
- `serializedData` - Previously saved data from `OnSceneSaveRequested()`
|
||||||
|
|
||||||
|
**Use For:**
|
||||||
|
- Restoring level progress
|
||||||
|
- Setting object positions
|
||||||
|
- Restoring puzzle states
|
||||||
|
|
||||||
|
**⚠️ Important:** Must execute synchronously. Do not use coroutines or async/await.
|
||||||
|
|
||||||
|
##### `OnSceneRestoreCompleted()`
|
||||||
|
```csharp
|
||||||
|
internal virtual void OnSceneRestoreCompleted()
|
||||||
|
```
|
||||||
|
**Called:** After all `OnSceneRestoreRequested()` calls complete
|
||||||
|
**Timing:** Always called after scene load, whether save data exists or not
|
||||||
|
**Use For:**
|
||||||
|
- Post-restore initialization
|
||||||
|
- First-time initialization (when no save data exists)
|
||||||
|
- Triggering events after state is restored
|
||||||
|
|
||||||
|
**Common Pattern:**
|
||||||
|
```csharp
|
||||||
|
internal override void OnSceneRestoreCompleted()
|
||||||
|
{
|
||||||
|
if (!_hasPlayed) // Check if this is first time
|
||||||
|
{
|
||||||
|
PlayIntroAudio();
|
||||||
|
_hasPlayed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### `OnGlobalSaveRequested()`
|
||||||
|
```csharp
|
||||||
|
internal virtual string OnGlobalSaveRequested()
|
||||||
|
```
|
||||||
|
**Called:** Once before save file is written to disk
|
||||||
|
**Returns:** Serialized global persistent data (JSON string), or `null`
|
||||||
|
**Use For:**
|
||||||
|
- Player inventory
|
||||||
|
- Unlocked features
|
||||||
|
- Card collections
|
||||||
|
- Persistent progression
|
||||||
|
|
||||||
|
**Timing:** Called once per game save (not per scene transition)
|
||||||
|
|
||||||
|
##### `OnGlobalRestoreRequested(string serializedData)`
|
||||||
|
```csharp
|
||||||
|
internal virtual void OnGlobalRestoreRequested(string serializedData)
|
||||||
|
```
|
||||||
|
**Called:** Once on game boot after save file is read
|
||||||
|
**Parameters:**
|
||||||
|
- `serializedData` - Previously saved data from `OnGlobalSaveRequested()`
|
||||||
|
|
||||||
|
**Use For:**
|
||||||
|
- Restoring player inventory
|
||||||
|
- Restoring unlocked features
|
||||||
|
- Restoring persistent progression
|
||||||
|
|
||||||
|
**Timing:** Called once on boot, not during scene transitions
|
||||||
|
|
||||||
|
##### `OnGlobalLoadCompleted()`
|
||||||
|
```csharp
|
||||||
|
internal virtual void OnGlobalLoadCompleted()
|
||||||
|
```
|
||||||
|
**Called:** Once on game boot after all global restore operations complete
|
||||||
|
**Use For:**
|
||||||
|
- Triggering UI updates after load
|
||||||
|
- Broadcasting load events
|
||||||
|
- Post-load initialization
|
||||||
|
|
||||||
|
##### `OnGlobalSaveStarted()`
|
||||||
|
```csharp
|
||||||
|
internal virtual void OnGlobalSaveStarted()
|
||||||
|
```
|
||||||
|
**Called:** Once before save file is written
|
||||||
|
**Use For:**
|
||||||
|
- Final validation before save
|
||||||
|
- Cleanup operations before save
|
||||||
|
|
||||||
|
##### `OnManagedDestroy()`
|
||||||
|
```csharp
|
||||||
|
internal virtual void OnManagedDestroy()
|
||||||
|
```
|
||||||
|
**Called:** During `OnDestroy`, before unregistration
|
||||||
|
**Execution Order:** Registration order
|
||||||
|
**Use For:**
|
||||||
|
- Unsubscribing from events
|
||||||
|
- Releasing resources
|
||||||
|
- Custom cleanup logic
|
||||||
|
|
||||||
|
**Note:** Most cleanup is automatic (auto-registrations are handled by framework).
|
||||||
|
</details>
|
||||||
|
|
||||||
|
#### Configuration Properties
|
||||||
|
|
||||||
|
Virtual properties that control automatic behaviors like pause registration and save system participation.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Click to see more details</summary>
|
||||||
|
|
||||||
|
##### `AutoRegisterPausable`
|
||||||
|
```csharp
|
||||||
|
public virtual bool AutoRegisterPausable => false;
|
||||||
|
```
|
||||||
|
**Type:** `bool`
|
||||||
|
**Default:** `false`
|
||||||
|
**Description:** If true and component implements `IPausable`, automatically registers with `GameManager.Instance` during initialization. Automatic unregistration occurs on destruction.
|
||||||
|
|
||||||
|
##### `AutoRegisterForSave`
|
||||||
|
```csharp
|
||||||
|
public virtual bool AutoRegisterForSave => false;
|
||||||
|
```
|
||||||
|
**Type:** `bool`
|
||||||
|
**Default:** `false`
|
||||||
|
**Description:** If true, component participates in the save/load system. Should override `OnSceneSaveRequested()` and `OnSceneRestoreRequested()` or global equivalents.
|
||||||
|
|
||||||
|
##### `SaveId`
|
||||||
|
```csharp
|
||||||
|
public virtual string SaveId { get; }
|
||||||
|
```
|
||||||
|
**Type:** `string`
|
||||||
|
**Default:** `"{SceneName}/{GameObjectName}/{ComponentType}"`
|
||||||
|
**Description:** Unique identifier for this component in the save system. Cached on first access for performance. Override for singletons (e.g., `"PlayerController"`) or custom IDs.
|
||||||
|
|
||||||
|
**⚠️ Warning:** GameObject name changes at runtime will NOT update the cached SaveId.
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### Private Lifecycle Methods
|
||||||
|
<details>
|
||||||
|
<summary>Click to see more details</summary>
|
||||||
|
|
||||||
|
##### `Awake()`
|
||||||
|
```csharp
|
||||||
|
private void Awake()
|
||||||
|
```
|
||||||
|
**Visibility:** `private` (sealed, cannot be overridden)
|
||||||
|
**Called By:** Unity
|
||||||
|
**Description:** Automatically registers component with `LifecycleManager`. Calls `OnManagedAwake()` during registration.
|
||||||
|
|
||||||
|
**⚠️ Important:** This method is sealed. Use `OnManagedAwake()` for early initialization.
|
||||||
|
|
||||||
|
##### `OnDestroy()`
|
||||||
|
```csharp
|
||||||
|
private void OnDestroy()
|
||||||
|
```
|
||||||
|
**Visibility:** `private` (sealed, cannot be overridden)
|
||||||
|
**Called By:** Unity
|
||||||
|
**Description:** Calls `OnManagedDestroy()`, unregisters from `LifecycleManager`, and handles auto-unregistrations.
|
||||||
|
|
||||||
|
**⚠️ Important:** This method is sealed. Use `OnManagedDestroy()` for custom cleanup.
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## LifecycleManager (Singleton Orchestrator)
|
||||||
|
|
||||||
|
**Namespace:** `Core.Lifecycle`
|
||||||
|
**Inherits:** `MonoBehaviour`
|
||||||
|
**Location:** `Assets/Scripts/Core/Lifecycle/LifecycleManager.cs` → [View Source](../../Assets/Scripts/Core/Lifecycle/LifecycleManager.cs)
|
||||||
|
|
||||||
|
Central orchestrator that manages all `ManagedBehaviour` components and broadcasts lifecycle events.
|
||||||
|
|
||||||
|
### Static Properties
|
||||||
|
|
||||||
|
##### `Instance`
|
||||||
|
Singleton instance. Created automatically by `CustomBoot` before bootstrap begins.
|
||||||
|
|
||||||
|
### Public Methods
|
||||||
|
|
||||||
|
Core methods for registration, lifecycle broadcasting, and save/restore operations. Most are called automatically by the framework.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Click to see more details</summary>
|
||||||
|
|
||||||
|
##### `Register(ManagedBehaviour component)`
|
||||||
|
```csharp
|
||||||
|
public void Register(ManagedBehaviour component)
|
||||||
|
```
|
||||||
|
Registers a component with the lifecycle system. **Called automatically from `ManagedBehaviour.Awake()`.**
|
||||||
|
|
||||||
|
##### `Unregister(ManagedBehaviour component)`
|
||||||
|
```csharp
|
||||||
|
public void Unregister(ManagedBehaviour component)
|
||||||
|
```
|
||||||
|
Unregisters a component. **Called automatically from `ManagedBehaviour.OnDestroy()`.**
|
||||||
|
|
||||||
|
##### `OnBootCompletionTriggered()`
|
||||||
|
```csharp
|
||||||
|
public void OnBootCompletionTriggered()
|
||||||
|
```
|
||||||
|
Called by `CustomBoot` after bootstrap completes. Broadcasts `OnManagedStart()` to all registered components.
|
||||||
|
|
||||||
|
##### `BeginSceneLoad(string sceneName)`
|
||||||
|
```csharp
|
||||||
|
public void BeginSceneLoad(string sceneName)
|
||||||
|
```
|
||||||
|
Activates scene loading batching mode. Called by `SceneManagerService` when loading a scene.
|
||||||
|
|
||||||
|
##### `BroadcastSceneReady(string sceneName)`
|
||||||
|
```csharp
|
||||||
|
public void BroadcastSceneReady(string sceneName)
|
||||||
|
```
|
||||||
|
Processes batched components and broadcasts `OnSceneReady()` to all components in the scene. Called by `SceneManagerService` after scene load.
|
||||||
|
|
||||||
|
##### `BroadcastSceneUnloading(string sceneName)`
|
||||||
|
```csharp
|
||||||
|
public void BroadcastSceneUnloading(string sceneName)
|
||||||
|
```
|
||||||
|
Broadcasts `OnSceneUnloading()` to all components in the specified scene. Called by `SceneManagerService` before scene unload.
|
||||||
|
|
||||||
|
##### `BroadcastSceneSaveRequested()`
|
||||||
|
```csharp
|
||||||
|
public Dictionary<string, string> BroadcastSceneSaveRequested()
|
||||||
|
```
|
||||||
|
Broadcasts `OnSceneSaveRequested()` to all components with `AutoRegisterForSave == true`. Returns dictionary of SaveId → serialized data.
|
||||||
|
|
||||||
|
##### `BroadcastSceneRestoreRequested(Dictionary<string, string> saveData)`
|
||||||
|
```csharp
|
||||||
|
public void BroadcastSceneRestoreRequested(Dictionary<string, string> saveData)
|
||||||
|
```
|
||||||
|
Distributes save data to components by matching `SaveId`, then broadcasts `OnSceneRestoreCompleted()`.
|
||||||
|
|
||||||
|
##### `BroadcastGlobalSaveRequested()`
|
||||||
|
```csharp
|
||||||
|
public Dictionary<string, string> BroadcastGlobalSaveRequested()
|
||||||
|
```
|
||||||
|
Broadcasts `OnGlobalSaveRequested()` to all components with `AutoRegisterForSave == true`. Returns dictionary of SaveId → serialized data.
|
||||||
|
|
||||||
|
##### `BroadcastGlobalRestoreRequested(Dictionary<string, string> saveData)`
|
||||||
|
```csharp
|
||||||
|
public void BroadcastGlobalRestoreRequested(Dictionary<string, string> saveData)
|
||||||
|
```
|
||||||
|
Distributes save data to components by matching `SaveId`, then broadcasts `OnGlobalLoadCompleted()`.
|
||||||
|
|
||||||
|
##### `BroadcastGlobalSaveStarted()`
|
||||||
|
```csharp
|
||||||
|
public void BroadcastGlobalSaveStarted()
|
||||||
|
```
|
||||||
|
Broadcasts `OnGlobalSaveStarted()` to all components with `AutoRegisterForSave == true`.
|
||||||
|
|
||||||
|
## LifecyclePhase (Enum)
|
||||||
|
|
||||||
|
**Namespace:** `Core.Lifecycle`
|
||||||
|
**Location:** `Assets/Scripts/Core/Lifecycle/LifecycleEnums.cs` → [View Source](../../Assets/Scripts/Core/Lifecycle/LifecycleEnums.cs)
|
||||||
|
|
||||||
|
Defines the different lifecycle phases for documentation and tooling purposes.
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public enum LifecyclePhase
|
||||||
|
{
|
||||||
|
ManagedAwake, // During registration (Awake)
|
||||||
|
ManagedStart, // After bootstrap or late registration
|
||||||
|
SceneUnloading, // Before scene unload
|
||||||
|
SceneReady, // After scene load
|
||||||
|
SaveRequested, // Before scene unload (save)
|
||||||
|
RestoreRequested, // After scene load (restore)
|
||||||
|
ManagedDestroy // During OnDestroy
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
522
docs/managed_behavior/use_cases_quick_start.md
Normal file
522
docs/managed_behavior/use_cases_quick_start.md
Normal file
@@ -0,0 +1,522 @@
|
|||||||
|
# ManagedBehaviour System - Quick Start & Use Cases
|
||||||
|
|
||||||
|
**TL;DR:** Inherit from `ManagedBehaviour` instead of `MonoBehaviour`. Override lifecycle hooks instead of Awake/OnDestroy. Get guaranteed initialization order and automatic registration.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
1. [Lifecycle Methods Summary](#lifecycle-methods-summary)
|
||||||
|
2. [Quick Reference - Common Use Cases](#quick-reference---common-use-cases)
|
||||||
|
3. [Getting Started Examples](#getting-started-examples)
|
||||||
|
4. [Detailed Use Cases](#detailed-use-cases)
|
||||||
|
5. [Common Patterns](#common-patterns)
|
||||||
|
6. [Migration Checklist](#migration-checklist)
|
||||||
|
7. [Troubleshooting](#troubleshooting)
|
||||||
|
8. [Best Practices](#best-practices)
|
||||||
|
9. [FAQ](#faq)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
**ManagedBehaviour in 3 Sentences:**
|
||||||
|
|
||||||
|
Inherit from `ManagedBehaviour` to get automatic lifecycle management with guaranteed initialization order. Use `OnManagedStart()` to safely access manager singletons, and use built-in save/load hooks for persistence. The framework handles registration and cleanup automatically - you just override the hooks you need.
|
||||||
|
|
||||||
|
**When to Use:**
|
||||||
|
- ✅ Singleton managers
|
||||||
|
- ✅ Components that access managers
|
||||||
|
- ✅ Components that need save/load
|
||||||
|
- ✅ Components that need scene lifecycle events
|
||||||
|
|
||||||
|
**When to Skip:**
|
||||||
|
- ❌ Simple self-contained components
|
||||||
|
- ❌ Third-party code (can't change base class)
|
||||||
|
- ❌ Performance-critical code with no dependencies
|
||||||
|
|
||||||
|
**But can I still use regular MonoBehaviour?!** <br>
|
||||||
|
_Yes!_ Only use ManagedBehaviour when you need its features (manager access, save/load, etc.)
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Lifecycle Methods Summary
|
||||||
|
|
||||||
|
1. **OnManagedAwake()** - Called during Unity's Awake phase; use for **internal setup** and GetComponent calls.
|
||||||
|
2. **OnManagedStart()** - Called after bootstrap completes; **safe to access** manager singletons.
|
||||||
|
3. **OnSceneReady()** - Called after scene finishes loading; use for scene-specific initialization.
|
||||||
|
4. **OnSceneUnloading()** - Called before scene unloads; use for scene cleanup.
|
||||||
|
5. **OnSceneSaveRequested()** - Returns serialized scene-specific data before scene transitions.
|
||||||
|
6. **OnSceneRestoreRequested(data)** - Receives saved scene data after scene loads.
|
||||||
|
7. **OnSceneRestoreCompleted()** - Called after all scene restore operations complete.
|
||||||
|
8. **OnGlobalSaveRequested()** - Returns serialized persistent data when game saves.
|
||||||
|
9. **OnGlobalRestoreRequested(data)** - Receives persistent data on game boot.
|
||||||
|
10. **OnGlobalLoadCompleted()** - Called after all global restore operations complete on boot.
|
||||||
|
11. **OnGlobalSaveStarted()** - Called before save file is written; use for pre-save validation.
|
||||||
|
12. **OnManagedDestroy()** - Called during OnDestroy; use for cleanup and event unsubscription.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Reference - Common Use Cases
|
||||||
|
|
||||||
|
### Access Manager Singleton Safely
|
||||||
|
```csharp
|
||||||
|
internal override void OnManagedStart()
|
||||||
|
{
|
||||||
|
GameManager.Instance.DoSomething(); // Safe - managers guaranteed ready
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Create Singleton Manager
|
||||||
|
```csharp
|
||||||
|
private static MyManager _instance;
|
||||||
|
public static MyManager Instance => _instance;
|
||||||
|
|
||||||
|
internal override void OnManagedAwake()
|
||||||
|
{
|
||||||
|
_instance = this;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Save Scene Progress
|
||||||
|
```csharp
|
||||||
|
public override bool AutoRegisterForSave => true;
|
||||||
|
|
||||||
|
internal override string OnSceneSaveRequested()
|
||||||
|
{
|
||||||
|
return JsonUtility.ToJson(myData);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void OnSceneRestoreRequested(string data)
|
||||||
|
{
|
||||||
|
myData = JsonUtility.FromJson<MyData>(data);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Auto-Register as Pausable
|
||||||
|
```csharp
|
||||||
|
public class MyComponent : ManagedBehaviour, IPausable
|
||||||
|
{
|
||||||
|
public override bool AutoRegisterPausable => true;
|
||||||
|
|
||||||
|
public void Pause() { /* pause logic */ }
|
||||||
|
public void Resume() { /* resume logic */ }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Scene-Specific Initialization
|
||||||
|
```csharp
|
||||||
|
internal override void OnSceneReady()
|
||||||
|
{
|
||||||
|
FindObjectsInScene();
|
||||||
|
InitializeLevel();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cleanup on Destroy
|
||||||
|
```csharp
|
||||||
|
internal override void OnManagedDestroy()
|
||||||
|
{
|
||||||
|
EventBus.OnSomething -= HandleEvent;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Getting Started Examples
|
||||||
|
|
||||||
|
### 1. Basic Component
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using Core.Lifecycle;
|
||||||
|
|
||||||
|
public class MyComponent : ManagedBehaviour
|
||||||
|
{
|
||||||
|
internal override void OnManagedAwake()
|
||||||
|
{
|
||||||
|
// Early initialization (singleton setup, GetComponent)
|
||||||
|
Debug.Log("MyComponent awakened");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void OnManagedStart()
|
||||||
|
{
|
||||||
|
// Late initialization (safe to access managers)
|
||||||
|
Debug.Log("MyComponent started - managers are ready");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Singleton Manager
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using Core.Lifecycle;
|
||||||
|
|
||||||
|
public class MyManager : ManagedBehaviour
|
||||||
|
{
|
||||||
|
private static MyManager _instance;
|
||||||
|
public static MyManager Instance => _instance;
|
||||||
|
|
||||||
|
internal override void OnManagedAwake()
|
||||||
|
{
|
||||||
|
_instance = this; // Set singleton early
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void OnManagedStart()
|
||||||
|
{
|
||||||
|
// All other managers are ready here
|
||||||
|
AudioManager.Instance.PlaySound("ManagerReady");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Component with Save/Load
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using Core.Lifecycle;
|
||||||
|
|
||||||
|
public class PuzzleComponent : ManagedBehaviour
|
||||||
|
{
|
||||||
|
public override bool AutoRegisterForSave => true;
|
||||||
|
public override string SaveId => "MyPuzzle"; // Custom ID
|
||||||
|
|
||||||
|
private bool _isSolved;
|
||||||
|
|
||||||
|
internal override string OnSceneSaveRequested()
|
||||||
|
{
|
||||||
|
return JsonUtility.ToJson(new { isSolved = _isSolved });
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void OnSceneRestoreRequested(string data)
|
||||||
|
{
|
||||||
|
var saveData = JsonUtility.FromJson<SaveData>(data);
|
||||||
|
_isSolved = saveData.isSolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
[System.Serializable]
|
||||||
|
private class SaveData
|
||||||
|
{
|
||||||
|
public bool isSolved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Component with Cleanup
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using Core.Lifecycle;
|
||||||
|
|
||||||
|
public class EventSubscriber : ManagedBehaviour
|
||||||
|
{
|
||||||
|
internal override void OnManagedStart()
|
||||||
|
{
|
||||||
|
GameManager.Instance.OnGamePaused += HandlePause;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void OnManagedDestroy()
|
||||||
|
{
|
||||||
|
// Automatic cleanup
|
||||||
|
if (GameManager.Instance != null)
|
||||||
|
GameManager.Instance.OnGamePaused -= HandlePause;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandlePause() { }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Detailed Use Cases
|
||||||
|
|
||||||
|
### Use Case 1: Accessing Singleton Managers Safely
|
||||||
|
|
||||||
|
**Problem:** Accessing `GameManager.Instance` in `Awake()` might fail if GameManager hasn't initialized yet.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
```csharp
|
||||||
|
public class Player : ManagedBehaviour
|
||||||
|
{
|
||||||
|
// ❌ DON'T: Risky in OnManagedAwake (managers may not be ready)
|
||||||
|
internal override void OnManagedAwake()
|
||||||
|
{
|
||||||
|
// var settings = GameManager.Instance.GetSettings(); // RISKY!
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ DO: Safe in OnManagedStart (managers guaranteed ready)
|
||||||
|
internal override void OnManagedStart()
|
||||||
|
{
|
||||||
|
var settings = GameManager.Instance.GetSettings(); // SAFE!
|
||||||
|
ApplySettings(settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Use Case 2: Scene-Specific Initialization
|
||||||
|
|
||||||
|
**Problem:** Need to initialize something after a scene finishes loading.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
```csharp
|
||||||
|
public class LevelManager : ManagedBehaviour
|
||||||
|
{
|
||||||
|
internal override void OnSceneReady()
|
||||||
|
{
|
||||||
|
// Scene is fully loaded, all objects exist
|
||||||
|
FindObjectiveMarkers();
|
||||||
|
SpawnEnemies();
|
||||||
|
PlayLevelMusic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Use Case 3: Saving Player Progress
|
||||||
|
|
||||||
|
**Problem:** Need to save level progress when transitioning between scenes.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
```csharp
|
||||||
|
public class LevelProgress : ManagedBehaviour
|
||||||
|
{
|
||||||
|
public override bool AutoRegisterForSave => true;
|
||||||
|
public override string SaveId => "LevelProgress";
|
||||||
|
|
||||||
|
private int _checkpointIndex;
|
||||||
|
private float _timeElapsed;
|
||||||
|
|
||||||
|
internal override string OnSceneSaveRequested()
|
||||||
|
{
|
||||||
|
return JsonUtility.ToJson(new
|
||||||
|
{
|
||||||
|
checkpoint = _checkpointIndex,
|
||||||
|
time = _timeElapsed
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void OnSceneRestoreRequested(string data)
|
||||||
|
{
|
||||||
|
var save = JsonUtility.FromJson<SaveData>(data);
|
||||||
|
_checkpointIndex = save.checkpoint;
|
||||||
|
_timeElapsed = save.time;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void OnSceneRestoreCompleted()
|
||||||
|
{
|
||||||
|
// Restore complete, trigger UI update
|
||||||
|
UpdateProgressUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Use Case 4: Global Persistent Data (Inventory)
|
||||||
|
|
||||||
|
**Problem:** Need to save player inventory across all scenes.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
```csharp
|
||||||
|
public class InventoryManager : ManagedBehaviour
|
||||||
|
{
|
||||||
|
public override bool AutoRegisterForSave => true;
|
||||||
|
public override string SaveId => "Inventory";
|
||||||
|
|
||||||
|
private List<string> _items = new List<string>();
|
||||||
|
|
||||||
|
internal override string OnGlobalSaveRequested()
|
||||||
|
{
|
||||||
|
// Save to global save file (not scene-specific)
|
||||||
|
return JsonUtility.ToJson(new { items = _items });
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void OnGlobalRestoreRequested(string data)
|
||||||
|
{
|
||||||
|
// Restore from global save file on boot
|
||||||
|
var save = JsonUtility.FromJson<SaveData>(data);
|
||||||
|
_items = new List<string>(save.items);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void OnGlobalLoadCompleted()
|
||||||
|
{
|
||||||
|
// All global data loaded, safe to initialize UI
|
||||||
|
RefreshInventoryUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Use Case 5: Auto-Registering as Pausable
|
||||||
|
|
||||||
|
**Problem:** Component implements `IPausable` and needs to register with `GameManager`.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
```csharp
|
||||||
|
public class AnimatedCharacter : ManagedBehaviour, IPausable
|
||||||
|
{
|
||||||
|
public override bool AutoRegisterPausable => true;
|
||||||
|
|
||||||
|
// IPausable implementation
|
||||||
|
public void Pause()
|
||||||
|
{
|
||||||
|
// Pause animations
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Resume()
|
||||||
|
{
|
||||||
|
// Resume animations
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// No manual registration needed - automatic!
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Use Case 6: Scene Cleanup
|
||||||
|
|
||||||
|
**Problem:** Need to clean up scene-specific state before transitioning.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
```csharp
|
||||||
|
public class ParticleSpawner : ManagedBehaviour
|
||||||
|
{
|
||||||
|
private List<GameObject> _activeParticles = new List<GameObject>();
|
||||||
|
|
||||||
|
internal override void OnSceneUnloading()
|
||||||
|
{
|
||||||
|
// Clean up before scene unloads
|
||||||
|
foreach (var particle in _activeParticles)
|
||||||
|
{
|
||||||
|
if (particle != null)
|
||||||
|
Destroy(particle);
|
||||||
|
}
|
||||||
|
_activeParticles.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Use Case 7: First-Time vs Restored State
|
||||||
|
|
||||||
|
**Problem:** Need to play intro animation only on first visit, not when restoring from save.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
```csharp
|
||||||
|
public class LevelIntro : ManagedBehaviour
|
||||||
|
{
|
||||||
|
public override bool AutoRegisterForSave => true;
|
||||||
|
|
||||||
|
private bool _hasPlayedIntro;
|
||||||
|
|
||||||
|
internal override string OnSceneSaveRequested()
|
||||||
|
{
|
||||||
|
return JsonUtility.ToJson(new { hasPlayed = _hasPlayedIntro });
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void OnSceneRestoreRequested(string data)
|
||||||
|
{
|
||||||
|
var save = JsonUtility.FromJson<SaveData>(data);
|
||||||
|
_hasPlayedIntro = save.hasPlayed;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void OnSceneRestoreCompleted()
|
||||||
|
{
|
||||||
|
// This fires whether we restored or not
|
||||||
|
if (!_hasPlayedIntro)
|
||||||
|
{
|
||||||
|
PlayIntroAnimation();
|
||||||
|
_hasPlayedIntro = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
## Common Patterns
|
||||||
|
|
||||||
|
### Pattern: Manager Singleton
|
||||||
|
```csharp
|
||||||
|
public class MyManager : ManagedBehaviour
|
||||||
|
{
|
||||||
|
private static MyManager _instance;
|
||||||
|
public static MyManager Instance => _instance;
|
||||||
|
|
||||||
|
internal override void OnManagedAwake()
|
||||||
|
{
|
||||||
|
_instance = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern: Event Subscription
|
||||||
|
```csharp
|
||||||
|
internal override void OnManagedStart()
|
||||||
|
{
|
||||||
|
EventBus.OnSomething += HandleEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void OnManagedDestroy()
|
||||||
|
{
|
||||||
|
EventBus.OnSomething -= HandleEvent;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern: Save/Restore
|
||||||
|
```csharp
|
||||||
|
public override bool AutoRegisterForSave => true;
|
||||||
|
|
||||||
|
internal override string OnSceneSaveRequested()
|
||||||
|
{
|
||||||
|
return JsonUtility.ToJson(myData);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void OnSceneRestoreRequested(string data)
|
||||||
|
{
|
||||||
|
myData = JsonUtility.FromJson<MyData>(data);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pattern: Custom SaveId
|
||||||
|
```csharp
|
||||||
|
// For singletons or special cases
|
||||||
|
public override string SaveId => "PlayerInventory";
|
||||||
|
|
||||||
|
// For scene-specific instances
|
||||||
|
public override string SaveId => $"{gameObject.scene.name}/MySpecialObject";
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### "NullReferenceException when accessing Manager.Instance"
|
||||||
|
**Problem:** Accessing singleton in `OnManagedAwake()`
|
||||||
|
**Solution:** Move to `OnManagedStart()` where managers are guaranteed ready
|
||||||
|
|
||||||
|
### "My SaveId is colliding with another component"
|
||||||
|
**Problem:** Two components have same GameObject name and type
|
||||||
|
**Solution:** Override `SaveId` property with unique value
|
||||||
|
|
||||||
|
### "My component isn't receiving lifecycle callbacks"
|
||||||
|
**Problem:** Not inheriting from `ManagedBehaviour`
|
||||||
|
**Solution:** Ensure class inherits `ManagedBehaviour` (not plain `MonoBehaviour`)
|
||||||
|
|
||||||
|
### "Save data isn't persisting"
|
||||||
|
**Problem:** `AutoRegisterForSave` is false
|
||||||
|
**Solution:** Set `public override bool AutoRegisterForSave => true;`
|
||||||
|
|
||||||
|
### "OnSceneRestoreCompleted isn't firing"
|
||||||
|
**Problem:** Missing implementation
|
||||||
|
**Solution:** Override the method even if just logging for now
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Quick Links:**
|
||||||
|
- [Technical Reference](01_technical_reference.md) - Complete API documentation
|
||||||
|
- [Architecture Overview](02_architecture_overview.md) - System design and principles
|
||||||
|
|
||||||
|
|
||||||
BIN
docs/media/Scene_transition_flow.png
Normal file
BIN
docs/media/Scene_transition_flow.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 287 KiB |
BIN
docs/media/boot_sequence.png
Normal file
BIN
docs/media/boot_sequence.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 239 KiB |
BIN
docs/media/class_diagram.png
Normal file
BIN
docs/media/class_diagram.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 252 KiB |
BIN
docs/media/component_lifecycle.png
Normal file
BIN
docs/media/component_lifecycle.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 219 KiB |
Reference in New Issue
Block a user