diff --git a/Jenkins/get-version.ps1 b/Jenkins/get-version.ps1 new file mode 100644 index 0000000..8650739 --- /dev/null +++ b/Jenkins/get-version.ps1 @@ -0,0 +1,5 @@ +$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} +Write-Host "$simpleVersionStandard.$buildSalt" \ No newline at end of file diff --git a/Jenkins/jenkins-grab-se.ps1 b/Jenkins/jenkins-grab-se.ps1 new file mode 100644 index 0000000..ea820af --- /dev/null +++ b/Jenkins/jenkins-grab-se.ps1 @@ -0,0 +1,26 @@ +pushd + +$steamData = "C:/Steam/Data/" +$steamCMDPath = "C:/Steam/steamcmd/" +$steamCMDZip = "C:/Steam/steamcmd.zip" + +if (!(Test-Path $steamData)) { + mkdir "$steamData" +} +if (!(Test-Path $steamCMDPath)) { + if (!(Test-Path $steamCMDZip)) { + Invoke-WebRequest -OutFile $steamCMDZip https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip + } + Expand-Archive $steamCMDZip -DestinationPath $steamCMDPath +} +& "$steamCMDPath/steamcmd.exe" "+login anonymous" "+force_install_dir $steamData" "+app_update 298740" "+quit" + +$dataPath = $steamData.Replace("/", "\"); +$contentPath = "$dataPath\Content"; +if (Test-Path $contentPath) { + Remove-Item -LiteralPath $contentPath -Force -Recurse +} + +cmd /S /C mklink /J .\GameBinaries $dataPath\DedicatedServer64 + +popd diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..39ae44a --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,55 @@ +def packageAndArchive(buildMode, packageName) { + zipFile = "bin\\${packageName}.zip" + packageDir = "publish" + + bat 'powershell -Command { Compress-Archive -Path ${packageDir}\\* -DestinationPath ${zipFile} }' + archiveArtifacts artifacts: zipFile, caseSensitive: false, onlyIfSuccessful: true +} + +node('windows') { + stage('Checkout') { + checkout scm + bat 'git pull https://github.com/TorchAPI/Torch/ ${env.BRANCH_NAME} --tags' + } + + stage('Acquire SE') { + bat 'powershell -File Jenkins/jenkins-grab-se.ps1' + } + + stage('Build') { + dotnetVersion = bat(returnStdout: true, script: '@powershell -NonInteractive -NoLogo -NoProfile -File Jenkins/get-version.ps1').trim() + infoVersion = "${dotnetVersion}-${env.BRANCH_NAME}" + currentBuild.description = infoVersion + + bat 'dotnet publish .\\Torch.Server\\Torch.Server.csproj -p:PackageVersion=${dotnetVersion} -p:InformationalVersion=${infoVersion} --self-contained -f net6-windows -r win-x64 -c Release -o .\\publish\\' + } + + 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 + ]] + ]) + } + */ +} diff --git a/Torch.API/IApplicationContext.cs b/Torch.API/IApplicationContext.cs new file mode 100644 index 0000000..5744592 --- /dev/null +++ b/Torch.API/IApplicationContext.cs @@ -0,0 +1,30 @@ +using System.IO; +namespace Torch.API; + +public interface IApplicationContext +{ + /// + /// Directory contains torch binaries. + /// + public DirectoryInfo TorchDirectory { get; } + /// + /// Root directory for all game files. + /// + public DirectoryInfo GameFilesDirectory { get; } + /// + /// Directory contains game binaries. + /// + public DirectoryInfo GameBinariesDirectory { get; } + /// + /// Current instance directory. + /// + public DirectoryInfo InstanceDirectory { get; } + /// + /// Current instance name. + /// + public string InstanceName { get; } + /// + /// Application running in service mode. + /// + public bool IsService { get; } +} diff --git a/Torch.API/Properties/AssemblyInfo.cs b/Torch.API/Properties/AssemblyInfo.cs deleted file mode 100644 index a2627e8..0000000 --- a/Torch.API/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("Torch API")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Torch")] -[assembly: AssemblyCopyright("Copyright © Torch API 2017")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: ComVisible(false)] - -#if DEBUG -[assembly: AssemblyConfiguration("Debug")] -#else -[assembly: AssemblyConfiguration("Release")] -#endif \ No newline at end of file diff --git a/Torch.API/Torch.API.csproj b/Torch.API/Torch.API.csproj index 48dd83d..693a5a9 100644 --- a/Torch.API/Torch.API.csproj +++ b/Torch.API/Torch.API.csproj @@ -1,13 +1,13 @@  net6-windows + 10 Torch API Torch Copyright © Torch API 2017 false ..\bin\$(Platform)\$(Configuration)\ True - False x64 Debug;Release AnyCPU @@ -19,6 +19,9 @@ + + + @@ -99,7 +102,4 @@ False - - - \ No newline at end of file diff --git a/Torch.API/Utils/IsExternalInit.cs b/Torch.API/Utils/IsExternalInit.cs new file mode 100644 index 0000000..58e2c72 --- /dev/null +++ b/Torch.API/Utils/IsExternalInit.cs @@ -0,0 +1,8 @@ +#if NETFRAMEWORK +// ReSharper disable once CheckNamespace +namespace System.Runtime.CompilerServices; + +public class IsExternalInit +{ +} +#endif diff --git a/Torch.API/WebAPI/JenkinsQuery.cs b/Torch.API/WebAPI/JenkinsQuery.cs index a5be97f..d9d099b 100644 --- a/Torch.API/WebAPI/JenkinsQuery.cs +++ b/Torch.API/WebAPI/JenkinsQuery.cs @@ -68,7 +68,11 @@ namespace Torch.API.WebAPI return false; } var s = await h.Content.ReadAsStreamAsync(); +#if !NETFRAMEWORK await using var fs = new FileStream(path, FileMode.Create); +#else + using var fs = new FileStream(path, FileMode.Create); +#endif await s.CopyToAsync(fs); return true; } diff --git a/Torch.API/WebAPI/PluginQuery.cs b/Torch.API/WebAPI/PluginQuery.cs index 8c24a64..ad7b8e6 100644 --- a/Torch.API/WebAPI/PluginQuery.cs +++ b/Torch.API/WebAPI/PluginQuery.cs @@ -78,7 +78,11 @@ namespace Torch.API.WebAPI if(File.Exists(path)) File.Delete(path); +#if NETFRAMEWORK + using var f = File.Create(path); +#else await using var f = File.Create(path); +#endif await s.CopyToAsync(f); } catch (Exception ex) diff --git a/Torch.Server.Tests/Properties/AssemblyInfo.cs b/Torch.Server.Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index 8891763..0000000 --- a/Torch.Server.Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("Torch Server Tests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Torch")] -[assembly: AssemblyCopyright("Copyright © Torch API 2017")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: ComVisible(false)] - -#if DEBUG -[assembly: AssemblyConfiguration("Debug")] -#else -[assembly: AssemblyConfiguration("Release")] -#endif \ No newline at end of file diff --git a/Torch.Server.Tests/Torch.Server.Tests.csproj b/Torch.Server.Tests/Torch.Server.Tests.csproj index b31bcb2..21224d5 100644 --- a/Torch.Server.Tests/Torch.Server.Tests.csproj +++ b/Torch.Server.Tests/Torch.Server.Tests.csproj @@ -1,6 +1,7 @@  net6-windows + 10 1591,0649 Torch Server Tests Torch @@ -27,9 +28,6 @@ False - - - diff --git a/Torch.Server.Tests/app.config b/Torch.Server.Tests/app.config deleted file mode 100644 index cf4f4e1..0000000 --- a/Torch.Server.Tests/app.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/Torch.Server/Initializer.cs b/Torch.Server/Initializer.cs index ddc7552..83616e9 100644 --- a/Torch.Server/Initializer.cs +++ b/Torch.Server/Initializer.cs @@ -36,7 +36,7 @@ namespace Torch.Server public TorchConfig Config => ConfigPersistent?.Data; public TorchServer Server => _server; - public Initializer(string basePath, Persistent torchConfig) + public Initializer(Persistent torchConfig) { Instance = this; ConfigPersistent = torchConfig; @@ -83,11 +83,11 @@ namespace Torch.Server return true; } - public void Run(bool isService, string instanceName, string instancePath) + public void Run() { - _server = new TorchServer(Config, instancePath, instanceName); + _server = new TorchServer(Config, ApplicationContext.Current.InstanceDirectory.FullName, ApplicationContext.Current.InstanceName); - if (isService || Config.NoGui) + if (ApplicationContext.Current.IsService || Config.NoGui) { _server.Init(); _server.Start(); diff --git a/Torch.Server/Managers/EntityControlManager.cs b/Torch.Server/Managers/EntityControlManager.cs index b121fdf..d5500ba 100644 --- a/Torch.Server/Managers/EntityControlManager.cs +++ b/Torch.Server/Managers/EntityControlManager.cs @@ -40,7 +40,13 @@ namespace Torch.Server.Managers protected abstract EntityControlViewModel Create(EntityViewModel evm); +#if NETFRAMEWORK + [ReflectedGetter(Name = "Keys")] + private static readonly Func, ICollection> WeakTableKeys = null!; + internal IEnumerable Keys => WeakTableKeys(_models); +#else internal IEnumerable Keys => _models.Select(b => b.Key); +#endif internal EntityControlViewModel GetOrCreate(EntityViewModel evm) { diff --git a/Torch.Server/Program.cs b/Torch.Server/Program.cs index 82c5ee5..74e14d1 100644 --- a/Torch.Server/Program.cs +++ b/Torch.Server/Program.cs @@ -3,6 +3,7 @@ using System.IO; using NLog; using NLog.Config; using NLog.Targets; +using Torch.API; using Torch.Utils; namespace Torch.Server @@ -12,112 +13,71 @@ namespace Torch.Server [STAThread] public static void Main(string[] args) { - var isService = Environment.GetEnvironmentVariable("TORCH_SERVICE") - ?.Equals(bool.TrueString, StringComparison.OrdinalIgnoreCase) ?? false; - //Ensures that all the files are downloaded in the Torch directory. - var workingDir = AppContext.BaseDirectory; - var binDir = Path.Combine(Environment.GetEnvironmentVariable("TORCH_GAME_PATH") ?? workingDir, "DedicatedServer64"); - Directory.SetCurrentDirectory(Environment.GetEnvironmentVariable("TORCH_GAME_PATH") ?? workingDir); - - if (!isService && Directory.Exists(binDir)) - foreach (var file in Directory.GetFiles(binDir, "System.*.dll")) - { - File.Delete(file); - } + var context = CreateApplicationContext(); - // Breaks on Windows Server 2019 -#if TORCH_SERVICE - if (!new ComputerInfo().OSFullName.Contains("Server 2019") && !Environment.UserInteractive) - { - using (var service = new TorchService(args)) - ServiceBase.Run(service); - return; - } -#endif + SetupLogging(); - var instanceName = Environment.GetEnvironmentVariable("TORCH_INSTANCE") ?? "Instance"; - string instancePath; - - if (Path.IsPathRooted(instanceName)) - { - instancePath = instanceName; - instanceName = Path.GetDirectoryName(instanceName); - } - else - { - instancePath = Directory.CreateDirectory(instanceName).FullName; - } - - var oldNlog = Path.Combine(workingDir, "NLog.config"); - var newNlog = Path.Combine(instancePath, "NLog.config"); - if (File.Exists(oldNlog) && !File.ReadAllText(oldNlog).Contains("FlowDocument", StringComparison.Ordinal)) - File.Move(oldNlog, newNlog, true); - else if (!File.Exists(newNlog)) - using (var f = File.Create(newNlog)) - typeof(Program).Assembly.GetManifestResourceStream("Torch.Server.NLog.config")!.CopyTo(f); - - var oldTorchCfg = Path.Combine(workingDir, "Torch.cfg"); - var torchCfg = Path.Combine(instancePath, "Torch.cfg"); + var oldTorchCfg = Path.Combine(context.TorchDirectory.FullName, "Torch.cfg"); + var torchCfg = Path.Combine(context.InstanceDirectory.FullName, "Torch.cfg"); if (File.Exists(oldTorchCfg)) - File.Move(oldTorchCfg, torchCfg, true); + File.Move(oldTorchCfg, torchCfg); var config = Persistent.Load(torchCfg); - config.Data.InstanceName = instanceName; - config.Data.InstancePath = instancePath; + config.Data.InstanceName = context.InstanceName; + config.Data.InstancePath = context.InstanceDirectory.FullName; + if (!config.Data.Parse(args)) { Console.WriteLine("Invalid arguments"); Environment.Exit(1); } - var handler = new UnhandledExceptionHandler(config.Data, isService); + var handler = new UnhandledExceptionHandler(config.Data); AppDomain.CurrentDomain.UnhandledException += handler.OnUnhandledException; - - Target.Register(nameof(LogViewerTarget)); - TorchLogManager.RegisterTargets(Environment.GetEnvironmentVariable("TORCH_LOG_EXTENSIONS_PATH") ?? - Path.Combine(instancePath, "LoggingExtensions")); - - TorchLogManager.SetConfiguration(new XmlLoggingConfiguration(newNlog)); - var initializer = new Initializer(workingDir, config); + var initializer = new Initializer(config); if (!initializer.Initialize(args)) Environment.Exit(1); - TorchLauncher.Launch(workingDir, binDir); +#if DEBUG + TorchLauncher.Launch(context.TorchDirectory.FullName, context.GameBinariesDirectory.FullName); +#else + TorchLauncher.Launch(context.TorchDirectory.FullName, Path.Combine(context.TorchDirectory.FullName, "torch64"), + context.GameBinariesDirectory.FullName); +#endif - CopyNative(binDir); + CopyNative(); - initializer.Run(isService, instanceName, instancePath); + initializer.Run(); } - private static void CopyNative(string binPath) + private static void CopyNative() { var log = LogManager.GetLogger("TorchLauncher"); - var workingDir = new DirectoryInfo(Directory.GetCurrentDirectory()); - if (workingDir.Attributes.HasFlag(FileAttributes.ReadOnly)) + if (ApplicationContext.Current.GameFilesDirectory.Attributes.HasFlag(FileAttributes.ReadOnly)) { - log.Warn("Game directory is readonly. You should copy steam_api64.dll, Havok.dll from bin manually"); + log.Warn("Torch directory is readonly. You should copy steam_api64.dll, Havok.dll from bin manually"); return; } try { - var apiSource = Path.Combine(binPath, "steam_api64.dll"); - var apiTarget = Path.Combine(workingDir.FullName, "steam_api64.dll"); + var apiSource = Path.Combine(ApplicationContext.Current.GameBinariesDirectory.FullName, "steam_api64.dll"); + var apiTarget = Path.Combine(ApplicationContext.Current.GameFilesDirectory.FullName, "steam_api64.dll"); if (!File.Exists(apiTarget)) { File.Copy(apiSource, apiTarget); } - else if (File.GetLastWriteTime(apiTarget) < File.GetLastWriteTime(binPath)) + else if (File.GetLastWriteTime(apiTarget) < ApplicationContext.Current.GameBinariesDirectory.LastWriteTime) { File.Delete(apiTarget); File.Copy(apiSource, apiTarget); } - var havokSource = Path.Combine(binPath, "Havok.dll"); - var havokTarget = Path.Combine(workingDir.FullName, "Havok.dll"); + var havokSource = Path.Combine(ApplicationContext.Current.GameBinariesDirectory.FullName, "Havok.dll"); + var havokTarget = Path.Combine(ApplicationContext.Current.GameFilesDirectory.FullName, "Havok.dll"); if (!File.Exists(havokTarget)) { @@ -138,5 +98,49 @@ namespace Torch.Server log.Error(e); } } + + private static void SetupLogging() + { + var oldNlog = Path.Combine(ApplicationContext.Current.TorchDirectory.FullName, "NLog.config"); + var newNlog = Path.Combine(ApplicationContext.Current.InstanceDirectory.FullName, "NLog.config"); + if (File.Exists(oldNlog) && !File.ReadAllText(oldNlog).Contains("FlowDocument")) + File.Move(oldNlog, newNlog); + else if (!File.Exists(newNlog)) + using (var f = File.Create(newNlog)) + typeof(Program).Assembly.GetManifestResourceStream("Torch.Server.NLog.config")!.CopyTo(f); + + Target.Register(nameof(LogViewerTarget)); + TorchLogManager.RegisterTargets(Environment.GetEnvironmentVariable("TORCH_LOG_EXTENSIONS_PATH") ?? + Path.Combine(ApplicationContext.Current.InstanceDirectory.FullName, "LoggingExtensions")); + + TorchLogManager.SetConfiguration(new XmlLoggingConfiguration(newNlog)); + } + + private static IApplicationContext CreateApplicationContext() + { + var isService = Environment.GetEnvironmentVariable("TORCH_SERVICE") + ?.Equals(bool.TrueString, StringComparison.OrdinalIgnoreCase) ?? false; + + var workingDir = AppContext.BaseDirectory; + var gamePath = Environment.GetEnvironmentVariable("TORCH_GAME_PATH") ?? workingDir; + var binDir = Path.Combine(gamePath, "DedicatedServer64"); + Directory.SetCurrentDirectory(gamePath); + + var instanceName = Environment.GetEnvironmentVariable("TORCH_INSTANCE") ?? "Instance"; + string instancePath; + + if (Path.IsPathRooted(instanceName)) + { + instancePath = instanceName; + instanceName = Path.GetDirectoryName(instanceName); + } + else + { + instancePath = Directory.CreateDirectory(instanceName).FullName; + } + + return new ApplicationContext(new(workingDir), new(gamePath), new(binDir), + new(instancePath), instanceName, isService); + } } } diff --git a/Torch.Server/Properties/AssemblyInfo.cs b/Torch.Server/Properties/AssemblyInfo.cs deleted file mode 100644 index 2256788..0000000 --- a/Torch.Server/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("Torch Server")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Torch")] -[assembly: AssemblyCopyright("Copyright © Torch API 2017")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: ComVisible(false)] - -#if DEBUG -[assembly: AssemblyConfiguration("Debug")] -#else -[assembly: AssemblyConfiguration("Release")] -#endif \ No newline at end of file diff --git a/Torch.Server/Torch.Server.csproj b/Torch.Server/Torch.Server.csproj index 0b02c4f..473265f 100644 --- a/Torch.Server/Torch.Server.csproj +++ b/Torch.Server/Torch.Server.csproj @@ -2,11 +2,10 @@ Exe net6-windows + 10 {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} true publish\ - 0 - 1.0.0.%2a false Torch Server Torch @@ -14,13 +13,16 @@ false ..\bin\$(Platform)\$(Configuration)\ true - False en x64 Debug;Release AnyCPU false en + + torch64 + True + True Torch.Server.Program @@ -40,6 +42,7 @@ + @@ -143,7 +146,6 @@ - diff --git a/Torch.Server/TorchServer.cs b/Torch.Server/TorchServer.cs index 81a9d79..35ab007 100644 --- a/Torch.Server/TorchServer.cs +++ b/Torch.Server/TorchServer.cs @@ -221,7 +221,11 @@ namespace Torch.Server LogManager.Flush(); string exe = Assembly.GetExecutingAssembly().Location.Replace("dll", "exe"); +#if NETFRAMEWORK + config.WaitForPID = Process.GetCurrentProcess().Id.ToString(); +#else config.WaitForPID = Environment.ProcessId.ToString(); +#endif config.TempAutostart = true; Process.Start(exe, config.ToString()); @@ -370,35 +374,37 @@ namespace Torch.Server // return stack.ToString(); // Modified from https://www.examplefiles.net/cs/579311 - using (var target = DataTarget.CreateSnapshotAndAttach(Environment.ProcessId)) - { - var runtime = target.ClrVersions[0].CreateRuntime(); +#if NETFRAMEWORK + using var target = DataTarget.CreateSnapshotAndAttach(Process.GetCurrentProcess().Id); +#else + using var target = DataTarget.CreateSnapshotAndAttach(Environment.ProcessId); +#endif + var runtime = target.ClrVersions[0].CreateRuntime(); - var clrThread = runtime.Threads.First(b => b.ManagedThreadId == thread.ManagedThreadId); + var clrThread = runtime.Threads.First(b => b.ManagedThreadId == thread.ManagedThreadId); - var sb = new StringBuilder(); + var sb = new StringBuilder(); - foreach (var frame in clrThread.EnumerateStackTrace()) + foreach (var frame in clrThread.EnumerateStackTrace()) + { + sb.Append('\t'); + switch (frame.Kind) { - sb.Append('\t'); - switch (frame.Kind) - { - case ClrStackFrameKind.Unknown: - sb.AppendLine("[Unknown]"); - break; - case ClrStackFrameKind.ManagedMethod: - sb.AppendLine(frame.Method?.Signature ?? "[Unable to get method signature]"); - break; - case ClrStackFrameKind.Runtime: - sb.AppendLine("[CLR Runtime]"); - break; - default: - throw new ArgumentOutOfRangeException(nameof(frame.Kind), frame.Kind, "Incorrect value in EnumerateStackTrace"); - } + case ClrStackFrameKind.Unknown: + sb.AppendLine("[Unknown]"); + break; + case ClrStackFrameKind.ManagedMethod: + sb.AppendLine(frame.Method?.Signature ?? "[Unable to get method signature]"); + break; + case ClrStackFrameKind.Runtime: + sb.AppendLine("[CLR Runtime]"); + break; + default: + throw new ArgumentOutOfRangeException(nameof(frame.Kind), frame.Kind, "Incorrect value in EnumerateStackTrace"); } - - return sb.ToString(); } + + return sb.ToString(); } #endregion diff --git a/Torch.Server/UnhandledExceptionHandler.cs b/Torch.Server/UnhandledExceptionHandler.cs index 86a831d..7353719 100644 --- a/Torch.Server/UnhandledExceptionHandler.cs +++ b/Torch.Server/UnhandledExceptionHandler.cs @@ -9,13 +9,11 @@ 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) + public UnhandledExceptionHandler(TorchConfig config) { _config = config; - _isService = isService; } internal void OnUnhandledException(object sender, UnhandledExceptionEventArgs e) @@ -26,7 +24,7 @@ internal class UnhandledExceptionHandler Log.Fatal(ex.ToStringDemystified()); LogManager.Flush(); - if (_isService) + if (ApplicationContext.Current.IsService) Environment.Exit(1); if (_config.RestartOnCrash) @@ -34,7 +32,11 @@ internal class UnhandledExceptionHandler Console.WriteLine("Restarting in 5 seconds."); Thread.Sleep(5000); var exe = typeof(Program).Assembly.Location; +#if NETFRAMEWORK + _config.WaitForPID = Process.GetCurrentProcess().Id.ToString(); +#else _config.WaitForPID = Environment.ProcessId.ToString(); +#endif Process.Start(exe, _config.ToString()); } else diff --git a/Torch.Server/Views/CommandSuggestionsProvider.cs b/Torch.Server/Views/CommandSuggestionsProvider.cs index 6c18a22..ad89d98 100644 --- a/Torch.Server/Views/CommandSuggestionsProvider.cs +++ b/Torch.Server/Views/CommandSuggestionsProvider.cs @@ -32,7 +32,7 @@ public class CommandSuggestionsProvider : ISuggestionProvider { if (_commandManager is null || !_commandManager.IsCommand(filter)) yield break; - var args = filter[1..].Split(' ').ToList(); + var args = filter.Substring(1).Split(' ').ToList(); var skip = _commandManager.Commands.GetNode(args, out var node); if (skip == -1) yield break; @@ -42,7 +42,7 @@ public class CommandSuggestionsProvider : ISuggestionProvider { if (lastArg != node.Name && !subcommandsKey.Contains(lastArg)) continue; - yield return $"!{string.Join(' ', node.GetPath())} {subcommandsKey}"; + yield return $"!{string.Join(" ", node.GetPath())} {subcommandsKey}"; } } } \ No newline at end of file diff --git a/Torch.Tests/Properties/AssemblyInfo.cs b/Torch.Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index 1551025..0000000 --- a/Torch.Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("Torch Tests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Torch")] -[assembly: AssemblyCopyright("Copyright © Torch API 2017")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: ComVisible(false)] - -#if DEBUG -[assembly: AssemblyConfiguration("Debug")] -#else -[assembly: AssemblyConfiguration("Release")] -#endif \ No newline at end of file diff --git a/Torch.Tests/Torch.Tests.csproj b/Torch.Tests/Torch.Tests.csproj index d3e2c1f..25636f9 100644 --- a/Torch.Tests/Torch.Tests.csproj +++ b/Torch.Tests/Torch.Tests.csproj @@ -1,6 +1,7 @@  net6-windows + 10 1591,0649 Torch Tests Torch @@ -8,7 +9,6 @@ false MinimumRecommendedRules.ruleset $(SolutionDir)\bin-test\$(Platform)\$(Configuration)\ - False x64 Debug;Release AnyCPU @@ -27,13 +27,6 @@ - - - - - - - diff --git a/Torch.Tests/app.config b/Torch.Tests/app.config deleted file mode 100644 index cf4f4e1..0000000 --- a/Torch.Tests/app.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/Torch.sln b/Torch.sln index e44265d..093e776 100644 --- a/Torch.sln +++ b/Torch.sln @@ -12,17 +12,13 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7AD02A71-1D4C-48F9-A8C1-789A5512424F}" ProjectSection(SolutionItems) = preProject NLog.config = NLog.config + Jenkinsfile = Jenkinsfile EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.Tests", "Torch.Tests\Torch.Tests.csproj", "{C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.Server.Tests", "Torch.Server.Tests\Torch.Server.Tests.csproj", "{9EFD1D91-2FA2-47ED-B537-D8BC3B0E543E}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Versioning", "Versioning", "{762F6A0D-55EF-4173-8CDE-309D183F40C4}" - ProjectSection(SolutionItems) = preProject - Versioning\AssemblyVersion.cs = Versioning\AssemblyVersion.cs - EndProjectSection -EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Torch.Mod", "Torch.Mod\Torch.Mod.shproj", "{3CE4D2E9-B461-4F19-8233-F87E0DFDDD74}" EndProject Global @@ -56,7 +52,6 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {762F6A0D-55EF-4173-8CDE-309D183F40C4} = {7AD02A71-1D4C-48F9-A8C1-789A5512424F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB51D91F-958D-4B63-A897-3C40642ACD3E} diff --git a/Torch/ApplicationContext.cs b/Torch/ApplicationContext.cs new file mode 100644 index 0000000..e3a4b26 --- /dev/null +++ b/Torch/ApplicationContext.cs @@ -0,0 +1,32 @@ +using System.IO; +using Torch.API; +namespace Torch; + +public class ApplicationContext : IApplicationContext +{ + public static IApplicationContext Current { get; private set; } + public ApplicationContext(DirectoryInfo torchDirectory, DirectoryInfo gameFilesDirectory, DirectoryInfo gameBinariesDirectory, + DirectoryInfo instanceDirectory, string instanceName, bool isService) + { + TorchDirectory = torchDirectory; + GameFilesDirectory = gameFilesDirectory; + GameBinariesDirectory = gameBinariesDirectory; + InstanceDirectory = instanceDirectory; + InstanceName = instanceName; + IsService = isService; + Current = this; + } + + /// + public DirectoryInfo TorchDirectory { get; } + /// + public DirectoryInfo GameFilesDirectory { get; } + /// + public DirectoryInfo GameBinariesDirectory { get; } + /// + public DirectoryInfo InstanceDirectory { get; } + /// + public string InstanceName { get; } + /// + public bool IsService { get; } +} diff --git a/Torch/Patches/ScriptCompilerPatch.cs b/Torch/Patches/ScriptCompilerPatch.cs index 858210c..ae19e24 100644 --- a/Torch/Patches/ScriptCompilerPatch.cs +++ b/Torch/Patches/ScriptCompilerPatch.cs @@ -1,8 +1,10 @@ -using System; +#if !NETFRAMEWORK +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.ComponentModel; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; @@ -11,6 +13,8 @@ using System.Reflection.Emit; using System.Text.RegularExpressions; using System.Threading; using Microsoft.CodeAnalysis; +using ProtoBuf; +using ProtoBuf.Meta; using Torch.Managers.PatchManager; using Torch.Managers.PatchManager.MSIL; using Torch.Utils; @@ -55,9 +59,9 @@ namespace Torch.Patches typeof(ImmutableArray).Assembly.Location, typeof(PropertyChangedEventArgs).Assembly.Location, typeof(TypeConverter).Assembly.Location, - typeof(System.Diagnostics.TraceSource).Assembly.Location, - typeof(ProtoBuf.Meta.RuntimeTypeModel).Assembly.Location, - typeof(ProtoBuf.ProtoMemberAttribute).Assembly.Location, + typeof(TraceSource).Assembly.Location, + typeof(RuntimeTypeModel).Assembly.Location, + typeof(ProtoMemberAttribute).Assembly.Location, Path.Combine(MyFileSystem.ExePath, "Sandbox.Game.dll"), Path.Combine(MyFileSystem.ExePath, "Sandbox.Common.dll"), Path.Combine(MyFileSystem.ExePath, "Sandbox.Graphics.dll"), @@ -107,4 +111,5 @@ namespace Torch.Patches return ins; } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/Torch/Properties/AssemblyInfo.cs b/Torch/Properties/AssemblyInfo.cs index 21a30ba..e69de29 100644 --- a/Torch/Properties/AssemblyInfo.cs +++ b/Torch/Properties/AssemblyInfo.cs @@ -1,17 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("Torch")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Torch")] -[assembly: AssemblyCopyright("Copyright © Torch API 2017")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: ComVisible(false)] - -#if DEBUG -[assembly: AssemblyConfiguration("Debug")] -#else -[assembly: AssemblyConfiguration("Release")] -#endif \ No newline at end of file diff --git a/Torch/Torch.csproj b/Torch/Torch.csproj index 0d4e0cb..ea8bb18 100644 --- a/Torch/Torch.csproj +++ b/Torch/Torch.csproj @@ -1,6 +1,7 @@  net6-windows + 10 Torch Torch Copyright © Torch API 2017 @@ -8,7 +9,6 @@ true ..\bin\$(Platform)\$(Configuration)\ True - False x64 Debug;Release AnyCPU diff --git a/Torch/Utils/TorchLauncher.cs b/Torch/Utils/TorchLauncher.cs index a4cc6a6..93a8fed 100644 --- a/Torch/Utils/TorchLauncher.cs +++ b/Torch/Utils/TorchLauncher.cs @@ -1,14 +1,8 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; -using System.Runtime.Loader; -using System.Text; -using System.Threading.Tasks; -using ProtoBuf; -using Torch.API; namespace Torch.Utils { @@ -23,7 +17,13 @@ namespace Torch.Utils try { var name = AssemblyName.GetAssemblyName(file); - Assemblies.TryAdd(name.Name ?? name.FullName.Split(',')[0], file); + var key = name.Name ?? name.FullName.Split(',')[0]; +#if NETFRAMEWORK + if (!Assemblies.ContainsKey(key)) + Assemblies.Add(key, file); +#else + Assemblies.TryAdd(key, file); +#endif } catch (BadImageFormatException) { @@ -37,7 +37,7 @@ namespace Torch.Utils private static Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args) { var name = args.Name; - return Assemblies.TryGetValue(name[..name.IndexOf(',')], out var path) ? Assembly.LoadFrom(path) : null; + return Assemblies.TryGetValue(name.IndexOf(',') > 0 ? name.Substring(0, name.IndexOf(',')) : name, out var path) ? Assembly.LoadFrom(path) : null; } } } diff --git a/Torch/Utils/TorchLogManager.cs b/Torch/Utils/TorchLogManager.cs index 5adea49..bfe67cb 100644 --- a/Torch/Utils/TorchLogManager.cs +++ b/Torch/Utils/TorchLogManager.cs @@ -2,7 +2,9 @@ using System.IO; using System.Linq; using System.Reflection; +#if !NETFRAMEWORK using System.Runtime.Loader; +#endif using NLog; using NLog.Config; using NLog.Targets; @@ -11,7 +13,9 @@ namespace Torch.Utils; public static class TorchLogManager { +#if !NETFRAMEWORK private static AssemblyLoadContext LoadContext = new("TorchLog"); +#endif public static LoggingConfiguration Configuration { get; private set; } @@ -26,7 +30,12 @@ public static class TorchLogManager { if (!Directory.Exists(dir)) return; - foreach (var type in Directory.EnumerateFiles(dir, "*.dll").Select(LoadContext.LoadFromAssemblyPath) + foreach (var type in Directory.EnumerateFiles(dir, "*.dll") +#if NETFRAMEWORK + .Select(Assembly.LoadFile) +#else + .Select(LoadContext.LoadFromAssemblyPath) +#endif .SelectMany(b => b.ExportedTypes) .Where(b => b.GetCustomAttribute() is { })) { diff --git a/Versioning/AssemblyVersion.cs b/Versioning/AssemblyVersion.cs deleted file mode 100644 index c663bea..0000000 --- a/Versioning/AssemblyVersion.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyVersion("0.0.0.0")] -[assembly: AssemblyInformationalVersion("v0.0.0-dev")]