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}");