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.Numerics;
using Content.Client.Administration.Systems;
@@ -24,6 +25,7 @@ internal sealed class AdminNameOverlay : Overlay
private readonly EntityLookupSystem _entityLookup;
private readonly IUserInterfaceManager _userInterfaceManager;
private readonly SharedRoleSystem _roles;
private readonly IPrototypeManager _prototypeManager;
private readonly Font _font;
private readonly Font _fontBold;
private AdminOverlayAntagFormat _overlayFormat;
@@ -36,8 +38,9 @@ internal sealed class AdminNameOverlay : Overlay
private float _overlayMergeDistance;
//TODO make this adjustable via GUI?
private readonly ProtoId<RoleTypePrototype>[] _filter =
["SoloAntagonist", "TeamAntagonist", "SiliconAntagonist", "FreeAgent"];
private static readonly FrozenSet<ProtoId<RoleTypePrototype>> Filter =
new ProtoId<RoleTypePrototype>[] {"SoloAntagonist", "TeamAntagonist", "SiliconAntagonist", "FreeAgent"}
.ToFrozenSet();
private readonly string _antagLabelClassic = Loc.GetString("admin-overlay-antag-classic");
@@ -49,7 +52,8 @@ internal sealed class AdminNameOverlay : Overlay
EntityLookupSystem entityLookup,
IUserInterfaceManager userInterfaceManager,
IConfigurationManager config,
SharedRoleSystem roles)
SharedRoleSystem roles,
IPrototypeManager prototypeManager)
{
_system = system;
_entityManager = entityManager;
@@ -57,6 +61,7 @@ internal sealed class AdminNameOverlay : Overlay
_entityLookup = entityLookup;
_userInterfaceManager = userInterfaceManager;
_roles = roles;
_prototypeManager = prototypeManager;
ZIndex = 200;
// Setting these to a specific ttf would break the antag symbols
_font = resourceCache.NotoStack();
@@ -125,6 +130,14 @@ internal sealed class AdminNameOverlay : Overlay
foreach (var info in sortable.OrderBy(s => s.Item4.Y).ToList())
{
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 entity = info.Item3;
var screenCoordinatesCenter = info.Item4;
@@ -209,7 +222,7 @@ internal sealed class AdminNameOverlay : Overlay
switch (_overlaySymbolStyle)
{
case AdminOverlayAntagSymbolStyle.Specific:
symbol = playerInfo.RoleProto.Symbol;
symbol = roleSymbol;
break;
case AdminOverlayAntagSymbolStyle.Basic:
symbol = Loc.GetString("player-tab-antag-prefix");
@@ -225,17 +238,17 @@ internal sealed class AdminNameOverlay : Overlay
switch (_overlayFormat)
{
case AdminOverlayAntagFormat.Roletype:
color = playerInfo.RoleProto.Color;
symbol = _filter.Contains(playerInfo.RoleProto) ? symbol : string.Empty;
text = _filter.Contains(playerInfo.RoleProto)
? Loc.GetString(playerInfo.RoleProto.Name).ToUpper()
color = roleColor;
symbol = IsFiltered(playerInfo.RoleProto) ? symbol : string.Empty;
text = IsFiltered(playerInfo.RoleProto)
? roleName.ToUpper()
: string.Empty;
break;
case AdminOverlayAntagFormat.Subtype:
color = playerInfo.RoleProto.Color;
symbol = _filter.Contains(playerInfo.RoleProto) ? symbol : string.Empty;
text = _filter.Contains(playerInfo.RoleProto)
? _roles.GetRoleSubtypeLabel(playerInfo.RoleProto.Name, playerInfo.Subtype).ToUpper()
color = roleColor;
symbol = IsFiltered(playerInfo.RoleProto) ? symbol : string.Empty;
text = IsFiltered(playerInfo.RoleProto)
? _roles.GetRoleSubtypeLabel(roleName, playerInfo.Subtype).ToUpper()
: string.Empty;
break;
default:
@@ -258,4 +271,12 @@ internal sealed class AdminNameOverlay : Overlay
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.UserInterface;
using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;
namespace Content.Client.Administration.Systems
{
@@ -17,6 +18,7 @@ namespace Content.Client.Administration.Systems
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
[Dependency] private readonly SharedRoleSystem _roles = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
private AdminNameOverlay _adminNameOverlay = default!;
@@ -33,7 +35,8 @@ namespace Content.Client.Administration.Systems
_entityLookup,
_userInterfaceManager,
_configurationManager,
_roles);
_roles,
_proto);
_adminManager.AdminStatusUpdated += OnAdminStatusUpdated;
}

View File

@@ -1,9 +1,11 @@
using Content.Shared.Administration;
using Content.Shared.Mind;
using Content.Shared.Roles;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
namespace Content.Client.Administration.UI.Tabs.PlayerTab;
@@ -11,6 +13,7 @@ namespace Content.Client.Administration.UI.Tabs.PlayerTab;
public sealed partial class PlayerTabEntry : PanelContainer
{
[Dependency] private readonly IEntityManager _entMan = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
public PlayerTabEntry(
PlayerInfo player,
@@ -23,6 +26,8 @@ public sealed partial class PlayerTabEntry : PanelContainer
RobustXamlLoader.Load(this);
var roles = _entMan.System<SharedRoleSystem>();
var rolePrototype = player.RoleProto == null ? null : _prototype.Index(player.RoleProto.Value);
UsernameLabel.Text = player.Username;
if (!player.Connected)
UsernameLabel.StyleClasses.Add("Disabled");
@@ -57,19 +62,19 @@ public sealed partial class PlayerTabEntry : PanelContainer
break;
default:
case AdminPlayerTabSymbolOption.Specific:
symbol = player.Antag ? player.RoleProto.Symbol : string.Empty;
symbol = player.Antag ? rolePrototype?.Symbol ?? RoleTypePrototype.FallbackSymbol : string.Empty;
break;
}
CharacterLabel.Text = Loc.GetString("player-tab-character-name-antag-symbol", ("symbol", symbol), ("name", player.CharacterName));
if (player.Antag && colorAntags)
CharacterLabel.FontColorOverride = player.RoleProto.Color;
CharacterLabel.FontColorOverride = rolePrototype?.Color ?? RoleTypePrototype.FallbackColor;
if (player.IdentityName != player.CharacterName)
CharacterLabel.Text += $" [{player.IdentityName}]";
var roletype = RoleTypeLabel.Text = Loc.GetString(player.RoleProto.Name);
var subtype = roles.GetRoleSubtypeLabel(player.RoleProto.Name, player.Subtype);
var roletype = RoleTypeLabel.Text = Loc.GetString(rolePrototype?.Name ?? RoleTypePrototype.FallbackName);
var subtype = roles.GetRoleSubtypeLabel(rolePrototype?.Name ?? RoleTypePrototype.FallbackName, player.Subtype);
switch (roleSetting)
{
case AdminPlayerTabRoleTypeOption.RoleTypeSubtype:
@@ -92,7 +97,7 @@ public sealed partial class PlayerTabEntry : PanelContainer
}
if (colorRoles)
RoleTypeLabel.FontColorOverride = player.RoleProto.Color;
RoleTypeLabel.FontColorOverride = rolePrototype?.Color ?? RoleTypePrototype.FallbackColor;
BackgroundColorPanel.PanelOverride = styleBoxFlat;
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.Shared.DeviceLinking;
using Content.Shared.DeviceNetwork;
@@ -14,6 +15,8 @@ namespace Content.Client.NetworkConfigurator;
[GenerateTypedNameReferences]
public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
{
private readonly IPrototypeManager _prototypeManager = null!;
private const string PanelBgColor = "#202023";
private readonly LinksRender _links;
@@ -33,6 +36,7 @@ public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
public NetworkConfiguratorLinkMenu()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
var footerStyleBox = new StyleBoxFlat()
{
@@ -61,7 +65,7 @@ public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
ButtonContainerRight.RemoveAllChildren();
_sources.Clear();
_sources.AddRange(linkState.Sources);
_sources.AddRange(linkState.Sources.Select(s => _prototypeManager.Index(s)));
_links.SourceButtons.Clear();
var i = 0;
foreach (var source in _sources)
@@ -73,7 +77,7 @@ public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
}
_sinks.Clear();
_sinks.AddRange(linkState.Sinks);
_sinks.AddRange(linkState.Sinks.Select(s => _prototypeManager.Index(s)));
_links.SinkButtons.Clear();
i = 0;
foreach (var sink in _sinks)

View File

@@ -9,12 +9,14 @@ using Content.Shared.Administration.Logs;
using Content.Shared.CCVar;
using Content.Shared.Chat;
using Content.Shared.Database;
using Content.Shared.Mind;
using Content.Shared.Players.PlayTimeTracking;
using Prometheus;
using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Reflection;
using Robust.Shared.Timing;
@@ -33,6 +35,7 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa
[Dependency] private readonly ISharedPlayerManager _player = default!;
[Dependency] private readonly ISharedPlaytimeManager _playtime = default!;
[Dependency] private readonly ISharedChatManager _chat = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
public const string SawmillId = "admin.logs";
@@ -330,7 +333,8 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa
var cachedInfo = adminSys.GetCachedPlayerInfo(new NetUserId(id));
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(
"admin-alert-antag-label",
("message", logMessage),

View File

@@ -231,7 +231,7 @@ public sealed class AdminSystem : EntitySystem
var antag = false;
// Starting role, antagonist status and role type
RoleTypePrototype roleType = new();
RoleTypePrototype? roleType = null;
var startingRole = string.Empty;
LocId? subtype = 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;
}
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);
startingRole = _jobs.MindTryGetJobName(mindId);
@@ -270,7 +270,7 @@ public sealed class AdminSystem : EntitySystem
identityName,
startingRole,
antag,
roleType,
roleType?.ID,
subtype,
sortWeight,
GetNetEntity(session?.AttachedEntity),

View File

@@ -18,6 +18,7 @@ using Robust.Server.Audio;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Map.Events;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
@@ -496,14 +497,15 @@ public sealed class NetworkConfiguratorSystem : SharedNetworkConfiguratorSystem
return;
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 defaults = _deviceLinkSystem.GetDefaults(sources);
var sourceIds = sources.Select(s => (ProtoId<SourcePortPrototype>)s.ID).ToArray();
var sourceAddress = Resolve(sourceUid, ref sourceNetworkComponent, false) ? sourceNetworkComponent.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);
}

View File

@@ -2,6 +2,7 @@ using Content.Server.Chat.Systems;
using Content.Server.Speech.Components;
using Content.Shared.Chat.Prototypes;
using Content.Shared.Speech.Components;
using Robust.Shared.Prototypes;
namespace Content.Server.Speech.EntitySystems;
@@ -9,6 +10,7 @@ public sealed class MumbleAccentSystem : EntitySystem
{
[Dependency] private readonly ChatSystem _chat = default!;
[Dependency] private readonly ReplacementAccentSystem _replacement = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
public override void Initialize()
{
@@ -23,10 +25,14 @@ public sealed class MumbleAccentSystem : EntitySystem
if (args.Handled || !args.Emote.Category.HasFlag(EmoteCategory.Vocal))
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
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;
}
if (component.EmoteSounds is not { } sounds)
return;
// 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)
@@ -85,7 +88,10 @@ public sealed class VocalSystem : EntitySystem
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)
@@ -97,6 +103,10 @@ public sealed class VocalSystem : EntitySystem
if (!component.Sounds.TryGetValue(sex.Value, out var protoId))
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 Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
namespace Content.Shared.Administration;
@@ -11,7 +12,7 @@ public sealed record PlayerInfo(
string IdentityName,
string StartingJob,
bool Antag,
RoleTypePrototype RoleProto,
ProtoId<RoleTypePrototype>? RoleProto,
LocId? Subtype,
int SortWeight,
NetEntity? NetEntity,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,4 @@
using System.Linq;
using Content.Shared.Administration.Logs;
using Content.Shared.Database;
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>
/// Retrieves the available ports from a source
/// </summary>
@@ -160,6 +166,11 @@ public abstract class SharedDeviceLinkSystem : EntitySystem
return sourcePorts;
}
public ProtoId<SinkPortPrototype>[] GetSinkPortIds(Entity<DeviceLinkSinkComponent> source)
{
return source.Comp.Ports.ToArray();
}
/// <summary>
/// Retrieves the available ports from a sink
/// </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.
/// </summary>
[Prototype]
[Serializable, NetSerializable]
public sealed partial class DeviceFrequencyPrototype : IPrototype
{
[IdDataField]

View File

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

View File

@@ -5,27 +5,31 @@ namespace Content.Shared.Mind;
/// <summary>
/// The core properties of Role Types
/// </summary>
[Prototype, Serializable]
[Prototype]
public sealed partial class RoleTypePrototype : IPrototype
{
[IdDataField]
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>
/// The role's name as displayed on the UI.
/// </summary>
[DataField]
public LocId Name = "role-type-crew-aligned-name";
public LocId Name = FallbackName;
/// <summary>
/// The role's displayed color.
/// </summary>
[DataField]
public Color Color = Color.FromHex("#eeeeee");
public Color Color = FallbackColor;
/// <summary>
/// A symbol used to represent the role type.
/// </summary>
[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.
/// </summary>
[Prototype]
[Serializable, NetSerializable]
public sealed partial class AntagPrototype : IPrototype
{
[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.
/// </summary>
[Prototype]
[Serializable, NetSerializable]
public sealed partial class SiliconLawPrototype : SiliconLaw, IPrototype
{
/// <inheritdoc/>

View File

@@ -61,7 +61,7 @@ public sealed partial class SiliconLawset
/// 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>.
/// </summary>
[Prototype, Serializable, NetSerializable]
[Prototype]
public sealed partial class SiliconLawsetPrototype : IPrototype
{
/// <inheritdoc/>

View File

@@ -49,5 +49,5 @@ public sealed partial class VocalComponent : Component
/// </summary>
[ViewVariables]
[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.
/// </summary>
[Prototype]
[DataDefinition, Serializable, NetSerializable]
[DataDefinition]
public sealed partial class CurrencyPrototype : IPrototype
{
[ViewVariables]

View File

@@ -242,7 +242,6 @@ public partial class ListingData : IEquatable<ListingData>
/// Defines a set item listing that is available in a store
/// </summary>
[Prototype]
[Serializable, NetSerializable]
[DataDefinition]
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.
/// </summary>
[Prototype]
[DataDefinition, Serializable, NetSerializable]
[DataDefinition]
public sealed partial class DiscountCategoryPrototype : IPrototype
{
[ViewVariables]

View File

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

View File

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

View File

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