Compare commits

..

24 Commits

Author SHA1 Message Date
zznty
6f886d4f7d fix for releases 2022-10-09 20:28:58 +07:00
zznty
a753abb8fd i love github and windows 2022-10-09 20:25:00 +07:00
zznty
452970d2fd add nuget source to ci 2022-10-09 20:14:25 +07:00
zznty
e28c38e04f update ci 2022-10-09 20:07:08 +07:00
zznty
5d9fe01c69 Update README.md 2022-10-09 15:58:28 +03:00
zznty
04227912b0 github ci 2022-10-09 19:55:22 +07:00
zznty
44dd0805e2 get rid of old ci files 2022-10-09 17:54:36 +07:00
zznty
c5c8e527da projects cleanup 2022-10-09 17:52:30 +07:00
zznty
49f68a8fcc allow selection for log lines 2022-10-09 17:51:45 +07:00
zznty
f8a3647308 seems to be configuration rework 2022-09-09 16:48:14 +07:00
zznty
0a40b1fe0f move some parts of main class to other
fix poorly implemented features
2022-06-05 15:50:03 +07:00
zznty
a1e9434444 remove compat for netframework 2022-06-05 15:43:15 +07:00
zznty
d2d96df8be fix csproj 2022-05-08 12:39:09 +07:00
zznty
b40f288827 Merge remote-tracking branch 'zznty/master'
# Conflicts:
#	Torch.API/Torch.API.csproj
#	Torch/Patches/ScriptCompilerPatch.cs
2022-05-08 12:36:22 +07:00
zznty
6267cffebe update packages 2022-05-08 12:30:05 +07:00
zznty
5fe25fb781 ship harmony with torch to prevent crashes due to runtime version mismatch
add warning if plugin is using harmony
update monomod package
2022-05-08 12:26:31 +07:00
zznty
d05e979ede remove unnecessary async lambda 2022-05-08 12:25:06 +07:00
zznty
1afb126cb5 fix plugin downloading on separated runtime directory 2022-05-08 12:24:38 +07:00
zznty
d52348149a fix scripts compilation 2022-05-08 11:44:12 +07:00
zznty
20eac508d3 clean up project files 2022-05-08 11:22:39 +07:00
zznty
8ba02a84d3 correct logging indent 2022-05-08 11:22:14 +07:00
zznty
15be85b4f5 forced lang version to 10 (as ryo requested)
all libs are now packed into directory
jenkins file is back
some directives to get net48 supported too
2022-03-16 20:34:01 +07:00
zznty
cf5c00ce0e fixed steamcmd path does not follow TORCH_GAME_PATH env variable 2022-03-07 13:25:38 +07:00
zznty
9c185d5577 fixed mods not being properly cleared from bulk edit
fixed bulk edit crash if input format is invalid
2022-03-05 20:19:01 +07:00
74 changed files with 563 additions and 2180 deletions

73
.github/workflows/release.yaml vendored Normal file
View File

@@ -0,0 +1,73 @@
name: Release
on:
push:
tags:
- '*'
jobs:
build:
name: Build
runs-on: windows-latest
env:
VERSION: ${{ github.ref_name }}
BUILD_CONFIGURATION: Release
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
steps:
- uses: actions/checkout@master
name: Checkout
- uses: actions/setup-dotnet@v3
name: Setup dotnet
with:
dotnet-version: '6.0.x'
- uses: actions/cache@v1
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
restore-keys: |
${{ runner.os }}-nuget-
- name: Add Gh Packages Nuget Source
run: dotnet nuget add source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" --username ${{ github.actor }} --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text --name github
- name: Restore dependencies
run: dotnet restore Torch.Server/Torch.Server.csproj --use-lock-file
- name: Build
run: dotnet build Torch.Server/Torch.Server.csproj --no-restore -c $env:BUILD_CONFIGURATION /p:AssemblyVersion=$env:VERSION /p:Version=$env:VERSION
- name: Publish
run: dotnet publish Torch.Server/Torch.Server.csproj --no-build -r win-x64 --sc -c $env:BUILD_CONFIGURATION
- uses: vimtor/action-zip@v1
name: Zip Release
with:
files: publish/
dest: release.zip
- name: Build Changelog
id: build_changelog
uses: mikepenz/release-changelog-builder-action@v3
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ env.VERSION }}
release_name: Release v${{ env.VERSION }}
body: ${{ steps.github_release.outputs.changelog }}
draft: true
prerelease: false
- name: Upload release asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: release.zip
asset_name: torch-server.zip
asset_content_type: application/zip
- name: Publish release
uses: StuYarrow/publish-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
id: ${{ steps.create_release.outputs.id }}

View File

