Use EntityUID for all ghost warps (#11113)
This commit is contained in:
@@ -103,8 +103,7 @@ namespace Content.Client.Ghost
|
|||||||
|
|
||||||
if (window != null)
|
if (window != null)
|
||||||
{
|
{
|
||||||
window.Locations = msg.Locations;
|
window.UpdateWarps(msg.Warps);
|
||||||
window.Players = msg.Players;
|
|
||||||
window.Populate();
|
window.Populate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,9 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Shared.Ghost;
|
using Content.Shared.Ghost;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Client.UserInterface.CustomControls;
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Localization;
|
|
||||||
|
|
||||||
namespace Content.Client.Ghost.UI
|
namespace Content.Client.Ghost.UI
|
||||||
{
|
{
|
||||||
@@ -17,9 +12,7 @@ namespace Content.Client.Ghost.UI
|
|||||||
{
|
{
|
||||||
private readonly IEntityNetworkManager _netManager;
|
private readonly IEntityNetworkManager _netManager;
|
||||||
|
|
||||||
public List<string> Locations { get; set; } = new();
|
private List<(string, EntityUid)> _warps = new();
|
||||||
|
|
||||||
public Dictionary<EntityUid, string> Players { get; set; } = new();
|
|
||||||
|
|
||||||
public GhostTargetWindow(IEntityNetworkManager netManager)
|
public GhostTargetWindow(IEntityNetworkManager netManager)
|
||||||
{
|
{
|
||||||
@@ -28,58 +21,37 @@ namespace Content.Client.Ghost.UI
|
|||||||
_netManager = netManager;
|
_netManager = netManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateWarps(IEnumerable<GhostWarp> warps)
|
||||||
|
{
|
||||||
|
// Server COULD send these sorted but how about we just use the client to do it instead
|
||||||
|
_warps = warps
|
||||||
|
.OrderBy(w => w.IsWarpPoint)
|
||||||
|
.ThenBy(w => w.DisplayName, Comparer<string>.Create(
|
||||||
|
(x, y) => string.Compare(x, y, StringComparison.Ordinal)))
|
||||||
|
.Select(w =>
|
||||||
|
{
|
||||||
|
var name = w.IsWarpPoint
|
||||||
|
? Loc.GetString("ghost-target-window-current-button", ("name", w.DisplayName))
|
||||||
|
: w.DisplayName;
|
||||||
|
|
||||||
|
return (name, w.Entity);
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
public void Populate()
|
public void Populate()
|
||||||
{
|
{
|
||||||
ButtonContainer.DisposeAllChildren();
|
ButtonContainer.DisposeAllChildren();
|
||||||
AddButtonPlayers();
|
AddButtons();
|
||||||
AddButtonLocations();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddButtonPlayers()
|
private void AddButtons()
|
||||||
{
|
{
|
||||||
var sortedPlayers = new List<(string, EntityUid)>(Players.Count);
|
foreach (var (name, warp) in _warps)
|
||||||
|
|
||||||
foreach (var (key, player) in Players)
|
|
||||||
{
|
|
||||||
sortedPlayers.Add((player, key));
|
|
||||||
}
|
|
||||||
|
|
||||||
sortedPlayers.Sort((x, y) => string.Compare(x.Item1, y.Item1, StringComparison.Ordinal));
|
|
||||||
|
|
||||||
foreach (var (key, player) in sortedPlayers)
|
|
||||||
{
|
{
|
||||||
var currentButtonRef = new Button
|
var currentButtonRef = new Button
|
||||||
{
|
{
|
||||||
Text = key,
|
Text = name,
|
||||||
TextAlign = Label.AlignMode.Right,
|
|
||||||
HorizontalAlignment = HAlignment.Center,
|
|
||||||
VerticalAlignment = VAlignment.Center,
|
|
||||||
SizeFlagsStretchRatio = 1,
|
|
||||||
MinSize = (340, 20),
|
|
||||||
ClipText = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
currentButtonRef.OnPressed += (_) =>
|
|
||||||
{
|
|
||||||
var msg = new GhostWarpToTargetRequestEvent(player);
|
|
||||||
_netManager.SendSystemNetworkMessage(msg);
|
|
||||||
};
|
|
||||||
|
|
||||||
ButtonContainer.AddChild(currentButtonRef);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddButtonLocations()
|
|
||||||
{
|
|
||||||
// Server COULD send these sorted but how about we just use the client to do it instead.
|
|
||||||
var sortedLocations = new List<string>(Locations);
|
|
||||||
sortedLocations.Sort((x, y) => string.Compare(x, y, StringComparison.Ordinal));
|
|
||||||
|
|
||||||
foreach (var name in sortedLocations)
|
|
||||||
{
|
|
||||||
var currentButtonRef = new Button
|
|
||||||
{
|
|
||||||
Text = Loc.GetString("ghost-target-window-current-button", ("name", name)),
|
|
||||||
TextAlign = Label.AlignMode.Right,
|
TextAlign = Label.AlignMode.Right,
|
||||||
HorizontalAlignment = HAlignment.Center,
|
HorizontalAlignment = HAlignment.Center,
|
||||||
VerticalAlignment = VAlignment.Center,
|
VerticalAlignment = VAlignment.Center,
|
||||||
@@ -90,7 +62,7 @@ namespace Content.Client.Ghost.UI
|
|||||||
|
|
||||||
currentButtonRef.OnPressed += _ =>
|
currentButtonRef.OnPressed += _ =>
|
||||||
{
|
{
|
||||||
var msg = new GhostWarpToLocationRequestEvent(name);
|
var msg = new GhostWarpToTargetRequestEvent(warp);
|
||||||
_netManager.SendSystemNetworkMessage(msg);
|
_netManager.SendSystemNetworkMessage(msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ namespace Content.Server.Ghost
|
|||||||
|
|
||||||
SubscribeNetworkEvent<GhostWarpsRequestEvent>(OnGhostWarpsRequest);
|
SubscribeNetworkEvent<GhostWarpsRequestEvent>(OnGhostWarpsRequest);
|
||||||
SubscribeNetworkEvent<GhostReturnToBodyRequest>(OnGhostReturnToBodyRequest);
|
SubscribeNetworkEvent<GhostReturnToBodyRequest>(OnGhostReturnToBodyRequest);
|
||||||
SubscribeNetworkEvent<GhostWarpToLocationRequestEvent>(OnGhostWarpToLocationRequest);
|
|
||||||
SubscribeNetworkEvent<GhostWarpToTargetRequestEvent>(OnGhostWarpToTargetRequest);
|
SubscribeNetworkEvent<GhostWarpToTargetRequestEvent>(OnGhostWarpToTargetRequest);
|
||||||
|
|
||||||
SubscribeLocalEvent<GhostComponent, BooActionEvent>(OnActionPerform);
|
SubscribeLocalEvent<GhostComponent, BooActionEvent>(OnActionPerform);
|
||||||
@@ -157,7 +156,7 @@ namespace Content.Server.Ghost
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = new GhostWarpsResponseEvent(GetLocationNames().ToList(), GetPlayerWarps(entity));
|
var response = new GhostWarpsResponseEvent(GetPlayerWarps(entity).Concat(GetLocationWarps()).ToList());
|
||||||
RaiseNetworkEvent(response, args.SenderSession.ConnectedClient);
|
RaiseNetworkEvent(response, args.SenderSession.ConnectedClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,37 +174,6 @@ namespace Content.Server.Ghost
|
|||||||
actor.PlayerSession.ContentData()!.Mind?.UnVisit();
|
actor.PlayerSession.ContentData()!.Mind?.UnVisit();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnGhostWarpToLocationRequest(GhostWarpToLocationRequestEvent msg, EntitySessionEventArgs args)
|
|
||||||
{
|
|
||||||
if (args.SenderSession.AttachedEntity is not {Valid: true} attached ||
|
|
||||||
!EntityManager.TryGetComponent(attached, out GhostComponent? ghost))
|
|
||||||
{
|
|
||||||
Logger.Warning($"User {args.SenderSession.Name} tried to warp to {msg.Name} without being a ghost.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: why the fuck is this using the name instead of an entity id or something?
|
|
||||||
// at least it makes sense for the warp command to need to use names, but not this.
|
|
||||||
|
|
||||||
if (FindLocation(msg.Name) is not { } warp)
|
|
||||||
{
|
|
||||||
Logger.Warning($"User {args.SenderSession.Name} tried to warp to an invalid warp: {msg.Name}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (warp.Follow)
|
|
||||||
{
|
|
||||||
_followerSystem.StartFollowingEntity(attached, warp.Owner);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var xform = Transform(attached);
|
|
||||||
xform.Coordinates = Transform(warp.Owner).Coordinates;
|
|
||||||
xform.AttachToGridOrMap();
|
|
||||||
if (TryComp(attached, out PhysicsComponent? physics))
|
|
||||||
physics.LinearVelocity = Vector2.Zero;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnGhostWarpToTargetRequest(GhostWarpToTargetRequestEvent msg, EntitySessionEventArgs args)
|
private void OnGhostWarpToTargetRequest(GhostWarpToTargetRequestEvent msg, EntitySessionEventArgs args)
|
||||||
{
|
{
|
||||||
if (args.SenderSession.AttachedEntity is not {Valid: true} attached ||
|
if (args.SenderSession.AttachedEntity is not {Valid: true} attached ||
|
||||||
@@ -221,7 +189,18 @@ namespace Content.Server.Ghost
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_followerSystem.StartFollowingEntity(ghost.Owner, msg.Target);
|
if (TryComp(msg.Target, out WarpPointComponent? warp) && warp.Follow
|
||||||
|
|| HasComp<MobStateComponent>(msg.Target))
|
||||||
|
{
|
||||||
|
_followerSystem.StartFollowingEntity(ghost.Owner, msg.Target);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var xform = Transform(ghost.Owner);
|
||||||
|
xform.Coordinates = Transform(msg.Target).Coordinates;
|
||||||
|
xform.AttachToGridOrMap();
|
||||||
|
if (TryComp(attached, out PhysicsComponent? physics))
|
||||||
|
physics.LinearVelocity = Vector2.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeleteEntity(EntityUid uid)
|
private void DeleteEntity(EntityUid uid)
|
||||||
@@ -234,50 +213,33 @@ namespace Content.Server.Ghost
|
|||||||
EntityManager.DeleteEntity(uid);
|
EntityManager.DeleteEntity(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<string> GetLocationNames()
|
private IEnumerable<GhostWarp> GetLocationWarps()
|
||||||
{
|
{
|
||||||
foreach (var warp in EntityManager.EntityQuery<WarpPointComponent>(true))
|
foreach (var warp in EntityManager.EntityQuery<WarpPointComponent>(true))
|
||||||
{
|
{
|
||||||
if (warp.Location != null)
|
if (warp.Location != null)
|
||||||
{
|
{
|
||||||
yield return warp.Location;
|
yield return new GhostWarp(warp.Owner, warp.Location, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private WarpPointComponent? FindLocation(string name)
|
private IEnumerable<GhostWarp> GetPlayerWarps(EntityUid except)
|
||||||
{
|
{
|
||||||
foreach (var warp in EntityManager.EntityQuery<WarpPointComponent>(true))
|
|
||||||
{
|
|
||||||
if (warp.Location == name)
|
|
||||||
{
|
|
||||||
return warp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Dictionary<EntityUid, string> GetPlayerWarps(EntityUid except)
|
|
||||||
{
|
|
||||||
var players = new Dictionary<EntityUid, string>();
|
|
||||||
|
|
||||||
foreach (var player in _playerManager.Sessions)
|
foreach (var player in _playerManager.Sessions)
|
||||||
{
|
{
|
||||||
if (player.AttachedEntity is {Valid: true} attached)
|
if (player.AttachedEntity is {Valid: true} attached)
|
||||||
{
|
{
|
||||||
|
if (attached == except) continue;
|
||||||
|
|
||||||
TryComp<MindComponent>(attached, out var mind);
|
TryComp<MindComponent>(attached, out var mind);
|
||||||
|
|
||||||
string playerInfo = $"{EntityManager.GetComponent<MetaDataComponent>(attached).EntityName} ({mind?.Mind?.CurrentJob?.Name ?? "Unknown"})";
|
string playerInfo = $"{EntityManager.GetComponent<MetaDataComponent>(attached).EntityName} ({mind?.Mind?.CurrentJob?.Name ?? "Unknown"})";
|
||||||
|
|
||||||
if (TryComp<MobStateComponent>(attached, out var state) && !state.IsDead())
|
if (TryComp<MobStateComponent>(attached, out var state) && !state.IsDead())
|
||||||
players.Add(attached, playerInfo);
|
yield return new GhostWarp(attached, playerInfo, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
players.Remove(except);
|
|
||||||
|
|
||||||
return players;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnEntityStorageInsertAttempt(EntityUid uid, GhostComponent comp, InsertIntoEntityStorageAttemptEvent args)
|
public void OnEntityStorageInsertAttempt(EntityUid uid, GhostComponent comp, InsertIntoEntityStorageAttemptEvent args)
|
||||||
|
|||||||
@@ -43,6 +43,35 @@ namespace Content.Shared.Ghost
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An individual place a ghost can warp to.
|
||||||
|
/// This is used as part of <see cref="GhostWarpsResponseEvent"/>
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public struct GhostWarp
|
||||||
|
{
|
||||||
|
public GhostWarp(EntityUid entity, string displayName, bool isWarpPoint)
|
||||||
|
{
|
||||||
|
Entity = entity;
|
||||||
|
DisplayName = displayName;
|
||||||
|
IsWarpPoint = isWarpPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The entity representing the warp point.
|
||||||
|
/// This is passed back to the server in <see cref="GhostWarpToTargetRequestEvent"/>
|
||||||
|
/// </summary>
|
||||||
|
public EntityUid Entity { get; }
|
||||||
|
/// <summary>
|
||||||
|
/// The display name to be surfaced in the ghost warps menu
|
||||||
|
/// </summary>
|
||||||
|
public string DisplayName { get; }
|
||||||
|
/// <summary>
|
||||||
|
/// Whether this warp represents a warp point or a player
|
||||||
|
/// </summary>
|
||||||
|
public bool IsWarpPoint { get; }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A server to client response for a <see cref="GhostWarpsRequestEvent"/>.
|
/// A server to client response for a <see cref="GhostWarpsRequestEvent"/>.
|
||||||
/// Contains players, and locations a ghost can warp to
|
/// Contains players, and locations a ghost can warp to
|
||||||
@@ -50,38 +79,15 @@ namespace Content.Shared.Ghost
|
|||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed class GhostWarpsResponseEvent : EntityEventArgs
|
public sealed class GhostWarpsResponseEvent : EntityEventArgs
|
||||||
{
|
{
|
||||||
public GhostWarpsResponseEvent(List<string> locations, Dictionary<EntityUid, string> players)
|
public GhostWarpsResponseEvent(List<GhostWarp> warps)
|
||||||
{
|
{
|
||||||
Locations = locations;
|
Warps = warps;
|
||||||
Players = players;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A list of location names that can be warped to.
|
/// A list of warp points.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<string> Locations { get; }
|
public List<GhostWarp> Warps { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A dictionary containing the entity id, and name of players that can be warped to.
|
|
||||||
/// </summary>
|
|
||||||
public Dictionary<EntityUid, string> Players { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A client to server request for their ghost to be warped to a location
|
|
||||||
/// </summary>
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public sealed class GhostWarpToLocationRequestEvent : EntityEventArgs
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The location name to warp to.
|
|
||||||
/// </summary>
|
|
||||||
public string Name { get; }
|
|
||||||
|
|
||||||
public GhostWarpToLocationRequestEvent(string locationName)
|
|
||||||
{
|
|
||||||
Name = locationName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user