124 lines
3.8 KiB
C#
124 lines
3.8 KiB
C#
![]() |
using System;
|
||
|
using System.Buffers;
|
||
|
using System.Collections;
|
||
|
using System.Collections.Concurrent;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Linq;
|
||
|
using BITKit;
|
||
|
using BITKit.Entities;
|
||
|
using BITKit.Pool;
|
||
|
using Cysharp.Threading.Tasks;
|
||
|
using Microsoft.Extensions.DependencyInjection;
|
||
|
using Net.BITKit.VFX;
|
||
|
using Net.Project.B.Damage;
|
||
|
using UnityEngine;
|
||
|
|
||
|
namespace Net.Project.B.Melee
|
||
|
{
|
||
|
public class UnityMeleeService : IMeleeService,IDisposable
|
||
|
{
|
||
|
private readonly ITicker _ticker;
|
||
|
|
||
|
private readonly IDamageService _damageService;
|
||
|
|
||
|
private readonly IPoolService _poolService;
|
||
|
|
||
|
private readonly VFXService _vfxService;
|
||
|
|
||
|
private readonly IEntitiesService _entitiesService;
|
||
|
|
||
|
private readonly ConcurrentQueue<IMeleeData> _melees=new();
|
||
|
|
||
|
private readonly LayerMask _detectedLayer = LayerMask.GetMask("Entities");
|
||
|
|
||
|
private readonly LayerMask _obstacleLayer = LayerMask.GetMask("Default");
|
||
|
|
||
|
private readonly Collider[] _colliders=new Collider[64];
|
||
|
|
||
|
public UnityMeleeService(ITicker ticker, IDamageService damageService, IEntitiesService entitiesService, IPoolService poolService, VFXService vfxService)
|
||
|
{
|
||
|
_ticker = ticker;
|
||
|
_damageService = damageService;
|
||
|
_entitiesService = entitiesService;
|
||
|
_poolService = poolService;
|
||
|
_vfxService = vfxService;
|
||
|
|
||
|
_ticker.Add(OnTick);
|
||
|
}
|
||
|
|
||
|
private async void OnTick(float obj)
|
||
|
{
|
||
|
if (_melees.TryDequeue(out var melee) is false) return;
|
||
|
|
||
|
var length = Physics.OverlapSphereNonAlloc(melee.StartPosition, melee.Radius, _colliders, _detectedLayer);
|
||
|
|
||
|
var damagedCount = 0;
|
||
|
|
||
|
for (var i = 0; i < length; i++)
|
||
|
{
|
||
|
var collider = _colliders[i];
|
||
|
if (Physics.Raycast(melee.StartPosition, collider.transform.position - (Vector3)melee.StartPosition,
|
||
|
out var hit,
|
||
|
melee.Radius, _obstacleLayer))
|
||
|
{
|
||
|
if (hit.collider != collider)
|
||
|
{
|
||
|
// continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (_entitiesService.TryGetEntity(collider.gameObject.GetInstanceID(), out var entity) is false)
|
||
|
continue;
|
||
|
|
||
|
if (entity.Id == melee.Initiator) continue;
|
||
|
|
||
|
if (entity.ServiceProvider.GetService<ITag>() is not { } tags) continue;
|
||
|
|
||
|
var targetTags = tags.Tags;
|
||
|
|
||
|
|
||
|
|
||
|
if (melee.IgnoreTags.Count > 0)
|
||
|
{
|
||
|
if (melee.IgnoreTags.Intersect(targetTags).Any()) continue;
|
||
|
}
|
||
|
|
||
|
if (melee.Tags.Count > 0)
|
||
|
{
|
||
|
if (tags.Tags.Intersect(targetTags).Any() is false) continue;
|
||
|
}
|
||
|
|
||
|
var array = ArrayPool<string>.Shared.Rent(targetTags.Count + 1);
|
||
|
|
||
|
var index = 1;
|
||
|
foreach (var x in targetTags)
|
||
|
{
|
||
|
array[index++] = x;
|
||
|
}
|
||
|
|
||
|
array[0] = "melee";
|
||
|
|
||
|
var vfx = _vfxService.GetPrefab(array).gameObject;
|
||
|
vfx = await _poolService.Spawn<GameObject>(vfx.name, vfx);
|
||
|
|
||
|
var closestPoint = collider.ClosestPoint(melee.StartPosition);
|
||
|
|
||
|
vfx.transform.position = closestPoint;
|
||
|
|
||
|
_damageService.CreateDamageAsync(melee.Initiator, entity.Id, melee.Damage, melee,melee.StartPosition).Forget();
|
||
|
|
||
|
ArrayPool<string>.Shared.Return(array);
|
||
|
|
||
|
if (damagedCount++ >= melee.MaxTargetCount) return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void Add(IMeleeData meleeData) => _melees.Enqueue(meleeData);
|
||
|
public void Dispose()
|
||
|
{
|
||
|
_ticker.Remove(OnTick);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|