Merge branch 'main' into DamianCardStyles

This commit is contained in:
2025-10-28 09:51:42 +00:00
52 changed files with 1229 additions and 105 deletions

View File

@@ -0,0 +1,63 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!850595691 &4890085278179872738
LightingSettings:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: AppleHillsLightingSettings
serializedVersion: 9
m_EnableBakedLightmaps: 0
m_EnableRealtimeLightmaps: 0
m_RealtimeEnvironmentLighting: 1
m_BounceScale: 1
m_AlbedoBoost: 1
m_IndirectOutputScale: 1
m_UsingShadowmask: 1
m_BakeBackend: 1
m_LightmapMaxSize: 1024
m_LightmapSizeFixed: 0
m_UseMipmapLimits: 1
m_BakeResolution: 40
m_Padding: 2
m_LightmapCompression: 3
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAO: 0
m_MixedBakeMode: 2
m_LightmapsBakeMode: 1
m_FilterMode: 1
m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0}
m_ExportTrainingData: 0
m_EnableWorkerProcessBaking: 1
m_TrainingDataDestination: TrainingData
m_RealtimeResolution: 2
m_ForceWhiteAlbedo: 0
m_ForceUpdates: 0
m_PVRCulling: 1
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 512
m_PVREnvironmentSampleCount: 256
m_PVREnvironmentReferencePointCount: 2048
m_LightProbeSampleCountMultiplier: 4
m_PVRBounces: 2
m_PVRMinBounces: 2
m_PVREnvironmentImportanceSampling: 1
m_PVRFilteringMode: 1
m_PVRDenoiserTypeDirect: 1
m_PVRDenoiserTypeIndirect: 1
m_PVRDenoiserTypeAO: 1
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 1
m_PVRFilteringGaussRadiusAO: 1
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_RespectSceneVisibilityWhenBakingGI: 0

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d13be91f5840cb447b407875cd9bbefc
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 4890085278179872738
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -22,7 +22,7 @@ MonoBehaviour:
m_RequireDepthTexture: 0 m_RequireDepthTexture: 0
m_RequireOpaqueTexture: 0 m_RequireOpaqueTexture: 0
m_OpaqueDownsampling: 1 m_OpaqueDownsampling: 1
m_SupportsTerrainHoles: 1 m_SupportsTerrainHoles: 0
m_SupportsHDR: 0 m_SupportsHDR: 0
m_HDRColorBufferPrecision: 0 m_HDRColorBufferPrecision: 0
m_MSAA: 1 m_MSAA: 1
@@ -44,7 +44,7 @@ MonoBehaviour:
m_MainLightRenderingMode: 0 m_MainLightRenderingMode: 0
m_MainLightShadowsSupported: 0 m_MainLightShadowsSupported: 0
m_MainLightShadowmapResolution: 2048 m_MainLightShadowmapResolution: 2048
m_AdditionalLightsRenderingMode: 1 m_AdditionalLightsRenderingMode: 0
m_AdditionalLightsPerObjectLimit: 4 m_AdditionalLightsPerObjectLimit: 4
m_AdditionalLightShadowsSupported: 0 m_AdditionalLightShadowsSupported: 0
m_AdditionalLightsShadowmapResolution: 2048 m_AdditionalLightsShadowmapResolution: 2048
@@ -71,8 +71,8 @@ MonoBehaviour:
m_AdditionalLightsCookieFormat: 3 m_AdditionalLightsCookieFormat: 3
m_UseSRPBatcher: 1 m_UseSRPBatcher: 1
m_SupportsDynamicBatching: 0 m_SupportsDynamicBatching: 0
m_MixedLightingSupported: 1 m_MixedLightingSupported: 0
m_SupportsLightCookies: 1 m_SupportsLightCookies: 0
m_SupportsLightLayers: 0 m_SupportsLightLayers: 0
m_DebugLevel: 0 m_DebugLevel: 0
m_StoreActionsOptimization: 0 m_StoreActionsOptimization: 0
@@ -91,7 +91,7 @@ MonoBehaviour:
m_LocalShadowsAtlasResolution: 256 m_LocalShadowsAtlasResolution: 256
m_MaxPixelLights: 0 m_MaxPixelLights: 0
m_ShadowAtlasResolution: 256 m_ShadowAtlasResolution: 256
m_VolumeFrameworkUpdateMode: 0 m_VolumeFrameworkUpdateMode: 1
m_VolumeProfile: {fileID: 0} m_VolumeProfile: {fileID: 0}
apvScenesData: apvScenesData:
obsoleteSceneBounds: obsoleteSceneBounds:

View File

@@ -53,6 +53,6 @@ MonoBehaviour:
m_CameraSortingLayerDownsamplingMethod: 0 m_CameraSortingLayerDownsamplingMethod: 0
m_MaxLightRenderTextureCount: 16 m_MaxLightRenderTextureCount: 16
m_MaxShadowRenderTextureCount: 1 m_MaxShadowRenderTextureCount: 1
m_PostProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2} m_PostProcessData: {fileID: 0}
m_DefaultMaterialType: 0 m_DefaultMaterialType: 1
m_DefaultCustomMaterial: {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2} m_DefaultCustomMaterial: {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2}

View File

@@ -288,7 +288,7 @@ AnimationClip:
m_AdditiveReferencePoseClip: {fileID: 0} m_AdditiveReferencePoseClip: {fileID: 0}
m_AdditiveReferencePoseTime: 0 m_AdditiveReferencePoseTime: 0
m_StartTime: 0 m_StartTime: 0
m_StopTime: 2.3999999 m_StopTime: 2.4
m_OrientationOffsetY: 0 m_OrientationOffsetY: 0
m_Level: 0 m_Level: 0
m_CycleOffset: 0 m_CycleOffset: 0
@@ -370,4 +370,11 @@ AnimationClip:
m_EulerEditorCurves: [] m_EulerEditorCurves: []
m_HasGenericRootTransform: 0 m_HasGenericRootTransform: 0
m_HasMotionFloatCurves: 0 m_HasMotionFloatCurves: 0
m_Events: [] m_Events:
- time: 2.4
functionName: OnStationaryAnimationComplete
data:
objectReferenceParameter: {fileID: 0}
floatParameter: 0
intParameter: 0
messageOptions: 0

View File

@@ -336,4 +336,11 @@ AnimationClip:
m_EulerEditorCurves: [] m_EulerEditorCurves: []
m_HasGenericRootTransform: 0 m_HasGenericRootTransform: 0
m_HasMotionFloatCurves: 0 m_HasMotionFloatCurves: 0
m_Events: [] m_Events:
- time: 1.6666666
functionName: OnStationaryAnimationComplete
data:
objectReferenceParameter: {fileID: 0}
floatParameter: 0
intParameter: 0
messageOptions: 0

View File

@@ -26,3 +26,4 @@ MonoBehaviour:
- {fileID: 3528960956969533010, guid: 53eea3840d3cde34a9768b8773a3a7e8, type: 3} - {fileID: 3528960956969533010, guid: 53eea3840d3cde34a9768b8773a3a7e8, type: 3}
- {fileID: 6895404274863911569, guid: 840f3d8a936b39a41b5896328a692005, type: 3} - {fileID: 6895404274863911569, guid: 840f3d8a936b39a41b5896328a692005, type: 3}
- {fileID: 3863019143023165617, guid: 774e30e3f0b1d0d49bad0c2abf11038a, type: 3} - {fileID: 3863019143023165617, guid: 774e30e3f0b1d0d49bad0c2abf11038a, type: 3}
- {fileID: 5034240524438268576, guid: b15ba9d3d508ef244b0eeb76404dc9de, type: 3}

View File

@@ -307,6 +307,7 @@ MonoBehaviour:
- LoopThroughIncorrectItemLines - LoopThroughIncorrectItemLines
- ForbiddenItemDialogueContent - ForbiddenItemDialogueContent
- LoopThroughForbiddenItemLines - LoopThroughForbiddenItemLines
- ShouldAutoPlay
m_ValueList: m_ValueList:
- rid: 4008004961314799713 - rid: 4008004961314799713
- rid: 4008004961314799714 - rid: 4008004961314799714
@@ -321,6 +322,7 @@ MonoBehaviour:
- rid: 4008004961314799723 - rid: 4008004961314799723
- rid: 4008004961314799724 - rid: 4008004961314799724
- rid: 4008004961314799725 - rid: 4008004961314799725
- rid: 7545630068434796544
m_InputPortInfos: m_InputPortInfos:
expandedPortsById: expandedPortsById:
m_KeyList: [] m_KeyList: []
@@ -525,3 +527,7 @@ MonoBehaviour:
- rid: 4008004961314799729 - rid: 4008004961314799729
type: {class: EndNode, ns: Editor.Dialogue, asm: AppleHillsEditor} type: {class: EndNode, ns: Editor.Dialogue, asm: AppleHillsEditor}
data: data:
- rid: 7545630068434796544
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: Unity.GraphToolkit.Internal.Editor}
data:
m_Value: 1

View File

