diff --git a/Content.Client/Popups/PopupSystem.cs b/Content.Client/Popups/PopupSystem.cs index 58e3044591..be0966674d 100644 --- a/Content.Client/Popups/PopupSystem.cs +++ b/Content.Client/Popups/PopupSystem.cs @@ -11,6 +11,7 @@ using Robust.Shared.Map; using Robust.Shared.Player; using Robust.Shared.Players; using Robust.Shared.Prototypes; +using Robust.Shared.Replays; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -26,6 +27,7 @@ namespace Content.Client.Popups [Dependency] private readonly IResourceCache _resource = default!; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IUserInterfaceManager _uiManager = default!; + [Dependency] private readonly IReplayRecordingManager _replayRecording = default!; public IReadOnlyList WorldLabels => _aliveWorldLabels; public IReadOnlyList CursorLabels => _aliveCursorLabels; @@ -52,8 +54,16 @@ namespace Content.Client.Popups .RemoveOverlay(); } - private void PopupMessage(string message, PopupType type, EntityCoordinates coordinates, EntityUid? entity = null) + private void PopupMessage(string message, PopupType type, EntityCoordinates coordinates, EntityUid? entity, bool recordReplay) { + if (recordReplay && _replayRecording.IsRecording) + { + if (entity != null) + _replayRecording.RecordClientMessage(new PopupEntityEvent(message, type, entity.Value)); + else + _replayRecording.RecordClientMessage(new PopupCoordinatesEvent(message, type, coordinates)); + } + var label = new WorldPopupLabel(coordinates) { Text = message, @@ -66,23 +76,26 @@ namespace Content.Client.Popups #region Abstract Method Implementations public override void PopupCoordinates(string message, EntityCoordinates coordinates, PopupType type = PopupType.Small) { - PopupMessage(message, type, coordinates, null); + PopupMessage(message, type, coordinates, null, true); } public override void PopupCoordinates(string message, EntityCoordinates coordinates, ICommonSession recipient, PopupType type = PopupType.Small) { if (_playerManager.LocalPlayer?.Session == recipient) - PopupMessage(message, type, coordinates, null); + PopupMessage(message, type, coordinates, null, true); } public override void PopupCoordinates(string message, EntityCoordinates coordinates, EntityUid recipient, PopupType type = PopupType.Small) { if (_playerManager.LocalPlayer?.ControlledEntity == recipient) - PopupMessage(message, type, coordinates, null); + PopupMessage(message, type, coordinates, null, true); } - public override void PopupCursor(string message, PopupType type = PopupType.Small) + private void PopupCursorInternal(string message, PopupType type, bool recordReplay) { + if (recordReplay && _replayRecording.IsRecording) + _replayRecording.RecordClientMessage(new PopupCursorEvent(message, type)); + var label = new CursorPopupLabel(_inputManager.MouseScreenPosition) { Text = message, @@ -92,6 +105,9 @@ namespace Content.Client.Popups _aliveCursorLabels.Add(label); } + public override void PopupCursor(string message, PopupType type = PopupType.Small) + => PopupCursorInternal(message, type, true); + public override void PopupCursor(string message, ICommonSession recipient, PopupType type = PopupType.Small) { if (_playerManager.LocalPlayer?.Session == recipient) @@ -137,12 +153,8 @@ namespace Content.Client.Popups public override void PopupEntity(string message, EntityUid uid, PopupType type = PopupType.Small) { - if (!EntityManager.EntityExists(uid)) - return; - - var transform = EntityManager.GetComponent(uid); - - PopupMessage(message, type, transform.Coordinates, uid); + if (TryComp(uid, out TransformComponent? transform)) + PopupMessage(message, type, transform.Coordinates, uid, true); } #endregion @@ -151,17 +163,18 @@ namespace Content.Client.Popups private void OnPopupCursorEvent(PopupCursorEvent ev) { - PopupCursor(ev.Message, ev.Type); + PopupCursorInternal(ev.Message, ev.Type, false); } private void OnPopupCoordinatesEvent(PopupCoordinatesEvent ev) { - PopupCoordinates(ev.Message, ev.Coordinates, ev.Type); + PopupMessage(ev.Message, ev.Type, ev.Coordinates, null, false); } private void OnPopupEntityEvent(PopupEntityEvent ev) { - PopupEntity(ev.Message, ev.Uid, ev.Type); + if (TryComp(ev.Uid, out TransformComponent? transform)) + PopupMessage(ev.Message, ev.Type, transform.Coordinates, ev.Uid, false); } private void OnRoundRestart(RoundRestartCleanupEvent ev) diff --git a/Content.Client/Replay/ContentReplayPlaybackManager.cs b/Content.Client/Replay/ContentReplayPlaybackManager.cs index 0ecb98ec0d..e400958bca 100644 --- a/Content.Client/Replay/ContentReplayPlaybackManager.cs +++ b/Content.Client/Replay/ContentReplayPlaybackManager.cs @@ -22,6 +22,7 @@ using Robust.Client.State; using Robust.Client.Timing; using Robust.Client.UserInterface; using Robust.Shared.ContentPack; +using Robust.Shared.Serialization.Markdown.Mapping; using Robust.Shared.Utility; namespace Content.Client.Replay; @@ -99,6 +100,8 @@ public sealed class ContentReplayPlaybackManager { switch (message) { + case BoundUserInterfaceMessage: + break; // TODO REPLAYS refactor BUIs case ChatMessage chat: // Just pass on the chat message to the UI controller, but skip speech-bubbles if we are fast-forwarding. _uiMan.GetUIController().ProcessChatMessage(chat, speechBubble: !skipEffects); @@ -129,8 +132,7 @@ public sealed class ContentReplayPlaybackManager return false; } - - private void OnReplayPlaybackStarted() + private void OnReplayPlaybackStarted(MappingDataNode metadata, List objects) { _conGrp.Implementation = new ReplayConGroup(); } diff --git a/Content.Client/Replay/Spectator/ReplaySpectatorSystem.Position.cs b/Content.Client/Replay/Spectator/ReplaySpectatorSystem.Position.cs index 3b17191c16..4a88f48add 100644 --- a/Content.Client/Replay/Spectator/ReplaySpectatorSystem.Position.cs +++ b/Content.Client/Replay/Spectator/ReplaySpectatorSystem.Position.cs @@ -3,6 +3,7 @@ using Content.Shared.Movement.Components; using Robust.Client.GameObjects; using Robust.Shared.Map; using Robust.Shared.Map.Components; +using Robust.Shared.Network; namespace Content.Client.Replay.Spectator; @@ -13,61 +14,99 @@ public sealed partial class ReplaySpectatorSystem /// /// Simple struct containing position & rotation data for maintaining a persistent view when jumping around in time. /// - public struct SpectatorPosition + public struct SpectatorData { // TODO REPLAYS handle ghost-following. + + /// + /// The current entity being spectated. + /// public EntityUid Entity; + + /// + /// The player that was originally controlling + /// + public NetUserId? Controller; + public (EntityCoordinates Coords, Angle Rot)? Local; public (EntityCoordinates Coords, Angle Rot)? World; public (EntityUid? Ent, Angle Rot)? Eye; } - public SpectatorPosition GetSpectatorPosition() + public SpectatorData GetSpectatorData() { - var obs = new SpectatorPosition(); - if (_player.LocalPlayer?.ControlledEntity is { } player && TryComp(player, out TransformComponent? xform) && xform.MapUid != null) + var data = new SpectatorData(); + + if (_player.LocalPlayer?.ControlledEntity is not { } player) + return data; + + foreach (var session in _player.Sessions) { - obs.Local = (xform.Coordinates, xform.LocalRotation); - obs.World = (new(xform.MapUid.Value, xform.WorldPosition), xform.WorldRotation); + if (session.UserId == _player.LocalPlayer?.UserId) + continue; - if (TryComp(player, out InputMoverComponent? mover)) - obs.Eye = (mover.RelativeEntity, mover.TargetRelativeRotation); - - obs.Entity = player; + if (session.AttachedEntity == player) + { + data.Controller = session.UserId; + break; + } } - return obs; + if (!TryComp(player, out TransformComponent? xform) || xform.MapUid == null) + return data; + + data.Local = (xform.Coordinates, xform.LocalRotation); + data.World = (new(xform.MapUid.Value, xform.WorldPosition), xform.WorldRotation); + + if (TryComp(player, out InputMoverComponent? mover)) + data.Eye = (mover.RelativeEntity, mover.TargetRelativeRotation); + + data.Entity = player; + + return data; } private void OnBeforeSetTick() { - _oldPosition = GetSpectatorPosition(); + _spectatorData = GetSpectatorData(); } private void OnAfterSetTick() { - if (_oldPosition != null) - SetSpectatorPosition(_oldPosition.Value); - _oldPosition = null; + if (_spectatorData != null) + SetSpectatorPosition(_spectatorData.Value); + _spectatorData = null; } - public void SetSpectatorPosition(SpectatorPosition spectatorPosition) + public void SetSpectatorPosition(SpectatorData data) { - if (Exists(spectatorPosition.Entity) && Transform(spectatorPosition.Entity).MapID != MapId.Nullspace) + if (_player.LocalPlayer == null) + return; + + if (data.Controller != null + && _player.SessionsDict.TryGetValue(data.Controller.Value, out var session) + && Exists(session.AttachedEntity) + && Transform(session.AttachedEntity.Value).MapID != MapId.Nullspace) { - _player.LocalPlayer!.AttachEntity(spectatorPosition.Entity, EntityManager, _client); + _player.LocalPlayer.AttachEntity(session.AttachedEntity.Value, EntityManager, _client); return; } - if (spectatorPosition.Local != null && spectatorPosition.Local.Value.Coords.IsValid(EntityManager)) + if (Exists(data.Entity) && Transform(data.Entity).MapID != MapId.Nullspace) { - var newXform = SpawnSpectatorGhost(spectatorPosition.Local.Value.Coords, false); - newXform.LocalRotation = spectatorPosition.Local.Value.Rot; + _player.LocalPlayer.AttachEntity(data.Entity, EntityManager, _client); + return; } - else if (spectatorPosition.World != null && spectatorPosition.World.Value.Coords.IsValid(EntityManager)) + + if (data.Local != null && data.Local.Value.Coords.IsValid(EntityManager)) { - var newXform = SpawnSpectatorGhost(spectatorPosition.World.Value.Coords, true); - newXform.LocalRotation = spectatorPosition.World.Value.Rot; + var newXform = SpawnSpectatorGhost(data.Local.Value.Coords, false); + newXform.LocalRotation = data.Local.Value.Rot; + } + else if (data.World != null && data.World.Value.Coords.IsValid(EntityManager)) + { + var newXform = SpawnSpectatorGhost(data.World.Value.Coords, true); + newXform.LocalRotation = data.World.Value.Rot; } else if (TryFindFallbackSpawn(out var coords)) { @@ -80,15 +119,21 @@ public sealed partial class ReplaySpectatorSystem return; } - if (spectatorPosition.Eye != null && TryComp(_player.LocalPlayer?.ControlledEntity, out InputMoverComponent? newMover)) + if (data.Eye != null && TryComp(_player.LocalPlayer.ControlledEntity, out InputMoverComponent? newMover)) { - newMover.RelativeEntity = spectatorPosition.Eye.Value.Ent; - newMover.TargetRelativeRotation = newMover.RelativeRotation = spectatorPosition.Eye.Value.Rot; + newMover.RelativeEntity = data.Eye.Value.Ent; + newMover.TargetRelativeRotation = newMover.RelativeRotation = data.Eye.Value.Rot; } } private bool TryFindFallbackSpawn(out EntityCoordinates coords) { + if (_replayPlayback.TryGetRecorderEntity(out var recorder)) + { + coords = new EntityCoordinates(recorder.Value, default); + return true; + } + var uid = EntityQuery() .OrderByDescending(x => x.LocalAABB.Size.LengthSquared) .FirstOrDefault()?.Owner; diff --git a/Content.Client/Replay/Spectator/ReplaySpectatorSystem.Spectate.cs b/Content.Client/Replay/Spectator/ReplaySpectatorSystem.Spectate.cs index 0d4775a498..7230179bad 100644 --- a/Content.Client/Replay/Spectator/ReplaySpectatorSystem.Spectate.cs +++ b/Content.Client/Replay/Spectator/ReplaySpectatorSystem.Spectate.cs @@ -84,6 +84,7 @@ public sealed partial class ReplaySpectatorSystem _stateMan.RequestStateChange(); + _spectatorData = GetSpectatorData(); return xform; } diff --git a/Content.Client/Replay/Spectator/ReplaySpectatorSystem.cs b/Content.Client/Replay/Spectator/ReplaySpectatorSystem.cs index add786544e..c75529c037 100644 --- a/Content.Client/Replay/Spectator/ReplaySpectatorSystem.cs +++ b/Content.Client/Replay/Spectator/ReplaySpectatorSystem.cs @@ -6,6 +6,8 @@ using Robust.Client.Player; using Robust.Client.Replays.Playback; using Robust.Client.State; using Robust.Shared.Console; +using Robust.Shared.Network; +using Robust.Shared.Serialization.Markdown.Mapping; namespace Content.Client.Replay.Spectator; @@ -29,7 +31,7 @@ public sealed partial class ReplaySpectatorSystem : EntitySystem [Dependency] private readonly SharedContentEyeSystem _eye = default!; [Dependency] private readonly IReplayPlaybackManager _replayPlayback = default!; - private SpectatorPosition? _oldPosition; + private SpectatorData? _spectatorData; public const string SpectateCmd = "replay_spectate"; public override void Initialize() @@ -58,15 +60,19 @@ public sealed partial class ReplaySpectatorSystem : EntitySystem _replayPlayback.ReplayPlaybackStopped -= OnPlaybackStopped; } - private void OnPlaybackStarted() + private void OnPlaybackStarted(MappingDataNode yamlMappingNode, List objects) { InitializeMovement(); - SetSpectatorPosition(default); _conHost.RegisterCommand(SpectateCmd, Loc.GetString("cmd-replay-spectate-desc"), Loc.GetString("cmd-replay-spectate-help"), SpectateCommand, SpectateCompletions); + + if (_replayPlayback.TryGetRecorderEntity(out var recorder)) + SpectateEntity(recorder.Value); + else + SetSpectatorPosition(default); } private void OnPlaybackStopped() diff --git a/Content.Client/SubFloor/SubFloorHideSystem.cs b/Content.Client/SubFloor/SubFloorHideSystem.cs index 1d47f93a5a..482ab94a00 100644 --- a/Content.Client/SubFloor/SubFloorHideSystem.cs +++ b/Content.Client/SubFloor/SubFloorHideSystem.cs @@ -66,9 +66,10 @@ public sealed class SubFloorHideSystem : SharedSubFloorHideSystem private void UpdateAll() { - foreach (var (_, appearance) in EntityManager.EntityQuery(true)) + var query = AllEntityQuery(); + while (query.MoveNext(out var uid, out _, out var appearance)) { - _appearance.MarkDirty(appearance, true); + _appearance.QueueUpdate(uid, appearance); } } } diff --git a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs index 691725dd4d..336b2d0757 100644 --- a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs +++ b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs @@ -29,6 +29,7 @@ using Robust.Shared.Configuration; using Robust.Shared.Input.Binding; using Robust.Shared.Map; using Robust.Shared.Network; +using Robust.Shared.Replays; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -46,6 +47,8 @@ public sealed class ChatUIController : UIController [Dependency] private readonly IPlayerManager _player = default!; [Dependency] private readonly IStateManager _state = default!; [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly IReplayRecordingManager _replayRecording = default!; + [Dependency] private readonly IConfigurationManager _cfg = default!; [UISystemDependency] private readonly ExamineSystem? _examine = default; [UISystemDependency] private readonly GhostSystem? _ghost = default; @@ -758,7 +761,17 @@ public sealed class ChatUIController : UIController _manager.SendMessage(text, prefixChannel == 0 ? channel : prefixChannel); } - private void OnChatMessage(MsgChatMessage message) => ProcessChatMessage(message.Message); + private void OnChatMessage(MsgChatMessage message) + { + var msg = message.Message; + ProcessChatMessage(msg); + + if ((msg.Channel & ChatChannel.AdminRelated) == 0 || + _cfg.GetCVar(CCVars.ReplayRecordAdminChat)) + { + _replayRecording.RecordClientMessage(msg); + } + } public void ProcessChatMessage(ChatMessage msg, bool speechBubble = true) { diff --git a/Content.Replay/Menu/ReplayMainMenu.cs b/Content.Replay/Menu/ReplayMainMenu.cs index 6748c20988..096abb6971 100644 --- a/Content.Replay/Menu/ReplayMainMenu.cs +++ b/Content.Replay/Menu/ReplayMainMenu.cs @@ -10,11 +10,10 @@ using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Shared; using Robust.Shared.Configuration; +using Robust.Shared.ContentPack; using Robust.Shared.Serialization.Markdown.Value; using Robust.Shared.Utility; -using TerraFX.Interop.Windows; using static Robust.Shared.Replays.IReplayRecordingManager; -using IResourceManager = Robust.Shared.ContentPack.IResourceManager; namespace Content.Replay.Menu; @@ -94,7 +93,8 @@ public sealed class ReplayMainScreen : State var forkId = string.Empty; if (data.TryGet(Fork, out var forkNode)) { - // TODO REPLAYS somehow distribute and load from build.json? + // TODO Replay client build info. + // When distributing the client we need to distribute a build.json or provide these cvars some other way? var clientFork = _cfg.GetCVar(CVars.BuildForkId); if (string.IsNullOrWhiteSpace(clientFork)) forkId = forkNode.Value; @@ -181,6 +181,7 @@ public sealed class ReplayMainScreen : State info.HorizontalAlignment = Control.HAlignment.Left; info.VerticalAlignment = Control.VAlignment.Top; + info.SetMarkup(Loc.GetString( "replay-info-info", ("file", file), diff --git a/Content.Server/Administration/Commands/PlayGlobalSoundCommand.cs b/Content.Server/Administration/Commands/PlayGlobalSoundCommand.cs index fdd3173809..ec5b21dcee 100644 --- a/Content.Server/Administration/Commands/PlayGlobalSoundCommand.cs +++ b/Content.Server/Administration/Commands/PlayGlobalSoundCommand.cs @@ -65,7 +65,6 @@ public sealed class PlayGlobalSoundCommand : IConsoleCommand } else { - // TODO REPLAYS uhhh.. what to do with this? replay = false; filter = Filter.Empty(); diff --git a/Content.Server/Chat/Managers/ChatManager.cs b/Content.Server/Chat/Managers/ChatManager.cs index 3ad3ff7c3e..56f516942b 100644 --- a/Content.Server/Chat/Managers/ChatManager.cs +++ b/Content.Server/Chat/Managers/ChatManager.cs @@ -253,7 +253,7 @@ namespace Content.Server.Chat.Managers if ((channel & ChatChannel.AdminRelated) == 0 || _configurationManager.GetCVar(CCVars.ReplayRecordAdminChat)) { - _replay.QueueReplayMessage(msg); + _replay.RecordServerMessage(msg); } } @@ -271,7 +271,7 @@ namespace Content.Server.Chat.Managers if ((channel & ChatChannel.AdminRelated) == 0 || _configurationManager.GetCVar(CCVars.ReplayRecordAdminChat)) { - _replay.QueueReplayMessage(msg); + _replay.RecordServerMessage(msg); } } @@ -301,7 +301,7 @@ namespace Content.Server.Chat.Managers if ((channel & ChatChannel.AdminRelated) == 0 || _configurationManager.GetCVar(CCVars.ReplayRecordAdminChat)) { - _replay.QueueReplayMessage(msg); + _replay.RecordServerMessage(msg); } } diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index 39aa207466..3e1a264369 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -397,7 +397,7 @@ public sealed partial class ChatSystem : SharedChatSystem _chatManager.ChatMessageToOne(ChatChannel.Whisper, obfuscatedMessage, wrappedobfuscatedMessage, source, false, session.ConnectedClient); } - _replay.QueueReplayMessage(new ChatMessage(ChatChannel.Whisper, message, wrappedMessage, source, MessageRangeHideChatForReplay(range))); + _replay.RecordServerMessage(new ChatMessage(ChatChannel.Whisper, message, wrappedMessage, source, MessageRangeHideChatForReplay(range))); var ev = new EntitySpokeEvent(source, message, channel, obfuscatedMessage); RaiseLocalEvent(source, ev, true); @@ -548,7 +548,7 @@ public sealed partial class ChatSystem : SharedChatSystem _chatManager.ChatMessageToOne(channel, message, wrappedMessage, source, entHideChat, session.ConnectedClient); } - _replay.QueueReplayMessage(new ChatMessage(channel, message, wrappedMessage, source, MessageRangeHideChatForReplay(range))); + _replay.RecordServerMessage(new ChatMessage(channel, message, wrappedMessage, source, MessageRangeHideChatForReplay(range))); } /// diff --git a/Content.Server/Chat/TypingIndicator/TypingIndicatorSystem.cs b/Content.Server/Chat/TypingIndicator/TypingIndicatorSystem.cs index 44af5b197c..c48ba07c44 100644 --- a/Content.Server/Chat/TypingIndicator/TypingIndicatorSystem.cs +++ b/Content.Server/Chat/TypingIndicator/TypingIndicatorSystem.cs @@ -25,7 +25,7 @@ public sealed class TypingIndicatorSystem : SharedTypingIndicatorSystem // when player poses entity we want to make sure that there is typing indicator EnsureComp(ev.Entity); // we also need appearance component to sync visual state - EnsureComp(ev.Entity); + EnsureComp(ev.Entity); } private void OnPlayerDetached(EntityUid uid, TypingIndicatorComponent component, PlayerDetachedEvent args) diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Visuals.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Visuals.cs index 9892b36896..5d3adff1c2 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Visuals.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Visuals.cs @@ -50,7 +50,7 @@ public sealed partial class ExplosionSystem : EntitySystem // restricted to something like the same map, but whatever. _pvsSys.AddGlobalOverride(explosionEntity); - var appearance = AddComp(explosionEntity); + var appearance = AddComp(explosionEntity); _appearance.SetData(explosionEntity, ExplosionAppearanceData.Progress, 1, appearance); return explosionEntity; diff --git a/Content.Server/GameTicking/GameTicker.RoundFlow.cs b/Content.Server/GameTicking/GameTicker.RoundFlow.cs index 7697e927ac..b7a814878e 100644 --- a/Content.Server/GameTicking/GameTicker.RoundFlow.cs +++ b/Content.Server/GameTicking/GameTicker.RoundFlow.cs @@ -4,7 +4,6 @@ using Content.Server.Ghost; using Content.Server.Maps; using Content.Server.Mind; using Content.Server.Players; -using Content.Shared.CCVar; using Content.Shared.GameTicking; using Content.Shared.Preferences; using JetBrains.Annotations; @@ -18,7 +17,6 @@ using Robust.Shared.Player; using Robust.Shared.Random; using Robust.Shared.Utility; using System.Linq; -using System.Threading.Tasks; using Content.Shared.Database; using Robust.Shared.Asynchronous; @@ -66,9 +64,6 @@ namespace Content.Server.GameTicking } } - [ViewVariables] - public int RoundId { get; private set; } - /// /// Returns true if the round's map is eligible to be updated. /// diff --git a/Content.Server/GameTicking/GameTicker.cs b/Content.Server/GameTicking/GameTicker.cs index 4ede0f6f50..7951f5d119 100644 --- a/Content.Server/GameTicking/GameTicker.cs +++ b/Content.Server/GameTicking/GameTicker.cs @@ -1,6 +1,5 @@ using Content.Server.Administration.Logs; using Content.Server.Administration.Managers; -using Content.Server.Chat; using Content.Server.Chat.Managers; using Content.Server.Chat.Systems; using Content.Server.Database; @@ -14,23 +13,17 @@ using Content.Server.Station.Systems; using Content.Shared.Chat; using Content.Shared.Damage; using Content.Shared.GameTicking; -using Content.Shared.Mobs.Systems; using Content.Shared.Roles; using Robust.Server; using Robust.Server.GameObjects; -using Robust.Server.Maps; using Robust.Shared.Configuration; using Robust.Shared.Console; #if EXCEPTION_TOLERANCE using Robust.Shared.Exceptions; #endif using Robust.Shared.Map; -using Robust.Shared.Network; using Robust.Shared.Prototypes; using Robust.Shared.Random; -using Robust.Shared.Replays; -using Robust.Shared.Serialization.Markdown.Mapping; -using Robust.Shared.Serialization.Markdown.Value; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -68,7 +61,6 @@ namespace Content.Server.GameTicking DebugTools.Assert(_prototypeManager.Index(FallbackOverflowJob).Name == FallbackOverflowJobName, "Overflow role does not have the correct name!"); InitializeGameRules(); - _replay.OnRecordingStarted += OnRecordingStart; _initialized = true; } @@ -88,12 +80,6 @@ namespace Content.Server.GameTicking base.Shutdown(); ShutdownGameRules(); - _replay.OnRecordingStarted -= OnRecordingStart; - } - - private void OnRecordingStart((MappingDataNode, List) data) - { - data.Item1["roundId"] = new ValueDataNode(RoundId.ToString()); } private void SendServerMessage(string message) @@ -123,7 +109,6 @@ namespace Content.Server.GameTicking #if EXCEPTION_TOLERANCE [Dependency] private readonly IRuntimeLog _runtimeLog = default!; #endif - [Dependency] private readonly StationSystem _stationSystem = default!; [Dependency] private readonly StationSpawningSystem _stationSpawning = default!; [Dependency] private readonly StationJobsSystem _stationJobs = default!; [Dependency] private readonly DamageableSystem _damageable = default!; @@ -133,6 +118,5 @@ namespace Content.Server.GameTicking [Dependency] private readonly ServerUpdateManager _serverUpdates = default!; [Dependency] private readonly PlayTimeTrackingSystem _playTimeTrackings = default!; [Dependency] private readonly UserDbDataManager _userDb = default!; - [Dependency] private readonly IReplayRecordingManager _replay = default!; } } diff --git a/Content.Server/Pointing/EntitySystems/PointingSystem.cs b/Content.Server/Pointing/EntitySystems/PointingSystem.cs index 37cb168139..bcf6ca6657 100644 --- a/Content.Server/Pointing/EntitySystems/PointingSystem.cs +++ b/Content.Server/Pointing/EntitySystems/PointingSystem.cs @@ -80,7 +80,7 @@ namespace Content.Server.Pointing.EntitySystems RaiseNetworkEvent(new PopupEntityEvent(message, PopupType.Small, source), viewerEntity); } - _replay.QueueReplayMessage(new PopupEntityEvent(viewerMessage, PopupType.Small, source)); + _replay.RecordServerMessage(new PopupEntityEvent(viewerMessage, PopupType.Small, source)); } public bool InRange(EntityUid pointer, EntityCoordinates coordinates) diff --git a/Content.Server/Radio/EntitySystems/RadioSystem.cs b/Content.Server/Radio/EntitySystems/RadioSystem.cs index b5ced6637e..44963c2863 100644 --- a/Content.Server/Radio/EntitySystems/RadioSystem.cs +++ b/Content.Server/Radio/EntitySystems/RadioSystem.cs @@ -122,7 +122,7 @@ public sealed class RadioSystem : EntitySystem else _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Radio message from {ToPrettyString(messageSource):user} on {channel.LocalizedName}: {message}"); - _replay.QueueReplayMessage(chat); + _replay.RecordServerMessage(chat); _messages.Remove(message); } diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index fef043efc4..ac5b02b1ad 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -1596,6 +1596,6 @@ namespace Content.Shared.CCVar /// false. /// public static readonly CVarDef ReplayRecordAdminChat = - CVarDef.Create("replay.record_admin_chat", false, CVar.SERVERONLY); + CVarDef.Create("replay.record_admin_chat", false, CVar.ARCHIVE); } } diff --git a/Content.Shared/GameTicking/SharedGameTicker.cs b/Content.Shared/GameTicking/SharedGameTicker.cs index 47ea4e950e..14e8b68e9f 100644 --- a/Content.Shared/GameTicking/SharedGameTicker.cs +++ b/Content.Shared/GameTicking/SharedGameTicker.cs @@ -1,16 +1,41 @@ using Robust.Shared.Network; +using Robust.Shared.Replays; using Robust.Shared.Serialization; -using Robust.Shared.Utility; +using Robust.Shared.Serialization.Markdown.Mapping; +using Robust.Shared.Serialization.Markdown.Value; namespace Content.Shared.GameTicking { public abstract class SharedGameTicker : EntitySystem { + [Dependency] private readonly IReplayRecordingManager _replay = default!; + // See ideally these would be pulled from the job definition or something. // But this is easier, and at least it isn't hardcoded. //TODO: Move these, they really belong in StationJobsSystem or a cvar. public const string FallbackOverflowJob = "Passenger"; public const string FallbackOverflowJobName = "job-name-passenger"; + + // TODO network. + // Probably most useful for replays, round end info, and probably things like lobby menus. + [ViewVariables] + public int RoundId { get; protected set; } + + public override void Initialize() + { + base.Initialize(); + _replay.RecordingStarted += OnRecordingStart; + } + + public override void Shutdown() + { + _replay.RecordingStarted -= OnRecordingStart; + } + + private void OnRecordingStart(MappingDataNode metadata, List events) + { + metadata["roundId"] = new ValueDataNode(RoundId.ToString()); + } } [Serializable, NetSerializable] diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml index 17dbbbace0..89fc4fa85f 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml @@ -228,12 +228,6 @@ layer: - MobLayer - type: Appearance - rotate: true - states: - Alive: - Base: onestar_boss - Dead: - Base: onestar_boss_wrecked - type: CombatMode - type: Tag tags: diff --git a/Resources/clientCommandPerms.yml b/Resources/clientCommandPerms.yml index 1b762ecf0c..d2eed89736 100644 --- a/Resources/clientCommandPerms.yml +++ b/Resources/clientCommandPerms.yml @@ -31,6 +31,16 @@ - cvar - fuckrules - midipanic + - replay_recording_start + - replay_recording_stop + - replay_recording_stats + - replay_play + - replay_pause + - replay_toggle + - replay_skip + - replay_set_time + - replay_stop + - replay_load - Flags: DEBUG Commands: diff --git a/Resources/engineCommandPerms.yml b/Resources/engineCommandPerms.yml index a2aafdff78..6dff0d9b22 100644 --- a/Resources/engineCommandPerms.yml +++ b/Resources/engineCommandPerms.yml @@ -64,6 +64,7 @@ - tilelookup - net_entityreport - scene + - replay_recording_stats - Flags: MAPPING @@ -120,6 +121,8 @@ - gcf - getcomponentregistration - fuck + - replay_recording_start + - replay_recording_stop - Flags: QUERY Commands: