Skip to content

Conversation

SadPencil
Copy link
Member

@SadPencil SadPencil commented May 16, 2025

We should rely on the asserts to build a robust program.

  • The client will now actively throw assert errors if it's a development build, or ModMode is turned on.
  • Fix in some cases the loading screen might hang forever. Delay using XNAMessageBox as the DisplayErrorAction until the main menu has been loaded. Otherwise, if there are any exceptions (not only assert failures but also other exceptions) be thrown when parsing the maps, the loading screen will hang forever. (moved to Fix loading screen hanging on map parsing errors #782)

Example:

diff --git a/DXMainClient/DXGUI/Multiplayer/GameLobby/GameLobbyBase.cs b/DXMainClient/DXGUI/Multiplayer/GameLobby/GameLobbyBase.cs
index 92796ae4..c2333632 100644
--- a/DXMainClient/DXGUI/Multiplayer/GameLobby/GameLobbyBase.cs
+++ b/DXMainClient/DXGUI/Multiplayer/GameLobby/GameLobbyBase.cs
@@ -969,6 +969,7 @@ namespace DTAClient.DXGUI.Multiplayer.GameLobby
         {
             var playerExtraOptions = GetPlayerExtraOptions();

+            Dev.Assert(!playerExtraOptions.IsForceRandomTeams || !Map.IsCoop, "Co-ops should not have force no teams enabled.");
             for (int i = 0; i < ddPlayerSides.Length; i++)
                 EnablePlayerOptionDropDown(ddPlayerSides[i], i, !playerExtraOptions.IsForceRandomSides);

Snipaste_2025-05-16_20-14-32

16.05. 20:52:55.355    KABOOOOOOM!!! Info:
16.05. 20:52:55.355    Type: DTAClient.AssertFailedException
16.05. 20:52:55.356    Message: Assert failed. Co-ops should not have force no teams enabled.
16.05. 20:52:55.357    Source: clientdx
16.05. 20:52:55.357    TargetSite.Name: Assert
16.05. 20:52:55.359    Stacktrace:    at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
   at System.Environment.get_StackTrace()
   at DTAClient.Dev.Assert(Boolean condition, String message) in D:\SadPencil\Documents\GitHub\xna-cncnet-client\DXMainClient\Dev.cs:line 34
   at DTAClient.DXGUI.Multiplayer.GameLobby.GameLobbyBase.PlayerExtraOptions_OptionsChanged(Object sender, EventArgs e) in D:\SadPencil\Documents\GitHub\xna-cncnet-client\DXMainClient\DXGUI\Multiplayer\GameLobby\GameLobbyBase.cs:line 972
   at DTAClient.DXGUI.Multiplayer.PlayerExtraOptionsPanel.Options_Changed(Object sender, EventArgs e) in D:\SadPencil\Documents\GitHub\xna-cncnet-client\DXMainClient\DXGUI\Multiplayer\PlayerExtraOptionsPanel.cs:line 47
   at Rampastring.XNAUI.XNAControls.XNACheckBox.set_Checked(Boolean value)
   at Rampastring.XNAUI.XNAControls.XNACheckBox.OnLeftClick()
   at Rampastring.XNAUI.XNAControls.XNAControl.Update(GameTime gameTime)
   at Rampastring.XNAUI.XNAControls.XNACheckBox.Update(GameTime gameTime)
   at Rampastring.XNAUI.XNAControls.XNAControl.Update(GameTime gameTime)
   at Rampastring.XNAUI.XNAControls.XNAPanel.Update(GameTime gameTime)
   at Rampastring.XNAUI.XNAControls.XNAControl.Update(GameTime gameTime)
   at Rampastring.XNAUI.XNAControls.XNAPanel.Update(GameTime gameTime)
   at Rampastring.XNAUI.XNAControls.XNAControl.Update(GameTime gameTime)
   at Rampastring.XNAUI.XNAControls.XNAPanel.Update(GameTime gameTime)
   at ClientGUI.DarkeningPanel.Update(GameTime gameTime) in D:\SadPencil\Documents\GitHub\xna-cncnet-client\ClientGUI\DarkeningPanel.cs:line 93
   at Rampastring.XNAUI.WindowManager.Update(GameTime gameTime)
   at Microsoft.Xna.Framework.Game.SortingFilteringCollection`1.ForEachFilteredItem[TUserData](Action`2 action, TUserData userData)
   at Microsoft.Xna.Framework.Game.DoUpdate(GameTime gameTime)
   at Microsoft.Xna.Framework.Game.Tick()
   at MonoGame.Framework.WinFormsGameWindow.TickOnIdle(Object sender, EventArgs e)
   at System.Windows.Forms.Application.ThreadContext.System.Windows.Forms.UnsafeNativeMethods.IMsoComponent.FDoIdle(Int32 grfidlef)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at MonoGame.Framework.WinFormsGameWindow.RunLoop()
   at Microsoft.Xna.Framework.Game.Run(GameRunBehavior runBehavior)
   at DTAClient.Startup.Execute() in D:\SadPencil\Documents\GitHub\xna-cncnet-client\DXMainClient\Startup.cs:line 177
   at DTAClient.PreStartup.Initialize(StartupParams parameters) in D:\SadPencil\Documents\GitHub\xna-cncnet-client\DXMainClient\PreStartup.cs:line 212
   at DTAClient.Program.Main(String[] args) in D:\SadPencil\Documents\GitHub\xna-cncnet-client\DXMainClient\Program.cs:line 166

@SadPencil SadPencil changed the title Throw exceptions on assert failure on dev build Throw assert failure exceptions on development build May 16, 2025
@SadPencil SadPencil requested a review from Copilot May 16, 2025 12:20
Copilot

This comment was marked as outdated.

Copy link

github-actions bot commented May 16, 2025

Nightly build for this pull request:

  • artifacts.zip
    This comment is automatic and is meant to allow guests to get latest automatic builds without registering. It is updated on every successful build.

@SadPencil SadPencil requested a review from Copilot May 16, 2025 12:55
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This pull request changes the assert mechanism in development builds by replacing Debug.Assert with a custom Dev.Assert that actively throws exceptions, thereby preventing issues like the loading screen hanging. It also updates error logging and error display behaviors to better handle exceptions, and introduces a custom AssertFailedException.

Reviewed Changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
DXMainClient/DXGUI/Multiplayer/GameLobby/GameLobbyBase.cs Replace Debug.Assert with Dev.Assert in player option checks.
DXMainClient/PreStartup.cs Adds Dev.Initialize(), updates LogException and HandleException signature and logic.
DXMainClient/Online/FileHashCalculator.cs Replaces Debug.Assert with Dev.Assert in file existence and path checking.
DXMainClient/Online/Channel.cs Updates assert comment and uses Dev.Assert for user collection checks.
DXMainClient/Domain/Multiplayer/MapLoader.cs Replaces Debug.Assert with Dev.Assert when verifying map path conditions.
DXMainClient/Domain/Multiplayer/Map.cs Replaces Debug.Assert with Dev.Assert in map path and waypoint validations.
DXMainClient/Dev.cs Introduces Dev helper methods for asserting and initialization.
DXMainClient/DXGUI/Multiplayer/GameInformationPanel.cs Uses Dev.Assert to validate texture disposal states.
DXMainClient/DXGUI/Multiplayer/CnCNet/CnCNetLobby.cs Replaces Debug.Assert with Dev.Assert for user collection type validation.
DXMainClient/DXGUI/Generic/MainMenu.cs Updates error display behavior by redefining DisplayErrorAction with a delayed error box.
DXMainClient/DXGUI/GameClass.cs Removes redundant DisplayErrorAction assignment in favor of a centralized error action.
DXMainClient/AssertFailedException.cs Adds a custom exception for failed assertions.

Comment on lines +1 to +12
#nullable enable
using System;

namespace DTAClient
{
public class AssertFailedException : Exception
{
public AssertFailedException(string message) : base(message)
{
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why you placed exception not in ClientCore?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the Dev class is not in ClientCore

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same question about "why not ClientCore"

Copy link
Member Author

@SadPencil SadPencil May 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. The Dev.Initialize() method is called after the DXMainClient sets up it self. Also, DEVELOPMENT_BUILD is only available in DXMainClient.
        public static void Initialize()
        {
            IsDev = IsDev || ClientConfiguration.Instance.ModMode;

#if DEVELOPMENT_BUILD
            IsDev = IsDev || ClientConfiguration.Instance.ShowDevelopmentBuildWarnings;
#endif
        }
  1. The whole exception handling logic is processed in DXMainClient
MainClientConstants.DisplayErrorAction

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants