Files
Net.Like.Xue.Tokyo/Packages-Local/Com.Project.B.Unity/Melee/UnityMeleeService.cs

124 lines
3.8 KiB
C#
Raw Normal View History

2025-06-24 23:49:13 +08:00
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);
}
}
}