Merge remote-tracking branch 'zznty/master'

# Conflicts:
#	Torch.API/Torch.API.csproj
#	Torch/Patches/ScriptCompilerPatch.cs
This commit is contained in:
zznty
2022-05-08 12:36:22 +07:00
34 changed files with 430 additions and 274 deletions

5
Jenkins/get-version.ps1 Normal file
View File

@@ -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"

View File

@@ -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

55
Jenkinsfile vendored Normal file
View File

@@ -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
]]
])
}
*/
}

View File

@@ -0,0 +1,30 @@
using System.IO;
namespace Torch.API;
public interface IApplicationContext
{
/// <summary>
/// Directory contains torch binaries.
/// </summary>
public DirectoryInfo TorchDirectory { get; }
/// <summary>
/// Root directory for all game files.
/// </summary>
public DirectoryInfo GameFilesDirectory { get; }
/// <summary>
/// Directory contains game binaries.
/// </summary>
public DirectoryInfo GameBinariesDirectory { get; }
/// <summary>
/// Current instance directory.
/// </summary>
public DirectoryInfo InstanceDirectory { get; }
/// <summary>
/// Current instance name.
/// </summary>
public string InstanceName { get; }
/// <summary>
/// Application running in service mode.
/// </summary>
public bool IsService { get; }
}

View File

@@ -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

View File

@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6-windows</TargetFramework> <TargetFramework>net6-windows</TargetFramework>
<LangVersion>10</LangVersion>
<AssemblyTitle>Torch API</AssemblyTitle> <AssemblyTitle>Torch API</AssemblyTitle>
<Product>Torch</Product> <Product>Torch</Product>
<Copyright>Copyright © Torch API 2017</Copyright> <Copyright>Copyright © Torch API 2017</Copyright>
@@ -19,6 +20,9 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="NLog" Version="5.0.0-rc2" /> <PackageReference Include="NLog" Version="5.0.0-rc2" />
<PackageReference Include="SemanticVersioning" Version="2.0.2" /> <PackageReference Include="SemanticVersioning" Version="2.0.2" />
<PackageReference Include="System.Text.Json" Version="6.0.2" Condition="$(TargetFramework) == 'net48'" />
<PackageReference Include="System.Net.Http" Version="4.3.4" Condition="$(TargetFramework) == 'net48'" />
<PackageReference Include="System.Net.Http.Json" Version="6.0.0" Condition="$(TargetFramework) == 'net48'" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="HavokWrapper, Version=1.0.6278.22649, Culture=neutral, processorArchitecture=AMD64"> <Reference Include="HavokWrapper, Version=1.0.6278.22649, Culture=neutral, processorArchitecture=AMD64">

View File

@@ -0,0 +1,8 @@
#if NETFRAMEWORK
// ReSharper disable once CheckNamespace
namespace System.Runtime.CompilerServices;
public class IsExternalInit
{
}
#endif

View File

@@ -68,7 +68,11 @@ namespace Torch.API.WebAPI
return false; return false;
} }
var s = await h.Content.ReadAsStreamAsync(); var s = await h.Content.ReadAsStreamAsync();
#if !NETFRAMEWORK
await using var fs = new FileStream(path, FileMode.Create); await using var fs = new FileStream(path, FileMode.Create);
#else
using var fs = new FileStream(path, FileMode.Create);
#endif
await s.CopyToAsync(fs); await s.CopyToAsync(fs);
return true; return true;
} }

View File

@@ -78,7 +78,11 @@ namespace Torch.API.WebAPI
if(File.Exists(path)) if(File.Exists(path))
File.Delete(path); File.Delete(path);
#if NETFRAMEWORK
using var f = File.Create(path);
#else
await using var f = File.Create(path); await using var f = File.Create(path);
#endif
await s.CopyToAsync(f); await s.CopyToAsync(f);
} }
catch (Exception ex) catch (Exception ex)

View File

@@ -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

View File

