using System.Collections.Concurrent; using XFEEDToolBox.Core.Rendering; namespace XFEEDToolBox.Rendering; internal static class LocalShipModels { private static readonly ConcurrentDictionary> cache = new(); private static readonly object sourceLock = new(); private static EliteLocalModels? gameModels; private static string gamePath = ""; private static readonly ConcurrentDictionary> icons=new(); private static readonly ConcurrentDictionary> nebulae=new(); public static Task LoadNebulaAsync(string template) { var executable=App.ViewModel.PluginGameExecutable; return nebulae.GetOrAdd(executable+":"+template,_=>Task.Run(()=> { lock(sourceLock) { if(gameModels is null||!executable.Equals(gamePath,StringComparison.OrdinalIgnoreCase)){gameModels=new(executable);gamePath=executable;} return EliteNebulae.Read(gameModels,template); } })); } public static Task LoadIconAsync(string name) { var executable=App.ViewModel.PluginGameExecutable; return icons.GetOrAdd(executable+":"+name,_=>Task.Run(()=> { lock(sourceLock) { if(gameModels is null||!executable.Equals(gamePath,StringComparison.OrdinalIgnoreCase)){gameModels=new(executable);gamePath=executable;} return EliteModuleIcons.Read(gameModels,name); } })); } public static string Key(string type) => new(type.ToLowerInvariant().Where(char.IsAsciiLetterOrDigit).ToArray()); public static ShipMesh? Load(string type) { var key = Key(type); if (key.Length == 0) return null; foreach (var directory in new[] { Path.Combine(App.Runtime.DataDirectory, "models"), Path.Combine(AppContext.BaseDirectory, "Assets", "Ships") }) foreach (var extension in new[] { ".obj", ".stl" }) { var path = Path.Combine(directory, key + extension); if (!File.Exists(path)) continue; var stamp = path + ":" + File.GetLastWriteTimeUtc(path).Ticks; if (cache.TryGetValue(stamp, out var weak) && weak.TryGetTarget(out var found)) return found; var mesh = ShipMeshReader.Read(path); cache[stamp] = new(mesh); return mesh; } var executable = App.ViewModel.PluginGameExecutable; if (!File.Exists(executable)) return null; lock (sourceLock) { if (gameModels is null || !executable.Equals(gamePath, StringComparison.OrdinalIgnoreCase)) { gameModels = new(executable); gamePath = executable; } var stamp = executable + ":" + key; if (cache.TryGetValue(stamp, out var weak) && weak.TryGetTarget(out var found)) return found; var mesh = gameModels.Read(type); if (mesh is not null) cache[stamp] = new(mesh); return mesh; } } }