@@ -1,33 +0,0 @@
# Torch 1.1.229.265
* Features
- Added more lenient version parsing for plugins (v#.# should work)
- Added countdown option to restart command (!restart [seconds])
* Fixes
- General fixes to work with the latest SE version
- Fixed config changes not saving
- (hopefully) Fixed issue causing crashes on servers using the Windows Classic theme
# Torch 1.1.207.7
* Notes
- This release makes significant changes to TorchConfig.xml. It has been renamed to Torch.cfg and has different options.
* Features
- Plugins, Torch, and the DS can now all update automatically
- Changed command prefix to !
- Added manual save command (thanks to Maldark)
- Added restart command
- Improved instance creation: now creates an entire skeleton instance with blank config
- Added instance name to console title
* Fixes
- Optimized UI so it's snappier and freezes less often
- Fixed NetworkManager.RaiseEvent overload that had an off-by-one bug
- Fixed chat window so it automatically scrolls down
# Torch 1.0.182.329
* Improved logging, logs now to go the Logs folder and aren't deleted on start
* Fixed chat tab not enabling with -autostart
* Fixed player list
* Watchdog time-out is now configurable in TorchConfig.xml
* Fixed infinario log spam
* Fixed crash when sending empty message from chat tab
* Fixed permissions on Torch commands
* Changed plugin StoragePath to the current instance path (per-instance configs)

View File

@@ -1,5 +1,3 @@
[![Build status](https://ci.appveyor.com/api/projects/status/us64kmwshl50f5a3/branch/master?svg=true)](https://ci.appveyor.com/project/zznty/torch/branch/master)
# What is Torch?
Torch is the successor to SE Server Extender and gives server admins the tools they need to keep their Space Engineers servers running smoothly. It features a user interface with live management tools and a plugin system so you can run your server exactly how you'd like. Torch is still in early development so there may be bugs and incomplete features.

View File

@@ -1,13 +0,0 @@
:: This script creates a symlink to the game binaries to account for different installation directories on different systems.
@echo off
set /p path="Please enter the folder location of your SpaceEngineersDedicated.exe: "
cd %~dp0
mklink /J GameBinaries "%path%"
if errorlevel 1 goto Error
echo Done! You can now open the Torch solution without issue.
goto End
:Error
echo An error occured creating the symlink.
:End
pause

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

@@ -16,30 +16,6 @@ namespace Torch.API
/// </summary>
public interface ITorchBase
{
/// <summary>
/// Fired when the session begins loading.
/// </summary>
[Obsolete("Prefer using the TorchSessionManager.SessionStateChanged event")]
event Action SessionLoading;
/// <summary>
/// Fired when the session finishes loading.
/// </summary>
[Obsolete("Prefer using the TorchSessionManager.SessionStateChanged event")]
event Action SessionLoaded;
/// <summary>
/// Fires when the session begins unloading.
/// </summary>
[Obsolete("Prefer using the TorchSessionManager.SessionStateChanged event")]
event Action SessionUnloading;
/// <summary>
/// Fired when the session finishes unloading.
/// </summary>
[Obsolete("Prefer using the TorchSessionManager.SessionStateChanged event")]
event Action SessionUnloaded;
/// <summary>
/// Gets the currently running session instance, or null if none exists.
/// </summary>
@@ -68,6 +44,16 @@ namespace Torch.API
/// </summary>
Version TorchVersion { get; }
/// <summary>
/// Path of the dedicated instance folder.
/// </summary>
string InstancePath { get; }
/// <summary>
/// Name of the dedicated instance.
/// </summary>
string InstanceName { get; }
/// <summary>
/// Invoke an action on the game thread.
/// </summary>
@@ -146,16 +132,6 @@ namespace Torch.API
/// </summary>
ServerState State { get; }
/// <summary>
/// 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.
/// </summary>

View File

@@ -22,7 +22,6 @@ namespace Torch
bool ShouldUpdatePlugins { get; }
bool ShouldUpdateTorch { get; }
int TickTimeout { get; set; }
string WaitForPID { get; set; }
string ChatName { get; set; }
string ChatColor { get; set; }
string TestPlugin { get; set; }

View File

@@ -14,7 +14,6 @@ public interface IInstanceManager : IManager
public interface IWorld
{
string FolderName { get; }
string WorldPath { get; }
MyObjectBuilder_SessionSettings KeenSessionSettings { get; }
MyObjectBuilder_Checkpoint KeenCheckpoint { 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,105 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6-windows</TargetFramework>
<LangVersion>10</LangVersion>
<AssemblyTitle>Torch API</AssemblyTitle>
<Product>Torch</Product>
<Copyright>Copyright © Torch API 2017</Copyright>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<OutputPath>..\bin\$(Platform)\$(Configuration)\</OutputPath>
<UseWpf>True</UseWpf>
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>
<PlatformTarget>x64</PlatformTarget>
<Configurations>Debug;Release</Configurations>
<Platforms>AnyCPU</Platforms>
</PropertyGroup>
<PropertyGroup Condition="$(Configuration) == 'Release'">
<NoWarn>1591</NoWarn>
</PropertyGroup>
<!-- <Import Project="$(SolutionDir)\TransformOnBuild.targets" /> -->
<ItemGroup>
<PackageReference Include="NLog" Version="5.0.0-rc2" />
<PackageReference Include="SemanticVersioning" Version="2.0.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="HavokWrapper, Version=1.0.6278.22649, Culture=neutral, processorArchitecture=AMD64">
<HintPath>..\GameBinaries\HavokWrapper.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="Sandbox.Common, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\GameBinaries\Sandbox.Common.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="Sandbox.Game, Version=0.1.6305.30774, Culture=neutral, processorArchitecture=AMD64">
<HintPath>..\GameBinaries\Sandbox.Game.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="Sandbox.Graphics, Version=0.1.6305.30761, Culture=neutral, processorArchitecture=AMD64">
<HintPath>..\GameBinaries\Sandbox.Graphics.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="SpaceEngineers.Game, Version=1.0.0.0, Culture=neutral, processorArchitecture=AMD64">
<HintPath>..\GameBinaries\SpaceEngineers.Game.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="SpaceEngineers.ObjectBuilders, Version=1.0.0.0, Culture=neutral, processorArchitecture=AMD64">
<HintPath>..\GameBinaries\SpaceEngineers.ObjectBuilders.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="VRage">
<HintPath>..\GameBinaries\VRage.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Audio, Version=1.0.0.0, Culture=neutral, processorArchitecture=AMD64">
<HintPath>..\GameBinaries\VRage.Audio.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="VRage.Dedicated">
<HintPath>..\GameBinaries\VRage.Dedicated.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Game, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\GameBinaries\VRage.Game.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="VRage.Input, Version=1.0.0.0, Culture=neutral, processorArchitecture=AMD64">
<HintPath>..\GameBinaries\VRage.Input.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="VRage.Library">
<HintPath>..\GameBinaries\VRage.Library.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Math, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\GameBinaries\VRage.Math.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="VRage.Render, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\GameBinaries\VRage.Render.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="VRage.Render11, Version=1.0.0.0, Culture=neutral, processorArchitecture=AMD64">
<HintPath>..\GameBinaries\VRage.Render11.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="VRage.Scripting, Version=1.0.0.0, Culture=neutral, processorArchitecture=AMD64">
<HintPath>..\GameBinaries\VRage.Scripting.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\Versioning\AssemblyVersion.cs" Link="Properties/AssemblyVersion.cs" />
<PackageReference Include="NLog" Version="5.0.4" />
<PackageReference Include="SemanticVersioning" Version="2.0.2" />
<PackageReference Include="SpaceEngineersDedicated.ReferenceAssemblies" Version="1.201.13">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>compile</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

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

View File

@@ -60,7 +60,7 @@ namespace Torch.API.WebAPI
{
try
{
path ??= Path.Combine(Directory.GetCurrentDirectory(), "Plugins", $"{item.Name}.zip");
path ??= Path.Combine(AppContext.BaseDirectory, "Plugins", $"{item.Name}.zip");
if (item.Versions.Length == 0)
{

View File

@@ -1,17 +0,0 @@
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("Torch Client 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,51 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net461</TargetFramework>
<NoWarn>1591,0649</NoWarn>
<AssemblyTitle>Torch Client Tests</AssemblyTitle>
<Product>Torch</Product>
<Copyright>Copyright © Torch API 2017</Copyright>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<OutputPath>$(SolutionDir)\bin-test\$(Platform)\$(Configuration)\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugType>full</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<DebugType>pdbonly</DebugType>
<DocumentationFile>$(SolutionDir)\bin-test\$(Platform)\$(Configuration)\Torch.Client.Tests.xml</DocumentationFile>
</PropertyGroup>
<Import Project="$(SolutionDir)\TransformOnBuild.targets" />
<ItemGroup>
<PackageReference Include="Mono.TextTransform" Version="1.0.0" />
<PackageReference Include="NLog" Version="4.4.12" />
<PackageReference Include="xunit" Version="2.2.0" />
<PackageReference Include="xunit.abstractions" Version="2.0.1" />
<PackageReference Include="xunit.assert" Version="2.2.0" />
<PackageReference Include="xunit.core" Version="2.2.0" />
<PackageReference Include="xunit.extensibility.core" Version="2.2.0" />
<PackageReference Include="xunit.extensibility.execution" Version="2.2.0" />
<PackageReference Include="xunit.runner.console" Version="2.2.0">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Versioning\AssemblyVersion.cs" Link="Properties\AssemblyVersion.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Torch.API\Torch.API.csproj" />
<ProjectReference Include="..\Torch.Client\Torch.Client.csproj" />
<ProjectReference Include="..\Torch.Tests\Torch.Tests.csproj" />
<ProjectReference Include="..\Torch\Torch.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Remove="obj\x64\Debug\.NETFramework,Version=v4.6.1.AssemblyAttributes.cs" />
<Compile Remove="obj\x64\Release\.NETFramework,Version=v4.6.1.AssemblyAttributes.cs" />
</ItemGroup>
</Project>

View File

@@ -1,94 +0,0 @@
using System;
using System.Collections.Generic;
using Torch.Client;
using Torch.Tests;
using Torch.Utils;
using Xunit;
namespace Torch.Client.Tests
{
public class TorchClientReflectionTest
{
static TorchClientReflectionTest()
{
TestUtils.Init();
}
private static ReflectionTestManager _manager;
private static ReflectionTestManager Manager()
{
if (_manager != null)
return _manager;
return _manager = new ReflectionTestManager().Init(typeof(TorchClient).Assembly);
}
public static IEnumerable<object[]> Getters => Manager().Getters;
public static IEnumerable<object[]> Setters => Manager().Setters;
public static IEnumerable<object[]> Invokers => Manager().Invokers;
public static IEnumerable<object[]> MemberInfo => Manager().MemberInfo;
public static IEnumerable<object[]> Events => Manager().Events;
#region Binding
[Theory]
[MemberData(nameof(Getters))]
public void TestBindingGetter(ReflectionTestManager.FieldRef field)
{
if (field.Field == null)
return;
Assert.True(ReflectedManager.Process(field.Field));
if (field.Field.IsStatic)
Assert.NotNull(field.Field.GetValue(null));
}
[Theory]
[MemberData(nameof(Setters))]
public void TestBindingSetter(ReflectionTestManager.FieldRef field)
{
if (field.Field == null)
return;
Assert.True(ReflectedManager.Process(field.Field));
if (field.Field.IsStatic)
Assert.NotNull(field.Field.GetValue(null));
}
[Theory]
[MemberData(nameof(Invokers))]
public void TestBindingInvoker(ReflectionTestManager.FieldRef field)
{
if (field.Field == null)
return;
Assert.True(ReflectedManager.Process(field.Field));
if (field.Field.IsStatic)
Assert.NotNull(field.Field.GetValue(null));
}
[Theory]
[MemberData(nameof(MemberInfo))]
public void TestBindingMemberInfo(ReflectionTestManager.FieldRef field)
{
if (field.Field == null)
return;
Assert.True(ReflectedManager.Process(field.Field));
if (field.Field.IsStatic)
Assert.NotNull(field.Field.GetValue(null));
}
[Theory]
[MemberData(nameof(Events))]
public void TestBindingEvents(ReflectionTestManager.FieldRef field)
{
if (field.Field == null)
return;
Assert.True(ReflectedManager.Process(field.Field));
if (field.Field.IsStatic)
((Func<ReflectedEventReplacer>)field.Field.GetValue(null)).Invoke();
}
#endregion
}
}

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>
</configuration>

View File

@@ -1,32 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sandbox.Engine.Multiplayer;
using Torch.API;
using Torch.API.Managers;
using Torch.Managers;
namespace Torch.Client.Manager
{
public class MultiplayerManagerClient : MultiplayerManagerBase, IMultiplayerManagerClient
{
/// <inheritdoc />
public MultiplayerManagerClient(ITorchBase torch) : base(torch) { }
/// <inheritdoc />
public override void Attach()
{
base.Attach();
MyMultiplayer.Static.ClientJoined += RaiseClientJoined;
}
/// <inheritdoc />
public override void Detach()
{
MyMultiplayer.Static.ClientJoined -= RaiseClientJoined;
base.Detach();
}
}
}

View File

@@ -1,95 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sandbox.Engine.Multiplayer;
using Sandbox.Game.World;
using Torch.API;
using Torch.API.Managers;
using Torch.Managers;
using VRage.Game.ModAPI;
namespace Torch.Client.Manager
{
public class MultiplayerManagerLobby : MultiplayerManagerBase, IMultiplayerManagerServer
{
/// <inheritdoc />
public IReadOnlyList<ulong> BannedPlayers => new List<ulong>();
/// <inheritdoc />
public MultiplayerManagerLobby(ITorchBase torch) : base(torch) { }
/// <inheritdoc />
public void KickPlayer(ulong steamId) => Torch.Invoke(() => MyMultiplayer.Static.KickClient(steamId));
/// <inheritdoc />
public void BanPlayer(ulong steamId, bool banned = true) => Torch.Invoke(() => MyMultiplayer.Static.BanClient(steamId, banned));
/// <inheritdoc />
public void PromoteUser(ulong steamId)
{
Torch.Invoke(() =>
{
var p = MySession.Static.GetUserPromoteLevel(steamId);
if (p < MyPromoteLevel.Admin) //cannot promote to owner by design
MySession.Static.SetUserPromoteLevel(steamId, p + 1);
});
}
/// <inheritdoc />
public void DemoteUser(ulong steamId)
{
Torch.Invoke(() =>
{
var p = MySession.Static.GetUserPromoteLevel(steamId);
if (p > MyPromoteLevel.None && p < MyPromoteLevel.Owner) //owner cannot be demoted by design
MySession.Static.SetUserPromoteLevel(steamId, p - 1);
});
}
/// <inheritdoc />
public MyPromoteLevel GetUserPromoteLevel(ulong steamId)
{
return MySession.Static.GetUserPromoteLevel(steamId);
}
/// <inheritdoc />
public bool IsBanned(ulong steamId) => false;
/// <inheritdoc />
public event Action<ulong> PlayerKicked
{
add => throw new NotImplementedException();
remove => throw new NotImplementedException();
}
/// <inheritdoc />
public event Action<ulong, bool> PlayerBanned
{
add => throw new NotImplementedException();
remove => throw new NotImplementedException();
}
/// <inheritdoc />
public event Action<ulong, MyPromoteLevel> PlayerPromoted
{
add => throw new NotImplementedException();
remove => throw new NotImplementedException();
}
/// <inheritdoc/>
public override void Attach()
{
base.Attach();
MyMultiplayer.Static.ClientJoined += RaiseClientJoined;
}
/// <inheritdoc/>
public override void Detach()
{
MyMultiplayer.Static.ClientJoined -= RaiseClientJoined;
base.Detach();
}
}
}

View File

@@ -1,194 +0,0 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Forms;
using NLog;
using Torch.Utils;
using MessageBox = System.Windows.MessageBox;
namespace Torch.Client
{
public static class Program
{
public const string SpaceEngineersBinaries = "Bin64";
private static string _spaceEngInstallAlias = null;
public static string SpaceEngineersInstallAlias
{
get
{
// ReSharper disable once ConvertIfStatementToNullCoalescingExpression
if (_spaceEngInstallAlias == null)
{
// ReSharper disable once AssignNullToNotNullAttribute
_spaceEngInstallAlias = Path.Combine(Path.GetDirectoryName(typeof(Program).Assembly.Location),
"SpaceEngineersAlias");
}
return _spaceEngInstallAlias;
}
}
private const string _steamSpaceEngineersDirectory = @"steamapps\common\SpaceEngineers\";
private const string _spaceEngineersVerifyFile = SpaceEngineersBinaries + @"\SpaceEngineers.exe";
public const string ConfigName = "Torch.cfg";
private static Logger _log = LogManager.GetLogger("Torch");
#if DEBUG
[DllImport("kernel32.dll")]
private static extern void AllocConsole();
[DllImport("kernel32.dll")]
private static extern void FreeConsole();
#endif
public static void Main(string[] args)
{
#if DEBUG
try
{
AllocConsole();
#endif
if (!TorchLauncher.IsTorchWrapped())
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
// Early config: Resolve SE install directory.
if (!File.Exists(Path.Combine(SpaceEngineersInstallAlias, _spaceEngineersVerifyFile)))
SetupSpaceEngInstallAlias();
TorchLauncher.Launch(Assembly.GetEntryAssembly().FullName, args,
Path.Combine(SpaceEngineersInstallAlias, SpaceEngineersBinaries));
return;
}
RunClient();
#if DEBUG
}
finally
{
FreeConsole();
}
#endif
}
private static void SetupSpaceEngInstallAlias()
{
string spaceEngineersDirectory = null;
// TODO look at Steam/config/Config.VDF? Has alternate directories.
var steamDir =
Microsoft.Win32.Registry.GetValue("HKEY_CURRENT_USER\\SOFTWARE\\Valve\\Steam", "SteamPath",
null) as string;
if (steamDir != null)
{
spaceEngineersDirectory = Path.Combine(steamDir, _steamSpaceEngineersDirectory);
// ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
if (File.Exists(Path.Combine(spaceEngineersDirectory, _spaceEngineersVerifyFile)))
_log.Debug("Found Space Engineers in {0}", spaceEngineersDirectory);
else
{
_log.Debug("Couldn't find Space Engineers in {0}", spaceEngineersDirectory);
spaceEngineersDirectory = null;
}
}
if (spaceEngineersDirectory == null)
{
var dialog = new System.Windows.Forms.FolderBrowserDialog
{
Description = "Please select the SpaceEngineers installation folder"
};
do
{
if (dialog.ShowDialog() != DialogResult.OK)
{
var ex = new FileNotFoundException(
"Unable to find the Space Engineers install directory, aborting");
_log.Fatal(ex);
LogManager.Flush();
throw ex;
}
spaceEngineersDirectory = dialog.SelectedPath;
if (File.Exists(Path.Combine(spaceEngineersDirectory, _spaceEngineersVerifyFile)))
break;
if (MessageBox.Show(
$"Unable to find {0} in {1}. Are you sure it's the Space Engineers install directory?",
"Invalid Space Engineers Directory", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
break;
} while (true); // Repeat until they confirm.
}
if (!JunctionLink(SpaceEngineersInstallAlias, spaceEngineersDirectory))
{
var ex = new IOException(
$"Failed to create junction link {SpaceEngineersInstallAlias} => {spaceEngineersDirectory}. Aborting.");
_log.Fatal(ex);
LogManager.Flush();
throw ex;
}
string junctionVerify = Path.Combine(SpaceEngineersInstallAlias, _spaceEngineersVerifyFile);
if (!File.Exists(junctionVerify))
{
var ex = new FileNotFoundException(
$"Junction link is not working. File {junctionVerify} does not exist");
_log.Fatal(ex);
LogManager.Flush();
throw ex;
}
}
private static bool JunctionLink(string linkName, string targetDir)
{
var junctionLinkProc = new ProcessStartInfo("cmd.exe", $"/c mklink /J \"{linkName}\" \"{targetDir}\"")
{
WorkingDirectory = Directory.GetCurrentDirectory(),
UseShellExecute = false,
RedirectStandardOutput = true,
StandardOutputEncoding = Encoding.ASCII
};
Process cmd = Process.Start(junctionLinkProc);
// ReSharper disable once PossibleNullReferenceException
while (!cmd.HasExited)
{
string line = cmd.StandardOutput.ReadLine();
if (!string.IsNullOrWhiteSpace(line))
_log.Info(line);
Thread.Sleep(100);
}
if (cmd.ExitCode != 0)
_log.Error("Unable to create junction link {0} => {1}", linkName, targetDir);
return cmd.ExitCode == 0;
}
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var ex = (Exception) e.ExceptionObject;
_log.Error(ex);
LogManager.Flush();
MessageBox.Show(ex.StackTrace, ex.Message);
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void RunClient()
{
var client = new TorchClient();
try
{
client.Init();
}
catch (Exception e)
{
_log.Fatal("Torch encountered an error trying to initialize the game.");
_log.Fatal(e);
return;
}
client.Start();
}
}
}

View File

@@ -1,17 +0,0 @@
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("Torch Client")]
[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,63 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Torch.Client.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Torch.Client.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@@ -1,117 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -1,26 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Torch.Client.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

View File

@@ -1,7 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@@ -1,122 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net461</TargetFramework>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<AssemblyTitle>Torch Client</AssemblyTitle>
<Product>Torch</Product>
<Copyright>Copyright © Torch API 2017</Copyright>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<OutputPath>$(SolutionDir)\bin\$(Platform)\$(Configuration)\</OutputPath>
<Prefer32Bit>true</Prefer32Bit>
<UseWPF>true</UseWPF>
<PostBuildEvent>copy "$(SolutionDir)NLog.config" "$(TargetDir)"
</PostBuildEvent>
<PostBuildEvent>copy "$(SolutionDir)NLog.config" "$(TargetDir)"
</PostBuildEvent>
<PostBuildEvent>copy "$(SolutionDir)NLog.config" "$(TargetDir)"
</PostBuildEvent>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugType>full</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<DebugType>pdbonly</DebugType>
<DocumentationFile>$(SolutionDir)\bin\$(Platform)\$(Configuration)\Torch.Client.xml</DocumentationFile>
<NoWarn>1591</NoWarn>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>torchicon.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup>
<PostBuildEvent>copy "$(SolutionDir)NLog.config" "$(TargetDir)"
</PostBuildEvent>
</PropertyGroup>
<Import Project="$(SolutionDir)\TransformOnBuild.targets" />
<ItemGroup>
<PackageReference Include="Mono.TextTransform" Version="1.0.0" />
<PackageReference Include="NLog" Version="4.4.12" />
</ItemGroup>
<ItemGroup>
<Reference Include="Sandbox.Common, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\GameBinaries\Sandbox.Common.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="Sandbox.Game">
<HintPath>..\GameBinaries\Sandbox.Game.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Sandbox.Graphics, Version=0.1.6108.20417, Culture=neutral, processorArchitecture=AMD64">
<HintPath>..\GameBinaries\Sandbox.Graphics.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="SpaceEngineers.Game">
<HintPath>..\GameBinaries\SpaceEngineers.Game.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="System.Windows.Forms" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml" />
<Reference Include="VRage">
<HintPath>..\GameBinaries\VRage.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Game">
<HintPath>..\GameBinaries\VRage.Game.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Game.XmlSerializers">
<HintPath>..\GameBinaries\VRage.Game.XmlSerializers.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Input, Version=1.0.0.0, Culture=neutral, processorArchitecture=AMD64">
<HintPath>..\GameBinaries\VRage.Input.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="VRage.Library">
<HintPath>..\GameBinaries\VRage.Library.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Math, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\GameBinaries\VRage.Math.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="VRage.Render">
<HintPath>..\GameBinaries\VRage.Render.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Render11">
<HintPath>..\GameBinaries\VRage.Render11.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Steam">
<HintPath>..\GameBinaries\VRage.Steam.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Versioning\AssemblyVersion.cs" Link="Properties\AssemblyVersion.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Torch.API\Torch.API.csproj" />
<ProjectReference Include="..\Torch\Torch.csproj" />
</ItemGroup>
<ItemGroup>
<Resource Include="torchicon.ico" />
</ItemGroup>
<ItemGroup>
<Compile Remove="obj\x64\Debug\.NETFramework,Version=v4.6.1.AssemblyAttributes.cs" />
<Compile Remove="obj\x64\Release\.NETFramework,Version=v4.6.1.AssemblyAttributes.cs" />
</ItemGroup>
</Project>

View File

@@ -1,92 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Windows;
using Sandbox;
using Sandbox.Engine.Multiplayer;
using Sandbox.Engine.Networking;
using Sandbox.Engine.Platform;
using Sandbox.Game;
using SpaceEngineers.Game;
using VRage.Steam;
using Torch.API;
using Torch.API.Managers;
using Torch.API.Session;
using Torch.Client.Manager;
using Torch.Client.UI;
using Torch.Session;
using VRage;
using VRage.FileSystem;
using VRage.GameServices;
using VRageRender;
using VRageRender.ExternalApp;
namespace Torch.Client
{
public class TorchClient : TorchBase, ITorchClient
{
protected override uint SteamAppId => 244850;
protected override string SteamAppName => "SpaceEngineers";
public TorchClient()
{
Config = new TorchClientConfig();
var sessionManager = Managers.GetManager<ITorchSessionManager>();
sessionManager.AddFactory((x) => MyMultiplayer.Static is MyMultiplayerLobby
? new MultiplayerManagerLobby(this)
: null);
sessionManager.AddFactory((x) => MyMultiplayer.Static is MyMultiplayerClientBase
? new MultiplayerManagerClient(this)
: null);
}
public override void Init()
{
Directory.SetCurrentDirectory(Program.SpaceEngineersInstallAlias);
MyFileSystem.ExePath = Path.Combine(Program.SpaceEngineersInstallAlias, Program.SpaceEngineersBinaries);
Log.Info("Initializing Torch Client");
Config.InstancePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
SteamAppName);
base.Init();
OverrideMenus();
SetRenderWindowTitle($"Space Engineers v{GameVersion} with Torch v{TorchVersion}");
}
private void OverrideMenus()
{
var credits = new MyCreditsDepartment("Torch Developed By")
{
Persons = new List<MyCreditsPerson>
{
new MyCreditsPerson("THE TORCH TEAM"),
new MyCreditsPerson("http://github.com/TorchSE"),
}
};
MyPerGameSettings.Credits.Departments.Insert(0, credits);
MyPerGameSettings.GUI.MainMenu = typeof(TorchMainMenuScreen);
}
private void SetRenderWindowTitle(string title)
{
MyRenderThread renderThread = MySandboxGame.Static?.GameRenderComponent?.RenderThread;
if (renderThread == null)
return;
FieldInfo renderWindowField = typeof(MyRenderThread).GetField("m_renderWindow",
BindingFlags.Instance | BindingFlags.NonPublic);
if (renderWindowField == null)
return;
var window =
renderWindowField.GetValue(MySandboxGame.Static.GameRenderComponent.RenderThread) as
System.Windows.Forms.Form;
if (window != null)
renderThread.Invoke(() => { window.Text = title; });
}
public override void Restart()
{
throw new NotImplementedException();
}
}
}

View File

@@ -1,34 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Torch.Client
{
public class TorchClientConfig : ITorchConfig
{
// How do we want to handle client side config? It's radically different than the server.
public bool GetPluginUpdates { get; set; } = false;
public bool GetTorchUpdates { get; set; } = false;
public string InstanceName { get; set; } = "TorchClient";
public string InstancePath { get; set; }
public bool NoUpdate { get; set; } = true;
public List<string> Plugins { get; set; }
public bool ShouldUpdatePlugins { get; } = false;
public bool ShouldUpdateTorch { get; } = false;
public int TickTimeout { get; set; }
public bool Autostart { get; set; } = false;
public bool ForceUpdate { get; set; } = false;
public bool NoGui { get; set; } = false;
public bool RestartOnCrash { get; set; } = false;
public string WaitForPID { get; set; } = null;
public string ChatName { get; set; }
public string ChatColor { get; set; }
public bool Save(string path = null)
{
return true;
}
}
}

View File

@@ -1,63 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using Sandbox.Graphics;
using Sandbox.Graphics.GUI;
using Sandbox.Gui;
using VRage.Utils;
using VRageMath;
namespace Torch.Client
{
public class TorchConsoleScreen : MyGuiScreenBase
{
private MyGuiControlTextbox _textBox;
public override string GetFriendlyName()
{
return "Torch Console";
}
public TorchConsoleScreen() : base(isTopMostScreen: true)
{
BackgroundColor = new Vector4(0, 0, 0, 0.5f);
Size = new Vector2(0.5f);
RecreateControls(true);
}
public sealed override void RecreateControls(bool constructor)
{
Elements.Clear();
Elements.Add(new MyGuiControlLabel
{
Text = "Torch Console",
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_RIGHT_AND_VERTICAL_TOP,
Position = MyGuiManager.ComputeFullscreenGuiCoordinate(MyGuiDrawAlignEnum.HORISONTAL_RIGHT_AND_VERTICAL_TOP)
});
Controls.Clear();
_textBox = new MyGuiControlTextbox
{
BorderEnabled = false,
Enabled = true,
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP,
Position = new Vector2(-0.5f)
};
Controls.Add(_textBox);
var pistonBtn = new MyGuiControlImageButton
{
Name = "TorchButton",
Text = "Torch",
HighlightType = MyGuiControlHighlightType.WHEN_CURSOR_OVER,
Visible = true,
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP
};
Controls.Add(pistonBtn);
}
}
}

View File

@@ -1,38 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sandbox.Graphics;
using Sandbox.Graphics.GUI;
using VRage.Utils;
using VRageMath;
namespace Torch.Client
{
public class TorchSettingsScreen : MyGuiScreenBase
{
public override string GetFriendlyName() => "Torch Settings";
public TorchSettingsScreen() : base(new Vector2(0.5f), null, Vector2.One, true)
{
RecreateControls(true);
}
public sealed override void RecreateControls(bool constructor)
{
base.RecreateControls(constructor);
AddCaption(MyStringId.GetOrCompute("Torch Settings"), null, new Vector2(0, 0), 1.2f);
var pluginList = new MyGuiControlListbox
{
VisibleRowsCount = 10,
};
foreach (var plugin in TorchBase.Instance.Plugins)
{
pluginList.Items.Add(new MyGuiControlListbox.Item(new StringBuilder(plugin.Name)));
}
Controls.Add(pluginList);
}
}
}

View File

@@ -1,56 +0,0 @@
#pragma warning disable 618
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sandbox.Engine.Networking;
using Sandbox.Engine.Utils;
using Sandbox.Game;
using Sandbox.Game.Gui;
using Sandbox.Graphics;
using Sandbox.Graphics.GUI;
using Sandbox.Gui;
using SpaceEngineers.Game.GUI;
using Torch.Utils;
using VRage.Game;
using VRage.Utils;
using VRageMath;
namespace Torch.Client.UI
{
public class TorchMainMenuScreen : MyGuiScreenMainMenu
{
#pragma warning disable 169
[ReflectedGetter(Name = "m_elementGroup")]
private static Func<MyGuiScreenMainMenu, MyGuiControlElementGroup> _elementsGroup;
#pragma warning restore 169
public TorchMainMenuScreen() : this(false)
{
}
public TorchMainMenuScreen(bool pauseGame)
: base(pauseGame)
{
}
/// <inheritdoc />
public override void RecreateControls(bool constructor)
{
base.RecreateControls(constructor);
Vector2 minSizeGui = MyGuiControlButton.GetVisualStyle(MyGuiControlButtonStyleEnum.Default).NormalTexture.MinSizeGui;
Vector2 value = MyGuiManager.ComputeFullscreenGuiCoordinate(MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_BOTTOM, 54, 54) + new Vector2(minSizeGui.X / 2f, 0f) + new Vector2(15f, 0f) / MyGuiConstants.GUI_OPTIMAL_SIZE;
MyGuiControlButton myGuiControlButton = MakeButton(value - 9 * MyGuiConstants.MENU_BUTTONS_POSITION_DELTA,
MyStringId.GetOrCompute("Torch"), TorchButtonClicked, MyCommonTexts.ToolTipExitToWindows);
Controls.Add(myGuiControlButton);
_elementsGroup.Invoke(this).Add(myGuiControlButton);
}
private void TorchButtonClicked(MyGuiControlButton obj)
{
MyGuiSandbox.AddScreen(MyGuiSandbox.CreateScreen<TorchNavScreen>());
}
}
}

View File

@@ -1,49 +0,0 @@
using Sandbox;
using Sandbox.Game.Gui;
using Sandbox.Graphics.GUI;
using VRage;
using VRage.Game;
using VRage.Utils;
using VRageMath;
namespace Torch.Client.UI
{
public class TorchNavScreen : MyGuiScreenBase
{
private MyGuiControlElementGroup _elementGroup;
public TorchNavScreen() : base(new Vector2(0.5f, 0.5f), MyGuiConstants.SCREEN_BACKGROUND_COLOR, new Vector2(0.35875f, 0.558333337f))
{
EnabledBackgroundFade = true;
RecreateControls(true);
}
public override void RecreateControls(bool constructor)
{
base.RecreateControls(constructor);
_elementGroup = new MyGuiControlElementGroup();
_elementGroup.HighlightChanged += ElementGroupHighlightChanged;
AddCaption(MyCommonTexts.ScreenCaptionOptions, null, null);
var value = new Vector2(0f, -m_size.Value.Y / 2f + 0.146f);
var num = 0;
var myGuiControlButton = new MyGuiControlButton(value + num++ * MyGuiConstants.MENU_BUTTONS_POSITION_DELTA, MyGuiControlButtonStyleEnum.Default, null, null, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER, null, MyTexts.Get(MyCommonTexts.ScreenOptionsButtonGame), 0.8f, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER, MyGuiControlHighlightType.WHEN_ACTIVE, delegate(MyGuiControlButton sender)
{
MyGuiSandbox.AddScreen(MyGuiSandbox.CreateScreen<TorchSettingsScreen>());
}, GuiSounds.MouseClick, 1f, null);
Controls.Add(myGuiControlButton);
_elementGroup.Add(myGuiControlButton);
CloseButtonEnabled = true;
}
private void ElementGroupHighlightChanged(MyGuiControlElementGroup obj)
{
foreach (MyGuiControlBase current in _elementGroup)
if (current.HasFocus && obj.SelectedElement != current)
FocusedControl = obj.SelectedElement;
}
public override string GetFriendlyName() => "Torch";
public void OnBackClick(MyGuiControlButton sender) => CloseScreen();
}
}

View File

@@ -1,25 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sandbox.Graphics.GUI;
using VRageMath;
namespace Torch.Client.UI
{
public class TorchSettingsScreen : MyGuiScreenBase
{
public TorchSettingsScreen() : base(new Vector2(0.5f, 0.5f), MyGuiConstants.SCREEN_BACKGROUND_COLOR,
new Vector2(0.35875f, 0.558333337f))
{
EnabledBackgroundFade = true;
RecreateControls(true);
}
/// <inheritdoc />
public override string GetFriendlyName() => "Torch Settings";
public void OnBackClick(MyGuiControlButton sender) => CloseScreen();
}
}

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>
</configuration>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

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">
<PropertyGroup>
<TargetFramework>net6-windows</TargetFramework>
<LangVersion>10</LangVersion>
<NoWarn>1591,0649</NoWarn>
<AssemblyTitle>Torch Server Tests</AssemblyTitle>
<Product>Torch</Product>
@@ -17,9 +18,9 @@
</PropertyGroup>
<!-- <Import Project="$(SolutionDir)\TransformOnBuild.targets" /> -->
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="NLog" Version="5.0.0-rc2" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="NLog" Version="5.0.4" />
<PackageReference Include="xunit" Version="2.4.2" />
</ItemGroup>
<ItemGroup>
<Reference Include="VRage.Game, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
@@ -27,9 +28,6 @@
<SpecificVersion>False</SpecificVersion>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\Versioning\AssemblyVersion.cs" Link="Properties\AssemblyVersion.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Torch.API\Torch.API.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

@@ -12,6 +12,7 @@ using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using Microsoft.Extensions.Configuration;
using NLog;
using NLog.Targets;
using Sandbox.Engine.Utils;
@@ -29,25 +30,20 @@ namespace Torch.Server
private const string STEAMCMD_DIR = "steamcmd";
private const string STEAMCMD_ZIP = "temp.zip";
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 const string STEAMCMD_ARGS = "+force_install_dir \"{0}\" +login anonymous +app_update 298740 +quit";
private TorchServer _server;
internal Persistent<TorchConfig> ConfigPersistent { get; }
public TorchConfig Config => ConfigPersistent?.Data;
public TorchServer Server => _server;
public Initializer(string basePath, Persistent<TorchConfig> torchConfig)
public Initializer(Persistent<TorchConfig> torchConfig)
{
Instance = this;
ConfigPersistent = torchConfig;
}
public bool Initialize(string[] args)
public bool Initialize(IConfiguration configuration)
{
if (_init)
return false;
@@ -60,18 +56,17 @@ quit";
Log.Debug("Debug logging enabled.");
#endif
// This is what happens when Keen is bad and puts extensions into the System namespace.
if (!Enumerable.Contains(args, "-noupdate"))
if (!configuration.GetValue("noupdate", false))
RunSteamCmd();
if (!string.IsNullOrEmpty(Config.WaitForPID))
var processPid = configuration.GetValue<int>("waitForPid");
if (processPid != 0)
{
try
{
var pid = int.Parse(Config.WaitForPID);
var waitProc = Process.GetProcessById(pid);
var waitProc = Process.GetProcessById(processPid);
Log.Info("Continuing in 5 seconds.");
Log.Warn($"Waiting for process {pid} to close");
Log.Warn($"Waiting for process {processPid} to close");
while (!waitProc.HasExited)
{
Console.Write(".");
@@ -88,11 +83,11 @@ quit";
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();
@@ -140,10 +135,6 @@ quit";
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);
if (!File.Exists(steamCmdExePath))
{
@@ -166,8 +157,9 @@ quit";
}
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,
UseShellExecute = false,
RedirectStandardOutput = true,

View File

@@ -236,9 +236,9 @@ namespace Torch.Server.Managers
{
var world = DedicatedConfig.SelectedWorld;
world.Checkpoint.SessionName = string.IsNullOrEmpty(DedicatedConfig.WorldName)
world.Checkpoint.SessionName = string.IsNullOrEmpty(world.Checkpoint.SessionName)
? Path.GetDirectoryName(DedicatedConfig.LoadWorld)
: DedicatedConfig.WorldName;
: world.Checkpoint.SessionName;
world.WorldConfiguration.Settings = DedicatedConfig.SessionSettings;
world.WorldConfiguration.Mods.Clear();
@@ -284,7 +284,6 @@ namespace Torch.Server.Managers
{
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
public string FolderName { get; set; }
public string WorldPath { get; }
public MyObjectBuilder_SessionSettings KeenSessionSettings => WorldConfiguration.Settings;
public MyObjectBuilder_Checkpoint KeenCheckpoint => Checkpoint;
@@ -313,7 +312,6 @@ namespace Torch.Server.Managers
WorldSizeKB = new DirectoryInfo(worldPath).GetFiles().Sum(x => x.Length) / 1024;
_checkpointPath = Path.Combine(WorldPath, "Sandbox.sbc");
_worldConfigPath = Path.Combine(WorldPath, "Sandbox_config.sbc");
FolderName = Path.GetFileName(worldPath);
if (loadFiles)
LoadSandbox();
}

View File

@@ -12,7 +12,6 @@ using Sandbox.Engine.Multiplayer;
using Sandbox.Engine.Networking;
using Sandbox.Game.Gui;
using Sandbox.Game.World;
using Steamworks;
using Torch.API;
using Torch.API.Managers;
using Torch.Managers;

View File

@@ -3,6 +3,7 @@ using NLog;
using Sandbox.Engine.Networking;
using Torch.API.Managers;
using Torch.Managers.PatchManager;
using Torch.Server;
using Torch.Server.Managers;
using Torch.Utils;
using VRage.Game;
@@ -25,6 +26,9 @@ public static class CheckpointLoadPatch
private static bool Prefix(ref MyObjectBuilder_Checkpoint __result)
{
#pragma warning disable CS0618
if (!((TorchServer)TorchBase.Instance).HasRun)
return true;
var world = TorchBase.Instance.Managers.GetManager<InstanceManager>().DedicatedConfig.SelectedWorld;
#pragma warning restore CS0618
if (world is null)

View File

@@ -1,8 +1,11 @@
using System;
using System.IO;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Xml;
using NLog;
using NLog.Config;
using NLog.Targets;
using Torch.API;
using Torch.Utils;
namespace Torch.Server
@@ -12,30 +15,84 @@ 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);
var configurationBuilder = new ConfigurationBuilder()
.AddEnvironmentVariables("TORCH")
.AddCommandLine(args);
var configuration = configurationBuilder.Build();
if (!isService && Directory.Exists(binDir))
foreach (var file in Directory.GetFiles(binDir, "System.*.dll"))
{
File.Delete(file);
}
var context = CreateApplicationContext(configuration);
// 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;
}
SetupLogging(context, configuration);
var config = SetupConfiguration(context, configurationBuilder, out configuration);
var handler = new UnhandledExceptionHandler(config.Data);
AppDomain.CurrentDomain.UnhandledException += handler.OnUnhandledException;
var initializer = new Initializer(config);
if (!initializer.Initialize(configuration))
Environment.Exit(1);
#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
var instanceName = Environment.GetEnvironmentVariable("TORCH_INSTANCE") ?? "Instance";
initializer.Run();
}
private static void SetupLogging(IApplicationContext context, IConfiguration configuration)
{
var oldNlog = Path.Combine(context.TorchDirectory.FullName, "NLog.config");
var newNlog = configuration.GetValue("loggingConfigPath", Path.Combine(context.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(configuration.GetValue("loggingExtensionsPath",
Path.Combine(
context.InstanceDirectory.FullName,
"LoggingExtensions")));
TorchLogManager.SetConfiguration(new XmlLoggingConfiguration(newNlog));
}
private static Persistent<TorchConfig> SetupConfiguration(IApplicationContext context,
IConfigurationBuilder builder,
out IConfigurationRoot configuration)
{
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);
builder.AddXmlFile(torchCfg, true, true);
configuration = builder.Build();
var config = new Persistent<TorchConfig>(torchCfg, configuration.Get<TorchConfig>() ?? new());
config.Data.InstanceName = context.InstanceName;
config.Data.InstancePath = context.InstanceDirectory.FullName;
return config;
}
private static IApplicationContext CreateApplicationContext(IConfiguration configuration)
{
var isService = configuration.GetValue("service", false);
var workingDir = AppContext.BaseDirectory;
var gamePath = configuration.GetValue("gamePath", workingDir);
var binDir = Path.Combine(gamePath, "DedicatedServer64");
Directory.SetCurrentDirectory(gamePath);
var instanceName = configuration.GetValue("instanceName", "Instance");
string instancePath;
if (Path.IsPathRooted(instanceName))
@@ -45,98 +102,11 @@ namespace Torch.Server
}
else
{
instancePath = Directory.CreateDirectory(instanceName).FullName;
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))
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;
Target.Register<LogViewerTarget>(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);
if (!initializer.Initialize(args))
Environment.Exit(1);
TorchLauncher.Launch(workingDir, binDir);
CopyNative(binDir);
initializer.Run(isService, instanceName, instancePath);
}
private static void CopyNative(string binPath)
{
var log = LogManager.GetLogger("TorchLauncher");
var workingDir = new DirectoryInfo(Directory.GetCurrentDirectory());
if (workingDir.Attributes.HasFlag(FileAttributes.ReadOnly))
{
log.Warn("Game 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");
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(workingDir.FullName, "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);
}
}
catch (UnauthorizedAccessException)
{
// file is being used by another process, probably previous torch has not been closed yet
}
catch (Exception e)
{
log.Error(e);
}
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

@@ -3,7 +3,7 @@
"profiles": {
"Torch.Server": {
"commandName": "Project",
"commandLineArgs": "-noupdate",
"commandLineArgs": "--noupdate true --gamepath \"C:\\Program Files (x86)\\Steam\\steamapps\\common\\SpaceEngineersDedicatedServer\"",
"use64Bit": true,
"hotReloadEnabled": false
}

View File

@@ -2,11 +2,10 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6-windows</TargetFramework>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<LangVersion>10</LangVersion>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<PublishUrl>publish\</PublishUrl>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<AssemblyTitle>Torch Server</AssemblyTitle>
<Product>Torch</Product>
@@ -14,144 +13,62 @@
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<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>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup>
<BeautyLibsDir>torch64</BeautyLibsDir>
<NoBeautyFlag>True</NoBeautyFlag>
<ForceBeauty>True</ForceBeauty>
</PropertyGroup>
<PropertyGroup>
<StartupObject>Torch.Server.Program</StartupObject>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>torchicon.ico</ApplicationIcon>
</PropertyGroup>
<!-- <Import Project="$(SolutionDir)\TransformOnBuild.targets" /> -->
<ItemGroup>
<PackageReference Include="AutoCompleteTextBox" Version="1.3.0" />
<PackageReference Include="AutoCompleteTextBox" Version="1.6.0" />
<PackageReference Include="Ben.Demystifier" Version="0.4.1" />
<PackageReference Include="ControlzEx" Version="5.0.1" />
<PackageReference Include="MahApps.Metro" Version="2.4.9" />
<PackageReference Include="MdXaml" Version="1.12.0" />
<PackageReference Include="Microsoft.Diagnostics.Runtime" Version="2.0.226801" />
<PackageReference Include="NLog" Version="5.0.0-rc2" />
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" PrivateAssets="all" />
<PackageReference Include="MdXaml" Version="1.16.0" />
<PackageReference Include="Microsoft.Diagnostics.Runtime" Version="2.2.332302" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Xml" Version="6.0.0" />
<PackageReference Include="NLog" Version="5.0.4" />
<PackageReference Include="PropertyChanged.Fody" Version="4.0.3" PrivateAssets="all" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.Management" Version="6.0.0" />
<PackageReference Include="nulastudio.NetCoreBeauty" Version="1.2.9.3" />
<PackageReference Include="SpaceEngineersDedicated.ReferenceAssemblies" Version="1.201.13">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>compile</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Reference Include="HavokWrapper, Version=1.0.6051.28726, Culture=neutral, processorArchitecture=AMD64">
<HintPath>..\GameBinaries\HavokWrapper.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="Microsoft.CodeAnalysis, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\GameBinaries\Microsoft.CodeAnalysis.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="Microsoft.CodeAnalysis.CSharp, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\GameBinaries\Microsoft.CodeAnalysis.CSharp.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="Sandbox.Common, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\GameBinaries\Sandbox.Common.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="Sandbox.Game, Version=0.1.6305.30774, Culture=neutral, processorArchitecture=AMD64">
<HintPath>..\GameBinaries\Sandbox.Game.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="Sandbox.Graphics, Version=0.1.6305.30761, Culture=neutral, processorArchitecture=AMD64">
<HintPath>..\GameBinaries\Sandbox.Graphics.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="SpaceEngineers.Game, Version=1.0.0.0, Culture=neutral, processorArchitecture=AMD64">
<HintPath>..\GameBinaries\SpaceEngineers.Game.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="Steamworks.NET">
<HintPath>..\GameBinaries\Steamworks.NET.dll</HintPath>
</Reference>
<Reference Include="VRage, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\GameBinaries\VRage.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="VRage.Audio, Version=1.0.0.0, Culture=neutral, processorArchitecture=AMD64">
<HintPath>..\GameBinaries\VRage.Audio.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="VRage.Dedicated, Version=1.0.0.0, Culture=neutral, processorArchitecture=AMD64">
<HintPath>..\GameBinaries\VRage.Dedicated.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="VRage.Game, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\GameBinaries\VRage.Game.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="VRage.Input, Version=1.0.0.0, Culture=neutral, processorArchitecture=AMD64">
<HintPath>..\GameBinaries\VRage.Input.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="VRage.Library, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\GameBinaries\VRage.Library.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="VRage.Math, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\GameBinaries\VRage.Math.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="VRage.Platform.Windows, Culture=neutral, PublicKeyToken=null">
<HintPath>..\GameBinaries\VRage.Platform.Windows.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Render, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\GameBinaries\VRage.Render.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="VRage.Render11, Version=1.0.0.0, Culture=neutral, processorArchitecture=AMD64">
<HintPath>..\GameBinaries\VRage.Render11.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="VRage.Scripting, Version=1.0.0.0, Culture=neutral, processorArchitecture=AMD64">
<HintPath>..\GameBinaries\VRage.Scripting.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="VRage.Steam">
<HintPath>..\GameBinaries\VRage.Steam.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Remove="ServerManager.cs" />
<Compile Remove="ViewModels\SessionSettingsViewModel1.cs" />
<Compile Remove="Views\WorldSelectControl.xaml.cs" />
<Compile Include="..\Versioning\AssemblyVersion.cs" Link="Properties/AssemblyVersion.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Torch.API\Torch.API.csproj" />
<ProjectReference Include="..\Torch\Torch.csproj" />
</ItemGroup>
<ItemGroup>
<Resource Include="torchicon.ico" />
</ItemGroup>
<ItemGroup>
<Page Remove="Views\WorldSelectControl.xaml" />
<EmbeddedResource Include="..\NLog.config" Visible="false" />

View File

@@ -71,10 +71,6 @@ namespace Torch.Server
[Display(Name = "No GUI", Description = "Do not show the Torch UI.", GroupName = "Window")]
public bool NoGui { get => _noGui; set => Set(value, ref _noGui); }
/// <inheritdoc />
[XmlIgnore, Arg("waitforpid", "Makes Torch wait for another process to exit.")]
public string WaitForPID { get; set; }
/// <inheritdoc />
[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); }

View File

@@ -37,15 +37,9 @@ namespace Torch.Server
{
public class TorchServer : TorchBase, ITorchServer
{
private bool _hasRun;
private bool _canRun;
private TimeSpan _elapsedPlayTime;
private bool _isRunning;
private float _simRatio;
private ServerState _state;
private Stopwatch _uptime;
private Timer _watchdog;
private int _players;
private MultiplayerManagerDedicated _multiplayerManagerDedicated;
internal bool FatalException { get; set; }
@@ -67,11 +61,13 @@ namespace Torch.Server
var sessionManager = Managers.GetManager<ITorchSessionManager>();
sessionManager.AddFactory(x => new MultiplayerManagerDedicated(this));
sessionManager.SessionStateChanged += OnSessionStateChanged;
// Needs to be done at some point after MyVRageWindows.Init
// where the debug listeners are registered
if (!((TorchConfig)Config).EnableAsserts)
MyDebug.Listeners.Clear();
_simUpdateTimer.Elapsed += SimUpdateElapsed;
_simUpdateTimer.Start();
}
@@ -85,7 +81,7 @@ namespace Torch.Server
}
}
public bool HasRun { get => _hasRun; set => SetValue(ref _hasRun, value); }
public bool HasRun { get; set; }
/// <inheritdoc />
@@ -104,22 +100,19 @@ namespace Torch.Server
}
/// <inheritdoc />
public TimeSpan ElapsedPlayTime { get => _elapsedPlayTime; set => SetValue(ref _elapsedPlayTime, value); }
public TimeSpan ElapsedPlayTime { get; set; }
/// <inheritdoc />
public Thread GameThread => MySandboxGame.Static?.UpdateThread;
/// <inheritdoc />
public bool IsRunning { get => _isRunning; set => SetValue(ref _isRunning, value); }
public bool IsRunning { get; set; }
public bool CanRun { get => _canRun; set => SetValue(ref _canRun, value); }
public bool CanRun { get; set; }
/// <inheritdoc />
public InstanceManager DedicatedInstance { get; }
/// <inheritdoc />
public string InstanceName { get; }
/// <inheritdoc />
protected override uint SteamAppId => 244850;
@@ -127,22 +120,17 @@ namespace Torch.Server
protected override string SteamAppName => "SpaceEngineersDedicated";
/// <inheritdoc />
public ServerState State { get => _state; private set => SetValue(ref _state, value); }
public ServerState State { get; private set; }
public event Action<ITorchServer> Initialized;
/// <inheritdoc />
public string InstancePath { get; }
public int OnlinePlayers { get => _players; private set => SetValue(ref _players, value); }
public int OnlinePlayers { get; private set; }
/// <inheritdoc />
public override void Init()
{
Log.Info("Initializing server");
MySandboxGame.IsDedicated = true;
base.Init();
Managers.GetManager<ITorchSessionManager>().SessionStateChanged += OnSessionStateChanged;
GetManager<InstanceManager>().LoadInstance(InstancePath);
CanRun = true;
Initialized?.Invoke(this);
@@ -221,9 +209,10 @@ namespace Torch.Server
LogManager.Flush();
string exe = Assembly.GetExecutingAssembly().Location.Replace("dll", "exe");
config.WaitForPID = Environment.ProcessId.ToString();
config.TempAutostart = true;
Process.Start(exe, config.ToString());
Process.Start(exe, $"-waitForPid {Environment.ProcessId} {config}");
Environment.Exit(0);
})
@@ -235,21 +224,27 @@ namespace Torch.Server
[SuppressPropertyChangedWarnings]
private void OnSessionStateChanged(ITorchSession session, TorchSessionState newState)
{
if (newState == TorchSessionState.Unloading || newState == TorchSessionState.Unloaded)
switch (newState)
{
_watchdog?.Dispose();
_watchdog = null;
ModCommunication.Unregister();
case TorchSessionState.Unloading:
_watchdog?.Dispose();
_watchdog = null;
ModCommunication.Unregister();
break;
case TorchSessionState.Loaded:
_multiplayerManagerDedicated = CurrentSession.Managers.GetManager<MultiplayerManagerDedicated>();
_multiplayerManagerDedicated.PlayerJoined += MultiplayerManagerDedicatedOnPlayerJoined;
_multiplayerManagerDedicated.PlayerLeft += MultiplayerManagerDedicatedOnPlayerLeft;
CurrentSession.Managers.GetManager<CommandManager>().RegisterCommandModule(typeof(WhitelistCommands));
ModCommunication.Register();
break;
case TorchSessionState.Loading:
case TorchSessionState.Unloaded:
break;
default:
throw new ArgumentOutOfRangeException(nameof(newState), newState, null);
}
if (newState == TorchSessionState.Loaded)
{
_multiplayerManagerDedicated = CurrentSession.Managers.GetManager<MultiplayerManagerDedicated>();
_multiplayerManagerDedicated.PlayerJoined += MultiplayerManagerDedicatedOnPlayerJoined;
_multiplayerManagerDedicated.PlayerLeft += MultiplayerManagerDedicatedOnPlayerLeft;
CurrentSession.Managers.GetManager<CommandManager>().RegisterCommandModule(typeof(WhitelistCommands));
ModCommunication.Register();
}
}
private void MultiplayerManagerDedicatedOnPlayerLeft(IPlayer player)
@@ -370,35 +365,34 @@ namespace Torch.Server
// return stack.ToString();
// Modified from https://www.examplefiles.net/cs/579311
using (var target = DataTarget.CreateSnapshotAndAttach(Environment.ProcessId))
using var target = DataTarget.CreateSnapshotAndAttach(Environment.ProcessId);
var runtime = target.ClrVersions[0].CreateRuntime();
var clrThread = runtime.Threads.First(b => b.ManagedThreadId == thread.ManagedThreadId);
var sb = new StringBuilder();
foreach (var frame in clrThread.EnumerateStackTrace())
{
var runtime = target.ClrVersions[0].CreateRuntime();
var clrThread = runtime.Threads.First(b => b.ManagedThreadId == thread.ManagedThreadId);
var sb = new StringBuilder();
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

View File

@@ -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,8 +32,8 @@ internal class UnhandledExceptionHandler
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());
Process.Start(exe, $"-waitForPid {Environment.ProcessId} {_config}");
}
else
{

View File

@@ -1,23 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Steamworks;
namespace Torch.Server.ViewModels
{
public class SteamUserViewModel : ViewModel
{
public string Name { get; }
public ulong SteamId { get; }
public SteamUserViewModel(ulong id)
{
SteamId = id;
Name = SteamFriends.GetFriendPersonaName(new CSteamID(id));
}
public SteamUserViewModel() : this(0) { }
}
}

View File

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

View File

@@ -15,7 +15,8 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ScrollViewer CanContentScroll="True" ScrollChanged="ScrollViewer_OnScrollChanged" Loaded="ScrollViewer_OnLoaded" Unloaded="ScrollViewer_OnUnloaded">
<ScrollViewer CanContentScroll="True" ScrollChanged="ScrollViewer_OnScrollChanged"
Loaded="ScrollViewer_OnLoaded" Unloaded="ScrollViewer_OnUnloaded">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
@@ -31,10 +32,6 @@
</Setter>
</Style>
<Style TargetType="{x:Type TextBlock}" x:Key="TextBlockBaseStyle">
<Setter Property="FontFamily" Value="Consolas" />
</Style>
<DataTemplate DataType="{x:Type viewModels:LogEntry}">
<Grid IsSharedSizeScope="True">
<Grid.ColumnDefinitions>
@@ -43,10 +40,16 @@
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Timestamp, StringFormat=HH:mm:ss.fff}" Grid.Column="0"
FontWeight="Bold" Style="{StaticResource TextBlockBaseStyle}" Foreground="{Binding Color}" Margin="5,0,5,0" />
FontWeight="Bold" FontFamily="Consolas" Foreground="{Binding Color}" Margin="5,0,5,0" />
<TextBlock Text="{Binding Message}" Grid.Column="1"
TextWrapping="Wrap" Style="{StaticResource TextBlockBaseStyle}" Foreground="{Binding Color}" />
<TextBox Grid.Column="1"
Text="{Binding Message, Mode=OneWay}"
TextWrapping="Wrap"
FontFamily="Consolas"
Background="Transparent"
BorderThickness="0"
IsReadOnly="True"
Foreground="{Binding Color}" />
</Grid>
</DataTemplate>
</UserControl.Resources>

View File

@@ -130,17 +130,17 @@ namespace Torch.Server.Views
//blocking
editor.Edit<string>(idList, "Mods");
modList.RemoveAll(m =>
{
var mod = m.ToString();
return idList.Any(mod.Equals);
});
modList.Clear();
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));
return info;
}));
}).Where(b => b is not null));
_instanceManager.DedicatedConfig.Mods.Clear();
foreach (var mod in modList)
_instanceManager.DedicatedConfig.Mods.Add(mod);

