Fix admin verb PVS issue (#21406)

This commit is contained in:
Leon Friedrich
2023-11-05 02:58:26 +11:00
committed by GitHub
parent 40afc2719b
commit 6a8023cf8b
6 changed files with 59 additions and 31 deletions

View File

@@ -60,7 +60,7 @@ namespace Content.Client.Administration.UI.CustomControls
} }
else if (args.Event.Function == EngineKeyFunctions.UseSecondary && selectedPlayer.NetEntity != null) else if (args.Event.Function == EngineKeyFunctions.UseSecondary && selectedPlayer.NetEntity != null)
{ {
_uiManager.GetUIController<VerbMenuUIController>().OpenVerbMenu(_entManager.GetEntity(selectedPlayer.NetEntity.Value)); _uiManager.GetUIController<VerbMenuUIController>().OpenVerbMenu(selectedPlayer.NetEntity.Value, true);
} }
} }

View File

@@ -14,11 +14,13 @@ namespace Content.Client.Administration.UI.Tabs.PlayerTab
[GenerateTypedNameReferences] [GenerateTypedNameReferences]
public sealed partial class PlayerTab : Control public sealed partial class PlayerTab : Control
{ {
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IPlayerManager _playerMan = default!;
private const string ArrowUp = "↑"; private const string ArrowUp = "↑";
private const string ArrowDown = "↓"; private const string ArrowDown = "↓";
private readonly Color _altColor = Color.FromHex("#292B38"); private readonly Color _altColor = Color.FromHex("#292B38");
private readonly Color _defaultColor = Color.FromHex("#2F2F3B"); private readonly Color _defaultColor = Color.FromHex("#2F2F3B");
private IEntityManager _entManager;
private readonly AdminSystem _adminSystem; private readonly AdminSystem _adminSystem;
private IReadOnlyList<PlayerInfo> _players = new List<PlayerInfo>(); private IReadOnlyList<PlayerInfo> _players = new List<PlayerInfo>();
@@ -30,7 +32,7 @@ namespace Content.Client.Administration.UI.Tabs.PlayerTab
public PlayerTab() public PlayerTab()
{ {
_entManager = IoCManager.Resolve<IEntityManager>(); IoCManager.InjectDependencies(this);
_adminSystem = _entManager.System<AdminSystem>(); _adminSystem = _entManager.System<AdminSystem>();
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
RefreshPlayerList(_adminSystem.PlayerList); RefreshPlayerList(_adminSystem.PlayerList);
@@ -95,13 +97,11 @@ namespace Content.Client.Administration.UI.Tabs.PlayerTab
foreach (var child in PlayerList.Children.ToArray()) foreach (var child in PlayerList.Children.ToArray())
{ {
if (child is PlayerTabEntry) if (child is PlayerTabEntry)
child.Orphan(); child.Dispose();
} }
_players = players; _players = players;
PlayerCount.Text = $"Players: {_playerMan.PlayerCount}";
var playerManager = IoCManager.Resolve<IPlayerManager>();
PlayerCount.Text = $"Players: {playerManager.PlayerCount}";
var sortedPlayers = new List<PlayerInfo>(players); var sortedPlayers = new List<PlayerInfo>(players);
sortedPlayers.Sort(Compare); sortedPlayers.Sort(Compare);

View File

@@ -187,7 +187,7 @@ public sealed class AdminUIController : UIController, IOnStateEntered<GameplaySt
if (function == EngineKeyFunctions.UIClick) if (function == EngineKeyFunctions.UIClick)
_conHost.ExecuteCommand($"vv {entity}"); _conHost.ExecuteCommand($"vv {entity}");
else if (function == EngineKeyFunctions.UseSecondary) else if (function == EngineKeyFunctions.UseSecondary)
_verb.OpenVerbMenu(EntityManager.GetEntity(entity), true); _verb.OpenVerbMenu(entity, true);
else else
return; return;

View File

@@ -9,6 +9,7 @@ using Robust.Client.Player;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers; using Robust.Client.UserInterface.Controllers;
using Robust.Shared.Input; using Robust.Shared.Input;
using Robust.Shared.Utility;
namespace Content.Client.Verbs.UI namespace Content.Client.Verbs.UI
{ {
@@ -29,7 +30,7 @@ namespace Content.Client.Verbs.UI
[UISystemDependency] private readonly CombatModeSystem _combatMode = default!; [UISystemDependency] private readonly CombatModeSystem _combatMode = default!;
[UISystemDependency] private readonly VerbSystem _verbSystem = default!; [UISystemDependency] private readonly VerbSystem _verbSystem = default!;
public EntityUid CurrentTarget; public NetEntity CurrentTarget;
public SortedSet<Verb> CurrentVerbs = new(); public SortedSet<Verb> CurrentVerbs = new();
/// <summary> /// <summary>
@@ -64,8 +65,25 @@ namespace Content.Client.Verbs.UI
/// </param> /// </param>
public void OpenVerbMenu(EntityUid target, bool force = false, ContextMenuPopup? popup=null) public void OpenVerbMenu(EntityUid target, bool force = false, ContextMenuPopup? popup=null)
{ {
if (_playerManager.LocalPlayer?.ControlledEntity is not {Valid: true} user || DebugTools.Assert(target.IsValid());
_combatMode.IsInCombatMode(user)) OpenVerbMenu(EntityManager.GetNetEntity(target), force, popup);
}
/// <summary>
/// Open a verb menu and fill it with verbs applicable to the given target entity.
/// </summary>
/// <param name="target">Entity to get verbs on.</param>
/// <param name="force">Used to force showing all verbs. Only works on networked entities if the user is an admin.</param>
/// <param name="popup">
/// If this is not null, verbs will be placed into the given popup instead.
/// </param>
public void OpenVerbMenu(NetEntity target, bool force = false, ContextMenuPopup? popup=null)
{
DebugTools.Assert(target.IsValid());
if (_playerManager.LocalEntity is not {Valid: true} user)
return;
if (!force && _combatMode.IsInCombatMode(user))
return; return;
Close(); Close();
@@ -82,7 +100,7 @@ namespace Content.Client.Verbs.UI
// Add indicator that some verbs may be missing. // Add indicator that some verbs may be missing.
// I long for the day when verbs will all be predicted and this becomes unnecessary. // I long for the day when verbs will all be predicted and this becomes unnecessary.
if (!EntityManager.IsClientSide(target)) if (!target.IsClientSide())
{ {
_context.AddElement(menu, new ContextMenuElement(Loc.GetString("verb-system-waiting-on-server-text"))); _context.AddElement(menu, new ContextMenuElement(Loc.GetString("verb-system-waiting-on-server-text")));
} }
@@ -248,7 +266,7 @@ namespace Content.Client.Verbs.UI
private void HandleVerbsResponse(VerbsResponseEvent msg) private void HandleVerbsResponse(VerbsResponseEvent msg)
{ {
if (OpenMenu == null || !OpenMenu.Visible || CurrentTarget != EntityManager.GetEntity(msg.Entity)) if (OpenMenu == null || !OpenMenu.Visible || CurrentTarget != msg.Entity)
return; return;
AddServerVerbs(msg.Verbs, OpenMenu); AddServerVerbs(msg.Verbs, OpenMenu);

View File

@@ -170,28 +170,27 @@ namespace Content.Client.Verbs
/// </summary> /// </summary>
public SortedSet<Verb> GetVerbs(EntityUid target, EntityUid user, Type type, bool force = false) public SortedSet<Verb> GetVerbs(EntityUid target, EntityUid user, Type type, bool force = false)
{ {
return GetVerbs(target, user, new List<Type>() { type }, force); return GetVerbs(GetNetEntity(target), user, new List<Type>() { type }, force);
} }
/// <summary> /// <summary>
/// Ask the server to send back a list of server-side verbs, and for now return an incomplete list of verbs /// Ask the server to send back a list of server-side verbs, and for now return an incomplete list of verbs
/// (only those defined locally). /// (only those defined locally).
/// </summary> /// </summary>
public SortedSet<Verb> GetVerbs(EntityUid target, EntityUid user, List<Type> verbTypes, public SortedSet<Verb> GetVerbs(NetEntity target, EntityUid user, List<Type> verbTypes,
bool force = false) bool force = false)
{ {
if (!IsClientSide(target)) if (!target.IsClientSide())
{ RaiseNetworkEvent(new RequestServerVerbsEvent(target, verbTypes, adminRequest: force));
RaiseNetworkEvent(new RequestServerVerbsEvent(GetNetEntity(target), verbTypes, adminRequest: force));
}
// Some admin menu interactions will try get verbs for entities that have not yet been sent to the player. // Some admin menu interactions will try get verbs for entities that have not yet been sent to the player.
if (!Exists(target)) if (!TryGetEntity(target, out var local))
return new(); return new();
return GetLocalVerbs(target, user, verbTypes, force); return GetLocalVerbs(local.Value, user, verbTypes, force);
} }
/// <summary> /// <summary>
/// Execute actions associated with the given verb. /// Execute actions associated with the given verb.
/// </summary> /// </summary>
@@ -200,8 +199,18 @@ namespace Content.Client.Verbs
/// </remarks> /// </remarks>
public void ExecuteVerb(EntityUid target, Verb verb) public void ExecuteVerb(EntityUid target, Verb verb)
{ {
var user = _playerManager.LocalPlayer?.ControlledEntity; ExecuteVerb(GetNetEntity(target), verb);
if (user == null) }
/// <summary>
/// Execute actions associated with the given verb.
/// </summary>
/// <remarks>
/// Unless this is a client-exclusive verb, this will also tell the server to run the same verb.
/// </remarks>
public void ExecuteVerb(NetEntity target, Verb verb)
{
if ( _playerManager.LocalEntity is not {} user)
return; return;
// is this verb actually valid? // is this verb actually valid?
@@ -209,16 +218,16 @@ namespace Content.Client.Verbs
{ {
// maybe send an informative pop-up message. // maybe send an informative pop-up message.
if (!string.IsNullOrWhiteSpace(verb.Message)) if (!string.IsNullOrWhiteSpace(verb.Message))
_popupSystem.PopupEntity(verb.Message, user.Value); _popupSystem.PopupEntity(verb.Message, user);
return; return;
} }
if (verb.ClientExclusive || IsClientSide(target)) if (verb.ClientExclusive || target.IsClientSide())
// is this a client exclusive (gui) verb? // is this a client exclusive (gui) verb?
ExecuteVerb(verb, user.Value, target); ExecuteVerb(verb, user, GetEntity(target));
else else
EntityManager.RaisePredictiveEvent(new ExecuteVerbEvent(GetNetEntity(target), verb)); EntityManager.RaisePredictiveEvent(new ExecuteVerbEvent(target, verb));
} }
private void HandleVerbResponse(VerbsResponseEvent msg) private void HandleVerbResponse(VerbsResponseEvent msg)

View File

@@ -24,16 +24,17 @@ namespace Content.Shared.Verbs
if (user == null) if (user == null)
return; return;
var target = GetEntity(args.Target); if (!TryGetEntity(args.Target, out var target))
return;
// It is possible that client-side prediction can cause this event to be raised after the target entity has // It is possible that client-side prediction can cause this event to be raised after the target entity has
// been deleted. So we need to check that the entity still exists. // been deleted. So we need to check that the entity still exists.
if (Deleted(target) || Deleted(user)) if (Deleted(user))
return; return;
// Get the list of verbs. This effectively also checks that the requested verb is in fact a valid verb that // Get the list of verbs. This effectively also checks that the requested verb is in fact a valid verb that
// the user can perform. // the user can perform.
var verbs = GetLocalVerbs(target, user.Value, args.RequestedVerb.GetType()); var verbs = GetLocalVerbs(target.Value, user.Value, args.RequestedVerb.GetType());
// Note that GetLocalVerbs might waste time checking & preparing unrelated verbs even though we know // Note that GetLocalVerbs might waste time checking & preparing unrelated verbs even though we know
// precisely which one we want to run. However, MOST entities will only have 1 or 2 verbs of a given type. // precisely which one we want to run. However, MOST entities will only have 1 or 2 verbs of a given type.
@@ -41,7 +42,7 @@ namespace Content.Shared.Verbs
// Find the requested verb. // Find the requested verb.
if (verbs.TryGetValue(args.RequestedVerb, out var verb)) if (verbs.TryGetValue(args.RequestedVerb, out var verb))
ExecuteVerb(verb, user.Value, target); ExecuteVerb(verb, user.Value, target.Value);
} }
/// <summary> /// <summary>