Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/host not loading on map share #608

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
a3bc9e8
Add DisallowJoiningIncompatibleGames to ClientConfiguration
devo1929 Feb 21, 2023
aa21f20
#465 non host cannot select America/Cuba with random selectors and di…
devo1929 May 9, 2023
6bdd1da
Move favorite maps to its own section
devo1929 Nov 4, 2023
599c68d
#502 - players cannot select Germany faction with "No Yuri/No France"
devo1929 Jan 17, 2024
c4692fb
Warn host and eventually close if inactive
GrantBartlett Aug 31, 2022
e645946
Event handler null checks
devo1929 Feb 13, 2024
6fee581
Check for enabled on inactive host kick timer
devo1929 Feb 13, 2024
5beffda
Check for "default" updateconfig.ini file to copy
devo1929 Feb 14, 2024
6213cf2
Proper onmousemove, stop timer after lobby leave
devo1929 Feb 14, 2024
012fdf5
Consolidate inactive timer check, move logic into containing class
devo1929 Feb 15, 2024
9d0b20b
build on yr/** branches
devo1929 Feb 16, 2024
1417cc5
Skip inactive timer for password games
devo1929 Feb 20, 2024
1e48267
Rewords privacy notice as per #427 (#459)
GrantBartlett Apr 10, 2023
1deb919
Merge branch 'refs/heads/develop' into yr/develop
devo1929 Aug 1, 2024
b0274ea
Merge remote-tracking branch 'remotes/origin/develop' into yr/develop
devo1929 Oct 1, 2024
1126e02
post merge fixes
devo1929 Oct 1, 2024
91cbbfa
Merge branch 'develop' into yr/develop
GrantBartlett Jan 1, 2025
1bdf521
Merge branch 'develop' into yr/develop
GrantBartlett Jan 1, 2025
cdc3614
Merge branch 'develop' into yr/develop
GrantBartlett Jan 2, 2025
6e5bf90
Write OriginalFilename in non mp games
GrantBartlett Jan 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: build client

on:
push:
branches: [ master, develop ]
branches: [ master, develop, yr/** ]
pull_request:
branches: [ master, develop ]
workflow_dispatch:
Expand Down
12 changes: 11 additions & 1 deletion ClientCore/ClientConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,16 @@ private List<TranslationGameFile> ParseTranslationGameFiles()

public string AllowedCustomGameModes => clientDefinitionsIni.GetStringValue(SETTINGS, "AllowedCustomGameModes", "Standard,Custom Map");

public string InactiveHostWarningTitle => clientDefinitionsIni.GetStringValue(SETTINGS, "InactiveHostWarningTitle", "Are you still here?");

public string InactiveHostWarningMessage => clientDefinitionsIni.GetStringValue(SETTINGS, "InactiveHostWarningMessage", "Your game may be closed due to inactivity.");

public int InactiveHostWarningMessageSeconds => clientDefinitionsIni.GetIntValue(SETTINGS, "InactiveHostWarningMessageSeconds", 0);

public int InactiveHostKickSeconds => clientDefinitionsIni.GetIntValue(SETTINGS, "InactiveHostKickSeconds", 0);

public bool InactiveHostKickEnabled => InactiveHostWarningMessageSeconds > 0 && InactiveHostKickSeconds > 0;

public string GetGameExecutableName()
{
string[] exeNames = clientDefinitionsIni.GetStringValue(SETTINGS, "GameExecutableNames", "Game.exe").Split(',');
Expand All @@ -348,7 +358,7 @@ public string GetGameExecutableName()
public bool DisplayPlayerCountInTopBar => clientDefinitionsIni.GetBooleanValue(SETTINGS, "DisplayPlayerCountInTopBar", false);

/// <summary>
/// The name of the executable in the main game directory that selects
/// The name of the executable in the main game directory that selects
/// the correct main client executable.
/// For example, DTA.exe in case of DTA.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion ClientCore/ClientCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
<PackageReference Include="Rampastring.XNAUI.$(Engine).Debug" Condition="'$(Configuration.Contains(Debug))'" />
<PackageReference Include="System.Text.Encoding.CodePages" />
</ItemGroup>
</Project>
</Project>
26 changes: 26 additions & 0 deletions ClientCore/Extensions/IniFileExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Collections.Generic;
using Rampastring.Tools;

namespace ClientCore.Extensions
{
public static class IniFileExtensions
{
public static IniSection GetOrAddSection(this IniFile iniFile, string sectionName)
{
var section = iniFile.GetSection(sectionName);
if (section != null)
return section;

section = new IniSection(sectionName);
iniFile.AddSection(section);
return section;
}

public static void RemoveAllKeys(this IniSection iniSection)
{
var keys = new List<KeyValuePair<string, string>>(iniSection.Keys);
foreach (KeyValuePair<string, string> iniSectionKey in keys)
iniSection.RemoveKey(iniSectionKey.Key);
}
}
}
63 changes: 59 additions & 4 deletions ClientCore/Settings/UserINISettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
using Rampastring.Tools;
using System;
using System.Collections.Generic;
using System.Linq;
using ClientCore.Enums;
using ClientCore.Extensions;

namespace ClientCore
{
Expand All @@ -16,6 +18,7 @@ public class UserINISettings
public const string AUDIO = "Audio";
public const string COMPATIBILITY = "Compatibility";
public const string GAME_FILTERS = "GameFilters";
private const string FAVORITE_MAPS = "FavoriteMaps";

private const bool DEFAULT_SHOW_FRIENDS_ONLY_GAMES = false;
private const bool DEFAULT_HIDE_LOCKED_GAMES = false;
Expand Down Expand Up @@ -123,7 +126,7 @@ protected UserINISettings(IniFile iniFile)
HideIncompatibleGames = new BoolSetting(iniFile, GAME_FILTERS, "HideIncompatibleGames", DEFAULT_HIDE_INCOMPATIBLE_GAMES);
MaxPlayerCount = new IntRangeSetting(iniFile, GAME_FILTERS, "MaxPlayerCount", DEFAULT_MAX_PLAYER_COUNT, 2, 8);

FavoriteMaps = new StringListSetting(iniFile, OPTIONS, "FavoriteMaps", new List<string>());
LoadFavoriteMaps(iniFile);
}

public IniFile SettingsIni { get; private set; }
Expand Down Expand Up @@ -252,7 +255,7 @@ protected UserINISettings(IniFile iniFile)

public BoolSetting GenerateOnlyNewValuesInTranslationStub { get; private set; }

public StringListSetting FavoriteMaps { get; private set; }
public List<string> FavoriteMaps { get; private set; }

public void SetValue(string section, string key, string value)
=> SettingsIni.SetStringValue(section, key, value);
Expand Down Expand Up @@ -282,7 +285,7 @@ public bool ToggleFavoriteMap(string mapName, string gameModeName, bool isFavori
if (string.IsNullOrEmpty(mapName))
return isFavorite;

var favoriteMapKey = FavoriteMapKey(mapName, gameModeName);
string favoriteMapKey = FavoriteMapKey(mapName, gameModeName);
isFavorite = IsFavoriteMap(mapName, gameModeName);
if (isFavorite)
FavoriteMaps.Remove(favoriteMapKey);
Expand All @@ -291,15 +294,39 @@ public bool ToggleFavoriteMap(string mapName, string gameModeName, bool isFavori

Instance.SaveSettings();

WriteFavoriteMaps();

return !isFavorite;
}

private void LoadFavoriteMaps(IniFile iniFile)
{
FavoriteMaps = new List<string>();
bool legacyMapsLoaded = LoadLegacyFavoriteMaps(iniFile);
var favoriteMapsSection = SettingsIni.GetOrAddSection(FAVORITE_MAPS);
foreach (KeyValuePair<string, string> keyValuePair in favoriteMapsSection.Keys)
FavoriteMaps.Add(keyValuePair.Value);

if (legacyMapsLoaded)
WriteFavoriteMaps();
}

private void WriteFavoriteMaps()
{
var favoriteMapsSection = SettingsIni.GetOrAddSection(FAVORITE_MAPS);
favoriteMapsSection.RemoveAllKeys();
for (int i = 0; i < FavoriteMaps.Count; i++)
favoriteMapsSection.AddKey(i.ToString(), FavoriteMaps[i]);

SaveSettings();
}

/// <summary>
/// Checks if a specified map name and game mode name belongs to the favorite map list.
/// </summary>
/// <param name="nameName">The name of the map.</param>
/// <param name="gameModeName">The name of the game mode</param>
public bool IsFavoriteMap(string nameName, string gameModeName) => FavoriteMaps.Value.Contains(FavoriteMapKey(nameName, gameModeName));
public bool IsFavoriteMap(string nameName, string gameModeName) => FavoriteMaps.Contains(FavoriteMapKey(nameName, gameModeName));

private string FavoriteMapKey(string nameName, string gameModeName) => $"{nameName}:{gameModeName}";

Expand Down Expand Up @@ -344,5 +371,33 @@ public void ResetGameFilters()
HidePasswordedGames.Value = DEFAULT_HIDE_PASSWORDED_GAMES;
MaxPlayerCount.Value = DEFAULT_MAX_PLAYER_COUNT;
}

/// <summary>
/// Used to remove old sections/keys to avoid confusion when viewing the ini file directly.
/// </summary>
private void CleanUpLegacySettings()
{
SettingsIni.GetSection(GAME_FILTERS).RemoveKey("SortAlpha");
}

/// <summary>
/// Previously, favorite maps were stored under a single key under the [Options] section.
/// This attempts to read in that legacy key.
/// </summary>
/// <param name="iniFile"></param>
/// <returns>Whether or not legacy favorites were loaded.</returns>
private bool LoadLegacyFavoriteMaps(IniFile iniFile)
{
var legacyFavoriteMaps = new StringListSetting(iniFile, OPTIONS, FAVORITE_MAPS, new List<string>());
if (!legacyFavoriteMaps.Value?.Any() ?? true)
return false;

foreach (string favoriteMapKey in legacyFavoriteMaps.Value)
FavoriteMaps.Add(favoriteMapKey);

// remove the old key
iniFile.GetSection(OPTIONS).RemoveKey(FAVORITE_MAPS);
return true;
}
}
}
3 changes: 3 additions & 0 deletions DXMainClient/DXGUI/Multiplayer/CnCNet/CnCNetLobby.cs
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,9 @@ private string GetJoinGameError(HostedCnCNetGame hg)
if (hg.Incompatible && ClientConfiguration.Instance.DisallowJoiningIncompatibleGames)
return "Cannot join game. The host is on a different game version than you.".L10N("Client:Main:DisallowJoiningIncompatibleGames");

if (hg.Incompatible && ClientConfiguration.Instance.DisallowJoiningIncompatibleGames)
return "Cannot join game. The host is on a different game version than you.".L10N("UI:Main:DisallowJoiningIncompatibleGames");

if (hg.Locked)
return "The selected game is locked!".L10N("Client:Main:GameLocked");

Expand Down
34 changes: 32 additions & 2 deletions DXMainClient/DXGUI/Multiplayer/GameLobby/CnCNetGameLobby.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ PrivateMessagingWindow pmWindow
this.gameCollection = gameCollection;
this.cncnetUserData = cncnetUserData;
this.pmWindow = pmWindow;
gameHostInactiveCheck = new GameHostInactiveCheck(WindowManager);

ctcpCommandHandlers = new CommandHandlerBase[]
{
Expand Down Expand Up @@ -141,6 +142,8 @@ PrivateMessagingWindow pmWindow

private MapSharingConfirmationPanel mapSharingConfirmationPanel;

private readonly GameHostInactiveCheck gameHostInactiveCheck;

/// <summary>
/// The SHA1 of the latest selected map.
/// Used for map sharing.
Expand Down Expand Up @@ -169,6 +172,8 @@ public override void Initialize()
IniNameOverride = nameof(CnCNetGameLobby);
base.Initialize();

MouseMove += (sender, args) => gameHostInactiveCheck.Reset();

btnChangeTunnel = FindChild<XNAClientButton>(nameof(btnChangeTunnel));
btnChangeTunnel.LeftClick += BtnChangeTunnel_LeftClick;

Expand All @@ -178,6 +183,8 @@ public override void Initialize()
gameBroadcastTimer.Enabled = false;
gameBroadcastTimer.TimeElapsed += GameBroadcastTimer_TimeElapsed;

gameHostInactiveCheck.CloseEvent += GameHostInactiveCheckCloseEvent;

tunnelSelectionWindow = new TunnelSelectionWindow(WindowManager, tunnelHandler);
tunnelSelectionWindow.Initialize();
tunnelSelectionWindow.DrawOrder = 1;
Expand Down Expand Up @@ -236,6 +243,7 @@ public void SetUp(Channel channel, bool isHost, int playerLimit,
RandomSeed = new Random().Next();
RefreshMapSelectionUI();
btnChangeTunnel.Enable();
StartInactiveCheck();
}
else
{
Expand All @@ -255,6 +263,17 @@ public void SetUp(Channel channel, bool isHost, int playerLimit,

private void TunnelHandler_CurrentTunnelPinged(object sender, EventArgs e) => UpdatePing();

private void GameHostInactiveCheckCloseEvent(object sender, EventArgs e) => LeaveGameLobby();

public void StartInactiveCheck()
{
if (!ClientConfiguration.Instance.InactiveHostKickEnabled || isCustomPassword)
return;
gameHostInactiveCheck.Start();
}

public void StopInactiveCheck() => gameHostInactiveCheck.Stop();

public void OnJoined()
{
FileHashCalculator fhc = new FileHashCalculator();
Expand Down Expand Up @@ -397,6 +416,7 @@ public void LeaveGameLobby()
{
if (IsHost)
{
StopInactiveCheck();
closed = true;
BroadcastGame();
}
Expand Down Expand Up @@ -746,9 +766,15 @@ private void HandleOptionsRequest(string playerName, int options)
if (color < 0 || color > MPColors.Count)
return;

var disallowedSides = GetDisallowedSides();
var disallowedSides = GetDisallowedSides().ToList();

if (side > 0 && side <= SideCount && disallowedSides[side - 1])
// Disallowed sides from client, maps, or game modes do not take random selectors into account
// So, we need to insert "false" for each random at the beginning of this list AFTER getting them
// from client, maps, or game modes.
for(int i = 0; i < RandomSelectorCount; i++)
disallowedSides.Insert(0, false);

if (side > 0 && side <= SideCount && disallowedSides[side])
return;

if (Map.CoopInfo != null)
Expand Down Expand Up @@ -1241,6 +1267,8 @@ protected override void GameProcessExited()
BroadcastPlayerOptions();
BroadcastPlayerExtraOptions();

StartInactiveCheck();

if (Players.Count < playerLimit)
UnlockGame(true);
}
Expand Down Expand Up @@ -1309,6 +1337,8 @@ protected override void StartGame()
HandleCheatDetectedMessage(ProgramConstants.PLAYERNAME);
}

StopInactiveCheck();

base.StartGame();
}

Expand Down
81 changes: 81 additions & 0 deletions DXMainClient/DXGUI/Multiplayer/GameLobby/GameHostInactiveCheck.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System;
using System.Timers;
using ClientCore;
using ClientGUI;
using Rampastring.XNAUI;

namespace DTAClient.DXGUI.Multiplayer.GameLobby
{
public class GameHostInactiveCheck
{
private readonly WindowManager windowManager;
private readonly Timer timer;
private bool warningShown;
private DateTime startDttm;
private static int WarningSeconds => ClientConfiguration.Instance.InactiveHostWarningMessageSeconds;
private static int CloseSeconds => WarningSeconds + ClientConfiguration.Instance.InactiveHostKickSeconds;

public event EventHandler CloseEvent;

public GameHostInactiveCheck(WindowManager windowManager)
{
this.windowManager = windowManager;
timer = CreateTimer();
}


private Timer CreateTimer()
{
var _timer = new Timer();
_timer.AutoReset = true;
_timer.Interval = 1000;
_timer.Elapsed += TimerOnElapsed;
return _timer;
}

private void TimerOnElapsed(object sender, ElapsedEventArgs e)
{
double secondsElapsed = (DateTime.UtcNow - startDttm).TotalSeconds;

if (secondsElapsed > WarningSeconds && !warningShown)
ShowWarning();

if (secondsElapsed > CloseSeconds)
SendCloseEvent();
}

public void Start()
{
Reset();
timer.Start();
}


public void Reset()
{
startDttm = DateTime.UtcNow;
warningShown = false;
}

public void Stop() => timer.Stop();

private void SendCloseEvent()
{
Stop();
CloseEvent?.Invoke(this, null);
}

private void ShowWarning()
{
warningShown = true;
XNAMessageBox hostInactiveWarningMessageBox = new XNAMessageBox(
windowManager,
ClientConfiguration.Instance.InactiveHostWarningTitle,
ClientConfiguration.Instance.InactiveHostWarningMessage,
XNAMessageBoxButtons.OK
);
hostInactiveWarningMessageBox.OKClickedAction = box => Reset();
hostInactiveWarningMessageBox.Show();
}
}
}
Loading
Loading