mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
Adds GameController options for games using RobustToolbox as a library. (#1711)
This commit is contained in:
committed by
GitHub
parent
4ce6629ace
commit
8bd1e72e9f
@@ -5,10 +5,15 @@ namespace Robust.Client
|
||||
public static void Start(string[] args)
|
||||
{
|
||||
#if FULL_RELEASE
|
||||
throw new System.InvalidOperationException("ContentStart is not available on a full release.");
|
||||
throw new System.InvalidOperationException("ContentStart.Start is not available on a full release.");
|
||||
#else
|
||||
GameController.Start(args, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void StartLibrary(string[] args, GameControllerOptions options)
|
||||
{
|
||||
GameController.Start(args, true, null, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,18 +61,18 @@ namespace Robust.Client
|
||||
[Dependency] private readonly IFontManagerInternal _fontManager = default!;
|
||||
[Dependency] private readonly IModLoaderInternal _modLoader = default!;
|
||||
[Dependency] private readonly IScriptClient _scriptClient = default!;
|
||||
[Dependency] private readonly IComponentManager _componentManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IRobustMappedStringSerializer _stringSerializer = default!;
|
||||
[Dependency] private readonly IAuthManager _authManager = default!;
|
||||
[Dependency] private readonly IMidiManager _midiManager = default!;
|
||||
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
||||
|
||||
private CommandLineArgs? _commandLineArgs;
|
||||
private bool _disableAssemblyLoadContext;
|
||||
|
||||
// Arguments for loader-load. Not used otherwise.
|
||||
private IMainArgs? _loaderArgs;
|
||||
|
||||
public bool ContentStart { get; set; } = false;
|
||||
public GameControllerOptions Options { get; private set; } = new();
|
||||
public InitialLaunchState LaunchState { get; private set; } = default!;
|
||||
|
||||
public bool LoadConfigAndUserData { get; set; } = true;
|
||||
@@ -89,10 +89,10 @@ namespace Robust.Client
|
||||
|
||||
// Disable load context usage on content start.
|
||||
// This prevents Content.Client being loaded twice and things like csi blowing up because of it.
|
||||
_modLoader.SetUseLoadContext(!_disableAssemblyLoadContext);
|
||||
_modLoader.SetEnableSandboxing(true);
|
||||
_modLoader.SetUseLoadContext(!ContentStart);
|
||||
_modLoader.SetEnableSandboxing(Options.Sandboxing);
|
||||
|
||||
if (!_modLoader.TryLoadModulesFrom(new ResourcePath("/Assemblies/"), "Content."))
|
||||
if (!_modLoader.TryLoadModulesFrom(new ResourcePath("/Assemblies/"), Options.ContentModulePrefix))
|
||||
{
|
||||
Logger.Fatal("Errors while loading content assemblies.");
|
||||
return false;
|
||||
@@ -118,7 +118,7 @@ namespace Robust.Client
|
||||
_inputManager.Initialize();
|
||||
_console.Initialize();
|
||||
_prototypeManager.Initialize();
|
||||
_prototypeManager.LoadDirectory(new ResourcePath(@"/Prototypes/"));
|
||||
_prototypeManager.LoadDirectory(Options.PrototypeDirectory);
|
||||
_prototypeManager.Resync();
|
||||
_mapManager.Initialize();
|
||||
_entityManager.Initialize();
|
||||
@@ -143,7 +143,8 @@ namespace Robust.Client
|
||||
|
||||
_clyde.Ready();
|
||||
|
||||
if ((_commandLineArgs?.Connect == true || _commandLineArgs?.Launcher == true)
|
||||
if (!Options.DisableCommandLineConnect &&
|
||||
(_commandLineArgs?.Connect == true || _commandLineArgs?.Launcher == true)
|
||||
&& LaunchState.ConnectEndpoint != null)
|
||||
{
|
||||
_client.ConnectToServer(LaunchState.ConnectEndpoint);
|
||||
@@ -172,7 +173,7 @@ namespace Robust.Client
|
||||
|
||||
if (LoadConfigAndUserData)
|
||||
{
|
||||
var configFile = Path.Combine(userDataDir, "client_config.toml");
|
||||
var configFile = Path.Combine(userDataDir, Options.ConfigFileName);
|
||||
if (File.Exists(configFile))
|
||||
{
|
||||
// Load config from user data if available.
|
||||
@@ -196,7 +197,12 @@ namespace Robust.Client
|
||||
|
||||
_resourceCache.Initialize(LoadConfigAndUserData ? userDataDir : null);
|
||||
|
||||
ProgramShared.DoMounts(_resourceCache, _commandLineArgs?.MountOptions, "Content.Client", _loaderArgs != null);
|
||||
var mountOptions = _commandLineArgs != null
|
||||
? MountOptions.Merge(_commandLineArgs.MountOptions, Options.MountOptions) : Options.MountOptions;
|
||||
|
||||
ProgramShared.DoMounts(_resourceCache, mountOptions, Options.ContentBuildDirectory,
|
||||
_loaderArgs != null && !Options.ResourceMountDisabled, ContentStart);
|
||||
|
||||
if (_loaderArgs != null)
|
||||
{
|
||||
_stringSerializer.EnableCaching = false;
|
||||
@@ -217,7 +223,7 @@ namespace Robust.Client
|
||||
return false;
|
||||
}
|
||||
|
||||
_clyde.SetWindowTitle("Space Station 14");
|
||||
_clyde.SetWindowTitle(Options.DefaultWindowTitle);
|
||||
|
||||
_fontManager.SetFontDpi((uint) _configurationManager.GetCVar(CVars.DisplayFontDpi));
|
||||
return true;
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Robust.Client
|
||||
Start(args);
|
||||
}
|
||||
|
||||
public static void Start(string[] args, bool contentStart = false, IMainArgs? loaderArgs=null)
|
||||
public static void Start(string[] args, bool contentStart = false, IMainArgs? loaderArgs=null, GameControllerOptions? options = null)
|
||||
{
|
||||
if (_hasStarted)
|
||||
{
|
||||
@@ -30,11 +30,11 @@ namespace Robust.Client
|
||||
|
||||
if (CommandLineArgs.TryParse(args, out var parsed))
|
||||
{
|
||||
ParsedMain(parsed, contentStart, loaderArgs);
|
||||
ParsedMain(parsed, contentStart, loaderArgs, options);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ParsedMain(CommandLineArgs args, bool contentStart, IMainArgs? loaderArgs)
|
||||
private static void ParsedMain(CommandLineArgs args, bool contentStart, IMainArgs? loaderArgs, GameControllerOptions? options)
|
||||
{
|
||||
IoCManager.InitThread();
|
||||
|
||||
@@ -45,11 +45,13 @@ namespace Robust.Client
|
||||
var gc = (GameController) IoCManager.Resolve<IGameController>();
|
||||
gc.SetCommandLineArgs(args);
|
||||
gc._loaderArgs = loaderArgs;
|
||||
if(options != null)
|
||||
gc.Options = options;
|
||||
|
||||
// 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._disableAssemblyLoadContext = contentStart;
|
||||
gc.ContentStart = contentStart;
|
||||
if (!gc.Startup())
|
||||
{
|
||||
Logger.Fatal("Failed to start game controller!");
|
||||
|
||||
60
Robust.Client/GameControllerOptions.cs
Normal file
60
Robust.Client/GameControllerOptions.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Client
|
||||
{
|
||||
public class GameControllerOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether content sandboxing will be enabled & enforced.
|
||||
/// </summary>
|
||||
public bool Sandboxing { get; init; } = true;
|
||||
|
||||
// TODO: Expose mounting methods to games using Robust as a library.
|
||||
/// <summary>
|
||||
/// Lists of mount options to mount.
|
||||
/// </summary>
|
||||
public MountOptions MountOptions { get; init; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Name the userdata directory will have.
|
||||
/// </summary>
|
||||
public string UserDataDirectoryName { get; init; } = "Space Station 14";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the configuration file in the user data directory.
|
||||
/// </summary>
|
||||
public string ConfigFileName { get; init; } = "client_config.toml";
|
||||
|
||||
// TODO: Define engine branding from json file in resources.
|
||||
/// <summary>
|
||||
/// Default window title.
|
||||
/// </summary>
|
||||
public string DefaultWindowTitle { get; init; } = "Space Station 14";
|
||||
|
||||
/// <summary>
|
||||
/// Assemblies with this prefix will be loaded.
|
||||
/// </summary>
|
||||
public string ContentModulePrefix { get; init; } = "Content.";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the content build directory, for game pack mounting purposes.
|
||||
/// </summary>
|
||||
public string ContentBuildDirectory { get; init; } = "Content.Client";
|
||||
|
||||
/// <summary>
|
||||
/// Directory to load all prototypes from.
|
||||
/// </summary>
|
||||
public ResourcePath PrototypeDirectory { get; init; } = new(@"/Prototypes/");
|
||||
|
||||
/// <summary>
|
||||
/// Whether to disable mounting the "Resources/" folder on FULL_RELEASE.
|
||||
/// </summary>
|
||||
public bool ResourceMountDisabled { get; init; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to disable command line args server auto-connecting.
|
||||
/// </summary>
|
||||
public bool DisableCommandLineConnect { get; init; } = false;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ namespace Robust.Client
|
||||
{
|
||||
internal interface IGameControllerInternal : IGameController
|
||||
{
|
||||
GameControllerOptions Options { get; }
|
||||
bool ContentStart { get; set; }
|
||||
void SetCommandLineArgs(CommandLineArgs args);
|
||||
bool LoadConfigAndUserData { get; set; }
|
||||
bool Startup(Func<ILogHandler>? logHandlerFactory = null);
|
||||
@@ -18,4 +20,4 @@ namespace Robust.Client
|
||||
void MouseWheel(MouseWheelEventArgs mouseWheelEventArgs);
|
||||
void OverrideMainLoop(IGameLoop gameLoop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Robust.Client.Utility
|
||||
{
|
||||
@@ -29,7 +30,7 @@ namespace Robust.Client.Utility
|
||||
appDataDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||
#endif
|
||||
|
||||
return Path.Combine(appDataDir, "Space Station 14", "data");
|
||||
return Path.Combine(appDataDir, IoCManager.Resolve<IGameControllerInternal>().Options.UserDataDirectoryName, "data");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -254,9 +254,12 @@ namespace Robust.Server
|
||||
// Set up the VFS
|
||||
_resources.Initialize(dataDir);
|
||||
|
||||
ProgramShared.DoMounts(_resources, _commandLineArgs?.MountOptions, "Content.Server");
|
||||
ProgramShared.DoMounts(_resources, _commandLineArgs?.MountOptions, "Content.Server", contentStart:ContentStart);
|
||||
|
||||
_modLoader.SetUseLoadContext(!DisableLoadContext);
|
||||
// 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.
|
||||
_modLoader.SetUseLoadContext(!ContentStart);
|
||||
_modLoader.SetEnableSandboxing(false);
|
||||
|
||||
if (!_modLoader.TryLoadModulesFrom(new ResourcePath("/Assemblies/"), "Content."))
|
||||
@@ -431,7 +434,7 @@ namespace Robust.Server
|
||||
_shutdownEvent.Set();
|
||||
}
|
||||
|
||||
public bool DisableLoadContext { private get; set; }
|
||||
public bool ContentStart { get; set; }
|
||||
public bool LoadConfigAndUserData { private get; set; } = true;
|
||||
|
||||
public void OverrideMainLoop(IGameLoop gameLoop)
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace Robust.Server
|
||||
|
||||
internal interface IBaseServerInternal : IBaseServer
|
||||
{
|
||||
bool DisableLoadContext { set; }
|
||||
bool ContentStart { set; }
|
||||
bool LoadConfigAndUserData { set; }
|
||||
|
||||
void OverrideMainLoop(IGameLoop gameLoop);
|
||||
|
||||
@@ -62,10 +62,7 @@ namespace Robust.Server
|
||||
|
||||
var server = IoCManager.Resolve<IBaseServerInternal>();
|
||||
|
||||
// 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.
|
||||
server.DisableLoadContext = contentStart;
|
||||
server.ContentStart = contentStart;
|
||||
server.SetCommandLineArgs(args);
|
||||
|
||||
Logger.Info("Server -> Starting");
|
||||
|
||||
@@ -2,9 +2,32 @@
|
||||
|
||||
namespace Robust.Shared
|
||||
{
|
||||
internal sealed class MountOptions
|
||||
public sealed class MountOptions
|
||||
{
|
||||
public List<string> ZipMounts = new();
|
||||
public List<string> DirMounts = new();
|
||||
|
||||
public MountOptions()
|
||||
{ }
|
||||
|
||||
public MountOptions(List<string> zipMounts, List<string> dirMounts)
|
||||
{
|
||||
ZipMounts = zipMounts;
|
||||
DirMounts = dirMounts;
|
||||
}
|
||||
|
||||
public static MountOptions Merge(MountOptions a, MountOptions b)
|
||||
{
|
||||
var zipMounts = new List<string>();
|
||||
var dirMounts = new List<string>();
|
||||
|
||||
zipMounts.AddRange(a.ZipMounts);
|
||||
zipMounts.AddRange(b.ZipMounts);
|
||||
|
||||
dirMounts.AddRange(a.DirMounts);
|
||||
dirMounts.AddRange(b.DirMounts);
|
||||
|
||||
return new MountOptions(zipMounts, dirMounts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,28 +7,19 @@ namespace Robust.Shared
|
||||
internal static class ProgramShared
|
||||
{
|
||||
#if !FULL_RELEASE
|
||||
private static string FindContentRootDir()
|
||||
private static string FindContentRootDir(bool contentStart)
|
||||
{
|
||||
var contentPath = PathHelpers.ExecutableRelativeFile("Content.Shared.dll");
|
||||
|
||||
// If Content.Shared.dll is next to us,
|
||||
// that means we've been executed from one of content's bin directories.
|
||||
if (File.Exists(contentPath))
|
||||
{
|
||||
return "../../";
|
||||
}
|
||||
|
||||
return "../../../";
|
||||
return contentStart ? "../../" : "../../../";
|
||||
}
|
||||
#endif
|
||||
|
||||
internal static void DoMounts(IResourceManagerInternal res, MountOptions? options, string contentBuildDir, bool loader=false)
|
||||
internal static void DoMounts(IResourceManagerInternal res, MountOptions? options, string contentBuildDir, bool loader=false, bool contentStart=false)
|
||||
{
|
||||
#if FULL_RELEASE
|
||||
if (!loader)
|
||||
res.MountContentDirectory(@"Resources/");
|
||||
#else
|
||||
var contentRootDir = FindContentRootDir();
|
||||
var contentRootDir = FindContentRootDir(contentStart);
|
||||
res.MountContentDirectory($@"{contentRootDir}RobustToolbox/Resources/");
|
||||
res.MountContentDirectory($@"{contentRootDir}bin/{contentBuildDir}/", new ResourcePath("/Assemblies/"));
|
||||
res.MountContentDirectory($@"{contentRootDir}Resources/");
|
||||
|
||||
@@ -9,6 +9,8 @@ namespace Robust.UnitTesting
|
||||
internal sealed class GameControllerDummy : IGameControllerInternal
|
||||
{
|
||||
public InitialLaunchState LaunchState { get; } = new(false, null, null, null);
|
||||
public GameControllerOptions Options { get; } = new();
|
||||
public bool ContentStart { get; set; }
|
||||
|
||||
public void Shutdown(string? reason = null)
|
||||
{
|
||||
|
||||
@@ -356,6 +356,7 @@ namespace Robust.UnitTesting
|
||||
cfg.OverrideConVars(new []{("log.runtimelog", "false"), (CVars.SysWinTickPeriod.Name, "-1")});
|
||||
|
||||
var failureLevel = _options == null ? LogLevel.Error : _options.FailureLogLevel;
|
||||
server.ContentStart = _options?.ContentStart ?? false;
|
||||
if (server.Start(() => new TestLogHandler("SERVER", failureLevel)))
|
||||
{
|
||||
throw new Exception("Server failed to start.");
|
||||
@@ -449,6 +450,7 @@ namespace Robust.UnitTesting
|
||||
cfg.OverrideConVars(new []{(CVars.NetPredictLagBias.Name, "0")});
|
||||
|
||||
var failureLevel = _options == null ? LogLevel.Error : _options.FailureLogLevel;
|
||||
client.ContentStart = _options?.ContentStart ?? false;
|
||||
client.Startup(() => new TestLogHandler("CLIENT", failureLevel));
|
||||
|
||||
var gameLoop = new IntegrationGameLoop(DependencyCollection.Resolve<IGameTiming>(),
|
||||
@@ -566,6 +568,7 @@ namespace Robust.UnitTesting
|
||||
public Assembly[]? ContentAssemblies { get; set; }
|
||||
public string? ExtraPrototypes { get; set; }
|
||||
public LogLevel? FailureLogLevel { get; set; } = LogLevel.Error;
|
||||
public bool ContentStart { get; set; } = false;
|
||||
|
||||
public Dictionary<string, string> CVarOverrides { get; } = new();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user