Examine verbs + tooltip buttons (#6489)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Client.Verbs;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Input;
|
||||
using Content.Shared.Verbs;
|
||||
@@ -10,13 +10,8 @@ using Robust.Client.Graphics;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Players;
|
||||
using Robust.Shared.Utility;
|
||||
using static Content.Shared.Interaction.SharedInteractionSystem;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
@@ -29,6 +24,7 @@ namespace Content.Client.Examine
|
||||
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
[Dependency] private readonly VerbSystem _verbSystem = default!;
|
||||
|
||||
public const string StyleClassEntityTooltip = "entity-tooltip";
|
||||
|
||||
@@ -41,7 +37,10 @@ namespace Content.Client.Examine
|
||||
{
|
||||
UpdatesOutsidePrediction = true;
|
||||
|
||||
SubscribeLocalEvent<GetVerbsEvent<Verb>>(AddExamineVerb);
|
||||
SubscribeLocalEvent<GetVerbsEvent<ExamineVerb>>(AddExamineVerb);
|
||||
|
||||
SubscribeNetworkEvent<ExamineSystemMessages.ExamineInfoResponseMessage>(OnExamineInfoResponse);
|
||||
SubscribeNetworkEvent<VerbsResponseEvent>(OnVerbsResponse);
|
||||
|
||||
CommandBinds.Builder
|
||||
.Bind(ContentKeyFunctions.ExamineEntity, new PointerInputCmdHandler(HandleExamine, outsidePrediction: true))
|
||||
@@ -90,40 +89,102 @@ namespace Content.Client.Examine
|
||||
return true;
|
||||
}
|
||||
|
||||
private void AddExamineVerb(GetVerbsEvent<Verb> args)
|
||||
private void AddExamineVerb(GetVerbsEvent<ExamineVerb> args)
|
||||
{
|
||||
if (!CanExamine(args.User, args.Target))
|
||||
return;
|
||||
|
||||
Verb verb = new();
|
||||
verb.Act = () => DoExamine(args.Target) ;
|
||||
// Basic examine verb.
|
||||
ExamineVerb verb = new();
|
||||
verb.Category = VerbCategory.Examine;
|
||||
verb.Priority = 10;
|
||||
// Center it on the entity if they use the verb instead.
|
||||
verb.Act = () => DoExamine(args.Target, false);
|
||||
verb.Text = Loc.GetString("examine-verb-name");
|
||||
verb.IconTexture = "/Textures/Interface/VerbIcons/examine.svg.192dpi.png";
|
||||
verb.ShowOnExamineTooltip = false;
|
||||
verb.ClientExclusive = true;
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
public async void DoExamine(EntityUid entity)
|
||||
private void OnExamineInfoResponse(ExamineSystemMessages.ExamineInfoResponseMessage ev)
|
||||
{
|
||||
var player = _playerManager.LocalPlayer?.ControlledEntity;
|
||||
if (player == null)
|
||||
return;
|
||||
|
||||
// Tooltips coming in from the server generally prioritize
|
||||
// opening at the old tooltip rather than the cursor/another entity,
|
||||
// since there's probably one open already if it's coming in from the server.
|
||||
OpenTooltip(player.Value, ev.EntityUid, ev.CenterAtCursor, ev.OpenAtOldTooltip);
|
||||
UpdateTooltipInfo(player.Value, ev.EntityUid, ev.Message, ev.GetVerbs);
|
||||
}
|
||||
|
||||
private void OnVerbsResponse(VerbsResponseEvent ev)
|
||||
{
|
||||
if (ev.Verbs == null || _examineTooltipOpen == null)
|
||||
return;
|
||||
|
||||
var verbs = new List<ExamineVerb>();
|
||||
|
||||
foreach (var verb in ev.Verbs)
|
||||
{
|
||||
if (verb is ExamineVerb ex)
|
||||
verbs.Add(ex);
|
||||
}
|
||||
|
||||
AddVerbsToTooltip(verbs);
|
||||
}
|
||||
|
||||
public override void SendExamineTooltip(EntityUid player, EntityUid target, FormattedMessage message, bool getVerbs, bool centerAtCursor)
|
||||
{
|
||||
OpenTooltip(player, target, centerAtCursor, false);
|
||||
UpdateTooltipInfo(player, target, message, getVerbs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens the tooltip window and sets spriteview/name/etc, but does
|
||||
/// not fill it with information. This is done when the server sends examine info/verbs,
|
||||
/// or immediately if it's entirely clientside.
|
||||
/// </summary>
|
||||
public void OpenTooltip(EntityUid player, EntityUid target, bool centeredOnCursor=true, bool openAtOldTooltip=true)
|
||||
{
|
||||
// Close any examine tooltip that might already be opened
|
||||
// Before we do that, save its position. We'll prioritize opening any new popups there if
|
||||
// openAtOldTooltip is true.
|
||||
var oldTooltipPos = _examineTooltipOpen?.ScreenCoordinates;
|
||||
CloseTooltip();
|
||||
|
||||
// cache entity for Update function
|
||||
_examinedEntity = entity;
|
||||
_examinedEntity = target;
|
||||
|
||||
const float minWidth = 300;
|
||||
var popupPos = _userInterfaceManager.MousePositionScaled;
|
||||
ScreenCoordinates popupPos;
|
||||
|
||||
if (openAtOldTooltip && oldTooltipPos != null)
|
||||
{
|
||||
popupPos = oldTooltipPos.Value;
|
||||
}
|
||||
else if (centeredOnCursor)
|
||||
{
|
||||
popupPos = _userInterfaceManager.MousePositionScaled;
|
||||
}
|
||||
else
|
||||
{
|
||||
popupPos = _eyeManager.CoordinatesToScreen(Transform(target).Coordinates);
|
||||
}
|
||||
|
||||
// Actually open the tooltip.
|
||||
_examineTooltipOpen = new Popup { MaxWidth = 400 };
|
||||
_userInterfaceManager.ModalRoot.AddChild(_examineTooltipOpen);
|
||||
var panel = new PanelContainer();
|
||||
var panel = new PanelContainer() { Name = "ExaminePopupPanel" };
|
||||
panel.AddStyleClass(StyleClassEntityTooltip);
|
||||
panel.ModulateSelfOverride = Color.LightGray.WithAlpha(0.90f);
|
||||
_examineTooltipOpen.AddChild(panel);
|
||||
|
||||
var vBox = new BoxContainer
|
||||
{
|
||||
Name = "ExaminePopupVbox",
|
||||
Orientation = LayoutOrientation.Vertical
|
||||
};
|
||||
panel.AddChild(vBox);
|
||||
@@ -133,16 +194,21 @@ namespace Content.Client.Examine
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
SeparationOverride = 5
|
||||
};
|
||||
|
||||
vBox.AddChild(hBox);
|
||||
|
||||
if (EntityManager.TryGetComponent(entity, out ISpriteComponent? sprite))
|
||||
if (EntityManager.TryGetComponent(target, out ISpriteComponent? sprite))
|
||||
{
|
||||
hBox.AddChild(new SpriteView { Sprite = sprite, OverrideDirection = Direction.South });
|
||||
hBox.AddChild(new SpriteView
|
||||
{
|
||||
Sprite = sprite, OverrideDirection = Direction.South,
|
||||
Margin = new Thickness(2, 0, 2, 0),
|
||||
});
|
||||
}
|
||||
|
||||
hBox.AddChild(new Label
|
||||
{
|
||||
Text = EntityManager.GetComponent<MetaDataComponent>(entity).EntityName,
|
||||
Text = EntityManager.GetComponent<MetaDataComponent>(target).EntityName,
|
||||
HorizontalExpand = true,
|
||||
});
|
||||
|
||||
@@ -150,52 +216,125 @@ namespace Content.Client.Examine
|
||||
var size = Vector2.ComponentMax((minWidth, 0), panel.DesiredSize);
|
||||
|
||||
_examineTooltipOpen.Open(UIBox2.FromDimensions(popupPos.Position, size));
|
||||
}
|
||||
|
||||
FormattedMessage message;
|
||||
if (entity.IsClientSide())
|
||||
/// <summary>
|
||||
/// Fills the examine tooltip with a message and buttons if applicable.
|
||||
/// </summary>
|
||||
public void UpdateTooltipInfo(EntityUid player, EntityUid target, FormattedMessage message, bool getVerbs = true)
|
||||
{
|
||||
var vBox = _examineTooltipOpen?.GetChild(0).GetChild(0);
|
||||
if (vBox == null)
|
||||
{
|
||||
message = GetExamineText(entity, _playerManager.LocalPlayer?.ControlledEntity);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ask server for extra examine info.
|
||||
RaiseNetworkEvent(new ExamineSystemMessages.RequestExamineInfoMessage(entity));
|
||||
|
||||
ExamineSystemMessages.ExamineInfoResponseMessage response;
|
||||
try
|
||||
{
|
||||
_requestCancelTokenSource = new CancellationTokenSource();
|
||||
response =
|
||||
await AwaitNetworkEvent<ExamineSystemMessages.ExamineInfoResponseMessage>(_requestCancelTokenSource
|
||||
.Token);
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_requestCancelTokenSource = null;
|
||||
}
|
||||
|
||||
message = response.Message;
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var msg in message.Tags.OfType<FormattedMessage.TagText>())
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(msg.Text)) continue;
|
||||
|
||||
var richLabel = new RichTextLabel();
|
||||
var richLabel = new RichTextLabel() { Margin = new Thickness(4, 4, 0, 4)};
|
||||
richLabel.SetMessage(message);
|
||||
vBox.AddChild(richLabel);
|
||||
break;
|
||||
}
|
||||
|
||||
if (getVerbs)
|
||||
{
|
||||
// Get verbs
|
||||
var set = _verbSystem.GetVerbs(target, player, typeof(ExamineVerb));
|
||||
AddVerbsToTooltip(set);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddVerbsToTooltip(IEnumerable<Verb> verbs)
|
||||
{
|
||||
if (_examineTooltipOpen == null)
|
||||
return;
|
||||
|
||||
var buttonsHBox = new BoxContainer
|
||||
{
|
||||
Name = "ExamineButtonsHBox",
|
||||
Orientation = LayoutOrientation.Horizontal,
|
||||
HorizontalAlignment = Control.HAlignment.Right,
|
||||
VerticalAlignment = Control.VAlignment.Bottom,
|
||||
};
|
||||
|
||||
// Examine button time
|
||||
foreach (var verb in verbs)
|
||||
{
|
||||
if (verb is not ExamineVerb examine)
|
||||
continue;
|
||||
|
||||
if (examine.IconTexture == null)
|
||||
continue;
|
||||
|
||||
if (!examine.ShowOnExamineTooltip)
|
||||
continue;
|
||||
|
||||
var button = new ExamineButton(examine);
|
||||
|
||||
button.OnPressed += VerbButtonPressed;
|
||||
buttonsHBox.AddChild(button);
|
||||
}
|
||||
|
||||
var vbox = _examineTooltipOpen?.GetChild(0).GetChild(0);
|
||||
if (vbox == null)
|
||||
{
|
||||
buttonsHBox.Dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove any existing buttons hbox, in case we generated it from the client
|
||||
// then received ones from the server
|
||||
var hbox = vbox.Children.Where(c => c.Name == "ExamineButtonsHBox").ToArray();
|
||||
if (hbox.Any())
|
||||
{
|
||||
vbox.Children.Remove(hbox.First());
|
||||
}
|
||||
vbox.AddChild(buttonsHBox);
|
||||
}
|
||||
|
||||
public void VerbButtonPressed(BaseButton.ButtonEventArgs obj)
|
||||
{
|
||||
if (obj.Button is ExamineButton button)
|
||||
{
|
||||
_verbSystem.ExecuteVerb(_examinedEntity, button.Verb);
|
||||
}
|
||||
}
|
||||
|
||||
public void DoExamine(EntityUid entity, bool centeredOnCursor=true)
|
||||
{
|
||||
var playerEnt = _playerManager.LocalPlayer?.ControlledEntity;
|
||||
if (playerEnt == null)
|
||||
return;
|
||||
|
||||
FormattedMessage message;
|
||||
OpenTooltip(playerEnt.Value, entity, centeredOnCursor, false);
|
||||
if (entity.IsClientSide())
|
||||
{
|
||||
message = GetExamineText(entity, playerEnt);
|
||||
|
||||
UpdateTooltipInfo(playerEnt.Value, entity, message);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ask server for extra examine info.
|
||||
RaiseNetworkEvent(new ExamineSystemMessages.RequestExamineInfoMessage(entity, true));
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseTooltip()
|
||||
{
|
||||
if (_examineTooltipOpen != null)
|
||||
{
|
||||
foreach (var control in _examineTooltipOpen.Children)
|
||||
{
|
||||
if (control is ExamineButton button)
|
||||
{
|
||||
button.OnPressed -= VerbButtonPressed;
|
||||
}
|
||||
}
|
||||
_examineTooltipOpen.Dispose();
|
||||
_examineTooltipOpen = null;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user