Skip to content

Commit d295e8f

Browse files
committed
#352: Add custom map directory file watcher
- Add a file watcher that will detect when a map is added or deleted, then update the game mode dropdown according to the new map list - Add and use `CustomMapsDirectory` field to `MapLoader` to avoid hard coded strings. - Add `GetLoadedMapBySha1` to remove some duplicate `GameModeMaps.Find()`. - Add a function `RefreshGameModeDropdown` to modify the dropdown after client is loaded. The function is a bit complicated due to doing inline modifications to the items and keeping the selected mode. Issue: #352 PR: #358
1 parent 624dfcc commit d295e8f

File tree

8 files changed

+270
-32
lines changed

8 files changed

+270
-32
lines changed

DXMainClient/DXGUI/Generic/LoadingScreen.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ private void LoadMaps()
8181
{
8282
mapLoader = new MapLoader();
8383
mapLoader.LoadMaps();
84+
mapLoader.StartCustomMapFileWatcher();
8485
}
8586

8687
private void Finish()

DXMainClient/DXGUI/Multiplayer/GameLobby/CnCNetGameLobby.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1594,14 +1594,14 @@ private void MapSharer_HandleMapDownloadComplete(SHA1EventArgs e)
15941594
{
15951595
string mapFileName = MapSharer.GetMapFileName(e.SHA1, e.MapName);
15961596
Logger.Log("Map " + mapFileName + " downloaded, parsing.");
1597-
string mapPath = "Maps/Custom/" + mapFileName;
1597+
string mapPath = MapLoader.CustomMapsDirectory + mapFileName;
15981598
Map map = MapLoader.LoadCustomMap(mapPath, out string returnMessage);
15991599
if (map != null)
16001600
{
16011601
AddNotice(returnMessage);
16021602
if (lastMapSHA1 == e.SHA1)
16031603
{
1604-
GameModeMap = GameModeMaps.Find(gmm => gmm.Map.SHA1 == lastMapSHA1);
1604+
GameModeMap = MapLoader.GetLoadedMapBySha1(lastMapSHA1);
16051605
ChangeMap(GameModeMap);
16061606
}
16071607
}
@@ -1803,7 +1803,7 @@ private void DownloadMapByIdCommand(string parameters)
18031803
sha1 = sha1.Replace("?", "");
18041804

18051805
// See if the user already has this map, with any filename, before attempting to download it.
1806-
GameModeMap loadedMap = GameModeMaps.Find(gmm => gmm.Map.SHA1 == sha1);
1806+
GameModeMap loadedMap = MapLoader.GetLoadedMapBySha1(sha1);
18071807

18081808
if (loadedMap != null)
18091809
{

DXMainClient/DXGUI/Multiplayer/GameLobby/GameLobbyBase.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,10 @@ DiscordHandler discordHandler
5959
) : base(windowManager)
6060
{
6161
_iniSectionName = iniName;
62+
6263
MapLoader = mapLoader;
64+
MapLoader.GameModeMapsUpdated += MapLoader_GameModeMapsUpdated;
65+
6366
this.isMultiplayer = isMultiplayer;
6467
this.discordHandler = discordHandler;
6568
}
@@ -2315,5 +2318,63 @@ public bool LoadGameOptionPreset(string name)
23152318
}
23162319

23172320
protected abstract bool AllowPlayerOptionsChange();
2321+
2322+
/// <summary>
2323+
/// Handle the GameModeMapsUpdated event from the MapLoader.
2324+
///
2325+
/// Updates the gamemode dropdown for new maps being added while the client is running
2326+
/// </summary>
2327+
/// <param name="sender"></param>
2328+
/// <param name="e"></param>
2329+
private void MapLoader_GameModeMapsUpdated(object sender, MapLoaderEventArgs e)
2330+
{
2331+
RefreshGameModeDropdown();
2332+
}
2333+
2334+
/// <summary>
2335+
/// Update the gamemode dropdown.
2336+
///
2337+
/// Allows us to show gamemodes for maps that were loaded after the client was started.
2338+
/// This function will do in-place modifications to `ddGameModeMapFilter.Items`.
2339+
/// </summary>
2340+
public void RefreshGameModeDropdown()
2341+
{
2342+
// Use a hashset to store the existing gamemodes in the dropdown for instant lookups.
2343+
// This is the set of existing dropdown items. Add anything from GameModeMaps, that isn't in this set, to the dropdown.
2344+
HashSet<string> existingDdGameModes = new HashSet<string>(ddGameModeMapFilter.Items.Select(ddItem => ddItem.Text));
2345+
// This is the updated list of game modes. Anything not in this set, that is in existingDdGameModes, should be removed from the dropdown.
2346+
HashSet<string> gameModeUpdated = new HashSet<string>(GameModeMaps.GameModes.Select(gm => gm.UIName));
2347+
// Don't accidentally remove favorite maps item.
2348+
gameModeUpdated.Add(FavoriteMapsLabel);
2349+
2350+
XNADropDownItem currentItem = ddGameModeMapFilter.SelectedItem;
2351+
2352+
Logger.Log($"Updating game modes dropdown display: lobbyType={this.GetType().Name}");
2353+
2354+
// Add any new game modes.
2355+
foreach (GameMode gm in GameModeMaps.GameModes)
2356+
{
2357+
//skip the game mode if it is already in the dropdown.
2358+
if (existingDdGameModes.Contains(gm.UIName))
2359+
continue;
2360+
2361+
// If the gamemode was not present, then add it.
2362+
ddGameModeMapFilter.AddItem(CreateGameFilterItem(gm.UIName, new GameModeMapFilter(GetGameModeMaps(gm))));
2363+
}
2364+
2365+
// Now remove game modes that should no longer be displayed.
2366+
ddGameModeMapFilter.Items.RemoveAll(ddItem => !gameModeUpdated.Contains(ddItem.Text));
2367+
2368+
// Make sure we keep the same game mode selected after adding or removing game modes.
2369+
// If the game mode is no longer available then switch to 0, aka, favorite maps.
2370+
int newIndex = 0;
2371+
for (int i = 0; i < ddGameModeMapFilter.Items.Count; i++)
2372+
{
2373+
if (ddGameModeMapFilter.Items[i].Text == currentItem.Text)
2374+
newIndex = i;
2375+
}
2376+
2377+
ddGameModeMapFilter.SelectedIndex = newIndex;
2378+
}
23182379
}
23192380
}

