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 _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 _followVfx=new(); private int _currentNfcIndex; public GodMode(IMainTicker ticker, IHealthService healthService, ILogger 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()[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()) { _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,GameObject,ICharacterController>()) { emojiService.Play(new EmojiData() { Clip = _data.BoostAnimation }); { var groundVfx = Object.Instantiate(_data.GroundVfx.gameObject, characterController.Position,characterController.Rotation); { if (groundVfx.TryGetComponent(out var vfx)) { vfx.Play(true); } } DestroyAfter(groundVfx.transform, 3); } { gameObject.TryGetComponent(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(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(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); } } }