Actions System + UI (#2710)

Co-authored-by: Vera Aguilera Puerto <6766154+Zumorica@users.noreply.github.com>
This commit is contained in:
chairbender
2020-12-13 14:28:20 -08:00
committed by GitHub
parent fd0df9a00a
commit 7a3c281f60
150 changed files with 7283 additions and 854 deletions

View File

@@ -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;
}
}
}
}