Many more things use the new reflection system
Project for Torch.Server tests. Refactoring some of the torch utility classes into a different namespace.
This commit is contained in:
2
Jenkinsfile
vendored
2
Jenkinsfile
vendored
@@ -19,7 +19,7 @@ node {
|
||||
|
||||
stage('Test') {
|
||||
bat 'IF NOT EXIST GameBinaries MKDIR GameBinaries'
|
||||
bat "\"packages/xunit.runner.console.2.2.0/tools/xunit.console.exe\" \"bin-test/x64/Release/Torch.Tests.dll\" -parallel none -xml \"reports/Torch.Tests.xml\""
|
||||
bat "\"packages/xunit.runner.console.2.2.0/tools/xunit.console.exe\" \"bin-test/x64/Release/Torch.Tests.dll\" \"bin-test/x64/Release/Torch.Server.Tests.dll\" -parallel none -xml \"reports/Torch.Tests.xml\""
|
||||
step([
|
||||
$class: 'XUnitBuilder',
|
||||
thresholdMode: 1,
|
||||
|
@@ -9,6 +9,7 @@ using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using NLog;
|
||||
using Torch.Utils;
|
||||
using MessageBox = System.Windows.MessageBox;
|
||||
|
||||
namespace Torch.Client
|
||||
|
36
Torch.Server.Tests/Properties/AssemblyInfo.cs
Normal file
36
Torch.Server.Tests/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Torch.Server.Tests")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Torch.Server.Tests")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("9efd1d91-2fa2-47ed-b537-d8bc3b0e543e")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
85
Torch.Server.Tests/Torch.Server.Tests.csproj
Normal file
85
Torch.Server.Tests/Torch.Server.Tests.csproj
Normal file
@@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{9EFD1D91-2FA2-47ED-B537-D8BC3B0E543E}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Torch.Server.Tests</RootNamespace>
|
||||
<AssemblyName>Torch.Server.Tests</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile />
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
<NoWarn>1591,0649</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>$(SolutionDir)\bin-test\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>$(SolutionDir)\bin-test\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<DocumentationFile>$(SolutionDir)\bin-test\x64\Release\Torch.Server.Tests.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="xunit.assert, Version=2.2.0.3545, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\xunit.assert.2.2.0\lib\netstandard1.1\xunit.assert.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="xunit.core, Version=2.2.0.3545, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\xunit.extensibility.core.2.2.0\lib\netstandard1.1\xunit.core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="xunit.execution.desktop, Version=2.2.0.3545, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\xunit.extensibility.execution.2.2.0\lib\net452\xunit.execution.desktop.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="TorchServerReflectionTest.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Torch.API\Torch.API.csproj">
|
||||
<Project>{fba5d932-6254-4a1e-baf4-e229fa94e3c2}</Project>
|
||||
<Name>Torch.API</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Torch.Server\Torch.Server.csproj">
|
||||
<Project>{ca50886b-7b22-4cd8-93a0-c06f38d4f77d}</Project>
|
||||
<Name>Torch.Server</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Torch.Tests\Torch.Tests.csproj">
|
||||
<Project>{c3c8b671-6ad1-44aa-a8da-e0c0dc0fedf5}</Project>
|
||||
<Name>Torch.Tests</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Torch\Torch.csproj">
|
||||
<Project>{7e01635c-3b67-472e-bcd6-c5539564f214}</Project>
|
||||
<Name>Torch</Name>
|
||||
<Private>True</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
66
Torch.Server.Tests/TorchServerReflectionTest.cs
Normal file
66
Torch.Server.Tests/TorchServerReflectionTest.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System.Collections.Generic;
|
||||
using Torch.Tests;
|
||||
using Torch.Utils;
|
||||
using Xunit;
|
||||
|
||||
namespace Torch.Server.Tests
|
||||
{
|
||||
public class TorchServerReflectionTest
|
||||
{
|
||||
static TorchServerReflectionTest()
|
||||
{
|
||||
TestUtils.Init();
|
||||
}
|
||||
|
||||
private static ReflectionTestManager _manager;
|
||||
|
||||
private static ReflectionTestManager Manager()
|
||||
{
|
||||
if (_manager != null)
|
||||
return _manager;
|
||||
|
||||
return _manager = new ReflectionTestManager().Init(typeof(TorchServer).Assembly);
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> Getters => Manager().Getters;
|
||||
|
||||
public static IEnumerable<object[]> Setters => Manager().Setters;
|
||||
|
||||
public static IEnumerable<object[]> Invokers => Manager().Invokers;
|
||||
|
||||
#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));
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
10
Torch.Server.Tests/packages.config
Normal file
10
Torch.Server.Tests/packages.config
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="xunit" version="2.2.0" targetFramework="net461" />
|
||||
<package id="xunit.abstractions" version="2.0.1" targetFramework="net461" />
|
||||
<package id="xunit.assert" version="2.2.0" targetFramework="net461" />
|
||||
<package id="xunit.core" version="2.2.0" targetFramework="net461" />
|
||||
<package id="xunit.extensibility.core" version="2.2.0" targetFramework="net461" />
|
||||
<package id="xunit.extensibility.execution" version="2.2.0" targetFramework="net461" />
|
||||
<package id="xunit.runner.console" version="2.2.0" targetFramework="net461" developmentDependency="true" />
|
||||
</packages>
|
@@ -19,6 +19,7 @@ using SteamSDK;
|
||||
using Torch.API;
|
||||
using Torch.Managers;
|
||||
using Torch.Server.Managers;
|
||||
using Torch.Utils;
|
||||
using VRage.Dedicated;
|
||||
using VRage.FileSystem;
|
||||
using VRage.Game;
|
||||
@@ -121,6 +122,9 @@ namespace Torch.Server
|
||||
MySandboxGame.Config.Load();
|
||||
}
|
||||
|
||||
[ReflectedStaticMethod(Type = typeof(DedicatedServer), Name = "RunInternal")]
|
||||
private static Action _dsRunInternal;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Start()
|
||||
{
|
||||
@@ -134,8 +138,6 @@ namespace Torch.Server
|
||||
State = ServerState.Starting;
|
||||
Log.Info("Starting server.");
|
||||
|
||||
var runInternal = typeof(DedicatedServer).GetMethod("RunInternal", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
|
||||
MySandboxGame.IsDedicated = true;
|
||||
Environment.SetEnvironmentVariable("SteamAppId", MyPerServerSettings.AppId.ToString());
|
||||
|
||||
@@ -144,7 +146,7 @@ namespace Torch.Server
|
||||
base.Start();
|
||||
//Stops RunInternal from calling MyFileSystem.InitUserSpecific(null), we call it in InstanceManager.
|
||||
MySandboxGame.IsReloading = true;
|
||||
runInternal.Invoke(null, null);
|
||||
_dsRunInternal.Invoke();
|
||||
|
||||
MySandboxGame.Log.Close();
|
||||
State = ServerState.Stopped;
|
||||
|
@@ -1,61 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Torch.API;
|
||||
using Torch.Client;
|
||||
using Torch.Managers;
|
||||
using Torch.Utils;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Torch.Tests
|
||||
{
|
||||
public class ReflectionTests
|
||||
public class ReflectionSystemTest
|
||||
{
|
||||
private static string GetGameBinaries()
|
||||
static ReflectionSystemTest()
|
||||
{
|
||||
string dir = Environment.CurrentDirectory;
|
||||
while (!string.IsNullOrWhiteSpace(dir))
|
||||
{
|
||||
string gameBin = Path.Combine(dir, "GameBinaries");
|
||||
if (Directory.Exists(gameBin))
|
||||
return gameBin;
|
||||
|
||||
dir = Path.GetDirectoryName(dir);
|
||||
}
|
||||
throw new Exception("GetGameBinaries failed to find a folder named GameBinaries in the directory tree");
|
||||
TestUtils.Init();
|
||||
}
|
||||
|
||||
private static readonly TorchAssemblyResolver _torchResolver =
|
||||
new TorchAssemblyResolver(GetGameBinaries());
|
||||
private static ReflectionTestManager _manager = new ReflectionTestManager().Init(typeof(ReflectionTestBinding));
|
||||
public static IEnumerable<object[]> Getters => _manager.Getters;
|
||||
|
||||
public static IEnumerable<object[]> Setters => _manager.Setters;
|
||||
|
||||
public static IEnumerable<object[]> Invokers => _manager.Invokers;
|
||||
|
||||
#region Binding
|
||||
[Theory]
|
||||
[MemberData(nameof(Getters))]
|
||||
public void TestBindingGetter(FieldRef field)
|
||||
public void TestBindingGetter(ReflectionTestManager.FieldRef field)
|
||||
{
|
||||
Assert.True(ReflectionManager.Process(field.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(FieldRef field)
|
||||
public void TestBindingSetter(ReflectionTestManager.FieldRef field)
|
||||
{
|
||||
Assert.True(ReflectionManager.Process(field.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(FieldRef field)
|
||||
public void TestBindingInvoker(ReflectionTestManager.FieldRef field)
|
||||
{
|
||||
Assert.True(ReflectionManager.Process(field.Field));
|
||||
if (field.Field == null)
|
||||
return;
|
||||
Assert.True(ReflectedManager.Process(field.Field));
|
||||
if (field.Field.IsStatic)
|
||||
Assert.NotNull(field.Field.GetValue(null));
|
||||
}
|
||||
@@ -129,7 +122,7 @@ namespace Torch.Tests
|
||||
[Fact]
|
||||
public void TestInstanceFieldGet()
|
||||
{
|
||||
ReflectionManager.Process(typeof(ReflectionTestBinding));
|
||||
ReflectedManager.Process(typeof(ReflectionTestBinding));
|
||||
int testNumber = AcquireRandomNum();
|
||||
var target = new ReflectionTestTarget
|
||||
{
|
||||
@@ -140,7 +133,7 @@ namespace Torch.Tests
|
||||
[Fact]
|
||||
public void TestInstanceFieldSet()
|
||||
{
|
||||
ReflectionManager.Process(typeof(ReflectionTestBinding));
|
||||
ReflectedManager.Process(typeof(ReflectionTestBinding));
|
||||
int testNumber = AcquireRandomNum();
|
||||
var target = new ReflectionTestTarget();
|
||||
ReflectionTestBinding.TestFieldSetter.Invoke(target, testNumber);
|
||||
@@ -150,7 +143,7 @@ namespace Torch.Tests
|
||||
[Fact]
|
||||
public void TestInstancePropertyGet()
|
||||
{
|
||||
ReflectionManager.Process(typeof(ReflectionTestBinding));
|
||||
ReflectedManager.Process(typeof(ReflectionTestBinding));
|
||||
int testNumber = AcquireRandomNum();
|
||||
var target = new ReflectionTestTarget
|
||||
{
|
||||
@@ -162,7 +155,7 @@ namespace Torch.Tests
|
||||
[Fact]
|
||||
public void TestInstancePropertySet()
|
||||
{
|
||||
ReflectionManager.Process(typeof(ReflectionTestBinding));
|
||||
ReflectedManager.Process(typeof(ReflectionTestBinding));
|
||||
int testNumber = AcquireRandomNum();
|
||||
var target = new ReflectionTestTarget();
|
||||
ReflectionTestBinding.TestPropertySetter.Invoke(target, testNumber);
|
||||
@@ -172,7 +165,7 @@ namespace Torch.Tests
|
||||
[Fact]
|
||||
public void TestInstanceInvoke()
|
||||
{
|
||||
ReflectionManager.Process(typeof(ReflectionTestBinding));
|
||||
ReflectedManager.Process(typeof(ReflectionTestBinding));
|
||||
var target = new ReflectionTestTarget();
|
||||
Assert.True(ReflectionTestBinding.TestCall.Invoke(target, 1));
|
||||
Assert.False(ReflectionTestBinding.TestCall.Invoke(target, -1));
|
||||
@@ -183,7 +176,7 @@ namespace Torch.Tests
|
||||
[Fact]
|
||||
public void TestStaticFieldGet()
|
||||
{
|
||||
ReflectionManager.Process(typeof(ReflectionTestBinding));
|
||||
ReflectedManager.Process(typeof(ReflectionTestBinding));
|
||||
int testNumber = AcquireRandomNum();
|
||||
ReflectionTestTarget.TestFieldStatic = testNumber;
|
||||
Assert.Equal(testNumber, ReflectionTestBinding.TestStaticFieldGetter.Invoke());
|
||||
@@ -191,7 +184,7 @@ namespace Torch.Tests
|
||||
[Fact]
|
||||
public void TestStaticFieldSet()
|
||||
{
|
||||
ReflectionManager.Process(typeof(ReflectionTestBinding));
|
||||
ReflectedManager.Process(typeof(ReflectionTestBinding));
|
||||
int testNumber = AcquireRandomNum();
|
||||
ReflectionTestBinding.TestStaticFieldSetter.Invoke(testNumber);
|
||||
Assert.Equal(testNumber, ReflectionTestTarget.TestFieldStatic);
|
||||
@@ -200,7 +193,7 @@ namespace Torch.Tests
|
||||
[Fact]
|
||||
public void TestStaticPropertyGet()
|
||||
{
|
||||
ReflectionManager.Process(typeof(ReflectionTestBinding));
|
||||
ReflectedManager.Process(typeof(ReflectionTestBinding));
|
||||
int testNumber = AcquireRandomNum();
|
||||
ReflectionTestTarget.TestPropertyStatic = testNumber;
|
||||
Assert.Equal(testNumber, ReflectionTestBinding.TestStaticPropertyGetter.Invoke());
|
||||
@@ -209,7 +202,7 @@ namespace Torch.Tests
|
||||
[Fact]
|
||||
public void TestStaticPropertySet()
|
||||
{
|
||||
ReflectionManager.Process(typeof(ReflectionTestBinding));
|
||||
ReflectedManager.Process(typeof(ReflectionTestBinding));
|
||||
int testNumber = AcquireRandomNum();
|
||||
ReflectionTestBinding.TestStaticPropertySetter.Invoke(testNumber);
|
||||
Assert.Equal(testNumber, ReflectionTestTarget.TestPropertyStatic);
|
||||
@@ -218,89 +211,11 @@ namespace Torch.Tests
|
||||
[Fact]
|
||||
public void TestStaticInvoke()
|
||||
{
|
||||
ReflectionManager.Process(typeof(ReflectionTestBinding));
|
||||
ReflectedManager.Process(typeof(ReflectionTestBinding));
|
||||
Assert.True(ReflectionTestBinding.TestCallStatic.Invoke(1));
|
||||
Assert.False(ReflectionTestBinding.TestCallStatic.Invoke(-1));
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region FieldProvider
|
||||
public struct FieldRef
|
||||
{
|
||||
public FieldInfo Field;
|
||||
|
||||
public FieldRef(FieldInfo f)
|
||||
{
|
||||
Field = f;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Field.DeclaringType?.FullName + "." + Field.Name;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool _init = false;
|
||||
private static HashSet<object[]> _getters, _setters, _invokers;
|
||||
|
||||
private static void Init()
|
||||
{
|
||||
if (_init)
|
||||
return;
|
||||
_getters = new HashSet<object[]>();
|
||||
_setters = new HashSet<object[]>();
|
||||
_invokers = new HashSet<object[]>();
|
||||
|
||||
foreach (Type type in typeof(TorchBase).Assembly.GetTypes())
|
||||
InternalInit(type);
|
||||
InternalInit(typeof(ReflectionTestBinding));
|
||||
|
||||
_init = true;
|
||||
}
|
||||
|
||||
private static void InternalInit(Type type)
|
||||
{
|
||||
foreach (FieldInfo field in type.GetFields(BindingFlags.Static |
|
||||
BindingFlags.Instance |
|
||||
BindingFlags.Public |
|
||||
BindingFlags.NonPublic))
|
||||
{
|
||||
if (field.GetCustomAttribute<ReflectedMethodAttribute>() != null)
|
||||
_invokers.Add(new object[] { new FieldRef(field) });
|
||||
if (field.GetCustomAttribute<ReflectedGetterAttribute>() != null)
|
||||
_getters.Add(new object[] { new FieldRef(field) });
|
||||
if (field.GetCustomAttribute<ReflectedSetterAttribute>() != null)
|
||||
_setters.Add(new object[] { new FieldRef(field) });
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> Getters
|
||||
{
|
||||
get
|
||||
{
|
||||
Init();
|
||||
return _getters;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> Setters
|
||||
{
|
||||
get
|
||||
{
|
||||
Init();
|
||||
return _setters;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> Invokers
|
||||
{
|
||||
get
|
||||
{
|
||||
Init();
|
||||
return _invokers;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
72
Torch.Tests/ReflectionTestManager.cs
Normal file
72
Torch.Tests/ReflectionTestManager.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Torch.Utils;
|
||||
|
||||
namespace Torch.Tests
|
||||
{
|
||||
public class ReflectionTestManager
|
||||
{
|
||||
#region FieldProvider
|
||||
public struct FieldRef
|
||||
{
|
||||
public FieldInfo Field;
|
||||
|
||||
public FieldRef(FieldInfo f)
|
||||
{
|
||||
Field = f;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (Field == null)
|
||||
return "Ignored";
|
||||
return Field.DeclaringType?.FullName + "." + Field.Name;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly HashSet<object[]> _getters = new HashSet<object[]>();
|
||||
private readonly HashSet<object[]> _setters = new HashSet<object[]>();
|
||||
private readonly HashSet<object[]> _invokers = new HashSet<object[]>();
|
||||
|
||||
public ReflectionTestManager()
|
||||
{
|
||||
_getters.Add(new object[] { new FieldRef(null) });
|
||||
_setters.Add(new object[] { new FieldRef(null) });
|
||||
_invokers.Add(new object[] { new FieldRef(null) });
|
||||
}
|
||||
|
||||
public ReflectionTestManager Init(Assembly asm)
|
||||
{
|
||||
foreach (Type type in asm.GetTypes())
|
||||
Init(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReflectionTestManager Init(Type type)
|
||||
{
|
||||
foreach (FieldInfo field in type.GetFields(BindingFlags.Static |
|
||||
BindingFlags.Instance |
|
||||
BindingFlags.Public |
|
||||
BindingFlags.NonPublic))
|
||||
{
|
||||
if (field.GetCustomAttribute<ReflectedMethodAttribute>() != null)
|
||||
_invokers.Add(new object[] { new FieldRef(field) });
|
||||
if (field.GetCustomAttribute<ReflectedGetterAttribute>() != null)
|
||||
_getters.Add(new object[] { new FieldRef(field) });
|
||||
if (field.GetCustomAttribute<ReflectedSetterAttribute>() != null)
|
||||
_setters.Add(new object[] { new FieldRef(field) });
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public IEnumerable<object[]> Getters => _getters;
|
||||
|
||||
public IEnumerable<object[]> Setters => _setters;
|
||||
|
||||
public IEnumerable<object[]> Invokers => _invokers;
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
35
Torch.Tests/TestUtils.cs
Normal file
35
Torch.Tests/TestUtils.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Torch.Utils;
|
||||
|
||||
namespace Torch.Tests
|
||||
{
|
||||
public sealed class TestUtils
|
||||
{
|
||||
public static void Init()
|
||||
{
|
||||
if (_torchResolver == null)
|
||||
_torchResolver = new TorchAssemblyResolver(GetGameBinaries());
|
||||
}
|
||||
|
||||
private static string GetGameBinaries()
|
||||
{
|
||||
string dir = Environment.CurrentDirectory;
|
||||
while (!string.IsNullOrWhiteSpace(dir))
|
||||
{
|
||||
string gameBin = Path.Combine(dir, "GameBinaries");
|
||||
if (Directory.Exists(gameBin))
|
||||
return gameBin;
|
||||
|
||||
dir = Path.GetDirectoryName(dir);
|
||||
}
|
||||
throw new Exception("GetGameBinaries failed to find a folder named GameBinaries in the directory tree");
|
||||
}
|
||||
|
||||
private static TorchAssemblyResolver _torchResolver;
|
||||
}
|
||||
}
|
@@ -56,7 +56,11 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ReflectionTests.cs" />
|
||||
<Compile Include="ReflectionTestManager.cs" />
|
||||
<Compile Include="ReflectionSystemTest.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="TestUtils.cs" />
|
||||
<Compile Include="TorchReflectionTest.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Torch.API\Torch.API.csproj">
|
||||
|
65
Torch.Tests/TorchReflectionTest.cs
Normal file
65
Torch.Tests/TorchReflectionTest.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System.Collections.Generic;
|
||||
using Torch.Utils;
|
||||
using Xunit;
|
||||
|
||||
namespace Torch.Tests
|
||||
{
|
||||
public class TorchReflectionTest
|
||||
{
|
||||
static TorchReflectionTest()
|
||||
{
|
||||
TestUtils.Init();
|
||||
}
|
||||
|
||||
private static ReflectionTestManager _manager;
|
||||
|
||||
private static ReflectionTestManager Manager()
|
||||
{
|
||||
if (_manager != null)
|
||||
return _manager;
|
||||
|
||||
return _manager = new ReflectionTestManager().Init(typeof(TorchBase).Assembly);
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> Getters => Manager().Getters;
|
||||
|
||||
public static IEnumerable<object[]> Setters => Manager().Setters;
|
||||
|
||||
public static IEnumerable<object[]> Invokers => Manager().Invokers;
|
||||
|
||||
#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));
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -18,6 +18,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.Tests", "Torch.Tests\Torch.Tests.csproj", "{C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.Server.Tests", "Torch.Server.Tests\Torch.Server.Tests.csproj", "{9EFD1D91-2FA2-47ED-B537-D8BC3B0E543E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -56,6 +58,12 @@ Global
|
||||
{C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}.Release|x64.ActiveCfg = Release|x64
|
||||
{C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}.Release|x64.Build.0 = Release|x64
|
||||
{9EFD1D91-2FA2-47ED-B537-D8BC3B0E543E}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{9EFD1D91-2FA2-47ED-B537-D8BC3B0E543E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9EFD1D91-2FA2-47ED-B537-D8BC3B0E543E}.Debug|x64.Build.0 = Debug|x64
|
||||
{9EFD1D91-2FA2-47ED-B537-D8BC3B0E543E}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{9EFD1D91-2FA2-47ED-B537-D8BC3B0E543E}.Release|x64.ActiveCfg = Release|x64
|
||||
{9EFD1D91-2FA2-47ED-B537-D8BC3B0E543E}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@@ -26,6 +26,7 @@ using Torch.API;
|
||||
using Torch.API.Managers;
|
||||
using Torch.Collections;
|
||||
using Torch.Commands;
|
||||
using Torch.Utils;
|
||||
using Torch.ViewModels;
|
||||
using VRage.Game;
|
||||
using VRage.Game.ModAPI;
|
||||
@@ -167,15 +168,6 @@ namespace Torch.Managers
|
||||
}
|
||||
MyGameService.GameServer.ValidateAuthTicketResponse += ValidateAuthTicketResponse;
|
||||
MyGameService.GameServer.UserGroupStatusResponse += UserGroupStatusResponse;
|
||||
// _members = MyMultiplayer.Static.GetPrivateField<List<ulong>>("m_members", true);
|
||||
// if (_members == null)
|
||||
// throw new InvalidOperationException("Unable to get m_members from MyMultiplayer.Static. Is this a dedicated server?");
|
||||
// _waitingForGroup = MyMultiplayer.Static.GetPrivateField<HashSet<ulong>>("m_waitingForGroup", true);
|
||||
// if (_waitingForGroup == null)
|
||||
// throw new InvalidOperationException("Unable to get m_waitingForGroup from MyMultiplayer.Static. Is this a dedicated server?");
|
||||
// _kickedClients = MyMultiplayer.Static.GetPrivateField<Dictionary<ulong, int>>("m_kickedClients", true);
|
||||
// if (_kickedClients == null)
|
||||
// throw new InvalidOperationException("Unable to get m_kickedClients from MyMultiplayer.Static. Is this a dedicated server?");
|
||||
Log.Info("Steam auth initialized");
|
||||
}
|
||||
|
||||
@@ -279,19 +271,19 @@ namespace Torch.Managers
|
||||
UserRejected.Invoke((MyDedicatedServerBase)MyMultiplayer.Static, steamID, response);
|
||||
return;
|
||||
}
|
||||
if (MyMultiplayer.Static.MemberLimit > 0 && _members.Invoke((MyDedicatedServerBase) MyMultiplayer.Static).Count - 1 >= MyMultiplayer.Static.MemberLimit)
|
||||
if (MyMultiplayer.Static.MemberLimit > 0 && _members.Invoke((MyDedicatedServerBase)MyMultiplayer.Static).Count - 1 >= MyMultiplayer.Static.MemberLimit)
|
||||
{
|
||||
UserRejected.Invoke((MyDedicatedServerBase)MyMultiplayer.Static, steamID, JoinResult.ServerFull);
|
||||
return;
|
||||
}
|
||||
if (MySandboxGame.ConfigDedicated.GroupID == 0uL ||
|
||||
MySandboxGame.ConfigDedicated.Administrators.Contains(steamID.ToString()) ||
|
||||
MySandboxGame.ConfigDedicated.Administrators.Contains((string)Reflection.InvokeStaticMethod(typeof(MyDedicatedServerBase), "ConvertSteamIDFrom64", steamID)))
|
||||
MySandboxGame.ConfigDedicated.Administrators.Contains(ConvertSteamIDFrom64(steamID)))
|
||||
{
|
||||
this.UserAccepted(steamID);
|
||||
return;
|
||||
}
|
||||
if ((MyGameServiceAccountType)Reflection.InvokeStaticMethod(typeof(MyGameService), "GetServerAccountType", MySandboxGame.ConfigDedicated.GroupID) != MyGameServiceAccountType.Clan)
|
||||
if (GetServerAccountType(MySandboxGame.ConfigDedicated.GroupID) != MyGameServiceAccountType.Clan)
|
||||
{
|
||||
UserRejected.Invoke((MyDedicatedServerBase)MyMultiplayer.Static, steamID, JoinResult.GroupIdInvalid);
|
||||
return;
|
||||
@@ -317,7 +309,7 @@ namespace Torch.Managers
|
||||
|
||||
private void UserAccepted(ulong steamId)
|
||||
{
|
||||
Reflection.InvokePrivateMethod(MyMultiplayer.Static, "UserAccepted", steamId);
|
||||
UserAcceptedImpl.Invoke((MyDedicatedServerBase)MyMultiplayer.Static, steamId);
|
||||
|
||||
var vm = new PlayerViewModel(steamId) { State = ConnectionState.Connected };
|
||||
Log.Info($"Player {vm.Name} joined ({vm.SteamId})");
|
||||
@@ -325,6 +317,15 @@ namespace Torch.Managers
|
||||
PlayerJoined?.Invoke(vm);
|
||||
}
|
||||
|
||||
[ReflectedStaticMethod(Type = typeof(MyDedicatedServerBase))]
|
||||
private static Func<ulong, string> ConvertSteamIDFrom64;
|
||||
|
||||
[ReflectedStaticMethod(Type = typeof(MyGameService))]
|
||||
private static Func<ulong, MyGameServiceAccountType> GetServerAccountType;
|
||||
|
||||
[ReflectedMethod(Name = "UserAccepted")]
|
||||
private static Action<MyDedicatedServerBase, ulong> UserAcceptedImpl;
|
||||
|
||||
[ReflectedMethod]
|
||||
private static Action<MyDedicatedServerBase, ulong, JoinResult> UserRejected;
|
||||
[ReflectedMethod]
|
||||
|
@@ -9,6 +9,7 @@ using Sandbox.Engine.Multiplayer;
|
||||
using Sandbox.Game.Multiplayer;
|
||||
using Torch.API;
|
||||
using Torch.API.Managers;
|
||||
using Torch.Utils;
|
||||
using VRage;
|
||||
using VRage.Library.Collections;
|
||||
using VRage.Network;
|
||||
@@ -20,12 +21,15 @@ namespace Torch.Managers
|
||||
private static Logger _log = LogManager.GetLogger(nameof(NetworkManager));
|
||||
|
||||
private const string MyTransportLayerField = "TransportLayer";
|
||||
private const string TypeTableField = "m_typeTable";
|
||||
private const string TransportHandlersField = "m_handlers";
|
||||
private MyTypeTable m_typeTable = new MyTypeTable();
|
||||
private HashSet<INetworkHandler> _networkHandlers = new HashSet<INetworkHandler>();
|
||||
private bool _init;
|
||||
|
||||
[ReflectedGetter(Name = "m_typeTable")]
|
||||
private static Func<MyReplicationLayerBase, MyTypeTable> _typeTableGetter;
|
||||
[ReflectedGetter(Name = "m_methodInfoLookup")]
|
||||
private static Func<MyEventTable, Dictionary<MethodInfo, CallSite>> _methodInfoLookupGetter;
|
||||
|
||||
public NetworkManager(ITorchBase torchInstance) : base(torchInstance)
|
||||
{
|
||||
|
||||
@@ -43,10 +47,6 @@ namespace Torch.Managers
|
||||
|
||||
var transportLayerType = transportLayerField.FieldType;
|
||||
|
||||
var replicationLayerType = typeof(MyReplicationLayerBase);
|
||||
if (!Reflection.HasField(replicationLayerType, TypeTableField))
|
||||
throw new TypeLoadException("Could not find TypeTable field");
|
||||
|
||||
if (!Reflection.HasField(transportLayerType, TransportHandlersField))
|
||||
throw new TypeLoadException("Could not find Handlers field");
|
||||
|
||||
@@ -78,7 +78,6 @@ namespace Torch.Managers
|
||||
if (!ReflectionUnitTest())
|
||||
throw new InvalidOperationException("Reflection unit test failed.");
|
||||
|
||||
m_typeTable = typeof(MyReplicationLayerBase).GetField(TypeTableField, BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(MyMultiplayer.ReplicationLayer) as MyTypeTable;
|
||||
//don't bother with nullchecks here, it was all handled in ReflectionUnitTest
|
||||
var transportType = typeof(MySyncLayer).GetField(MyTransportLayerField, BindingFlags.NonPublic | BindingFlags.Instance).FieldType;
|
||||
var transportInstance = typeof(MySyncLayer).GetField(MyTransportLayerField, BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(MyMultiplayer.Static.SyncLayer);
|
||||
@@ -146,7 +145,7 @@ namespace Torch.Managers
|
||||
object obj;
|
||||
if (networkId.IsInvalid) // Static event
|
||||
{
|
||||
site = m_typeTable.StaticEventTable.Get(eventId);
|
||||
site = _typeTableGetter.Invoke(MyMultiplayer.ReplicationLayer).StaticEventTable.Get(eventId);
|
||||
obj = null;
|
||||
}
|
||||
else // Instance event
|
||||
@@ -156,7 +155,7 @@ namespace Torch.Managers
|
||||
{
|
||||
return;
|
||||
}
|
||||
var typeInfo = m_typeTable.Get(sendAs.GetType());
|
||||
var typeInfo = _typeTableGetter.Invoke(MyMultiplayer.ReplicationLayer).Get(sendAs.GetType());
|
||||
var eventCount = typeInfo.EventTable.Count;
|
||||
if (eventId < eventCount) // Directly
|
||||
{
|
||||
@@ -166,7 +165,7 @@ namespace Torch.Managers
|
||||
else // Through proxy
|
||||
{
|
||||
obj = ((IMyProxyTarget)sendAs).Target;
|
||||
typeInfo = m_typeTable.Get(obj.GetType());
|
||||
typeInfo = _typeTableGetter.Invoke(MyMultiplayer.ReplicationLayer).Get(obj.GetType());
|
||||
site = typeInfo.EventTable.Get(eventId - (uint)eventCount); // Subtract max id of Proxy
|
||||
}
|
||||
}
|
||||
@@ -280,7 +279,7 @@ namespace Torch.Managers
|
||||
if (obj != null && owner == null)
|
||||
throw new InvalidCastException("Provided event target is not of type IMyEventOwner!");
|
||||
|
||||
if(!method.HasAttribute<EventAttribute>())
|
||||
if (!method.HasAttribute<EventAttribute>())
|
||||
throw new CustomAttributeFormatException("Provided event target does not have the Event attribute! Replication will not succeed!");
|
||||
|
||||
//array to hold arguments to pass into DispatchEvent
|
||||
@@ -356,17 +355,16 @@ namespace Torch.Managers
|
||||
|
||||
private CallSite TryGetStaticCallSite(MethodInfo method)
|
||||
{
|
||||
var methodLookup = (Dictionary<MethodInfo, CallSite>)typeof(MyEventTable).GetField("m_methodInfoLookup", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(m_typeTable.StaticEventTable);
|
||||
if (!methodLookup.TryGetValue(method, out CallSite result))
|
||||
MyTypeTable typeTable = _typeTableGetter.Invoke(MyMultiplayer.ReplicationLayer);
|
||||
if (!_methodInfoLookupGetter.Invoke(typeTable.StaticEventTable).TryGetValue(method, out CallSite result))
|
||||
throw new MissingMemberException("Provided event target not found!");
|
||||
return result;
|
||||
}
|
||||
|
||||
private CallSite TryGetCallSite(MethodInfo method, object arg)
|
||||
{
|
||||
var typeInfo = m_typeTable.Get(arg.GetType());
|
||||
var methodLookup = (Dictionary<MethodInfo, CallSite>)typeof(MyEventTable).GetField("m_methodInfoLookup", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(typeInfo.EventTable);
|
||||
if (!methodLookup.TryGetValue(method, out CallSite result))
|
||||
MySynchronizedTypeInfo typeInfo = _typeTableGetter.Invoke(MyMultiplayer.ReplicationLayer).Get(arg.GetType());
|
||||
if (!_methodInfoLookupGetter.Invoke(typeInfo.EventTable).TryGetValue(method, out CallSite result))
|
||||
throw new MissingMemberException("Provided event target not found!");
|
||||
return result;
|
||||
}
|
||||
|
@@ -6,6 +6,8 @@ using System.Threading.Tasks;
|
||||
using SteamSDK;
|
||||
using VRage.Steam;
|
||||
using Sandbox;
|
||||
using Torch.Utils;
|
||||
using VRage.GameServices;
|
||||
|
||||
namespace Torch
|
||||
{
|
||||
@@ -17,48 +19,67 @@ namespace Torch
|
||||
/// </summary>
|
||||
public class SteamService : MySteamService
|
||||
{
|
||||
[ReflectedSetter(Name = nameof(SteamServerAPI))]
|
||||
private static Action<MySteamService, SteamServerAPI> _steamServerAPISetter;
|
||||
[ReflectedSetter(Name = "m_gameServer")]
|
||||
private static Action<MySteamService, MySteamGameServer> _steamGameServerSetter;
|
||||
[ReflectedSetter(Name = nameof(AppId))]
|
||||
private static Action<MySteamService, uint> _steamAppIdSetter;
|
||||
[ReflectedSetter(Name = nameof(API))]
|
||||
private static Action<MySteamService, SteamAPI> _steamApiSetter;
|
||||
[ReflectedSetter(Name = nameof(IsActive))]
|
||||
private static Action<MySteamService, bool> _steamIsActiveSetter;
|
||||
[ReflectedSetter(Name = nameof(UserId))]
|
||||
private static Action<MySteamService, ulong> _steamUserIdSetter;
|
||||
[ReflectedSetter(Name = nameof(UserName))]
|
||||
private static Action<MySteamService, string> _steamUserNameSetter;
|
||||
[ReflectedSetter(Name = nameof(OwnsGame))]
|
||||
private static Action<MySteamService, bool> _steamOwnsGameSetter;
|
||||
[ReflectedSetter(Name = nameof(UserUniverse))]
|
||||
private static Action<MySteamService, MyGameServiceUniverse> _steamUserUniverseSetter;
|
||||
[ReflectedSetter(Name = nameof(BranchName))]
|
||||
private static Action<MySteamService, string> _steamBranchNameSetter;
|
||||
[ReflectedSetter(Name = nameof(InventoryAPI))]
|
||||
private static Action<MySteamService, MySteamInventory> _steamInventoryAPISetter;
|
||||
[ReflectedMethod]
|
||||
private static Action<MySteamService> RegisterCallbacks;
|
||||
[ReflectedSetter(Name = nameof(Peer2Peer))]
|
||||
private static Action<MySteamService, IMyPeer2Peer> _steamPeer2PeerSetter;
|
||||
|
||||
public SteamService(bool isDedicated, uint appId)
|
||||
: base(true, appId)
|
||||
{
|
||||
// TODO: Add protection for this mess... somewhere
|
||||
SteamSDK.SteamServerAPI.Instance.Dispose();
|
||||
var steam = typeof(MySteamService);
|
||||
SteamServerAPI.Instance.Dispose();
|
||||
_steamServerAPISetter.Invoke(this, null);
|
||||
_steamGameServerSetter.Invoke(this, null);
|
||||
_steamAppIdSetter.Invoke(this, appId);
|
||||
|
||||
steam.GetProperty("SteamServerAPI").GetSetMethod(true).Invoke(this, new object[] { null });
|
||||
steam.GetField("m_gameServer", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(this, null);
|
||||
|
||||
steam.GetProperty("AppId").GetSetMethod(true).Invoke(this, new object[] { appId });
|
||||
if (isDedicated)
|
||||
{
|
||||
steam.GetProperty("SteamServerAPI").GetSetMethod(true).Invoke(this, new object[] { null });
|
||||
steam.GetField("m_gameServer").SetValue(this, new MySteamGameServer());
|
||||
_steamServerAPISetter.Invoke(this, null);
|
||||
_steamGameServerSetter.Invoke(this, new MySteamGameServer());
|
||||
}
|
||||
else
|
||||
{
|
||||
var SteamAPI = SteamSDK.SteamAPI.Instance;
|
||||
steam.GetProperty("API").GetSetMethod(true).Invoke(this, new object[] { SteamAPI.Instance });
|
||||
steam.GetProperty("IsActive").GetSetMethod(true).Invoke(this, new object[] {
|
||||
SteamAPI.Instance.Init()
|
||||
});
|
||||
SteamAPI steamApi = SteamAPI.Instance;
|
||||
_steamApiSetter.Invoke(this, steamApi);
|
||||
_steamIsActiveSetter.Invoke(this, steamApi.Init());
|
||||
|
||||
if (IsActive)
|
||||
{
|
||||
steam.GetProperty("UserId").GetSetMethod(true).Invoke(this, new object[] { SteamAPI.GetSteamUserId() });
|
||||
steam.GetProperty("UserName").GetSetMethod(true).Invoke(this, new object[] { SteamAPI.GetSteamName() });
|
||||
steam.GetProperty("OwnsGame").GetSetMethod(true).Invoke(this, new object[] { SteamAPI.HasGame() });
|
||||
steam.GetProperty("UserUniverse").GetSetMethod(true).Invoke(this, new object[] { SteamAPI.GetSteamUserUniverse() });
|
||||
steam.GetProperty("BranchName").GetSetMethod(true).Invoke(this, new object[] { SteamAPI.GetBranchName() });
|
||||
SteamAPI.LoadStats();
|
||||
_steamUserIdSetter.Invoke(this, steamApi.GetSteamUserId());
|
||||
_steamUserNameSetter.Invoke(this, steamApi.GetSteamName());
|
||||
_steamOwnsGameSetter.Invoke(this, steamApi.HasGame());
|
||||
_steamUserUniverseSetter.Invoke(this, (MyGameServiceUniverse)steamApi.GetSteamUserUniverse());
|
||||
_steamBranchNameSetter.Invoke(this, steamApi.GetBranchName());
|
||||
steamApi.LoadStats();
|
||||
|
||||
steam.GetProperty("InventoryAPI").GetSetMethod(true).Invoke(this, new object[] { new MySteamInventory() });
|
||||
|
||||
steam.GetMethod("RegisterCallbacks",
|
||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
|
||||
.Invoke(this, null);
|
||||
_steamInventoryAPISetter.Invoke(this, new MySteamInventory());
|
||||
RegisterCallbacks(this);
|
||||
}
|
||||
}
|
||||
|
||||
steam.GetProperty("Peer2Peer").GetSetMethod(true).Invoke(this, new object[] { new MySteamPeer2Peer() });
|
||||
_steamPeer2PeerSetter.Invoke(this, new MySteamPeer2Peer());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -151,7 +151,7 @@
|
||||
<Compile Include="Collections\ObservableList.cs" />
|
||||
<Compile Include="DispatcherExtensions.cs" />
|
||||
<Compile Include="Managers\DependencyManager.cs" />
|
||||
<Compile Include="Managers\ReflectionManager.cs" />
|
||||
<Compile Include="Utils\ReflectedManager.cs" />
|
||||
<Compile Include="SaveGameStatus.cs" />
|
||||
<Compile Include="Collections\KeyTree.cs" />
|
||||
<Compile Include="Collections\ObservableDictionary.cs" />
|
||||
@@ -177,9 +177,9 @@
|
||||
<Compile Include="Managers\UpdateManager.cs" />
|
||||
<Compile Include="Persistent.cs" />
|
||||
<Compile Include="PluginManifest.cs" />
|
||||
<Compile Include="Reflection.cs" />
|
||||
<Compile Include="Utils\Reflection.cs" />
|
||||
<Compile Include="Managers\ScriptingManager.cs" />
|
||||
<Compile Include="TorchAssemblyResolver.cs" />
|
||||
<Compile Include="Utils\TorchAssemblyResolver.cs" />
|
||||
<Compile Include="TorchBase.cs" />
|
||||
<Compile Include="SteamService.cs" />
|
||||
<Compile Include="TorchPluginBase.cs" />
|
||||
|
@@ -21,6 +21,7 @@ using Torch.API.Managers;
|
||||
using Torch.API.ModAPI;
|
||||
using Torch.Commands;
|
||||
using Torch.Managers;
|
||||
using Torch.Utils;
|
||||
using VRage.Collections;
|
||||
using VRage.FileSystem;
|
||||
using VRage.Game.ObjectBuilder;
|
||||
@@ -36,6 +37,12 @@ namespace Torch
|
||||
/// </summary>
|
||||
public abstract class TorchBase : ViewModel, ITorchBase, IPlugin
|
||||
{
|
||||
static TorchBase()
|
||||
{
|
||||
// We can safely never detach this since we don't reload assemblies.
|
||||
new ReflectedManager().Attach();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hack because *keen*.
|
||||
/// Use only if necessary, prefer dependency injection.
|
||||
@@ -224,7 +231,6 @@ namespace Torch
|
||||
public virtual void Init()
|
||||
{
|
||||
Debug.Assert(!_init, "Torch instance is already initialized.");
|
||||
|
||||
SpaceEngineersGame.SetupBasicGameInfo();
|
||||
SpaceEngineersGame.SetupPerGameSettings();
|
||||
|
||||
|
@@ -10,7 +10,7 @@ using System.Threading.Tasks;
|
||||
using Sandbox.Engine.Multiplayer;
|
||||
using Torch.API;
|
||||
|
||||
namespace Torch.Managers
|
||||
namespace Torch.Utils
|
||||
{
|
||||
public abstract class ReflectedMemberAttribute : Attribute
|
||||
{
|
||||
@@ -118,27 +118,28 @@ namespace Torch.Managers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Automatically calls <see cref="ReflectionManager.Process(Assembly)"/> for every assembly already loaded, and every assembly that is loaded in the future.
|
||||
/// Automatically calls <see cref="ReflectedManager.Process(Assembly)"/> for every assembly already loaded, and every assembly that is loaded in the future.
|
||||
/// </summary>
|
||||
public class ReflectionManager : Manager
|
||||
public class ReflectedManager
|
||||
{
|
||||
private static readonly string[] _namespaceBlacklist = new[] {
|
||||
"System", "VRage", "Sandbox", "SpaceEngineers"
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public ReflectionManager(ITorchBase torchInstance) : base(torchInstance) { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Attach()
|
||||
/// <summary>
|
||||
/// Registers the assembly load event and loads every already existing assembly.
|
||||
/// </summary>
|
||||
public void Attach()
|
||||
{
|
||||
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
|
||||
Process(asm);
|
||||
AppDomain.CurrentDomain.AssemblyLoad += CurrentDomain_AssemblyLoad;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Detach()
|
||||
/// <summary>
|
||||
/// Deregisters the assembly load event
|
||||
/// </summary>
|
||||
public void Detach()
|
||||
{
|
||||
AppDomain.CurrentDomain.AssemblyLoad -= CurrentDomain_AssemblyLoad;
|
||||
}
|
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||
using NLog;
|
||||
using SteamSDK;
|
||||
|
||||
namespace Torch
|
||||
namespace Torch.Utils
|
||||
{
|
||||
public static class Reflection
|
||||
{
|
@@ -7,8 +7,11 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NLog;
|
||||
|
||||
namespace Torch.Client
|
||||
namespace Torch.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds and removes an additional library path
|
||||
/// </summary>
|
||||
public class TorchAssemblyResolver : IDisposable
|
||||
{
|
||||
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
|
||||
@@ -17,6 +20,10 @@ namespace Torch.Client
|
||||
private readonly string[] _paths;
|
||||
private readonly string _removablePathPrefix;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an assembly resolver that looks at the given paths for assemblies
|
||||
/// </summary>
|
||||
/// <param name="paths"></param>
|
||||
public TorchAssemblyResolver(params string[] paths)
|
||||
{
|
||||
string location = Assembly.GetEntryAssembly()?.Location ?? GetType().Assembly.Location;
|
||||
@@ -79,6 +86,9 @@ namespace Torch.Client
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unregisters the assembly resolver
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomainOnAssemblyResolve;
|
Reference in New Issue
Block a user