Skip to content

Commit

Permalink
#352: Add custom map directory file watcher
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
alexlambson committed Aug 2, 2022
1 parent 624dfcc commit d295e8f
Show file tree
Hide file tree
Showing 8 changed files with 270 additions and 32 deletions.
1 change: 1 addition & 0 deletions DXMainClient/DXGUI/Generic/LoadingScreen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ private void LoadMaps()
{
mapLoader = new MapLoader();
mapLoader.LoadMaps();
mapLoader.StartCustomMapFileWatcher();
}

private void Finish()
Expand Down
6 changes: 3 additions & 3 deletions DXMainClient/DXGUI/Multiplayer/GameLobby/CnCNetGameLobby.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1594,14 +1594,14 @@ private void MapSharer_HandleMapDownloadComplete(SHA1EventArgs e)
{
string mapFileName = MapSharer.GetMapFileName(e.SHA1, e.MapName);
Logger.Log("Map " + mapFileName + " downloaded, parsing.");
string mapPath = "Maps/Custom/" + mapFileName;
string mapPath = MapLoader.CustomMapsDirectory + mapFileName;
Map map = MapLoader.LoadCustomMap(mapPath, out string returnMessage);
if (map != null)
{
AddNotice(returnMessage);
if (lastMapSHA1 == e.SHA1)
{
GameModeMap = GameModeMaps.Find(gmm => gmm.Map.SHA1 == lastMapSHA1);
GameModeMap = MapLoader.GetLoadedMapBySha1(lastMapSHA1);
ChangeMap(GameModeMap);
}
}
Expand Down Expand Up @@ -1803,7 +1803,7 @@ private void DownloadMapByIdCommand(string parameters)
sha1 = sha1.Replace("?", "");

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

if (loadedMap != null)
{
Expand Down
61 changes: 61 additions & 0 deletions DXMainClient/DXGUI/Multiplayer/GameLobby/GameLobbyBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ DiscordHandler discordHandler
) : base(windowManager)
{
_iniSectionName = iniName;

MapLoader = mapLoader;
MapLoader.GameModeMapsUpdated += MapLoader_GameModeMapsUpdated;

this.isMultiplayer = isMultiplayer;
this.discordHandler = discordHandler;
}
Expand Down Expand Up @@ -2315,5 +2318,63 @@ public bool LoadGameOptionPreset(string name)
}

protected abstract bool AllowPlayerOptionsChange();

/// <summary>
/// Handle the GameModeMapsUpdated event from the MapLoader.
///
/// Updates the gamemode dropdown for new maps being added while the client is running
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MapLoader_GameModeMapsUpdated(object sender, MapLoaderEventArgs e)
{
RefreshGameModeDropdown();
}

