Files
MiraExporter/Export/StatsExporter.cs

122 lines
4.3 KiB
C#

using System;
using System.IO;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using TownOfUsStatsExporter.Config;
using TownOfUsStatsExporter.Models;
namespace TownOfUsStatsExporter.Export;
/// <summary>
/// Main orchestrator for stats export process.
/// </summary>
public static class StatsExporter
{
/// <summary>
/// Exports game statistics asynchronously.
/// </summary>
/// <returns>A task representing the asynchronous operation.</returns>
public static async Task ExportGameStatsAsync()
{
try
{
TownOfUsStatsPlugin.Logger.LogInfo("=== Starting Game Stats Export ===");
// Read configuration
var config = await ApiConfigManager.ReadConfigAsync();
if (!config.EnableApiExport)
{
TownOfUsStatsPlugin.Logger.LogInfo("API export is disabled - skipping");
return;
}
if (!config.IsValid())
{
TownOfUsStatsPlugin.Logger.LogWarning("API configuration is incomplete - skipping export");
return;
}
// Wait a short delay to ensure TOU Mira has finished updating all static fields
// (including WinningFaction which is set after PlayerRecords)
await Task.Delay(100);
// Get data from TOU Mira via reflection
var bridge = ReflectionBridgeProvider.GetBridge();
var playerRecords = bridge.GetPlayerRecords();
if (playerRecords.Count == 0)
{
TownOfUsStatsPlugin.Logger.LogWarning("No player data available - skipping export");
return;
}
var playerStats = bridge.GetPlayerStats();
var roleHistory = bridge.GetRoleHistory();
var killedPlayers = bridge.GetKilledPlayers();
var winningFaction = bridge.GetWinningFaction();
TownOfUsStatsPlugin.Logger.LogInfo($"Collected data: {playerRecords.Count} players, {playerStats.Count} stats entries");
TownOfUsStatsPlugin.Logger.LogInfo($"WinningFaction from GameHistory: '{winningFaction}'");
// Transform to export format
var gameData = DataTransformer.TransformToExportFormat(
playerRecords,
playerStats,
roleHistory,
killedPlayers,
winningFaction,
config.ApiToken!,
config.Secret);
TownOfUsStatsPlugin.Logger.LogInfo($"Transformed data: {gameData.Players.Count} players ready for export");
// Save local backup if enabled
if (config.SaveLocalBackup)
{
await SaveLocalBackupAsync(gameData);
}
// Send to API
await ApiClient.SendToApiAsync(gameData, config.ApiEndpoint!);
TownOfUsStatsPlugin.Logger.LogInfo("=== Game Stats Export Completed Successfully ===");
}
catch (Exception ex)
{
TownOfUsStatsPlugin.Logger.LogError($"Error during stats export: {ex}");
}
}
private static async Task SaveLocalBackupAsync(GameStatsData data)
{
try
{
var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var logFolder = Path.Combine(documentsPath, "TownOfUs", "GameLogs");
Directory.CreateDirectory(logFolder);
var gameIdShort = data.GameInfo.GameId.Substring(0, 8);
var fileName = $"Game_{DateTime.Now:yyyyMMdd_HHmmss}_{gameIdShort}.json";
var filePath = Path.Combine(logFolder, fileName);
var jsonOptions = new JsonSerializerOptions
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull,
};
var jsonData = JsonSerializer.Serialize(data, jsonOptions);
await File.WriteAllTextAsync(filePath, jsonData, Encoding.UTF8);
TownOfUsStatsPlugin.Logger.LogInfo($"Local backup saved: {filePath}");
}
catch (Exception ex)
{
TownOfUsStatsPlugin.Logger.LogError($"Failed to save local backup: {ex}");
}
}
}