BITKit/Src/Unity/Scripts/Entity/Components/Health/DamageService.cs

183 lines
6.0 KiB
C#
Raw Normal View History

2023-08-11 23:57:37 +08:00
using System;
using System.Collections;
using System.Collections.Generic;
2024-03-31 23:31:00 +08:00
using System.IO;
2023-08-11 23:57:37 +08:00
using UnityEngine;
using BITKit;
using BITKit.SubSystems;
using BITKit.Entities;
namespace BITKit.Entities
{
public interface IDamageType { }
public interface IDamageService
{
public event Action<DamageMessage> OnEntityDamaged;
public event Action<DamageMessage> OnEntityKilled;
void Execute(DamageMessage damageMessage);
}
2024-03-31 23:31:00 +08:00
public struct MeleeDamageMessage : IDamageType
{
public bool Bleeding;
}
2023-11-15 23:55:06 +08:00
public struct BulletDamageMessage:IDamageType{}
2023-08-11 23:57:37 +08:00
[Serializable]
public class DamageServiceSingleton:IDamageService
{
private IDamageService _damageServiceImplementation => DamageService.Singleton;
public event Action<DamageMessage> OnEntityDamaged
{
add => _damageServiceImplementation.OnEntityDamaged += value;
remove => _damageServiceImplementation.OnEntityDamaged -= value;
}
public event Action<DamageMessage> OnEntityKilled
{
add => _damageServiceImplementation.OnEntityKilled += value;
remove => _damageServiceImplementation.OnEntityKilled -= value;
}
public void Execute(DamageMessage damageMessage)
{
_damageServiceImplementation.Execute(damageMessage);
}
}
[Serializable]
public class DamageServiceMonoProxy:IDamageService
{
[SerializeField] private MonoBehaviour monoBehaviour;
private IDamageService _damageServiceImplementation=>monoBehaviour as IDamageService;
public event Action<DamageMessage> OnEntityDamaged
{
add => _damageServiceImplementation.OnEntityDamaged += value;
remove => _damageServiceImplementation.OnEntityDamaged -= value;
}
public event Action<DamageMessage> OnEntityKilled
{
add => _damageServiceImplementation.OnEntityKilled += value;
remove => _damageServiceImplementation.OnEntityKilled -= value;
}
public void Execute(DamageMessage damageMessage)
{
_damageServiceImplementation.Execute(damageMessage);
}
}
public record DamageMessage
{
2023-11-06 01:17:23 +08:00
public IUnityEntity Initiator;
public IUnityEntity Target;
2023-10-24 23:38:22 +08:00
public bool RawDamage;
public int Damage;
public IDamagable Hit;
2023-11-30 00:25:43 +08:00
public Vector3 Position;
public Quaternion Rotation;
2023-10-24 23:38:22 +08:00
public IDamageType DamageType;
2024-03-31 23:31:00 +08:00
public RaycastHit? RaycastHit;
}
public sealed class DamageMessageNetMessageWriter : NetMessageReader<DamageMessage>
{
public override DamageMessage ReadBinary(BinaryReader reader)
{
2024-05-31 01:23:15 +08:00
UnityEntitiesService.TryGetEntity(reader.ReadInt32(),out var initiator);
UnityEntitiesService.TryGetEntity(reader.ReadInt32(),out var target);
2024-03-31 23:31:00 +08:00
return new DamageMessage()
{
Initiator = initiator as Entity,
Target = target as Entity,
RawDamage = reader.ReadBoolean(),
Damage = reader.ReadInt32(),
Position = reader.ReadFloat3(),
Rotation = reader.ReadQuaternion(),
};
}
public override void WriteBinary(BinaryWriter writer, DamageMessage value)
{
writer.Write(value.Initiator?.Id ?? 0);
writer.Write(value.Target?.Id ?? 0);
writer.Write(value.RawDamage);
writer.Write(value.Damage);
writer.WriteFloat3(value.Position);
writer.WriteQuaternion(value.Rotation);
}
2023-08-11 23:57:37 +08:00
}
2023-11-15 23:55:06 +08:00
2023-08-11 23:57:37 +08:00
public interface IDamageCallback
{
void OnGetDamage(DamageMessage message);
}
public interface IDamagable
{
2024-04-06 16:33:32 +08:00
string Tag { get; }
2024-03-31 23:31:00 +08:00
IHealth Health { get; }
2023-11-06 01:17:23 +08:00
IUnityEntity UnityEntity { get; }
2023-08-11 23:57:37 +08:00
Rigidbody Rigidbody { get; }
2024-05-31 01:23:15 +08:00
Collider Collider { get; }
2023-08-11 23:57:37 +08:00
void GiveDamage(DamageMessage message);
}
public class DamageService:MonoBehaviour,IDamageService
{
2024-03-31 23:31:00 +08:00
public static IDamageService Singleton { get;private set; }
2023-08-11 23:57:37 +08:00
private readonly Queue<DamageMessage> Messages = new();
2024-03-31 23:31:00 +08:00
[SerializeReference,SubclassSelector] private INetClient netClient;
[SerializeReference,SubclassSelector] private INetServer netServer;
private INetProvider netClientProvider => netClient.Source as INetProvider;
private INetProvider netServerProvider => netServer.Source as INetProvider;
2023-08-11 23:57:37 +08:00
private void Awake()
{
Singleton = this;
}
2024-03-31 23:31:00 +08:00
private void Start()
{
netClientProvider.AddCommandListener<DamageMessage>(ExecuteInternal);
}
2023-08-11 23:57:37 +08:00
private void FixedUpdate()
{
2024-03-31 23:31:00 +08:00
if (!netServer.IsRunningServer && netClient.IsConnected) return;
2023-08-11 23:57:37 +08:00
while (Messages.TryDequeue(out var damageMessage))
{
2023-10-24 23:38:22 +08:00
var unityEntity = (Entity)damageMessage.Target;
2023-11-30 00:25:43 +08:00
if (!unityEntity || !unityEntity.TryGetComponent<IHealth>(out var heal) || !heal.IsAlive) continue;
2023-08-11 23:57:37 +08:00
2024-03-31 23:31:00 +08:00
ExecuteInternal(damageMessage);
netServerProvider?.AllClientCommand(damageMessage);
}
}
private void ExecuteInternal(DamageMessage damageMessage)
{
IHealth heal = null;
if (damageMessage.Target?.TryGetComponent<IHealth>(out heal) is false)
{
return;
}
damageMessage.Initiator?.Invoke(damageMessage);
damageMessage.Target?.Invoke(damageMessage);
if (heal!.IsAlive)
{
2023-08-11 23:57:37 +08:00
OnEntityDamaged?.Invoke(damageMessage);
2024-03-31 23:31:00 +08:00
}
else
{
OnEntityKilled?.Invoke(damageMessage);
2023-08-11 23:57:37 +08:00
}
}
public event Action<DamageMessage> OnEntityDamaged;
public event Action<DamageMessage> OnEntityKilled;
public void Execute(DamageMessage damageMessage)=>Messages.Enqueue(damageMessage);
}
}