got it working on docker
fixed log closing exception
This commit is contained in:
17
Dockerfile
Normal file
17
Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
||||
FROM mcr.microsoft.com/windows/servercore:ltsc2022
|
||||
|
||||
USER ContainerAdministrator
|
||||
ADD https://aka.ms/highdpimfc2013x64enu vc_redist2013.exe
|
||||
ADD https://aka.ms/vs/16/release/vc_redist.x64.exe vc_redist.exe
|
||||
|
||||
RUN vc_redist2013.exe /passive /norestart
|
||||
RUN vc_redist.exe /passive /norestart
|
||||
RUN del vc_redist2013.exe && del vc_redist.exe
|
||||
|
||||
USER ContainerUser
|
||||
COPY . .
|
||||
ENV TORCH_GAME_PATH="c:\dedi"
|
||||
ENV TORCH_INSTANCE="c:\instance"
|
||||
ENV TORCH_SERVICE="true"
|
||||
ENTRYPOINT ["Torch.Server.exe"]
|
||||
CMD ["-noupdate"]
|
@@ -1,22 +0,0 @@
|
||||
pushd
|
||||
|
||||
$steamData = "C:/Steam/Data/"
|
||||
$steamCMDPath = "C:/Steam/steamcmd/"
|
||||
$steamCMDZip = "C:/Steam/steamcmd.zip"
|
||||
|
||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||
|
||||
if (!(Test-Path $steamData)) {
|
||||
mkdir "$steamData"
|
||||
}
|
||||
if (!(Test-Path $steamCMDPath)) {
|
||||
if (!(Test-Path $steamCMDZip)) {
|
||||
(New-Object System.Net.WebClient).DownloadFile("https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip", "$steamCMDZip");
|
||||
}
|
||||
[System.IO.Compression.ZipFile]::ExtractToDirectory($steamCMDZip, $steamCMDPath)
|
||||
}
|
||||
|
||||
cd "$steamData"
|
||||
& "$steamCMDPath/steamcmd.exe" "+login anonymous" "+force_install_dir $steamData" "+app_update 298740 validate" "+quit"
|
||||
|
||||
popd
|
@@ -1,52 +0,0 @@
|
||||
param([string] $ApiBase, [string]$tagName, [string]$authinfo, [string[]] $assetPaths)
|
||||
Add-Type -AssemblyName "System.Web"
|
||||
|
||||
$headers = @{
|
||||
Authorization = "Basic " + [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($authinfo))
|
||||
Accept = "application/vnd.github.v3+json"
|
||||
}
|
||||
try
|
||||
{
|
||||
Write-Output("Checking if release with tag " + $tagName + " already exists...")
|
||||
$release = Invoke-RestMethod -Uri ($ApiBase+"releases/tags/$tagName") -Method "GET" -Headers $headers
|
||||
Write-Output(" Using existing release " + $release.id + " at " + $release.html_url)
|
||||
} catch {
|
||||
Write-Output(" Doesn't exist")
|
||||
$rel_arg = @{
|
||||
tag_name=$tagName
|
||||
name="Generated $tagName"
|
||||
body=""
|
||||
draft=$TRUE
|
||||
prerelease=$tagName.Contains("alpha") -or $tagName.Contains("beta")
|
||||
}
|
||||
Write-Output("Creating new release " + $tagName + "...")
|
||||
$release = Invoke-RestMethod -Uri ($ApiBase+"releases") -Method "POST" -Headers $headers -Body (ConvertTo-Json($rel_arg))
|
||||
Write-Output(" Created new release " + $tagName + " at " + $release.html_url)
|
||||
}
|
||||
|
||||
$assetsApiBase = $release.assets_url
|
||||
Write-Output("Checking for existing assets...")
|
||||
$existingAssets = Invoke-RestMethod -Uri ($assetsApiBase) -Method "GET" -Headers $headers
|
||||
$assetLabels = ($assetPaths | ForEach-Object {[System.IO.Path]::GetFileName($_)})
|
||||
foreach ($asset in $existingAssets) {
|
||||
if ($assetLabels -contains $asset.name) {
|
||||
$uri = $asset.url
|
||||
Write-Output(" Deleting old asset " + $asset.name + " (id " + $asset.id + "); URI=" + $uri)
|
||||
$result = Invoke-RestMethod -Uri $uri -Method "DELETE" -Headers $headers
|
||||
}
|
||||
}
|
||||
Write-Output("Uploading assets...")
|
||||
$uploadUrl = $release.upload_url.Substring(0, $release.upload_url.LastIndexOf('{'))
|
||||
foreach ($asset in $assetPaths) {
|
||||
$assetName = [System.IO.Path]::GetFileName($asset)
|
||||
$assetType = [System.Web.MimeMapping]::GetMimeMapping($asset)
|
||||
$assetData = [System.IO.File]::ReadAllBytes($asset)
|
||||
$headerExtra = $headers + @{
|
||||
"Content-Type" = $assetType
|
||||
Name = $assetName
|
||||
}
|
||||
$uri = $uploadUrl + "?name=" + $assetName
|
||||
Write-Output(" Uploading " + $asset + " as " + $assetType + "; URI=" + $uri)
|
||||
$result = Invoke-RestMethod -Uri $uri -Method "POST" -Headers $headerExtra -Body $assetData
|
||||
Write-Output(" ID=" + $result.id + ", found at=" + $result.browser_download_url)
|
||||
}
|
77
Jenkinsfile
vendored
77
Jenkinsfile
vendored
@@ -1,77 +0,0 @@
|
||||
def packageAndArchive(buildMode, packageName) {
|
||||
zipFile = "bin\\${packageName}.zip"
|
||||
packageDir = "bin\\${packageName}\\"
|
||||
|
||||
bat "IF EXIST ${zipFile} DEL ${zipFile}"
|
||||
bat "IF EXIST ${packageDir} RMDIR /S /Q ${packageDir}"
|
||||
|
||||
bat "xcopy bin\\x64\\${buildMode} ${packageDir}"
|
||||
|
||||
bat "del ${packageDir}VRage.*"
|
||||
bat "del ${packageDir}Sandbox.*"
|
||||
bat "del ${packageDir}SpaceEngineers.*"
|
||||
|
||||
powershell "Add-Type -Assembly System.IO.Compression.FileSystem; [System.IO.Compression.ZipFile]::CreateFromDirectory(\"\$PWD\\${packageDir}\", \"\$PWD\\${zipFile}\")"
|
||||
archiveArtifacts artifacts: zipFile, caseSensitive: false, onlyIfSuccessful: true
|
||||
}
|
||||
|
||||
node('windows') {
|
||||
stage('Checkout') {
|
||||
checkout scm
|
||||
bat 'git pull https://github.com/TorchAPI/Torch/ master --tags'
|
||||
}
|
||||
|
||||
stage('Acquire SE') {
|
||||
bat 'powershell -File Jenkins/jenkins-grab-se.ps1'
|
||||
bat 'IF EXIST GameBinaries RMDIR GameBinaries'
|
||||
bat 'mklink /J GameBinaries "C:/Steam/Data/DedicatedServer64/"'
|
||||
bat 'dir GameBinaries'
|
||||
}
|
||||
|
||||
stage('Acquire NuGet Packages') {
|
||||
bat 'cd C:\\Program Files\\Jenkins'
|
||||
bat '"C:\\Program Files\\Jenkins\\nuget.exe" restore Torch.sln'
|
||||
}
|
||||
|
||||
stage('Build') {
|
||||
currentBuild.description = bat(returnStdout: true, script: '@powershell -File Versioning/version.ps1').trim()
|
||||
if (env.BRANCH_NAME == "master" || env.BRANCH_NAME == "Patron" || env.BRANCH_NAME == "publictest") {
|
||||
buildMode = "Release"
|
||||
} else {
|
||||
buildMode = "Release"
|
||||
}
|
||||
bat "IF EXIST \"bin\" rmdir /Q /S \"bin\""
|
||||
bat "IF EXIST \"bin-test\" rmdir /Q /S \"bin-test\""
|
||||
bat "\"${tool 'MSBuild'}msbuild\" Torch.sln /p:Configuration=${buildMode} /p:Platform=x64 /t:Clean"
|
||||
bat "\"${tool 'MSBuild'}msbuild\" Torch.sln /p:Configuration=${buildMode} /p:Platform=x64"
|
||||
}
|
||||
|
||||
stage('Archive') {
|
||||
archiveArtifacts artifacts: "bin/x64/${buildMode}/Torch*", caseSensitive: false, fingerprint: true, onlyIfSuccessful: true
|
||||
|
||||
packageAndArchive(buildMode, "torch-server")
|
||||
|
||||
/*packageAndArchive(buildMode, "torch-client", "Torch.Server*")*/
|
||||
}
|
||||
|
||||
/* Disabled because they fail builds more often than they detect actual problems
|
||||
stage('Test') {
|
||||
bat 'IF NOT EXIST reports MKDIR reports'
|
||||
bat "\"packages/xunit.runner.console.2.2.0/tools/xunit.console.exe\" \"bin-test/x64/${buildMode}/Torch.Tests.dll\" \"bin-test/x64/${buildMode}/Torch.Server.Tests.dll\" \"bin-test/x64/${buildMode}/Torch.Client.Tests.dll\" -parallel none -xml \"reports/Torch.Tests.xml\""
|
||||
|
||||
step([
|
||||
$class: 'XUnitBuilder',
|
||||
thresholdMode: 1,
|
||||
thresholds: [[$class: 'FailedThreshold', failureThreshold: '1']],
|
||||
tools: [[
|
||||
$class: 'XUnitDotNetTestType',
|
||||
deleteOutputFiles: true,
|
||||
failIfNotNew: true,
|
||||
pattern: 'reports/*.xml',
|
||||
skipNoTestFiles: false,
|
||||
stopProcessingIfError: true
|
||||
]]
|
||||
])
|
||||
}
|
||||
*/
|
||||
}
|
@@ -150,6 +150,11 @@ namespace Torch.API
|
||||
/// Path of the dedicated instance folder.
|
||||
/// </summary>
|
||||
string InstancePath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the dedicated instance.
|
||||
/// </summary>
|
||||
string InstanceName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Raised when the server's Init() method has completed.
|
||||
|
@@ -10,7 +10,9 @@ namespace Torch
|
||||
bool ForceUpdate { get; set; }
|
||||
bool GetPluginUpdates { get; set; }
|
||||
bool GetTorchUpdates { get; set; }
|
||||
[Obsolete("Use Torch.InstanceName instead")]
|
||||
string InstanceName { get; set; }
|
||||
[Obsolete("Use Torch.InstancePath instead")]
|
||||
string InstancePath { get; set; }
|
||||
bool NoGui { get; set; }
|
||||
bool NoUpdate { get; set; }
|
||||
|
@@ -5,7 +5,7 @@
|
||||
<Product>Torch</Product>
|
||||
<Copyright>Copyright © Torch API 2017</Copyright>
|
||||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
|
||||
<OutputPath>$(SolutionDir)\bin\$(Platform)\$(Configuration)\</OutputPath>
|
||||
<OutputPath>..\bin\$(Platform)\$(Configuration)\</OutputPath>
|
||||
<UseWpf>True</UseWpf>
|
||||
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@@ -22,40 +22,35 @@ namespace Torch.Server
|
||||
{
|
||||
public class Initializer
|
||||
{
|
||||
[Obsolete("It's hack. Do not use it!")]
|
||||
internal static Initializer Instance { get; private set; }
|
||||
|
||||
private static readonly Logger Log = LogManager.GetLogger(nameof(Initializer));
|
||||
private bool _init;
|
||||
private const string STEAMCMD_DIR = "steamcmd";
|
||||
private const string STEAMCMD_ZIP = "temp.zip";
|
||||
private static readonly string STEAMCMD_PATH = $"{STEAMCMD_DIR}\\steamcmd.exe";
|
||||
private static readonly string RUNSCRIPT_PATH = $"{STEAMCMD_DIR}\\runscript.txt";
|
||||
private static readonly string STEAMCMD_EXE = "steamcmd.exe";
|
||||
private static readonly string RUNSCRIPT_FILE = "runscript.txt";
|
||||
|
||||
private const string RUNSCRIPT = @"force_install_dir ../
|
||||
login anonymous
|
||||
app_update 298740
|
||||
quit";
|
||||
private TorchServer _server;
|
||||
private string _basePath;
|
||||
|
||||
internal Persistent<TorchConfig> ConfigPersistent { get; private set; }
|
||||
internal Persistent<TorchConfig> ConfigPersistent { get; }
|
||||
public TorchConfig Config => ConfigPersistent?.Data;
|
||||
public TorchServer Server => _server;
|
||||
|
||||
public Initializer(string basePath)
|
||||
public Initializer(string basePath, Persistent<TorchConfig> torchConfig)
|
||||
{
|
||||
_basePath = basePath;
|
||||
Instance = this;
|
||||
ConfigPersistent = torchConfig;
|
||||
}
|
||||
|
||||
public bool Initialize(string[] args)
|
||||
{
|
||||
if (_init)
|
||||
return false;
|
||||
|
||||
AppDomain.CurrentDomain.UnhandledException += HandleException;
|
||||
|
||||
#if DEBUG
|
||||
//enables logging debug messages when built in debug mode. Amazing.
|
||||
LogManager.Configuration.AddRule(LogLevel.Debug, LogLevel.Debug, "main");
|
||||
@@ -69,37 +64,6 @@ quit";
|
||||
if (!Enumerable.Contains(args, "-noupdate"))
|
||||
RunSteamCmd();
|
||||
|
||||
var basePath = new FileInfo(typeof(Program).Assembly.Location).Directory.ToString();
|
||||
var apiSource = Path.Combine(basePath, "DedicatedServer64", "steam_api64.dll");
|
||||
var apiTarget = Path.Combine(basePath, "steam_api64.dll");
|
||||
|
||||
if (!File.Exists(apiTarget))
|
||||
{
|
||||
File.Copy(apiSource, apiTarget);
|
||||
}
|
||||
else if (File.GetLastWriteTime(apiTarget) < File.GetLastWriteTime(apiSource))
|
||||
{
|
||||
File.Delete(apiTarget);
|
||||
File.Copy(apiSource, apiTarget);
|
||||
}
|
||||
|
||||
var havokSource = Path.Combine(basePath, "DedicatedServer64", "Havok.dll");
|
||||
var havokTarget = Path.Combine(basePath, "Havok.dll");
|
||||
|
||||
if (!File.Exists(havokTarget))
|
||||
{
|
||||
File.Copy(havokSource, havokTarget);
|
||||
}
|
||||
else if (File.GetLastWriteTime(havokTarget) < File.GetLastWriteTime(havokSource))
|
||||
{
|
||||
File.Delete(havokTarget);
|
||||
File.Copy(havokSource, havokTarget);
|
||||
}
|
||||
|
||||
InitConfig();
|
||||
if (!Config.Parse(args))
|
||||
return false;
|
||||
|
||||
if (!string.IsNullOrEmpty(Config.WaitForPID))
|
||||
{
|
||||
try
|
||||
@@ -114,9 +78,9 @@ quit";
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (Exception e)
|
||||
{
|
||||
// ignored
|
||||
Log.Warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,11 +88,11 @@ quit";
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Run()
|
||||
public void Run(bool isService, string instanceName, string instancePath)
|
||||
{
|
||||
_server = new TorchServer(Config);
|
||||
_server = new TorchServer(Config, instancePath, instanceName);
|
||||
|
||||
if (Config.NoGui)
|
||||
if (isService || Config.NoGui)
|
||||
{
|
||||
_server.Init();
|
||||
_server.Start();
|
||||
@@ -164,35 +128,24 @@ quit";
|
||||
ui.ShowDialog();
|
||||
}
|
||||
}
|
||||
|
||||
private void InitConfig()
|
||||
{
|
||||
var configName = "Torch.cfg";
|
||||
var configPath = Path.Combine(Directory.GetCurrentDirectory(), configName);
|
||||
if (File.Exists(configName))
|
||||
{
|
||||
Log.Info($"Loading config {configName}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Info($"Generating default config at {configPath}");
|
||||
}
|
||||
ConfigPersistent = Persistent<TorchConfig>.Load(configPath);
|
||||
}
|
||||
|
||||
|
||||
public static void RunSteamCmd()
|
||||
{
|
||||
var log = LogManager.GetLogger("SteamCMD");
|
||||
|
||||
if (!Directory.Exists(STEAMCMD_DIR))
|
||||
var path = Environment.GetEnvironmentVariable("TORCH_STEAMCMD") ?? Path.GetFullPath(STEAMCMD_DIR);
|
||||
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Directory.CreateDirectory(STEAMCMD_DIR);
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
if (!File.Exists(RUNSCRIPT_PATH))
|
||||
File.WriteAllText(RUNSCRIPT_PATH, RUNSCRIPT);
|
||||
var runScriptPath = Path.Combine(path, RUNSCRIPT_FILE);
|
||||
if (!File.Exists(runScriptPath))
|
||||
File.WriteAllText(runScriptPath, RUNSCRIPT);
|
||||
|
||||
if (!File.Exists(STEAMCMD_PATH))
|
||||
var steamCmdExePath = Path.Combine(path, STEAMCMD_EXE);
|
||||
if (!File.Exists(steamCmdExePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -201,22 +154,21 @@ quit";
|
||||
using (var file = File.Create(STEAMCMD_ZIP))
|
||||
client.GetStreamAsync("https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip").Result.CopyTo(file);
|
||||
|
||||
ZipFile.ExtractToDirectory(STEAMCMD_ZIP, STEAMCMD_DIR);
|
||||
ZipFile.ExtractToDirectory(STEAMCMD_ZIP, path);
|
||||
File.Delete(STEAMCMD_ZIP);
|
||||
log.Info("SteamCMD downloaded successfully!");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.Error("Failed to download SteamCMD, unable to update the DS.");
|
||||
log.Error(e);
|
||||
log.Error(e, "Failed to download SteamCMD, unable to update the DS.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
log.Info("Checking for DS updates.");
|
||||
var steamCmdProc = new ProcessStartInfo(STEAMCMD_PATH, "+runscript runscript.txt")
|
||||
var steamCmdProc = new ProcessStartInfo(steamCmdExePath, "+runscript runscript.txt")
|
||||
{
|
||||
WorkingDirectory = Path.Combine(Directory.GetCurrentDirectory(), STEAMCMD_DIR),
|
||||
WorkingDirectory = path,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
StandardOutputEncoding = Encoding.ASCII
|
||||
@@ -230,29 +182,5 @@ quit";
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
_server.FatalException = true;
|
||||
if (Debugger.IsAttached)
|
||||
return;
|
||||
var ex = (Exception)e.ExceptionObject;
|
||||
Log.Fatal(ex.ToStringDemystified());
|
||||
LogManager.Flush();
|
||||
if (Config.RestartOnCrash)
|
||||
{
|
||||
Console.WriteLine("Restarting in 5 seconds.");
|
||||
Thread.Sleep(5000);
|
||||
var exe = typeof(Program).Assembly.Location;
|
||||
Config.WaitForPID = Environment.ProcessId.ToString();
|
||||
Process.Start(exe, Config.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("Torch encountered a fatal error and needs to close. Please check the logs for details.");
|
||||
}
|
||||
|
||||
Environment.Exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -41,9 +41,11 @@ namespace Torch.Server.Managers
|
||||
[Dependency]
|
||||
private FilesystemManager _filesystemManager;
|
||||
|
||||
public InstanceManager(ITorchBase torchInstance) : base(torchInstance)
|
||||
private new ITorchServer Torch { get; }
|
||||
|
||||
public InstanceManager(ITorchServer torchInstance) : base(torchInstance)
|
||||
{
|
||||
|
||||
Torch = torchInstance;
|
||||
}
|
||||
|
||||
public IWorld SelectedWorld => DedicatedConfig.SelectedWorld;
|
||||
@@ -74,7 +76,7 @@ namespace Torch.Server.Managers
|
||||
|
||||
DedicatedConfig = new ConfigDedicatedViewModel((MyConfigDedicated<MyObjectBuilder_SessionSettings>) MySandboxGame.ConfigDedicated);
|
||||
|
||||
var worldFolders = Directory.EnumerateDirectories(Path.Combine(Torch.Config.InstancePath, "Saves"));
|
||||
var worldFolders = Directory.EnumerateDirectories(Path.Combine(Torch.InstancePath, "Saves"));
|
||||
|
||||
foreach (var f in worldFolders)
|
||||
{
|
||||
@@ -226,7 +228,7 @@ namespace Torch.Server.Managers
|
||||
{
|
||||
if (!((TorchServer)Torch).HasRun)
|
||||
{
|
||||
DedicatedConfig.Save(Path.Combine(Torch.Config.InstancePath, CONFIG_NAME));
|
||||
DedicatedConfig.Save(Path.Combine(Torch.InstancePath, CONFIG_NAME));
|
||||
Log.Info("Saved dedicated config.");
|
||||
}
|
||||
|
||||
|
@@ -1,17 +1,5 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.ServiceProcess;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
#if TORCH_SERVICE
|
||||
using Microsoft.VisualBasic.Devices;
|
||||
#endif
|
||||
using NLog;
|
||||
using NLog.Fluent;
|
||||
using NLog.Targets;
|
||||
using Torch.Utils;
|
||||
|
||||
@@ -19,19 +7,17 @@ namespace Torch.Server
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
/// <remarks>
|
||||
/// This method must *NOT* load any types/assemblies from the vanilla game, otherwise automatic updates will fail.
|
||||
/// </remarks>
|
||||
[STAThread]
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var isService = Environment.GetEnvironmentVariable("TORCH_SERVICE")
|
||||
?.Equals(bool.TrueString, StringComparison.OrdinalIgnoreCase) ?? false;
|
||||
Target.Register<LogViewerTarget>(nameof(LogViewerTarget));
|
||||
//Ensures that all the files are downloaded in the Torch directory.
|
||||
var workingDir = new FileInfo(typeof(Program).Assembly.Location).Directory!.FullName;
|
||||
var binDir = Path.Combine(workingDir, "DedicatedServer64");
|
||||
Directory.SetCurrentDirectory(workingDir);
|
||||
var workingDir = AppContext.BaseDirectory;
|
||||
var binDir = Path.Combine(Environment.GetEnvironmentVariable("TORCH_GAME_PATH") ?? workingDir, "DedicatedServer64");
|
||||
Directory.SetCurrentDirectory(Environment.GetEnvironmentVariable("TORCH_GAME_PATH") ?? workingDir);
|
||||
|
||||
if (Directory.Exists(binDir))
|
||||
if (!isService && Directory.Exists(binDir))
|
||||
foreach (var file in Directory.GetFiles(binDir, "System.*.dll"))
|
||||
{
|
||||
File.Delete(file);
|
||||
@@ -49,11 +35,71 @@ namespace Torch.Server
|
||||
}
|
||||
#endif
|
||||
|
||||
var initializer = new Initializer(workingDir);
|
||||
if (!initializer.Initialize(args))
|
||||
return;
|
||||
var instanceName = Environment.GetEnvironmentVariable("TORCH_INSTANCE") ?? "Instance";
|
||||
string instancePath;
|
||||
|
||||
if (Path.IsPathRooted(instanceName))
|
||||
{
|
||||
instancePath = instanceName;
|
||||
instanceName = Path.GetDirectoryName(instanceName);
|
||||
}
|
||||
else
|
||||
{
|
||||
instancePath = Path.GetFullPath(instanceName);
|
||||
}
|
||||
|
||||
initializer.Run();
|
||||
var oldTorchCfg = Path.Combine(workingDir, "Torch.cfg");
|
||||
var torchCfg = Path.Combine(instancePath, "Torch.cfg");
|
||||
|
||||
if (File.Exists(oldTorchCfg))
|
||||
File.Move(oldTorchCfg, torchCfg, true);
|
||||
|
||||
var config = Persistent<TorchConfig>.Load(torchCfg);
|
||||
config.Data.InstanceName = instanceName;
|
||||
config.Data.InstancePath = instancePath;
|
||||
if (!config.Data.Parse(args))
|
||||
{
|
||||
Console.WriteLine("Invalid arguments");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
var handler = new UnhandledExceptionHandler(config.Data, isService);
|
||||
AppDomain.CurrentDomain.UnhandledException += handler.OnUnhandledException;
|
||||
|
||||
var initializer = new Initializer(workingDir, config);
|
||||
if (!initializer.Initialize(args))
|
||||
Environment.Exit(1);
|
||||
|
||||
CopyNative(binDir);
|
||||
initializer.Run(isService, instanceName, instancePath);
|
||||
}
|
||||
|
||||
private static void CopyNative(string binPath)
|
||||
{
|
||||
var apiSource = Path.Combine(binPath, "steam_api64.dll");
|
||||
var apiTarget = Path.Combine(AppContext.BaseDirectory, "steam_api64.dll");
|
||||
if (!File.Exists(apiTarget))
|
||||
{
|
||||
File.Copy(apiSource, apiTarget);
|
||||
}
|
||||
else if (File.GetLastWriteTime(apiTarget) < File.GetLastWriteTime(binPath))
|
||||
{
|
||||
File.Delete(apiTarget);
|
||||
File.Copy(apiSource, apiTarget);
|
||||
}
|
||||
|
||||
var havokSource = Path.Combine(binPath, "Havok.dll");
|
||||
var havokTarget = Path.Combine(AppContext.BaseDirectory, "Havok.dll");
|
||||
|
||||
if (!File.Exists(havokTarget))
|
||||
{
|
||||
File.Copy(havokSource, havokTarget);
|
||||
}
|
||||
else if (File.GetLastWriteTime(havokTarget) < File.GetLastWriteTime(havokSource))
|
||||
{
|
||||
File.Delete(havokTarget);
|
||||
File.Copy(havokSource, havokTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -5,31 +5,22 @@
|
||||
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
<UpdateEnabled>false</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||
<UpdatePeriodically>false</UpdatePeriodically>
|
||||
<UpdateRequired>false</UpdateRequired>
|
||||
<MapFileExtensions>true</MapFileExtensions>
|
||||
<ApplicationRevision>0</ApplicationRevision>
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
<AssemblyTitle>Torch Server</AssemblyTitle>
|
||||
<Product>Torch</Product>
|
||||
<Copyright>Copyright © Torch API 2017</Copyright>
|
||||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
|
||||
<OutputPath>$(SolutionDir)\bin\$(Platform)\$(Configuration)\</OutputPath>
|
||||
<OutputPath>..\bin\$(Platform)\$(Configuration)\</OutputPath>
|
||||
<UseWPF>true</UseWPF>
|
||||
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>
|
||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Platforms>AnyCPU</Platforms>
|
||||
<IsPackable>false</IsPackable>
|
||||
<NeutralLanguage>en</NeutralLanguage>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<StartupObject>Torch.Server.Program</StartupObject>
|
||||
@@ -169,8 +160,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Remove="Views\WorldSelectControl.xaml" />
|
||||
<None Include="..\NLog.config" Visible="false" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="Always" />
|
||||
<None Include="..\Dockerfile" Visible="false" CopyToPublishDirectory="Always" />
|
||||
</ItemGroup>
|
||||
<Target Name="CopyLoggingConfig" AfterTargets="Build">
|
||||
<Copy SourceFiles="$(SolutionDir)NLog.config" DestinationFolder="$(TargetDir)" />
|
||||
</Target>
|
||||
</Project>
|
2
Torch.Server/Torch.Server.csproj.DotSettings
Normal file
2
Torch.Server/Torch.Server.csproj.DotSettings
Normal file
@@ -0,0 +1,2 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeEditing/Localization/Localizable/@EntryValue">No</s:String></wpf:ResourceDictionary>
|
@@ -17,9 +17,7 @@ namespace Torch.Server
|
||||
|
||||
public bool ShouldUpdatePlugins => (GetPluginUpdates && !NoUpdate) || ForceUpdate;
|
||||
public bool ShouldUpdateTorch => (GetTorchUpdates && !NoUpdate) || ForceUpdate;
|
||||
|
||||
private string _instancePath = Path.GetFullPath("Instance");
|
||||
private string _instanceName = "Instance";
|
||||
|
||||
private bool _autostart;
|
||||
private bool _restartOnCrash;
|
||||
private bool _noGui;
|
||||
@@ -40,21 +38,6 @@ namespace Torch.Server
|
||||
private UGCServiceType _ugcServiceType = UGCServiceType.Steam;
|
||||
private bool _entityManagerEnabled = true;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
[Arg("instancename", "The name of the Torch instance.")]
|
||||
[Display(Name = "Instance Name", Description = "The name of the Torch instance.", GroupName = "Server")]
|
||||
public string InstanceName { get => _instanceName; set => Set(value, ref _instanceName); }
|
||||
|
||||
/// <inheritdoc />
|
||||
[Arg("instancepath", "Server data folder where saves and mods are stored.")]
|
||||
[Display(Name = "Instance Path", Description = "Server data folder where saves and mods are stored.", GroupName = "Server")]
|
||||
public string InstancePath
|
||||
{
|
||||
get => _instancePath;
|
||||
set => Set(value, ref _instancePath);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[XmlIgnore, Arg("noupdate", "Disable automatically downloading game and plugin updates.")]
|
||||
public bool NoUpdate { get; set; }
|
||||
@@ -81,6 +64,8 @@ namespace Torch.Server
|
||||
[Display(Name = "Restart On Crash", Description = "Automatically restart the server if it crashes.", GroupName = "Server")]
|
||||
public bool RestartOnCrash { get => _restartOnCrash; set => Set(value, ref _restartOnCrash); }
|
||||
|
||||
public string InstancePath { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[Arg("nogui", "Do not show the Torch UI.")]
|
||||
[Display(Name = "No GUI", Description = "Do not show the Torch UI.", GroupName = "Window")]
|
||||
@@ -94,6 +79,8 @@ namespace Torch.Server
|
||||
[Display(Name = "Update Torch", Description = "Check every start for new versions of torch.", GroupName = "Server")]
|
||||
public bool GetTorchUpdates { get => _getTorchUpdates; set => Set(value, ref _getTorchUpdates); }
|
||||
|
||||
public string InstanceName { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[Display(Name = "Update Plugins", Description = "Check every start for new versions of plugins.", GroupName = "Server")]
|
||||
public bool GetPluginUpdates { get => _getPluginUpdates; set => Set(value, ref _getPluginUpdates); }
|
||||
|
@@ -55,8 +55,10 @@ namespace Torch.Server
|
||||
|
||||
//Here to trigger rebuild
|
||||
/// <inheritdoc />
|
||||
public TorchServer(TorchConfig config) : base(config)
|
||||
public TorchServer(ITorchConfig config, string instancePath, string instanceName) : base(config)
|
||||
{
|
||||
InstancePath = instancePath;
|
||||
InstanceName = instanceName;
|
||||
DedicatedInstance = new InstanceManager(this);
|
||||
AddManager(DedicatedInstance);
|
||||
if (config.EntityManagerEnabled)
|
||||
@@ -116,7 +118,7 @@ namespace Torch.Server
|
||||
public InstanceManager DedicatedInstance { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string InstanceName => Config?.InstanceName;
|
||||
public string InstanceName { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override uint SteamAppId => 244850;
|
||||
@@ -130,7 +132,7 @@ namespace Torch.Server
|
||||
public event Action<ITorchServer> Initialized;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string InstancePath => Config?.InstancePath;
|
||||
public string InstancePath { get; }
|
||||
|
||||
public int OnlinePlayers { get => _players; private set => SetValue(ref _players, value); }
|
||||
|
||||
@@ -141,10 +143,10 @@ namespace Torch.Server
|
||||
MySandboxGame.IsDedicated = true;
|
||||
base.Init();
|
||||
Managers.GetManager<ITorchSessionManager>().SessionStateChanged += OnSessionStateChanged;
|
||||
GetManager<InstanceManager>().LoadInstance(Config.InstancePath);
|
||||
GetManager<InstanceManager>().LoadInstance(InstancePath);
|
||||
CanRun = true;
|
||||
Initialized?.Invoke(this);
|
||||
Log.Info($"Initialized server '{Config.InstanceName}' at '{Config.InstancePath}'");
|
||||
Log.Info($"Initialized server '{InstanceName}' at '{InstancePath}'");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
49
Torch.Server/UnhandledExceptionHandler.cs
Normal file
49
Torch.Server/UnhandledExceptionHandler.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using NLog;
|
||||
using VRage;
|
||||
|
||||
namespace Torch.Server;
|
||||
|
||||
internal class UnhandledExceptionHandler
|
||||
{
|
||||
private readonly TorchConfig _config;
|
||||
private readonly bool _isService;
|
||||
private static readonly ILogger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
public UnhandledExceptionHandler(TorchConfig config, bool isService)
|
||||
{
|
||||
_config = config;
|
||||
_isService = isService;
|
||||
}
|
||||
|
||||
internal void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
if (Debugger.IsAttached)
|
||||
return;
|
||||
var ex = (Exception)e.ExceptionObject;
|
||||
Log.Fatal(ex.ToStringDemystified());
|
||||
LogManager.Flush();
|
||||
|
||||
if (_isService)
|
||||
Environment.Exit(1);
|
||||
|
||||
if (_config.RestartOnCrash)
|
||||
{
|
||||
Console.WriteLine("Restarting in 5 seconds.");
|
||||
Thread.Sleep(5000);
|
||||
var exe = typeof(Program).Assembly.Location;
|
||||
_config.WaitForPID = Environment.ProcessId.ToString();
|
||||
Process.Start(exe, _config.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
MyVRage.Platform.Windows.MessageBox(
|
||||
"Torch encountered a fatal error and needs to close. Please check the logs for details.",
|
||||
"Fatal exception", MessageBoxOptions.OkOnly);
|
||||
}
|
||||
|
||||
Environment.Exit(1);
|
||||
}
|
||||
}
|
@@ -12,6 +12,7 @@ EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7AD02A71-1D4C-48F9-A8C1-789A5512424F}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
NLog.config = NLog.config
|
||||
Dockerfile = Dockerfile
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.Tests", "Torch.Tests\Torch.Tests.csproj", "{C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}"
|
||||
|
@@ -46,6 +46,9 @@ namespace Torch.Patches
|
||||
|
||||
[ReflectedMethodInfo(typeof(MyLog), nameof(MyLog.Init))]
|
||||
private static MethodInfo _logInit;
|
||||
|
||||
[ReflectedMethodInfo(typeof(MyLog), nameof(MyLog.Close))]
|
||||
private static MethodInfo _logClose;
|
||||
#pragma warning restore 649
|
||||
|
||||
|
||||
@@ -64,6 +67,7 @@ namespace Torch.Patches
|
||||
context.GetPattern(_logWriteLineOptions).AddPrefix(nameof(PrefixWriteLineOptions));
|
||||
|
||||
context.GetPattern(_logInit).AddPrefix(nameof(PrefixInit));
|
||||
context.GetPattern(_logClose).AddPrefix(nameof(PrefixClose));
|
||||
}
|
||||
|
||||
[ReflectedMethod(Name = "GetIdentByThread")]
|
||||
@@ -81,6 +85,8 @@ namespace Torch.Patches
|
||||
return _getIndentByThread(MyLog.Default, Environment.CurrentManagedThreadId);
|
||||
}
|
||||
|
||||
private static bool PrefixClose() => false;
|
||||
|
||||
private static bool PrefixInit(MyLog __instance, StringBuilder appVersionString)
|
||||
{
|
||||
__instance.WriteLine("Log Started");
|
||||
|
@@ -26,7 +26,7 @@ namespace Torch
|
||||
public T Data
|
||||
{
|
||||
get => _data;
|
||||
private set
|
||||
private init
|
||||
{
|
||||
if (_data is INotifyPropertyChanged npc1)
|
||||
npc1.PropertyChanged -= OnPropertyChanged;
|
||||
|
@@ -6,7 +6,7 @@
|
||||
<Copyright>Copyright © Torch API 2017</Copyright>
|
||||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<OutputPath>$(SolutionDir)\bin\$(Platform)\$(Configuration)\</OutputPath>
|
||||
<OutputPath>..\bin\$(Platform)\$(Configuration)\</OutputPath>
|
||||
<UseWpf>True</UseWpf>
|
||||
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
|
@@ -1,17 +0,0 @@
|
||||
$buildSalt = $Env:BUILD_NUMBER
|
||||
$branchName = $Env:BRANCH_NAME
|
||||
$gitSimpleVersion = git describe --tags --abbrev=0
|
||||
$simpleVersionStandard = echo $gitSimpleVersion | Select-String -Pattern "([0-9]+)\.([0-9]+)\.([0-9]+)" | % {$_.Matches} | %{$_.Groups[1].Value+"."+$_.Groups[2].Value+"."+$_.Groups[3].Value}
|
||||
$dotNetVersion = "$simpleVersionStandard.$buildSalt"
|
||||
$infoVersion = -join(("$gitSimpleVersion" -replace "([0-9]+)\.([0-9]+)\.([0-9]+)","$dotNetVersion"), "-", "$branchName")
|
||||
|
||||
$fileContent = @"
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyVersion("$dotNetVersion")]
|
||||
[assembly: AssemblyInformationalVersion("$infoVersion")]
|
||||
"@
|
||||
|
||||
echo $fileContent | Set-Content "$PSScriptRoot/AssemblyVersion.cs"
|
||||
|
||||
echo "$infoVersion"
|
Reference in New Issue
Block a user