From e8f748ccd40b8d1bee4d343deff3d61112dbeebe Mon Sep 17 00:00:00 2001 From: sleepyyapril Date: Tue, 4 Nov 2025 12:45:31 -0400 Subject: [PATCH 01/11] feat: player requests --- .../_DEN/PlayerRequest/PlayerRequestSystem.cs | 5 + .../_DEN/PlayerRequest/PlayerRequestSystem.cs | 182 ++++++++++++++++++ .../AcceptedRequestAlertEvent.cs | 5 + .../PlayerRequest/PlayerRequestComponent.cs | 22 +++ .../PlayerRequest/PlayerRequestPrototype.cs | 61 ++++++ .../SharedPlayerRequestSystem.cs | 53 +++++ 6 files changed, 328 insertions(+) create mode 100644 Content.Client/_DEN/PlayerRequest/PlayerRequestSystem.cs create mode 100644 Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs create mode 100644 Content.Shared/_DEN/PlayerRequest/AcceptedRequestAlertEvent.cs create mode 100644 Content.Shared/_DEN/PlayerRequest/PlayerRequestComponent.cs create mode 100644 Content.Shared/_DEN/PlayerRequest/PlayerRequestPrototype.cs create mode 100644 Content.Shared/_DEN/PlayerRequest/SharedPlayerRequestSystem.cs diff --git a/Content.Client/_DEN/PlayerRequest/PlayerRequestSystem.cs b/Content.Client/_DEN/PlayerRequest/PlayerRequestSystem.cs new file mode 100644 index 0000000000..16c11c18ed --- /dev/null +++ b/Content.Client/_DEN/PlayerRequest/PlayerRequestSystem.cs @@ -0,0 +1,5 @@ +using Content.Shared._DEN.PlayerRequest; + +namespace Content.Client._DEN.PlayerRequest; + +public sealed class PlayerRequestSystem : SharedPlayerRequestSystem; diff --git a/Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs b/Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs new file mode 100644 index 0000000000..3d65c2a8c0 --- /dev/null +++ b/Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs @@ -0,0 +1,182 @@ +using Content.Server.Alert; +using Content.Server.Popups; +using Content.Shared._DEN.PlayerRequest; +using Content.Shared.Alert; +using Content.Shared.Popups; +using Robust.Shared.Prototypes; + +namespace Content.Server._DEN.PlayerRequest; + +public sealed class PlayerRequestSystem : SharedPlayerRequestSystem +{ + [Dependency] private readonly ServerAlertsSystem _alertsSystem = null!; + [Dependency] private readonly PopupSystem _popupSystem = null!; + [Dependency] private readonly IPrototypeManager _protoManager = null!; + + private readonly Dictionary, List> _registryEntries = new(); + private readonly Dictionary, ProtoId> _alertTranslations = new(); + + private const PopupType RequestPopupType = PopupType.Medium; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnRequestAccepted); + + _protoManager.PrototypesReloaded += OnPrototypesReloaded; + InitializePrototypes(); + } + + private void OnRequestAccepted(AcceptedRequestAlertEvent ev) + { + var translation = _alertTranslations[ev.AlertId]; + var requestProto = _protoManager.Index(translation); + + if (!_registryEntries.TryGetValue(requestProto, out var events) + || events.Count == 0) + return; + + // This should never happen. + if (!TryComp(ev.User, out var requestComp)) + throw new InvalidOperationException("Request was accepted, but we don't have a PlayerRequestComponent?"); + + var requesterUid = GetEntity(requestComp.Target); + + if (requesterUid == EntityUid.Invalid) + return; + + var statusUpdatedEvent = new PlayerRequestStatusUpdatedEvent(translation, ev.User, true); + RaiseLocalEvent(statusUpdatedEvent); + + foreach (var entry in events) + { + var requester = requestComp.IsRequester ? ev.User : requesterUid; + var target = !requestComp.IsRequester ? ev.User : requesterUid; + + entry.OnAccepted(requester, target); + ClearAlert(translation, target); + + if (requestProto.AcceptPopup == null) + continue; + + var acceptPopup = Loc.GetString(requestProto.AcceptPopup, ("target", target)); + _popupSystem.PopupEntity(acceptPopup, requester, requester, RequestPopupType); + } + } + + private void OnPrototypesReloaded(PrototypesReloadedEventArgs args) + { + if (args.WasModified()) + InitializePrototypes(); + } + + /// + /// Registers a new for player request callbacks. + /// + /// The that the request falls under. + /// The callback to run if they accepted the request. + /// The optional callback to run if they declined the request. + /// Parameters for callback actions are always ordered: Requester, Target + public void RegisterRequestCallback(ProtoId request, + Action onAccepted, + Action? onCancelled = null + ) + { + if (!_registryEntries.TryGetValue(request, out _)) + _registryEntries[request] = new List(); + + var requestInfo = new RequestRegistryEntry(onAccepted, onCancelled); + _registryEntries[request].Add(requestInfo); + } + + public override void StartRequest(ProtoId request, EntityUid requester, EntityUid target) + { + if (HasComp(requester) || HasComp(target) + || !_protoManager.TryIndex(request, out var requestProto)) + return; + + var ev = new AttemptPlayerRequestEvent(request, requester, target); + RaiseLocalEvent(ref ev); + + if (ev.Cancelled) + return; + + var requesterComp = EnsureComp(requester); + var targetComp = EnsureComp(target); + + var receivePopup = Loc.GetString(requestProto.ReceivePopup, ("requester", requester)); + var sendPopup = Loc.GetString(requestProto.SendPopup, ("target", target)); + + requesterComp.IsRequester = true; + requesterComp.Target = GetNetEntity(target); + + targetComp.IsRequester = false; + targetComp.Target = GetNetEntity(requester); + + Dirty(requester, requesterComp); + Dirty(target, targetComp); + ShowAlert(request, target); + + _popupSystem.PopupEntity(receivePopup, target, target, RequestPopupType); + _popupSystem.PopupEntity(sendPopup, requester, requester, RequestPopupType); + + RaiseLocalEvent(new PlayerRequestStartedEvent(request, requester, target)); + } + + private void ShowAlert(ProtoId request, EntityUid target) + { + if (!Exists(target) || !TryComp(target, out var alerts)) + return; + + if (!_protoManager.TryIndex(request, out var requestProto)) + return; + + _alertsSystem.ShowAlert((target, alerts), requestProto.Alert); + } + + private void ClearAlert(ProtoId request, EntityUid target) + { + if (!Exists(target) || !TryComp(target, out var alerts)) + return; + + if (!_protoManager.TryIndex(request, out var requestProto)) + return; + + _alertsSystem.ClearAlert((target, alerts), requestProto.Alert); + } + + private void InitializePrototypes() + { + foreach (var requestPrototype in _protoManager.EnumeratePrototypes()) + { + _alertTranslations[requestPrototype.Alert] = requestPrototype; + + if (!_registryEntries.TryGetValue(requestPrototype, out var registry)) + registry = new(); + + _registryEntries[requestPrototype] = registry; + } + } +} + +[ByRefEvent] +public record struct AttemptPlayerRequestEvent( + ProtoId RequestId, + EntityUid Requester, + EntityUid Target, + bool Cancelled = false); + +public record struct PlayerRequestStartedEvent( + ProtoId RequestId, + EntityUid Requester, + EntityUid Target); + +public record struct PlayerRequestStatusUpdatedEvent( + ProtoId RequestId, + EntityUid UpdatedBy, + bool IsApproved); + +public record struct RequestRegistryEntry( + Action OnAccepted, + Action? OnCancelled); diff --git a/Content.Shared/_DEN/PlayerRequest/AcceptedRequestAlertEvent.cs b/Content.Shared/_DEN/PlayerRequest/AcceptedRequestAlertEvent.cs new file mode 100644 index 0000000000..c6ccb13567 --- /dev/null +++ b/Content.Shared/_DEN/PlayerRequest/AcceptedRequestAlertEvent.cs @@ -0,0 +1,5 @@ +using Content.Shared.Alert; + +namespace Content.Shared._DEN.PlayerRequest; + +public sealed partial class AcceptedRequestAlertEvent : BaseAlertEvent; diff --git a/Content.Shared/_DEN/PlayerRequest/PlayerRequestComponent.cs b/Content.Shared/_DEN/PlayerRequest/PlayerRequestComponent.cs new file mode 100644 index 0000000000..e934872700 --- /dev/null +++ b/Content.Shared/_DEN/PlayerRequest/PlayerRequestComponent.cs @@ -0,0 +1,22 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._DEN.PlayerRequest; + +/// +/// This is used for tracking an active request. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class PlayerRequestComponent : Component +{ + /// + /// Whether the user is the requester or not. + /// + [DataField, AutoNetworkedField] + public bool IsRequester; + + /// + /// The other user involved in a player request. + /// + [DataField, AutoNetworkedField] + public NetEntity Target; +} diff --git a/Content.Shared/_DEN/PlayerRequest/PlayerRequestPrototype.cs b/Content.Shared/_DEN/PlayerRequest/PlayerRequestPrototype.cs new file mode 100644 index 0000000000..fb61d32c8c --- /dev/null +++ b/Content.Shared/_DEN/PlayerRequest/PlayerRequestPrototype.cs @@ -0,0 +1,61 @@ +using Content.Shared.Alert; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Array; + +namespace Content.Shared._DEN.PlayerRequest; + +/// +/// This is a prototype for declaring player requests +/// +[Prototype] +public sealed class PlayerRequestPrototype : IPrototype, IInheritingPrototype +{ + /// + [IdDataField] + public string ID { get; } = default!; + + /// + [ParentDataField(typeof(AbstractPrototypeIdArraySerializer))] + public string[]? Parents { get; } + + /// + [NeverPushInheritance] + [AbstractDataField] + public bool Abstract { get; } + + /// + /// The specific alert to use for this request. + /// + [DataField] + public ProtoId Alert = "PlayerRequestAcceptAlert"; + + /// + /// How long (in seconds) should the request stay waiting for a player to accept before canceling? + /// + [DataField] + public int AutoDeclineAfter { get; } = 30; + + /// + /// The popup message that will appear when a player receives this request. + /// + [DataField(required: true)] + public LocId ReceivePopup { get; } + + /// + /// The popup message that will appear when a player sends the request. + /// + [DataField(required: true)] + public LocId SendPopup { get; } + + /// + /// The popup message that will appear to the requester when the target player accepts this request. + /// + [DataField] + public LocId? AcceptPopup { get; } + + /// + /// The popup message that will appear to the requester when the target player accepts this request. + /// + [DataField] + public LocId? CancelledPopup { get; } +} diff --git a/Content.Shared/_DEN/PlayerRequest/SharedPlayerRequestSystem.cs b/Content.Shared/_DEN/PlayerRequest/SharedPlayerRequestSystem.cs new file mode 100644 index 0000000000..2753213d0f --- /dev/null +++ b/Content.Shared/_DEN/PlayerRequest/SharedPlayerRequestSystem.cs @@ -0,0 +1,53 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared._DEN.PlayerRequest; + +/// +/// Handles player-to-player requests, such as when a player offers something. +/// +public abstract partial class SharedPlayerRequestSystem : EntitySystem +{ + public override void Initialize() + { + base.Initialize(); + + + } + + /// + /// Start a player request that sends the popups and alert as needed. + /// + /// The ID for this request. + /// The one who initiated the request. + /// The target of the request. + public virtual void StartRequest(ProtoId request, + EntityUid requester, + EntityUid target) + { + } + + /// + /// Cancels a player request, removing the alert and notifying the other party. + /// Sends a PlayerRequestStatusUpdated event. + /// + /// The ID for this request. + /// The user canceling the request. + public virtual void CancelRequest( + ProtoId request, + EntityUid cancelling) + { + } + + /// + /// Approves a player request, removing the alert. + /// also allows for an optional popup to the requester when approved. + /// Sends a PlayerRequestStatusUpdated event. + /// + /// The ID for this request. + /// The target who approved the request. + public virtual void ApproveRequest( + ProtoId request, + EntityUid target) + { + } +} From b817dbe975ecb337d98750e343ae67f86800e03e Mon Sep 17 00:00:00 2001 From: sleepyyapril Date: Tue, 4 Nov 2025 12:48:23 -0400 Subject: [PATCH 02/11] fix: fixed only being able to offer once --- Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs b/Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs index 3d65c2a8c0..1bb8e1415c 100644 --- a/Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs +++ b/Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs @@ -7,6 +7,7 @@ namespace Content.Server._DEN.PlayerRequest; +// todo: prediction??? maybe unnecessary??? public sealed class PlayerRequestSystem : SharedPlayerRequestSystem { [Dependency] private readonly ServerAlertsSystem _alertsSystem = null!; @@ -57,6 +58,9 @@ private void OnRequestAccepted(AcceptedRequestAlertEvent ev) entry.OnAccepted(requester, target); ClearAlert(translation, target); + RemCompDeferred(requester); + RemCompDeferred(target); + if (requestProto.AcceptPopup == null) continue; From 23aad264a5735e4ea48ae58dfd7ae4228240757b Mon Sep 17 00:00:00 2001 From: sleepyyapril Date: Tue, 4 Nov 2025 12:49:21 -0400 Subject: [PATCH 03/11] chore: cleanup --- .../_DEN/PlayerRequest/SharedPlayerRequestSystem.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Content.Shared/_DEN/PlayerRequest/SharedPlayerRequestSystem.cs b/Content.Shared/_DEN/PlayerRequest/SharedPlayerRequestSystem.cs index 2753213d0f..e6f9482f8b 100644 --- a/Content.Shared/_DEN/PlayerRequest/SharedPlayerRequestSystem.cs +++ b/Content.Shared/_DEN/PlayerRequest/SharedPlayerRequestSystem.cs @@ -7,13 +7,6 @@ namespace Content.Shared._DEN.PlayerRequest; /// public abstract partial class SharedPlayerRequestSystem : EntitySystem { - public override void Initialize() - { - base.Initialize(); - - - } - /// /// Start a player request that sends the popups and alert as needed. /// From 6da9c89c649457dfb8571b3e0b93f7e91fa18a65 Mon Sep 17 00:00:00 2001 From: sleepyyapril Date: Wed, 5 Nov 2025 10:55:44 -0400 Subject: [PATCH 04/11] feat: move to shared, kill registry --- .../_DEN/PlayerRequest/PlayerRequestSystem.cs | 2 +- .../_DEN/PlayerRequest/PlayerRequestSystem.cs | 174 ++---------------- .../AcceptedRequestAlertEvent.cs | 5 - .../Components/RequestReceiverComponent.cs | 17 ++ .../Components/RequestSenderComponent.cs | 17 ++ .../SharedPlayerRequestSystem.API.cs | 137 ++++++++++++++ .../SharedPlayerRequestSystem.Helpers.cs | 37 ++++ .../SharedPlayerRequestSystem.cs | 102 ++++++++++ .../Events/PlayerRequestEvents.cs | 23 +++ .../PlayerRequest/PlayerRequestComponent.cs | 22 --- .../PlayerRequestPrototype.cs | 0 .../SharedPlayerRequestSystem.cs | 46 ----- 12 files changed, 352 insertions(+), 230 deletions(-) delete mode 100644 Content.Shared/_DEN/PlayerRequest/AcceptedRequestAlertEvent.cs create mode 100644 Content.Shared/_DEN/PlayerRequest/Components/RequestReceiverComponent.cs create mode 100644 Content.Shared/_DEN/PlayerRequest/Components/RequestSenderComponent.cs create mode 100644 Content.Shared/_DEN/PlayerRequest/EntitySystems/SharedPlayerRequestSystem.API.cs create mode 100644 Content.Shared/_DEN/PlayerRequest/EntitySystems/SharedPlayerRequestSystem.Helpers.cs create mode 100644 Content.Shared/_DEN/PlayerRequest/EntitySystems/SharedPlayerRequestSystem.cs create mode 100644 Content.Shared/_DEN/PlayerRequest/Events/PlayerRequestEvents.cs delete mode 100644 Content.Shared/_DEN/PlayerRequest/PlayerRequestComponent.cs rename Content.Shared/_DEN/PlayerRequest/{ => Prototypes}/PlayerRequestPrototype.cs (100%) delete mode 100644 Content.Shared/_DEN/PlayerRequest/SharedPlayerRequestSystem.cs diff --git a/Content.Client/_DEN/PlayerRequest/PlayerRequestSystem.cs b/Content.Client/_DEN/PlayerRequest/PlayerRequestSystem.cs index 16c11c18ed..f7497843da 100644 --- a/Content.Client/_DEN/PlayerRequest/PlayerRequestSystem.cs +++ b/Content.Client/_DEN/PlayerRequest/PlayerRequestSystem.cs @@ -1,4 +1,4 @@ -using Content.Shared._DEN.PlayerRequest; +using Content.Shared._DEN.PlayerRequest.EntitySystems; namespace Content.Client._DEN.PlayerRequest; diff --git a/Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs b/Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs index 1bb8e1415c..e95aadfe6e 100644 --- a/Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs +++ b/Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs @@ -1,186 +1,48 @@ -using Content.Server.Alert; using Content.Server.Popups; using Content.Shared._DEN.PlayerRequest; -using Content.Shared.Alert; +using Content.Shared._DEN.PlayerRequest.Components; +using Content.Shared._DEN.PlayerRequest.EntitySystems; using Content.Shared.Popups; using Robust.Shared.Prototypes; namespace Content.Server._DEN.PlayerRequest; -// todo: prediction??? maybe unnecessary??? public sealed class PlayerRequestSystem : SharedPlayerRequestSystem { - [Dependency] private readonly ServerAlertsSystem _alertsSystem = null!; [Dependency] private readonly PopupSystem _popupSystem = null!; - [Dependency] private readonly IPrototypeManager _protoManager = null!; - private readonly Dictionary, List> _registryEntries = new(); - private readonly Dictionary, ProtoId> _alertTranslations = new(); - - private const PopupType RequestPopupType = PopupType.Medium; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnRequestAccepted); - - _protoManager.PrototypesReloaded += OnPrototypesReloaded; - InitializePrototypes(); - } - - private void OnRequestAccepted(AcceptedRequestAlertEvent ev) + public override void StartRequest(ProtoId request, EntityUid sender, EntityUid receiver) { - var translation = _alertTranslations[ev.AlertId]; - var requestProto = _protoManager.Index(translation); - - if (!_registryEntries.TryGetValue(requestProto, out var events) - || events.Count == 0) - return; - - // This should never happen. - if (!TryComp(ev.User, out var requestComp)) - throw new InvalidOperationException("Request was accepted, but we don't have a PlayerRequestComponent?"); - - var requesterUid = GetEntity(requestComp.Target); - - if (requesterUid == EntityUid.Invalid) - return; - - var statusUpdatedEvent = new PlayerRequestStatusUpdatedEvent(translation, ev.User, true); - RaiseLocalEvent(statusUpdatedEvent); - - foreach (var entry in events) + if (!CanRequest(request, sender, receiver, out var reason)) { - var requester = requestComp.IsRequester ? ev.User : requesterUid; - var target = !requestComp.IsRequester ? ev.User : requesterUid; - - entry.OnAccepted(requester, target); - ClearAlert(translation, target); - - RemCompDeferred(requester); - RemCompDeferred(target); - - if (requestProto.AcceptPopup == null) - continue; - - var acceptPopup = Loc.GetString(requestProto.AcceptPopup, ("target", target)); - _popupSystem.PopupEntity(acceptPopup, requester, requester, RequestPopupType); - } - } - - private void OnPrototypesReloaded(PrototypesReloadedEventArgs args) - { - if (args.WasModified()) - InitializePrototypes(); - } - - /// - /// Registers a new for player request callbacks. - /// - /// The that the request falls under. - /// The callback to run if they accepted the request. - /// The optional callback to run if they declined the request. - /// Parameters for callback actions are always ordered: Requester, Target - public void RegisterRequestCallback(ProtoId request, - Action onAccepted, - Action? onCancelled = null - ) - { - if (!_registryEntries.TryGetValue(request, out _)) - _registryEntries[request] = new List(); - - var requestInfo = new RequestRegistryEntry(onAccepted, onCancelled); - _registryEntries[request].Add(requestInfo); - } - - public override void StartRequest(ProtoId request, EntityUid requester, EntityUid target) - { - if (HasComp(requester) || HasComp(target) - || !_protoManager.TryIndex(request, out var requestProto)) + _popupSystem.PopupEntity(reason, sender, sender, PopupType.MediumCaution); return; + } - var ev = new AttemptPlayerRequestEvent(request, requester, target); + var ev = new AttemptPlayerRequestEvent(request, sender, receiver); RaiseLocalEvent(ref ev); if (ev.Cancelled) return; - var requesterComp = EnsureComp(requester); - var targetComp = EnsureComp(target); - - var receivePopup = Loc.GetString(requestProto.ReceivePopup, ("requester", requester)); - var sendPopup = Loc.GetString(requestProto.SendPopup, ("target", target)); - - requesterComp.IsRequester = true; - requesterComp.Target = GetNetEntity(target); - - targetComp.IsRequester = false; - targetComp.Target = GetNetEntity(requester); - - Dirty(requester, requesterComp); - Dirty(target, targetComp); - ShowAlert(request, target); + var senderComp = EnsureComp(sender); + var receiverComp = EnsureComp(receiver); - _popupSystem.PopupEntity(receivePopup, target, target, RequestPopupType); - _popupSystem.PopupEntity(sendPopup, requester, requester, RequestPopupType); - - RaiseLocalEvent(new PlayerRequestStartedEvent(request, requester, target)); - } - - private void ShowAlert(ProtoId request, EntityUid target) - { - if (!Exists(target) || !TryComp(target, out var alerts)) - return; - - if (!_protoManager.TryIndex(request, out var requestProto)) - return; + senderComp.Receivers[request] = receiver; + receiverComp.Senders[request] = sender; - _alertsSystem.ShowAlert((target, alerts), requestProto.Alert); + RaiseLocalEvent(new PlayerRequestStartedEvent(request, sender, receiver)); } - private void ClearAlert(ProtoId request, EntityUid target) + public override void ApproveRequest(ProtoId request, EntityUid receiver) { - if (!Exists(target) || !TryComp(target, out var alerts)) - return; - - if (!_protoManager.TryIndex(request, out var requestProto)) - return; - - _alertsSystem.ClearAlert((target, alerts), requestProto.Alert); + var statusUpdatedEvent = new PlayerRequestUpdatedEvent(request, receiver, true); + RaiseLocalEvent(statusUpdatedEvent); } - private void InitializePrototypes() + public override void CancelRequest(ProtoId request, EntityUid cancelling) { - foreach (var requestPrototype in _protoManager.EnumeratePrototypes()) - { - _alertTranslations[requestPrototype.Alert] = requestPrototype; - - if (!_registryEntries.TryGetValue(requestPrototype, out var registry)) - registry = new(); - - _registryEntries[requestPrototype] = registry; - } + var statusUpdatedEvent = new PlayerRequestUpdatedEvent(request, cancelling, false); + RaiseLocalEvent(statusUpdatedEvent); } } - -[ByRefEvent] -public record struct AttemptPlayerRequestEvent( - ProtoId RequestId, - EntityUid Requester, - EntityUid Target, - bool Cancelled = false); - -public record struct PlayerRequestStartedEvent( - ProtoId RequestId, - EntityUid Requester, - EntityUid Target); - -public record struct PlayerRequestStatusUpdatedEvent( - ProtoId RequestId, - EntityUid UpdatedBy, - bool IsApproved); - -public record struct RequestRegistryEntry( - Action OnAccepted, - Action? OnCancelled); diff --git a/Content.Shared/_DEN/PlayerRequest/AcceptedRequestAlertEvent.cs b/Content.Shared/_DEN/PlayerRequest/AcceptedRequestAlertEvent.cs deleted file mode 100644 index c6ccb13567..0000000000 --- a/Content.Shared/_DEN/PlayerRequest/AcceptedRequestAlertEvent.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Content.Shared.Alert; - -namespace Content.Shared._DEN.PlayerRequest; - -public sealed partial class AcceptedRequestAlertEvent : BaseAlertEvent; diff --git a/Content.Shared/_DEN/PlayerRequest/Components/RequestReceiverComponent.cs b/Content.Shared/_DEN/PlayerRequest/Components/RequestReceiverComponent.cs new file mode 100644 index 0000000000..02e2396174 --- /dev/null +++ b/Content.Shared/_DEN/PlayerRequest/Components/RequestReceiverComponent.cs @@ -0,0 +1,17 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared._DEN.PlayerRequest.Components; + +/// +/// This is used for tracking active requests where the user is a receiver. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class RequestReceiverComponent : Component +{ + /// + /// The other users involved in a player request. + /// + [DataField, AutoNetworkedField] + public Dictionary, EntityUid> Senders = new(); +} diff --git a/Content.Shared/_DEN/PlayerRequest/Components/RequestSenderComponent.cs b/Content.Shared/_DEN/PlayerRequest/Components/RequestSenderComponent.cs new file mode 100644 index 0000000000..8b6fcf2839 --- /dev/null +++ b/Content.Shared/_DEN/PlayerRequest/Components/RequestSenderComponent.cs @@ -0,0 +1,17 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared._DEN.PlayerRequest.Components; + +/// +/// This is used for tracking active requests where this user is the sender. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class RequestSenderComponent : Component +{ + /// + /// The other user involved in a player request. + /// + [DataField, AutoNetworkedField] + public Dictionary, EntityUid> Receivers = new(); +} diff --git a/Content.Shared/_DEN/PlayerRequest/EntitySystems/SharedPlayerRequestSystem.API.cs b/Content.Shared/_DEN/PlayerRequest/EntitySystems/SharedPlayerRequestSystem.API.cs new file mode 100644 index 0000000000..fa271c5020 --- /dev/null +++ b/Content.Shared/_DEN/PlayerRequest/EntitySystems/SharedPlayerRequestSystem.API.cs @@ -0,0 +1,137 @@ +using Content.Shared._DEN.PlayerRequest.Components; +using Robust.Shared.Prototypes; + +namespace Content.Shared._DEN.PlayerRequest.EntitySystems; + +public abstract partial class SharedPlayerRequestSystem +{ + /// + /// Start a player request that sends the popups and alert as needed. + /// + /// The ID for this request. + /// The one who initiated the request. + /// The target of the request. + public virtual void StartRequest(ProtoId request, + EntityUid requester, + EntityUid target) + { + } + + /// + /// Cancels a player request, removing the alert and notifying the other party. + /// Sends a PlayerRequestStatusUpdated event. + /// + /// The ID for this request. + /// The user canceling the request. + public virtual void CancelRequest( + ProtoId request, + EntityUid cancelling) + { + } + + /// + /// Approves a player request, removing the alert. + /// also allows for an optional popup to the requester when approved. + /// Sends a PlayerRequestStatusUpdated event. + /// + /// The ID for this request. + /// The receiver who approved the request. + public virtual void ApproveRequest( + ProtoId request, + EntityUid receiver) + { + } + + /// + /// Tries to get the sender's from a receiver . + /// + /// The request that we should try to find the sender in. + /// The receiver that received the request. + /// The output sender that was acquired. + /// The to be resolved. + /// True if a valid EntityUid was found, false if not. + /// The entity will always exist if it returned true. + public bool TryGetSender(ProtoId request, + EntityUid receiver, + out EntityUid sender, + RequestReceiverComponent? receiverComp = null) + { + sender = EntityUid.Invalid; + + if (!Resolve(receiver, ref receiverComp, false) + || !receiverComp.Senders.TryGetValue(request, out var potentialSender) + || !Exists(potentialSender)) + return false; + + sender = potentialSender; + return true; + } + + /// + /// Tries to get the receiver's from a sender . + /// + /// The request that the sender sent. + /// The sender that sent the request. + /// The output receiver acquired. + /// The to be resolved. + /// True if a valid EntityUid was found, false if not. + /// The entity will always exist if it returned true. + public bool TryGetReceiver(ProtoId request, + EntityUid sender, + out EntityUid receiver, + RequestSenderComponent? senderComp = null) + { + receiver = EntityUid.Invalid; + + if (!Resolve(sender, ref senderComp, false) + || !senderComp.Receivers.TryGetValue(request, out var potentialReceiver) + || !Exists(potentialReceiver)) + return false; + + receiver = potentialReceiver; + return true; + } + + /// + /// Whether or not a request should go forth. + /// + /// The request attempting to be made. + /// The sender trying to send a request. + /// The receiver that would get the request. + /// The display-friendly message if we couldn't request. + /// Whether or not they can request in their current condition. + protected bool CanRequest( + ProtoId request, + EntityUid sender, + EntityUid receiver, + out string? reason) + { + reason = null; + + // If any of the users don't exist or don't have a mind, + // there's no one to send a request to. + if (!Exists(sender) || !Exists(receiver) + || !_mindSystem.TryGetMind(sender, out _, out _) + || !_mindSystem.TryGetMind(receiver, out _, out _)) + { + return false; + } + + // Alerts only support one alert at a time, so might as well enforce it. + if (TryComp(sender, out var requestSenderComp) + && requestSenderComp.Receivers.ContainsKey(request)) + { + reason = Loc.GetString("player-request-existing-sender", ("sender", sender)); + return false; + } + + if (TryComp(receiver, out var requestReceiverComp) + && requestReceiverComp.Senders.ContainsKey(request)) + { + reason = Loc.GetString("player-request-existing-receiver", ("receiver", receiver)); + return false; + } + + return true; + } +} diff --git a/Content.Shared/_DEN/PlayerRequest/EntitySystems/SharedPlayerRequestSystem.Helpers.cs b/Content.Shared/_DEN/PlayerRequest/EntitySystems/SharedPlayerRequestSystem.Helpers.cs new file mode 100644 index 0000000000..084a72306f --- /dev/null +++ b/Content.Shared/_DEN/PlayerRequest/EntitySystems/SharedPlayerRequestSystem.Helpers.cs @@ -0,0 +1,37 @@ +using Content.Shared.Alert; +using Robust.Shared.Prototypes; + +namespace Content.Shared._DEN.PlayerRequest.EntitySystems; + +public abstract partial class SharedPlayerRequestSystem +{ + private void ShowAlert(ProtoId request, EntityUid target) + { + if (!Exists(target) || !TryComp(target, out var alerts)) + return; + + if (!_protoManager.TryIndex(request, out var requestProto)) + return; + + _alertsSystem.ShowAlert((target, alerts), requestProto.Alert); + } + + private void ClearAlert(ProtoId request, EntityUid target) + { + if (!Exists(target) || !TryComp(target, out var alerts)) + return; + + if (!_protoManager.TryIndex(request, out var requestProto)) + return; + + _alertsSystem.ClearAlert((target, alerts), requestProto.Alert); + } + + private void InitializePrototypes() + { + foreach (var requestPrototype in _protoManager.EnumeratePrototypes()) + { + _alertTranslations[requestPrototype.Alert] = requestPrototype; + } + } +} diff --git a/Content.Shared/_DEN/PlayerRequest/EntitySystems/SharedPlayerRequestSystem.cs b/Content.Shared/_DEN/PlayerRequest/EntitySystems/SharedPlayerRequestSystem.cs new file mode 100644 index 0000000000..3e51c989be --- /dev/null +++ b/Content.Shared/_DEN/PlayerRequest/EntitySystems/SharedPlayerRequestSystem.cs @@ -0,0 +1,102 @@ +using Content.Shared._DEN.PlayerRequest.Components; +using Content.Shared._DEN.PlayerRequest.Events; +using Content.Shared.Alert; +using Content.Shared.Mind; +using Content.Shared.Popups; +using Robust.Shared.Prototypes; + +namespace Content.Shared._DEN.PlayerRequest.EntitySystems; + +/// +/// Handles player-to-player requests, such as when a player offers something. +/// +public abstract partial class SharedPlayerRequestSystem : EntitySystem +{ + [Dependency] private readonly AlertsSystem _alertsSystem = null!; + [Dependency] private readonly SharedMindSystem _mindSystem = null!; + [Dependency] private readonly SharedPopupSystem _popupSystem = null!; + [Dependency] private readonly IPrototypeManager _protoManager = null!; + + private const PopupType RequestPopupType = PopupType.Medium; + private readonly Dictionary, ProtoId> _alertTranslations = new(); + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnRequestAcceptedAlert); + SubscribeLocalEvent(OnRequestStarted); + SubscribeLocalEvent(OnRequestUpdated); + + InitializePrototypes(); + _protoManager.PrototypesReloaded += OnPrototypesReloaded; + } + + private void OnRequestStarted(PlayerRequestStartedEvent ev) + { + if (!_protoManager.TryIndex(ev.RequestId, out var playerRequest)) + return; + + var receivePopup = Loc.GetString(playerRequest.ReceivePopup, ("sender", ev.Sender)); + var sendPopup = Loc.GetString(playerRequest.SendPopup, ("receiver", ev.Receiver)); + + ShowAlert(ev.RequestId, ev.Receiver); + + _popupSystem.PopupPredicted(receivePopup, ev.Receiver, ev.Receiver, RequestPopupType); + _popupSystem.PopupPredicted(sendPopup, ev.Sender, ev.Sender, RequestPopupType); + } + + private void OnPrototypesReloaded(PrototypesReloadedEventArgs args) + { + if (args.WasModified()) + InitializePrototypes(); + } + + private void OnRequestAcceptedAlert(AcceptedRequestAlertEvent ev) + { + if (!_alertTranslations.TryGetValue(ev.AlertId, out var requestId)) + return; + + var statusUpdatedEvent = new PlayerRequestUpdatedEvent(requestId, ev.User, true); + RaiseLocalEvent(statusUpdatedEvent); + } + + private void OnRequestUpdated(PlayerRequestUpdatedEvent ev) + { + if (!ev.IsApproved) + return; + + var requestProto = _protoManager.Index(ev.RequestId); + + if (!TryComp(ev.Receiver, out var requestComp)) + return; + + if (!TryGetSender(ev.RequestId, ev.Receiver, out var sender, requestComp)) + return; + + ClearAlert(ev.RequestId, ev.Receiver); + + if (requestProto.AcceptPopup == null) + return; + + var acceptPopup = Loc.GetString(requestProto.AcceptPopup, ("receiver", ev.Receiver)); + _popupSystem.PopupPredicted(acceptPopup, sender, sender, RequestPopupType); + } +} + +[ByRefEvent] +public record struct AttemptPlayerRequestEvent( + ProtoId RequestId, + EntityUid Sender, + EntityUid Receiver, + bool Cancelled = false); + +public record struct PlayerRequestStartedEvent( + ProtoId RequestId, + EntityUid Sender, + EntityUid Receiver); + +public record struct PlayerRequestUpdatedEvent( + ProtoId RequestId, + EntityUid Receiver, + bool IsApproved); diff --git a/Content.Shared/_DEN/PlayerRequest/Events/PlayerRequestEvents.cs b/Content.Shared/_DEN/PlayerRequest/Events/PlayerRequestEvents.cs new file mode 100644 index 0000000000..8f0bf3bddd --- /dev/null +++ b/Content.Shared/_DEN/PlayerRequest/Events/PlayerRequestEvents.cs @@ -0,0 +1,23 @@ +using Content.Shared.Alert; +using Robust.Shared.Prototypes; + +namespace Content.Shared._DEN.PlayerRequest.Events; + +[ByRefEvent] +public record struct AttemptPlayerRequestEvent( + ProtoId RequestId, + EntityUid Sender, + EntityUid Receiver, + bool Cancelled = false); + +public record struct PlayerRequestStartedEvent( + ProtoId RequestId, + EntityUid Sender, + EntityUid Receiver); + +public record struct PlayerRequestUpdatedEvent( + ProtoId RequestId, + EntityUid Receiver, + bool IsApproved); + +public sealed partial class AcceptedRequestAlertEvent : BaseAlertEvent; diff --git a/Content.Shared/_DEN/PlayerRequest/PlayerRequestComponent.cs b/Content.Shared/_DEN/PlayerRequest/PlayerRequestComponent.cs deleted file mode 100644 index e934872700..0000000000 --- a/Content.Shared/_DEN/PlayerRequest/PlayerRequestComponent.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared._DEN.PlayerRequest; - -/// -/// This is used for tracking an active request. -/// -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -public sealed partial class PlayerRequestComponent : Component -{ - /// - /// Whether the user is the requester or not. - /// - [DataField, AutoNetworkedField] - public bool IsRequester; - - /// - /// The other user involved in a player request. - /// - [DataField, AutoNetworkedField] - public NetEntity Target; -} diff --git a/Content.Shared/_DEN/PlayerRequest/PlayerRequestPrototype.cs b/Content.Shared/_DEN/PlayerRequest/Prototypes/PlayerRequestPrototype.cs similarity index 100% rename from Content.Shared/_DEN/PlayerRequest/PlayerRequestPrototype.cs rename to Content.Shared/_DEN/PlayerRequest/Prototypes/PlayerRequestPrototype.cs diff --git a/Content.Shared/_DEN/PlayerRequest/SharedPlayerRequestSystem.cs b/Content.Shared/_DEN/PlayerRequest/SharedPlayerRequestSystem.cs deleted file mode 100644 index e6f9482f8b..0000000000 --- a/Content.Shared/_DEN/PlayerRequest/SharedPlayerRequestSystem.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Robust.Shared.Prototypes; - -namespace Content.Shared._DEN.PlayerRequest; - -/// -/// Handles player-to-player requests, such as when a player offers something. -/// -public abstract partial class SharedPlayerRequestSystem : EntitySystem -{ - /// - /// Start a player request that sends the popups and alert as needed. - /// - /// The ID for this request. - /// The one who initiated the request. - /// The target of the request. - public virtual void StartRequest(ProtoId request, - EntityUid requester, - EntityUid target) - { - } - - /// - /// Cancels a player request, removing the alert and notifying the other party. - /// Sends a PlayerRequestStatusUpdated event. - /// - /// The ID for this request. - /// The user canceling the request. - public virtual void CancelRequest( - ProtoId request, - EntityUid cancelling) - { - } - - /// - /// Approves a player request, removing the alert. - /// also allows for an optional popup to the requester when approved. - /// Sends a PlayerRequestStatusUpdated event. - /// - /// The ID for this request. - /// The target who approved the request. - public virtual void ApproveRequest( - ProtoId request, - EntityUid target) - { - } -} From 2f13df3428855d4f875417320ebf57bb095d7b24 Mon Sep 17 00:00:00 2001 From: sleepyyapril Date: Wed, 5 Nov 2025 10:57:07 -0400 Subject: [PATCH 05/11] fix: dirty --- Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs b/Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs index e95aadfe6e..c8320bc8dc 100644 --- a/Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs +++ b/Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs @@ -31,6 +31,9 @@ public override void StartRequest(ProtoId request, Entit senderComp.Receivers[request] = receiver; receiverComp.Senders[request] = sender; + Dirty(sender, senderComp); + Dirty(receiver, receiverComp); + RaiseLocalEvent(new PlayerRequestStartedEvent(request, sender, receiver)); } From 66c39b22d468de82ba975c40e17fd629b7edbeaf Mon Sep 17 00:00:00 2001 From: sleepyyapril Date: Wed, 5 Nov 2025 11:12:22 -0400 Subject: [PATCH 06/11] chore: use Entity for API methods --- .../SharedPlayerRequestSystem.API.cs | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/Content.Shared/_DEN/PlayerRequest/EntitySystems/SharedPlayerRequestSystem.API.cs b/Content.Shared/_DEN/PlayerRequest/EntitySystems/SharedPlayerRequestSystem.API.cs index fa271c5020..5f38b6e0ba 100644 --- a/Content.Shared/_DEN/PlayerRequest/EntitySystems/SharedPlayerRequestSystem.API.cs +++ b/Content.Shared/_DEN/PlayerRequest/EntitySystems/SharedPlayerRequestSystem.API.cs @@ -48,22 +48,20 @@ public virtual void ApproveRequest( /// The request that we should try to find the sender in. /// The receiver that received the request. /// The output sender that was acquired. - /// The to be resolved. /// True if a valid EntityUid was found, false if not. /// The entity will always exist if it returned true. public bool TryGetSender(ProtoId request, - EntityUid receiver, - out EntityUid sender, - RequestReceiverComponent? receiverComp = null) + Entity receiver, + out Entity sender) { sender = EntityUid.Invalid; - if (!Resolve(receiver, ref receiverComp, false) - || !receiverComp.Senders.TryGetValue(request, out var potentialSender) - || !Exists(potentialSender)) + if (!Resolve(receiver, ref receiver.Comp, false) + || !receiver.Comp.Senders.TryGetValue(request, out var potentialSender) + || !Exists(potentialSender) || !TryComp(potentialSender, out var senderComp)) return false; - sender = potentialSender; + sender = (potentialSender, senderComp); return true; } @@ -73,22 +71,20 @@ public bool TryGetSender(ProtoId request, /// The request that the sender sent. /// The sender that sent the request. /// The output receiver acquired. - /// The to be resolved. /// True if a valid EntityUid was found, false if not. /// The entity will always exist if it returned true. public bool TryGetReceiver(ProtoId request, - EntityUid sender, - out EntityUid receiver, - RequestSenderComponent? senderComp = null) + Entity sender, + out Entity receiver) { receiver = EntityUid.Invalid; - if (!Resolve(sender, ref senderComp, false) - || !senderComp.Receivers.TryGetValue(request, out var potentialReceiver) - || !Exists(potentialReceiver)) + if (!Resolve(sender, ref sender.Comp, false) + || !sender.Comp.Receivers.TryGetValue(request, out var potentialReceiver) + || !Exists(potentialReceiver) || !TryComp(potentialReceiver, out var receiverComp)) return false; - receiver = potentialReceiver; + receiver = (potentialReceiver, receiverComp); return true; } From a1ad7313c4548aac2fce14a51831d4e5d99689fa Mon Sep 17 00:00:00 2001 From: sleepyyapril Date: Wed, 5 Nov 2025 11:12:49 -0400 Subject: [PATCH 07/11] feat: reset on updated in event --- .../SharedPlayerRequestSystem.cs | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/Content.Shared/_DEN/PlayerRequest/EntitySystems/SharedPlayerRequestSystem.cs b/Content.Shared/_DEN/PlayerRequest/EntitySystems/SharedPlayerRequestSystem.cs index 3e51c989be..a021558225 100644 --- a/Content.Shared/_DEN/PlayerRequest/EntitySystems/SharedPlayerRequestSystem.cs +++ b/Content.Shared/_DEN/PlayerRequest/EntitySystems/SharedPlayerRequestSystem.cs @@ -57,21 +57,37 @@ private void OnRequestAcceptedAlert(AcceptedRequestAlertEvent ev) if (!_alertTranslations.TryGetValue(ev.AlertId, out var requestId)) return; - var statusUpdatedEvent = new PlayerRequestUpdatedEvent(requestId, ev.User, true); + if (!TryGetSender(requestId, ev.User, out var sender)) + return; + + var statusUpdatedEvent = new PlayerRequestUpdatedEvent(requestId, ev.User, sender, true); RaiseLocalEvent(statusUpdatedEvent); } private void OnRequestUpdated(PlayerRequestUpdatedEvent ev) { - if (!ev.IsApproved) + if (ev.IsApproved) + OnRequestApproved(ev); + + if (!TryComp(ev.Receiver, out var receiverComp) + || !TryComp(ev.Sender, out var senderComp)) return; + receiverComp.Senders.Remove(ev.RequestId); + senderComp.Receivers.Remove(ev.RequestId); + + Dirty(ev.Receiver, receiverComp); + Dirty(ev.Sender, senderComp); + } + + private void OnRequestApproved(PlayerRequestUpdatedEvent ev) + { var requestProto = _protoManager.Index(ev.RequestId); if (!TryComp(ev.Receiver, out var requestComp)) return; - if (!TryGetSender(ev.RequestId, ev.Receiver, out var sender, requestComp)) + if (!TryGetSender(ev.RequestId, (ev.Receiver, requestComp), out var sender)) return; ClearAlert(ev.RequestId, ev.Receiver); @@ -99,4 +115,5 @@ public record struct PlayerRequestStartedEvent( public record struct PlayerRequestUpdatedEvent( ProtoId RequestId, EntityUid Receiver, + EntityUid Sender, bool IsApproved); From 2e880baff4916ca99430094fc40e922d421caa84 Mon Sep 17 00:00:00 2001 From: sleepyyapril Date: Thu, 6 Nov 2025 02:39:22 -0400 Subject: [PATCH 08/11] fix: error --- .../_DEN/PlayerRequest/PlayerRequestSystem.cs | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs b/Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs index c8320bc8dc..00cd623b4c 100644 --- a/Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs +++ b/Content.Server/_DEN/PlayerRequest/PlayerRequestSystem.cs @@ -39,13 +39,37 @@ public override void StartRequest(ProtoId request, Entit public override void ApproveRequest(ProtoId request, EntityUid receiver) { - var statusUpdatedEvent = new PlayerRequestUpdatedEvent(request, receiver, true); + if (!TryComp(receiver, out var receiverComp) + || !TryGetSender(request, (receiver, receiverComp), out var sender)) + return; + + var statusUpdatedEvent = new PlayerRequestUpdatedEvent(request, receiver, sender, true); RaiseLocalEvent(statusUpdatedEvent); } public override void CancelRequest(ProtoId request, EntityUid cancelling) { - var statusUpdatedEvent = new PlayerRequestUpdatedEvent(request, cancelling, false); + Entity sender; + Entity receiver; + + if (TryGetSender(request, cancelling, out var potentialSender) + && TryComp(cancelling, out var receiverComp)) + { + sender = potentialSender; + receiver = (cancelling, receiverComp); + } + else if (TryGetReceiver(request, cancelling, out var potentialReceiver) + && TryComp(cancelling, out var senderComp)) + { + sender = (cancelling, senderComp); + receiver = potentialReceiver; + } + else + { + return; + } + + var statusUpdatedEvent = new PlayerRequestUpdatedEvent(request, receiver, sender, false); RaiseLocalEvent(statusUpdatedEvent); } } From 8095d262546e74c47812458e9767b7092e17d707 Mon Sep 17 00:00:00 2001 From: sleepyyapril <123355664+sleepyyapril@users.noreply.github.com> Date: Thu, 12 Feb 2026 13:50:56 -0400 Subject: [PATCH 09/11] Update PlayerRequestPrototype.cs --- .../_DEN/PlayerRequest/Prototypes/PlayerRequestPrototype.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Shared/_DEN/PlayerRequest/Prototypes/PlayerRequestPrototype.cs b/Content.Shared/_DEN/PlayerRequest/Prototypes/PlayerRequestPrototype.cs index fb61d32c8c..51a3220b57 100644 --- a/Content.Shared/_DEN/PlayerRequest/Prototypes/PlayerRequestPrototype.cs +++ b/Content.Shared/_DEN/PlayerRequest/Prototypes/PlayerRequestPrototype.cs @@ -8,7 +8,7 @@ namespace Content.Shared._DEN.PlayerRequest; /// This is a prototype for declaring player requests /// [Prototype] -public sealed class PlayerRequestPrototype : IPrototype, IInheritingPrototype +public sealed partial class PlayerRequestPrototype : IPrototype, IInheritingPrototype { /// [IdDataField] From 3f59a4cd3b4aa46240b9468cd126881d1b946686 Mon Sep 17 00:00:00 2001 From: sleepyyapril <123355664+sleepyyapril@users.noreply.github.com> Date: Thu, 12 Feb 2026 14:00:48 -0400 Subject: [PATCH 10/11] Apply suggestions from code review --- .../PlayerRequest/Prototypes/PlayerRequestPrototype.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Content.Shared/_DEN/PlayerRequest/Prototypes/PlayerRequestPrototype.cs b/Content.Shared/_DEN/PlayerRequest/Prototypes/PlayerRequestPrototype.cs index 51a3220b57..3e3bd61e58 100644 --- a/Content.Shared/_DEN/PlayerRequest/Prototypes/PlayerRequestPrototype.cs +++ b/Content.Shared/_DEN/PlayerRequest/Prototypes/PlayerRequestPrototype.cs @@ -33,29 +33,29 @@ public sealed partial class PlayerRequestPrototype : IPrototype, IInheritingProt /// How long (in seconds) should the request stay waiting for a player to accept before canceling? /// [DataField] - public int AutoDeclineAfter { get; } = 30; + public int AutoDeclineAfter { get; set; } = 30; /// /// The popup message that will appear when a player receives this request. /// [DataField(required: true)] - public LocId ReceivePopup { get; } + public LocId ReceivePopup { get; set; } /// /// The popup message that will appear when a player sends the request. /// [DataField(required: true)] - public LocId SendPopup { get; } + public LocId SendPopup { get; set; } /// /// The popup message that will appear to the requester when the target player accepts this request. /// [DataField] - public LocId? AcceptPopup { get; } + public LocId? AcceptPopup { get; set; } /// /// The popup message that will appear to the requester when the target player accepts this request. /// [DataField] - public LocId? CancelledPopup { get; } + public LocId? CancelledPopup { get; set; } } From 878a5ce00831552b03ad49f79bae3b56c08df7e1 Mon Sep 17 00:00:00 2001 From: sleepyyapril <123355664+sleepyyapril@users.noreply.github.com> Date: Thu, 12 Feb 2026 14:42:23 -0400 Subject: [PATCH 11/11] private --- .../_DEN/PlayerRequest/Prototypes/PlayerRequestPrototype.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Content.Shared/_DEN/PlayerRequest/Prototypes/PlayerRequestPrototype.cs b/Content.Shared/_DEN/PlayerRequest/Prototypes/PlayerRequestPrototype.cs index 3e3bd61e58..8f1383e6d4 100644 --- a/Content.Shared/_DEN/PlayerRequest/Prototypes/PlayerRequestPrototype.cs +++ b/Content.Shared/_DEN/PlayerRequest/Prototypes/PlayerRequestPrototype.cs @@ -12,16 +12,16 @@ public sealed partial class PlayerRequestPrototype : IPrototype, IInheritingProt { /// [IdDataField] - public string ID { get; } = default!; + public string ID { get; private set; } = default!; /// [ParentDataField(typeof(AbstractPrototypeIdArraySerializer))] - public string[]? Parents { get; } + public string[]? Parents { get; private set; } /// [NeverPushInheritance] [AbstractDataField] - public bool Abstract { get; } + public bool Abstract { get; private set; } /// /// The specific alert to use for this request.