using System; using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; using BITKit; using BITKit.SubSystems; using BITKit.Entities; namespace BITKit.Entities { public interface IDamageType { } public interface IDamageService { public event Action OnEntityDamaged; public event Action OnEntityKilled; void Execute(DamageMessage damageMessage); } public struct MeleeDamageMessage : IDamageType { public bool Bleeding; } public struct BulletDamageMessage:IDamageType{} [Serializable] public class DamageServiceSingleton:IDamageService { private IDamageService _damageServiceImplementation => DamageService.Singleton; public event Action OnEntityDamaged { add => _damageServiceImplementation.OnEntityDamaged += value; remove => _damageServiceImplementation.OnEntityDamaged -= value; } public event Action 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 OnEntityDamaged { add => _damageServiceImplementation.OnEntityDamaged += value; remove => _damageServiceImplementation.OnEntityDamaged -= value; } public event Action OnEntityKilled { add => _damageServiceImplementation.OnEntityKilled += value; remove => _damageServiceImplementation.OnEntityKilled -= value; } public void Execute(DamageMessage damageMessage) { _damageServiceImplementation.Execute(damageMessage); } } public record DamageMessage { public IUnityEntity Initiator; public IUnityEntity Target; public bool RawDamage; public int Damage; public IDamagable Hit; public Vector3 Position; public Quaternion Rotation; public IDamageType DamageType; public RaycastHit? RaycastHit; } public sealed class DamageMessageNetMessageWriter : NetMessageReader { public override DamageMessage ReadBinary(BinaryReader reader) { UnityEntitiesService.TryGetEntity(reader.ReadUInt64(),out var initiator); UnityEntitiesService.TryGetEntity(reader.ReadUInt64(),out var target); 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); } } public interface IDamageCallback { void OnGetDamage(DamageMessage message); } public interface IDamagable { IHealth Health { get; } IUnityEntity UnityEntity { get; } Rigidbody Rigidbody { get; } void GiveDamage(DamageMessage message); } public class DamageService:MonoBehaviour,IDamageService { internal static IDamageService Singleton { get; set; } private readonly Queue Messages = new(); [SerializeReference,SubclassSelector] private INetClient netClient; [SerializeReference,SubclassSelector] private INetServer netServer; private INetProvider netClientProvider => netClient.Source as INetProvider; private INetProvider netServerProvider => netServer.Source as INetProvider; private void Awake() { Singleton = this; } private void Start() { netClientProvider.AddCommandListener(ExecuteInternal); } private void FixedUpdate() { if (!netServer.IsRunningServer && netClient.IsConnected) return; while (Messages.TryDequeue(out var damageMessage)) { var unityEntity = (Entity)damageMessage.Target; if (!unityEntity || !unityEntity.TryGetComponent(out var heal) || !heal.IsAlive) continue; ExecuteInternal(damageMessage); netServerProvider?.AllClientCommand(damageMessage); } } private void ExecuteInternal(DamageMessage damageMessage) { IHealth heal = null; if (damageMessage.Target?.TryGetComponent(out heal) is false) { return; } damageMessage.Initiator?.Invoke(damageMessage); damageMessage.Target?.Invoke(damageMessage); if (heal!.IsAlive) { OnEntityDamaged?.Invoke(damageMessage); } else { OnEntityKilled?.Invoke(damageMessage); } } public event Action OnEntityDamaged; public event Action OnEntityKilled; public void Execute(DamageMessage damageMessage)=>Messages.Enqueue(damageMessage); } }