Add necessary infrastructure to allow content to launch game from itself.

This allows us to make Content.Client and Content.Server Exe projects so that they can be executed directly via your IDE. This'll help wtih not forgetting to do a full rebuild and such.
This commit is contained in:
Pieter-Jan Briers
2020-01-22 20:16:29 +01:00
parent 997f1c031f
commit d945247f31
13 changed files with 130 additions and 76 deletions

View File

@@ -1,17 +1,18 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
<PropertyGroup>
<RobustToolsPath>../Tools/</RobustToolsPath>
<RobustToolsPath>$(MSBuildThisFileDirectory)/../Tools/</RobustToolsPath>
</PropertyGroup>
<Target Name="CopySwnfd">
<Exec Condition="'$(Platform)' == 'x64'" Command="$(Python) $(RobustToolsPath)download_swnfd.py $(Platform) $(TargetOS) $(OutputPath)" CustomErrorRegularExpression="^Error" />
<Exec Condition="'$(Platform)' == 'x64'" Command="$(Python) $(RobustToolsPath)/download_swnfd.py $(Platform) $(TargetOS) $(OutputPath)" CustomErrorRegularExpression="^Error" />
<Warning Condition="'$(Platform)' != 'x64'" Text="Did not download swnfd because the platform is not set to x64. Only use this build for unit testing!" />
</Target>
<Target Name="CopyGlfw">
<Exec Condition="'$(Platform)' == 'x64'" Command="$(Python) $(RobustToolsPath)download_glfw.py $(Platform) $(TargetOS) $(OutputPath)" CustomErrorRegularExpression="^Error" />
<Exec Condition="'$(Platform)' == 'x64'" Command="$(Python) $(RobustToolsPath)/download_glfw.py $(Platform) $(TargetOS) $(OutputPath)" CustomErrorRegularExpression="^Error" />
<Warning Condition="'$(Platform)' != 'x64'" Text="Did not download GLFW because the platform is not set to x64. Only use this build for unit testing!" />
</Target>
<Target Name="CopyMiscDependencies">
<Exec Condition="'$(Platform)' == 'x64'" Command="$(Python) $(RobustToolsPath)download_misc_dependencies.py $(Platform) $(TargetOS) $(OutputPath)" CustomErrorRegularExpression="^Error" />
<Exec Condition="'$(Platform)' == 'x64'" Command="$(Python) $(RobustToolsPath)/download_misc_dependencies.py $(Platform) $(TargetOS) $(OutputPath)" CustomErrorRegularExpression="^Error" />
<Warning Condition="'$(Platform)' != 'x64'" Text="Did not download misc dependencies because the platform is not set to x64. Only use this build for unit testing!" />
</Target>
<Target Name="ClientAfterBuild" DependsOnTargets="CopyMiscDependencies;CopySwnfd;CopyGlfw" />
</Project>

View File

@@ -0,0 +1,14 @@
namespace Robust.Client
{
public static class ContentStart
{
public static void Start(string[] args)
{
#if FULL_RELEASE
throw new System.InvalidOperationException("ContentStart is not available on a full release.");
#else
GameController.Start(args);
#endif
}
}
}

View File