View File

@@ -50,7 +50,7 @@ namespace Torch.Server.Views
var PercentChangeOnDownload = 100 / PluginsToDownload.Count;
foreach (PluginItem PluginItem in PluginsToDownload) {
if (!Task.Run(async () => await PluginQuery.Instance.DownloadPlugin(PluginItem.Id)).Result) {
if (!PluginQuery.Instance.DownloadPlugin(PluginItem.Id).Result) {
failedDownloads++;
DownloadProgress += PercentChangeOnDownload;
(sender as BackgroundWorker).ReportProgress(DownloadProgress);

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">
<PropertyGroup>
<TargetFramework>net6-windows</TargetFramework>
<LangVersion>10</LangVersion>
<NoWarn>1591,0649</NoWarn>
<AssemblyTitle>Torch Tests</AssemblyTitle>
<Product>Torch</Product>
@@ -8,7 +9,6 @@
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<OutputPath>$(SolutionDir)\bin-test\$(Platform)\$(Configuration)\</OutputPath>
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>
<PlatformTarget>x64</PlatformTarget>
<Configurations>Debug;Release</Configurations>
<Platforms>AnyCPU</Platforms>
@@ -18,22 +18,15 @@
</PropertyGroup>
<!-- <Import Project="$(SolutionDir)\TransformOnBuild.targets" /> -->
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="NLog" Version="5.0.0-rc2" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="NLog" Version="5.0.4" />
<PackageReference Include="xunit" Version="2.4.2" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Net.Http" />
</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>
<ProjectReference Include="..\Torch.API\Torch.API.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

@@ -18,13 +18,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.Tests", "Torch.Tests\
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
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CI/CD workflows", "CI/CD workflows", "{DFC9AB6D-BD21-4748-8CE8-57097DC673AF}"
ProjectSection(SolutionItems) = preProject
.github\workflows\release.yaml = .github\workflows\release.yaml
EndProjectSection
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
Torch.Mod\Torch.Mod.projitems*{3ce4d2e9-b461-4f19-8233-f87e0dfddd74}*SharedItemsImports = 13
@@ -56,7 +56,7 @@ Global
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{762F6A0D-55EF-4173-8CDE-309D183F40C4} = {7AD02A71-1D4C-48F9-A8C1-789A5512424F}
{DFC9AB6D-BD21-4748-8CE8-57097DC673AF} = {7AD02A71-1D4C-48F9-A8C1-789A5512424F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
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

@@ -11,7 +11,6 @@ using System.Timers;
using NLog;
using Sandbox.Game.Multiplayer;
using Sandbox.ModAPI;
using Steamworks;
using Torch;
using Torch.API;
using Torch.API.Managers;

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
@@ -11,6 +12,7 @@ using System.Reflection.Emit;
using System.Text.RegularExpressions;
using System.Threading;
using Microsoft.CodeAnalysis;
using ProtoBuf;
using Torch.Managers.PatchManager;
using Torch.Managers.PatchManager.MSIL;
using Torch.Utils;
@@ -40,14 +42,12 @@ namespace Torch.Patches
context.GetPattern(Register2Method).AddTranspiler(nameof(RegisterTranspiler));
}
private static void WhitelistCtorPrefix(MyScriptCompiler scriptCompiler, MyScriptWhitelist __instance)
private static void WhitelistCtorPrefix(MyScriptCompiler scriptCompiler)
{
var basePath = new FileInfo(typeof(object).Assembly.Location).DirectoryName!;
var baseDir = new FileInfo(typeof(Type).Assembly.Location).DirectoryName!;
scriptCompiler.AddReferencedAssemblies(
Path.Combine(basePath, "netstandard.dll"),
Path.Combine(basePath, "mscorlib.dll"),
Path.Combine(basePath, "System.Runtime.dll"),
typeof(Type).Assembly.Location,
typeof(LinkedList<>).Assembly.Location,
typeof(Regex).Assembly.Location,
typeof(Enumerable).Assembly.Location,
@@ -56,8 +56,11 @@ namespace Torch.Patches
typeof(PropertyChangedEventArgs).Assembly.Location,
typeof(TypeConverter).Assembly.Location,
typeof(System.Diagnostics.TraceSource).Assembly.Location,
typeof(System.Security.Policy.Evidence).Assembly.Location,
typeof(ProtoBuf.Meta.RuntimeTypeModel).Assembly.Location,
typeof(ProtoBuf.ProtoMemberAttribute).Assembly.Location,
typeof(ProtoContractAttribute).Assembly.Location,
Path.Combine(baseDir, "netstandard.dll"),
Path.Combine(baseDir, "System.Runtime.dll"),
Path.Combine(MyFileSystem.ExePath, "Sandbox.Game.dll"),
Path.Combine(MyFileSystem.ExePath, "Sandbox.Common.dll"),
Path.Combine(MyFileSystem.ExePath, "Sandbox.Graphics.dll"),
@@ -76,9 +79,10 @@ namespace Torch.Patches
MyModWatchdog.Init(updateThread);
MyScriptCompiler.Static.AddImplicitIngameNamespacesFromTypes(referencedTypes);
MyScriptCompiler.Static.AddConditionalCompilationSymbols(symbols);
using var batch = MyScriptCompiler.Static.Whitelist.OpenBatch();
// Dict and queue in different assemblies, microsoft being microsoft
batch.AllowNamespaceOfTypes(MyWhitelistTarget.ModApi, typeof(ConcurrentQueue<>));
batch.AllowTypes(MyWhitelistTarget.ModApi, typeof(ConcurrentQueue<>));
return false;
}

View File

@@ -20,6 +20,7 @@ namespace Torch
public sealed class Persistent<T> : IDisposable where T : new()
{
private static readonly XmlSerializer Serializer = new(typeof(T));
private static readonly XmlSerializerNamespaces Namespaces = new(new[] {new XmlQualifiedName("", "")});
private static Logger _log = LogManager.GetCurrentClassLogger();
public string Path { get; set; }
private T _data;
@@ -69,9 +70,10 @@ namespace Torch
using var f = File.Create(path);
using var writer = new XmlTextWriter(f, Encoding.UTF8)
{
Formatting = Formatting.Indented
Formatting = Formatting.Indented,
Namespaces = false
};
Serializer.Serialize(writer, Data);
Serializer.Serialize(writer, Data, Namespaces);
}
public static Persistent<T> Load(string path, bool saveIfNew = true)

View File

@@ -384,6 +384,13 @@ namespace Torch.Managers
}
var harmonyAssembly = assemblies.FirstOrDefault(b => b.FullName?.StartsWith("0Harmony") == true);
if (harmonyAssembly is { })
{
_log.Warn($"Plugin {item.Manifest.Name} is using harmony library, logic collision between plugins could be encountered!");
assemblies.Remove(harmonyAssembly);
}
RegisterAllAssemblies(assemblies);
InstantiatePlugin(item.Manifest, assemblies);
}
@@ -412,12 +419,15 @@ namespace Torch.Managers
AppDomain.CurrentDomain.AssemblyResolve += ResolveDependentAssembly;
foreach (Assembly asm in assemblies)
{
TorchBase.RegisterAuxAssembly(asm);
TorchLauncher.RegisterAssembly(asm);
}
}
private static bool IsAssemblyCompatible(AssemblyName a, AssemblyName b)
{
if (a.Version is null || b.Version is null)
return a.Name == b.Name;
return a.Name == b.Name && a.Version.Major == b.Version.Major && a.Version.Minor == b.Version.Minor;
}

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

@@ -113,7 +113,7 @@ namespace Torch.Session
_currentSession.Detach();
}
_log.Info($"Starting new torch session for {_instanceManager.SelectedWorld.FolderName}");
_log.Info($"Starting new torch session for {_instanceManager.SelectedWorld.KeenCheckpoint.SessionName}");
_currentSession = new TorchSession(Torch, MySession.Static, _instanceManager.SelectedWorld);
SetState(TorchSessionState.Loading);
@@ -139,7 +139,7 @@ namespace Torch.Session
CurrentSession.Managers.AddManager(manager);
}
(CurrentSession as TorchSession)?.Attach();
_log.Info($"Loaded torch session for {CurrentSession.World.FolderName}");
_log.Info($"Loaded torch session for {CurrentSession.World.KeenCheckpoint.SessionName}");
SetState(TorchSessionState.Loaded);
}
catch (Exception e)
@@ -156,7 +156,7 @@ namespace Torch.Session
if (_currentSession is null)
throw new InvalidOperationException("Session loaded event occurred when we don't have a session.");
_log.Info($"Unloading torch session for {_currentSession.World.FolderName}");
_log.Info($"Unloading torch session for {_currentSession.World.KeenCheckpoint.SessionName}");
SetState(TorchSessionState.Unloading);
_currentSession.Detach();
}
@@ -174,7 +174,7 @@ namespace Torch.Session
if (_currentSession is null)
throw new InvalidOperationException("Session loaded event occurred when we don't have a session.");
_log.Info($"Unloaded torch session for {_currentSession.World.FolderName}");
_log.Info($"Unloaded torch session for {_currentSession.World.KeenCheckpoint.SessionName}");
SetState(TorchSessionState.Unloaded);
_currentSession = null;
}