@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6-windows</TargetFramework> <TargetFramework>net6-windows</TargetFramework>
<LangVersion>10</LangVersion>
<NoWarn>1591,0649</NoWarn> <NoWarn>1591,0649</NoWarn>
<AssemblyTitle>Torch Server Tests</AssemblyTitle> <AssemblyTitle>Torch Server Tests</AssemblyTitle>
<Product>Torch</Product> <Product>Torch</Product>
@@ -27,9 +28,6 @@
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Compile Include="..\Versioning\AssemblyVersion.cs" Link="Properties\AssemblyVersion.cs" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Torch.API\Torch.API.csproj" /> <ProjectReference Include="..\Torch.API\Torch.API.csproj" />
<ProjectReference Include="..\Torch.Server\Torch.Server.csproj" /> <ProjectReference Include="..\Torch.Server\Torch.Server.csproj" />

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="protobuf-net" publicKeyToken="257b51d87d2e4d67" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-2.4.0.0" newVersion="2.4.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/></startup></configuration>

View File

@@ -29,19 +29,14 @@ namespace Torch.Server
private const string STEAMCMD_DIR = "steamcmd"; private const string STEAMCMD_DIR = "steamcmd";
private const string STEAMCMD_ZIP = "temp.zip"; private const string STEAMCMD_ZIP = "temp.zip";
private static readonly string STEAMCMD_EXE = "steamcmd.exe"; private static readonly string STEAMCMD_EXE = "steamcmd.exe";
private static readonly string RUNSCRIPT_FILE = "runscript.txt"; private const string STEAMCMD_ARGS = "+force_install_dir \"{0}\" +login anonymous +app_update 298740 +quit";
private const string RUNSCRIPT = @"force_install_dir ../
login anonymous
app_update 298740
quit";
private TorchServer _server; private TorchServer _server;
internal Persistent<TorchConfig> ConfigPersistent { get; } internal Persistent<TorchConfig> ConfigPersistent { get; }
public TorchConfig Config => ConfigPersistent?.Data; public TorchConfig Config => ConfigPersistent?.Data;
public TorchServer Server => _server; public TorchServer Server => _server;
public Initializer(string basePath, Persistent<TorchConfig> torchConfig) public Initializer(Persistent<TorchConfig> torchConfig)
{ {
Instance = this; Instance = this;
ConfigPersistent = torchConfig; ConfigPersistent = torchConfig;
@@ -88,11 +83,11 @@ quit";
return true; 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.Init();
_server.Start(); _server.Start();
@@ -140,10 +135,6 @@ quit";
Directory.CreateDirectory(path); Directory.CreateDirectory(path);
} }
var runScriptPath = Path.Combine(path, RUNSCRIPT_FILE);
if (!File.Exists(runScriptPath))
File.WriteAllText(runScriptPath, RUNSCRIPT);
var steamCmdExePath = Path.Combine(path, STEAMCMD_EXE); var steamCmdExePath = Path.Combine(path, STEAMCMD_EXE);
if (!File.Exists(steamCmdExePath)) if (!File.Exists(steamCmdExePath))
{ {
@@ -166,8 +157,9 @@ quit";
} }
log.Info("Checking for DS updates."); log.Info("Checking for DS updates.");
var steamCmdProc = new ProcessStartInfo(steamCmdExePath, "+runscript runscript.txt") var steamCmdProc = new ProcessStartInfo(steamCmdExePath)
{ {
Arguments = string.Format(STEAMCMD_ARGS, Environment.GetEnvironmentVariable("TORCH_GAME_PATH") ?? "../"),
WorkingDirectory = path, WorkingDirectory = path,
UseShellExecute = false, UseShellExecute = false,
RedirectStandardOutput = true, RedirectStandardOutput = true,

View File

@@ -40,7 +40,13 @@ namespace Torch.Server.Managers
protected abstract EntityControlViewModel Create(EntityViewModel evm); protected abstract EntityControlViewModel Create(EntityViewModel evm);
#if NETFRAMEWORK
[ReflectedGetter(Name = "Keys")]
private static readonly Func<ConditionalWeakTable<EntityViewModel, EntityControlViewModel>, ICollection<EntityViewModel>> WeakTableKeys = null!;
internal IEnumerable<EntityViewModel> Keys => WeakTableKeys(_models);
#else
internal IEnumerable<EntityViewModel> Keys => _models.Select(b => b.Key); internal IEnumerable<EntityViewModel> Keys => _models.Select(b => b.Key);
#endif
internal EntityControlViewModel GetOrCreate(EntityViewModel evm) internal EntityControlViewModel GetOrCreate(EntityViewModel evm)
{ {

View File

@@ -3,6 +3,7 @@ using System.IO;
using NLog; using NLog;
using NLog.Config; using NLog.Config;
using NLog.Targets; using NLog.Targets;
using Torch.API;
using Torch.Utils; using Torch.Utils;
namespace Torch.Server namespace Torch.Server
@@ -12,112 +13,71 @@ namespace Torch.Server
[STAThread] [STAThread]
public static void Main(string[] args) public static void Main(string[] args)
{ {
var isService = Environment.GetEnvironmentVariable("TORCH_SERVICE") var context = CreateApplicationContext();
?.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)) SetupLogging();
foreach (var file in Directory.GetFiles(binDir, "System.*.dll"))
{
File.Delete(file);
}
// Breaks on Windows Server 2019 var oldTorchCfg = Path.Combine(context.TorchDirectory.FullName, "Torch.cfg");
#if TORCH_SERVICE var torchCfg = Path.Combine(context.InstanceDirectory.FullName, "Torch.cfg");
if (!new ComputerInfo().OSFullName.Contains("Server 2019") && !Environment.UserInteractive)
{
using (var service = new TorchService(args))
ServiceBase.Run(service);
return;
}
#endif
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");
if (File.Exists(oldTorchCfg)) if (File.Exists(oldTorchCfg))
File.Move(oldTorchCfg, torchCfg, true); File.Move(oldTorchCfg, torchCfg);
var config = Persistent<TorchConfig>.Load(torchCfg); var config = Persistent<TorchConfig>.Load(torchCfg);
config.Data.InstanceName = instanceName; config.Data.InstanceName = context.InstanceName;
config.Data.InstancePath = instancePath; config.Data.InstancePath = context.InstanceDirectory.FullName;
if (!config.Data.Parse(args)) if (!config.Data.Parse(args))
{ {
Console.WriteLine("Invalid arguments"); Console.WriteLine("Invalid arguments");
Environment.Exit(1); Environment.Exit(1);
} }
var handler = new UnhandledExceptionHandler(config.Data, isService); var handler = new UnhandledExceptionHandler(config.Data);
AppDomain.CurrentDomain.UnhandledException += handler.OnUnhandledException; AppDomain.CurrentDomain.UnhandledException += handler.OnUnhandledException;
Target.Register<LogViewerTarget>(nameof(LogViewerTarget)); var initializer = new Initializer(config);
TorchLogManager.RegisterTargets(Environment.GetEnvironmentVariable("TORCH_LOG_EXTENSIONS_PATH") ??
Path.Combine(instancePath, "LoggingExtensions"));
TorchLogManager.SetConfiguration(new XmlLoggingConfiguration(newNlog));
var initializer = new Initializer(workingDir, config);
if (!initializer.Initialize(args)) if (!initializer.Initialize(args))
Environment.Exit(1); 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 log = LogManager.GetLogger("TorchLauncher");
var workingDir = new DirectoryInfo(Directory.GetCurrentDirectory()); if (ApplicationContext.Current.GameFilesDirectory.Attributes.HasFlag(FileAttributes.ReadOnly))
if (workingDir.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; return;
} }
try try
{ {
var apiSource = Path.Combine(binPath, "steam_api64.dll"); var apiSource = Path.Combine(ApplicationContext.Current.GameBinariesDirectory.FullName, "steam_api64.dll");
var apiTarget = Path.Combine(workingDir.FullName, "steam_api64.dll"); var apiTarget = Path.Combine(ApplicationContext.Current.GameFilesDirectory.FullName, "steam_api64.dll");
if (!File.Exists(apiTarget)) if (!File.Exists(apiTarget))
{ {
File.Copy(apiSource, 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.Delete(apiTarget);
File.Copy(apiSource, apiTarget); File.Copy(apiSource, apiTarget);
} }
var havokSource = Path.Combine(binPath, "Havok.dll"); var havokSource = Path.Combine(ApplicationContext.Current.GameBinariesDirectory.FullName, "Havok.dll");
var havokTarget = Path.Combine(workingDir.FullName, "Havok.dll"); var havokTarget = Path.Combine(ApplicationContext.Current.GameFilesDirectory.FullName, "Havok.dll");
if (!File.Exists(havokTarget)) if (!File.Exists(havokTarget))
{ {
@@ -138,5 +98,49 @@ namespace Torch.Server
log.Error(e); 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<LogViewerTarget>(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);
}
} }
} }

View File

@@ -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

View File

@@ -2,11 +2,10 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net6-windows</TargetFramework> <TargetFramework>net6-windows</TargetFramework>
<LangVersion>10</LangVersion>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<PublishUrl>publish\</PublishUrl> <PublishUrl>publish\</PublishUrl>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust> <UseApplicationTrust>false</UseApplicationTrust>
<AssemblyTitle>Torch Server</AssemblyTitle> <AssemblyTitle>Torch Server</AssemblyTitle>
<Product>Torch</Product> <Product>Torch</Product>
@@ -14,13 +13,16 @@
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<OutputPath>..\bin\$(Platform)\$(Configuration)\</OutputPath> <OutputPath>..\bin\$(Platform)\$(Configuration)\</OutputPath>
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages> <SatelliteResourceLanguages>en</SatelliteResourceLanguages>
<PlatformTarget>x64</PlatformTarget> <PlatformTarget>x64</PlatformTarget>
<Configurations>Debug;Release</Configurations> <Configurations>Debug;Release</Configurations>
<Platforms>AnyCPU</Platforms> <Platforms>AnyCPU</Platforms>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<NeutralLanguage>en</NeutralLanguage> <NeutralLanguage>en</NeutralLanguage>
<BeautyLibsDir>torch64</BeautyLibsDir>
<NoBeautyFlag>True</NoBeautyFlag>
<ForceBeauty>True</ForceBeauty>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<StartupObject>Torch.Server.Program</StartupObject> <StartupObject>Torch.Server.Program</StartupObject>
@@ -40,6 +42,7 @@
<PackageReference Include="PropertyChanged.Fody" Version="4.0.0" PrivateAssets="all" /> <PackageReference Include="PropertyChanged.Fody" Version="4.0.0" PrivateAssets="all" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.Management" Version="6.0.0" /> <PackageReference Include="System.Management" Version="6.0.0" />
<PackageReference Include="nulastudio.NetCoreBeauty" Version="1.2.9.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="HavokWrapper, Version=1.0.6051.28726, Culture=neutral, processorArchitecture=AMD64"> <Reference Include="HavokWrapper, Version=1.0.6051.28726, Culture=neutral, processorArchitecture=AMD64">
@@ -143,7 +146,6 @@
<Compile Remove="ServerManager.cs" /> <Compile Remove="ServerManager.cs" />
<Compile Remove="ViewModels\SessionSettingsViewModel1.cs" /> <Compile Remove="ViewModels\SessionSettingsViewModel1.cs" />
<Compile Remove="Views\WorldSelectControl.xaml.cs" /> <Compile Remove="Views\WorldSelectControl.xaml.cs" />
<Compile Include="..\Versioning\AssemblyVersion.cs" Link="Properties/AssemblyVersion.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Torch.API\Torch.API.csproj" /> <ProjectReference Include="..\Torch.API\Torch.API.csproj" />

View File

@@ -221,7 +221,11 @@ namespace Torch.Server
LogManager.Flush(); LogManager.Flush();
string exe = Assembly.GetExecutingAssembly().Location.Replace("dll", "exe"); string exe = Assembly.GetExecutingAssembly().Location.Replace("dll", "exe");
#if NETFRAMEWORK
config.WaitForPID = Process.GetCurrentProcess().Id.ToString();
#else
config.WaitForPID = Environment.ProcessId.ToString(); config.WaitForPID = Environment.ProcessId.ToString();
#endif
config.TempAutostart = true; config.TempAutostart = true;
Process.Start(exe, config.ToString()); Process.Start(exe, config.ToString());
@@ -370,8 +374,11 @@ namespace Torch.Server
// return stack.ToString(); // return stack.ToString();
// Modified from https://www.examplefiles.net/cs/579311 // Modified from https://www.examplefiles.net/cs/579311
using (var target = DataTarget.CreateSnapshotAndAttach(Environment.ProcessId)) #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 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);
@@ -399,7 +406,6 @@ namespace Torch.Server
return sb.ToString(); return sb.ToString();
} }
}
#endregion #endregion
} }

