From 7d9693d9761a1c38e06151144ce8addf0c397263 Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Sat, 16 Sep 2023 23:46:12 +1200 Subject: [PATCH] Fix replay recording temporary paths not supporting subdirectories (#19887) --- .../Tests/Replays/ReplayTests.cs | 56 +++++++++++++++++++ .../GameTicking/GameTicker.Replays.cs | 13 +++-- Content.Shared/CCVar/CCVars.cs | 1 + 3 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 Content.IntegrationTests/Tests/Replays/ReplayTests.cs diff --git a/Content.IntegrationTests/Tests/Replays/ReplayTests.cs b/Content.IntegrationTests/Tests/Replays/ReplayTests.cs new file mode 100644 index 0000000000..7e2d3da4b6 --- /dev/null +++ b/Content.IntegrationTests/Tests/Replays/ReplayTests.cs @@ -0,0 +1,56 @@ +using Content.Server.GameTicking; +using Content.Shared.CCVar; +using Robust.Shared; +using Robust.Shared.Replays; + +namespace Content.IntegrationTests.Tests.Replays; + +[TestFixture] +public sealed class ReplayTests +{ + /// + /// Simple test that just makes sure that automatic replay recording on round restarts works without any issues. + /// + [Test] + public async Task AutoRecordReplayTest() + { + var settings = new PoolSettings {DummyTicker = false}; + await using var pair = await PoolManager.GetServerClient(settings); + var server = pair.Server; + + Assert.That(server.CfgMan.GetCVar(CVars.ReplayServerRecordingEnabled), Is.False); + var recordMan = server.ResolveDependency(); + Assert.That(recordMan.IsRecording, Is.False); + + // Setup cvars. + var autoRec = server.CfgMan.GetCVar(CCVars.ReplayAutoRecord); + var autoRecName = server.CfgMan.GetCVar(CCVars.ReplayAutoRecordName); + var tempDir = server.CfgMan.GetCVar(CCVars.ReplayAutoRecordTempDir); + server.CfgMan.SetCVar(CVars.ReplayServerRecordingEnabled, true); + server.CfgMan.SetCVar(CCVars.ReplayAutoRecord, true); + server.CfgMan.SetCVar(CCVars.ReplayAutoRecordTempDir, "/a/b/"); + server.CfgMan.SetCVar(CCVars.ReplayAutoRecordName, $"c/d/{autoRecName}"); + + // Restart the round a few times + var ticker = server.System(); + await server.WaitPost(() => ticker.RestartRound()); + await pair.RunTicksSync(25); + Assert.That(recordMan.IsRecording, Is.True); + await server.WaitPost(() => ticker.RestartRound()); + await pair.RunTicksSync(25); + Assert.That(recordMan.IsRecording, Is.True); + + // Reset cvars + server.CfgMan.SetCVar(CVars.ReplayServerRecordingEnabled, false); + server.CfgMan.SetCVar(CCVars.ReplayAutoRecord, autoRec); + server.CfgMan.SetCVar(CCVars.ReplayAutoRecordTempDir, tempDir); + server.CfgMan.SetCVar(CCVars.ReplayAutoRecordName, autoRecName); + + // Restart the round again to disable the current recording. + await server.WaitPost(() => ticker.RestartRound()); + await pair.RunTicksSync(25); + Assert.That(recordMan.IsRecording, Is.False); + + await pair.CleanReturnAsync(); + } +} diff --git a/Content.Server/GameTicking/GameTicker.Replays.cs b/Content.Server/GameTicking/GameTicker.Replays.cs index 3254fb840d..42e2de0228 100644 --- a/Content.Server/GameTicking/GameTicker.Replays.cs +++ b/Content.Server/GameTicking/GameTicker.Replays.cs @@ -72,13 +72,14 @@ public sealed partial class GameTicker if (data.State is not ReplayRecordState state) return; - if (state.MoveToPath != null) - { - _sawmillReplays.Info($"Moving replay into final position: {state.MoveToPath}"); + if (state.MoveToPath == null) + return; - _taskManager.BlockWaitOnTask(_replays.WaitWriteTasks()); - data.Directory.Rename(data.Path, state.MoveToPath.Value); - } + _sawmillReplays.Info($"Moving replay into final position: {state.MoveToPath}"); + _taskManager.BlockWaitOnTask(_replays.WaitWriteTasks()); + DebugTools.Assert(!_replays.IsWriting()); + data.Directory.CreateDir(state.MoveToPath.Value.Directory); + data.Directory.Rename(data.Path, state.MoveToPath.Value); } private ResPath GetAutoReplayPath() diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index 19464a4fc3..a0cde055ba 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -1776,6 +1776,7 @@ namespace Content.Shared.CCVar /// /// Path that, if provided, automatic replays are initially recorded in. /// When the recording is done, the file is moved into its final destination. + /// Unless this path is rooted, it will be relative to . /// public static readonly CVarDef ReplayAutoRecordTempDir = CVarDef.Create("replay.auto_record_temp_dir", "", CVar.SERVERONLY); -- 2.51.2