using Assets.Scripts.UI; using DefaultNamespace; using DefaultNamespace.Util; using System; using System.Collections.Generic; using System.Text.RegularExpressions; using TMPro; using Trive.Mono.Utils; using Unity.Entities; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.UI; using Zenject; using Object = UnityEngine.Object; namespace UI { [UpdateInGroup(typeof(PresentationSystemGroup)), UpdateBefore(typeof(PlayerCoverSystemWeaponAdjust))] public class ArHudManager : InjectableComponentSystem, IInitializable { [Serializable] public class Settings { public TMP_Text Ammo; public VerticalLayoutGroup AmmoGroup; public GameObject AmmoObj; public Canvas Canvas; public TMP_Text ClipAmmo; public Gradient ClipAmmoColor; public GameObject ClipAmmoObj; public LineRenderer CoverLine; [Range(0, 1)] public float CoverLineAlpha = 0.2f; public TMP_Text Grenades; public GameObject GrenadesObj; public Gradient HealthGradient; public TMP_Text HealthPackCount; public Slider HealthSlider; public RectTransform HeathGroup; public Slider MaxRegenSlider; public HorizontalLayoutGroup SliderGroup; public int SlotCount; public GameObject SlotPrefab; public RectTransform StatusBar; public Vector2 StatusBarOffset; public RectTransform TakeBar; public Vector2 TakeBarOffset; public RectTransform VaultIndicator; public float ZeroesAlpha; } [Inject] private readonly Camera camera; [Inject] private readonly PlayerCoverSystem.Settings coverSystemSettings; [Inject(Id = AssetManifest.HealthKit)] private readonly AssetReferenceT healthKit; [Inject] private readonly ItemPickupSystem.Settings pickupSystemSettings; [Inject] private readonly Settings settings; [Inject] private readonly PlayerVitalsSystem.Settings vitalsSystemSettings; private List CloseItems; private readonly List slotEntries = new List(); [Inject] private PlayerVitalsSystem vitalsSystem; private Regex zeroesRegex; public void Initialize() { zeroesRegex = new Regex("^0+", RegexOptions.Compiled); slotEntries.Add( new SlotPartsData { Amount = settings.SlotPrefab.FindChild("$Amount"), Highlight = settings.SlotPrefab.FindChild("$Highlight"), Icon = settings.SlotPrefab.FindChild("$Icon") }); for (var i = 0; i < settings.SlotCount - 1; i++) { var slotInstance = Object.Instantiate(settings.SlotPrefab, settings.SlotPrefab.transform.parent); slotEntries.Add( new SlotPartsData { Amount = slotInstance.FindChild("$Amount"), Highlight = slotInstance.FindChild("$Highlight"), Icon = slotInstance.FindChild("$Icon") }); } foreach (var slotEntry in slotEntries) { slotEntry.Amount.text = ""; slotEntry.Highlight.enabled = false; slotEntry.Icon.enabled = false; } } protected override void OnCreate() { CloseItems = new List(); } protected override void OnStartRunning() { settings.Canvas.enabled = true; } protected override void OnStopRunning() { if (settings.Canvas != null) { settings.Canvas.enabled = false; } } protected override void OnSystemUpdate() { Entities.WithAllReadOnly() .ForEach( ( Entity entity, ref PlayerData player, ref ActorData actor, ref Rotation2D rotation, ref LocalPlayerData localPlayerData, ref RigidBody2DData rigidBody) => { var parts = EntityManager.GetComponentObject(entity); var facade = EntityManager.GetComponentObject(entity); var inventory = EntityManager.GetBuffer(entity); var healthPacks = inventory.Begin().Where(d => d.Type == SlotType.Health && d.HasItem()).Sum(d => d.Item.Amount); var hasGrenadeSlot = inventory.Begin().Any(d => d.Type == SlotType.Grenade); var grenades = inventory.Begin().FirstOrDefault(s => s.Type == SlotType.Grenade && s.HasItem()).Item.Amount; var healthPercent = Mathf.Clamp01(actor.Health / facade.MaxHealth); var healthColor = settings.HealthGradient.Evaluate(healthPercent); settings.HealthSlider.value = healthPercent; settings.MaxRegenSlider.value = Mathf.Clamp01(vitalsSystemSettings.MaxRegenHealth / facade.MaxHealth); settings.HealthSlider.colors = new ColorBlock { normalColor = healthColor, colorMultiplier = 1 }; settings.GrenadesObj.gameObject.SetActive(hasGrenadeSlot); SetAmountText(settings.Grenades, grenades, "00"); var hasWeapon = EntityManager.HasComponent(entity); settings.AmmoObj.SetActive(hasWeapon); settings.ClipAmmoObj.SetActive(hasWeapon); if (hasWeapon) { var weaponReference = EntityManager.GetComponentData(entity); if (EntityManager.Exists(weaponReference.Weapon) && EntityManager.TryGetComponentData(weaponReference.Weapon, out var weaponData) && EntityManager.TryGetSharedComponentData(weaponReference.Weapon, out var weapon)) { SetAmountText(settings.ClipAmmo, weaponData.ClipAmmo, "00"); settings.ClipAmmo.color = settings.ClipAmmoColor.Evaluate((float)weaponData.ClipAmmo / weapon.Weapon.Data.ClipCapacity); SetAmountText(settings.Ammo, weaponData.Ammo, "000"); } } var leftSide = Mathf.Sign(facade.transform.right.x) > 0; settings.SliderGroup.childAlignment = leftSide ? TextAnchor.LowerLeft : TextAnchor.LowerRight; settings.HeathGroup.SetSiblingIndex(leftSide ? 0 : 1); settings.AmmoGroup.childAlignment = leftSide ? TextAnchor.LowerLeft : TextAnchor.LowerRight; var screenCenter = RectTransformUtility.WorldToScreenPoint(camera, parts.Hip.position); settings.StatusBar.anchoredPosition = screenCenter + Vector2.left * rotation.Axis * (leftSide ? settings.StatusBarOffset.x : settings.StatusBarOffset.y); settings.TakeBar.anchoredPosition = screenCenter + Vector2.left * (leftSide ? settings.TakeBarOffset.x : settings.TakeBarOffset.y); SetAmountText(settings.HealthPackCount, healthPacks, "0"); ManageTakeBar(facade, ref player); ManageCoverUi(entity, rigidBody, actor, rotation, parts, facade); }); } private void ManageCoverUi( Entity entity, RigidBody2DData rigidBody, ActorData actor, Rotation2D rotation, ActorBodyParts parts, PlayerFacade facade) { if (EntityManager.TryGetComponentData(entity, out var raycast)) { float heightOffset; if (EntityManager.TryGetComponentData(entity, out var coverData)) { heightOffset = coverData.WeaponOffset; } else { heightOffset = raycast.TopHit.y + coverSystemSettings.Offset - parts.WeaponContainer.transform.position.y; } var hasCover = EntityManager.HasComponent(entity) && raycast.HadForwardHit && heightOffset > 0 && actor.Grounded && Vector2.Angle(raycast.TopNormal, Vector2.up) <= 22.5f && Vector2.Angle(raycast.ForwardNormal, Vector2.right * rotation.Axis) <= 22.5f; var canVault = EntityManager.HasComponent(entity); settings.CoverLine.positionCount = hasCover ? 4 : 0; settings.VaultIndicator.gameObject.SetActive(canVault); var topRight = new Vector3(raycast.ForwardHit.x, raycast.TopHit.y); Vector3 topLeft = raycast.TopHit; var bottomRight = new Vector3(raycast.ForwardHit.x, raycast.TopHit.y - raycast.Height); var playerFeet = new Vector3(rigidBody.Position.x, raycast.TopHit.y - raycast.Height); if (hasCover) { var healthPercent = Mathf.Clamp01(actor.Health / facade.MaxHealth); var col = settings.HealthGradient.Evaluate(healthPercent); settings.CoverLine.startColor = col * new Color(1, 1, 1, settings.CoverLineAlpha); settings.CoverLine.endColor = col * new Color(1, 1, 1, 0); settings.CoverLine.SetPositions(new[] { topLeft, topRight, bottomRight, playerFeet }); } if (canVault) { var vaultData = EntityManager.GetComponentData(entity); var parent = settings.VaultIndicator.transform.parent as RectTransform; var sizeDelta = settings.VaultIndicator.sizeDelta; var indicatorScreenPos = RectTransformUtility.WorldToScreenPoint(camera, vaultData.VaultPoint); RectTransformUtility.ScreenPointToLocalPointInRectangle(parent, indicatorScreenPos, camera, out var indicatorPos); settings.VaultIndicator.anchoredPosition = indicatorPos + Vector2.down * (8 + sizeDelta.y * 0.5f) + Vector2.left * rotation.Axis * (8 + sizeDelta.x * 0.5f); } } } private void SetAmountText(TMP_Text text, int amount, string format) { var str = amount.ToString(format); if (text.name != str) { text.text = zeroesRegex.Replace(str, m => $"{m.Value}"); text.name = str; } } private void ManageTakeBar(PlayerFacade facade, ref PlayerData player) { var pickupDistanceSqr = pickupSystemSettings.PickupDistance * pickupSystemSettings.PickupDistance; CloseItems.Clear(); Entities.ForEach( (Entity entity, SpriteRenderer renderer, ref ItemContainerData container) => { var d = Vector2.SqrMagnitude(renderer.transform.position - facade.transform.position); if (d <= pickupDistanceSqr) { CloseItems.Add(entity); } }); for (var i = 0; i < CloseItems.Count; i++) { if (i < slotEntries.Count) { var itemEntity = CloseItems[i]; slotEntries[i].Icon.sprite = EntityManager.GetComponentObject(CloseItems[i]).sprite; slotEntries[i].Icon.enabled = true; if (EntityManager.TryGetComponentData(itemEntity, out var itemAmount)) { slotEntries[i].Amount.enabled = true; slotEntries[i].Amount.text = itemAmount.Amount.ToString(); } else { slotEntries[i].Amount.enabled = false; } } } for (var i = 0; i < slotEntries.Count; i++) { slotEntries[i].Highlight.enabled = player.PickupIndex == i; if (i >= CloseItems.Count) { slotEntries[i].Icon.sprite = null; slotEntries[i].Amount.enabled = false; slotEntries[i].Icon.enabled = false; } } settings.TakeBar.gameObject.SetActive(CloseItems.Count > 0); } } }