using UnityEngine; namespace Ashwild.Player { /// /// Owns the local player's death-and-return. It flips locomotion into its dead state when the /// player dies, and on teleports the body back to the current respawn pose, /// revives the stats and clears the dead state. The respawn pose starts at the assigned spawn /// point (or wherever the player begins) and is reassigned live when the player claims a bed โ€” /// pushed in over the bus, so it stays pure local state that never crosses the wire (ยง3). /// [DisallowMultipleComponent] public class PlayerLifecycle : MonoBehaviour { #region Serialized Fields [Header("Spawn point (auto-captured at scene start if left empty)")] [SerializeField] private Transform spawnPoint; #endregion #region State private PlayerLocomotion locomotion; private Rigidbody rb; private Vector3 spawnPosition; private Quaternion spawnRotation; private bool isDead; #endregion #region Unity Lifecycle /// /// Caches the sibling components the respawn drives. /// private void Awake() { locomotion = GetComponent(); rb = GetComponent(); } /// /// Seeds the respawn pose from the assigned spawn point, or the player's starting pose when /// none is set, so a death before any bed is claimed still returns somewhere valid. /// private void Start() { if (spawnPoint != null) { spawnPosition = spawnPoint.position; spawnRotation = spawnPoint.rotation; } else { spawnPosition = transform.position; spawnRotation = transform.rotation; } } /// /// Subscribes to death and to respawn-point reassignments (claiming a bed). /// private void OnEnable() { PlayerEvents.Died += OnDied; PlayerEvents.RespawnPointChanged += HandleRespawnPointChanged; } /// /// Unsubscribes โ€” mirrors OnEnable exactly. /// private void OnDisable() { PlayerEvents.Died -= OnDied; PlayerEvents.RespawnPointChanged -= HandleRespawnPointChanged; } #endregion #region Event Handlers /// /// Freezes the player into its dead state once, ignoring repeat death events. /// private void OnDied() { if (isDead) return; isDead = true; if (locomotion != null) locomotion.SetDead(true); } /// /// Adopts a new respawn pose pushed over the bus (the player claimed a bed). Local state /// only โ€” the respawn location is never networked, so each client keeps its own. /// private void HandleRespawnPointChanged(Vector3 position, Quaternion rotation) => SetSpawnPoint(position, rotation); #endregion #region Public API /// /// Returns the player to the current respawn pose: zeroes momentum, teleports the body, /// revives the stats and clears the dead state. /// public void Respawn() { if (rb != null) { rb.linearVelocity = Vector3.zero; rb.angularVelocity = Vector3.zero; } transform.SetPositionAndRotation(spawnPosition, spawnRotation); if (PlayerStats.Instance != null) PlayerStats.Instance.Revive(); if (locomotion != null) locomotion.SetDead(false); isDead = false; } /// /// Overrides the respawn pose directly with a world position and rotation. /// public void SetSpawnPoint(Vector3 position, Quaternion rotation) { spawnPosition = position; spawnRotation = rotation; } #endregion } }