View File

@@ -9,13 +9,11 @@ namespace Torch.Server;
internal class UnhandledExceptionHandler internal class UnhandledExceptionHandler
{ {
private readonly TorchConfig _config; private readonly TorchConfig _config;
private readonly bool _isService;
private static readonly ILogger Log = LogManager.GetCurrentClassLogger(); private static readonly ILogger Log = LogManager.GetCurrentClassLogger();
public UnhandledExceptionHandler(TorchConfig config, bool isService) public UnhandledExceptionHandler(TorchConfig config)
{ {
_config = config; _config = config;
_isService = isService;
} }
internal void OnUnhandledException(object sender, UnhandledExceptionEventArgs e) internal void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
@@ -26,7 +24,7 @@ internal class UnhandledExceptionHandler
Log.Fatal(ex.ToStringDemystified()); Log.Fatal(ex.ToStringDemystified());
LogManager.Flush(); LogManager.Flush();
if (_isService) if (ApplicationContext.Current.IsService)
Environment.Exit(1); Environment.Exit(1);
if (_config.RestartOnCrash) if (_config.RestartOnCrash)
@@ -34,7 +32,11 @@ internal class UnhandledExceptionHandler
Console.WriteLine("Restarting in 5 seconds."); Console.WriteLine("Restarting in 5 seconds.");
Thread.Sleep(5000); Thread.Sleep(5000);
var exe = typeof(Program).Assembly.Location; var exe = typeof(Program).Assembly.Location;
#if NETFRAMEWORK
_config.WaitForPID = Process.GetCurrentProcess().Id.ToString();
#else
_config.WaitForPID = Environment.ProcessId.ToString(); _config.WaitForPID = Environment.ProcessId.ToString();
#endif
Process.Start(exe, _config.ToString()); Process.Start(exe, _config.ToString());
} }
else else

