Files
squad-rain-ops-mini/Helpers/RCON/RconParser.cs

164 lines
7.3 KiB
C#

using System.Text.RegularExpressions;
using RainOpsMini.Models;
using System.Text.Json;
using System.Text.Json.Serialization;
using RainOpsMini.Helpers.RCON;
namespace RainOpsMini
{
public static class RconParser
{
// Team ID: 1 (1st Infantry Division)
private static readonly Regex TeamHeaderRegex = new Regex(@"Team ID:\s*(\d+)\s*\(", RegexOptions.Compiled);
// ID: 1 | Name: Squad 1 | Size: 5 | Locked: False | Creator Name: lanyu | Creator Online IDs: EOS: 00020148e4944a0a9ca3ddd4c703b5e0 steam: 76561198296558085
private static readonly Regex SquadRegex = new Regex(@"ID:\s*(\d+)\s*\|\s*Name:\s*(.+?)\s*\|\s*Size:\s*(\d+)\s*\|\s*Locked:\s*(\w+)\s*\|\s*Creator Name:\s*(.+?)\s*\|\s*Creator Online IDs:\s*EOS:\s*(\w+)\s*steam:\s*(\d+)", RegexOptions.Compiled);
// ID: 40 | Online IDs: EOS: 00026c77c7fc494fa0ab3a337382826f steam: 76561199065911668 | Name: ANDRUHA | Team ID: 1 | Squad ID: N/A | Is Leader: False | Role: USA_Rifleman_01
private static readonly Regex PlayerRegex = new Regex(@"ID:\s*(\d+)\s*\|\s*Online IDs:\s*EOS:\s*(\w+)\s*steam:\s*(\d+)\s*\|\s*Name:\s*(.+?)\s*\|\s*Team ID:\s*(\d+)\s*\|\s*Squad ID:\s*(.+?)\s*\|\s*Is Leader:\s*(\w+)\s*\|\s*Role:\s*(.+)", RegexOptions.Compiled);
// [ChatAll] [Online IDs:EOS: 0002236691c54d00b82bcf1b04a27761 steam: 76561199735605536] [hina] 澶ф : cj
// [ChatAll] [Online IDs:EOS: 00026937662e43e593caf18bebdbeb2a steam: 76561199402993315] Rain鍦ㄤ笅鐝?: 00
// Improved Regex to handle both [Name] Message and Name : Message formats
private static readonly Regex ChatRegex = new Regex(@"\[(ChatAll|ChatTeam|ChatSquad|ChatAdmin|ChatGame)\]\s*\[Online IDs:?\s*EOS:\s*(\w+)\s*steam:\s*(\d+)\]\s*(?:\[(.+?)\]\s*(.*)|(.+?)\s*:\s*(.*))", RegexOptions.Compiled);
public static ChatMessage? ParseChatMessage(string rconOutput)
{
if (string.IsNullOrWhiteSpace(rconOutput)) return null;
var match = ChatRegex.Match(rconOutput);
if (match.Success)
{
// Group 4/5 are for [Name] Message format
// Group 6/7 are for Name : Message format
string name = match.Groups[4].Success ? match.Groups[4].Value : match.Groups[6].Value;
string message = match.Groups[4].Success ? match.Groups[5].Value : match.Groups[7].Value;
return new ChatMessage
{
Type = match.Groups[1].Value,
EosId = match.Groups[2].Value,
SteamId = match.Groups[3].Value,
Name = name?.Trim() ?? "Unknown",
Message = message?.Trim() ?? "",
Timestamp = DateTime.Now
};
}
return null;
}
public static ServerInfoResponse? ParseServerInfo(string rconOutput)
{
if (string.IsNullOrWhiteSpace(rconOutput)) return null;
// ShowServerInfo might return raw JSON string, sometimes wrapped in quotes or with other text
// We'll try to find the JSON object part: starts with { and ends with }
int startIndex = rconOutput.IndexOf('{');
int endIndex = rconOutput.LastIndexOf('}');
if (startIndex >= 0 && endIndex > startIndex)
{
string json = rconOutput.Substring(startIndex, endIndex - startIndex + 1);
try
{
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
NumberHandling = JsonNumberHandling.AllowReadingFromString
};
var info = JsonSerializer.Deserialize<ServerInfoResponse>(json, options);
// Fallback for PlayTime_I if not in JSON (it is usually there, but just in case)
// Actually standard ShowServerInfo returns JSON with PLAYTIME_I field.
return info;
}
catch (Exception ex)
{
RainOpsMini.Helpers.RainOpsLog.Log($"[Error] Failed to parse ServerInfo JSON: {ex.Message}");
// Optional: Print json snippet for debugging
// RainOpsMini.Helpers.RainOpsLog.Log($"[Debug] JSON: {json}");
return null;
}
}
return null;
}
public static List<SquadInfo> ParseSquads(string rconOutput)
{
var squads = new List<SquadInfo>();
if (string.IsNullOrWhiteSpace(rconOutput)) return squads;
var lines = rconOutput.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
int currentTeamId = 0;
foreach (var line in lines)
{
var teamMatch = TeamHeaderRegex.Match(line);
if (teamMatch.Success)
{
if (int.TryParse(teamMatch.Groups[1].Value, out int tid))
{
currentTeamId = tid;
}
continue;
}
var squadMatch = SquadRegex.Match(line);
if (squadMatch.Success)
{
var squad = new SquadInfo
{
TeamId = currentTeamId,
Id = int.Parse(squadMatch.Groups[1].Value),
Name = squadMatch.Groups[2].Value.Trim(),
Size = int.Parse(squadMatch.Groups[3].Value),
Locked = bool.Parse(squadMatch.Groups[4].Value),
CreatorName = squadMatch.Groups[5].Value.Trim(),
CreatorEosId = squadMatch.Groups[6].Value,
CreatorSteamId = squadMatch.Groups[7].Value
};
squads.Add(squad);
}
}
return squads;
}
public static List<PlayerInfo> ParsePlayers(string rconOutput)
{
var players = new List<PlayerInfo>();
if (string.IsNullOrWhiteSpace(rconOutput)) return players;
var lines = rconOutput.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
var match = PlayerRegex.Match(line);
if (match.Success)
{
var player = new PlayerInfo
{
Id = int.Parse(match.Groups[1].Value),
EosId = match.Groups[2].Value,
SteamId = match.Groups[3].Value,
Name = match.Groups[4].Value.Trim(),
TeamId = int.Parse(match.Groups[5].Value),
IsLeader = bool.Parse(match.Groups[7].Value),
Role = match.Groups[8].Value.Trim()
};
string squadIdStr = match.Groups[6].Value.Trim();
if (squadIdStr != "N/A" && int.TryParse(squadIdStr, out int sid))
{
player.SquadId = sid;
}
players.Add(player);
}
}
return players;
}
}
}