DXMainClient/DXGUI/Multiplayer/GameLobby/MultiplayerGameLobby.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public MultiplayerGameLobby(WindowManager windowManager, string iniName,
4444
s => SetMaxAhead(s)),
4545
new ChatBoxCommand("PROTOCOLVERSION", "Change ProtocolVersion (default 2) (game host only)".L10N("UI:Main:ChatboxCommandProtocolVersionHelp"), true,
4646
s => SetProtocolVersion(s)),
47-
new ChatBoxCommand("LOADMAP", "Load a custom map with given filename from /Maps/Custom/ folder.".L10N("UI:Main:ChatboxCommandLoadMapHelp"), true, LoadCustomMap),
47+
new ChatBoxCommand("LOADMAP", $"Load a custom map with given filename from {MapLoader.CustomMapsDirectory} folder.".L10N("UI:Main:ChatboxCommandLoadMapHelp"), true, LoadCustomMap),
4848
new ChatBoxCommand("RANDOMSTARTS", "Enables completely random starting locations (Tiberian Sun based games only).".L10N("UI:Main:ChatboxCommandRandomStartsHelp"), true,
4949
s => SetStartingLocationClearance(s)),
5050
new ChatBoxCommand("ROLL", "Roll dice, for example /roll 3d6".L10N("UI:Main:ChatboxCommandRollHelp"), false, RollDiceCommand),
@@ -487,7 +487,7 @@ private void RollDiceCommand(string dieType)
487487
/// <param name="mapName">Name of the map given as a parameter, without file extension.</param>
488488
private void LoadCustomMap(string mapName)
489489
{
490-
Map map = MapLoader.LoadCustomMap($"Maps/Custom/{mapName}", out string resultMessage);
490+
Map map = MapLoader.LoadCustomMap($"{MapLoader.CustomMapsDirectory}{mapName}", out string resultMessage);
491491
if (map != null)
492492
{
493493
AddNotice(resultMessage);

DXMainClient/DXMainClient.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,7 @@
432432
<Compile Include="Domain\Multiplayer\CnCNet\MapSharer.cs" />
433433
<Compile Include="Domain\Multiplayer\GameModeMap.cs" />
434434
<Compile Include="Domain\Multiplayer\GameModeMapCollection.cs" />
435+
<Compile Include="Domain\Multiplayer\MapLoaderEventArgs.cs" />
435436
<Compile Include="Domain\Multiplayer\GameOptionPresets.cs" />
436437
<Compile Include="Domain\Multiplayer\LAN\ClientIntCommandHandler.cs" />
437438
<Compile Include="Domain\Multiplayer\LAN\LANLobbyUser.cs" />

DXMainClient/Domain/Multiplayer/CnCNet/MapSharer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ private static string MapUpload(string _URL, Map map, string gameName, out bool
121121
{
122122
ServicePointManager.Expect100Continue = false;
123123

124-
string zipFile = ProgramConstants.GamePath + "Maps/Custom/" + map.SHA1 + ".zip";
124+
string zipFile = ProgramConstants.GamePath + MapLoader.CustomMapsDirectory + map.SHA1 + ".zip";
125125

126126
if (File.Exists(zipFile)) File.Delete(zipFile);
127127

@@ -380,7 +380,7 @@ public static string GetMapFileName(string sha1, string mapName)
380380

381381
private static string DownloadMain(string sha1, string myGame, string mapName, out bool success)
382382
{
383-
string customMapsDirectory = ProgramConstants.GamePath + "Maps/Custom/";
383+
string customMapsDirectory = ProgramConstants.GamePath + MapLoader.CustomMapsDirectory;
384384

385385
string mapFileName = GetMapFileName(sha1, mapName);
386386

0 commit comments

Comments
 (0)