View File

@@ -32,7 +32,7 @@ public class CommandSuggestionsProvider : ISuggestionProvider
{ {
if (_commandManager is null || !_commandManager.IsCommand(filter)) if (_commandManager is null || !_commandManager.IsCommand(filter))
yield break; yield break;
var args = filter[1..].Split(' ').ToList(); var args = filter.Substring(1).Split(' ').ToList();
var skip = _commandManager.Commands.GetNode(args, out var node); var skip = _commandManager.Commands.GetNode(args, out var node);
if (skip == -1) if (skip == -1)
yield break; yield break;
@@ -42,7 +42,7 @@ public class CommandSuggestionsProvider : ISuggestionProvider
{ {
if (lastArg != node.Name && !subcommandsKey.Contains(lastArg)) if (lastArg != node.Name && !subcommandsKey.Contains(lastArg))
continue; continue;
yield return $"!{string.Join(' ', node.GetPath())} {subcommandsKey}"; yield return $"!{string.Join(" ", node.GetPath())} {subcommandsKey}";
} }
} }
} }

View File

@@ -130,17 +130,17 @@ namespace Torch.Server.Views
//blocking //blocking
editor.Edit<string>(idList, "Mods"); editor.Edit<string>(idList, "Mods");
modList.RemoveAll(m => modList.Clear();
{
var mod = m.ToString();
return idList.Any(mod.Equals);
});
modList.AddRange(idList.Select(id => modList.AddRange(idList.Select(id =>
{ {
var info = new ModItemInfo(ModItemUtils.Create(id)); if (!ModItemUtils.TryParse(id, out var item))
return null;
var info = new ModItemInfo(item);
tasks.Add(Task.Run(info.UpdateModInfoAsync)); tasks.Add(Task.Run(info.UpdateModInfoAsync));
return info; return info;
})); }).Where(b => b is not null));
_instanceManager.DedicatedConfig.Mods.Clear(); _instanceManager.DedicatedConfig.Mods.Clear();
foreach (var mod in modList) foreach (var mod in modList)
_instanceManager.DedicatedConfig.Mods.Add(mod); _instanceManager.DedicatedConfig.Mods.Add(mod);

