Skip to content

Commit e495159

Browse files
Add a basic loading screen! (space-wizards#6003)
* Added basic loading screen * Make it look better! * I forgor xD * Fix test fails * Add comment * Removed unused import * Only write to file if the number of sections changed * Servers can now have their own settings * Minor optionzation and rare colors * Remove some of the cvars * debug only loading messages * Added a few more steps * Only one section at a time * nullable section name * Lock out functions if finished * Get rid of saving the ccvar * Cleanup * Forgot! * A few tweaks * Disable vsync * remove colors * remove outdated vsync functions * Silly me xD * What I get for trying to be clever... ;( * Better seconds display * Simplify drawing logic + it looks better * Type does not need to be partial * Make interface to expose to content * Use correct define to gate showing debug info Should be TOOLS instead of DEBUG * Use appropriate exception type in BeginLoadingSection * Fix exception when closing window during loading screen Would try to stop the main loop before it exists. * Rename CVars, put debug info behind CVar instead of conditional compilation. * Add to RELEASE-NOTES.md * Add UI scaling support * Make ILoadingScreenManager fully internal Didn't realize content can't touch it as it'd break the total amount of sections * Don't re-enable vsync manually, GameController does it at the end of init * Add command to show top load time usage. * Improve verbosity of debug time tracking More steps and some steps named better --------- Co-authored-by: PJB3005 <[email protected]>
1 parent f3a3f56 commit e495159

File tree

10 files changed

+440
-62
lines changed

10 files changed

+440
-62
lines changed

RELEASE-NOTES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ END TEMPLATE-->
5050
* The engine can now load system fonts.
5151
* At the moment only available on Windows.
5252
* See `ISystemFontManager` for API.
53+
* The client now display a loading screen during startup.
5354

5455
### Bugfixes
5556

Robust.Client/ClientIoC.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ public static void RegisterIoC(GameController.DisplayMode mode, IDependencyColle
110110
deps.Register<IReloadManager, ReloadManager>();
111111
deps.Register<ILocalizationManager, ClientLocalizationManager>();
112112
deps.Register<ILocalizationManagerInternal, ClientLocalizationManager>();
113+
deps.Register<LoadingScreenManager>();
114+
deps.Register<ILoadingScreenManager, LoadingScreenManager>();
113115

114116
switch (mode)
115117
{

Robust.Client/GameController/GameController.Standalone.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ namespace Robust.Client
1515
internal partial class GameController : IPostInjectInit
1616
{
1717
private IGameLoop? _mainLoop;
18+
private bool _dontStart;
1819

1920
[Dependency] private readonly IClientGameTiming _gameTiming = default!;
2021
[Dependency] private readonly IDependencyCollection _dependencyCollection = default!;
@@ -162,8 +163,11 @@ private void ContinueStartupAndLoop(DisplayMode mode)
162163
return;
163164
}
164165

165-
DebugTools.AssertNotNull(_mainLoop);
166-
_mainLoop!.Run();
166+
if (!_dontStart)
167+
{
168+
DebugTools.AssertNotNull(_mainLoop);
169+
_mainLoop!.Run();
170+
}
167171

168172
CleanupGameThread();
169173
}

Robust.Client/GameController/GameController.cs

Lines changed: 81 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ internal sealed partial class GameController : IGameControllerInternal
9797
[Dependency] private readonly IReloadManager _reload = default!;
9898
[Dependency] private readonly ILocalizationManager _loc = default!;
9999
[Dependency] private readonly ISystemFontManagerInternal _systemFontManager = default!;
100+
[Dependency] private readonly LoadingScreenManager _loadscr = default!;
100101

101102
private IWebViewManagerHook? _webViewHook;
102103

@@ -133,28 +134,39 @@ public string SplashLogo()
133134
return Options.SplashLogo?.ToString() ?? _resourceManifest!.SplashLogo ?? "";
134135
}
135136

137+
public bool ShowLoadingBar()
138+
{
139+
return _resourceManifest!.ShowLoadingBar ?? _configurationManager.GetCVar(CVars.LoadingShowBar);
140+
}
141+
136142
internal bool StartupContinue(DisplayMode displayMode)
137143
{
138144
DebugTools.AssertNotNull(_resourceManifest);
139145

146+
_loadscr.Initialize(42);
147+
148+
_loadscr.BeginLoadingSection("Init graphics", dontRender: true);
140149
_clyde.InitializePostWindowing();
141-
_audio.InitializePostWindowing();
142150
_clyde.SetWindowTitle(GameTitle());
151+
_loadscr.EndLoadingSection();
143152

144-
_taskManager.Initialize();
145-
_parallelMgr.Initialize();
153+
_loadscr.LoadingStep(_audio.InitializePostWindowing, "Init audio");
154+
155+
_loadscr.LoadingStep(_taskManager.Initialize, _taskManager);
156+
_loadscr.LoadingStep(_parallelMgr.Initialize, _parallelMgr);
146157
_fontManager.SetFontDpi((uint)_configurationManager.GetCVar(CVars.DisplayFontDpi));
147-
_systemFontManager.Initialize();
158+
159+
_loadscr.LoadingStep(_systemFontManager.Initialize, "System fonts");
148160

149161
// Load optional Robust modules.
150-
LoadOptionalRobustModules(displayMode, _resourceManifest!);
162+
_loadscr.LoadingStep(() => LoadOptionalRobustModules(displayMode, _resourceManifest!), "Robust Modules");
151163

164+
_loadscr.BeginLoadingSection(_modLoader);
152165
// Disable load context usage on content start.
153166
// This prevents Content.Client being loaded twice and things like csi blowing up because of it.
154167
_modLoader.SetUseLoadContext(!ContentStart);
155168
var disableSandbox = Environment.GetEnvironmentVariable("ROBUST_DISABLE_SANDBOX") == "1";
156169
_modLoader.SetEnableSandboxing(!disableSandbox && Options.Sandboxing);
157-
158170
if (!LoadModules())
159171
return false;
160172

@@ -163,16 +175,23 @@ internal bool StartupContinue(DisplayMode displayMode)
163175
_configurationManager.LoadCVarsFromAssembly(loadedModule);
164176
}
165177

166-
_serializationManager.Initialize();
167-
_loc.Initialize();
178+
_loadscr.EndLoadingSection();
179+
180+
_loadscr.LoadingStep(_serializationManager.Initialize, _serializationManager);
181+
_loadscr.LoadingStep(_loc.Initialize, _loc);
168182

169183
// Call Init in game assemblies.
170-
_modLoader.BroadcastRunLevel(ModRunLevel.PreInit);
184+
_loadscr.LoadingStep(() => _modLoader.BroadcastRunLevel(ModRunLevel.PreInit), "Content PreInit");
171185

172-
// Finish initialization of WebView if loaded.
173-
_webViewHook?.Initialize();
186+
_loadscr.LoadingStep(() =>
187+
{
188+
// Finish initialization of WebView if loaded.
189+
if (_webViewHook != null)
190+
_loadscr.LoadingStep(_webViewHook.Initialize, _webViewHook);
191+
},
192+
"WebView init");
174193

175-
_modLoader.BroadcastRunLevel(ModRunLevel.Init);
194+
_loadscr.LoadingStep(() => _modLoader.BroadcastRunLevel(ModRunLevel.Init), "Content Init");
176195

177196
// Start bad file extensions check after content init,
178197
// in case content screws with the VFS.
@@ -181,42 +200,51 @@ internal bool StartupContinue(DisplayMode displayMode)
181200
_configurationManager,
182201
_logManager.GetSawmill("res"));
183202

184-
_resourceCache.PreloadTextures();
185-
_networkManager.Initialize(false);
186-
_configurationManager.SetupNetworking();
187-
_serializer.Initialize();
188-
_inputManager.Initialize();
189-
_console.Initialize();
203+
_loadscr.LoadingStep(_resourceCache.PreloadTextures, "Texture preload");
204+
_loadscr.LoadingStep(() => { _networkManager.Initialize(false); }, _networkManager);
205+
_loadscr.LoadingStep(_configurationManager.SetupNetworking, _configurationManager);
206+
_loadscr.LoadingStep(_serializer.Initialize, _serializer);
207+
_loadscr.LoadingStep(_inputManager.Initialize, _inputManager);
208+
_loadscr.LoadingStep(_console.Initialize, _console);
190209

191210
// Make sure this is done before we try to load prototypes,
192211
// avoid any possibility of race conditions causing the check to not finish
193212
// before prototype load.
194-
ProgramShared.FinishCheckBadFileExtensions(checkBadExtensions);
213+
_loadscr.LoadingStep(
214+
() => ProgramShared.FinishCheckBadFileExtensions(checkBadExtensions),
215+
"Check bad file extensions");
195216

196-
_reload.Initialize();
197-
_reflectionManager.Initialize();
217+
_loadscr.LoadingStep(_reload.Initialize, _reload);
218+
_loadscr.LoadingStep(_reflectionManager.Initialize, _reflectionManager);
219+
_loadscr.BeginLoadingSection(_prototypeManager);
198220
_prototypeManager.Initialize();
199221
_prototypeManager.LoadDefaultPrototypes();
200-
_xamlProxyManager.Initialize();
201-
_xamlHotReloadManager.Initialize();
202-
_userInterfaceManager.Initialize();
203-
_eyeManager.Initialize();
204-
_entityManager.Initialize();
205-
_mapManager.Initialize();
206-
_gameStateManager.Initialize();
207-
_placementManager.Initialize();
208-
_viewVariablesManager.Initialize();
209-
_scriptClient.Initialize();
210-
_client.Initialize();
211-
_discord.Initialize();
212-
_tagManager.Initialize();
213-
_protoLoadMan.Initialize();
214-
_netResMan.Initialize();
215-
_replayLoader.Initialize();
216-
_replayPlayback.Initialize();
217-
_replayRecording.Initialize();
218-
_userInterfaceManager.PostInitialize();
219-
_modLoader.BroadcastRunLevel(ModRunLevel.PostInit);
222+
_loadscr.EndLoadingSection();
223+
_loadscr.LoadingStep(_xamlProxyManager.Initialize, _xamlProxyManager);
224+
_loadscr.LoadingStep(_xamlHotReloadManager.Initialize, _xamlHotReloadManager);
225+
_loadscr.LoadingStep(_userInterfaceManager.Initialize, "UI init");
226+
_loadscr.LoadingStep(_eyeManager.Initialize, _eyeManager);
227+
_loadscr.LoadingStep(_entityManager.Initialize, _entityManager);
228+
_loadscr.LoadingStep(_mapManager.Initialize, _mapManager);
229+
_loadscr.LoadingStep(_gameStateManager.Initialize, _gameStateManager);
230+
_loadscr.LoadingStep(_placementManager.Initialize, _placementManager);
231+
_loadscr.LoadingStep(_viewVariablesManager.Initialize, _viewVariablesManager);
232+
_loadscr.LoadingStep(_scriptClient.Initialize, _scriptClient);
233+
_loadscr.LoadingStep(_client.Initialize, _client);
234+
_loadscr.LoadingStep(_discord.Initialize, _discord);
235+
_loadscr.LoadingStep(_tagManager.Initialize, _tagManager);
236+
_loadscr.LoadingStep(_protoLoadMan.Initialize, _protoLoadMan);
237+
_loadscr.LoadingStep(_netResMan.Initialize, _netResMan);
238+
_loadscr.LoadingStep(_replayLoader.Initialize, _replayLoader);
239+
_loadscr.LoadingStep(_replayPlayback.Initialize, _replayPlayback);
240+
_loadscr.LoadingStep(_replayRecording.Initialize, _replayRecording);
241+
_loadscr.LoadingStep(_userInterfaceManager.PostInitialize, "UI postinit");
242+
243+
// Init stuff before this if at all possible.
244+
245+
_loadscr.LoadingStep(() => _modLoader.BroadcastRunLevel(ModRunLevel.PostInit), "Content PostInit");
246+
247+
_loadscr.Finish();
220248

221249
if (_commandLineArgs?.Username != null)
222250
{
@@ -423,7 +451,8 @@ internal bool StartupSystemSplash(
423451
_configurationManager.OverrideConVars(new[]
424452
{
425453
(CVars.DisplayWindowIconSet.Name, WindowIconSet()),
426-
(CVars.DisplaySplashLogo.Name, SplashLogo())
454+
(CVars.DisplaySplashLogo.Name, SplashLogo()),
455+
(CVars.LoadingShowBar.Name, ShowLoadingBar().ToString()),
427456
});
428457
}
429458

@@ -488,10 +517,18 @@ private void ReadInitialLaunchState()
488517

489518
public void Shutdown(string? reason = null)
490519
{
491-
DebugTools.AssertNotNull(_mainLoop);
520+
if (_mainLoop == null)
521+
{
522+
if (!_dontStart)
523+
{
524+
_logger.Info($"Shutdown called before client init completed: {reason ?? "No reason provided"}");
525+
_dontStart = true;
526+
}
527+
return;
528+
}
492529

493530
// Already got shut down I assume,
494-
if (!_mainLoop!.Running)
531+
if (!_mainLoop.Running)
495532
{
496533
return;
497534
}

Robust.Client/Graphics/Clyde/Clyde.HLR.cs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ public void Render()
7676
}
7777

7878
// Short path to render only the splash.
79-
if (_drawingSplash)
79+
if (_drawingLoadingScreen)
8080
{
81-
DrawSplash(_renderHandle);
81+
DrawLoadingScreen(_renderHandle);
8282
FlushRenderQueue();
8383
SwapAllBuffers();
8484
return;
@@ -430,18 +430,11 @@ private void DrawEntities(Viewport viewport, Box2Rotated worldBounds, Box2 world
430430
FlushRenderQueue();
431431
}
432432

433-
private void DrawSplash(IRenderHandle handle)
433+
private void DrawLoadingScreen(IRenderHandle handle)
434434
{
435-
// Clear screen to black for splash.
436435
ClearFramebuffer(Color.Black);
437436

438-
var splashTex = _cfg.GetCVar(CVars.DisplaySplashLogo);
439-
if (string.IsNullOrEmpty(splashTex))
440-
return;
441-
442-
var texture = _resourceCache.GetResource<TextureResource>(splashTex).Texture;
443-
444-
handle.DrawingHandleScreen.DrawTexture(texture, (ScreenSize - texture.Size) / 2);
437+
_loadingScreenManager.DrawLoadingScreen(handle, ScreenSize);
445438
}
446439

447440
private void RenderInRenderTarget(RenderTargetBase rt, Action a, Color? clearColor=default)

Robust.Client/Graphics/Clyde/Clyde.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ internal sealed partial class Clyde : IClydeInternal, IPostInjectInit, IEntityEv
5252
[Dependency] private readonly ClientEntityManager _entityManager = default!;
5353
[Dependency] private readonly IPrototypeManager _proto = default!;
5454
[Dependency] private readonly IReloadManager _reloads = default!;
55+
[Dependency] private readonly LoadingScreenManager _loadingScreenManager = default!;
5556

5657
private GLUniformBuffer<ProjViewMatrices> ProjViewUBO = default!;
5758
private GLUniformBuffer<UniformConstants> UniformConstantsUBO = default!;
@@ -68,7 +69,7 @@ internal sealed partial class Clyde : IClydeInternal, IPostInjectInit, IEntityEv
6869
// VAO is per-window and not stored (not necessary!)
6970
private GLBuffer WindowVBO = default!;
7071

71-
private bool _drawingSplash = true;
72+
private bool _drawingLoadingScreen = true;
7273

7374
private GLShaderProgram? _currentProgram;
7475

@@ -213,7 +214,7 @@ public void FrameProcess(FrameEventArgs eventArgs)
213214

214215
public void Ready()
215216
{
216-
_drawingSplash = false;
217+
_drawingLoadingScreen = false;
217218

218219
InitLighting();
219220
}

0 commit comments

Comments
 (0)