AnotherReplayReader/BigMinimapCache.cs
2021-04-23 00:56:08 +02:00

232 lines
7.8 KiB
C#

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<string> Bigs { get; set; }
public Dictionary<string, string> MapsToBigs { get; set; }
public CacheAdapter()
{
Bigs = new List<string>();
MapsToBigs = new Dictionary<string, string>();
}
}
//private Cache _cache;
private volatile IReadOnlyDictionary<string, string> _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<string, string>();
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<string> ParseSkudefs(IEnumerable<string> skudefs)
{
var skudefSet = new HashSet<string>(skudefs.Select(x => x.ToLowerInvariant()));
var unreadSkudefs = new HashSet<string>();
var bigSet = new HashSet<string>();
void ReadSkudefLine(string baseDirectory, string line, string expectedCommand, Action<string> 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<string, string> 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;
}
}
}