Poprawki w rolach zwyciezcow

This commit is contained in:
2025-10-10 21:52:09 +02:00
parent ffd05bf9f0
commit 5930cccfe5
3 changed files with 131 additions and 15 deletions

View File

@@ -195,28 +195,139 @@ public static class DataTransformer
private static string DetermineWinningTeam(string winningFaction, List<PlayerRecordData> playerRecords)
{
// Use WinningFaction from GameHistory if available
if (!string.IsNullOrEmpty(winningFaction))
{
// Clean HTML tags from winning faction
return StripColorTags(winningFaction);
}
TownOfUsStatsPlugin.Logger.LogInfo($"DetermineWinningTeam called with winningFaction='{winningFaction}'");
// Fallback: Check first winner's team
var winner = playerRecords.FirstOrDefault(r => r.Winner);
if (winner == null)
// ALWAYS use PlayerRecords to determine the winning team
// WinningFaction field can be stale (contains data from previous game)
var winners = playerRecords.Where(r => r.Winner).ToList();
if (winners.Count == 0)
{
TownOfUsStatsPlugin.Logger.LogWarning("No winners found in PlayerRecords!");
return "Unknown";
}
return winner.TeamString switch
TownOfUsStatsPlugin.Logger.LogInfo($"Found {winners.Count} winner(s)");
// Group winners by team
var winnersByTeam = winners.GroupBy(w => w.TeamString).ToList();
// Log all winner teams
foreach (var group in winnersByTeam)
{
var roles = string.Join(", ", group.Select(w => ParseFirstRoleFromRoleString(w.RoleString)));
TownOfUsStatsPlugin.Logger.LogInfo($" Team '{group.Key}': {group.Count()} winner(s) - Roles: {roles}");
}
// Case 1: All winners are from the same team
if (winnersByTeam.Count == 1)
{
var teamString = winnersByTeam[0].Key;
TownOfUsStatsPlugin.Logger.LogInfo($"All winners from same team: '{teamString}'");
// For Custom team (solo neutrals, Lovers, etc.), use the role name
if (teamString == "Custom")
{
// If there's only one winner, it's a solo neutral (Werewolf, Glitch, etc.)
if (winners.Count == 1)
{
var roleName = ParseFirstRoleFromRoleString(winners[0].RoleString);
TownOfUsStatsPlugin.Logger.LogInfo($"Solo neutral win: '{roleName}'");
return roleName;
}
// If multiple winners with Custom team, it's Lovers
else
{
TownOfUsStatsPlugin.Logger.LogInfo("Multiple Custom team winners: Lovers");
return "Lovers";
}
}
// Standard team conversions
var result = teamString switch
{
"Crewmate" => "Crewmates",
"Impostor" => "Impostors",
"Neutral" => "Neutrals",
"Custom" => "Custom",
_ => "Unknown",
};
TownOfUsStatsPlugin.Logger.LogInfo($"Determined winning team: '{result}'");
return result;
}
// Case 2: Mixed teams (e.g., Mercenary winning with Impostors, Jester with Crewmates)
// Find the main team (non-Neutral with most winners)
TownOfUsStatsPlugin.Logger.LogInfo("Mixed teams detected");
var mainTeam = winnersByTeam
.Where(g => g.Key is "Crewmate" or "Impostor") // Only Crewmate or Impostor
.OrderByDescending(g => g.Count())
.FirstOrDefault();
if (mainTeam != null)
{
var result = mainTeam.Key switch
{
"Crewmate" => "Crewmates",
"Impostor" => "Impostors",
_ => "Unknown",
};
TownOfUsStatsPlugin.Logger.LogInfo($"Main winning team (mixed): '{result}'");
return result;
}
// Case 3: Only Neutrals won (shouldn't happen, but fallback)
TownOfUsStatsPlugin.Logger.LogWarning("Only Neutral/Custom winners, no main team found");
return "Neutrals";
}
/// <summary>
/// Parses the first role name from RoleString (e.g., "Werewolf (Flash) (2/4) | Alive" → "Werewolf")
/// </summary>
private static string ParseFirstRoleFromRoleString(string roleString)
{
if (string.IsNullOrEmpty(roleString))
{
return "Unknown";
}
// Strip color tags first
var cleanString = StripColorTags(roleString);
// Remove everything after " |" (status info)
var pipeIndex = cleanString.IndexOf(" |");
if (pipeIndex > 0)
{
cleanString = cleanString.Substring(0, pipeIndex).Trim();
}
// Remove task info like "(0/4)" at the end
cleanString = Regex.Replace(cleanString, @"\s*\(\d+/\d+\)\s*$", "").Trim();
// Remove modifiers in parentheses (e.g., "(Flash)")
var parenIndex = cleanString.IndexOf('(');
if (parenIndex > 0)
{
cleanString = cleanString.Substring(0, parenIndex).Trim();
}
// If there's role history (separated by " > "), get the LAST role
if (cleanString.Contains(" > "))
{
var roles = cleanString.Split(new[] { " > " }, StringSplitOptions.RemoveEmptyEntries);
cleanString = roles.Last().Trim();
// Remove modifiers again (after extracting last role)
parenIndex = cleanString.IndexOf('(');
if (parenIndex > 0)
{
cleanString = cleanString.Substring(0, parenIndex).Trim();
}
}
return string.IsNullOrEmpty(cleanString) ? "Unknown" : cleanString;
}
private static string GetMapName(byte mapId)

View File

@@ -38,6 +38,10 @@ public static class StatsExporter
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();
@@ -54,6 +58,7 @@ public static class StatsExporter
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(

View File

@@ -338,7 +338,7 @@ public class TouMiraReflectionBridge
}
// Remove "Tou" suffix if present (e.g., "EngineerTou" -> "Engineer", "TrackerTou" -> "Tracker")
if (roleName.EndsWith("Tou"))
if (roleName != null && roleName.EndsWith("Tou"))
{
roleName = roleName.Substring(0, roleName.Length - 3);
}