Files
Lithium/Lithium/OperatorSets.cs
T
Trenten Pettry 60b519335f 🛠️ Fixed (Bugs resolved)
- Quick Swap Side Restoration: Fixed a bug where quickswap would fail to switch sides when toggling back to the original operator. The issue occurred because the baseline set was captured after the side had already switched, so the revert logic couldn't determine it needed to switch sides again. Now the baseline is captured before any side change, ensuring correct toggle behavior.
📂 File-Level Changes Summary
- OperatorSets.cs: Captured preSwitchSet before the SwitchSide() call in QuickSwapTo() and used it when storing originalSetBeforeQuickSwap.
2026-06-22 11:33:26 -04:00

460 lines
16 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
namespace Lua
{
static class OperatorSets
{
// AA0051
public static Dictionary<string, (double recoilX, double recoilY)> attackers =
new Dictionary<string, (double, double)>(StringComparer.OrdinalIgnoreCase);
// AA0052
public static Dictionary<string, (double recoilX, double recoilY)> defenders =
new Dictionary<string, (double, double)>(StringComparer.OrdinalIgnoreCase);
// AA0053
public static Dictionary<string, (double recoilX, double recoilY)> mergedSets =
new Dictionary<string, (double, double)>(StringComparer.OrdinalIgnoreCase);
// AA0054
public static List<string> attackerNames = new List<string>();
// AA0055
public static List<string> defenderNames = new List<string>();
// AA0056
public static List<string> setNames = new List<string>();
// AA0057
public static int currentSetIndex = 0;
// AA0058
public static bool onAttackers = true;
public static string originalSetBeforeQuickSwap = null;
public static bool isQuickSwapping = false;
// Static HttpClient for connection pooling (FIX: previously created new instance each time)
private static readonly HttpClient _httpClient = new HttpClient
{
Timeout = System.TimeSpan.FromSeconds(10)
};
private static string CacheDirectory =>
System.IO.Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
"coax"
);
private static string CacheFile =>
System.IO.Path.Combine(CacheDirectory, "config_cache.txt");
// AA0059
private static string OnlineConfigUrl =>
string.IsNullOrEmpty(ConfigLoader.userName)
? null
: $"https://jj.scpsmp.site/api/config/export?name={Uri.EscapeDataString(ConfigLoader.userName)}";
// AA0060
public static string ConfigExportUrl =>
string.IsNullOrEmpty(ConfigLoader.userName)
? null
: $"https://jj.scpsmp.site/exindex.html?name={Uri.EscapeDataString(ConfigLoader.userName)}";
// AA0061
public static string CurrentSet
{
get
{
if (setNames == null || setNames.Count == 0) return "N/A";
currentSetIndex = Helper.SafeClampIndex(currentSetIndex, setNames.Count);
return setNames[currentSetIndex];
}
}
// AA0062
private static string _currentOperator = "";
// AA0063
public static string CurrentOperator
{
get
{
if (!string.IsNullOrWhiteSpace(_currentOperator) && mergedSets.ContainsKey(_currentOperator))
return _currentOperator;
return CurrentSet;
}
set
{
if (mergedSets.ContainsKey(value))
_currentOperator = value;
}
}
// AA0064
public static (double recoilX, double recoilY) GetCurrentRecoil()
{
string op = CurrentOperator;
if (onAttackers && attackers.ContainsKey(op))
return attackers[op];
if (!onAttackers && defenders.ContainsKey(op))
return defenders[op];
return (0, 0);
}
// AA0065
public static void LoadOperatorSets(bool allowOnlineFetch = true)
{
attackers.Clear();
defenders.Clear();
attackerNames.Clear();
defenderNames.Clear();
var allLines = new List<string>();
bool loadedOnline = false;
// Ensure coax folder exists (with proper error handling)
try
{
if (!System.IO.Directory.Exists(CacheDirectory))
System.IO.Directory.CreateDirectory(CacheDirectory);
}
catch
{
// Directory creation failed - will fall back to cache if available
}
// Try loading from online source
if (allowOnlineFetch && !string.IsNullOrEmpty(OnlineConfigUrl))
{
try
{
string txt = _httpClient.GetStringAsync(OnlineConfigUrl).Result;
if (!string.IsNullOrWhiteSpace(txt))
{
allLines.AddRange(txt.Split('\n'));
// Save cache file - with proper error handling
try
{
if (System.IO.Directory.Exists(CacheDirectory))
System.IO.File.WriteAllText(CacheFile, txt);
}
catch
{
// Cache write failed, but we have the data in memory
}
loadedOnline = true;
}
}
catch (HttpRequestException)
{
// Network error - fall back to cache
}
catch (TaskCanceledException)
{
// Timeout - fall back to cache
}
catch
{
// Other errors - fall back to cache
}
}
// If online fetch failed → fallback to cached file
if (!loadedOnline && System.IO.File.Exists(CacheFile))
{
try
{
var cached = System.IO.File.ReadAllLines(CacheFile);
if (cached.Length > 0)
allLines.AddRange(cached);
}
catch
{
// Cache file read failed - continue without it
}
}
// Also load config.txt (local overrides)
var local = Helper.ReadLinesSafe("config.txt");
if (local.Length > 0)
allLines.AddRange(local);
bool inAttackers = false;
bool inDefenders = false;
foreach (var raw in allLines)
{
if (string.IsNullOrWhiteSpace(raw)) continue;
var line = raw.Trim();
if (line.StartsWith("--") || line.StartsWith("#"))
continue;
if (line.StartsWith("attackers", StringComparison.OrdinalIgnoreCase))
{
inAttackers = true;
inDefenders = false;
continue;
}
if (line.StartsWith("defenders", StringComparison.OrdinalIgnoreCase))
{
inAttackers = false;
inDefenders = true;
continue;
}
if (line == "}" || line == "]," || line == "],")
{
inAttackers = false;
inDefenders = false;
continue;
}
if (Helper.TryParseRecoilLine(line, out var name, out var x, out var y))
{
if (inAttackers)
{
attackers[name] = (x, y);
attackerNames.Add(name);
}
else if (inDefenders)
{
defenders[name] = (x, y);
defenderNames.Add(name);
}
}
}
MergeSets();
RestoreFavorites();
if (setNames.Count > 0)
CurrentOperator = CurrentSet;
}
// AA0070
public static void MergeSets()
{
if (!isQuickSwapping) originalSetBeforeQuickSwap = null;
if (ConfigLoader.betaTest)
{
mergedSets.Clear();
foreach (var kv in attackers) mergedSets[kv.Key] = kv.Value;
foreach (var kv in defenders) mergedSets[kv.Key] = kv.Value;
setNames = attackerNames.Concat(defenderNames)
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
}
else
{
mergedSets = onAttackers
? new Dictionary<string, (double, double)>(attackers, StringComparer.OrdinalIgnoreCase)
: new Dictionary<string, (double, double)>(defenders, StringComparer.OrdinalIgnoreCase);
setNames = onAttackers
? new List<string>(attackerNames)
: new List<string>(defenderNames);
}
if (setNames == null) setNames = new List<string>();
currentSetIndex = Helper.SafeClampIndex(currentSetIndex, setNames.Count);
}
// AA0071
public static void RestoreSet(string oldSet)
{
if (!isQuickSwapping) originalSetBeforeQuickSwap = null;
if (setNames.Count == 0)
{
currentSetIndex = 0;
return;
}
int idx = setNames.FindIndex(s => string.Equals(s, oldSet, StringComparison.OrdinalIgnoreCase));
currentSetIndex = idx >= 0 ? idx : 0;
CurrentOperator = CurrentSet;
}
// AA0072
public static void SwitchSide()
{
if (!isQuickSwapping) originalSetBeforeQuickSwap = null;
if (ConfigLoader.betaTest) return;
onAttackers = !onAttackers;
MergeSets();
RestoreFavorites();
}
// AA0073
public static void NextSet()
{
if (!isQuickSwapping) originalSetBeforeQuickSwap = null;
if (setNames.Count == 0) return;
currentSetIndex = (currentSetIndex + 1) % setNames.Count;
CurrentOperator = CurrentSet;
}
// AA0074
public static void PreviousSet()
{
if (!isQuickSwapping) originalSetBeforeQuickSwap = null;
if (setNames.Count == 0) return;
currentSetIndex = (currentSetIndex - 1 + setNames.Count) % setNames.Count;
CurrentOperator = CurrentSet;
}
// AA0075
public static void SetCurrentSet(string name)
{
if (!isQuickSwapping) originalSetBeforeQuickSwap = null;
if (setNames.Count == 0) return;
int idx = setNames.FindIndex(s => string.Equals(s, name, StringComparison.OrdinalIgnoreCase));
if (idx >= 0)
{
currentSetIndex = idx;
CurrentOperator = CurrentSet;
}
}
// AA0076
private static void RestoreFavorites()
{
if (setNames.Count == 0)
{
currentSetIndex = 0;
return;
}
if (ConfigLoader.betaTest)
{
if (!string.IsNullOrEmpty(ConfigLoader.favoriteAttackers) &&
setNames.Contains(ConfigLoader.favoriteAttackers, StringComparer.OrdinalIgnoreCase))
{
currentSetIndex = setNames.FindIndex(s =>
string.Equals(s, ConfigLoader.favoriteAttackers, StringComparison.OrdinalIgnoreCase));
CurrentOperator = CurrentSet;
return;
}
if (!string.IsNullOrEmpty(ConfigLoader.favoriteDefenders) &&
setNames.Contains(ConfigLoader.favoriteDefenders, StringComparer.OrdinalIgnoreCase))
{
currentSetIndex = setNames.FindIndex(s =>
string.Equals(s, ConfigLoader.favoriteDefenders, StringComparison.OrdinalIgnoreCase));
CurrentOperator = CurrentSet;
return;
}
}
else
{
if (onAttackers && !string.IsNullOrEmpty(ConfigLoader.favoriteAttackers) &&
setNames.Contains(ConfigLoader.favoriteAttackers, StringComparer.OrdinalIgnoreCase))
{
currentSetIndex = setNames.FindIndex(s =>
string.Equals(s, ConfigLoader.favoriteAttackers, StringComparison.OrdinalIgnoreCase));
CurrentOperator = CurrentSet;
return;
}
if (!onAttackers && !string.IsNullOrEmpty(ConfigLoader.favoriteDefenders) &&
setNames.Contains(ConfigLoader.favoriteDefenders, StringComparer.OrdinalIgnoreCase))
{
currentSetIndex = setNames.FindIndex(s =>
string.Equals(s, ConfigLoader.favoriteDefenders, StringComparison.OrdinalIgnoreCase));
CurrentOperator = CurrentSet;
return;
}
}
currentSetIndex = 0;
CurrentOperator = CurrentSet;
}
public static void QuickSwapTo(string targetOp)
{
if (setNames == null || setNames.Count == 0) return;
// Check if the target operator is valid
bool inAttackers = attackers.ContainsKey(targetOp);
bool inDefenders = defenders.ContainsKey(targetOp);
if (!inAttackers && !inDefenders)
{
if (!mergedSets.ContainsKey(targetOp))
{
return; // Invalid operator
}
}
isQuickSwapping = true;
try
{
string preSwitchSet = CurrentSet;
if (!ConfigLoader.betaTest)
{
if (inAttackers && !onAttackers)
{
SwitchSide();
}
else if (inDefenders && onAttackers)
{
SwitchSide();
}
}
if (string.Equals(CurrentSet, targetOp, StringComparison.OrdinalIgnoreCase))
{
if (!string.IsNullOrEmpty(originalSetBeforeQuickSwap))
{
bool origInAttackers = attackers.ContainsKey(originalSetBeforeQuickSwap);
bool origInDefenders = defenders.ContainsKey(originalSetBeforeQuickSwap);
if (!ConfigLoader.betaTest)
{
if (origInAttackers && !onAttackers)
{
SwitchSide();
}
else if (origInDefenders && onAttackers)
{
SwitchSide();
}
}
SetCurrentSet(originalSetBeforeQuickSwap);
originalSetBeforeQuickSwap = null;
}
}
else
{
if (string.IsNullOrEmpty(originalSetBeforeQuickSwap))
{
originalSetBeforeQuickSwap = preSwitchSet;
}
SetCurrentSet(targetOp);
}
}
finally
{
isQuickSwapping = false;
}
}
}
}