diff --git a/Assets/Scripts/Player/PlayerNetworkController.cs b/Assets/Scripts/Player/PlayerNetworkController.cs index b9a5d10f..6dcce4b0 100644 --- a/Assets/Scripts/Player/PlayerNetworkController.cs +++ b/Assets/Scripts/Player/PlayerNetworkController.cs @@ -1,13 +1,15 @@ +using System; using UnityEngine; using Unity.Netcode; using Colosseum.Stats; +using Colosseum.Combat; namespace Colosseum.Player { /// /// 플레이어 네트워크 상태 관리 (HP, MP 등) /// - public class PlayerNetworkController : NetworkBehaviour + public class PlayerNetworkController : NetworkBehaviour, IDamageable { [Header("References")] [Tooltip("CharacterStats 컴포넌트 (없으면 자동 검색)")] @@ -23,6 +25,14 @@ namespace Colosseum.Player public float MaxMana => characterStats != null ? characterStats.MaxMana : 50f; public CharacterStats Stats => characterStats; + // 체력/마나 변경 이벤트 + public event Action OnHealthChanged; // (oldValue, newValue) + public event Action OnManaChanged; // (oldValue, newValue) + + // IDamageable 구현 + public float CurrentHealth => currentHealth.Value; + public bool IsDead => currentHealth.Value <= 0f; + public override void OnNetworkSpawn() { // CharacterStats 참조 확인 @@ -31,6 +41,10 @@ namespace Colosseum.Player characterStats = GetComponent(); } + // 네트워크 변수 변경 콜백 등록 + currentHealth.OnValueChanged += HandleHealthChanged; + currentMana.OnValueChanged += HandleManaChanged; + // 초기화 if (IsServer) { @@ -39,6 +53,23 @@ namespace Colosseum.Player } } + public override void OnNetworkDespawn() + { + // 콜백 해제 + currentHealth.OnValueChanged -= HandleHealthChanged; + currentMana.OnValueChanged -= HandleManaChanged; + } + + private void HandleHealthChanged(float oldValue, float newValue) + { + OnHealthChanged?.Invoke(oldValue, newValue); + } + + private void HandleManaChanged(float oldValue, float newValue) + { + OnManaChanged?.Invoke(oldValue, newValue); + } + /// /// 대미지 적용 (서버에서만 실행) /// @@ -85,5 +116,38 @@ namespace Colosseum.Player // TODO: 사망 처리 로직 Debug.Log($"Player {OwnerClientId} died!"); } + + #region IDamageable + /// + /// 대미지 적용 (서버에서만 호출) + /// + public float TakeDamage(float damage, object source = null) + { + if (!IsServer) return 0f; + + float actualDamage = Mathf.Min(damage, currentHealth.Value); + currentHealth.Value = Mathf.Max(0f, currentHealth.Value - damage); + + if (currentHealth.Value <= 0f) + { + HandleDeath(); + } + + return actualDamage; + } + + /// + /// 체력 회복 (서버에서만 호출) + /// + public float Heal(float amount) + { + if (!IsServer) return 0f; + + float actualHeal = Mathf.Min(amount, MaxHealth - currentHealth.Value); + currentHealth.Value = Mathf.Min(MaxHealth, currentHealth.Value + amount); + + return actualHeal; + } + #endregion } } diff --git a/Assets/Scripts/Skills/Effects/DamageEffect.cs b/Assets/Scripts/Skills/Effects/DamageEffect.cs index 2030833b..73b942be 100644 --- a/Assets/Scripts/Skills/Effects/DamageEffect.cs +++ b/Assets/Scripts/Skills/Effects/DamageEffect.cs @@ -1,6 +1,7 @@ using UnityEngine; + using Colosseum.Stats; -using Colosseum.Player; +using Colosseum.Combat; namespace Colosseum.Skills.Effects { @@ -34,11 +35,11 @@ namespace Colosseum.Skills.Effects // 대미지 계산 float totalDamage = CalculateDamage(caster); - // 타겟에 대미지 적용 - var networkController = target.GetComponent(); - if (networkController != null) + // 타겟에 대미지 적용 (IDamageable 인터페이스 사용) + var damageable = target.GetComponent(); + if (damageable != null) { - networkController.TakeDamageRpc(totalDamage); + damageable.TakeDamage(totalDamage, caster); } Debug.Log($"[Damage] {caster.name} -> {target.name}: {totalDamage:F1} ({damageType})"); diff --git a/Assets/Scripts/Skills/Effects/HealEffect.cs b/Assets/Scripts/Skills/Effects/HealEffect.cs index 5ea6ce93..639e7b40 100644 --- a/Assets/Scripts/Skills/Effects/HealEffect.cs +++ b/Assets/Scripts/Skills/Effects/HealEffect.cs @@ -1,6 +1,7 @@ using UnityEngine; + using Colosseum.Stats; -using Colosseum.Player; +using Colosseum.Combat; namespace Colosseum.Skills.Effects { @@ -22,11 +23,11 @@ namespace Colosseum.Skills.Effects // 회복량 계산 float totalHeal = CalculateHeal(caster); - // 타겟에 회복 적용 - var networkController = target.GetComponent(); - if (networkController != null) + // 타겟에 회복 적용 (IDamageable 인터페이스 사용) + var damageable = target.GetComponent(); + if (damageable != null) { - networkController.RestoreHealthRpc(totalHeal); + damageable.Heal(totalHeal); } Debug.Log($"[Heal] {caster.name} -> {target.name}: {totalHeal:F1}");