60b519335f
- 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.
460 lines
16 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
} |