using Robust.Shared.Map; using Robust.Shared.Player; using Robust.Shared.Serialization; using Robust.Shared.Timing; namespace Content.Shared.Popups; /// /// System for displaying small text popups on users' screens. /// public abstract partial class SharedPopupSystem : EntitySystem { [Dependency] protected IGameTiming Timing = default!; /// /// Shows a popup at a user's cursor. /// /// The message to display. /// The entity whose attached player will see the popup. /// Used to customize how this popup should appear visually. public abstract void PopupCursor(string? message, EntityUid? recipient, PopupType type = PopupType.Small); /// /// Shows a popup at a user's cursor. /// /// The message to display. /// The player session that will see the popup. /// Used to customize how this popup should appear visually. public abstract void PopupCursor(string? message, ICommonSession recipient, PopupType type = PopupType.Small); /// /// Shows a popup at some users' cursors. /// /// The message to display. /// Filter for the clients that will see this popup. /// If true, this pop-up will be considered as a globally visible pop-up that gets shown during replays. /// Used to customize how this popup should appear visually. public abstract void PopupCursor(string? message, Filter filter, bool recordReplay, PopupType type = PopupType.Small); /// /// Shows a popup at a world location to every entity in PVS range. /// /// The message to display. /// The coordinates where to display the message. /// Used to customize how this popup should appear visually. /// Additional key used to uniquely identify this popup event for prediction purposes. /// /// In case your popup is predicted and may show up multiple times at different locations in a single tick, for each popup you should use a different prediction key, /// which server and client have to agree on. Otherwise, the client may ignore some of the popups. /// This is needed because the coordinates themselves cannot be part of the PredictionInstance, since they slightly differ between server and client due to /// floating point precision issues and predictive movement, so two popups at different locations with the same message in the same tick would be considered identical. /// The most common use case for this is when you delete an entity and spawn a popup at its location. For this you can use the NetEntity ID of the deleted entity as the prediction key. /// public abstract void PopupCoordinates(string? message, EntityCoordinates coordinates, PopupType type = PopupType.Small, int predictionKey = 0); /// /// Variant of that sends a popup to the player attached to some entity. /// /// The message to display. /// The coordinates where to display the message. /// The entity whose attached player will see the popup. /// Used to customize how this popup should appear visually. /// Additional key used to uniquely identify this popup event for prediction purposes. public abstract void PopupCoordinates(string? message, EntityCoordinates coordinates, EntityUid? recipient, PopupType type = PopupType.Small, int predictionKey = 0); /// /// Variant of that sends a popup to a specific player. /// /// The message to display. /// The coordinates where to display the message. /// The player session that will see the popup. /// Used to customize how this popup should appear visually. /// Additional key used to uniquely identify this popup event for prediction purposes. public abstract void PopupCoordinates(string? message, EntityCoordinates coordinates, ICommonSession recipient, PopupType type = PopupType.Small, int predictionKey = 0); /// /// Filtered variant of , which should only be used /// if the filtering has to be more specific than simply PVS range based. /// /// The message to display. /// The coordinates where to display the message. /// Filter for the clients that will see this popup. /// If true, this pop-up will be considered as a globally visible pop-up that gets shown during replays. /// Used to customize how this popup should appear visually. /// Additional key used to uniquely identify this popup event for prediction purposes. public abstract void PopupCoordinates(string? message, EntityCoordinates coordinates, Filter filter, bool recordReplay, PopupType type = PopupType.Small, int predictionKey = 0); /// /// Shows a popup above an entity for every player in PVS range. /// /// The message to display. /// The entity above which to display the popup. /// Used to customize how this popup should appear visually. public abstract void PopupEntity(string? message, EntityUid uid, PopupType type = PopupType.Small); /// /// Variant of that shows the popup only to some specific client. /// /// The message to display. /// The entity above which to display the popup. /// The entity whose attached player will see the popup.Used to customize how this popup should appear visually. public abstract void PopupEntity(string? message, EntityUid uid, EntityUid? recipient, PopupType type = PopupType.Small); /// /// Variant of that shows the popup only to some specific client. /// /// The message to display. /// The entity above which to display the popup. /// The player session that will see the popup. /// Used to customize how this popup should appear visually. public abstract void PopupEntity(string? message, EntityUid uid, ICommonSession recipient, PopupType type = PopupType.Small); /// /// Filtered variant of , which should only be used /// if the filtering has to be more specific than simply PVS range based. /// /// The message to display. /// The entity above which to display the popup. /// Filter for the clients that will see this popup. /// If true, this pop-up will be considered as a globally visible pop-up that gets shown during replays. /// Used to customize how this popup should appear visually. public abstract void PopupEntity(string? message, EntityUid uid, Filter filter, bool recordReplay, PopupType type = PopupType.Small); /// /// Variant of that displays /// to the recipient and to everyone else in PVS range. /// /// The message to display to the recipient. /// The message to display to everyone else in PVS range. /// The entity above which to display the popup. /// The entity whose attached player will see the recipient message. /// Used to customize how this popup should appear visually. /// Common base for all popup network events. /// [Serializable, NetSerializable] public abstract class PopupEvent(string message, PopupType type, GameTick tick) : EntityEventArgs { /// /// The message to display. /// public string Message = message; /// /// The type of the popup. /// public PopupType Type = type; /// /// The game tick at which the popup was created. /// public GameTick Tick = tick; } /// /// Interface for a prediction instance of a popup event. /// Used to keep track if a popup has already been predicted and displayed on the client side, to avoid duplicate popups. /// public interface IPopupPredictionInstance { /// /// The game tick at which the popup was created. /// GameTick Tick { get; } } /// /// Network event for displaying a popup on the user's cursor. /// [Serializable, NetSerializable] public sealed class PopupCursorEvent(string message, PopupType type, GameTick tick) : PopupEvent(message, type, tick) { /// /// Creates a new prediction instance for this popup event. /// public readonly record struct PredictionInstance(string Message, PopupType Type, GameTick Tick) : IPopupPredictionInstance; } /// /// Network event for displaying a popup at a world location. /// [Serializable, NetSerializable] public sealed class PopupCoordinatesEvent(string message, PopupType type, GameTick tick, NetCoordinates coordinates, int predictionKey) : PopupEvent(message, type, tick) { /// /// The coordinates where the popup should be displayed. /// public NetCoordinates Coordinates = coordinates; /// /// The key used to identify this popup event for prediction purposes. /// public int PredictionKey = predictionKey; /// /// Creates a new prediction instance for this popup event. /// /// /// TODO: remove coords, as they are not used for prediction. /// public readonly record struct PredictionInstance(string Message, PopupType Type, GameTick Tick, int PredictionKey) : IPopupPredictionInstance; } /// /// Network event for displaying a popup above an entity. /// [Serializable, NetSerializable] public sealed class PopupEntityEvent(string message, PopupType type, GameTick tick, NetEntity uid) : PopupEvent(message, type, tick) { /// /// The entity above which the popup should be displayed. /// public NetEntity Uid = uid; /// /// Creates a new prediction instance for this popup event. /// public readonly record struct PredictionInstance(string Message, PopupType Type, GameTick Tick, NetEntity Uid) : IPopupPredictionInstance; } /// /// Used to determine how a popup should appear visually to the client. Caution variants simply have a red color. /// /// /// Actions which can fail or succeed should use a smaller popup for failure and a larger popup for success. /// Actions which have different popups for the user vs. others should use a larger popup for the user and a smaller popup for others. /// Actions which result in harm or are otherwise dangerous should always show as the caution variant. /// [Serializable, NetSerializable] public enum PopupType : byte { /// /// Small popups are the default, and denote actions that may be spammable or are otherwise unimportant. /// Small, SmallCaution, /// /// Medium popups should be used for actions which are not spammable but may not be particularly important. /// Medium, MediumCaution, /// /// Large popups should be used for actions which may be important or very important to one or more users, /// but is not life-threatening. /// Large, LargeCaution }