@@ -168,6 +168,7 @@ MonoBehaviour:
- LoopThroughIncorrectItemLines - LoopThroughIncorrectItemLines
- ForbiddenItemDialogueContent - ForbiddenItemDialogueContent
- LoopThroughForbiddenItemLines - LoopThroughForbiddenItemLines
- ShouldAutoPlay
m_ValueList: m_ValueList:
- rid: 4008004961314799803 - rid: 4008004961314799803
- rid: 4008004961314799804 - rid: 4008004961314799804
@@ -182,6 +183,7 @@ MonoBehaviour:
- rid: 4008004961314799813 - rid: 4008004961314799813
- rid: 4008004961314799814 - rid: 4008004961314799814
- rid: 4008004961314799815 - rid: 4008004961314799815
- rid: 7545630068434796549
m_InputPortInfos: m_InputPortInfos:
expandedPortsById: expandedPortsById:
m_KeyList: [] m_KeyList: []
@@ -525,3 +527,7 @@ MonoBehaviour:
type: {class: 'Constant`1[[System.String, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: Unity.GraphToolkit.Internal.Editor} type: {class: 'Constant`1[[System.String, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: Unity.GraphToolkit.Internal.Editor}
data: data:
m_Value: AnneLise m_Value: AnneLise
- rid: 7545630068434796549
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: Unity.GraphToolkit.Internal.Editor}
data:
m_Value: 0

View File

@@ -168,6 +168,7 @@ MonoBehaviour:
- LoopThroughIncorrectItemLines - LoopThroughIncorrectItemLines
- ForbiddenItemDialogueContent - ForbiddenItemDialogueContent
- LoopThroughForbiddenItemLines - LoopThroughForbiddenItemLines
- ShouldAutoPlay
m_ValueList: m_ValueList:
- rid: 4008004961314799847 - rid: 4008004961314799847
- rid: 4008004961314799848 - rid: 4008004961314799848
@@ -182,6 +183,7 @@ MonoBehaviour:
- rid: 4008004961314799857 - rid: 4008004961314799857
- rid: 4008004961314799858 - rid: 4008004961314799858
- rid: 4008004961314799859 - rid: 4008004961314799859
- rid: 7545630068434796550
m_InputPortInfos: m_InputPortInfos:
expandedPortsById: expandedPortsById:
m_KeyList: [] m_KeyList: []
@@ -525,3 +527,7 @@ MonoBehaviour:
type: {class: 'Constant`1[[System.String, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: Unity.GraphToolkit.Internal.Editor} type: {class: 'Constant`1[[System.String, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: Unity.GraphToolkit.Internal.Editor}
data: data:
m_Value: AnneLise m_Value: AnneLise
- rid: 7545630068434796550
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: Unity.GraphToolkit.Internal.Editor}
data:
m_Value: 0

View File

@@ -168,6 +168,7 @@ MonoBehaviour:
- LoopThroughIncorrectItemLines - LoopThroughIncorrectItemLines
- ForbiddenItemDialogueContent - ForbiddenItemDialogueContent
- LoopThroughForbiddenItemLines - LoopThroughForbiddenItemLines
- ShouldAutoPlay
m_ValueList: m_ValueList:
- rid: 4008004961314799891 - rid: 4008004961314799891
- rid: 4008004961314799892 - rid: 4008004961314799892
@@ -182,6 +183,7 @@ MonoBehaviour:
- rid: 4008004961314799901 - rid: 4008004961314799901
- rid: 4008004961314799902 - rid: 4008004961314799902
- rid: 4008004961314799903 - rid: 4008004961314799903
- rid: 7545630068434796545
m_InputPortInfos: m_InputPortInfos:
expandedPortsById: expandedPortsById:
m_KeyList: [] m_KeyList: []
@@ -525,3 +527,7 @@ MonoBehaviour:
type: {class: 'Constant`1[[System.String, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: Unity.GraphToolkit.Internal.Editor} type: {class: 'Constant`1[[System.String, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: Unity.GraphToolkit.Internal.Editor}
data: data:
m_Value: AnneLise m_Value: AnneLise
- rid: 7545630068434796545
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: Unity.GraphToolkit.Internal.Editor}
data:
m_Value: 0

View File

@@ -42,12 +42,14 @@ MonoBehaviour:
- RequiredPuzzleStep - RequiredPuzzleStep
- DefaultDialogueContent - DefaultDialogueContent
- LoopThroughDefaultLines - LoopThroughDefaultLines
- ShouldAutoPlay
m_ValueList: m_ValueList:
- rid: 4008004961314799759 - rid: 4008004961314799759
- rid: 4008004961314799760 - rid: 4008004961314799760
- rid: 4008004961314799761 - rid: 4008004961314799761
- rid: 4008004961314799762 - rid: 4008004961314799762
- rid: 4008004961314799763 - rid: 4008004961314799763
- rid: 7545630068434796551
m_InputPortInfos: m_InputPortInfos:
expandedPortsById: expandedPortsById:
m_KeyList: [] m_KeyList: []
@@ -169,6 +171,10 @@ MonoBehaviour:
_text: _text:
_image: {fileID: 1487011052474782424, guid: f489e2c9ce64ff34aa3c7a91a4edbd77, type: 3} _image: {fileID: 1487011052474782424, guid: f489e2c9ce64ff34aa3c7a91a4edbd77, type: 3}
_audio: {fileID: 8300000, guid: b4ba973891dad4749b465e9a07987e1a, type: 3} _audio: {fileID: 8300000, guid: b4ba973891dad4749b465e9a07987e1a, type: 3}
- rid: 7545630068434796551
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: Unity.GraphToolkit.Internal.Editor}
data:
m_Value: 0
- rid: 7772910664224079994 - rid: 7772910664224079994
type: {class: GraphModelImp, ns: Unity.GraphToolkit.Editor.Implementation, asm: Unity.GraphToolkit.Editor} type: {class: GraphModelImp, ns: Unity.GraphToolkit.Editor.Implementation, asm: Unity.GraphToolkit.Editor}
data: data:

View File

@@ -487,6 +487,7 @@ MonoBehaviour:
- DefaultDialogueContent1 - DefaultDialogueContent1
- DefaultDialogueContent2 - DefaultDialogueContent2
- DefaultDialogueContent3 - DefaultDialogueContent3
- ShouldAutoPlay
m_ValueList: m_ValueList:
- rid: 1226592702090707084 - rid: 1226592702090707084
- rid: 1226592702090707085 - rid: 1226592702090707085
@@ -495,6 +496,7 @@ MonoBehaviour:
- rid: 7545629632211976304 - rid: 7545629632211976304
- rid: 7545629632211976305 - rid: 7545629632211976305
- rid: 7545629632211976306 - rid: 7545629632211976306
- rid: 7545630068434796546
m_InputPortInfos: m_InputPortInfos:
expandedPortsById: expandedPortsById:
m_KeyList: [] m_KeyList: []
@@ -689,12 +691,14 @@ MonoBehaviour:
- RequiredResultItem - RequiredResultItem
- LoopThroughDefaultLines - LoopThroughDefaultLines
- DefaultDialogueContent - DefaultDialogueContent
- ShouldAutoPlay
m_ValueList: m_ValueList:
- rid: 1226592736610877524 - rid: 1226592736610877524
- rid: 1226592736610877525 - rid: 1226592736610877525
- rid: 1226592736610877526 - rid: 1226592736610877526
- rid: 1226592736610877528 - rid: 1226592736610877528
- rid: 7545629632211976309 - rid: 7545629632211976309
- rid: 7545630068434796547
m_InputPortInfos: m_InputPortInfos:
expandedPortsById: expandedPortsById:
m_KeyList: [] m_KeyList: []
@@ -895,6 +899,7 @@ MonoBehaviour:
- DefaultDialogueContent - DefaultDialogueContent
- IncorrectItemDialogueContent - IncorrectItemDialogueContent
- ForbiddenItemDialogueContent - ForbiddenItemDialogueContent
- ShouldAutoPlay
m_ValueList: m_ValueList:
- rid: 1226592736610877547 - rid: 1226592736610877547
- rid: 1226592736610877548 - rid: 1226592736610877548
@@ -909,6 +914,7 @@ MonoBehaviour:
- rid: 7545629632211976311 - rid: 7545629632211976311
- rid: 7545629632211976312 - rid: 7545629632211976312
- rid: 7545629632211976313 - rid: 7545629632211976313
- rid: 7545630068434796548
m_InputPortInfos: m_InputPortInfos:
expandedPortsById: expandedPortsById:
m_KeyList: [] m_KeyList: []
@@ -1212,3 +1218,15 @@ MonoBehaviour:
_text: Yessssss, thanks! _text: Yessssss, thanks!
_image: {fileID: 0} _image: {fileID: 0}
_audio: {fileID: 0} _audio: {fileID: 0}
- rid: 7545630068434796546
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: Unity.GraphToolkit.Internal.Editor}
data:
m_Value: 0
- rid: 7545630068434796547
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: Unity.GraphToolkit.Internal.Editor}
data:
m_Value: 0
- rid: 7545630068434796548
type: {class: 'Constant`1[[System.Boolean, mscorlib]]', ns: Unity.GraphToolkit.Editor, asm: Unity.GraphToolkit.Internal.Editor}
data:
m_Value: 0

View File

@@ -164,6 +164,8 @@ namespace Editor.Dialogue
{ {
runtimeNode.puzzleStepID = puzzleStep.stepId; runtimeNode.puzzleStepID = puzzleStep.stepId;
} }
runtimeNode.shouldAutoPlay = GetPortValue<bool>(node.GetInputPortByName("ShouldAutoPlay"));
} }
private void ProcessPickupNode(WaitOnPickup node, RuntimeDialogueNode runtimeNode) private void ProcessPickupNode(WaitOnPickup node, RuntimeDialogueNode runtimeNode)
@@ -175,6 +177,8 @@ namespace Editor.Dialogue
{ {
runtimeNode.pickupItemID = pickup.itemId; runtimeNode.pickupItemID = pickup.itemId;
} }
runtimeNode.shouldAutoPlay = GetPortValue<bool>(node.GetInputPortByName("ShouldAutoPlay"));
} }
private void ProcessSlotNode(WaitOnSlot node, RuntimeDialogueNode runtimeNode) private void ProcessSlotNode(WaitOnSlot node, RuntimeDialogueNode runtimeNode)
@@ -187,6 +191,8 @@ namespace Editor.Dialogue
runtimeNode.slotItemID = slot.itemId; runtimeNode.slotItemID = slot.itemId;
} }
runtimeNode.shouldAutoPlay = GetPortValue<bool>(node.GetInputPortByName("ShouldAutoPlay"));
// Get line type and count options for incorrect items // Get line type and count options for incorrect items
var incorrectItemLineTypeOption = node.GetNodeOptionByName("IncorrectItemDialogueLineType"); var incorrectItemLineTypeOption = node.GetNodeOptionByName("IncorrectItemDialogueLineType");
incorrectItemLineTypeOption.TryGetValue<DialogueType>(out var incorrectItemLineType); incorrectItemLineTypeOption.TryGetValue<DialogueType>(out var incorrectItemLineType);
@@ -296,6 +302,8 @@ namespace Editor.Dialogue
{ {
runtimeNode.combinationResultItemID = resultItem.itemId; runtimeNode.combinationResultItemID = resultItem.itemId;
} }
runtimeNode.shouldAutoPlay = GetPortValue<bool>(node.GetInputPortByName("ShouldAutoPlay"));
} }
private T GetPortValue<T>(IPort port) private T GetPortValue<T>(IPort port)

View File

