Skip to content

Commit

Permalink
Add map refresh
Browse files Browse the repository at this point in the history
Update MapCache.cs
  • Loading branch information
PunkPun committed Jan 18, 2022
1 parent d149624 commit 3612602
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 20 deletions.
2 changes: 1 addition & 1 deletion OpenRA.Game/Map/Map.cs
Expand Up @@ -265,7 +265,7 @@ public static string ComputeUID(IReadOnlyPackage package)
try
{
foreach (var filename in contents)
if (filename.EndsWith(".yaml") || filename.EndsWith(".bin") || filename.EndsWith(".lua"))
if (filename.EndsWith(".yaml") || filename.EndsWith(".bin") || filename.EndsWith(".lua") || filename == "map.png")
streams.Add(package.GetStream(filename));

// Take the SHA1
Expand Down
169 changes: 150 additions & 19 deletions OpenRA.Game/Map/MapCache.cs
Expand Up @@ -39,6 +39,8 @@ public sealed class MapCache : IEnumerable<MapPreview>, IDisposable

public Dictionary<string, string> StringPool { get; } = new Dictionary<string, string>();

readonly List<MapDirectoryTracker> mapDirectoryTrackers = new List<MapDirectoryTracker>();

public MapCache(ModData modData)
{
this.modData = modData;
Expand All @@ -48,12 +50,25 @@ public MapCache(ModData modData)
sheetBuilder = new SheetBuilder(SheetType.BGRA);
}

public string UpdateMaps()
{
var lastUid = "";
foreach (var tracker in mapDirectoryTrackers)
{
lastUid = tracker.UpdateMaps() ?? lastUid;
}

return lastUid == "" ? null : lastUid;
}

public void LoadMaps()
{
// Utility mod that does not support maps
if (!modData.Manifest.Contains<MapGrid>())
return;

var mapGrid = modData.Manifest.Get<MapGrid>();

// Enumerate map directories
foreach (var kv in modData.Manifest.MapFolders)
{
Expand Down Expand Up @@ -85,36 +100,44 @@ public void LoadMaps()
}

mapLocations.Add(package, classification);
mapDirectoryTrackers.Add(new MapDirectoryTracker(mapGrid, package, classification));
}

var mapGrid = modData.Manifest.Get<MapGrid>();
foreach (var kv in MapLocations)
{
foreach (var map in kv.Key.Contents)
{
IReadOnlyPackage mapPackage = null;
try
{
using (new Support.PerfTimer(map))
{
mapPackage = kv.Key.OpenPackage(map, modData.ModFiles);
if (mapPackage == null)
continue;
LoadMap(map, kv.Key, kv.Value, mapGrid);
}
}
}

var uid = Map.ComputeUID(mapPackage);
previews[uid].UpdateFromMap(mapPackage, kv.Key, kv.Value, modData.Manifest.MapCompatibility, mapGrid.Type);
}
}
catch (Exception e)
public string LoadMap(string map, IReadOnlyPackage package, MapClassification classification, MapGrid mapGrid)
{
IReadOnlyPackage mapPackage = null;
try
{
using (new Support.PerfTimer(map))
{
mapPackage = package.OpenPackage(map, modData.ModFiles);
if (mapPackage != null)
{
mapPackage?.Dispose();
Console.WriteLine("Failed to load map: {0}", map);
Console.WriteLine("Details: {0}", e);
Log.Write("debug", "Failed to load map: {0}", map);
Log.Write("debug", "Details: {0}", e);
var uid = Map.ComputeUID(mapPackage);
previews[uid].UpdateFromMap(mapPackage, package, classification, modData.Manifest.MapCompatibility, mapGrid.Type);
return uid;
}
}
}
catch (Exception e)
{
mapPackage?.Dispose();
Console.WriteLine("Failed to load map: {0}", map);
Console.WriteLine("Details: {0}", e);
Log.Write("debug", "Failed to load map: {0}", map);
Log.Write("debug", "Details: {0}", e);
}

return null;
}

public IEnumerable<IReadWritePackage> EnumerateMapDirPackages(MapClassification classification = MapClassification.System)
Expand Down Expand Up @@ -378,4 +401,112 @@ public void Dispose()
});
}
}

