SaveLoad using managed lifecycle
This commit is contained in:
committed by
Michal Pikulski
parent
3e835ed3b8
commit
b932be2232
@@ -1,12 +1,10 @@
|
||||
using Interactions;
|
||||
using UnityEngine;
|
||||
using Pathfinding;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Utils;
|
||||
using AppleHills.Core.Settings;
|
||||
using Core;
|
||||
using Core.Lifecycle;
|
||||
using Core.SaveLoad;
|
||||
using UnityEngine.Events;
|
||||
|
||||
/// <summary>
|
||||
@@ -18,13 +16,13 @@ public class FollowerSaveData
|
||||
public Vector3 worldPosition;
|
||||
public Quaternion worldRotation;
|
||||
public string heldItemSaveId; // Save ID of held pickup (if any)
|
||||
public string heldItemDataAssetPath; // Asset path to PickupItemData
|
||||
public string heldItemDataAssetPath; // ItemId of the PickupItemData (for fallback restoration)
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Controls the follower character, including following the player, handling pickups, and managing held items.
|
||||
/// </summary>
|
||||
public class FollowerController : ManagedBehaviour, ISaveParticipant
|
||||
public class FollowerController : ManagedBehaviour
|
||||
{
|
||||
private static readonly int CombineTrigger = Animator.StringToHash("Combine");
|
||||
|
||||
@@ -54,6 +52,12 @@ public class FollowerController : ManagedBehaviour, ISaveParticipant
|
||||
// Direction variables for 2D blend tree animation
|
||||
private float _lastDirX = 0f; // -1 (left) to 1 (right)
|
||||
private float _lastDirY = -1f; // -1 (down) to 1 (up)
|
||||
|
||||
// Save system configuration
|
||||
public override bool AutoRegisterForSave => true;
|
||||
// Scene-specific SaveId - each level has its own follower state
|
||||
public override string SaveId => $"{gameObject.scene.name}/FollowerController";
|
||||
|
||||
private float _currentSpeed = 0f;
|
||||
private Animator _animator;
|
||||
private Transform _artTransform;
|
||||
@@ -98,8 +102,7 @@ public class FollowerController : ManagedBehaviour, ISaveParticipant
|
||||
|
||||
private Input.PlayerTouchController _playerTouchController;
|
||||
|
||||
// Save system tracking
|
||||
private bool hasBeenRestored;
|
||||
// Save system tracking for bilateral restoration
|
||||
private bool _hasRestoredHeldItem; // Track if held item restoration completed
|
||||
private string _expectedHeldItemSaveId; // Expected saveId during restoration
|
||||
|
||||
@@ -124,38 +127,11 @@ public class FollowerController : ManagedBehaviour, ISaveParticipant
|
||||
// Initialize settings references
|
||||
_settings = GameManager.GetSettingsObject<IPlayerFollowerSettings>();
|
||||
_interactionSettings = GameManager.GetSettingsObject<IInteractionSettings>();
|
||||
|
||||
// Register with save system
|
||||
if (SaveLoadManager.Instance != null)
|
||||
{
|
||||
SaveLoadManager.Instance.RegisterParticipant(this);
|
||||
Logging.Debug("[FollowerController] Registered with SaveLoadManager");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Warning("[FollowerController] SaveLoadManager not available for registration");
|
||||
}
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
SceneManager.sceneLoaded += OnSceneLoaded;
|
||||
FindPlayerReference();
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
SceneManager.sceneLoaded -= OnSceneLoaded;
|
||||
|
||||
// Unregister from save system
|
||||
if (SaveLoadManager.Instance != null)
|
||||
{
|
||||
SaveLoadManager.Instance.UnregisterParticipant(GetSaveId());
|
||||
}
|
||||
}
|
||||
|
||||
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
|
||||
protected override void OnSceneReady()
|
||||
{
|
||||
// Find player reference when scene is ready (called for every scene load)
|
||||
FindPlayerReference();
|
||||
}
|
||||
|
||||
@@ -163,9 +139,7 @@ public class FollowerController : ManagedBehaviour, ISaveParticipant
|
||||
{
|
||||
if (_playerTransform == null)
|
||||
{
|
||||
FindPlayerReference();
|
||||
if (_playerTransform == null)
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip all movement logic when playing a stationary animation
|
||||
@@ -749,16 +723,9 @@ public class FollowerController : ManagedBehaviour, ISaveParticipant
|
||||
|
||||
#endregion ItemInteractions
|
||||
|
||||
#region ISaveParticipant Implementation
|
||||
#region Save/Load Lifecycle Hooks
|
||||
|
||||
public bool HasBeenRestored => hasBeenRestored;
|
||||
|
||||
public string GetSaveId()
|
||||
{
|
||||
return "FollowerController";
|
||||
}
|
||||
|
||||
public string SerializeState()
|
||||
protected override string OnSceneSaveRequested()
|
||||
{
|
||||
var saveData = new FollowerSaveData
|
||||
{
|
||||
@@ -772,26 +739,24 @@ public class FollowerController : ManagedBehaviour, ISaveParticipant
|
||||
var pickup = _cachedPickupObject.GetComponent<Pickup>();
|
||||
if (pickup is SaveableInteractable saveable)
|
||||
{
|
||||
saveData.heldItemSaveId = saveable.GetSaveId();
|
||||
saveData.heldItemSaveId = saveable.SaveId;
|
||||
}
|
||||
|
||||
// Save the itemId for build-compatible restoration
|
||||
if (_currentlyHeldItemData != null)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
saveData.heldItemDataAssetPath = UnityEditor.AssetDatabase.GetAssetPath(_currentlyHeldItemData);
|
||||
#endif
|
||||
saveData.heldItemDataAssetPath = _currentlyHeldItemData.itemId;
|
||||
}
|
||||
}
|
||||
|
||||
return JsonUtility.ToJson(saveData);
|
||||
}
|
||||
|
||||
public void RestoreState(string serializedData)
|
||||
protected override void OnSceneRestoreRequested(string serializedData)
|
||||
{
|
||||
if (string.IsNullOrEmpty(serializedData))
|
||||
{
|
||||
Logging.Debug("[FollowerController] No saved state to restore");
|
||||
hasBeenRestored = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -811,7 +776,6 @@ public class FollowerController : ManagedBehaviour, ISaveParticipant
|
||||
TryRestoreHeldItem(saveData.heldItemSaveId, saveData.heldItemDataAssetPath);
|
||||
}
|
||||
|
||||
hasBeenRestored = true;
|
||||
Logging.Debug($"[FollowerController] Restored position: {saveData.worldPosition}");
|
||||
}
|
||||
}
|
||||
@@ -825,7 +789,7 @@ public class FollowerController : ManagedBehaviour, ISaveParticipant
|
||||
/// Bilateral restoration: Follower tries to find and claim the held item.
|
||||
/// If pickup doesn't exist yet, it will try to claim us when it restores.
|
||||
/// </summary>
|
||||
private void TryRestoreHeldItem(string heldItemSaveId, string heldItemDataAssetPath)
|
||||
private void TryRestoreHeldItem(string heldItemSaveId, string itemDataId)
|
||||
{
|
||||
if (_hasRestoredHeldItem)
|
||||
{
|
||||
@@ -850,7 +814,7 @@ public class FollowerController : ManagedBehaviour, ISaveParticipant
|
||||
}
|
||||
|
||||
// Claim the pickup
|
||||
TakeOwnership(pickup, heldItemDataAssetPath);
|
||||
TakeOwnership(pickup, itemDataId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -871,9 +835,9 @@ public class FollowerController : ManagedBehaviour, ISaveParticipant
|
||||
// Verify this is the expected pickup
|
||||
if (pickup is SaveableInteractable saveable)
|
||||
{
|
||||
if (saveable.GetSaveId() != _expectedHeldItemSaveId)
|
||||
if (saveable.SaveId != _expectedHeldItemSaveId)
|
||||
{
|
||||
Logging.Warning($"[FollowerController] Pickup tried to claim but saveId mismatch: {saveable.GetSaveId()} != {_expectedHeldItemSaveId}");
|
||||
Logging.Warning($"[FollowerController] Pickup tried to claim but saveId mismatch: {saveable.SaveId} != {_expectedHeldItemSaveId}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -886,28 +850,29 @@ public class FollowerController : ManagedBehaviour, ISaveParticipant
|
||||
/// <summary>
|
||||
/// Takes ownership of a pickup during restoration. Called by both restoration paths.
|
||||
/// </summary>
|
||||
private void TakeOwnership(Pickup pickup, string itemDataAssetPath)
|
||||
private void TakeOwnership(Pickup pickup, string itemDataIdOrPath)
|
||||
{
|
||||
if (_hasRestoredHeldItem)
|
||||
return; // Already claimed
|
||||
|
||||
// Get the item data
|
||||
// Get the item data from the pickup
|
||||
PickupItemData heldData = pickup.itemData;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Try loading from asset path if available and pickup doesn't have data
|
||||
if (heldData == null && !string.IsNullOrEmpty(itemDataAssetPath))
|
||||
{
|
||||
heldData = UnityEditor.AssetDatabase.LoadAssetAtPath<PickupItemData>(itemDataAssetPath);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Fallback: If pickup doesn't have itemData, log detailed error
|
||||
if (heldData == null)
|
||||
{
|
||||
Logging.Warning($"[FollowerController] Could not get item data for pickup: {pickup.gameObject.name}");
|
||||
Logging.Warning($"[FollowerController] Pickup {pickup.gameObject.name} has null itemData!");
|
||||
Logging.Warning($"[FollowerController] Expected itemId: {itemDataIdOrPath}");
|
||||
Logging.Warning($"[FollowerController] This pickup prefab may be missing its PickupItemData reference.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Verify itemId matches if we have it (additional safety check)
|
||||
if (!string.IsNullOrEmpty(itemDataIdOrPath) && heldData.itemId != itemDataIdOrPath)
|
||||
{
|
||||
Logging.Warning($"[FollowerController] ItemId mismatch! Pickup has '{heldData.itemId}' but expected '{itemDataIdOrPath}'");
|
||||
}
|
||||
|
||||
// Setup the held item
|
||||
_cachedPickupObject = pickup.gameObject;
|
||||
_cachedPickupObject.SetActive(false); // Held items should be hidden
|
||||
@@ -915,7 +880,7 @@ public class FollowerController : ManagedBehaviour, ISaveParticipant
|
||||
_animator.SetBool("IsCarrying", true);
|
||||
_hasRestoredHeldItem = true;
|
||||
|
||||
Logging.Debug($"[FollowerController] Successfully restored held item: {heldData.itemName}");
|
||||
Logging.Debug($"[FollowerController] Successfully restored held item: {heldData.itemName} (itemId: {heldData.itemId})");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -927,7 +892,7 @@ public class FollowerController : ManagedBehaviour, ISaveParticipant
|
||||
return FindObjectOfType<FollowerController>();
|
||||
}
|
||||
|
||||
#endregion ISaveParticipant Implementation
|
||||
#endregion Save/Load Lifecycle Hooks
|
||||
|
||||
#if UNITY_EDITOR
|
||||
void OnDrawGizmos()
|
||||
|
||||
Reference in New Issue
Block a user