Actions System + UI (#2710)
Co-authored-by: Vera Aguilera Puerto <6766154+Zumorica@users.noreply.github.com>
This commit is contained in:
@@ -1,25 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Client.UserInterface.Stylesheets;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.GameObjects.Components.Mobs;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Interfaces.Graphics;
|
||||
using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Client.Interfaces.UserInterface;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Mobs
|
||||
@@ -29,19 +24,11 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
[ComponentReference(typeof(SharedAlertsComponent))]
|
||||
public sealed class ClientAlertsComponent : SharedAlertsComponent
|
||||
{
|
||||
private static readonly float TooltipTextMaxWidth = 265;
|
||||
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
private AlertsUI _ui;
|
||||
private PanelContainer _tooltip;
|
||||
private RichTextLabel _stateName;
|
||||
private RichTextLabel _stateDescription;
|
||||
private RichTextLabel _stateCooldown;
|
||||
private AlertOrderPrototype _alertOrder;
|
||||
private bool _tooltipReady;
|
||||
|
||||
[ViewVariables]
|
||||
private readonly Dictionary<AlertKey, AlertControl> _alertControls
|
||||
@@ -49,7 +36,6 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
|
||||
/// <summary>
|
||||
/// Allows calculating if we need to act due to this component being controlled by the current mob
|
||||
/// TODO: should be revisited after space-wizards/RobustToolbox#1255
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
private bool CurrentlyControlled => _playerManager.LocalPlayer != null && _playerManager.LocalPlayer.ControlledEntity == Owner;
|
||||
@@ -78,14 +64,11 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
{
|
||||
base.HandleComponentState(curState, nextState);
|
||||
|
||||
if (curState is not AlertsComponentState state)
|
||||
if (curState is not AlertsComponentState)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// update the dict of states based on the array we got in the message
|
||||
SetAlerts(state.Alerts);
|
||||
|
||||
UpdateAlertsControls();
|
||||
}
|
||||
|
||||
@@ -102,48 +85,24 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
Logger.ErrorS("alert", "no alertOrder prototype found, alerts will be in random order");
|
||||
}
|
||||
|
||||
_ui = new AlertsUI(IoCManager.Resolve<IClyde>());
|
||||
var uiManager = IoCManager.Resolve<IUserInterfaceManager>();
|
||||
uiManager.StateRoot.AddChild(_ui);
|
||||
|
||||
_tooltip = new PanelContainer
|
||||
{
|
||||
Visible = false,
|
||||
StyleClasses = { StyleNano.StyleClassTooltipPanel }
|
||||
};
|
||||
var tooltipVBox = new VBoxContainer
|
||||
{
|
||||
RectClipContent = true
|
||||
};
|
||||
_tooltip.AddChild(tooltipVBox);
|
||||
_stateName = new RichTextLabel
|
||||
{
|
||||
MaxWidth = TooltipTextMaxWidth,
|
||||
StyleClasses = { StyleNano.StyleClassTooltipAlertTitle }
|
||||
};
|
||||
tooltipVBox.AddChild(_stateName);
|
||||
_stateDescription = new RichTextLabel
|
||||
{
|
||||
MaxWidth = TooltipTextMaxWidth,
|
||||
StyleClasses = { StyleNano.StyleClassTooltipAlertDescription }
|
||||
};
|
||||
tooltipVBox.AddChild(_stateDescription);
|
||||
_stateCooldown = new RichTextLabel
|
||||
{
|
||||
MaxWidth = TooltipTextMaxWidth,
|
||||
StyleClasses = { StyleNano.StyleClassTooltipAlertCooldown }
|
||||
};
|
||||
tooltipVBox.AddChild(_stateCooldown);
|
||||
|
||||
uiManager.PopupRoot.AddChild(_tooltip);
|
||||
_ui = new AlertsUI();
|
||||
IoCManager.Resolve<IUserInterfaceManager>().StateRoot.AddChild(_ui);
|
||||
|
||||
UpdateAlertsControls();
|
||||
}
|
||||
|
||||
private void PlayerDetached()
|
||||
{
|
||||
_ui?.Dispose();
|
||||
_ui = null;
|
||||
foreach (var alertControl in _alertControls.Values)
|
||||
{
|
||||
alertControl.OnPressed -= AlertControlOnPressed;
|
||||
}
|
||||
|
||||
if (_ui != null)
|
||||
{
|
||||
IoCManager.Resolve<IUserInterfaceManager>().StateRoot.RemoveChild(_ui);
|
||||
_ui = null;
|
||||
}
|
||||
_alertControls.Clear();
|
||||
}
|
||||
|
||||
@@ -168,39 +127,49 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
toRemove.Add(existingKey);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var alertKeyToRemove in toRemove)
|
||||
{
|
||||
// remove and dispose the control
|
||||
_alertControls.Remove(alertKeyToRemove, out var control);
|
||||
control?.Dispose();
|
||||
if (control == null) return;
|
||||
_ui.Grid.Children.Remove(control);
|
||||
}
|
||||
|
||||
// now we know that alertControls contains alerts that should still exist but
|
||||
// may need to updated,
|
||||
// also there may be some new alerts we need to show.
|
||||
// further, we need to ensure they are ordered w.r.t their configured order
|
||||
foreach (var alertStatus in EnumerateAlertStates())
|
||||
foreach (var (alertKey, alertState) in EnumerateAlertStates())
|
||||
{
|
||||
if (!AlertManager.TryDecode(alertStatus.AlertEncoded, out var newAlert))
|
||||
if (!alertKey.AlertType.HasValue)
|
||||
{
|
||||
Logger.ErrorS("alert", "Unable to decode alert {0}", alertStatus.AlertEncoded);
|
||||
Logger.WarningS("alert", "found alertkey without alerttype," +
|
||||
" alert keys should never be stored without an alerttype set: {0}", alertKey);
|
||||
continue;
|
||||
}
|
||||
var alertType = alertKey.AlertType.Value;
|
||||
if (!AlertManager.TryGet(alertType, out var newAlert))
|
||||
{
|
||||
Logger.ErrorS("alert", "Unrecognized alertType {0}", alertType);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_alertControls.TryGetValue(newAlert.AlertKey, out var existingAlertControl) &&
|
||||
existingAlertControl.Alert.AlertType == newAlert.AlertType)
|
||||
{
|
||||
// id is the same, simply update the existing control severity
|
||||
existingAlertControl.SetSeverity(alertStatus.Severity);
|
||||
// key is the same, simply update the existing control severity / cooldown
|
||||
existingAlertControl.SetSeverity(alertState.Severity);
|
||||
existingAlertControl.Cooldown = alertState.Cooldown;
|
||||
}
|
||||
else
|
||||
{
|
||||
existingAlertControl?.Dispose();
|
||||
if (existingAlertControl != null)
|
||||
{
|
||||
_ui.Grid.Children.Remove(existingAlertControl);
|
||||
}
|
||||
|
||||
// this is a new alert + alert key or just a different alert with the same
|
||||
// key, create the control and add it in the appropriate order
|
||||
var newAlertControl = CreateAlertControl(newAlert, alertStatus);
|
||||
var newAlertControl = CreateAlertControl(newAlert, alertState);
|
||||
if (_alertOrder != null)
|
||||
{
|
||||
var added = false;
|
||||
@@ -233,14 +202,11 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
|
||||
private AlertControl CreateAlertControl(AlertPrototype alert, AlertState alertState)
|
||||
{
|
||||
|
||||
var alertControl = new AlertControl(alert, alertState.Severity, _resourceCache);
|
||||
// show custom tooltip for the status control
|
||||
alertControl.OnShowTooltip += AlertOnOnShowTooltip;
|
||||
alertControl.OnHideTooltip += AlertOnOnHideTooltip;
|
||||
|
||||
var alertControl = new AlertControl(alert, alertState.Severity, _resourceCache)
|
||||
{
|
||||
Cooldown = alertState.Cooldown
|
||||
};
|
||||
alertControl.OnPressed += AlertControlOnPressed;
|
||||
|
||||
return alertControl;
|
||||
}
|
||||
|
||||
@@ -249,36 +215,6 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
AlertPressed(args, args.Button as AlertControl);
|
||||
}
|
||||
|
||||
private void AlertOnOnHideTooltip(object sender, EventArgs e)
|
||||
{
|
||||
_tooltipReady = false;
|
||||
_tooltip.Visible = false;
|
||||
}
|
||||
|
||||
private void AlertOnOnShowTooltip(object sender, EventArgs e)
|
||||
{
|
||||
var alertControl = (AlertControl) sender;
|
||||
_stateName.SetMessage(alertControl.Alert.Name);
|
||||
_stateDescription.SetMessage(alertControl.Alert.Description);
|
||||
// check for a cooldown
|
||||
if (alertControl.TotalDuration != null && alertControl.TotalDuration > 0)
|
||||
{
|
||||
_stateCooldown.SetMessage(FormattedMessage.FromMarkup("[color=#776a6a]" +
|
||||
alertControl.TotalDuration +
|
||||
" sec cooldown[/color]"));
|
||||
_stateCooldown.Visible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_stateCooldown.Visible = false;
|
||||
}
|
||||
// TODO: Text display of cooldown
|
||||
Tooltips.PositionTooltip(_tooltip);
|
||||
// if we set it visible here the size of the previous tooltip will flicker for a frame,
|
||||
// so instead we wait until FrameUpdate to make it visible
|
||||
_tooltipReady = true;
|
||||
}
|
||||
|
||||
private void AlertPressed(BaseButton.ButtonEventArgs args, AlertControl alert)
|
||||
{
|
||||
if (args.Event.Function != EngineKeyFunctions.UIClick)
|
||||
@@ -286,57 +222,17 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
return;
|
||||
}
|
||||
|
||||
if (AlertManager.TryEncode(alert.Alert, out var encoded))
|
||||
{
|
||||
SendNetworkMessage(new ClickAlertMessage(encoded));
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.ErrorS("alert", "unable to encode alert {0}", alert.Alert.AlertType);
|
||||
}
|
||||
|
||||
SendNetworkMessage(new ClickAlertMessage(alert.Alert.AlertType));
|
||||
}
|
||||
|
||||
public void FrameUpdate(float frameTime)
|
||||
protected override void AfterShowAlert()
|
||||
{
|
||||
if (_tooltipReady)
|
||||
{
|
||||
_tooltipReady = false;
|
||||
_tooltip.Visible = true;
|
||||
}
|
||||
foreach (var (alertKey, alertControl) in _alertControls)
|
||||
{
|
||||
// reconcile all alert controls with their current cooldowns
|
||||
if (TryGetAlertState(alertKey, out var alertState))
|
||||
{
|
||||
alertControl.UpdateCooldown(alertState.Cooldown, _gameTiming.CurTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.WarningS("alert", "coding error - no alert state for alert {0} " +
|
||||
"even though we had an AlertControl for it, this" +
|
||||
" should never happen", alertControl.Alert.AlertType);
|
||||
}
|
||||
|
||||
}
|
||||
UpdateAlertsControls();
|
||||
}
|
||||
|
||||
protected override void AfterClearAlert()
|
||||
{
|
||||
UpdateAlertsControls();
|
||||
}
|
||||
|
||||
public override void OnRemove()
|
||||
{
|
||||
base.OnRemove();
|
||||
|
||||
foreach (var alertControl in _alertControls.Values)
|
||||
{
|
||||
alertControl.OnShowTooltip -= AlertOnOnShowTooltip;
|
||||
alertControl.OnHideTooltip -= AlertOnOnHideTooltip;
|
||||
alertControl.OnPressed -= AlertControlOnPressed;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user