View File

@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6-windows</TargetFramework>
<LangVersion>10</LangVersion>
<AssemblyTitle>Torch</AssemblyTitle>
<Product>Torch</Product>
<Copyright>Copyright © Torch API 2017</Copyright>
@@ -8,121 +9,38 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<OutputPath>..\bin\$(Platform)\$(Configuration)\</OutputPath>
<UseWpf>True</UseWpf>
<GenerateAssemblyInfo>False</GenerateAssemblyInfo>
<PlatformTarget>x64</PlatformTarget>
<Configurations>Debug;Release</Configurations>
<Platforms>AnyCPU</Platforms>
</PropertyGroup>
<PropertyGroup Condition="$(Configuration) == 'Release'">
<NoWarn>1591</NoWarn>
</PropertyGroup>
<Import Project="..\Torch.Mod\Torch.Mod.projitems" Label="Shared" />
<!-- <Import Project="$(SolutionDir)\TransformOnBuild.targets" /> -->
<ItemGroup>
<PackageReference Include="ControlzEx" Version="5.0.1" />
<PackageReference Include="InfoOf.Fody" Version="2.1.0" PrivateAssets="all" />
<PackageReference Include="HarmonyX" Version="2.10.0" />
<PackageReference Include="InfoOf.Fody" Version="2.1.1" PrivateAssets="all" />
<PackageReference Include="MahApps.Metro" Version="2.4.9" />
<PackageReference Include="MonoMod.RuntimeDetour" Version="22.1.4.3" />
<PackageReference Include="NLog" Version="5.0.0-rc2" />
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.3.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.3.1" />
<PackageReference Include="MonoMod.RuntimeDetour" Version="22.5.1.1" />
<PackageReference Include="NLog" Version="5.0.4" />
<PackageReference Include="PropertyChanged.Fody" Version="4.0.3" PrivateAssets="all" />
<PackageReference Include="protobuf-net" Version="2.4.7" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="Torch.SixLabors.ImageSharp" Version="1.0.0-beta6" />
<PackageReference Include="SpaceEngineersDedicated.ReferenceAssemblies" Version="1.201.13">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>compile</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Reference Include="HavokWrapper, Version=1.0.6278.22649, Culture=neutral, processorArchitecture=AMD64">
<HintPath>..\GameBinaries\HavokWrapper.dll</HintPath>
<Private>False</Private>
<SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="Microsoft.CodeAnalysis, Version=2.9.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<HintPath>..\GameBinaries\Microsoft.CodeAnalysis.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="ProtoBuf.Net, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>..\GameBinaries\ProtoBuf.Net.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="ProtoBuf.Net.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>..\GameBinaries\ProtoBuf.Net.Core.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Sandbox.Common">
<HintPath>..\GameBinaries\Sandbox.Common.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Sandbox.Game">
<HintPath>..\GameBinaries\Sandbox.Game.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Sandbox.Graphics">
<HintPath>..\GameBinaries\Sandbox.Graphics.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="SpaceEngineers.Game">
<HintPath>..\GameBinaries\SpaceEngineers.Game.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Steamworks.NET">
<HintPath>..\GameBinaries\Steamworks.NET.dll</HintPath>
</Reference>
<Reference Include="VRage">
<HintPath>..\GameBinaries\VRage.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Audio">
<HintPath>..\GameBinaries\VRage.Audio.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Dedicated">
<HintPath>..\GameBinaries\VRage.Dedicated.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.EOS, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>..\GameBinaries\VRage.EOS.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Game">
<HintPath>..\GameBinaries\VRage.Game.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Input">
<HintPath>..\GameBinaries\VRage.Input.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Library">
<HintPath>..\GameBinaries\VRage.Library.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Math">
<HintPath>..\GameBinaries\VRage.Math.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Mod.Io, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<HintPath>..\GameBinaries\VRage.Mod.Io.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Platform.Windows, Culture=neutral, PublicKeyToken=null">
<HintPath>..\GameBinaries\VRage.Platform.Windows.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Render">
<HintPath>..\GameBinaries\VRage.Render.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Render11">
<HintPath>..\GameBinaries\VRage.Render11.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Scripting">
<HintPath>..\GameBinaries\VRage.Scripting.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="VRage.Steam">
<HintPath>..\GameBinaries\VRage.Steam.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Torch.API\Torch.API.csproj" />
</ItemGroup>
</Project>