public class MapDirectoryTracker
{
readonly FileSystemWatcher watcher;
readonly MapGrid mapGrid;
readonly IReadOnlyPackage package;
readonly MapClassification classification;

enum MapAction { Add, Delete, Update }
readonly Dictionary<string, MapAction> mapActionQueue = new Dictionary<string, MapAction>();

public MapDirectoryTracker(MapGrid mapGrid, IReadOnlyPackage package, MapClassification classification)
{
this.mapGrid = mapGrid;
this.package = package;
this.classification = classification;

watcher = new FileSystemWatcher(package.Name);
watcher.Changed += (object sender, FileSystemEventArgs e) => AddActionSub(MapAction.Update, e.FullPath);
watcher.Created += (object sender, FileSystemEventArgs e) => AddActionSub(MapAction.Add, e.FullPath);
watcher.Deleted += (object sender, FileSystemEventArgs e) => AddActionSub(MapAction.Delete, e.FullPath);
watcher.Renamed += (object sender, RenamedEventArgs e) => AddActionSub(MapAction.Add, e.FullPath, e.OldFullPath);

watcher.IncludeSubdirectories = true;
watcher.EnableRaisingEvents = true;
}

void AddActionSub(MapAction mapAction, string fullpath, string oldFullPath = null)
{
// if path is not root, update map instead
var path = RemoveSubDirs(fullpath);
if (fullpath == path)
AddAction(mapAction, path);
else
AddAction(MapAction.Update, path);

// called when renamed / file changed location
if (oldFullPath != null)
{
var oldpath = RemoveSubDirs(oldFullPath);
if (oldFullPath == oldpath)
AddAction(MapAction.Delete, oldFullPath);
else
if (oldpath != null)
AddAction(MapAction.Update, oldFullPath);
}
}

void AddAction(MapAction mapAction, string path)
{
Console.WriteLine(mapAction + " detected");

// If action already exists in the action queue
if (mapActionQueue.Any(x => x.Key == path))
{
// If map is loaded, update or delete it
// If map is not loaded, add it or delete actions
if (Game.ModData.MapCache.Any(x => x.Package?.Name == path))
if (mapAction == MapAction.Delete)
mapActionQueue[path] = MapAction.Delete;
else
mapActionQueue[path] = MapAction.Update;
else
if (mapAction == MapAction.Delete)
mapActionQueue.Remove(path);
else
mapActionQueue[path] = MapAction.Add;
}
else
mapActionQueue.Add(path, mapAction);
}

public string UpdateMaps()
{
var lastUid = "";
foreach (var a in mapActionQueue)
{
Console.WriteLine(a.Value + " " + a.Key);
switch (a.Value)
{
case MapAction.Add:
lastUid = Game.ModData.MapCache.LoadMap(a.Key.Replace(package.Name + Path.DirectorySeparatorChar, ""), package, classification, mapGrid);
break;
case MapAction.Update:
Game.ModData.MapCache.FirstOrDefault(x => x.Package.Name == a.Key && x.Status == MapStatus.Available)?.Invalidate();
lastUid = Game.ModData.MapCache.LoadMap(a.Key.Replace(package.Name + Path.DirectorySeparatorChar, ""), package, classification, mapGrid);
break;
case MapAction.Delete:
Game.ModData.MapCache.FirstOrDefault(x => x.Package.Name == a.Key && x.Status == MapStatus.Available)?.Invalidate();
break;
}
}

mapActionQueue.Clear();
return lastUid == "" ? null : lastUid;
}

string RemoveSubDirs(string path)
{
var endPath = path.Replace(package.Name + Path.DirectorySeparatorChar, "");

// if file moved from out outside directory
if (path == endPath)
return null;

return package.Name + Path.DirectorySeparatorChar + endPath.Split(Path.DirectorySeparatorChar)[0];
}
}
}
13 changes: 13 additions & 0 deletions OpenRA.Mods.Common/Widgets/Logic/MapChooserLogic.cs
Expand Up @@ -123,9 +123,22 @@ public class MapChooserLogic : ChromeLogic
});
};

var lastUpdatedUid = modData.MapCache.UpdateMaps();
SetupMapTab(MapClassification.User, filter, "USER_MAPS_TAB_BUTTON", "USER_MAPS_TAB", itemTemplate);
SetupMapTab(MapClassification.System, filter, "SYSTEM_MAPS_TAB_BUTTON", "SYSTEM_MAPS_TAB", itemTemplate);

if (lastUpdatedUid != null)
{
selectedUid = lastUpdatedUid;
currentTab = tabMaps.Keys.FirstOrDefault(k => tabMaps[k].Select(mp => mp.Uid).Contains(selectedUid));

if (currentTab != MapClassification.Unknown)
{
SwitchTab(currentTab, itemTemplate);
return;
}
}

if (initialMap == null && tabMaps.Keys.Contains(initialTab) && tabMaps[initialTab].Any())
{
selectedUid = Game.ModData.MapCache.ChooseInitialMap(tabMaps[initialTab].Select(mp => mp.Uid).First(),
Expand Down

0 comments on commit 3612602

Please sign in to comment.