using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.Win32; using OpenSage.FileFormats.Big; namespace AnotherReplayReader { internal sealed class BigMinimapCache { private sealed class CacheAdapter { public List Bigs { get; set; } public Dictionary MapsToBigs { get; set; } public CacheAdapter() { Bigs = new List(); MapsToBigs = new Dictionary(); } } //private Cache _cache; private volatile IReadOnlyDictionary _mapsToBigs = null; public BigMinimapCache(Cache cache, string ra3Directory) { //_cache = cache; Task.Run(() => { try { if (!Directory.Exists(ra3Directory)) { Debug.Instance.DebugMessage += $"Will not initialize BigMinimapCache because RA3Directory {ra3Directory} does not exist.\r\n"; return; } var bigSet = ParseSkudefs(Directory.EnumerateFiles(ra3Directory, "*.SkuDef")); //var cached = _cache.GetOrDefault("bigsCache", new CacheAdapter()); var mapsToBigs = new Dictionary(); foreach (var bigPath in bigSet/*.Where(x => !cached.Bigs.Contains(x))*/) { if (!File.Exists(bigPath)) { Debug.Instance.DebugMessage += $"Big {bigPath} does not exist.\r\n"; continue; } Debug.Instance.DebugMessage += $"Trying to add Big {bigPath} to big minimap cache...\r\n"; try { using (var big = new BigArchive(bigPath)) { foreach (var entry in big.Entries) { if (entry.FullName.EndsWith("_art.tga", StringComparison.OrdinalIgnoreCase)) { mapsToBigs[entry.FullName] = bigPath; } } } } catch(Exception exception) { Debug.Instance.DebugMessage += $"Exception when reading big:\r\n {exception}\r\n"; } } //cached.Bigs = bigSet.ToList(); //_cache.Set("bigsCache", cached); _mapsToBigs = mapsToBigs; //cached.MapsToBigs; } catch (Exception exception) { Debug.Instance.DebugMessage += $"Exception during initialization of BigMinimapCache: \r\n{exception}\r\n"; } }); } public static HashSet ParseSkudefs(IEnumerable skudefs) { var skudefSet = new HashSet(skudefs.Select(x => x.ToLowerInvariant())); var unreadSkudefs = new HashSet(); var bigSet = new HashSet(); void ReadSkudefLine(string baseDirectory, string line, string expectedCommand, Action action) { try { char[] separators = { ' ', '\t' }; line = line.ToLowerInvariant(); var splitted = line.Split(separators, 2, StringSplitOptions.RemoveEmptyEntries); if (splitted[0].Equals(expectedCommand)) { var path = splitted[1]; if (!Path.IsPathRooted(path)) { path = Path.Combine(baseDirectory, path); } action(path); } } catch (Exception exception) { Debug.Instance.DebugMessage += $"Exception when parsing skudef line:\r\n {exception}\r\n"; } } void ReadSkudef(string fileName, Action onBaseDirectoryAndLine) { try { var baseDirectory = Path.GetDirectoryName(fileName).ToLowerInvariant(); foreach (var line in File.ReadAllLines(fileName)) { onBaseDirectoryAndLine(baseDirectory, line); } } catch (Exception exception) { Debug.Instance.DebugMessage += $"Exception when parsing skudef file:\r\n {exception}\r\n"; } } foreach (var skudef in skudefSet) { ReadSkudef(skudef, (baseDirectory, line) => { ReadSkudefLine(baseDirectory, line, "add-config", x => { if (!skudefSet.Contains(x)) { unreadSkudefs.Add(x); } }); ReadSkudefLine(baseDirectory, line, "add-big", x => bigSet.Add(x)); }); } foreach (var skudef in unreadSkudefs) { ReadSkudef(skudef, (baseDirectory, line) => { ReadSkudefLine(baseDirectory, line, "add-big", x => bigSet.Add(x)); }); } return bigSet; } public bool TryGetBigByEntryPath(string path, out BigArchive big) { big = null; if (_mapsToBigs == null) { return false; } if (!_mapsToBigs.ContainsKey(path)) { Debug.Instance.DebugMessage += $"Cannot find big entry [{path}].\r\n"; return false; } try { var bigPath = _mapsToBigs[path]; big = new BigArchive(bigPath); if(big.GetEntry(path) == null) { //_cache.Remove("bigsCache"); big.Dispose(); big = null; return false; } } catch (Exception exception) { Debug.Instance.DebugMessage += $"Exception during query (entryStream) of BigMinimapCache: \r\n{exception}\r\n"; big = null; return false; } return true; } public byte[] TryReadBytesFromBig(string path) { if(_mapsToBigs == null) { return null; } if(!_mapsToBigs.ContainsKey(path)) { return null; } try { var bigPath = _mapsToBigs[path]; using (var big = new BigArchive(path)) { var entry = big.GetEntry(path); using (var stream = entry.Open()) using (var reader = new BinaryReader(stream)) { return reader.ReadBytes((int)entry.Length); } } } catch (Exception exception) { Debug.Instance.DebugMessage += $"Exception during query (bytes) of BigMinimapCache: \r\n{exception}\r\n"; //_cache.Remove("bigsCache"); } return null; } } }