View File

@@ -37,17 +37,16 @@ namespace Torch
{
static TorchBase()
{
MyVRageWindows.Init("SpaceEngineersDedicated", MySandboxGame.Log, null, false);
ReflectedManager.Process(typeof(TorchBase).Assembly);
ReflectedManager.Process(typeof(ITorchBase).Assembly);
TorchLauncher.RegisterAssembly(typeof(ITorchBase).Assembly);
TorchLauncher.RegisterAssembly(typeof(TorchBase).Assembly);
TorchLauncher.RegisterAssembly(Assembly.GetEntryAssembly());
PatchManager.AddPatchShim(typeof(GameStatePatchShim));
PatchManager.AddPatchShim(typeof(GameAnalyticsPatch));
PatchManager.AddPatchShim(typeof(KeenLogPatch));
PatchManager.AddPatchShim(typeof(XmlRootWriterPatch));
PatchManager.CommitInternal();
RegisterCoreAssembly(typeof(ITorchBase).Assembly);
RegisterCoreAssembly(typeof(TorchBase).Assembly);
RegisterCoreAssembly(Assembly.GetEntryAssembly());
//exceptions in English, please
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");
}
@@ -64,6 +63,8 @@ namespace Torch
/// <inheritdoc />
public SemanticVersioning.Version TorchVersion { get; }
public string InstancePath { get; protected init;}
public string InstanceName { get; protected init; }
/// <inheritdoc />
public Version GameVersion { get; private set; }
@@ -78,18 +79,6 @@ namespace Torch
/// <inheritdoc />
public ITorchSession CurrentSession => Managers?.GetManager<ITorchSessionManager>()?.CurrentSession;
/// <inheritdoc />
public event Action SessionLoading;
/// <inheritdoc />
public event Action SessionLoaded;
/// <inheritdoc />
public event Action SessionUnloading;
/// <inheritdoc />
public event Action SessionUnloaded;
/// <summary>
/// Common log for the Torch instance.
/// </summary>
@@ -106,7 +95,6 @@ namespace Torch
/// <exception cref="InvalidOperationException">Thrown if a TorchBase instance already exists.</exception>
protected TorchBase(ITorchConfig config)
{
RegisterCoreAssembly(GetType().Assembly);
#pragma warning disable CS0618
if (Instance != null)
throw new InvalidOperationException("A TorchBase instance already exists.");
@@ -158,27 +146,6 @@ namespace Torch
PatchManager.CommitInternal();
}
};
sessionManager.SessionStateChanged += (session, state) =>
{
switch (state)
{
case TorchSessionState.Loading:
SessionLoading?.Invoke();
break;
case TorchSessionState.Loaded:
SessionLoaded?.Invoke();
break;
case TorchSessionState.Unloading:
SessionUnloading?.Invoke();
break;
case TorchSessionState.Unloaded:
SessionUnloaded?.Invoke();
break;
default:
throw new ArgumentOutOfRangeException(nameof(state), state, null);
}
};
}
[Obsolete("Prefer using Managers.GetManager for global managers")]
@@ -193,11 +160,6 @@ namespace Torch
return Managers.AddManager(manager);
}
public bool IsOnGameThread()
{
return Thread.CurrentThread.ManagedThreadId == MySandboxGame.Static.UpdateThread.ManagedThreadId;
}
#region Game Actions
/// <summary>
@@ -288,16 +250,15 @@ namespace Torch
public virtual void Init()
{
Debug.Assert(!_init, "Torch instance is already initialized.");
SpaceEngineersGame.SetupBasicGameInfo();
SpaceEngineersGame.SetupPerGameSettings();
ObjectFactoryInitPatch.ForceRegisterAssemblies();
VRageGame.SetupVersionInfo();
Debug.Assert(MyPerGameSettings.BasicGameInfo.GameVersion != null, "MyPerGameSettings.BasicGameInfo.GameVersion != null");
GameVersion = new MyVersion(MyPerGameSettings.BasicGameInfo.GameVersion.Value);
try
{
Console.Title = $"{Config.InstanceName} - Torch {TorchVersion}, SE {GameVersion}";
Console.Title = $"{InstanceName} - Torch {TorchVersion}, SE {GameVersion}";
}
catch
{
@@ -311,17 +272,17 @@ namespace Torch
#endif
Log.Info($"Torch Version: {TorchVersion}");
Log.Info($"Game Version: {GameVersion}");
Log.Info($"Executing assembly: {Assembly.GetEntryAssembly().FullName}");
Log.Info($"Executing assembly: {Assembly.GetEntryAssembly()?.FullName}");
Log.Info($"Executing directory: {AppDomain.CurrentDomain.BaseDirectory}");
Managers.GetManager<PluginManager>().LoadPlugins();
Game = new VRageGame(this, TweakGameSettings, SteamAppName, SteamAppId, Config.InstancePath, RunArgs);
Game = new VRageGame(this, TweakGameSettings, SteamAppName, SteamAppId, InstancePath, RunArgs);
if (!Game.WaitFor(VRageGame.GameState.Stopped))
Log.Warn("Failed to wait for game to be initialized");
Managers.Attach();
_init = true;
if (GameState >= TorchGameState.Created && GameState < TorchGameState.Unloading)
if (GameState is >= TorchGameState.Created and < TorchGameState.Unloading)
// safe to commit here; all important static ctors have run
PatchManager.CommitInternal();
}
@@ -435,41 +396,5 @@ namespace Torch
/// <inheritdoc/>
public event TorchGameStateChangedDel GameStateChanged;
private static readonly HashSet<Assembly> _registeredCoreAssemblies = new HashSet<Assembly>();
/// <summary>
/// Registers a core (Torch) assembly with the system, including its
/// <see cref="EventManager"/> shims, <see cref="PatchManager"/> shims, and <see cref="ReflectedManager"/> components.
/// </summary>
/// <param name="asm">Assembly to register</param>
internal static void RegisterCoreAssembly(Assembly asm)
{
lock (_registeredCoreAssemblies)
if (_registeredCoreAssemblies.Add(asm))
{
ReflectedManager.Process(asm);
EventManager.AddDispatchShims(asm);
PatchManager.AddPatchShims(asm);
}
}
private static readonly HashSet<Assembly> _registeredAuxAssemblies = new HashSet<Assembly>();
private static readonly TimeSpan _gameStateChangeTimeout = TimeSpan.FromMinutes(1);
/// <summary>
/// Registers an auxillary (plugin) assembly with the system, including its
/// <see cref="ReflectedManager"/> related components.
/// </summary>
/// <param name="asm">Assembly to register</param>
internal static void RegisterAuxAssembly(Assembly asm)
{
lock (_registeredAuxAssemblies)
if (_registeredAuxAssemblies.Add(asm))
{
ReflectedManager.Process(asm);
PatchManager.AddPatchShims(asm);
}
}
}
}

