using LightlessSync.API.Data.Enum; namespace LightlessSync.LightlessConfiguration.Configurations; public class TransientConfig : ILightlessConfiguration { public Dictionary TransientConfigs { get; set; } = []; public int Version { get; set; } = 2; public class TransientPlayerConfig { public List GlobalPersistentCache { get; set; } = []; public Dictionary> JobSpecificCache { get; set; } = []; public Dictionary> JobSpecificPetCache { get; set; } = []; private readonly object _cacheLock = new(); public TransientPlayerConfig() { } private bool ElevateIfNeeded(uint jobId, string gamePath) { // check if it's in the job cache of other jobs and elevate if needed foreach (var kvp in JobSpecificCache) { if (kvp.Key == jobId) continue; // elevate if the gamepath is included somewhere else if (kvp.Value.Contains(gamePath, StringComparer.Ordinal)) { JobSpecificCache[kvp.Key].Remove(gamePath); GlobalPersistentCache.Add(gamePath); return true; } } return false; } public int RemovePath(string gamePath, ObjectKind objectKind) { lock (_cacheLock) { int removedEntries = 0; if (objectKind == ObjectKind.Player) { if (GlobalPersistentCache.Remove(gamePath)) removedEntries++; foreach (var kvp in JobSpecificCache) { if (kvp.Value.Remove(gamePath)) removedEntries++; } } if (objectKind == ObjectKind.Pet) { foreach (var kvp in JobSpecificPetCache) { if (kvp.Value.Remove(gamePath)) removedEntries++; } } return removedEntries; } } public void AddOrElevate(uint jobId, string gamePath) { lock (_cacheLock) { // check if it's in the global cache, if yes, do nothing if (GlobalPersistentCache.Contains(gamePath, StringComparer.Ordinal)) { return; } if (ElevateIfNeeded(jobId, gamePath)) return; // check if the jobid is already in the cache to start if (!JobSpecificCache.TryGetValue(jobId, out var jobCache)) { JobSpecificCache[jobId] = jobCache = new(); } // check if the path is already in the job specific cache if (!jobCache.Contains(gamePath, StringComparer.Ordinal)) { jobCache.Add(gamePath); } } } public bool NormalizePaths(out int removedEntries) { bool changed = false; removedEntries = 0; GlobalPersistentCache = NormalizeList(GlobalPersistentCache, ref changed, ref removedEntries); foreach (var jobId in JobSpecificCache.Keys.ToList()) { JobSpecificCache[jobId] = NormalizeList(JobSpecificCache[jobId], ref changed, ref removedEntries); } foreach (var jobId in JobSpecificPetCache.Keys.ToList()) { JobSpecificPetCache[jobId] = NormalizeList(JobSpecificPetCache[jobId], ref changed, ref removedEntries); } return changed; } private static List NormalizeList(List entries, ref bool changed, ref int removedEntries) { if (entries.Count == 0) return entries; var result = new List(entries.Count); var seen = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (var entry in entries) { var normalized = NormalizePath(entry); if (string.IsNullOrEmpty(normalized)) { changed = true; continue; } if (!string.Equals(entry, normalized, StringComparison.Ordinal)) { changed = true; } if (seen.Add(normalized)) { result.Add(normalized); } else { changed = true; } } removedEntries += entries.Count - result.Count; return result; } private static string NormalizePath(string path) { if (string.IsNullOrEmpty(path)) return string.Empty; return path.Replace("\\", "/", StringComparison.Ordinal).ToLowerInvariant(); } } }