@@ -90,10 +90,12 @@ namespace Editor.Dialogue
public class WaitOnPuzzleStep : DialogueNode public class WaitOnPuzzleStep : DialogueNode
{ {
const string RequiredPuzzleStep = "RequiredPuzzleStep"; const string RequiredPuzzleStep = "RequiredPuzzleStep";
const string ShouldAutoPlayOptionName = "ShouldAutoPlay";
protected override void OnDefinePorts(IPortDefinitionContext context) protected override void OnDefinePorts(IPortDefinitionContext context)
{ {
context.AddInputPort<PuzzleStepSO>(RequiredPuzzleStep).WithDisplayName("Required Puzzle Step").Build(); context.AddInputPort<PuzzleStepSO>(RequiredPuzzleStep).WithDisplayName("Required Puzzle Step").Build();
context.AddInputPort<bool>(ShouldAutoPlayOptionName).WithDisplayName("Should Auto-Play?").Build();
base.OnDefinePorts(context); base.OnDefinePorts(context);
} }
@@ -103,10 +105,12 @@ namespace Editor.Dialogue
public class WaitOnPickup : DialogueNode public class WaitOnPickup : DialogueNode
{ {
const string RequiredPickupsOptionName = "RequiredPickup"; const string RequiredPickupsOptionName = "RequiredPickup";
const string ShouldAutoPlayOptionName = "ShouldAutoPlay";
protected override void OnDefinePorts(IPortDefinitionContext context) protected override void OnDefinePorts(IPortDefinitionContext context)
{ {
context.AddInputPort<PickupItemData>(RequiredPickupsOptionName).WithDisplayName("Required Pickup").Build(); context.AddInputPort<PickupItemData>(RequiredPickupsOptionName).WithDisplayName("Required Pickup").Build();
context.AddInputPort<bool>(ShouldAutoPlayOptionName).WithDisplayName("Should Auto-Play?").Build();
base.OnDefinePorts(context); base.OnDefinePorts(context);
} }
@@ -116,6 +120,7 @@ namespace Editor.Dialogue
public class WaitOnSlot : DialogueNode public class WaitOnSlot : DialogueNode
{ {
const string RequiredSlotOptionName = "RequiredSlot"; const string RequiredSlotOptionName = "RequiredSlot";
const string ShouldAutoPlayOptionName = "ShouldAutoPlay";
const string IncorrectItemLineTypeOptionName = "IncorrectItemDialogueLineType"; const string IncorrectItemLineTypeOptionName = "IncorrectItemDialogueLineType";
const string IncorrectItemNoLinesOptionName = "IncorrectItemNoLines"; const string IncorrectItemNoLinesOptionName = "IncorrectItemNoLines";
const string LoopThroughIncorrectItemLinesOptionName = "LoopThroughIncorrectItemLines"; const string LoopThroughIncorrectItemLinesOptionName = "LoopThroughIncorrectItemLines";
@@ -156,6 +161,7 @@ namespace Editor.Dialogue
protected override void OnDefinePorts(IPortDefinitionContext context) protected override void OnDefinePorts(IPortDefinitionContext context)
{ {
context.AddInputPort<PickupItemData>(RequiredSlotOptionName).WithDisplayName("Required Slot").Build(); context.AddInputPort<PickupItemData>(RequiredSlotOptionName).WithDisplayName("Required Slot").Build();
context.AddInputPort<bool>(ShouldAutoPlayOptionName).WithDisplayName("Should Auto-Play?").Build();
base.OnDefinePorts(context); base.OnDefinePorts(context);
@@ -219,10 +225,12 @@ namespace Editor.Dialogue
public class WaitOnCombination : DialogueNode public class WaitOnCombination : DialogueNode
{ {
const string RequiredResultItemOptionName = "RequiredResultItem"; const string RequiredResultItemOptionName = "RequiredResultItem";
const string ShouldAutoPlayOptionName = "ShouldAutoPlay";
protected override void OnDefinePorts(IPortDefinitionContext context) protected override void OnDefinePorts(IPortDefinitionContext context)
{ {
context.AddInputPort<PickupItemData>(RequiredResultItemOptionName).WithDisplayName("Required Result Item").Build(); context.AddInputPort<PickupItemData>(RequiredResultItemOptionName).WithDisplayName("Required Result Item").Build();
context.AddInputPort<bool>(ShouldAutoPlayOptionName).WithDisplayName("Should Auto-Play?").Build();
base.OnDefinePorts(context); base.OnDefinePorts(context);
} }

View File

@@ -0,0 +1,63 @@
using System.IO;
using UnityEditor;
using UnityEngine;
namespace Editor.Tools
{
/// <summary>
/// Editor utility to clear all save data from the SaveLoadManager's save folder
/// </summary>
public static class ClearSavesMenuItem
{
[MenuItem("AppleHills/Clear Saves")]
private static void ClearSaves()
{
// Construct the save folder path (matches SaveLoadManager.DefaultSaveFolder)
string saveFolder = Path.Combine(Application.persistentDataPath, "GameSaves");
if (!Directory.Exists(saveFolder))
{
Debug.Log($"[ClearSaves] Save folder does not exist: {saveFolder}");
EditorUtility.DisplayDialog("Clear Saves", "No save data found to clear.", "OK");
return;
}
// Confirm with the user
bool confirmed = EditorUtility.DisplayDialog(
"Clear Saves",
$"Are you sure you want to delete all save data?\n\nFolder: {saveFolder}",
"Delete All",
"Cancel"
);
if (!confirmed)
{
Debug.Log("[ClearSaves] User cancelled save deletion");
return;
}
try
{
// Delete all files in the save folder
string[] files = Directory.GetFiles(saveFolder);
int deletedCount = 0;
foreach (string file in files)
{
File.Delete(file);
deletedCount++;
Debug.Log($"[ClearSaves] Deleted: {file}");
}
Debug.Log($"[ClearSaves] Successfully deleted {deletedCount} save file(s)");
EditorUtility.DisplayDialog("Clear Saves", $"Successfully deleted {deletedCount} save file(s).", "OK");
}
catch (System.Exception ex)
{
Debug.LogError($"[ClearSaves] Failed to clear saves: {ex}");
EditorUtility.DisplayDialog("Clear Saves", $"Error clearing saves:\n{ex.Message}", "OK");
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 747ab9e66b014771bc1486f9ab073f90
timeCreated: 1761569785

View File

@@ -62,19 +62,28 @@ public class SceneBrowserWindow : EditorWindow
if (GUILayout.Button("Refresh")) if (GUILayout.Button("Refresh"))
RefreshScenes(); RefreshScenes();
_scroll = EditorGUILayout.BeginScrollView(_scroll); _scroll = EditorGUILayout.BeginScrollView(_scroll);
// Create a safe copy to avoid collection modification during enumeration
var foldersCopy = _scenesByFolder.Keys.ToList();
// Top-level scenes // Top-level scenes
if (_scenesByFolder.ContainsKey("")) if (foldersCopy.Contains("") && _scenesByFolder.ContainsKey(""))
{ {
foreach (var scene in _scenesByFolder[""]) var topLevelScenes = _scenesByFolder[""].ToList();
foreach (var scene in topLevelScenes)
DrawSceneRow(scene); DrawSceneRow(scene);
EditorGUILayout.Space(); EditorGUILayout.Space();
} }
// Subfolders // Subfolders
foreach (var kvp in _scenesByFolder) foreach (var folderKey in foldersCopy)
{ {
if (string.IsNullOrEmpty(kvp.Key)) continue; if (string.IsNullOrEmpty(folderKey)) continue;
EditorGUILayout.LabelField(kvp.Key, EditorStyles.boldLabel); if (!_scenesByFolder.ContainsKey(folderKey)) continue;
foreach (var scene in kvp.Value)
EditorGUILayout.LabelField(folderKey, EditorStyles.boldLabel);
var scenesInFolder = _scenesByFolder[folderKey].ToList();
foreach (var scene in scenesInFolder)
DrawSceneRow(scene); DrawSceneRow(scene);
EditorGUILayout.Space(); EditorGUILayout.Space();
} }

View File

@@ -12,6 +12,22 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: fde0d25a170598d46a0b9dc16b4527a5, type: 3} m_Script: {fileID: 11500000, guid: fde0d25a170598d46a0b9dc16b4527a5, type: 3}
m_Name: ActivationPlayableAsset m_Name: ActivationPlayableAsset
m_EditorClassIdentifier: Unity.Timeline::UnityEngine.Timeline.ActivationPlayableAsset m_EditorClassIdentifier: Unity.Timeline::UnityEngine.Timeline.ActivationPlayableAsset
--- !u!114 &-7800811525781169865
MonoBehaviour:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 15c38f6fa1940124db1ab7f6fe7268d1, type: 3}
m_Name: Signal Emitter
m_EditorClassIdentifier: Unity.Timeline::UnityEngine.Timeline.SignalEmitter
m_Time: 0
m_Retroactive: 0
m_EmitOnce: 0
m_Asset: {fileID: 11400000, guid: 2a32e2abdb44cb1469e5c6b9a25f98bc, type: 2}
--- !u!114 &-7584736085941489071 --- !u!114 &-7584736085941489071
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 1 m_ObjectHideFlags: 1
@@ -139,6 +155,22 @@ MonoBehaviour:
m_bufferingTime: 0.1 m_bufferingTime: 0.1
m_ClipProperties: m_ClipProperties:
volume: 0.683 volume: 0.683
--- !u!114 &-5035745444053599677
MonoBehaviour:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 15c38f6fa1940124db1ab7f6fe7268d1, type: 3}
m_Name: Signal Emitter
m_EditorClassIdentifier: Unity.Timeline::UnityEngine.Timeline.SignalEmitter
m_Time: 1.65
m_Retroactive: 0
m_EmitOnce: 0
m_Asset: {fileID: 11400000, guid: 2ec36cde76b6baf4299c0dd9ab54714e, type: 2}
--- !u!114 &-4664548104421960294 --- !u!114 &-4664548104421960294
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 1 m_ObjectHideFlags: 1
@@ -491,12 +523,13 @@ MonoBehaviour:
- {fileID: 5194333105783184030} - {fileID: 5194333105783184030}
- {fileID: 8484886637748558501} - {fileID: 8484886637748558501}
- {fileID: 8776627858148209300} - {fileID: 8776627858148209300}
- {fileID: 6964431640287062015}
m_FixedDuration: 0 m_FixedDuration: 0
m_EditorSettings: m_EditorSettings:
m_Framerate: 60 m_Framerate: 60
m_ScenePreview: 1 m_ScenePreview: 1
m_DurationMode: 0 m_DurationMode: 0
m_MarkerTrack: {fileID: 0} m_MarkerTrack: {fileID: 7948415667162652308}
--- !u!114 &297111036028248502 --- !u!114 &297111036028248502
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 1 m_ObjectHideFlags: 1
@@ -746,6 +779,54 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: fde0d25a170598d46a0b9dc16b4527a5, type: 3} m_Script: {fileID: 11500000, guid: fde0d25a170598d46a0b9dc16b4527a5, type: 3}
m_Name: ActivationPlayableAsset m_Name: ActivationPlayableAsset
m_EditorClassIdentifier: Unity.Timeline::UnityEngine.Timeline.ActivationPlayableAsset m_EditorClassIdentifier: Unity.Timeline::UnityEngine.Timeline.ActivationPlayableAsset
--- !u!114 &6964431640287062015
MonoBehaviour:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: b46e36075dd1c124a8422c228e75e1fb, type: 3}
m_Name: Signal Track
m_EditorClassIdentifier: Unity.Timeline::UnityEngine.Timeline.SignalTrack
m_Version: 3
m_AnimClip: {fileID: 0}
m_Locked: 0
m_Muted: 0
m_CustomPlayableFullTypename:
m_Curves: {fileID: 0}
m_Parent: {fileID: 11400000}
m_Children: []
m_Clips: []
m_Markers:
m_Objects:
- {fileID: -7800811525781169865}
- {fileID: -5035745444053599677}
--- !u!114 &7948415667162652308
MonoBehaviour:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 2a16748d9461eae46a725db9776d5390, type: 3}
m_Name: Markers
m_EditorClassIdentifier: Unity.Timeline::UnityEngine.Timeline.MarkerTrack
m_Version: 3
m_AnimClip: {fileID: 0}
m_Locked: 0
m_Muted: 0
m_CustomPlayableFullTypename:
m_Curves: {fileID: 0}
m_Parent: {fileID: 11400000}
m_Children: []
m_Clips: []
m_Markers:
m_Objects: []
--- !u!114 &8484886637748558501 --- !u!114 &8484886637748558501
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 1 m_ObjectHideFlags: 1

View File

@@ -14,6 +14,7 @@ GameObject:
- component: {fileID: 8947209170748834035} - component: {fileID: 8947209170748834035}
- component: {fileID: 7852204877518954380} - component: {fileID: 7852204877518954380}
- component: {fileID: 1621671461027776358} - component: {fileID: 1621671461027776358}
- component: {fileID: 7002695641417196458}
m_Layer: 8 m_Layer: 8
m_Name: PulverCharacter m_Name: PulverCharacter
m_TagString: Pulver m_TagString: Pulver
@@ -184,6 +185,51 @@ MonoBehaviour:
bezierTangentLength: 0.4 bezierTangentLength: 0.4
offset: 0.2 offset: 0.2
factor: 0.1 factor: 0.1
--- !u!114 &7002695641417196458
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1102400833121127473}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e52de21a22b6dd44c9cc19f810c65059, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.Timeline::UnityEngine.Timeline.SignalReceiver
m_Events:
m_Signals:
- {fileID: 11400000, guid: 2a32e2abdb44cb1469e5c6b9a25f98bc, type: 2}
- {fileID: 11400000, guid: 2ec36cde76b6baf4299c0dd9ab54714e, type: 2}
m_Events:
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 3435632802124758411}
m_TargetAssemblyTypeName: FollowerController, AppleHillsScripts
m_MethodName: PauseMovement
m_Mode: 1
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
- m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 3435632802124758411}
m_TargetAssemblyTypeName: FollowerController, AppleHillsScripts
m_MethodName: ResumeMovement
m_Mode: 1
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
--- !u!1 &5934518940303293264 --- !u!1 &5934518940303293264
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -338,8 +384,29 @@ PrefabInstance:
- {fileID: 2732140975288177209, guid: e3b439d398cffdd4194cdb360a46c5a6, type: 3} - {fileID: 2732140975288177209, guid: e3b439d398cffdd4194cdb360a46c5a6, type: 3}
m_RemovedGameObjects: [] m_RemovedGameObjects: []
m_AddedGameObjects: [] m_AddedGameObjects: []
m_AddedComponents: [] m_AddedComponents:
- targetCorrespondingSourceObject: {fileID: 1102468210854536367, guid: e3b439d398cffdd4194cdb360a46c5a6, type: 3}
insertIndex: -1
addedObject: {fileID: 3454096590710680423}
m_SourcePrefab: {fileID: 100100000, guid: e3b439d398cffdd4194cdb360a46c5a6, type: 3} m_SourcePrefab: {fileID: 100100000, guid: e3b439d398cffdd4194cdb360a46c5a6, type: 3}
--- !u!1 &780600094299918916 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 1102468210854536367, guid: e3b439d398cffdd4194cdb360a46c5a6, type: 3}
m_PrefabInstance: {fileID: 403634400421951211}
m_PrefabAsset: {fileID: 0}
--- !u!114 &3454096590710680423
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 780600094299918916}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 39f2e64420884f11a9022fea7b3be5d0, type: 3}
m_Name:
m_EditorClassIdentifier: AppleHillsScripts::FollowerAnimationEventBridge
followerController: {fileID: 3435632802124758411}
--- !u!4 &6418503932309983819 stripped --- !u!4 &6418503932309983819 stripped
Transform: Transform:
m_CorrespondingSourceObject: {fileID: 6668392923879433376, guid: e3b439d398cffdd4194cdb360a46c5a6, type: 3} m_CorrespondingSourceObject: {fileID: 6668392923879433376, guid: e3b439d398cffdd4194cdb360a46c5a6, type: 3}

View File

@@ -0,0 +1,48 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &5034240524438268576
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 536416456044738252}
- component: {fileID: 6631817730171642502}
m_Layer: 0
m_Name: SaveLoadManager
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &536416456044738252
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5034240524438268576}
serializedVersion: 2
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: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &6631817730171642502
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5034240524438268576}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a1731f4790be4ec3bab71506427768d7, type: 3}
m_Name:
m_EditorClassIdentifier: AppleHillsScripts::Core.SaveLoad.SaveLoadManager
currentSaveData:
playedDivingTutorial: 0

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b15ba9d3d508ef244b0eeb76404dc9de
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -466228,6 +466228,17 @@ PrefabInstance:
m_AddedGameObjects: [] m_AddedGameObjects: []
m_AddedComponents: [] m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 0bbded61e58193848ac59c8eea761bcc, type: 3} m_SourcePrefab: {fileID: 100100000, guid: 0bbded61e58193848ac59c8eea761bcc, type: 3}
--- !u!114 &1760588396 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 7002695641417196458, guid: 8ac0210dbf9d7754e9526d6d5c214f49, type: 3}
m_PrefabInstance: {fileID: 1363194738}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e52de21a22b6dd44c9cc19f810c65059, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.Timeline::UnityEngine.Timeline.SignalReceiver
--- !u!1 &1761890788 --- !u!1 &1761890788
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -477381,7 +477392,7 @@ PrefabInstance:
objectReference: {fileID: 11400000, guid: 1791fd5a24a3142418ed441a2a25b374, type: 2} objectReference: {fileID: 11400000, guid: 1791fd5a24a3142418ed441a2a25b374, type: 2}
- target: {fileID: 1569498917964935965, guid: c36b48a324dcaef4cb5ee0f8ca57f0d6, type: 3} - target: {fileID: 1569498917964935965, guid: c36b48a324dcaef4cb5ee0f8ca57f0d6, type: 3}
propertyPath: m_SceneBindings.Array.size propertyPath: m_SceneBindings.Array.size
value: 13 value: 14
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 1569498917964935965, guid: c36b48a324dcaef4cb5ee0f8ca57f0d6, type: 3} - target: {fileID: 1569498917964935965, guid: c36b48a324dcaef4cb5ee0f8ca57f0d6, type: 3}
propertyPath: m_SceneBindings.Array.data[3].key propertyPath: m_SceneBindings.Array.data[3].key
@@ -477423,6 +477434,10 @@ PrefabInstance:
propertyPath: m_SceneBindings.Array.data[12].key propertyPath: m_SceneBindings.Array.data[12].key
value: value:
objectReference: {fileID: 8776627858148209300, guid: 1791fd5a24a3142418ed441a2a25b374, type: 2} objectReference: {fileID: 8776627858148209300, guid: 1791fd5a24a3142418ed441a2a25b374, type: 2}
- target: {fileID: 1569498917964935965, guid: c36b48a324dcaef4cb5ee0f8ca57f0d6, type: 3}
propertyPath: m_SceneBindings.Array.data[13].key
value:
objectReference: {fileID: 6964431640287062015, guid: 1791fd5a24a3142418ed441a2a25b374, type: 2}
- target: {fileID: 1569498917964935965, guid: c36b48a324dcaef4cb5ee0f8ca57f0d6, type: 3} - target: {fileID: 1569498917964935965, guid: c36b48a324dcaef4cb5ee0f8ca57f0d6, type: 3}
propertyPath: m_SceneBindings.Array.data[0].value propertyPath: m_SceneBindings.Array.data[0].value
value: value:
@@ -477467,6 +477482,10 @@ PrefabInstance:
propertyPath: m_SceneBindings.Array.data[12].value propertyPath: m_SceneBindings.Array.data[12].value
value: value:
objectReference: {fileID: 781815198} objectReference: {fileID: 781815198}
- target: {fileID: 1569498917964935965, guid: c36b48a324dcaef4cb5ee0f8ca57f0d6, type: 3}
propertyPath: m_SceneBindings.Array.data[13].value
value:
objectReference: {fileID: 1760588396}
- target: {fileID: 2084964592986606867, guid: c36b48a324dcaef4cb5ee0f8ca57f0d6, type: 3} - target: {fileID: 2084964592986606867, guid: c36b48a324dcaef4cb5ee0f8ca57f0d6, type: 3}
propertyPath: m_LocalPosition.y propertyPath: m_LocalPosition.y
value: 1.68 value: 1.68