@@ -72,8 +72,6 @@ namespace Robust.Client
private CommandLineArgs _commandLineArgs;
public string ContentRootDir { get; set; } = "../../../";
public bool LoadConfigAndUserData { get; set; } = true;
public void SetCommandLineArgs(CommandLineArgs args)
@@ -117,10 +115,11 @@ namespace Robust.Client
#if FULL_RELEASE
_resourceCache.MountContentDirectory(@"Resources/");
#else
_resourceCache.MountContentDirectory($@"{ContentRootDir}RobustToolbox/Resources/");
_resourceCache.MountContentDirectory($@"{ContentRootDir}bin/Content.Client/",
var contentRootDir = ProgramShared.FindContentRootDir();
_resourceCache.MountContentDirectory($@"{contentRootDir}RobustToolbox/Resources/");
_resourceCache.MountContentDirectory($@"{contentRootDir}bin/Content.Client/",
new ResourcePath("/Assemblies/"));
_resourceCache.MountContentDirectory($@"{ContentRootDir}Resources/");
_resourceCache.MountContentDirectory($@"{contentRootDir}Resources/");
#endif
// Default to en-US.

View File

@@ -1,4 +1,6 @@
using Robust.Client.Interfaces;
using System;
using System.Threading;
using Robust.Client.Interfaces;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.IoC;
using Robust.Shared.Log;
@@ -14,8 +16,22 @@ namespace Robust.Client
[Dependency] private IGameTiming _gameTiming;
#pragma warning restore 649
private static bool _hasStarted;
public static void Main(string[] args)
{
Start(args);
}
public static void Start(string[] args)
{
if (_hasStarted)
{
throw new InvalidOperationException("Cannot start twice!");
}
_hasStarted = true;
if (CommandLineArgs.TryParse(args, out var parsed))
{
ParsedMain(parsed);

View File

@@ -14,7 +14,6 @@ namespace Robust.Client.Interfaces
bool LoadConfigAndUserData { get; set; }
bool Startup();
void MainLoop(GameController.DisplayMode mode);
string ContentRootDir { get; set; }
void KeyDown(KeyEventArgs keyEvent);
void KeyUp(KeyEventArgs keyEvent);
void TextEntered(TextEventArgs textEvent);

View File

@@ -52,5 +52,5 @@
</EmbeddedResource>
</ItemGroup>
<Import Project="..\MSBuild\Robust.Engine.targets" />
<Target Name="RobustAfterBuild" DependsOnTargets="CopyMiscDependencies;CopySwnfd;CopyGlfw" AfterTargets="Build" />
<Target Name="RobustAfterBuild" DependsOnTargets="ClientAfterBuild" AfterTargets="Build" />
</Project>

View File

@@ -31,6 +31,7 @@ using Robust.Shared.Interfaces.Resources;
using Robust.Shared.Exceptions;
using Robust.Shared.Localization;
using Robust.Server.Interfaces.Debugging;
using Robust.Shared;
namespace Robust.Server
{
@@ -40,38 +41,22 @@ namespace Robust.Server
internal sealed class BaseServer : IBaseServerInternal
{
#pragma warning disable 649
[Dependency]
private readonly IConfigurationManager _config;
[Dependency]
private readonly IComponentManager _components;
[Dependency]
private readonly IServerEntityManager _entities;
[Dependency]
private readonly ILogManager _log;
[Dependency]
private readonly IRobustSerializer _serializer;
[Dependency]
private readonly IGameTiming _time;
[Dependency]
private readonly IResourceManagerInternal _resources;
[Dependency]
private readonly IMapManager _mapManager;
[Dependency]
private readonly ITimerManager timerManager;
[Dependency]
private readonly IServerGameStateManager _stateManager;
[Dependency]
private readonly IServerNetManager _network;
[Dependency]
private readonly ISystemConsoleManager _systemConsole;
[Dependency]
private readonly ITaskManager _taskManager;
[Dependency]
private readonly ILocalizationManager _localizationManager;
[Dependency]
private IRuntimeLog runtimeLog;
[Dependency]
private readonly IModLoader _modLoader;
[Dependency] private readonly IConfigurationManager _config;
[Dependency] private readonly IComponentManager _components;
[Dependency] private readonly IServerEntityManager _entities;
[Dependency] private readonly ILogManager _log;
[Dependency] private readonly IRobustSerializer _serializer;
[Dependency] private readonly IGameTiming _time;
[Dependency] private readonly IResourceManagerInternal _resources;
[Dependency] private readonly IMapManager _mapManager;
[Dependency] private readonly ITimerManager timerManager;
[Dependency] private readonly IServerGameStateManager _stateManager;
[Dependency] private readonly IServerNetManager _network;
[Dependency] private readonly ISystemConsoleManager _systemConsole;
[Dependency] private readonly ITaskManager _taskManager;
[Dependency] private readonly ILocalizationManager _localizationManager;
[Dependency] private IRuntimeLog runtimeLog;
[Dependency] private readonly IModLoader _modLoader;
#pragma warning restore 649
private CommandLineArgs _commandLineArgs;
@@ -82,8 +67,6 @@ namespace Robust.Server
private int _lastReceivedBytes;
private int _lastSentBytes;
public string ContentRootDir { get; set; } = "../../../";
/// <inheritdoc />
public int MaxPlayers => _config.GetCVar<int>("game.maxplayers");
@@ -155,7 +138,8 @@ namespace Robust.Server
var logPath = _config.GetCVar<string>("log.path");
var logFormat = _config.GetCVar<string>("log.format");
var logFilename = logFormat.Replace("%(date)s", DateTime.Now.ToString("yyyyMMdd")).Replace("%(time)s", DateTime.Now.ToString("hhmmss"));
var logFilename = logFormat.Replace("%(date)s", DateTime.Now.ToString("yyyyMMdd"))
.Replace("%(time)s", DateTime.Now.ToString("hhmmss"));
var fullPath = Path.Combine(logPath, logFilename);
if (!Path.IsPathRooted(fullPath))
@@ -181,7 +165,9 @@ namespace Robust.Server
catch (Exception e)
{
var port = netMan.Port;
Logger.Fatal("Unable to setup networking manager. Check port {0} is not already in use and that all binding addresses are correct!\n{1}", port, e);
Logger.Fatal(
"Unable to setup networking manager. Check port {0} is not already in use and that all binding addresses are correct!\n{1}",
port, e);
return true;
}
@@ -195,22 +181,16 @@ namespace Robust.Server
#else
// Load from the resources dir in the repo root instead.
// It's a debug build so this is fine.
_resources.MountContentDirectory($@"{ContentRootDir}RobustToolbox/Resources/");
_resources.MountContentDirectory($@"{ContentRootDir}bin/Content.Server/", new ResourcePath("/Assemblies/"));
_resources.MountContentDirectory($@"{ContentRootDir}Resources/");
var contentRootDir = ProgramShared.FindContentRootDir();
_resources.MountContentDirectory($@"{contentRootDir}RobustToolbox/Resources/");
_resources.MountContentDirectory($@"{contentRootDir}bin/Content.Server/", new ResourcePath("/Assemblies/"));
_resources.MountContentDirectory($@"{contentRootDir}Resources/");
#endif
// Default to en-US.
// Perhaps in the future we could make a command line arg or something to change this default.
_localizationManager.LoadCulture(new CultureInfo("en-US"));
//mount the engine content pack
// _resources.MountContentPack(@"EngineContentPack.zip");
//mount the default game ContentPack defined in config
// _resources.MountDefaultContentPack();
//identical code in game controller for client
if (!_modLoader.TryLoadAssembly<GameShared>(_resources, $"Content.Shared"))
{
@@ -323,7 +303,7 @@ namespace Robust.Server
cfgMgr.RegisterCVar("game.maxplayers", 32, CVar.ARCHIVE);
cfgMgr.RegisterCVar("game.type", GameType.Game);
_time.TickRate = (byte)_config.GetCVar<int>("net.tickrate");
_time.TickRate = (byte) _config.GetCVar<int>("net.tickrate");
Logger.InfoS("srv", $"Name: {ServerName}");
Logger.InfoS("srv", $"TickRate: {_time.TickRate}({_time.TickPeriod.TotalMilliseconds:0.00}ms)");
@@ -341,7 +321,8 @@ namespace Robust.Server
// Wrtie down exception log
var logPath = _config.GetCVar<string>("log.path");
var pathToWrite = Path.Combine(PathHelpers.ExecutableRelativeFile(logPath), "Runtime-" + DateTime.Now.ToString("yyyy-MM-dd-THH-mm-ss") + ".txt");
var pathToWrite = Path.Combine(PathHelpers.ExecutableRelativeFile(logPath),
"Runtime-" + DateTime.Now.ToString("yyyy-MM-dd-THH-mm-ss") + ".txt");
File.WriteAllText(pathToWrite, runtimeLog.Display(), EncodingHelpers.UTF8);
//TODO: This should prob shutdown all managers in a loop.
@@ -351,7 +332,8 @@ namespace Robust.Server
{
var stats = IoCManager.Resolve<IServerNetManager>().Statistics;
var bps = $"Send: {(stats.SentBytes - _lastSentBytes) >> 10:N0} KiB/s, Recv: {(stats.ReceivedBytes - _lastReceivedBytes) >> 10:N0} KiB/s";
var bps =
$"Send: {(stats.SentBytes - _lastSentBytes) >> 10:N0} KiB/s, Recv: {(stats.ReceivedBytes - _lastReceivedBytes) >> 10:N0} KiB/s";
_lastSentBytes = stats.SentBytes;
_lastReceivedBytes = stats.ReceivedBytes;

View File

@@ -0,0 +1,14 @@
namespace Robust.Server
{
public static class ContentStart
{
public static void Start(string[] args)
{
#if FULL_RELEASE
throw new System.InvalidOperationException("ContentStart is not available on a full release.");
#else
Program.Main(args);
#endif
}
}
}

View File

@@ -45,7 +45,6 @@ namespace Robust.Server.Interfaces
internal interface IBaseServerInternal : IBaseServer
{
void OverrideMainLoop(IGameLoop gameLoop);
string ContentRootDir { get; set; }
void SetCommandLineArgs(CommandLineArgs args);
}

View File

@@ -13,8 +13,22 @@ namespace Robust.Server
{
internal static class Program
{
private static bool _hasStarted;
internal static void Main(string[] args)
{
Start(args);
}
internal static void Start(string[] args)
{
if (_hasStarted)
{
throw new InvalidOperationException("Cannot start twice!");
}
_hasStarted = true;
if (CommandLineArgs.TryParse(args, out var parsed))
{
ParsedMain(parsed);

View File

@@ -8,7 +8,7 @@ namespace Robust.Shared.ContentPack
/// <summary>
/// Utility functions
/// </summary>
public static class PathHelpers
internal static class PathHelpers
{
/// <summary>
/// Get the full directory path that the executable is located in.
@@ -17,17 +17,12 @@ namespace Robust.Shared.ContentPack
{
// TODO: remove this shitty hack, either through making it less hardcoded into shared,
// or by making our file structure less spaghetti somehow.
// Godot always executes relative to the project.godot file you opened the engine/editor on.
// So this needs to return the directory relative to Robust.Client.dll,
// NOT the current working dir, when on the client.
var assembly = AppDomain.CurrentDomain.GetAssemblyByName("Robust.Client")
?? Assembly.GetEntryAssembly()
?? Assembly.GetExecutingAssembly();
var PathURI = new Uri(assembly.CodeBase);
var path = PathURI.LocalPath;
if (PathURI.Fragment != "")
var assembly = typeof(PathHelpers).Assembly;
var pathUri = new Uri(assembly.CodeBase);
var path = pathUri.LocalPath;
if (pathUri.Fragment != "")
{
path += PathURI.Fragment;
path += pathUri.Fragment;
}
return Path.GetDirectoryName(path);
}

View File

@@ -0,0 +1,24 @@
using System.IO;
using Robust.Shared.ContentPack;
namespace Robust.Shared
{
internal static class ProgramShared
{
#if !FULL_RELEASE
internal static string FindContentRootDir()
{
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 "../../../";
}
#endif
}
}

View File

@@ -296,8 +296,6 @@ namespace Robust.UnitTesting
IoCManager.Resolve<ModLoader>().SharedContentAssembly = _options.SharedContentAssembly;
}
server.ContentRootDir = "../../";
_options?.BeforeStart?.Invoke();
if (server.Start())
{
@@ -377,7 +375,6 @@ namespace Robust.UnitTesting
IoCManager.Resolve<ModLoader>().SharedContentAssembly = _options.SharedContentAssembly;
}
client.ContentRootDir = "../../";
client.LoadConfigAndUserData = false;
_options?.BeforeStart?.Invoke();
client.Startup();