mirror of
https://gitee.com/xiarenalofs/squad-rain-ops-mini.git
synced 2026-08-05 13:05:52 +08:00
178 lines
6.9 KiB
C#
178 lines
6.9 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using RainOpsMini.Helpers;
|
|
using RainOpsMini.Helpers.RCON;
|
|
using RainOpsMini.Models;
|
|
|
|
namespace RainOpsMini.Services
|
|
{
|
|
public class OnlineUserService
|
|
{
|
|
// Panel Users: Username -> ConnectionCount
|
|
private ConcurrentDictionary<string, int> _panelUsers = new ConcurrentDictionary<string, int>();
|
|
private readonly RconDataCache _rconCache;
|
|
|
|
public OnlineUserService(RconDataCache rconCache)
|
|
{
|
|
_rconCache = rconCache;
|
|
}
|
|
|
|
public void UserConnected(string username)
|
|
{
|
|
if (string.IsNullOrEmpty(username)) return;
|
|
_panelUsers.AddOrUpdate(username, 1, (k, v) => v + 1);
|
|
}
|
|
|
|
public void UserDisconnected(string username)
|
|
{
|
|
if (string.IsNullOrEmpty(username)) return;
|
|
_panelUsers.AddOrUpdate(username, 0, (k, v) => v > 1 ? v - 1 : 0);
|
|
|
|
// Clean up zeros
|
|
if (_panelUsers.TryGetValue(username, out int count) && count <= 0)
|
|
{
|
|
_panelUsers.TryRemove(username, out _);
|
|
}
|
|
}
|
|
|
|
public List<string> GetOnlinePanelUsers()
|
|
{
|
|
return _panelUsers.Where(kvp => kvp.Value > 0).Select(kvp => kvp.Key).ToList();
|
|
}
|
|
|
|
public List<CameramanInfo> GetOnlineCameramen()
|
|
{
|
|
// Priority 1: Check Current Directory (likely Project Root in Dev, or App Root in Prod)
|
|
var configPath = Path.Combine(Directory.GetCurrentDirectory(), "SquadGame", "ServerConfig", "Admins.cfg");
|
|
|
|
// Priority 2: Check Base Directory (Bin folder)
|
|
if (!File.Exists(configPath))
|
|
{
|
|
configPath = Path.Combine(Environment.CurrentDirectory, "SquadGame", "ServerConfig", "Admins.cfg");
|
|
}
|
|
|
|
if (!File.Exists(configPath)) return new List<CameramanInfo>();
|
|
|
|
// RainOpsMini.Helpers.RainOpsLog.Log($"Loading Admins.cfg from: {configPath}");
|
|
|
|
var groupsWithCameraman = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
var onlineCameramen = new List<CameramanInfo>();
|
|
|
|
try
|
|
{
|
|
var lines = File.ReadAllLines(configPath);
|
|
|
|
// 1. Identify Groups with 'cameraman' permission
|
|
foreach (var line in lines)
|
|
{
|
|
var trimLine = line.Trim();
|
|
if (string.IsNullOrWhiteSpace(trimLine) || trimLine.StartsWith("//") || trimLine.StartsWith("#")) continue;
|
|
|
|
if (trimLine.StartsWith("Group=", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
// Format: Group=GroupName:perm1,perm2...
|
|
var parts = trimLine.Substring(6).Split(':');
|
|
if (parts.Length >= 2)
|
|
{
|
|
var groupName = parts[0].Trim();
|
|
var perms = parts[1].Split(',').Select(p => p.Trim().ToLower()).ToHashSet();
|
|
|
|
if (perms.Contains("cameraman"))
|
|
{
|
|
groupsWithCameraman.Add(groupName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 2. Identify Admins in those groups
|
|
var definedCameramen = new List<CameramanInfo>();
|
|
foreach (var line in lines)
|
|
{
|
|
var trimLine = line.Trim();
|
|
if (string.IsNullOrWhiteSpace(trimLine) || trimLine.StartsWith("//") || trimLine.StartsWith("#")) continue;
|
|
|
|
if (trimLine.StartsWith("Admin=", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
// Format: Admin=SteamID:GroupName//Comment
|
|
var content = trimLine.Substring(6);
|
|
var parts = content.Split(':');
|
|
if (parts.Length >= 2)
|
|
{
|
|
var steamId = parts[0].Trim();
|
|
var rest = parts[1];
|
|
|
|
// Split GroupName and Comment
|
|
string groupName;
|
|
string comment = "";
|
|
|
|
int commentIdx = rest.IndexOf("//");
|
|
if (commentIdx >= 0)
|
|
{
|
|
groupName = rest.Substring(0, commentIdx).Trim();
|
|
comment = rest.Substring(commentIdx + 2).Trim();
|
|
}
|
|
else
|
|
{
|
|
groupName = rest.Trim();
|
|
}
|
|
|
|
if (groupsWithCameraman.Contains(groupName))
|
|
{
|
|
definedCameramen.Add(new CameramanInfo
|
|
{
|
|
SteamId = steamId,
|
|
Name = comment, // Use comment as name
|
|
GroupName = groupName
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 3. Check online status
|
|
// We use cached player list
|
|
var currentPlayers = _rconCache.Players ?? new List<PlayerInfo>();
|
|
// Safe dictionary creation to avoid duplicate keys exception
|
|
var onlineSteamIds = new Dictionary<string, string>();
|
|
foreach (var p in currentPlayers)
|
|
{
|
|
if (!string.IsNullOrEmpty(p.SteamId) && !onlineSteamIds.ContainsKey(p.SteamId))
|
|
{
|
|
onlineSteamIds[p.SteamId] = p.Name;
|
|
}
|
|
}
|
|
|
|
foreach (var cam in definedCameramen)
|
|
{
|
|
if (onlineSteamIds.ContainsKey(cam.SteamId))
|
|
{
|
|
cam.IsOnline = true;
|
|
// Optionally update name from actual player name if available
|
|
// cam.Name = $"{cam.Name} ({onlineSteamIds[cam.SteamId]})";
|
|
onlineCameramen.Add(cam);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
RainOpsLog.Log($"Error parsing Admins.cfg: {ex.Message}");
|
|
}
|
|
|
|
return onlineCameramen;
|
|
}
|
|
}
|
|
|
|
public class CameramanInfo
|
|
{
|
|
public string SteamId { get; set; } = "";
|
|
public string Name { get; set; } = "";
|
|
public string GroupName { get; set; } = "";
|
|
public bool IsOnline { get; set; }
|
|
}
|
|
}
|
|
|