View File

@@ -202,7 +202,7 @@ namespace AppleHillsCamera
private void FindCameraAdapter() private void FindCameraAdapter()
{ {
// Try to find the camera adapter in the scene // Try to find the camera adapter in the scene
var adapters = FindObjectsOfType<CameraScreenAdapter>(); var adapters = FindObjectsByType<CameraScreenAdapter>(FindObjectsSortMode.None);
if (adapters != null && adapters.Length > 0) if (adapters != null && adapters.Length > 0)
{ {
// Prioritize any adapter that's on the same camera we're using // Prioritize any adapter that's on the same camera we're using

View File

@@ -123,8 +123,12 @@ namespace Core
/// <param name="shouldPause">True to pause; false to resume</param> /// <param name="shouldPause">True to pause; false to resume</param>
private void ApplyPause(bool shouldPause) private void ApplyPause(bool shouldPause)
{ {
// TODO: Do we want to stop time? // Only affect timescale if debug setting allows it
// Time.timeScale = shouldPause ? 0f : 1f; var debugSettings = GetDeveloperSettings<DebugSettings>();
if (debugSettings != null && debugSettings.PauseTimeOnPauseGame)
{
Time.timeScale = shouldPause ? 0f : 1f;
}
// Notify registered components // Notify registered components
foreach (var component in _pausableComponents) foreach (var component in _pausableComponents)
@@ -213,8 +217,9 @@ namespace Core
// Load developer settings // Load developer settings
var divingDevSettings = DeveloperSettingsProvider.Instance.GetSettings<DivingDeveloperSettings>(); var divingDevSettings = DeveloperSettingsProvider.Instance.GetSettings<DivingDeveloperSettings>();
var debugSettings = DeveloperSettingsProvider.Instance.GetSettings<DebugSettings>();
_developerSettingsLoaded = divingDevSettings != null; _developerSettingsLoaded = divingDevSettings != null && debugSettings != null;
if (_developerSettingsLoaded) if (_developerSettingsLoaded)
{ {

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0541e0e1c3dd41f7a61773e4bc2c64ed
timeCreated: 1761553949

View File

@@ -0,0 +1,29 @@
using System.Collections.Generic;
namespace Core.SaveLoad
{
[System.Serializable]
public class SaveLoadData
{
public bool playedDivingTutorial = false;
// Snapshot of the player's card collection (MVP)
public CardCollectionState cardCollection;
}
// Minimal DTOs for card persistence
[System.Serializable]
public class CardCollectionState
{
public int boosterPackCount;
public List<SavedCardEntry> cards = new List<SavedCardEntry>();
}
[System.Serializable]
public class SavedCardEntry
{
public string definitionId;
public AppleHills.Data.CardSystem.CardRarity rarity;
public int copiesOwned;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1704f1fc7e6b4a398f39fb86cec265f8
timeCreated: 1761553972

View File

@@ -0,0 +1,238 @@
using System;
using System.Collections;
using System.IO;
using Bootstrap;
using UnityEngine;
namespace Core.SaveLoad
{
/// <summary>
/// Simple Save/Load manager that follows the project's bootstrap pattern.
/// - Singleton instance
/// - Registers a post-boot init action with BootCompletionService
/// - Exposes simple async Save/Load methods (PlayerPrefs-backed placeholder)
/// - Fires events on completion
/// This is intended as boilerplate to be expanded with a real serialization backend.
/// </summary>
public class SaveLoadManager : MonoBehaviour
{
private static SaveLoadManager _instance;
public static SaveLoadManager Instance => _instance;
// Path
private static string DefaultSaveFolder => Path.Combine(Application.persistentDataPath, "GameSaves");
public SaveLoadData currentSaveData;
// State
public bool IsSaving { get; private set; }
public bool IsLoading { get; private set; }
public bool IsSaveDataLoaded { get; private set; }
// Events
public event Action<string> OnSaveCompleted;
public event Action<string> OnLoadCompleted;
void Awake()
{
_instance = this;
IsSaveDataLoaded = false;
BootCompletionService.RegisterInitAction(InitializePostBoot);
}
private void Start()
{
Load();
}
private void OnApplicationQuit()
{
Save();
}
private void InitializePostBoot()
{
Logging.Debug("[SaveLoadManager] Post-boot initialization complete");
}
void OnDestroy()
{
if (_instance == this)
_instance = null;
}
private string GetFilePath(string slot)
{
return Path.Combine(DefaultSaveFolder, $"save_{slot}.json");
}
/// <summary>
/// Entry point to save to a named slot. Starts an async coroutine that writes to PlayerPrefs
/// (placeholder behavior). Fires OnSaveCompleted when finished.
/// </summary>
public void Save(string slot = "default")
{
if (IsSaving)
{
Logging.Warning("[SaveLoadManager] Save called while another save is in progress");
return;
}
StartCoroutine(SaveAsync(slot));
}
/// <summary>
/// Entry point to load from a named slot. Starts an async coroutine that reads from PlayerPrefs
/// (placeholder behavior). Fires OnLoadCompleted when finished.
/// </summary>
public void Load(string slot = "default")
{
if (IsLoading)
{
Logging.Warning("[SaveLoadManager] Load called while another load is in progress");
return;
}
StartCoroutine(LoadAsync(slot));
}
// TODO: This is stupid overkill, but over verbose logging is king for now
private IEnumerator SaveAsync(string slot)
{
Logging.Debug($"[SaveLoadManager] Starting save for slot '{slot}'");
IsSaving = true;
string path = GetFilePath(slot);
string tempPath = path + ".tmp";
string json = null;
bool prepFailed = false;
// Prep phase: ensure folder exists and serialize (no yields allowed inside try/catch)
try
{
Directory.CreateDirectory(DefaultSaveFolder);
if (currentSaveData == null)
{
Logging.Debug("[SaveLoadManager] currentSaveData is null, creating default instance before saving");
currentSaveData = new SaveLoadData();
}
// Pull latest card collection snapshot from CardSystem before serializing (don't overwrite with null)
if (Data.CardSystem.CardSystemManager.Instance != null)
{
currentSaveData.cardCollection = Data.CardSystem.CardSystemManager.Instance.ExportCardCollectionState();
}
json = JsonUtility.ToJson(currentSaveData, true);
}
catch (Exception ex)
{
Logging.Warning($"[SaveLoadManager] Exception during save prep for slot '{slot}': {ex}");
prepFailed = true;
}
if (prepFailed || string.IsNullOrEmpty(json))
{
// Ensure we clean up state and notify listeners outside of the try/catch
IsSaving = false;
OnSaveCompleted?.Invoke(slot);
Logging.Warning($"[SaveLoadManager] Aborting save for slot '{slot}' due to prep failure");
yield break;
}
// Write phase: perform IO and atomic move with fallback
try
{
File.WriteAllText(tempPath, json);
try
{
if (File.Exists(path))
File.Delete(path);
File.Move(tempPath, path);
}
catch (Exception moveEx)
{
Logging.Warning($"[SaveLoadManager] Atomic move failed for '{path}', attempting overwrite: {moveEx}");
File.Copy(tempPath, path, true);
File.Delete(tempPath);
}
Logging.Debug($"[SaveLoadManager] Save data written to '{path}'");
}
catch (Exception ex)
{
Logging.Warning($"[SaveLoadManager] Exception while saving slot '{slot}': {ex}");
}
finally
{
IsSaving = false;
OnSaveCompleted?.Invoke(slot);
Debug.Log($"[SaveLoadManager] Save completed for slot '{slot}'");
}
}
// TODO: This is stupid overkill, but over verbose logging is king for now
private IEnumerator LoadAsync(string slot)
{
Logging.Debug($"[SaveLoadManager] Starting load for slot '{slot}'");
IsLoading = true;
string path = GetFilePath(slot);
// Fast-path: no save file
if (!File.Exists(path))
{
Logging.Debug($"[SaveLoadManager] No save found at '{path}', creating defaults");
currentSaveData = new SaveLoadData();
// Simulate async operation and finish
yield return null;
IsLoading = false;
IsSaveDataLoaded = true;
OnLoadCompleted?.Invoke(slot);
yield break;
}
// Simulate async operation (optional)
yield return null;
try
{
string json = File.ReadAllText(path);
if (string.IsNullOrEmpty(json))
{
Logging.Warning($"[SaveLoadManager] Save file at '{path}' is empty. Creating defaults.");
currentSaveData = new SaveLoadData();
}
else
{
// Attempt to deserialize; if it fails or returns null, fall back to defaults
var loaded = JsonUtility.FromJson<SaveLoadData>(json);
if (loaded == null)
{
Logging.Warning($"[SaveLoadManager] Deserialized save data was null for slot '{slot}'. Creating defaults.");
currentSaveData = new SaveLoadData();
}
else
{
currentSaveData = loaded;
}
}
}
catch (Exception ex)
{
Logging.Warning($"[SaveLoadManager] Exception while reading/deserializing save file at '{path}': {ex}");
currentSaveData = new SaveLoadData();
}
finally
{
IsLoading = false;
IsSaveDataLoaded = true;
OnLoadCompleted?.Invoke(slot);
Logging.Debug($"[SaveLoadManager] Load completed for slot '{slot}'");
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a1731f4790be4ec3bab71506427768d7
timeCreated: 1761553854

View File

@@ -25,8 +25,13 @@ namespace AppleHills.Core.Settings
[Tooltip("Should debug messages be show on screen in Editor")] [Tooltip("Should debug messages be show on screen in Editor")]
[SerializeField] private bool showDebugUiMessages = false; [SerializeField] private bool showDebugUiMessages = false;
[Header("Game Behavior Options")]
[Tooltip("Should Time.timeScale be set to 0 when the game is paused")]
[SerializeField] private bool pauseTimeOnPauseGame = true;
// Property getters // Property getters
public bool ShowDebugUiMessages => showDebugUiMessages; public bool ShowDebugUiMessages => showDebugUiMessages;
public bool PauseTimeOnPauseGame => pauseTimeOnPauseGame;
public override void OnValidate() public override void OnValidate()
{ {

View File

@@ -4,6 +4,7 @@ using System.Linq;
using AppleHills.Data.CardSystem; using AppleHills.Data.CardSystem;
using Bootstrap; using Bootstrap;
using Core; using Core;
using Core.SaveLoad;
using UnityEngine; using UnityEngine;
#if UNITY_EDITOR #if UNITY_EDITOR
using UnityEditor; using UnityEditor;
@@ -36,6 +37,9 @@ namespace Data.CardSystem
public event Action<CardData> OnCardRarityUpgraded; public event Action<CardData> OnCardRarityUpgraded;
public event Action<int> OnBoosterCountChanged; public event Action<int> OnBoosterCountChanged;
// Keep a reference to unsubscribe safely
private Action<string> _onSaveDataLoadedHandler;
private void Awake() private void Awake()
{ {
_instance = this; _instance = this;
@@ -49,9 +53,6 @@ namespace Data.CardSystem
// Load card definitions from Addressables // Load card definitions from Addressables
LoadCardDefinitionsFromAddressables(); LoadCardDefinitionsFromAddressables();
// Build lookup dictionary
BuildDefinitionLookup();
Logging.Debug("[CardSystemManager] Post-boot initialization complete"); Logging.Debug("[CardSystemManager] Post-boot initialization complete");
} }
@@ -87,9 +88,54 @@ namespace Data.CardSystem
} }
} }
} }
// Build lookup now that cards are loaded
BuildDefinitionLookup();
// Apply saved state when save data is available
if (SaveLoadManager.Instance != null)
{
if (SaveLoadManager.Instance.IsSaveDataLoaded)
{
ApplySavedCardStateIfAvailable();
}
else
{
SaveLoadManager.Instance.OnLoadCompleted += OnSaveDataLoadedHandler;
}
}
} }
} }
private void OnDestroy()
{
if (SaveLoadManager.Instance != null)
{
SaveLoadManager.Instance.OnLoadCompleted -= OnSaveDataLoadedHandler;
}
}
// Apply saved state if present in the SaveLoadManager
private void ApplySavedCardStateIfAvailable()
{
var data = SaveLoadManager.Instance?.currentSaveData;
if (data?.cardCollection != null)
{
ApplyCardCollectionState(data.cardCollection);
Logging.Debug("[CardSystemManager] Applied saved card collection state after loading definitions");
}
}
// Event handler for when save data load completes
private void OnSaveDataLoadedHandler(string slot)
{
ApplySavedCardStateIfAvailable();
if (SaveLoadManager.Instance != null)
{
SaveLoadManager.Instance.OnLoadCompleted -= OnSaveDataLoadedHandler;
}
}
/// <summary> /// <summary>
/// Builds a lookup dictionary for quick access to card definitions by ID /// Builds a lookup dictionary for quick access to card definitions by ID
/// </summary> /// </summary>
@@ -383,5 +429,58 @@ namespace Data.CardSystem
return (float)collectedOfRarity / totalOfRarity * 100f; return (float)collectedOfRarity / totalOfRarity * 100f;
} }
/// <summary>
/// Export current card collection to a serializable snapshot
/// </summary>
public CardCollectionState ExportCardCollectionState()
{
var state = new CardCollectionState
{
boosterPackCount = playerInventory.BoosterPackCount,
cards = new List<SavedCardEntry>()
};
foreach (var card in playerInventory.CollectedCards.Values)
{
if (string.IsNullOrEmpty(card.DefinitionId)) continue;
state.cards.Add(new SavedCardEntry
{
definitionId = card.DefinitionId,
rarity = card.Rarity,
copiesOwned = card.CopiesOwned
});
}
return state;
}
/// <summary>
/// Apply a previously saved snapshot to the runtime inventory
/// </summary>
public void ApplyCardCollectionState(CardCollectionState state)
{
if (state == null) return;
playerInventory.ClearAllCards();
playerInventory.BoosterPackCount = state.boosterPackCount;
OnBoosterCountChanged?.Invoke(playerInventory.BoosterPackCount);
foreach (var entry in state.cards)
{
if (string.IsNullOrEmpty(entry.definitionId)) continue;
if (_definitionLookup.TryGetValue(entry.definitionId, out var def))
{
// Create from definition to ensure links, then overwrite runtime fields
var cd = def.CreateCardData();
cd.Rarity = entry.rarity;
cd.CopiesOwned = entry.copiesOwned;
playerInventory.AddCard(cd);
}
else
{
Logging.Warning($"[CardSystemManager] Saved card definition not found: {entry.definitionId}");
}
}
}
} }
} }

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using Bootstrap;
using Core; using Core;
using Interactions; using Interactions;
using UnityEngine; using UnityEngine;
@@ -46,23 +47,6 @@ namespace Dialogue
Debug.LogError("SpeechBubble component is missing on Dialogue Component"); Debug.LogError("SpeechBubble component is missing on Dialogue Component");
} }
// Register for global events
if (PuzzleManager.Instance != null)
PuzzleManager.Instance.OnStepCompleted += OnAnyPuzzleStepCompleted;
if (ItemManager.Instance != null)
{
ItemManager.Instance.OnItemPickedUp += OnAnyItemPickedUp;
ItemManager.Instance.OnCorrectItemSlotted += OnAnyItemSlotted;
ItemManager.Instance.OnIncorrectItemSlotted += OnAnyIncorrectItemSlotted;
ItemManager.Instance.OnForbiddenItemSlotted += OnAnyForbiddenItemSlotted;
ItemManager.Instance.OnItemSlotCleared += OnAnyItemSlotCleared;
ItemManager.Instance.OnItemsCombined += OnAnyItemsCombined;
}
// Auto-start the dialogue
// StartDialogue();
var interactable = GetComponent<Interactable>(); var interactable = GetComponent<Interactable>();
if (interactable != null) if (interactable != null)
{ {
@@ -74,6 +58,20 @@ namespace Dialogue
{ {
speechBubble.UpdatePromptVisibility(HasAnyLines()); speechBubble.UpdatePromptVisibility(HasAnyLines());
} }
BootCompletionService.RegisterInitAction(InitializePostBoot);
}
private void InitializePostBoot()
{
// Register for global events
PuzzleManager.Instance.OnStepCompleted += OnAnyPuzzleStepCompleted;
ItemManager.Instance.OnItemPickedUp += OnAnyItemPickedUp;
ItemManager.Instance.OnCorrectItemSlotted += OnAnyItemSlotted;
ItemManager.Instance.OnIncorrectItemSlotted += OnAnyIncorrectItemSlotted;
ItemManager.Instance.OnForbiddenItemSlotted += OnAnyForbiddenItemSlotted;
ItemManager.Instance.OnItemSlotCleared += OnAnyItemSlotCleared;
ItemManager.Instance.OnItemsCombined += OnAnyItemsCombined;
} }
private void OnCharacterArrived() private void OnCharacterArrived()
@@ -457,6 +455,12 @@ namespace Dialogue
// Global event handlers // Global event handlers
private void OnAnyPuzzleStepCompleted(PuzzleStepSO step) private void OnAnyPuzzleStepCompleted(PuzzleStepSO step)
{ {
// Initialize if needed
if (!initialized)
{
StartDialogue();
}
// Only react if we're active and waiting on a puzzle step // Only react if we're active and waiting on a puzzle step
if (!IsActive || IsCompleted || currentNode == null || if (!IsActive || IsCompleted || currentNode == null ||
currentNode.nodeType != RuntimeDialogueNodeType.WaitOnPuzzleStep) currentNode.nodeType != RuntimeDialogueNodeType.WaitOnPuzzleStep)
@@ -465,19 +469,21 @@ namespace Dialogue
// Check if this is the step we're waiting for // Check if this is the step we're waiting for
if (step.stepId == currentNode.puzzleStepID) if (step.stepId == currentNode.puzzleStepID)
{ {
// Instead of immediately moving to the next node, set the flag // Set the flag that condition is satisfied
_conditionSatisfiedPendingAdvance = true; _conditionSatisfiedPendingAdvance = true;
// Update bubble visibility after state change to show interaction prompt UpdateDialogueVisibilityOnItemEvent();
if (speechBubble != null)
{
speechBubble.UpdatePromptVisibility(HasAnyLines());
}
} }
} }
private void OnAnyItemPickedUp(PickupItemData item) private void OnAnyItemPickedUp(PickupItemData item)
{ {
// Initialize if needed
if (!initialized)
{
StartDialogue();
}
// Only react if we're active and waiting on an item pickup // Only react if we're active and waiting on an item pickup
if (!IsActive || IsCompleted || currentNode == null || if (!IsActive || IsCompleted || currentNode == null ||
currentNode.nodeType != RuntimeDialogueNodeType.WaitOnPickup) currentNode.nodeType != RuntimeDialogueNodeType.WaitOnPickup)
@@ -486,14 +492,10 @@ namespace Dialogue
// Check if this is the item we're waiting for // Check if this is the item we're waiting for
if (item.itemId == currentNode.pickupItemID) if (item.itemId == currentNode.pickupItemID)
{ {
// Instead of immediately moving to the next node, set the flag // Set the flag that condition is satisfied
_conditionSatisfiedPendingAdvance = true; _conditionSatisfiedPendingAdvance = true;
// Update bubble visibility after state change to show interaction prompt UpdateDialogueVisibilityOnItemEvent();
if (speechBubble != null)
{
speechBubble.UpdatePromptVisibility(HasAnyLines());
}
} }
} }
@@ -501,6 +503,12 @@ namespace Dialogue
{ {
Logging.Debug("[DialogueComponent] OnAnyItemSlotted"); Logging.Debug("[DialogueComponent] OnAnyItemSlotted");
// Initialize if needed
if (!initialized)
{
StartDialogue();
}
// Only react if we're active and waiting on a slot // Only react if we're active and waiting on a slot
if (!IsActive || IsCompleted || currentNode == null || if (!IsActive || IsCompleted || currentNode == null ||
currentNode.nodeType != RuntimeDialogueNodeType.WaitOnSlot) currentNode.nodeType != RuntimeDialogueNodeType.WaitOnSlot)
@@ -509,19 +517,21 @@ namespace Dialogue
// Check if this is the slot we're waiting for // Check if this is the slot we're waiting for
if (slotDefinition.itemId == currentNode.slotItemID) if (slotDefinition.itemId == currentNode.slotItemID)
{ {
// Instead of immediately moving to the next node, set the flag // Set the flag that condition is satisfied
_conditionSatisfiedPendingAdvance = true; _conditionSatisfiedPendingAdvance = true;
// Update bubble visibility after state change to show interaction prompt UpdateDialogueVisibilityOnItemEvent();
if (speechBubble != null)
{
speechBubble.UpdatePromptVisibility(HasAnyLines());
}
} }
} }
private void OnAnyItemsCombined(PickupItemData itemA, PickupItemData itemB, PickupItemData resultItem) private void OnAnyItemsCombined(PickupItemData itemA, PickupItemData itemB, PickupItemData resultItem)
{ {
// Initialize if needed
if (!initialized)
{
StartDialogue();
}
// Only react if we're active and waiting on a combination // Only react if we're active and waiting on a combination
if (!IsActive || IsCompleted || currentNode == null || if (!IsActive || IsCompleted || currentNode == null ||
currentNode.nodeType != RuntimeDialogueNodeType.WaitOnCombination) currentNode.nodeType != RuntimeDialogueNodeType.WaitOnCombination)
@@ -530,19 +540,21 @@ namespace Dialogue
// Check if this is the result item we're waiting for // Check if this is the result item we're waiting for
if (resultItem.itemId == currentNode.combinationResultItemID) if (resultItem.itemId == currentNode.combinationResultItemID)
{ {
// Instead of immediately moving to the next node, set the flag // Set the flag that condition is satisfied
_conditionSatisfiedPendingAdvance = true; _conditionSatisfiedPendingAdvance = true;
// Update bubble visibility after state change to show interaction prompt UpdateDialogueVisibilityOnItemEvent();
if (speechBubble != null)
{
speechBubble.UpdatePromptVisibility(HasAnyLines());
}
} }
} }
private void OnAnyIncorrectItemSlotted(PickupItemData slotDefinition, PickupItemData slottedItem) private void OnAnyIncorrectItemSlotted(PickupItemData slotDefinition, PickupItemData slottedItem)
{ {
// Initialize if needed
if (!initialized)
{
StartDialogue();
}
// Update the slot state for displaying the correct dialogue lines // Update the slot state for displaying the correct dialogue lines
if (!IsActive || IsCompleted || currentNode == null) if (!IsActive || IsCompleted || currentNode == null)
return; return;
@@ -554,16 +566,18 @@ namespace Dialogue
_currentSlotState = ItemSlotState.Incorrect; _currentSlotState = ItemSlotState.Incorrect;
_lastSlottedItem = slottedItem; _lastSlottedItem = slottedItem;
// Trigger dialogue update UpdateDialogueVisibilityOnItemEvent();
if (speechBubble != null)
{
speechBubble.UpdatePromptVisibility(HasAnyLines());
}
} }
} }
private void OnAnyForbiddenItemSlotted(PickupItemData slotDefinition, PickupItemData slottedItem) private void OnAnyForbiddenItemSlotted(PickupItemData slotDefinition, PickupItemData slottedItem)
{ {
// Initialize if needed
if (!initialized)
{
StartDialogue();
}
// Update the slot state for displaying the correct dialogue lines // Update the slot state for displaying the correct dialogue lines
if (!IsActive || IsCompleted || currentNode == null) if (!IsActive || IsCompleted || currentNode == null)
return; return;
@@ -575,16 +589,18 @@ namespace Dialogue
_currentSlotState = ItemSlotState.Forbidden; _currentSlotState = ItemSlotState.Forbidden;
_lastSlottedItem = slottedItem; _lastSlottedItem = slottedItem;
// Trigger dialogue update UpdateDialogueVisibilityOnItemEvent();
if (speechBubble != null)
{
speechBubble.UpdatePromptVisibility(HasAnyLines());
}
} }
} }
private void OnAnyItemSlotCleared(PickupItemData removedItem) private void OnAnyItemSlotCleared(PickupItemData removedItem)
{ {
// Initialize if needed
if (!initialized)
{
StartDialogue();
}
// Update the slot state when an item is removed // Update the slot state when an item is removed
if (!IsActive || IsCompleted || currentNode == null) if (!IsActive || IsCompleted || currentNode == null)
return; return;
@@ -594,8 +610,21 @@ namespace Dialogue
{ {
_currentSlotState = ItemSlotState.None; _currentSlotState = ItemSlotState.None;
_lastSlottedItem = null; _lastSlottedItem = null;
// Trigger dialogue update UpdateDialogueVisibilityOnItemEvent();
}
}
private void UpdateDialogueVisibilityOnItemEvent()
{
// If auto-play is enabled, immediately display dialogue
if (currentNode.shouldAutoPlay)
{
OnCharacterArrived();
}
else
{
// Manual mode: just update bubble visibility to show interaction prompt
if (speechBubble != null) if (speechBubble != null)
{ {
speechBubble.UpdatePromptVisibility(HasAnyLines()); speechBubble.UpdatePromptVisibility(HasAnyLines());

View File

@@ -50,6 +50,9 @@ namespace Dialogue
public string slotItemID; // For WaitOnSlot public string slotItemID; // For WaitOnSlot
public string combinationResultItemID; // For WaitOnCombination public string combinationResultItemID; // For WaitOnCombination
// Auto-play dialogue when condition is met (for item-related nodes)
public bool shouldAutoPlay;
// For WaitOnSlot - different responses // For WaitOnSlot - different responses
[HideInInspector] [HideInInspector]
public List<string> incorrectItemLines = new List<string>(); public List<string> incorrectItemLines = new List<string>();

View File

@@ -109,6 +109,32 @@ namespace Interactions
if ((heldItemData == null && _currentlySlottedItemObject != null) if ((heldItemData == null && _currentlySlottedItemObject != null)
|| (heldItemData != null && _currentlySlottedItemObject != null)) || (heldItemData != null && _currentlySlottedItemObject != null))
{ {
// If both held and slotted items exist, attempt combination via follower (reuse existing logic from Pickup)
if (heldItemData != null && _currentlySlottedItemData != null)
{
var slottedPickup = _currentlySlottedItemObject?.GetComponent<Pickup>();
if (slottedPickup != null)
{
var comboResult = FollowerController.TryCombineItems(slottedPickup, out var combinationResultItem);
if (combinationResultItem != null && comboResult == FollowerController.CombinationResult.Successful)
{
// Combination succeeded: fire slot-removed events and clear internals (don't call SlotItem to avoid duplicate events)
onItemSlotRemoved?.Invoke();
OnItemSlotRemoved?.Invoke(_currentlySlottedItemData);
_currentState = ItemSlotState.None;
// Clear internal references and visuals
_currentlySlottedItemObject = null;
_currentlySlottedItemData = null;
UpdateSlottedSprite();
Interactable.BroadcastInteractionComplete(false);
return;
}
}
}
// No combination (or not applicable) -> perform normal swap/pickup behavior
FollowerController.TryPickupItem(_currentlySlottedItemObject, _currentlySlottedItemData, false); FollowerController.TryPickupItem(_currentlySlottedItemObject, _currentlySlottedItemData, false);
onItemSlotRemoved?.Invoke(); onItemSlotRemoved?.Invoke();
OnItemSlotRemoved?.Invoke(_currentlySlottedItemData); OnItemSlotRemoved?.Invoke(_currentlySlottedItemData);

View File

@@ -0,0 +1,40 @@
using UnityEngine;
namespace Movement
{
/// <summary>
/// Bridge script that forwards Animation Events from the character art child object
/// to the FollowerController on the parent GameObject.
/// Attach this to the same GameObject that has the Animator component.
/// </summary>
public class FollowerAnimationEventBridge : MonoBehaviour
{
[SerializeField] private FollowerController followerController;
void Awake()
{
// Find the FollowerController on the parent
if (followerController == null)
{
followerController = GetComponentInParent<FollowerController>();
}
if (followerController == null)
{
Debug.LogError("[FollowerAnimationEventBridge] Could not find FollowerController in parent. This script must be on a child of the FollowerController.");
}
}
/// <summary>
/// Called by Animation Events. Forwards to the parent FollowerController.
/// </summary>
public void OnStationaryAnimationComplete()
{
if (followerController != null)
{
followerController.OnStationaryAnimationComplete();
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 39f2e64420884f11a9022fea7b3be5d0
timeCreated: 1761571513

View File

@@ -11,6 +11,8 @@ using Core;
/// </summary> /// </summary>
public class FollowerController: MonoBehaviour public class FollowerController: MonoBehaviour
{ {
private static readonly int CombineTrigger = Animator.StringToHash("Combine");
[Header("Follower Settings")] [Header("Follower Settings")]
public bool debugDrawTarget = true; public bool debugDrawTarget = true;
/// <summary> /// <summary>
@@ -52,6 +54,11 @@ public class FollowerController: MonoBehaviour
/// </summary> /// </summary>
public SpriteRenderer heldObjectRenderer; public SpriteRenderer heldObjectRenderer;
// Stationary animation state
private bool _isPlayingStationaryAnimation = false;
private Coroutine _stationaryAnimationCoroutine;
private System.Action _stationaryAnimationCallback;
private bool _isReturningToPlayer = false; private bool _isReturningToPlayer = false;
private float _playerMaxSpeed = 5f; private float _playerMaxSpeed = 5f;
private float _followerMaxSpeed = 6f; private float _followerMaxSpeed = 6f;
@@ -117,6 +124,19 @@ public class FollowerController: MonoBehaviour
return; return;
} }
// Skip all movement logic when playing a stationary animation
if (_isPlayingStationaryAnimation)
{
// Still update animator with zero speed to maintain idle state
if (_animator != null)
{
_animator.SetFloat("Speed", 0f);
_animator.SetFloat("DirX", _lastDirX);
_animator.SetFloat("DirY", _lastDirY);
}
return;
}
_timer += Time.deltaTime; _timer += Time.deltaTime;
if (_timer >= _settings.FollowUpdateInterval) if (_timer >= _settings.FollowUpdateInterval)
{ {
@@ -420,6 +440,100 @@ public class FollowerController: MonoBehaviour
} }
#endregion Movement #endregion Movement
#region StationaryAnimations
/// <summary>
/// Pauses all movement. Can be called directly from Timeline, Animation Events, or code.
/// Call ResumeMovement() to resume.
/// </summary>
public void PauseMovement()
{
_isPlayingStationaryAnimation = true;
_currentSpeed = 0f;
Logging.Debug("[FollowerController] Movement paused");
}
/// <summary>
/// Resumes movement after being paused. Can be called from Timeline, Animation Events, or code.
/// </summary>
public void ResumeMovement()
{
_isPlayingStationaryAnimation = false;
Logging.Debug("[FollowerController] Movement resumed");
}
/// <summary>
/// Plays an animation while pausing all movement. Resumes movement when animation completes.
/// Uses a hybrid approach: Animation Events (if set up) OR timeout fallback (if not).
/// To use Animation Events: Add an event at the end of your animation that calls OnStationaryAnimationComplete().
/// </summary>
/// <param name="triggerName">The animator trigger name to activate</param>
/// <param name="maxDuration">Maximum time to wait before auto-resuming (fallback if no Animation Event)</param>
/// <param name="onComplete">Optional callback to invoke when animation completes</param>
public void PlayAnimationStationary(string triggerName, float maxDuration = 2f, System.Action onComplete = null)
{
if (_animator == null)
{
Logging.Warning("[FollowerController] Cannot play stationary animation - no Animator found");
onComplete?.Invoke();
return;
}
// Stop any existing stationary animation
if (_stationaryAnimationCoroutine != null)
{
StopCoroutine(_stationaryAnimationCoroutine);
}
_isPlayingStationaryAnimation = true;
_stationaryAnimationCallback = onComplete;
_currentSpeed = 0f; // Immediately stop movement
// Trigger the animation
_animator.SetTrigger(triggerName);
// Start timeout coroutine (will be stopped early if Animation Event fires)
_stationaryAnimationCoroutine = StartCoroutine(StationaryAnimationTimeoutCoroutine(maxDuration));
}
private System.Collections.IEnumerator StationaryAnimationTimeoutCoroutine(float maxDuration)
{
yield return new WaitForSeconds(maxDuration);
// If we reach here, the Animation Event didn't fire - use fallback
Logging.Debug($"[FollowerController] Stationary animation timeout reached ({maxDuration}s) - resuming movement");
ResumeMovementAfterAnimation();
}
/// <summary>
/// Public method to be called by Animation Events at the end of stationary animations.
/// Add this as an Animation Event in your animation clip for frame-perfect timing.
/// </summary>
public void OnStationaryAnimationComplete()
{
Logging.Debug("[FollowerController] Stationary animation completed via Animation Event");
ResumeMovementAfterAnimation();
}
private void ResumeMovementAfterAnimation()
{
if (!_isPlayingStationaryAnimation) return; // Already resumed
// Stop the timeout coroutine if it's still running
if (_stationaryAnimationCoroutine != null)
{
StopCoroutine(_stationaryAnimationCoroutine);
_stationaryAnimationCoroutine = null;
}
_isPlayingStationaryAnimation = false;
// Invoke callback if provided
var callback = _stationaryAnimationCallback;
_stationaryAnimationCallback = null;
callback?.Invoke();
}
#endregion StationaryAnimations
#region ItemInteractions #region ItemInteractions
public void TryPickupItem(GameObject itemObject, PickupItemData itemData, bool dropItem = true) public void TryPickupItem(GameObject itemObject, PickupItemData itemData, bool dropItem = true)
{ {
@@ -445,7 +559,7 @@ public class FollowerController: MonoBehaviour
public CombinationResult TryCombineItems(Pickup pickupA, out GameObject newItem) public CombinationResult TryCombineItems(Pickup pickupA, out GameObject newItem)
{ {
_animator.ResetTrigger("Combine"); _animator.ResetTrigger(CombineTrigger);
newItem = null; newItem = null;
if (_cachedPickupObject == null) if (_cachedPickupObject == null)
{ {
@@ -468,7 +582,7 @@ public class FollowerController: MonoBehaviour
Destroy(pickupA.gameObject); Destroy(pickupA.gameObject);
Destroy(pickupB.gameObject); Destroy(pickupB.gameObject);
TryPickupItem(newItem, itemData); TryPickupItem(newItem, itemData);
_animator.SetTrigger("Combine"); PlayAnimationStationary("Combine", 10.0f);
return CombinationResult.Successful; return CombinationResult.Successful;
} }

View File

@@ -177,7 +177,7 @@ namespace AppleHills.Tests
#if UNITY_EDITOR #if UNITY_EDITOR
[CustomEditor(typeof(CardSystemTester))] [CustomEditor(typeof(CardSystemTester))]
public class CardSystemTesterEditor : Editor public class CardSystemTesterEditor : UnityEditor.Editor
{ {
public override void OnInspectorGUI() public override void OnInspectorGUI()
{ {

View File

@@ -274,7 +274,7 @@ namespace UI.CardSystem
if (canvasGroup != null) if (canvasGroup != null)
{ {
canvasGroup.alpha = 0f; canvasGroup.alpha = 0f;
Tween.Value(0f, 1f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete); Tween.Value(0f, 1f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete, obeyTimescale: false);
} }
else else
{ {
@@ -288,7 +288,7 @@ namespace UI.CardSystem
// Simple fade out animation // Simple fade out animation
if (canvasGroup != null) if (canvasGroup != null)
{ {
Tween.Value(canvasGroup.alpha, 0f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete); Tween.Value(canvasGroup.alpha, 0f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete, obeyTimescale: false);
} }
else else
{ {

View File

@@ -177,7 +177,8 @@ namespace UI.CardSystem
pulseDuration/2, pulseDuration/2,
0, 0,
Tween.EaseIn); Tween.EaseIn);
}); },
obeyTimescale: false);
} }
} }
} }

View File

@@ -54,7 +54,7 @@ namespace UI.CardSystem
private void Awake() private void Awake()
{ {
_cardManager = CardSystemManager.Instance; _cardManager = CardSystemManager.Instance;
_cardAlbumUI = FindObjectOfType<CardAlbumUI>(); _cardAlbumUI = FindFirstObjectByType<CardAlbumUI>();
// Set up button listeners // Set up button listeners
if (openBoosterButton != null) if (openBoosterButton != null)
@@ -255,7 +255,7 @@ namespace UI.CardSystem
// Animate the booster pack opening // Animate the booster pack opening
Tween.LocalScale(boosterPackObject.transform, Vector3.zero, 0.3f, 0f, Tween.EaseInBack, Tween.LoopType.None, null, () => { Tween.LocalScale(boosterPackObject.transform, Vector3.zero, 0.3f, 0f, Tween.EaseInBack, Tween.LoopType.None, null, () => {
boosterPackObject.SetActive(false); boosterPackObject.SetActive(false);
}); }, obeyTimescale: false);
} }
if (openBoosterButton != null) if (openBoosterButton != null)
@@ -322,7 +322,7 @@ namespace UI.CardSystem
Debug.Log($"[BoosterOpeningPage] Card back {i} activated"); Debug.Log($"[BoosterOpeningPage] Card back {i} activated");
// Play reveal animation using Pixelplacement.Tween // Play reveal animation using Pixelplacement.Tween
Tween.LocalScale(cardBackObj.transform, Vector3.one, 0.5f, 0f, Tween.EaseOutBack); Tween.LocalScale(cardBackObj.transform, Vector3.one, 0.5f, 0f, Tween.EaseOutBack, obeyTimescale: false);
// Wait for animation delay // Wait for animation delay
yield return new WaitForSeconds(cardRevealDelay); yield return new WaitForSeconds(cardRevealDelay);
@@ -374,7 +374,7 @@ namespace UI.CardSystem
Transform cardBackTransform = cardBack.transform; Transform cardBackTransform = cardBack.transform;
// Step 1: Flip the card 90 degrees (showing the edge) // Step 1: Flip the card 90 degrees (showing the edge)
Tween.LocalRotation(cardBackTransform, new Vector3(0, 90, 0), flipAnimationDuration * 0.5f, 0); Tween.LocalRotation(cardBackTransform, new Vector3(0, 90, 0), flipAnimationDuration * 0.5f, 0, obeyTimescale: false);
// Wait for half the flip duration // Wait for half the flip duration
yield return new WaitForSeconds(flipAnimationDuration * 0.5f); yield return new WaitForSeconds(flipAnimationDuration * 0.5f);
@@ -405,7 +405,7 @@ namespace UI.CardSystem
} }
// Step 3: Finish the flip animation (from 90 degrees to 0) // Step 3: Finish the flip animation (from 90 degrees to 0)
Tween.LocalRotation(cardObj.transform, Vector3.zero, flipAnimationDuration * 0.5f, 0); Tween.LocalRotation(cardObj.transform, Vector3.zero, flipAnimationDuration * 0.5f, 0, obeyTimescale: false);
// Increment counter of revealed cards // Increment counter of revealed cards
_revealedCardCount++; _revealedCardCount++;
@@ -441,8 +441,8 @@ namespace UI.CardSystem
Vector3 originalScale = cardTransform.localScale; Vector3 originalScale = cardTransform.localScale;
// Sequence: Scale up slightly, then back to normal // Sequence: Scale up slightly, then back to normal
Tween.LocalScale(cardTransform, originalScale * 1.2f, 0.2f, 0.1f, Tween.EaseOutBack); Tween.LocalScale(cardTransform, originalScale * 1.2f, 0.2f, 0.1f, Tween.EaseOutBack, obeyTimescale: false);
Tween.LocalScale(cardTransform, originalScale, 0.15f, 0.3f, Tween.EaseIn); Tween.LocalScale(cardTransform, originalScale, 0.15f, 0.3f, Tween.EaseIn, obeyTimescale: false);
// Play sound effect based on rarity (if available) // Play sound effect based on rarity (if available)
// This would require audio source components to be set up // This would require audio source components to be set up
@@ -463,7 +463,7 @@ namespace UI.CardSystem
continueButton.gameObject.SetActive(true); continueButton.gameObject.SetActive(true);
continueButton.transform.localScale = Vector3.zero; continueButton.transform.localScale = Vector3.zero;
Tween.LocalScale(continueButton.transform, Vector3.one, 0.3f, 0f, Tween.EaseOutBack); Tween.LocalScale(continueButton.transform, Vector3.one, 0.3f, 0f, Tween.EaseOutBack, obeyTimescale: false);
} }
} }
@@ -542,8 +542,8 @@ namespace UI.CardSystem
Vector3 targetPos = card.transform.parent.InverseTransformPoint(backpackWorldPos); Vector3 targetPos = card.transform.parent.InverseTransformPoint(backpackWorldPos);
// Start the move animation - ensure no cancellation between animations // Start the move animation - ensure no cancellation between animations
Tween.LocalPosition(card.transform, targetPos, animationDuration, cardDelay * i, Tween.EaseInOut); Tween.LocalPosition(card.transform, targetPos, animationDuration, cardDelay * i, Tween.EaseInOut, obeyTimescale: false);
Tween.LocalScale(card.transform, Vector3.zero, animationDuration, cardDelay * i, Tween.EaseIn); Tween.LocalScale(card.transform, Vector3.zero, animationDuration, cardDelay * i, Tween.EaseIn, obeyTimescale: false);
Debug.Log($"[BoosterOpeningPage] Starting animation for card {i}"); Debug.Log($"[BoosterOpeningPage] Starting animation for card {i}");
} }
@@ -578,7 +578,7 @@ namespace UI.CardSystem
if (canvasGroup != null) if (canvasGroup != null)
{ {
canvasGroup.alpha = 0f; canvasGroup.alpha = 0f;
Tween.Value(0f, 1f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete); Tween.Value(0f, 1f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete, obeyTimescale: false);
} }
else else
{ {
@@ -595,7 +595,7 @@ namespace UI.CardSystem
// Simple fade out animation // Simple fade out animation
if (canvasGroup != null) if (canvasGroup != null)
{ {
Tween.Value(canvasGroup.alpha, 0f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete); Tween.Value(canvasGroup.alpha, 0f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete, obeyTimescale: false);
} }
else else
{ {

View File

@@ -268,7 +268,7 @@ namespace UI.CardSystem
// Animate the notification dot for feedback // Animate the notification dot for feedback
boosterNotificationDot.transform.localScale = Vector3.one * 1.2f; boosterNotificationDot.transform.localScale = Vector3.one * 1.2f;
Tween.LocalScale(boosterNotificationDot.transform, Vector3.one, 0.3f, 0f); Tween.LocalScale(boosterNotificationDot.transform, Vector3.one, 0.3f, 0f, obeyTimescale: false);
// Update visibility based on count // Update visibility based on count
UpdateBoosterVisibility(); UpdateBoosterVisibility();

View File

@@ -175,7 +175,7 @@ namespace UI.CardSystem
if (canvasGroup != null) if (canvasGroup != null)
{ {
canvasGroup.alpha = 0f; canvasGroup.alpha = 0f;
Tween.Value(0f, 1f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete); Tween.Value(0f, 1f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete, obeyTimescale: false);
} }
else else
{ {
@@ -192,7 +192,7 @@ namespace UI.CardSystem
// Simple fade out animation // Simple fade out animation
if (canvasGroup != null) if (canvasGroup != null)
{ {
Tween.Value(canvasGroup.alpha, 0f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete); Tween.Value(canvasGroup.alpha, 0f, (value) => canvasGroup.alpha = value, transitionDuration, 0f, Tween.EaseInOut, Tween.LoopType.None, null, onComplete, obeyTimescale: false);
} }
else else
{ {

View File

@@ -233,7 +233,7 @@ namespace UI.CardSystem
#if UNITY_EDITOR #if UNITY_EDITOR
[CustomEditor(typeof(CardUIElement))] [CustomEditor(typeof(CardUIElement))]
public class CardUIElementEditor : Editor public class CardUIElementEditor : UnityEditor.Editor
{ {
public override void OnInspectorGUI() public override void OnInspectorGUI()
{ {

View File

@@ -1,6 +1,7 @@
using System.Collections; using System.Collections;
using Bootstrap; using Bootstrap;
using Core; using Core;
using Core.SaveLoad;
using Input; using Input;
using Pixelplacement; using Pixelplacement;
using UI.Core; using UI.Core;
@@ -10,8 +11,15 @@ namespace UI.Tutorial
{ {
public class DivingTutorial : MonoBehaviour, ITouchInputConsumer public class DivingTutorial : MonoBehaviour, ITouchInputConsumer
{ {
public enum ProgressType
{
Manual, // Wait for player tap after animation loop
Auto // Automatically progress after animation loop
}
private StateMachine _stateMachine; private StateMachine _stateMachine;
public bool playTutorial; public bool playTutorial;
[SerializeField] private ProgressType progressType = ProgressType.Auto;
// gating for input until current state's animation finishes first loop // gating for input until current state's animation finishes first loop
[SerializeField] private GameObject tapPrompt; [SerializeField] private GameObject tapPrompt;
@@ -31,8 +39,10 @@ namespace UI.Tutorial
void InitializeTutorial() void InitializeTutorial()
{ {
if (playTutorial) if (playTutorial && !SaveLoadManager.Instance.currentSaveData.playedDivingTutorial)
{ {
// TODO: Possibly do it better, but for now just mark tutorial as played immediately
SaveLoadManager.Instance.currentSaveData.playedDivingTutorial = true;
// pause the game, hide UI, and register for input overrides // pause the game, hide UI, and register for input overrides
GameManager.Instance.RequestPause(this); GameManager.Instance.RequestPause(this);
UIPageController.Instance.HideAllUI(); UIPageController.Instance.HideAllUI();
@@ -104,7 +114,8 @@ namespace UI.Tutorial
_canAcceptInput = allow; _canAcceptInput = allow;
if (tapPrompt != null) if (tapPrompt != null)
{ {
tapPrompt.SetActive(allow); // Only show tap prompt in Manual mode
tapPrompt.SetActive(allow && progressType == ProgressType.Manual);
} }
} }
@@ -198,7 +209,19 @@ namespace UI.Tutorial
yield return null; yield return null;
} }
SetInputEnabled(true); // After first loop completes, handle based on progress type
if (progressType == ProgressType.Auto)
{
// Auto mode: immediately progress to next state
_stateMachine.Next(true);
SetupInputGateForCurrentState();
}
else
{
// Manual mode: enable input and wait for player tap
SetInputEnabled(true);
}
_waitLoopCoroutine = null; _waitLoopCoroutine = null;
} }
} }

View File

@@ -13,3 +13,4 @@ MonoBehaviour:
m_Name: DebugSettings m_Name: DebugSettings
m_EditorClassIdentifier: AppleHillsScripts::AppleHills.Core.Settings.DebugSettings m_EditorClassIdentifier: AppleHillsScripts::AppleHills.Core.Settings.DebugSettings
showDebugUiMessages: 1 showDebugUiMessages: 1
pauseTimeOnPauseGame: 1

8
Assets/Signals.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2ba6a6b0f020a9741a46f32cdfe270f3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d6fa2d92fc1b3f34da284357edf89c3b, type: 3}
m_Name: PausePulverMovement
m_EditorClassIdentifier: Unity.Timeline::UnityEngine.Timeline.SignalAsset

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2a32e2abdb44cb1469e5c6b9a25f98bc
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d6fa2d92fc1b3f34da284357edf89c3b, type: 3}
m_Name: ResumePulverMovement
m_EditorClassIdentifier: Unity.Timeline::UnityEngine.Timeline.SignalAsset

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2ec36cde76b6baf4299c0dd9ab54714e
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant: