Stop network serializing prototypes (#38602)

* Stop network serializing prototypes

Send the damn proto ID instead.

* Fix sandbox violation
This commit is contained in:
Pieter-Jan Briers
2025-06-27 01:27:23 +02:00
committed by GitHub
parent bb7e7c3e5f
commit 73df3b1593
28 changed files with 120 additions and 59 deletions

View File

@@ -1,3 +1,4 @@
using System.Collections.Frozen;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using Content.Client.Administration.Systems; using Content.Client.Administration.Systems;
@@ -24,6 +25,7 @@ internal sealed class AdminNameOverlay : Overlay
private readonly EntityLookupSystem _entityLookup; private readonly EntityLookupSystem _entityLookup;
private readonly IUserInterfaceManager _userInterfaceManager; private readonly IUserInterfaceManager _userInterfaceManager;
private readonly SharedRoleSystem _roles; private readonly SharedRoleSystem _roles;
private readonly IPrototypeManager _prototypeManager;
private readonly Font _font; private readonly Font _font;
private readonly Font _fontBold; private readonly Font _fontBold;
private AdminOverlayAntagFormat _overlayFormat; private AdminOverlayAntagFormat _overlayFormat;
@@ -36,8 +38,9 @@ internal sealed class AdminNameOverlay : Overlay
private float _overlayMergeDistance; private float _overlayMergeDistance;
//TODO make this adjustable via GUI? //TODO make this adjustable via GUI?
private readonly ProtoId<RoleTypePrototype>[] _filter = private static readonly FrozenSet<ProtoId<RoleTypePrototype>> Filter =
["SoloAntagonist", "TeamAntagonist", "SiliconAntagonist", "FreeAgent"]; new ProtoId<RoleTypePrototype>[] {"SoloAntagonist", "TeamAntagonist", "SiliconAntagonist", "FreeAgent"}
.ToFrozenSet();
private readonly string _antagLabelClassic = Loc.GetString("admin-overlay-antag-classic"); private readonly string _antagLabelClassic = Loc.GetString("admin-overlay-antag-classic");
@@ -49,7 +52,8 @@ internal sealed class AdminNameOverlay : Overlay
EntityLookupSystem entityLookup, EntityLookupSystem entityLookup,
IUserInterfaceManager userInterfaceManager, IUserInterfaceManager userInterfaceManager,
IConfigurationManager config, IConfigurationManager config,
SharedRoleSystem roles) SharedRoleSystem roles,
IPrototypeManager prototypeManager)
{ {
_system = system; _system = system;
_entityManager = entityManager; _entityManager = entityManager;
@@ -57,6 +61,7 @@ internal sealed class AdminNameOverlay : Overlay
_entityLookup = entityLookup; _entityLookup = entityLookup;
_userInterfaceManager = userInterfaceManager; _userInterfaceManager = userInterfaceManager;
_roles = roles; _roles = roles;
_prototypeManager = prototypeManager;
ZIndex = 200; ZIndex = 200;
// Setting these to a specific ttf would break the antag symbols // Setting these to a specific ttf would break the antag symbols
_font = resourceCache.NotoStack(); _font = resourceCache.NotoStack();
@@ -125,6 +130,14 @@ internal sealed class AdminNameOverlay : Overlay
foreach (var info in sortable.OrderBy(s => s.Item4.Y).ToList()) foreach (var info in sortable.OrderBy(s => s.Item4.Y).ToList())
{ {
var playerInfo = info.Item1; var playerInfo = info.Item1;
var rolePrototype = playerInfo.RoleProto == null
? null
: _prototypeManager.Index(playerInfo.RoleProto.Value);
var roleName = Loc.GetString(rolePrototype?.Name ?? RoleTypePrototype.FallbackName);
var roleColor = rolePrototype?.Color ?? RoleTypePrototype.FallbackColor;
var roleSymbol = rolePrototype?.Symbol ?? RoleTypePrototype.FallbackSymbol;
var aabb = info.Item2; var aabb = info.Item2;
var entity = info.Item3; var entity = info.Item3;
var screenCoordinatesCenter = info.Item4; var screenCoordinatesCenter = info.Item4;
@@ -209,7 +222,7 @@ internal sealed class AdminNameOverlay : Overlay
switch (_overlaySymbolStyle) switch (_overlaySymbolStyle)
{ {
case AdminOverlayAntagSymbolStyle.Specific: case AdminOverlayAntagSymbolStyle.Specific:
symbol = playerInfo.RoleProto.Symbol; symbol = roleSymbol;
break; break;
case AdminOverlayAntagSymbolStyle.Basic: case AdminOverlayAntagSymbolStyle.Basic:
symbol = Loc.GetString("player-tab-antag-prefix"); symbol = Loc.GetString("player-tab-antag-prefix");
@@ -225,17 +238,17 @@ internal sealed class AdminNameOverlay : Overlay
switch (_overlayFormat) switch (_overlayFormat)
{ {
case AdminOverlayAntagFormat.Roletype: case AdminOverlayAntagFormat.Roletype:
color = playerInfo.RoleProto.Color; color = roleColor;
symbol = _filter.Contains(playerInfo.RoleProto) ? symbol : string.Empty; symbol = IsFiltered(playerInfo.RoleProto) ? symbol : string.Empty;
text = _filter.Contains(playerInfo.RoleProto) text = IsFiltered(playerInfo.RoleProto)
? Loc.GetString(playerInfo.RoleProto.Name).ToUpper() ? roleName.ToUpper()
: string.Empty; : string.Empty;
break; break;
case AdminOverlayAntagFormat.Subtype: case AdminOverlayAntagFormat.Subtype:
color = playerInfo.RoleProto.Color; color = roleColor;
symbol = _filter.Contains(playerInfo.RoleProto) ? symbol : string.Empty; symbol = IsFiltered(playerInfo.RoleProto) ? symbol : string.Empty;
text = _filter.Contains(playerInfo.RoleProto) text = IsFiltered(playerInfo.RoleProto)
? _roles.GetRoleSubtypeLabel(playerInfo.RoleProto.Name, playerInfo.Subtype).ToUpper() ? _roles.GetRoleSubtypeLabel(roleName, playerInfo.Subtype).ToUpper()
: string.Empty; : string.Empty;
break; break;
default: default:
@@ -258,4 +271,12 @@ internal sealed class AdminNameOverlay : Overlay
drawnOverlays.Add((screenCoordinatesCenter, currentOffset)); drawnOverlays.Add((screenCoordinatesCenter, currentOffset));
} }
} }
private static bool IsFiltered(ProtoId<RoleTypePrototype>? roleProtoId)
{
if (roleProtoId == null)
return false;
return Filter.Contains(roleProtoId.Value);
}
} }

View File

@@ -4,6 +4,7 @@ using Robust.Client.Graphics;
using Robust.Client.ResourceManagement; using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using Robust.Shared.Configuration; using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;
namespace Content.Client.Administration.Systems namespace Content.Client.Administration.Systems
{ {
@@ -17,6 +18,7 @@ namespace Content.Client.Administration.Systems
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!; [Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
[Dependency] private readonly IConfigurationManager _configurationManager = default!; [Dependency] private readonly IConfigurationManager _configurationManager = default!;
[Dependency] private readonly SharedRoleSystem _roles = default!; [Dependency] private readonly SharedRoleSystem _roles = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
private AdminNameOverlay _adminNameOverlay = default!; private AdminNameOverlay _adminNameOverlay = default!;
@@ -33,7 +35,8 @@ namespace Content.Client.Administration.Systems
_entityLookup, _entityLookup,
_userInterfaceManager, _userInterfaceManager,
_configurationManager, _configurationManager,
_roles); _roles,
_proto);
_adminManager.AdminStatusUpdated += OnAdminStatusUpdated; _adminManager.AdminStatusUpdated += OnAdminStatusUpdated;
} }

View File

@@ -1,9 +1,11 @@
using Content.Shared.Administration; using Content.Shared.Administration;
using Content.Shared.Mind;
using Content.Shared.Roles; using Content.Shared.Roles;
using Robust.Client.AutoGenerated; using Robust.Client.AutoGenerated;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML; using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
namespace Content.Client.Administration.UI.Tabs.PlayerTab; namespace Content.Client.Administration.UI.Tabs.PlayerTab;
@@ -11,6 +13,7 @@ namespace Content.Client.Administration.UI.Tabs.PlayerTab;
public sealed partial class PlayerTabEntry : PanelContainer public sealed partial class PlayerTabEntry : PanelContainer
{ {
[Dependency] private readonly IEntityManager _entMan = default!; [Dependency] private readonly IEntityManager _entMan = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
public PlayerTabEntry( public PlayerTabEntry(
PlayerInfo player, PlayerInfo player,
@@ -23,6 +26,8 @@ public sealed partial class PlayerTabEntry : PanelContainer
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
var roles = _entMan.System<SharedRoleSystem>(); var roles = _entMan.System<SharedRoleSystem>();
var rolePrototype = player.RoleProto == null ? null : _prototype.Index(player.RoleProto.Value);
UsernameLabel.Text = player.Username; UsernameLabel.Text = player.Username;
if (!player.Connected) if (!player.Connected)
UsernameLabel.StyleClasses.Add("Disabled"); UsernameLabel.StyleClasses.Add("Disabled");
@@ -57,19 +62,19 @@ public sealed partial class PlayerTabEntry : PanelContainer
break; break;
default: default:
case AdminPlayerTabSymbolOption.Specific: case AdminPlayerTabSymbolOption.Specific:
symbol = player.Antag ? player.RoleProto.Symbol : string.Empty; symbol = player.Antag ? rolePrototype?.Symbol ?? RoleTypePrototype.FallbackSymbol : string.Empty;
break; break;
} }
CharacterLabel.Text = Loc.GetString("player-tab-character-name-antag-symbol", ("symbol", symbol), ("name", player.CharacterName)); CharacterLabel.Text = Loc.GetString("player-tab-character-name-antag-symbol", ("symbol", symbol), ("name", player.CharacterName));
if (player.Antag && colorAntags) if (player.Antag && colorAntags)
CharacterLabel.FontColorOverride = player.RoleProto.Color; CharacterLabel.FontColorOverride = rolePrototype?.Color ?? RoleTypePrototype.FallbackColor;
if (player.IdentityName != player.CharacterName) if (player.IdentityName != player.CharacterName)
CharacterLabel.Text += $" [{player.IdentityName}]"; CharacterLabel.Text += $" [{player.IdentityName}]";
var roletype = RoleTypeLabel.Text = Loc.GetString(player.RoleProto.Name); var roletype = RoleTypeLabel.Text = Loc.GetString(rolePrototype?.Name ?? RoleTypePrototype.FallbackName);
var subtype = roles.GetRoleSubtypeLabel(player.RoleProto.Name, player.Subtype); var subtype = roles.GetRoleSubtypeLabel(rolePrototype?.Name ?? RoleTypePrototype.FallbackName, player.Subtype);
switch (roleSetting) switch (roleSetting)
{ {
case AdminPlayerTabRoleTypeOption.RoleTypeSubtype: case AdminPlayerTabRoleTypeOption.RoleTypeSubtype:
@@ -92,7 +97,7 @@ public sealed partial class PlayerTabEntry : PanelContainer
} }
if (colorRoles) if (colorRoles)
RoleTypeLabel.FontColorOverride = player.RoleProto.Color; RoleTypeLabel.FontColorOverride = rolePrototype?.Color ?? RoleTypePrototype.FallbackColor;
BackgroundColorPanel.PanelOverride = styleBoxFlat; BackgroundColorPanel.PanelOverride = styleBoxFlat;
OverallPlaytimeLabel.Text = player.PlaytimeString; OverallPlaytimeLabel.Text = player.PlaytimeString;
} }

View File

@@ -1,4 +1,5 @@
using System.Numerics; using System.Linq;
using System.Numerics;
using Content.Client.UserInterface.Controls; using Content.Client.UserInterface.Controls;
using Content.Shared.DeviceLinking; using Content.Shared.DeviceLinking;
using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork;
@@ -14,6 +15,8 @@ namespace Content.Client.NetworkConfigurator;
[GenerateTypedNameReferences] [GenerateTypedNameReferences]
public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
{ {
private readonly IPrototypeManager _prototypeManager = null!;
private const string PanelBgColor = "#202023"; private const string PanelBgColor = "#202023";
private readonly LinksRender _links; private readonly LinksRender _links;
@@ -33,6 +36,7 @@ public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
public NetworkConfiguratorLinkMenu() public NetworkConfiguratorLinkMenu()
{ {
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
var footerStyleBox = new StyleBoxFlat() var footerStyleBox = new StyleBoxFlat()
{ {
@@ -61,7 +65,7 @@ public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
ButtonContainerRight.RemoveAllChildren(); ButtonContainerRight.RemoveAllChildren();
_sources.Clear(); _sources.Clear();
_sources.AddRange(linkState.Sources); _sources.AddRange(linkState.Sources.Select(s => _prototypeManager.Index(s)));
_links.SourceButtons.Clear(); _links.SourceButtons.Clear();
var i = 0; var i = 0;
foreach (var source in _sources) foreach (var source in _sources)
@@ -73,7 +77,7 @@ public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
} }
_sinks.Clear(); _sinks.Clear();
_sinks.AddRange(linkState.Sinks); _sinks.AddRange(linkState.Sinks.Select(s => _prototypeManager.Index(s)));
_links.SinkButtons.Clear(); _links.SinkButtons.Clear();
i = 0; i = 0;
foreach (var sink in _sinks) foreach (var sink in _sinks)

View File

@@ -9,12 +9,14 @@ using Content.Shared.Administration.Logs;
using Content.Shared.CCVar; using Content.Shared.CCVar;
using Content.Shared.Chat; using Content.Shared.Chat;
using Content.Shared.Database; using Content.Shared.Database;
using Content.Shared.Mind;
using Content.Shared.Players.PlayTimeTracking; using Content.Shared.Players.PlayTimeTracking;
using Prometheus; using Prometheus;
using Robust.Shared; using Robust.Shared;
using Robust.Shared.Configuration; using Robust.Shared.Configuration;
using Robust.Shared.Network; using Robust.Shared.Network;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Reflection; using Robust.Shared.Reflection;
using Robust.Shared.Timing; using Robust.Shared.Timing;
@@ -33,6 +35,7 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa
[Dependency] private readonly ISharedPlayerManager _player = default!; [Dependency] private readonly ISharedPlayerManager _player = default!;
[Dependency] private readonly ISharedPlaytimeManager _playtime = default!; [Dependency] private readonly ISharedPlaytimeManager _playtime = default!;
[Dependency] private readonly ISharedChatManager _chat = default!; [Dependency] private readonly ISharedChatManager _chat = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
public const string SawmillId = "admin.logs"; public const string SawmillId = "admin.logs";
@@ -330,7 +333,8 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa
var cachedInfo = adminSys.GetCachedPlayerInfo(new NetUserId(id)); var cachedInfo = adminSys.GetCachedPlayerInfo(new NetUserId(id));
if (cachedInfo != null && cachedInfo.Antag) if (cachedInfo != null && cachedInfo.Antag)
{ {
var subtype = Loc.GetString(cachedInfo.Subtype ?? cachedInfo.RoleProto.Name); var proto = cachedInfo.RoleProto == null ? null : _proto.Index(cachedInfo.RoleProto.Value);
var subtype = Loc.GetString(cachedInfo.Subtype ?? proto?.Name ?? RoleTypePrototype.FallbackName);
logMessage = Loc.GetString( logMessage = Loc.GetString(
"admin-alert-antag-label", "admin-alert-antag-label",
("message", logMessage), ("message", logMessage),

View File

@@ -231,7 +231,7 @@ public sealed class AdminSystem : EntitySystem
var antag = false; var antag = false;
// Starting role, antagonist status and role type // Starting role, antagonist status and role type
RoleTypePrototype roleType = new(); RoleTypePrototype? roleType = null;
var startingRole = string.Empty; var startingRole = string.Empty;
LocId? subtype = null; LocId? subtype = null;
if (_minds.TryGetMind(session, out var mindId, out var mindComp) && mindComp is not null) if (_minds.TryGetMind(session, out var mindId, out var mindComp) && mindComp is not null)
@@ -244,7 +244,7 @@ public sealed class AdminSystem : EntitySystem
subtype = mindComp.Subtype; subtype = mindComp.Subtype;
} }
else else
Log.Error($"{ToPrettyString(mindId)} has invalid Role Type '{mindComp.RoleType}'. Displaying '{Loc.GetString(roleType.Name)}' instead"); Log.Error($"{ToPrettyString(mindId)} has invalid Role Type '{mindComp.RoleType}'. Displaying '{Loc.GetString(RoleTypePrototype.FallbackName)}' instead");
antag = _role.MindIsAntagonist(mindId); antag = _role.MindIsAntagonist(mindId);
startingRole = _jobs.MindTryGetJobName(mindId); startingRole = _jobs.MindTryGetJobName(mindId);
@@ -270,7 +270,7 @@ public sealed class AdminSystem : EntitySystem
identityName, identityName,
startingRole, startingRole,
antag, antag,
roleType, roleType?.ID,
subtype, subtype,
sortWeight, sortWeight,
GetNetEntity(session?.AttachedEntity), GetNetEntity(session?.AttachedEntity),

View File

@@ -18,6 +18,7 @@ using Robust.Server.Audio;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.Map.Events; using Robust.Shared.Map.Events;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing; using Robust.Shared.Timing;
using Robust.Shared.Utility; using Robust.Shared.Utility;
@@ -496,14 +497,15 @@ public sealed class NetworkConfiguratorSystem : SharedNetworkConfiguratorSystem
return; return;
var sources = _deviceLinkSystem.GetSourcePorts(sourceUid, sourceComponent); var sources = _deviceLinkSystem.GetSourcePorts(sourceUid, sourceComponent);
var sinks = _deviceLinkSystem.GetSinkPorts(sinkUid, sinkComponent); var sinks = _deviceLinkSystem.GetSinkPortIds((sinkUid, sinkComponent));
var links = _deviceLinkSystem.GetLinks(sourceUid, sinkUid, sourceComponent); var links = _deviceLinkSystem.GetLinks(sourceUid, sinkUid, sourceComponent);
var defaults = _deviceLinkSystem.GetDefaults(sources); var defaults = _deviceLinkSystem.GetDefaults(sources);
var sourceIds = sources.Select(s => (ProtoId<SourcePortPrototype>)s.ID).ToArray();
var sourceAddress = Resolve(sourceUid, ref sourceNetworkComponent, false) ? sourceNetworkComponent.Address : ""; var sourceAddress = Resolve(sourceUid, ref sourceNetworkComponent, false) ? sourceNetworkComponent.Address : "";
var sinkAddress = Resolve(sinkUid, ref sinkNetworkComponent, false) ? sinkNetworkComponent.Address : ""; var sinkAddress = Resolve(sinkUid, ref sinkNetworkComponent, false) ? sinkNetworkComponent.Address : "";
var state = new DeviceLinkUserInterfaceState(sources, sinks, links, sourceAddress, sinkAddress, defaults); var state = new DeviceLinkUserInterfaceState(sourceIds, sinks, links, sourceAddress, sinkAddress, defaults);
_uiSystem.SetUiState(configuratorUid, NetworkConfiguratorUiKey.Link, state); _uiSystem.SetUiState(configuratorUid, NetworkConfiguratorUiKey.Link, state);
} }

View File

@@ -2,6 +2,7 @@ using Content.Server.Chat.Systems;
using Content.Server.Speech.Components; using Content.Server.Speech.Components;
using Content.Shared.Chat.Prototypes; using Content.Shared.Chat.Prototypes;
using Content.Shared.Speech.Components; using Content.Shared.Speech.Components;
using Robust.Shared.Prototypes;
namespace Content.Server.Speech.EntitySystems; namespace Content.Server.Speech.EntitySystems;
@@ -9,6 +10,7 @@ public sealed class MumbleAccentSystem : EntitySystem
{ {
[Dependency] private readonly ChatSystem _chat = default!; [Dependency] private readonly ChatSystem _chat = default!;
[Dependency] private readonly ReplacementAccentSystem _replacement = default!; [Dependency] private readonly ReplacementAccentSystem _replacement = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -23,10 +25,14 @@ public sealed class MumbleAccentSystem : EntitySystem
if (args.Handled || !args.Emote.Category.HasFlag(EmoteCategory.Vocal)) if (args.Handled || !args.Emote.Category.HasFlag(EmoteCategory.Vocal))
return; return;
if (TryComp<VocalComponent>(ent.Owner, out var vocalComp)) if (TryComp<VocalComponent>(ent.Owner, out var vocalComp) && vocalComp.EmoteSounds is { } sounds)
{ {
// play a muffled version of the vocal emote // play a muffled version of the vocal emote
args.Handled = _chat.TryPlayEmoteSound(ent.Owner, vocalComp.EmoteSounds, args.Emote, ent.Comp.EmoteAudioParams); args.Handled = _chat.TryPlayEmoteSound(
ent.Owner,
_prototype.Index(sounds),
args.Emote,
ent.Comp.EmoteAudioParams);
} }
} }

View File

@@ -64,8 +64,11 @@ public sealed class VocalSystem : EntitySystem
return; return;
} }
if (component.EmoteSounds is not { } sounds)
return;
// just play regular sound based on emote proto // just play regular sound based on emote proto
args.Handled = _chat.TryPlayEmoteSound(uid, component.EmoteSounds, args.Emote); args.Handled = _chat.TryPlayEmoteSound(uid, _proto.Index(sounds), args.Emote);
} }
private void OnScreamAction(EntityUid uid, VocalComponent component, ScreamActionEvent args) private void OnScreamAction(EntityUid uid, VocalComponent component, ScreamActionEvent args)
@@ -85,7 +88,10 @@ public sealed class VocalSystem : EntitySystem
return true; return true;
} }
return _chat.TryPlayEmoteSound(uid, component.EmoteSounds, component.ScreamId); if (component.EmoteSounds is not { } sounds)
return false;
return _chat.TryPlayEmoteSound(uid, _proto.Index(sounds), component.ScreamId);
} }
private void LoadSounds(EntityUid uid, VocalComponent component, Sex? sex = null) private void LoadSounds(EntityUid uid, VocalComponent component, Sex? sex = null)
@@ -97,6 +103,10 @@ public sealed class VocalSystem : EntitySystem
if (!component.Sounds.TryGetValue(sex.Value, out var protoId)) if (!component.Sounds.TryGetValue(sex.Value, out var protoId))
return; return;
_proto.TryIndex(protoId, out component.EmoteSounds);
if (!_proto.HasIndex(protoId))
return;
component.EmoteSounds = protoId;
} }
} }

View File

@@ -1,5 +1,6 @@
using Content.Shared.Mind; using Content.Shared.Mind;
using Robust.Shared.Network; using Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
namespace Content.Shared.Administration; namespace Content.Shared.Administration;
@@ -11,7 +12,7 @@ public sealed record PlayerInfo(
string IdentityName, string IdentityName,
string StartingJob, string StartingJob,
bool Antag, bool Antag,
RoleTypePrototype RoleProto, ProtoId<RoleTypePrototype>? RoleProto,
LocId? Subtype, LocId? Subtype,
int SortWeight, int SortWeight,
NetEntity? NetEntity, NetEntity? NetEntity,

View File

@@ -10,7 +10,7 @@ namespace Content.Shared.Cargo.Prototypes;
/// that must be sold together in a labeled container in order /// that must be sold together in a labeled container in order
/// to receive a monetary reward. /// to receive a monetary reward.
/// </summary> /// </summary>
[Prototype, Serializable, NetSerializable] [Prototype]
public sealed partial class CargoBountyPrototype : IPrototype public sealed partial class CargoBountyPrototype : IPrototype
{ {
/// <inheritdoc/> /// <inheritdoc/>

View File

@@ -9,7 +9,7 @@ namespace Content.Shared.Chat.Prototypes;
/// Sounds collection for each <see cref="EmotePrototype"/>. /// Sounds collection for each <see cref="EmotePrototype"/>.
/// Different entities may use different sounds collections. /// Different entities may use different sounds collections.
/// </summary> /// </summary>
[Prototype, Serializable, NetSerializable] [Prototype]
public sealed partial class EmoteSoundsPrototype : IPrototype public sealed partial class EmoteSoundsPrototype : IPrototype
{ {
[IdDataField] [IdDataField]

View File

@@ -13,7 +13,6 @@ namespace Content.Shared.Damage.Prototypes
/// cref="DamageableComponent"/> should support. /// cref="DamageableComponent"/> should support.
/// </remarks> /// </remarks>
[Prototype] [Prototype]
[Serializable, NetSerializable]
public sealed partial class DamageContainerPrototype : IPrototype public sealed partial class DamageContainerPrototype : IPrototype
{ {
[ViewVariables] [ViewVariables]

View File

@@ -12,7 +12,6 @@ namespace Content.Shared.Damage.Prototypes
/// to change/get/set damage in a <see cref="DamageableComponent"/>. /// to change/get/set damage in a <see cref="DamageableComponent"/>.
/// </remarks> /// </remarks>
[Prototype(2)] [Prototype(2)]
[Serializable, NetSerializable]
public sealed partial class DamageGroupPrototype : IPrototype public sealed partial class DamageGroupPrototype : IPrototype
{ {
[IdDataField] public string ID { get; private set; } = default!; [IdDataField] public string ID { get; private set; } = default!;

View File

@@ -7,7 +7,6 @@ namespace Content.Shared.DeviceLinking;
/// <summary> /// <summary>
/// A prototype for a device port, for use with device linking. /// A prototype for a device port, for use with device linking.
/// </summary> /// </summary>
[Serializable, NetSerializable]
public abstract class DevicePortPrototype public abstract class DevicePortPrototype
{ {
[IdDataField] [IdDataField]
@@ -28,13 +27,11 @@ public abstract class DevicePortPrototype
} }
[Prototype] [Prototype]
[Serializable, NetSerializable]
public sealed partial class SinkPortPrototype : DevicePortPrototype, IPrototype public sealed partial class SinkPortPrototype : DevicePortPrototype, IPrototype
{ {
} }
[Prototype] [Prototype]
[Serializable, NetSerializable]
public sealed partial class SourcePortPrototype : DevicePortPrototype, IPrototype public sealed partial class SourcePortPrototype : DevicePortPrototype, IPrototype
{ {
/// <summary> /// <summary>

View File

@@ -1,3 +1,4 @@
using System.Linq;
using Content.Shared.Administration.Logs; using Content.Shared.Administration.Logs;
using Content.Shared.Database; using Content.Shared.Database;
using Content.Shared.DeviceLinking.Events; using Content.Shared.DeviceLinking.Events;
@@ -142,6 +143,11 @@ public abstract class SharedDeviceLinkSystem : EntitySystem
} }
} }
public ProtoId<SourcePortPrototype>[] GetSourcePortIds(Entity<DeviceLinkSourceComponent> source)
{
return source.Comp.Ports.ToArray();
}
/// <summary> /// <summary>
/// Retrieves the available ports from a source /// Retrieves the available ports from a source
/// </summary> /// </summary>
@@ -160,6 +166,11 @@ public abstract class SharedDeviceLinkSystem : EntitySystem
return sourcePorts; return sourcePorts;
} }
public ProtoId<SinkPortPrototype>[] GetSinkPortIds(Entity<DeviceLinkSinkComponent> source)
{
return source.Comp.Ports.ToArray();
}
/// <summary> /// <summary>
/// Retrieves the available ports from a sink /// Retrieves the available ports from a sink
/// </summary> /// </summary>

View File

@@ -7,7 +7,6 @@ namespace Content.Shared.DeviceNetwork;
/// A named device network frequency. Useful for ensuring entity prototypes can communicate with each other. /// A named device network frequency. Useful for ensuring entity prototypes can communicate with each other.
/// </summary> /// </summary>
[Prototype] [Prototype]
[Serializable, NetSerializable]
public sealed partial class DeviceFrequencyPrototype : IPrototype public sealed partial class DeviceFrequencyPrototype : IPrototype
{ {
[IdDataField] [IdDataField]

View File

@@ -29,16 +29,16 @@ public sealed class DeviceListUserInterfaceState : BoundUserInterfaceState
[Serializable, NetSerializable] [Serializable, NetSerializable]
public sealed class DeviceLinkUserInterfaceState : BoundUserInterfaceState public sealed class DeviceLinkUserInterfaceState : BoundUserInterfaceState
{ {
public readonly List<SourcePortPrototype> Sources; public readonly ProtoId<SourcePortPrototype>[] Sources;
public readonly List<SinkPortPrototype> Sinks; public readonly ProtoId<SinkPortPrototype>[] Sinks;
public readonly HashSet<(ProtoId<SourcePortPrototype> source, ProtoId<SinkPortPrototype> sink)> Links; public readonly HashSet<(ProtoId<SourcePortPrototype> source, ProtoId<SinkPortPrototype> sink)> Links;
public readonly List<(string source, string sink)>? Defaults; public readonly List<(string source, string sink)>? Defaults;
public readonly string SourceAddress; public readonly string SourceAddress;
public readonly string SinkAddress; public readonly string SinkAddress;
public DeviceLinkUserInterfaceState( public DeviceLinkUserInterfaceState(
List<SourcePortPrototype> sources, ProtoId<SourcePortPrototype>[] sources,
List<SinkPortPrototype> sinks, ProtoId<SinkPortPrototype>[] sinks,
HashSet<(ProtoId<SourcePortPrototype> source, ProtoId<SinkPortPrototype> sink)> links, HashSet<(ProtoId<SourcePortPrototype> source, ProtoId<SinkPortPrototype> sink)> links,
string sourceAddress, string sourceAddress,
string sinkAddress, string sinkAddress,

View File

@@ -5,27 +5,31 @@ namespace Content.Shared.Mind;
/// <summary> /// <summary>
/// The core properties of Role Types /// The core properties of Role Types
/// </summary> /// </summary>
[Prototype, Serializable] [Prototype]
public sealed partial class RoleTypePrototype : IPrototype public sealed partial class RoleTypePrototype : IPrototype
{ {
[IdDataField] [IdDataField]
public string ID { get; private set; } = default!; public string ID { get; private set; } = default!;
public static readonly LocId FallbackName = "role-type-crew-aligned-name";
public const string FallbackSymbol = "";
public static readonly Color FallbackColor = Color.FromHex("#eeeeee");
/// <summary> /// <summary>
/// The role's name as displayed on the UI. /// The role's name as displayed on the UI.
/// </summary> /// </summary>
[DataField] [DataField]
public LocId Name = "role-type-crew-aligned-name"; public LocId Name = FallbackName;
/// <summary> /// <summary>
/// The role's displayed color. /// The role's displayed color.
/// </summary> /// </summary>
[DataField] [DataField]
public Color Color = Color.FromHex("#eeeeee"); public Color Color = FallbackColor;
/// <summary> /// <summary>
/// A symbol used to represent the role type. /// A symbol used to represent the role type.
/// </summary> /// </summary>
[DataField] [DataField]
public string Symbol = string.Empty; public string Symbol = FallbackSymbol;
} }

View File

@@ -8,7 +8,6 @@ namespace Content.Shared.Roles;
/// Describes information for a single antag. /// Describes information for a single antag.
/// </summary> /// </summary>
[Prototype] [Prototype]
[Serializable, NetSerializable]
public sealed partial class AntagPrototype : IPrototype public sealed partial class AntagPrototype : IPrototype
{ {
[ViewVariables] [ViewVariables]

View File

@@ -78,7 +78,6 @@ public partial class SiliconLaw : IComparable<SiliconLaw>, IEquatable<SiliconLaw
/// This is a prototype for a law governing the behavior of silicons. /// This is a prototype for a law governing the behavior of silicons.
/// </summary> /// </summary>
[Prototype] [Prototype]
[Serializable, NetSerializable]
public sealed partial class SiliconLawPrototype : SiliconLaw, IPrototype public sealed partial class SiliconLawPrototype : SiliconLaw, IPrototype
{ {
/// <inheritdoc/> /// <inheritdoc/>

View File

@@ -61,7 +61,7 @@ public sealed partial class SiliconLawset
/// This is a prototype for a <see cref="SiliconLawPrototype"/> list. /// This is a prototype for a <see cref="SiliconLawPrototype"/> list.
/// Cannot be used directly since it is a list of prototype ids rather than List<Siliconlaw>. /// Cannot be used directly since it is a list of prototype ids rather than List<Siliconlaw>.
/// </summary> /// </summary>
[Prototype, Serializable, NetSerializable] [Prototype]
public sealed partial class SiliconLawsetPrototype : IPrototype public sealed partial class SiliconLawsetPrototype : IPrototype
{ {
/// <inheritdoc/> /// <inheritdoc/>

View File

@@ -49,5 +49,5 @@ public sealed partial class VocalComponent : Component
/// </summary> /// </summary>
[ViewVariables] [ViewVariables]
[AutoNetworkedField] [AutoNetworkedField]
public EmoteSoundsPrototype? EmoteSounds = null; public ProtoId<EmoteSoundsPrototype>? EmoteSounds = null;
} }

View File

@@ -11,7 +11,7 @@ namespace Content.Shared.Store;
/// This is separate to the cargo ordering system. /// This is separate to the cargo ordering system.
/// </summary> /// </summary>
[Prototype] [Prototype]
[DataDefinition, Serializable, NetSerializable] [DataDefinition]
public sealed partial class CurrencyPrototype : IPrototype public sealed partial class CurrencyPrototype : IPrototype
{ {
[ViewVariables] [ViewVariables]

View File

@@ -242,7 +242,6 @@ public partial class ListingData : IEquatable<ListingData>
/// Defines a set item listing that is available in a store /// Defines a set item listing that is available in a store
/// </summary> /// </summary>
[Prototype] [Prototype]
[Serializable, NetSerializable]
[DataDefinition] [DataDefinition]
public sealed partial class ListingPrototype : ListingData, IPrototype public sealed partial class ListingPrototype : ListingData, IPrototype
{ {
@@ -423,7 +422,7 @@ public sealed partial class ListingDataWithCostModifiers : ListingData
/// how <see cref="StoreDiscountComponent"/> will be filled by respective system. /// how <see cref="StoreDiscountComponent"/> will be filled by respective system.
/// </summary> /// </summary>
[Prototype] [Prototype]
[DataDefinition, Serializable, NetSerializable] [DataDefinition]
public sealed partial class DiscountCategoryPrototype : IPrototype public sealed partial class DiscountCategoryPrototype : IPrototype
{ {
[ViewVariables] [ViewVariables]

View File

@@ -7,7 +7,6 @@ namespace Content.Shared.Store;
/// Used to define different categories for a store. /// Used to define different categories for a store.
/// </summary> /// </summary>
[Prototype] [Prototype]
[Serializable, NetSerializable, DataDefinition]
public sealed partial class StoreCategoryPrototype : IPrototype public sealed partial class StoreCategoryPrototype : IPrototype
{ {
private string _name = string.Empty; private string _name = string.Empty;

View File

@@ -6,7 +6,7 @@ namespace Content.Shared.StoryGen;
/// <summary> /// <summary>
/// Prototype for a story template that can be filled in with words chosen from <see cref="DatasetPrototype"/>s. /// Prototype for a story template that can be filled in with words chosen from <see cref="DatasetPrototype"/>s.
/// </summary> /// </summary>
[Serializable, Prototype] [Prototype]
public sealed partial class StoryTemplatePrototype : IPrototype public sealed partial class StoryTemplatePrototype : IPrototype
{ {
/// <summary> /// <summary>

View File

@@ -4,7 +4,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototy
namespace Content.Shared.VendingMachines namespace Content.Shared.VendingMachines
{ {
[Serializable, NetSerializable, Prototype] [Prototype]
public sealed partial class VendingMachineInventoryPrototype : IPrototype public sealed partial class VendingMachineInventoryPrototype : IPrototype
{ {
[ViewVariables] [ViewVariables]