View File

@@ -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

View File

@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6-windows</TargetFramework> <TargetFramework>net6-windows</TargetFramework>
<LangVersion>10</LangVersion>
<NoWarn>1591,0649</NoWarn> <NoWarn>1591,0649</NoWarn>
<AssemblyTitle>Torch Tests</AssemblyTitle> <AssemblyTitle>Torch Tests</AssemblyTitle>
<Product>Torch</Product> <Product>Torch</Product>
@@ -8,7 +9,6 @@
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<OutputPath>$(SolutionDir)\bin-test\$(Platform)\$(Configuration)\</OutputPath> <OutputPath>$(SolutionDir)\bin-test\$(Platform)\$(Configuration)\</OutputPath>
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>
<PlatformTarget>x64</PlatformTarget> <PlatformTarget>x64</PlatformTarget>
<Configurations>Debug;Release</Configurations> <Configurations>Debug;Release</Configurations>
<Platforms>AnyCPU</Platforms> <Platforms>AnyCPU</Platforms>
@@ -27,13 +27,6 @@
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
<Reference Include="System.Net.Http" /> <Reference Include="System.Net.Http" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Reference Include="mscorlib" />
<Reference Include="netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Versioning\AssemblyVersion.cs" Link="Properties/AssemblyVersion.cs" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Torch.API\Torch.API.csproj" /> <ProjectReference Include="..\Torch.API\Torch.API.csproj" />
<ProjectReference Include="..\Torch\Torch.csproj" /> <ProjectReference Include="..\Torch\Torch.csproj" />

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="protobuf-net" publicKeyToken="257b51d87d2e4d67" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-2.4.0.0" newVersion="2.4.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/></startup></configuration>