/// <summary>
/// Update the gamemode dropdown.
///
/// Allows us to show gamemodes for maps that were loaded after the client was started.
/// This function will do in-place modifications to `ddGameModeMapFilter.Items`.
/// </summary>
public void RefreshGameModeDropdown()
{
// Use a hashset to store the existing gamemodes in the dropdown for instant lookups.
// This is the set of existing dropdown items. Add anything from GameModeMaps, that isn't in this set, to the dropdown.
HashSet<string> existingDdGameModes = new HashSet<string>(ddGameModeMapFilter.Items.Select(ddItem => ddItem.Text));
// This is the updated list of game modes. Anything not in this set, that is in existingDdGameModes, should be removed from the dropdown.
HashSet<string> gameModeUpdated = new HashSet<string>(GameModeMaps.GameModes.Select(gm => gm.UIName));
// Don't accidentally remove favorite maps item.
gameModeUpdated.Add(FavoriteMapsLabel);

XNADropDownItem currentItem = ddGameModeMapFilter.SelectedItem;

Logger.Log($"Updating game modes dropdown display: lobbyType={this.GetType().Name}");

// Add any new game modes.
foreach (GameMode gm in GameModeMaps.GameModes)
{
//skip the game mode if it is already in the dropdown.
if (existingDdGameModes.Contains(gm.UIName))
continue;

// If the gamemode was not present, then add it.
ddGameModeMapFilter.AddItem(CreateGameFilterItem(gm.UIName, new GameModeMapFilter(GetGameModeMaps(gm))));
}

// Now remove game modes that should no longer be displayed.
ddGameModeMapFilter.Items.RemoveAll(ddItem => !gameModeUpdated.Contains(ddItem.Text));

// Make sure we keep the same game mode selected after adding or removing game modes.
// If the game mode is no longer available then switch to 0, aka, favorite maps.
int newIndex = 0;
for (int i = 0; i < ddGameModeMapFilter.Items.Count; i++)
{
if (ddGameModeMapFilter.Items[i].Text == currentItem.Text)
newIndex = i;
}

ddGameModeMapFilter.SelectedIndex = newIndex;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public MultiplayerGameLobby(WindowManager windowManager, string iniName,
s => SetMaxAhead(s)),
new ChatBoxCommand("PROTOCOLVERSION", "Change ProtocolVersion (default 2) (game host only)".L10N("UI:Main:ChatboxCommandProtocolVersionHelp"), true,
s => SetProtocolVersion(s)),
new ChatBoxCommand("LOADMAP", "Load a custom map with given filename from /Maps/Custom/ folder.".L10N("UI:Main:ChatboxCommandLoadMapHelp"), true, LoadCustomMap),
new ChatBoxCommand("LOADMAP", $"Load a custom map with given filename from {MapLoader.CustomMapsDirectory} folder.".L10N("UI:Main:ChatboxCommandLoadMapHelp"), true, LoadCustomMap),
new ChatBoxCommand("RANDOMSTARTS", "Enables completely random starting locations (Tiberian Sun based games only).".L10N("UI:Main:ChatboxCommandRandomStartsHelp"), true,
s => SetStartingLocationClearance(s)),
new ChatBoxCommand("ROLL", "Roll dice, for example /roll 3d6".L10N("UI:Main:ChatboxCommandRollHelp"), false, RollDiceCommand),
Expand Down Expand Up @@ -487,7 +487,7 @@ private void RollDiceCommand(string dieType)
/// <param name="mapName">Name of the map given as a parameter, without file extension.</param>
private void LoadCustomMap(string mapName)
{
Map map = MapLoader.LoadCustomMap($"Maps/Custom/{mapName}", out string resultMessage);
Map map = MapLoader.LoadCustomMap($"{MapLoader.CustomMapsDirectory}{mapName}", out string resultMessage);
if (map != null)
{
AddNotice(resultMessage);
Expand Down
1 change: 1 addition & 0 deletions DXMainClient/DXMainClient.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@
<Compile Include="Domain\Multiplayer\CnCNet\MapSharer.cs" />
<Compile Include="Domain\Multiplayer\GameModeMap.cs" />
<Compile Include="Domain\Multiplayer\GameModeMapCollection.cs" />
<Compile Include="Domain\Multiplayer\MapLoaderEventArgs.cs" />
<Compile Include="Domain\Multiplayer\GameOptionPresets.cs" />
<Compile Include="Domain\Multiplayer\LAN\ClientIntCommandHandler.cs" />
<Compile Include="Domain\Multiplayer\LAN\LANLobbyUser.cs" />
Expand Down
4 changes: 2 additions & 2 deletions DXMainClient/Domain/Multiplayer/CnCNet/MapSharer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ private static string MapUpload(string _URL, Map map, string gameName, out bool
{
ServicePointManager.Expect100Continue = false;

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

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

Expand Down Expand Up @@ -380,7 +380,7 @@ public static string GetMapFileName(string sha1, string mapName)

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

string mapFileName = GetMapFileName(sha1, mapName);

Expand Down
Loading

0 comments on commit d295e8f

Please sign in to comment.