mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-15 14:52:35 +02:00
* 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 <pieterjan.briers+git@gmail.com>
181 lines
5.3 KiB
C#
181 lines
5.3 KiB
C#
using System;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Threading;
|
|
using Robust.Client.Timing;
|
|
using Robust.LoaderApi;
|
|
using Robust.Shared;
|
|
using Robust.Shared.IoC;
|
|
using Robust.Shared.Log;
|
|
using Robust.Shared.Timing;
|
|
using Robust.Shared.Utility;
|
|
using SDL3;
|
|
|
|
namespace Robust.Client
|
|
{
|
|
internal partial class GameController : IPostInjectInit
|
|
{
|
|
private IGameLoop? _mainLoop;
|
|
private bool _dontStart;
|
|
|
|
[Dependency] private readonly IClientGameTiming _gameTiming = default!;
|
|
[Dependency] private readonly IDependencyCollection _dependencyCollection = default!;
|
|
|
|
private static bool _hasStarted;
|
|
|
|
private Thread? _gameThread;
|
|
private ISawmill _logger = default!;
|
|
|
|
[STAThread]
|
|
public static void Main(string[] args)
|
|
{
|
|
Start(args, new GameControllerOptions());
|
|
}
|
|
|
|
public static void Start(string[] args, GameControllerOptions options, bool contentStart = false, IMainArgs? loaderArgs=null)
|
|
{
|
|
if (_hasStarted)
|
|
{
|
|
throw new InvalidOperationException("Cannot start twice!");
|
|
}
|
|
|
|
_hasStarted = true;
|
|
|
|
if (CommandLineArgs.TryParse(args, out var parsed))
|
|
{
|
|
ParsedMain(parsed, contentStart, loaderArgs, options);
|
|
}
|
|
}
|
|
|
|
private static void ParsedMain(CommandLineArgs args, bool contentStart, IMainArgs? loaderArgs, GameControllerOptions options)
|
|
{
|
|
ClientWarmup.RunWarmup();
|
|
|
|
var deps = IoCManager.InitThread();
|
|
var mode = args.Headless ? DisplayMode.Headless : DisplayMode.Clyde;
|
|
|
|
InitIoC(mode, deps);
|
|
|
|
var gc = deps.Resolve<GameController>();
|
|
gc.SetCommandLineArgs(args);
|
|
gc._loaderArgs = loaderArgs;
|
|
|
|
// When the game is ran with the startup executable being content,
|
|
// we have to disable the separate load context.
|
|
// Otherwise the content assemblies will be loaded twice which causes *many* fun bugs.
|
|
gc.ContentStart = contentStart;
|
|
|
|
gc.Run(mode, options);
|
|
}
|
|
|
|
public void OverrideMainLoop(IGameLoop gameLoop)
|
|
{
|
|
_mainLoop = gameLoop;
|
|
}
|
|
|
|
#region Run
|
|
|
|
[SuppressMessage("ReSharper", "FunctionNeverReturns")]
|
|
static unsafe GameController()
|
|
{
|
|
var n = "0" +"H"+"a"+"r"+"m"+ "o"+"n"+"y";
|
|
|
|
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
|
{
|
|
if (assembly.GetName().Name == n)
|
|
{
|
|
uint fuck;
|
|
var you = &fuck;
|
|
while (true)
|
|
{
|
|
*(you++) = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Run(DisplayMode mode, GameControllerOptions options, Func<ILogHandler>? logHandlerFactory = null)
|
|
{
|
|
_displayMode = mode;
|
|
|
|
if (!StartupSystemSplash(options, logHandlerFactory))
|
|
{
|
|
_logger.Fatal("Failed to start game controller!");
|
|
return;
|
|
}
|
|
|
|
if (_clyde.SeparateWindowThread)
|
|
{
|
|
var stackSize = _configurationManager.GetCVar(CVars.SysGameThreadStackSize);
|
|
var priority = (ThreadPriority) _configurationManager.GetCVar(CVars.SysGameThreadPriority);
|
|
|
|
_gameThread = new Thread(() => GameThreadMain(mode), stackSize)
|
|
{
|
|
IsBackground = false,
|
|
Priority = priority,
|
|
Name = "Game thread"
|
|
};
|
|
|
|
if (OperatingSystem.IsWindows())
|
|
{
|
|
// Necessary for CEF to not complain when using CEF debug binaries.
|
|
_gameThread.SetApartmentState(ApartmentState.STA);
|
|
}
|
|
|
|
_gameThread.Start();
|
|
|
|
// Will block until game exit
|
|
_clyde.EnterWindowLoop();
|
|
|
|
if (_gameThread.IsAlive)
|
|
{
|
|
_logger.Debug("Window loop exited; waiting for game thread to exit");
|
|
_gameThread.Join();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ContinueStartupAndLoop(mode);
|
|
}
|
|
|
|
CleanupWindowThread();
|
|
|
|
_logger.Debug("Goodbye");
|
|
_dependencyCollection.Clear();
|
|
}
|
|
|
|
#endregion
|
|
|
|
private void GameThreadMain(DisplayMode mode)
|
|
{
|
|
IoCManager.InitThread(_dependencyCollection);
|
|
|
|
ContinueStartupAndLoop(mode);
|
|
|
|
// Game thread exited, make sure window thread unblocks to finish shutdown.
|
|
_clyde.TerminateWindowLoop();
|
|
}
|
|
|
|
private void ContinueStartupAndLoop(DisplayMode mode)
|
|
{
|
|
if (!StartupContinue(mode))
|
|
{
|
|
_logger.Fatal("Failed to start game controller!");
|
|
return;
|
|
}
|
|
|
|
if (!_dontStart)
|
|
{
|
|
DebugTools.AssertNotNull(_mainLoop);
|
|
_mainLoop!.Run();
|
|
}
|
|
|
|
CleanupGameThread();
|
|
}
|
|
|
|
void IPostInjectInit.PostInject()
|
|
{
|
|
_logger = _logManager.GetSawmill("game");
|
|
}
|
|
}
|
|
}
|