View File

@@ -12,17 +12,13 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7AD02A71-1D4C-48F9-A8C1-789A5512424F}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7AD02A71-1D4C-48F9-A8C1-789A5512424F}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
NLog.config = NLog.config NLog.config = NLog.config
Jenkinsfile = Jenkinsfile
EndProjectSection EndProjectSection
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.Tests", "Torch.Tests\Torch.Tests.csproj", "{C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.Tests", "Torch.Tests\Torch.Tests.csproj", "{C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.Server.Tests", "Torch.Server.Tests\Torch.Server.Tests.csproj", "{9EFD1D91-2FA2-47ED-B537-D8BC3B0E543E}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.Server.Tests", "Torch.Server.Tests\Torch.Server.Tests.csproj", "{9EFD1D91-2FA2-47ED-B537-D8BC3B0E543E}"
EndProject 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}" Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Torch.Mod", "Torch.Mod\Torch.Mod.shproj", "{3CE4D2E9-B461-4F19-8233-F87E0DFDDD74}"
EndProject EndProject
Global Global
@@ -56,7 +52,6 @@ Global
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{762F6A0D-55EF-4173-8CDE-309D183F40C4} = {7AD02A71-1D4C-48F9-A8C1-789A5512424F}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB51D91F-958D-4B63-A897-3C40642ACD3E} SolutionGuid = {BB51D91F-958D-4B63-A897-3C40642ACD3E}

View File

@@ -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;
}
/// <inheritdoc />
public DirectoryInfo TorchDirectory { get; }
/// <inheritdoc />
public DirectoryInfo GameFilesDirectory { get; }
/// <inheritdoc />
public DirectoryInfo GameBinariesDirectory { get; }
/// <inheritdoc />
public DirectoryInfo InstanceDirectory { get; }
/// <inheritdoc />
public string InstanceName { get; }
/// <inheritdoc />
public bool IsService { get; }
}

View File