View File

@@ -6,7 +6,6 @@ using System.Threading;
using Sandbox.Engine.Multiplayer;
using Sandbox.Game.Entities;
using Sandbox.Game.World;
using Steamworks;
namespace Torch.Utils
{
@@ -54,12 +53,6 @@ namespace Torch.Utils
return result;
}
public static IPAddress GetRemoteIP(this P2PSessionState_t state)
{
// What is endianness anyway?
return new IPAddress(BitConverter.GetBytes(state.m_nRemoteIP).Reverse().ToArray());
}
public static string GetGridOwnerName(this MyCubeGrid grid)
{
if (grid.BigOwners.Count == 0 || grid.BigOwners[0] == 0)

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Sandbox.Engine.Networking;
using Torch.API;
@@ -19,6 +20,43 @@ namespace Torch.Utils
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!
public static string GetDefaultServiceName()
{

View File

@@ -1,29 +1,31 @@
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;
using NLog;
using Torch.Event;
using Torch.Managers.PatchManager;
namespace Torch.Utils
{
public class TorchLauncher
public static class TorchLauncher
{
private static readonly Dictionary<string, string> Assemblies = new Dictionary<string, string>();
private static readonly ILogger Log = LogManager.GetCurrentClassLogger();
private static readonly HashSet<Assembly> RegisteredAssemblies = new();
private static readonly Dictionary<string, string> Assemblies = new();
public static void Launch(params string[] binaryPaths)
{
CopyNative();
foreach (var file in binaryPaths.SelectMany(path => Directory.EnumerateFiles(path, "*.dll")))
{
try
{
var name = AssemblyName.GetAssemblyName(file);
Assemblies.TryAdd(name.Name ?? name.FullName.Split(',')[0], file);
var key = name.Name ?? name.FullName[..','];
Assemblies.TryAdd(key, file);
}
catch (BadImageFormatException)
{
@@ -34,10 +36,64 @@ namespace Torch.Utils
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainOnAssemblyResolve;
}
public static void RegisterAssembly(Assembly assembly)
{
if (!RegisteredAssemblies.Add(assembly))
return;
ReflectedManager.Process(assembly);
EventManager.AddDispatchShims(assembly);
PatchManager.AddPatchShims(assembly);
}
private static void CopyNative()
{
if (ApplicationContext.Current.GameFilesDirectory.Attributes.HasFlag(FileAttributes.ReadOnly))
{
Log.Warn("Torch directory is readonly. You should copy steam_api64.dll, Havok.dll from bin manually");
return;
}
try
{
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) < ApplicationContext.Current.GameBinariesDirectory.LastWriteTime)
{
File.Delete(apiTarget);
File.Copy(apiSource, apiTarget);
}
var havokSource = Path.Combine(ApplicationContext.Current.GameBinariesDirectory.FullName, "Havok.dll");
var havokTarget = Path.Combine(ApplicationContext.Current.GameFilesDirectory.FullName, "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);
}
}
catch (UnauthorizedAccessException)
{
// file is being used by another process, probably previous torch has not been closed yet
}
catch (Exception e)
{
Log.Error(e);
}
}
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[..name.IndexOf(',')] : name, out var path) ? Assembly.LoadFrom(path) : null;
}
}
}

