Aetheria/Assets/Scripts/Gameplay/ActionBarSlot.cs

278 lines
7.6 KiB
C#
Raw Normal View History

using System;
using System.Linq;
2026-06-21 09:54:15 +01:00
using GameCult.Aetheria.State.Verse;
2026-06-30 19:14:49 +01:00
using GameCult.Mesh;
using TMPro;
using UniRx.Triggers;
using UnityEngine;
using UnityEngine.UI;
public class ActionBarSlot : MonoBehaviour
{
public TextMeshProUGUI Label;
public RawImage Icon;
public TextMeshProUGUI InputLabel;
public Image InputIcon;
public TextMeshProUGUI QuantityRemaining;
public Image Fill;
public ObservablePointerEnterTrigger PointerEnterTrigger;
public ObservablePointerExitTrigger PointerExitTrigger;
private ActionBarBinding binding;
public string ControlPath { get; set; }
public ActionBarBinding Binding
{
get => binding;
set
{
if (ReferenceEquals(binding, value))
return;
binding = value;
if (binding == null)
{
Fill.fillAmount = 0;
Label.gameObject.SetActive(false);
QuantityRemaining.gameObject.SetActive(false);
Icon.gameObject.SetActive(false);
}
}
}
private void OnDestroy()
{
Binding = null;
}
private void Update()
{
Binding?.Update();
}
}
public abstract class ActionBarBinding
{
2026-06-30 19:14:49 +01:00
private static AetheriaClientState s_runtimeState;
public Entity Entity { get; }
2026-06-29 06:30:24 +01:00
private readonly Func<AetheriaControl> _resolveControl;
protected ActionBarSlot Slot { get; }
2026-06-25 18:09:33 +01:00
protected GameSettings Settings { get; }
public abstract void Activate();
public abstract void Deactivate();
public abstract void Update();
2026-06-25 18:09:33 +01:00
2026-06-29 06:30:24 +01:00
protected ActionBarBinding(
Entity entity,
ActionBarSlot slot,
Func<AetheriaControl> resolveControl,
GameSettings settings)
{
Entity = entity;
Slot = slot;
2026-06-29 06:30:24 +01:00
_resolveControl = resolveControl ?? (() => null);
2026-06-25 18:09:33 +01:00
Settings = settings;
}
protected bool TrySubmit(Action<AetheriaControl> submit, string label)
{
2026-06-29 06:30:24 +01:00
if (submit == null)
2026-06-25 18:09:33 +01:00
return false;
try
{
2026-06-29 06:30:24 +01:00
var control = _resolveControl();
if (control == null)
return false;
submit(control);
2026-06-25 18:09:33 +01:00
return true;
}
catch (Exception ex)
{
Debug.LogWarning($"Failed to send Aetheria daemon action-bar {label} operation; operation not submitted: {ex.Message}");
return false;
}
}
protected AetheriaRuntimeCatalogItem FindCatalogItem(ItemInstance item)
{
try
{
2026-06-30 19:14:49 +01:00
s_runtimeState ??= AetheriaUnityRuntimeClientProvider.RuntimeState("unity-action-bar");
return s_runtimeState.Catalog.Latest()?.FindItem(item, x => x.ItemKey);
2026-06-25 18:09:33 +01:00
}
catch (Exception ex)
{
Debug.LogWarning($"Failed to bind Aetheria runtime catalog for action-bar binding: {ex.Message}");
2026-06-25 18:09:33 +01:00
return null;
}
}
}
public class ActionBarConsumableBinding : ActionBarBinding
{
public AetheriaRuntimeCatalogItem Target { get; }
public ActionBarConsumableBinding(
Entity entity,
ActionBarSlot slot,
2026-06-29 06:30:24 +01:00
Func<AetheriaControl> resolveControl,
2026-06-25 18:09:33 +01:00
GameSettings settings,
2026-06-29 06:30:24 +01:00
AetheriaRuntimeCatalogItem target) : base(entity, slot, resolveControl, settings)
{
Target = target;
Slot.QuantityRemaining.gameObject.SetActive(true);
Slot.Label.gameObject.SetActive(false);
Slot.Icon.gameObject.SetActive(false);
}
public override void Activate()
{
2026-06-25 18:09:33 +01:00
TrySubmit(
operations => operations.ActivateConsumable(TargetItemKey),
"consumable");
}
public override void Deactivate()
{
}
public override void Update()
{
2026-06-14 23:09:49 +01:00
Slot.QuantityRemaining.text = $"{Entity.CountItemsInCargo(TargetItemKey)}";
if (string.IsNullOrWhiteSpace(TargetItemKey))
{
Slot.Fill.fillAmount = 0;
return;
}
2026-06-14 23:09:49 +01:00
var instance = Entity.FindActiveConsumable(TargetItemKey);
if (instance == null) Slot.Fill.fillAmount = 0;
else Slot.Fill.fillAmount = instance.RemainingDuration / instance.Duration;
}
public string TargetItemKey => Target?.ItemKey ?? "";
}
public class ActionBarGearBinding : ActionBarBinding
{
public EquippedItem Item { get; }
public IActivatedBehavior Behavior { get; }
public bool Active;
public int EquipmentIndex => Entity?.Equipment?.IndexOf(Item) ?? -1;
public int BehaviorIndex => Item?.Behaviors == null ? -1 : Array.IndexOf(Item.Behaviors, Behavior);
public string TargetItemKey => Item?.EquippableItem?.ItemKey ?? "";
2026-06-25 18:09:33 +01:00
public ActionBarGearBinding(
Entity entity,
ActionBarSlot slot,
2026-06-29 06:30:24 +01:00
Func<AetheriaControl> resolveControl,
2026-06-25 18:09:33 +01:00
GameSettings settings,
EquippedItem item,
2026-06-29 06:30:24 +01:00
IActivatedBehavior behavior) : base(entity, slot, resolveControl, settings)
{
Item = item;
Behavior = behavior;
Slot.QuantityRemaining.gameObject.SetActive(false);
Slot.Icon.gameObject.SetActive(true);
Slot.Label.gameObject.SetActive(false);
2026-06-14 06:47:47 +01:00
Slot.Icon.texture = ResolveIconTexture();
}
private Texture2D ResolveIconTexture()
{
2026-06-25 18:09:33 +01:00
var typedItem = FindCatalogItem(Item.EquippableItem);
if (typedItem != null)
{
2026-06-14 06:47:47 +01:00
var actionBarIcon = LoadActionBarIcon(typedItem.ActionBarIcon);
if (actionBarIcon != null)
return actionBarIcon;
if (Enum.TryParse<WeaponType>(typedItem.WeaponType, out var weaponType))
2026-06-25 18:09:33 +01:00
return Settings.GetIcon(weaponType).texture;
if (Enum.TryParse<HardpointType>(typedItem.HardpointType, out var hardpointType))
2026-06-25 18:09:33 +01:00
return Settings.GetIcon(hardpointType).texture;
}
2026-06-25 18:09:33 +01:00
return Settings.GetIcon(HardpointType.Tool).texture;
}
2026-06-14 06:47:47 +01:00
private static Texture2D LoadActionBarIcon(string path)
{
if (string.IsNullOrWhiteSpace(path))
return null;
const string resourcesPrefix = "Assets/Resources/";
var resourcePath = path.StartsWith(resourcesPrefix, StringComparison.Ordinal)
? path.Substring(resourcesPrefix.Length)
: path;
resourcePath = resourcePath.Split('.').First();
return Resources.Load<Texture2D>(resourcePath);
}
public override void Activate()
{
Active = true;
2026-06-25 18:09:33 +01:00
TrySubmit(
operations => operations.SetBehaviorActive(EquipmentIndex, BehaviorIndex, true),
"behavior activation");
}
public override void Deactivate()
{
Active = false;
2026-06-25 18:09:33 +01:00
TrySubmit(
operations => operations.SetBehaviorActive(EquipmentIndex, BehaviorIndex, false),
"behavior activation");
}
public override void Update()
{
Slot.Fill.fillAmount = Active ? 1 : 0;
}
}
public class ActionBarWeaponGroupBinding : ActionBarBinding
{
2026-06-13 05:39:06 +01:00
public int Group;
2026-06-25 18:09:33 +01:00
public ActionBarWeaponGroupBinding(
Entity entity,
ActionBarSlot slot,
2026-06-29 06:30:24 +01:00
Func<AetheriaControl> resolveControl,
2026-06-25 18:09:33 +01:00
GameSettings settings,
2026-06-29 06:30:24 +01:00
int group) : base(entity, slot, resolveControl, settings)
{
Group = group;
slot.Label.gameObject.SetActive(true);
slot.Label.text = $"G{Group+1}";
Slot.Icon.gameObject.SetActive(false);
}
public override void Activate()
{
2026-06-25 18:09:33 +01:00
TrySubmit(
operations => operations.SetWeaponGroupActive(Group, true),
"weapon-group");
}
public override void Deactivate()
{
2026-06-25 18:09:33 +01:00
TrySubmit(
operations => operations.SetWeaponGroupActive(Group, false),
"weapon-group");
}
public override void Update()
{
2026-06-13 04:56:50 +01:00
}
2026-06-13 05:39:06 +01:00
}