@@ -1,34 +1,52 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using Mono.Cecil; using Mono.Cecil;
using NLog;
namespace Torch.Plugins; namespace Torch.Plugins;
internal static class AssemblyRewriter internal static class AssemblyRewriter
{ {
private static readonly ILogger Log = LogManager.GetCurrentClassLogger(); private static readonly ZipResolver _zipResolver;
private static readonly DefaultAssemblyResolver _defaultResolver;
private static readonly IAssemblyResolver Resolver;
static AssemblyRewriter() static AssemblyRewriter()
{ {
var resolver = new DefaultAssemblyResolver(); _defaultResolver = new();
Resolver = resolver; _zipResolver = new(_defaultResolver);
resolver.AddSearchDirectory(Directory.GetCurrentDirectory()); _defaultResolver.AddSearchDirectory(Directory.GetCurrentDirectory());
resolver.AddSearchDirectory(Path.Combine(Directory.GetCurrentDirectory(), "DedicatedServer64")); _defaultResolver.AddSearchDirectory(Path.Combine(Directory.GetCurrentDirectory(), "DedicatedServer64"));
} }
public static Assembly ProcessWeavers(this Stream stream) public static Assembly ProcessWeavers(this Stream stream, ZipArchive archive)
{ {
_zipResolver.Archive = archive;
using var assStream = new MemoryStream(); using var assStream = new MemoryStream();
stream.CopyTo(assStream); stream.CopyTo(assStream);
assStream.Position = 0; assStream.Position = 0;
using var module = ModuleDefinition.ReadModule(assStream, new() var ass = ProcessInternal(assStream, _zipResolver);
_zipResolver.Archive = null;
return ass;
}
public static Assembly ProcessWeavers(this Stream stream, string path)
{ {
AssemblyResolver = Resolver _defaultResolver.AddSearchDirectory(path);
using var assStream = new MemoryStream();
stream.CopyTo(assStream);
assStream.Position = 0;
var ass = ProcessInternal(assStream, _defaultResolver);
_defaultResolver.RemoveSearchDirectory(path);
return ass;
}
private static Assembly ProcessInternal(Stream inputStream, IAssemblyResolver resolver)
{
using var module = ModuleDefinition.ReadModule(inputStream, new()
{
AssemblyResolver = _zipResolver
}); });
foreach (var fieldDefinition in FindAllToRewrite(module)) foreach (var fieldDefinition in FindAllToRewrite(module))
{ {
@@ -47,4 +65,40 @@ internal static class AssemblyRewriter
private static bool HasValidAttributes(FieldDefinition definition) => private static bool HasValidAttributes(FieldDefinition definition) =>
definition.CustomAttributes.Any(b => b.AttributeType.Name.Contains("Reflected") || b.AttributeType.Name == "DependencyAttribute"); definition.CustomAttributes.Any(b => b.AttributeType.Name.Contains("Reflected") || b.AttributeType.Name == "DependencyAttribute");
private class ZipResolver : IAssemblyResolver
{
private readonly IAssemblyResolver _fallbackResolver;
public ZipArchive Archive { get; set; }
public ZipResolver(IAssemblyResolver fallbackResolver)
{
_fallbackResolver = fallbackResolver;
}
public void Dispose()
{
_fallbackResolver.Dispose();
}
public AssemblyDefinition Resolve(AssemblyNameReference name)
{
return Resolve(name, new());
}
public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
{
var fileName = $"{name.Name}.dll";
if (Archive.Entries.FirstOrDefault(entry => entry.Name == fileName) is not { } archiveEntry)
return _fallbackResolver.Resolve(name, parameters);
using var stream = archiveEntry.Open();
using var memStream = new MemoryStream();
stream.CopyTo(memStream);
memStream.Position = 0;
return AssemblyDefinition.ReadAssembly(memStream, parameters);
}
}
} }

View File

@@ -360,7 +360,7 @@ namespace Torch.Managers
using var stream = entry.Open(); using var stream = entry.Open();
assemblies.Add(stream.ProcessWeavers()); assemblies.Add(stream.ProcessWeavers(zipFile));
} }
} }
else else
@@ -378,7 +378,7 @@ namespace Torch.Managers
// continue; // continue;
using var stream = File.OpenRead(file); using var stream = File.OpenRead(file);
assemblies.Add(stream.ProcessWeavers()); assemblies.Add(stream.ProcessWeavers(item.Path));
} }

View File

@@ -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

View File