View File

@@ -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,7 @@ namespace Torch.Utils;
public static class TorchLogManager
{
private static AssemblyLoadContext LoadContext = new("TorchLog");
private static readonly AssemblyLoadContext LoadContext = new("TorchLog");
public static LoggingConfiguration Configuration { get; private set; }
@@ -26,7 +28,8 @@ 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")
.Select(LoadContext.LoadFromAssemblyPath)
.SelectMany(b => b.ExportedTypes)
.Where(b => b.GetCustomAttribute<TargetAttribute>() is { }))
{

View File

@@ -22,7 +22,6 @@ using Sandbox.Game.World;
using Sandbox.Graphics.GUI;
using SpaceEngineers.Game;
using SpaceEngineers.Game.GUI;
using Steamworks;
using Torch.API;
using Torch.Utils;
using VRage;
@@ -35,11 +34,13 @@ using VRage.Game.ObjectBuilder;
using VRage.Game.SessionComponents;
using VRage.GameServices;
using VRage.Mod.Io;
using VRage.Platform.Windows;
using VRage.Plugins;
using VRage.Scripting;
using VRage.Steam;
using VRage.Utils;
using VRageRender;
using Game = Sandbox.Engine.Platform.Game;
using MyRenderProfiler = VRage.Profiler.MyRenderProfiler;
namespace Torch
@@ -138,13 +139,19 @@ namespace Torch
}
}
internal static void SetupVersionInfo()
{
Game.IsDedicated = true;
SpaceEngineersGame.SetupBasicGameInfo();
MyFinalBuildConstants.APP_VERSION = MyPerGameSettings.BasicGameInfo.GameVersion;
}
private void Create()
{
bool dedicated = true;
var dedicated = Game.IsDedicated;
Environment.SetEnvironmentVariable("SteamAppId", _appSteamId.ToString());
SpaceEngineersGame.SetupBasicGameInfo();
MyVRageWindows.Init("SpaceEngineersDedicated", MySandboxGame.Log, null, false);
SpaceEngineersGame.SetupPerGameSettings();
MyFinalBuildConstants.APP_VERSION = MyPerGameSettings.BasicGameInfo.GameVersion;
MySessionComponentExtDebug.ForceDisable = true;
MyPerGameSettings.SendLogToKeen = false;
// SpaceEngineersGame.SetupAnalytics();

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="TransformOnBuild">
<ItemGroup>
<TemplatePaths Include="@(None)" Condition="'%(None.Generator)' == 'TextTemplatingFileGenerator'" />
</ItemGroup>
<Exec Command="&quot;$(SolutionDir)\packages\Mono.TextTransform.1.0.0\tools\TextTransform.exe&quot; &quot;%(TemplatePaths.FullPath)&quot;" Condition="'%(TemplatePaths.Identity)' != ''"/>
</Target>
</Project>

View File

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

View File

@@ -1,65 +0,0 @@
version: 1.0.{build}-{branch}
pull_requests:
do_not_increment_build_number: true
branches:
only:
- master
skip_tags: true
image: Visual Studio 2022
configuration: Release
platform: x64
shallow_clone: true
assembly_info:
patch: true
file: '**\AssemblyVersion.*'
assembly_version: '{version}'
assembly_file_version: '{version}'
assembly_informational_version: v{version}
install:
- pwsh: >-
$steamData = "c:/steam/dedi/"
$steamCMDPath = "c:/steam/cmd/"
$steamCMDZip = "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
cache:
- c:\steam\dedi\
- c:\steam\cmd\
build_script:
- pwsh: >-
dotnet publish .\Torch.Server\Torch.Server.csproj --self-contained -f net6-windows -r win-x64 -c Release -o .\publish\
Compress-Archive -Path .\publish\* -DestinationPath .\torch-server.zip
artifacts:
- path: torch-server.zip
deploy:
- provider: GitHub
tag: v$(appveyor_build_version)
release: Torch - v$(appveyor_build_version)
auth_token:
secure: IOhwzgIpj85iHitQBiH4chKPL9fXAinEnqUcbZk0ANhfTmdUFh74ko7Bt7LoSJFy
artifact: torch-server.zip
on:
branch: master