149 lines
6.8 KiB
C#
149 lines
6.8 KiB
C#
using AnotherReplayReader.ReplayFile;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
|
|
namespace AnotherReplayReader
|
|
{
|
|
public static class ReplayAutoSaver
|
|
{
|
|
private static int _errorMessageCount = 0;
|
|
|
|
public static void SpawnAutoSaveReplaysTask(string replayFolderPath)
|
|
{
|
|
Task.Run(() => AutoSaveReplays(replayFolderPath));
|
|
}
|
|
|
|
private static async Task AutoSaveReplays(string replayFolderPath)
|
|
{
|
|
const string ourPrefix = "自动保存";
|
|
|
|
// filename and last write time
|
|
var previousFiles = new Dictionary<string, DateTime>(StringComparer.OrdinalIgnoreCase);
|
|
// filename and file size
|
|
var lastReplays = new Dictionary<string, long>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
while (true)
|
|
{
|
|
try
|
|
{
|
|
var changed = (from fileName in Directory.GetFiles(replayFolderPath, "*.RA3Replay")
|
|
let info = new FileInfo(fileName)
|
|
where !info.Name.StartsWith(ourPrefix)
|
|
where !previousFiles.ContainsKey(info.FullName) || previousFiles[info.FullName] != info.LastWriteTimeUtc
|
|
select info).ToList();
|
|
|
|
foreach (var info in changed)
|
|
{
|
|
previousFiles[info.FullName] = info.LastWriteTimeUtc;
|
|
}
|
|
|
|
var replays = changed.Select(info =>
|
|
{
|
|
Debug.Instance.DebugMessage += $"正在尝试检测已更改的文件:{info.FullName}\r\n";
|
|
try
|
|
{
|
|
using var stream = info.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
|
return new Replay(info.FullName, stream);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.Instance.DebugMessage += $"自动保存录像/检测录像更改时发生错误:{e}\r\n";
|
|
return null;
|
|
}
|
|
}).Where(replay => replay != null);
|
|
|
|
var newLastReplays = from replay in replays
|
|
let threshold = Math.Abs((DateTime.UtcNow - replay.Date).TotalSeconds)
|
|
let endDate = replay.Date.Add(replay.Length ?? TimeSpan.Zero)
|
|
let endThreshold = Math.Abs((DateTime.UtcNow - endDate).TotalSeconds)
|
|
where threshold < 40 || endThreshold < 40
|
|
select replay;
|
|
|
|
var toBeChecked = newLastReplays.ToDictionary(replay => replay.Path, StringComparer.OrdinalIgnoreCase);
|
|
foreach (var savedLastReplay in lastReplays.Keys)
|
|
{
|
|
if (!toBeChecked.ContainsKey(savedLastReplay))
|
|
{
|
|
try
|
|
{
|
|
using var stream = File.Open(savedLastReplay, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
|
toBeChecked.Add(savedLastReplay, new Replay(savedLastReplay, stream));
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.Instance.DebugMessage += $"自动保存录像/检测录像更改时发生错误:{e}\r\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var kv in toBeChecked)
|
|
{
|
|
Debug.Instance.DebugMessage += $"正在检测录像更改:{kv.Key}\r\n";
|
|
var replay = kv.Value;
|
|
if (lastReplays.TryGetValue(kv.Key, out var fileSize))
|
|
{
|
|
if (fileSize == replay.Size)
|
|
{
|
|
// skip if size is not changed
|
|
Debug.Instance.DebugMessage += $"已跳过未更改的录像:{kv.Key}\r\n";
|
|
continue;
|
|
}
|
|
}
|
|
Debug.Instance.DebugMessage += $"将会自动保存已更改的录像:{kv.Key}\r\n";
|
|
lastReplays[kv.Key] = replay.Size;
|
|
|
|
var date = replay.Date;
|
|
|
|
var playerString = $"{replay.NumberOfPlayingPlayers}名玩家";
|
|
if (replay.NumberOfPlayingPlayers <= 2)
|
|
{
|
|
var playingPlayers = from player in replay.Players
|
|
let faction = ModData.GetFaction(replay.Mod, player.FactionId)
|
|
where faction.Kind != FactionKind.Observer
|
|
select $"{player.PlayerName}({faction.Name})";
|
|
playerString = playingPlayers.Aggregate(string.Empty, (x, y) => x + y);
|
|
}
|
|
|
|
var dateString = $"{date.Year}{date.Month:D2}{date.Day:D2}_{date.Hour:D2}{date.Minute:D2}{date.Second:D2}";
|
|
var destinationPath = Path.Combine(replayFolderPath, $"{ourPrefix}-{playerString}{dateString}.RA3Replay");
|
|
try
|
|
{
|
|
File.Copy(replay.Path, destinationPath, true);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
throw new Exception($"复制文件({replay.Path} -> {destinationPath})失败:{e.Message}", e);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
var errorString = $"自动保存录像时出现错误:\r\n{e}\r\n";
|
|
Debug.Instance.DebugMessage += errorString;
|
|
if (Interlocked.Increment(ref _errorMessageCount) == 1)
|
|
{
|
|
_ = Application.Current.Dispatcher.InvokeAsync(() =>
|
|
{
|
|
try
|
|
{
|
|
MessageBox.Show(errorString);
|
|
}
|
|
finally
|
|
{
|
|
Interlocked.Decrement(ref _errorMessageCount);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
await Task.Delay(10 * 1000).ConfigureAwait(false);
|
|
}
|
|
}
|
|
}
|
|
}
|