@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6-windows</TargetFramework> <TargetFramework>net6-windows</TargetFramework>
<LangVersion>10</LangVersion>
<AssemblyTitle>Torch</AssemblyTitle> <AssemblyTitle>Torch</AssemblyTitle>
<Product>Torch</Product> <Product>Torch</Product>
<Copyright>Copyright © Torch API 2017</Copyright> <Copyright>Copyright © Torch API 2017</Copyright>
@@ -8,7 +9,6 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<OutputPath>..\bin\$(Platform)\$(Configuration)\</OutputPath> <OutputPath>..\bin\$(Platform)\$(Configuration)\</OutputPath>
<UseWpf>True</UseWpf> <UseWpf>True</UseWpf>
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>
<PlatformTarget>x64</PlatformTarget> <PlatformTarget>x64</PlatformTarget>
<Configurations>Debug;Release</Configurations> <Configurations>Debug;Release</Configurations>
<Platforms>AnyCPU</Platforms> <Platforms>AnyCPU</Platforms>

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Sandbox.Engine.Networking; using Sandbox.Engine.Networking;
using Torch.API; using Torch.API;
@@ -19,6 +20,43 @@ namespace Torch.Utils
return new MyObjectBuilder_Checkpoint.ModItem(ulong.Parse(arr[0]), arr[1]); return new MyObjectBuilder_Checkpoint.ModItem(ulong.Parse(arr[0]), arr[1]);
} }
public static bool TryParse(string str, out MyObjectBuilder_Checkpoint.ModItem item)
{
item = default;
var arr = str.Split('-');
if (arr.Length is 0 or > 2)
return false;
if (!ulong.TryParse(arr[0], out var id))
return false;
if (arr.Length == 1 || !TryParseServiceName(arr[1], out var serviceName))
serviceName = GetDefaultServiceName();
item = new(id, serviceName);
return true;
}
public static bool TryParseServiceName(string str, out string serviceName)
{
if (str.Equals("steam", StringComparison.OrdinalIgnoreCase))
{
serviceName = "Steam";
return true;
}
if (str.Equals("mod.io", StringComparison.OrdinalIgnoreCase) ||
str.Equals("eos", StringComparison.OrdinalIgnoreCase))
{
serviceName = "mod.io";
return true;
}
serviceName = null;
return false;
}
//because KEEEN! //because KEEEN!
public static string GetDefaultServiceName() public static string GetDefaultServiceName()
{ {

View File

@@ -1,14 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.Loader;
using System.Text;
using System.Threading.Tasks;
using ProtoBuf;
using Torch.API;
namespace Torch.Utils namespace Torch.Utils
{ {
@@ -23,7 +17,13 @@ namespace Torch.Utils
try try
{ {
var name = AssemblyName.GetAssemblyName(file); 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) catch (BadImageFormatException)
{ {
@@ -37,7 +37,7 @@ namespace Torch.Utils
private static Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args) private static Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args)
{ {
var name = args.Name; 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;
} }
} }
} }

View File

@@ -2,7 +2,9 @@
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
#if !NETFRAMEWORK
using System.Runtime.Loader; using System.Runtime.Loader;
#endif
using NLog; using NLog;
using NLog.Config; using NLog.Config;
using NLog.Targets; using NLog.Targets;
@@ -11,7 +13,9 @@ namespace Torch.Utils;
public static class TorchLogManager public static class TorchLogManager
{ {
#if !NETFRAMEWORK
private static AssemblyLoadContext LoadContext = new("TorchLog"); private static AssemblyLoadContext LoadContext = new("TorchLog");
#endif
public static LoggingConfiguration Configuration { get; private set; } public static LoggingConfiguration Configuration { get; private set; }
@@ -26,7 +30,12 @@ public static class TorchLogManager
{ {
if (!Directory.Exists(dir)) return; 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) .SelectMany(b => b.ExportedTypes)
.Where(b => b.GetCustomAttribute<TargetAttribute>() is { })) .Where(b => b.GetCustomAttribute<TargetAttribute>() is { }))
{ {

View File

@@ -1,4 +0,0 @@
using System.Reflection;
[assembly: AssemblyVersion("0.0.0.0")]
[assembly: AssemblyInformationalVersion("v0.0.0-dev")]