if (args.Current is not ActionsComponentState state)
return;
- var serverActions = new SortedSet<ActionType>(state.Actions);
+ state.SortedActions ??= new SortedSet<ActionType>(state.Actions);
+ var serverActions = state.SortedActions;
var removed = new List<ActionType>();
foreach (var act in component.Actions.ToList())
public void DirtyNeighbours(EntityUid uid, IconSmoothComponent? comp = null, TransformComponent? transform = null, EntityQuery<IconSmoothComponent>? smoothQuery = null)
{
smoothQuery ??= GetEntityQuery<IconSmoothComponent>();
- if (!smoothQuery.Value.Resolve(uid, ref comp))
+ if (!smoothQuery.Value.Resolve(uid, ref comp) || !comp.Running)
return;
_dirtyEntities.Enqueue(uid);
// Generation on the component is set after an update so we can cull updates that happened this generation.
if (!smoothQuery.Resolve(uid, ref smooth, false)
|| smooth.Mode == IconSmoothingMode.NoSprite
- || smooth.UpdateGeneration == _generation ||
- !smooth.Enabled)
+ || smooth.UpdateGeneration == _generation
+ || !smooth.Enabled
+ || !smooth.Running)
{
if (smooth is { Enabled: true } &&
TryComp<SmoothEdgeComponent>(uid, out var edge) &&
[DataField("name")]
public string DisplayName = string.Empty;
+ /// <summary>
+ /// This is just <see cref="DisplayName"/> with localized strings resolved and markup removed. If null, will be
+ /// inferred from <see cref="DisplayName"/>. This is cached to speed up game state handling.
+ /// </summary>
+ [NonSerialized]
+ public string? RawName;
+
/// <summary>
/// Description to show in UI. Accepts formatting.
/// </summary>
if (Priority != otherAction.Priority)
return otherAction.Priority - Priority;
- var name = FormattedMessage.RemoveMarkup(Loc.GetString(DisplayName));
- var otherName = FormattedMessage.RemoveMarkup(Loc.GetString(otherAction.DisplayName));
- if (name != otherName)
- return string.Compare(name, otherName, StringComparison.CurrentCulture);
+ RawName ??= FormattedMessage.RemoveMarkup(Loc.GetString(DisplayName));
+ otherAction.RawName ??= FormattedMessage.RemoveMarkup(Loc.GetString(otherAction.DisplayName));
+ var cmp = string.Compare(RawName, otherAction.RawName, StringComparison.CurrentCulture);
+ if (cmp != 0)
+ return cmp;
if (Provider != otherAction.Provider)
{
Icon = toClone.Icon;
IconOn = toClone.IconOn;
DisplayName = toClone.DisplayName;
+ RawName = null;
Description = toClone.Description;
Provider = toClone.Provider;
AttachedEntity = toClone.AttachedEntity;
{
public readonly List<ActionType> Actions;
+ [NonSerialized]
+ public SortedSet<ActionType>? SortedActions;
+
public ActionsComponentState(List<ActionType> actions)
{
Actions = actions;
+using System.Collections.ObjectModel;
using Content.Shared.Whitelist;
using Robust.Shared.Serialization;
[Serializable, NetSerializable]
public sealed class ShowLayerData : ICloneable
{
- public IReadOnlyList<string> QueuedEntities { get; internal set; }
+ public readonly IReadOnlyList<string> QueuedEntities;
public ShowLayerData()
{
QueuedEntities = new List<string>();
}
- public ShowLayerData(IEnumerable<string> other)
+ public ShowLayerData(IReadOnlyList<string> other)
{
- QueuedEntities = new List<string>(other);
+ QueuedEntities = other;
}
public object Clone()
{
- return new ShowLayerData(QueuedEntities);
+ // QueuedEntities should never be getting modified after this object is created.
+ return this;
}
}
}
/// <returns>false if <c>msg.Container.Owner</c> is not a storage, true otherwise.</returns>
private bool TryGetLayers(ContainerModifiedMessage msg,
ItemMapperComponent itemMapper,
- out IReadOnlyList<string> showLayers)
+ out List<string> showLayers)
{
var containedLayers = _container.GetAllContainers(msg.Container.Owner)
.Where(c => itemMapper.ContainerWhitelist?.Contains(c.ID) ?? true).SelectMany(cont => cont.ContainedEntities).ToArray();