261 lines
8.9 KiB
C#
261 lines
8.9 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using BITKit;
|
|
using BITKit.Entities;
|
|
using BITKit.Tween;
|
|
using BITKit.UX;
|
|
using Cysharp.Threading.Tasks;
|
|
using Microsoft.Extensions.Logging;
|
|
using Net.Project.B.Emoji;
|
|
using Net.Project.B.Health;
|
|
using Net.Project.B.UX;
|
|
using Project.B.CharacterController;
|
|
using Project.B.Entities;
|
|
using Unity.Mathematics;
|
|
using UnityEngine;
|
|
using UnityEngine.InputSystem;
|
|
using UnityEngine.UIElements;
|
|
using Object = UnityEngine.Object;
|
|
|
|
namespace Net.Like.Xue.Tokyo
|
|
{
|
|
public class GodMode:IDisposable
|
|
{
|
|
private readonly IUXHud _hud;
|
|
private readonly IEntitiesService _entitiesService;
|
|
private readonly IHealthService _healthService;
|
|
private readonly IMainTicker _ticker;
|
|
private readonly IAfterTicker _afterTicker;
|
|
private readonly ValidHandle _allow = new();
|
|
private readonly ILogger<GodMode> _logger;
|
|
private readonly IPlayerFactory _playerFactory;
|
|
|
|
private readonly ScriptableYangdunData _data;
|
|
private bool _allowGodMode;
|
|
private bool _allowNfc;
|
|
|
|
[UXBindPath("god_mode-banner")]
|
|
private VisualElement _godModeBanner;
|
|
[UXBindPath("nfc-texture")]
|
|
private VisualElement _nfcTexture;
|
|
[UXBindPath("game_over-banner")]
|
|
private VisualElement _gameOverBanner;
|
|
|
|
private readonly List<Transform> _followVfx=new();
|
|
|
|
private int _currentNfcIndex;
|
|
|
|
public GodMode(IMainTicker ticker, IHealthService healthService, ILogger<GodMode> logger, IEntitiesService entitiesService, IUXHud hud, IAfterTicker afterTicker, IPlayerFactory playerFactory)
|
|
{
|
|
_ticker = ticker;
|
|
_healthService = healthService;
|
|
_logger = logger;
|
|
_entitiesService = entitiesService;
|
|
_hud = hud;
|
|
_afterTicker = afterTicker;
|
|
_playerFactory = playerFactory;
|
|
|
|
_ticker.Add(OnTick);
|
|
_afterTicker.Add(AfterTick);
|
|
|
|
_healthService.OnHealthPlus += OnHealthPlus;
|
|
|
|
_allow.AddListener(OnAllow);
|
|
|
|
_data = _entitiesService.QueryComponents<ScriptableYangdunData>()[0];
|
|
|
|
_hud.OnInitiated += OnInitiated;
|
|
|
|
_playerFactory.OnEntityCreated += OnEntityCreated;
|
|
|
|
}
|
|
|
|
private UniTask OnEntityCreated(string arg1, IEntity arg2)
|
|
{
|
|
|
|
arg2.ServiceProvider.QueryComponents(out IHealthComponent healthComponent);
|
|
|
|
healthComponent.OnHealthChanged += OnHealthChanged;
|
|
|
|
return UniTask.CompletedTask;
|
|
}
|
|
|
|
private void OnHealthChanged(int arg1, int arg2)
|
|
{
|
|
_gameOverBanner.SetActive(arg2<0);
|
|
_hud.InCinematicMode.SetDisableElements(this,arg2<0);
|
|
}
|
|
|
|
private void AfterTick(float obj)
|
|
{
|
|
if(!_allowNfc)return;
|
|
|
|
|
|
foreach (var (_,characterController) in _entitiesService.QueryComponents<LocalPlayerComponent,ICharacterController>())
|
|
{
|
|
_nfcTexture.SetPosition(characterController.Position + new float3(0,characterController.Height,0));
|
|
}
|
|
}
|
|
|
|
private void OnInitiated()
|
|
{
|
|
if(_hud is not UIToolKitPanel panel)return;
|
|
UXUtils.Inject(this,panel.RootVisualElement);
|
|
|
|
_godModeBanner.RemoveFromClassList("active");
|
|
_godModeBanner.SetActive(false);
|
|
|
|
_gameOverBanner.SetActive(false);
|
|
_hud.InCinematicMode.RemoveElement(this);
|
|
|
|
_nfcTexture.schedule.Execute(() =>
|
|
{
|
|
if (!_allowNfc)return;
|
|
_nfcTexture.style.backgroundImage = new(_data.NfcSprites[_currentNfcIndex++%_data.NfcSprites.Length]);
|
|
}).Every(41);
|
|
_nfcTexture.SetActive(false);
|
|
}
|
|
|
|
private void OnAllow(bool allow)
|
|
{
|
|
_logger.LogInformation(allow ? "开启无敌" : "关闭无敌");
|
|
|
|
_godModeBanner.SetActive(allow);
|
|
|
|
_godModeBanner.EnableInClassList("active",allow);
|
|
|
|
_nfcTexture.SetActive(_allowNfc=false);
|
|
|
|
if (!allow)
|
|
{
|
|
foreach (var transform in _followVfx)
|
|
{
|
|
Object.Destroy(transform.gameObject);
|
|
}
|
|
_followVfx.Clear();
|
|
return;
|
|
}
|
|
|
|
|
|
foreach (var (_, emojiService,gameObject,characterController) in _entitiesService
|
|
.QueryComponents<LocalPlayerComponent, IEmojiService<AnimationClip>,GameObject,ICharacterController>())
|
|
{
|
|
emojiService.Play(new EmojiData<AnimationClip>()
|
|
{
|
|
Clip = _data.BoostAnimation
|
|
});
|
|
|
|
{
|
|
var groundVfx = Object.Instantiate(_data.GroundVfx.gameObject, characterController.Position,characterController.Rotation);
|
|
|
|
{
|
|
if (groundVfx.TryGetComponent<ParticleSystem>(out var vfx))
|
|
{
|
|
vfx.Play(true);
|
|
}
|
|
}
|
|
|
|
DestroyAfter(groundVfx.transform, 3);
|
|
}
|
|
{
|
|
gameObject.TryGetComponent<Animator>(out var animator);
|
|
|
|
foreach (var (humanBone,particleSystems) in _data.BoneVfx)
|
|
{
|
|
var bone = animator.GetBoneTransform(humanBone);
|
|
|
|
if (!bone)
|
|
{
|
|
_logger.LogWarning($"在{animator.gameObject.name}上没有找到骨骼:{humanBone}");
|
|
continue;
|
|
}
|
|
foreach (var particleSystem in particleSystems)
|
|
{
|
|
var bodyVfx = Object.Instantiate(particleSystem.gameObject, bone.position, bone.rotation);
|
|
|
|
if (!bodyVfx.TryGetComponent<ParticleSystem>(out var vfx)) continue;
|
|
vfx.Play(true);
|
|
|
|
DestroyAfter(bodyVfx.transform,5);
|
|
|
|
//vfx.Stop(withChildren: true, stopBehavior: ParticleSystemStopBehavior.StopEmitting);
|
|
}
|
|
}
|
|
|
|
foreach (var (humanBone,particleSystems) in _data.FollowVfx)
|
|
{
|
|
var bone = animator.GetBoneTransform(humanBone);
|
|
|
|
if (!bone)
|
|
{
|
|
_logger.LogWarning($"在{animator.gameObject.name}上没有找到骨骼:{humanBone}");
|
|
continue;
|
|
}
|
|
foreach (var particleSystem in particleSystems)
|
|
{
|
|
var bodyVfx = Object.Instantiate(particleSystem.gameObject, bone.position, bone.rotation);
|
|
|
|
bodyVfx.transform.SetParentConstraint(bone);
|
|
|
|
if (!bodyVfx.TryGetComponent<ParticleSystem>(out var vfx)) continue;
|
|
vfx.Play(true);
|
|
|
|
_followVfx.Add(bodyVfx.transform);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private int OnHealthPlus(int arg1, int arg2, int arg3, object arg4)
|
|
{
|
|
if (_allow.Allow)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return arg3;
|
|
}
|
|
|
|
protected virtual async void DestroyAfter(Transform transform,float time)
|
|
{
|
|
try
|
|
{
|
|
var ct = transform.GetCancellationTokenOnDestroy();
|
|
|
|
await UniTask.Delay(TimeSpan.FromSeconds(time),cancellationToken: ct);
|
|
|
|
await BITween.Lerp(x => transform.localScale = x, Vector3.one, default, 1, Vector3.Lerp, ct);
|
|
|
|
Object.Destroy(transform.gameObject);
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
}
|
|
}
|
|
|
|
private void OnTick(float obj)
|
|
{
|
|
if (Keyboard.current is { homeKey: { wasPressedThisFrame: true } })
|
|
{
|
|
_allow.SetElements(this,_allowGodMode=!_allowGodMode);
|
|
}
|
|
|
|
if (Keyboard.current is { endKey: { wasPressedThisFrame: true } })
|
|
{
|
|
_nfcTexture.SetActive(_allowNfc=!_allowNfc);
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_ticker.Remove(OnTick);
|
|
_afterTicker.Remove(AfterTick);
|
|
}
|
|
}
|
|
|
|
}
|
|
|