Net.Project.B/Src/Health/HealthService.cs

155 lines
5.0 KiB
C#
Raw Normal View History

2024-11-23 17:20:13 +08:00
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using BITKit;
2025-03-09 13:38:32 +08:00
using BITKit.Entities;
using BITKit.WorldNode;
2024-11-23 17:20:13 +08:00
using Cysharp.Threading.Tasks;
2025-03-09 13:38:32 +08:00
using Microsoft.Extensions.DependencyInjection;
2025-06-26 23:34:50 +08:00
using Microsoft.Extensions.Logging;
2024-11-23 17:20:13 +08:00
namespace Net.Project.B.Health
{
2025-03-09 13:38:32 +08:00
public interface IHealthComponent
{
2025-03-24 14:42:29 +08:00
public int HealthPoint { get;internal set; }
2025-03-09 13:38:32 +08:00
public int MaxHealthPoint { get; }
2025-03-24 14:42:29 +08:00
public event Action<int, int> OnHealthChanged;
2025-03-09 13:38:32 +08:00
}
[Serializable]
public class HealthComponent:IHealthComponent,IWorldNode
{
public int maxHealthPoint = 100;
2025-03-24 14:42:29 +08:00
public int healthPoint;
int IHealthComponent.HealthPoint
{
get => healthPoint;
set
{
var prevHp = healthPoint;
if(prevHp==value)return;
healthPoint = value;
OnHealthChanged?.Invoke(prevHp,healthPoint);
2025-06-12 16:08:12 +08:00
2025-03-24 14:42:29 +08:00
}
}
2025-03-09 13:38:32 +08:00
public int MaxHealthPoint => maxHealthPoint;
2025-03-24 14:42:29 +08:00
public event Action<int, int> OnHealthChanged;
2025-03-09 13:38:32 +08:00
}
2024-11-23 17:20:13 +08:00
/// <summary>
/// 生命值服务
/// </summary>
public interface IHealthService
{
/// <summary>
/// 已缓存的生命值
/// </summary>
public IReadOnlyDictionary<int,int> Healths { get; }
/// <summary>
/// 在改变生命值前,ID,当前生命值,新的生命值,来源
/// <returns>增加的数值</returns>
/// </summary>
public event Func<int,int,int,object,int> OnHealthPlus;
/// <summary>
/// 在改变生命值后
/// </summary>
/// /// <summary>
/// 当健康值发生变化时触发的事件。
/// </summary>
public event Action<int,int,int,object> OnHealthChanged;
/// <summary>
/// 调整生命值
/// </summary>
/// <param name="id"></param>
/// <param name="value">+- not set</param>
/// <returns></returns>
public UniTask<int> AddHealth(int id,int value,object arg);
}
2025-03-09 13:38:32 +08:00
public class HealthService:IHealthService,IDisposable
{ private static HealthService _singleton;
private readonly IEntitiesService _entitiesService;
private static readonly ConcurrentDictionary<int, IHealthComponent> HealthComponents = new();
2025-06-26 23:34:50 +08:00
private readonly ILogger<HealthService> _logger;
public HealthService(IEntitiesService entitiesService, ILogger<HealthService> logger)
2024-11-23 17:20:13 +08:00
{
2025-03-09 13:38:32 +08:00
_entitiesService = entitiesService;
2025-06-26 23:34:50 +08:00
_logger = logger;
2024-11-23 17:20:13 +08:00
_singleton = this;
2025-03-09 13:38:32 +08:00
_entitiesService.OnAdd += OnAdd;
2024-11-23 17:20:13 +08:00
}
2025-03-09 13:38:32 +08:00
private void OnAdd(IEntity obj)
{
2025-03-24 14:42:29 +08:00
if (obj.ServiceProvider.QueryComponents(out IHealthComponent healthComponent) is false) return;
HealthComponents[obj.Id] = healthComponent;
Healths[obj.Id] = healthComponent.HealthPoint = healthComponent.MaxHealthPoint <= 0 ? 100 : healthComponent.MaxHealthPoint;
2025-03-09 13:38:32 +08:00
}
2024-11-23 17:20:13 +08:00
[BITCommand]
public static void SetHealth(int id, int newHealth)
{
Healths.GetOrAdd(id,100);
Healths.Set(id,newHealth);
OnHealthChanged?.Invoke(id,newHealth,newHealth,null);
}
[BITCommand]
public static void AddHealth(int id, int newHealth)
{
Healths.GetOrAdd(id,100);
_singleton.AddHealth(id, newHealth, null).Forget();
}
IReadOnlyDictionary<int, int> IHealthService.Healths => Healths;
private static event Func<int,int,int,object,int> OnHealthChange;
private static event Action<int,int,int,object> OnHealthChanged;
private static readonly ConcurrentDictionary<int, int> Healths = new();
event Func<int,int,int,object,int> IHealthService.OnHealthPlus
{
add => OnHealthChange += value;
remove => OnHealthChange -= value;
}
event Action<int,int,int,object> IHealthService.OnHealthChanged
{
add => OnHealthChanged += value;
remove => OnHealthChanged -= value;
}
public UniTask<int> AddHealth(int id, int value,object arg)
{
2025-03-09 13:38:32 +08:00
if (Healths.TryGetValue(id,out var current) is false) return UniTask.FromResult(-1);
2024-11-23 17:20:13 +08:00
foreach (var func in OnHealthChange.CastAsFunc())
{
value =func.Invoke(id,current, value, arg);
}
2025-03-09 13:38:32 +08:00
var newHp = Math.Clamp(current + value, -1, HealthComponents[id].MaxHealthPoint);
2025-03-24 14:42:29 +08:00
Healths.Set(id,HealthComponents[id].HealthPoint = newHp);
2025-06-26 23:34:50 +08:00
try
{
OnHealthChanged?.Invoke(id, current, newHp, arg);
}
catch (Exception e)
{
_logger.LogCritical(e, e.Message);
}
2024-11-23 17:20:13 +08:00
return UniTask.FromResult(newHp);
}
2025-03-09 13:38:32 +08:00
public void Dispose()
{
_entitiesService.OnAdd -= OnAdd;
}
2024-11-23 17:20:13 +08:00
}
}