Reflection unit testing
Jenkins integration (we can only hope)
This commit is contained in:
17
Jenkinsfile
vendored
17
Jenkinsfile
vendored
@@ -17,6 +17,23 @@ node {
|
|||||||
bat "\"${tool 'MSBuild'}msbuild\" Torch.sln /p:Configuration=Release /p:Platform=x64"
|
bat "\"${tool 'MSBuild'}msbuild\" Torch.sln /p:Configuration=Release /p:Platform=x64"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stage('Test') {
|
||||||
|
bat "\"packages/xunit.runner.console.2.2.0/tools/xunit.console.exe\" \"bin-test/x64/Release/Torch.Tests.dll\" -parallel none -nunit \"reports/Torch.Tests.xml\""
|
||||||
|
step([
|
||||||
|
$class: 'XUnitBuilder',
|
||||||
|
thresholdMode: 1,
|
||||||
|
thresholds: [[$class: 'FailedThreshold', failureThreshold: '1']],
|
||||||
|
tools: [[
|
||||||
|
$class: 'XUnitDotNetTestType',
|
||||||
|
deleteOutputFiles: true,
|
||||||
|
failIfNotNew: true,
|
||||||
|
pattern: 'reports/*.xml',
|
||||||
|
skipNoTestFiles: false,
|
||||||
|
stopProcessingIfError: true
|
||||||
|
]]
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
stage('Archive') {
|
stage('Archive') {
|
||||||
archive 'bin/x64/Release/Torch.*'
|
archive 'bin/x64/Release/Torch.*'
|
||||||
}
|
}
|
||||||
|
@@ -122,7 +122,6 @@
|
|||||||
<DesignTime>True</DesignTime>
|
<DesignTime>True</DesignTime>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Properties\AssemblyInfo1.cs" />
|
<Compile Include="Properties\AssemblyInfo1.cs" />
|
||||||
<Compile Include="TorchAssemblyResolver.cs" />
|
|
||||||
<Compile Include="TorchClient.cs" />
|
<Compile Include="TorchClient.cs" />
|
||||||
<Compile Include="TorchClientConfig.cs" />
|
<Compile Include="TorchClientConfig.cs" />
|
||||||
<Compile Include="TorchConsoleScreen.cs" />
|
<Compile Include="TorchConsoleScreen.cs" />
|
||||||
|
36
Torch.Tests/Properties/AssemblyInfo.cs
Normal file
36
Torch.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.Tests")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("Torch.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("c3c8b671-6ad1-44aa-a8da-e0c0dc0fedf5")]
|
||||||
|
|
||||||
|
// 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")]
|
306
Torch.Tests/ReflectionTests.cs
Normal file
306
Torch.Tests/ReflectionTests.cs
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
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 Xunit;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
namespace Torch.Tests
|
||||||
|
{
|
||||||
|
public class ReflectionTests
|
||||||
|
{
|
||||||
|
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 readonly TorchAssemblyResolver _torchResolver =
|
||||||
|
new TorchAssemblyResolver(GetGameBinaries());
|
||||||
|
|
||||||
|
#region Binding
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(Getters))]
|
||||||
|
public void TestBindingGetter(FieldRef field)
|
||||||
|
{
|
||||||
|
Assert.True(ReflectionManager.Process(field.Field));
|
||||||
|
if (field.Field.IsStatic)
|
||||||
|
Assert.NotNull(field.Field.GetValue(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(Setters))]
|
||||||
|
public void TestBindingSetter(FieldRef field)
|
||||||
|
{
|
||||||
|
Assert.True(ReflectionManager.Process(field.Field));
|
||||||
|
if (field.Field.IsStatic)
|
||||||
|
Assert.NotNull(field.Field.GetValue(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(Invokers))]
|
||||||
|
public void TestBindingInvoker(FieldRef field)
|
||||||
|
{
|
||||||
|
Assert.True(ReflectionManager.Process(field.Field));
|
||||||
|
if (field.Field.IsStatic)
|
||||||
|
Assert.NotNull(field.Field.GetValue(null));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Results
|
||||||
|
#region Dummy
|
||||||
|
private class ReflectionTestTarget
|
||||||
|
{
|
||||||
|
public int TestField;
|
||||||
|
public int TestProperty { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return true when greater or equal than 0
|
||||||
|
/// </summary>
|
||||||
|
public bool TestCall(int k)
|
||||||
|
{
|
||||||
|
return k >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int TestFieldStatic;
|
||||||
|
public static int TestPropertyStatic { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return true when greater or equal than 0
|
||||||
|
/// </summary>
|
||||||
|
public static bool TestCallStatic(int k)
|
||||||
|
{
|
||||||
|
return k >= 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ReflectionTestBinding
|
||||||
|
{
|
||||||
|
[ReflectedGetter(Name = "TestField")]
|
||||||
|
public static Func<ReflectionTestTarget, int> TestFieldGetter;
|
||||||
|
[ReflectedSetter(Name = "TestField")]
|
||||||
|
public static Action<ReflectionTestTarget, int> TestFieldSetter;
|
||||||
|
|
||||||
|
[ReflectedGetter(Name = "TestProperty")]
|
||||||
|
public static Func<ReflectionTestTarget, int> TestPropertyGetter;
|
||||||
|
[ReflectedSetter(Name = "TestProperty")]
|
||||||
|
public static Action<ReflectionTestTarget, int> TestPropertySetter;
|
||||||
|
|
||||||
|
[ReflectedMethod]
|
||||||
|
public static Func<ReflectionTestTarget, int, bool> TestCall;
|
||||||
|
|
||||||
|
|
||||||
|
[ReflectedGetter(Name = "TestFieldStatic", Type = typeof(ReflectionTestTarget))]
|
||||||
|
public static Func<int> TestStaticFieldGetter;
|
||||||
|
[ReflectedSetter(Name = "TestFieldStatic", Type = typeof(ReflectionTestTarget))]
|
||||||
|
public static Action<int> TestStaticFieldSetter;
|
||||||
|
|
||||||
|
[ReflectedGetter(Name = "TestPropertyStatic", Type = typeof(ReflectionTestTarget))]
|
||||||
|
public static Func<int> TestStaticPropertyGetter;
|
||||||
|
[ReflectedSetter(Name = "TestPropertyStatic", Type = typeof(ReflectionTestTarget))]
|
||||||
|
public static Action<int> TestStaticPropertySetter;
|
||||||
|
|
||||||
|
[ReflectedStaticMethod(Type = typeof(ReflectionTestTarget))]
|
||||||
|
public static Func<int, bool> TestCallStatic;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private readonly Random _rand = new Random();
|
||||||
|
private int AcquireRandomNum()
|
||||||
|
{
|
||||||
|
return _rand.Next();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Instance
|
||||||
|
[Fact]
|
||||||
|
public void TestInstanceFieldGet()
|
||||||
|
{
|
||||||
|
ReflectionManager.Process(typeof(ReflectionTestBinding));
|
||||||
|
int testNumber = AcquireRandomNum();
|
||||||
|
var target = new ReflectionTestTarget
|
||||||
|
{
|
||||||
|
TestField = testNumber
|
||||||
|
};
|
||||||
|
Assert.Equal(testNumber, ReflectionTestBinding.TestFieldGetter.Invoke(target));
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void TestInstanceFieldSet()
|
||||||
|
{
|
||||||
|
ReflectionManager.Process(typeof(ReflectionTestBinding));
|
||||||
|
int testNumber = AcquireRandomNum();
|
||||||
|
var target = new ReflectionTestTarget();
|
||||||
|
ReflectionTestBinding.TestFieldSetter.Invoke(target, testNumber);
|
||||||
|
Assert.Equal(testNumber, target.TestField);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TestInstancePropertyGet()
|
||||||
|
{
|
||||||
|
ReflectionManager.Process(typeof(ReflectionTestBinding));
|
||||||
|
int testNumber = AcquireRandomNum();
|
||||||
|
var target = new ReflectionTestTarget
|
||||||
|
{
|
||||||
|
TestProperty = testNumber
|
||||||
|
};
|
||||||
|
Assert.Equal(testNumber, ReflectionTestBinding.TestPropertyGetter.Invoke(target));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TestInstancePropertySet()
|
||||||
|
{
|
||||||
|
ReflectionManager.Process(typeof(ReflectionTestBinding));
|
||||||
|
int testNumber = AcquireRandomNum();
|
||||||
|
var target = new ReflectionTestTarget();
|
||||||
|
ReflectionTestBinding.TestPropertySetter.Invoke(target, testNumber);
|
||||||
|
Assert.Equal(testNumber, target.TestProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TestInstanceInvoke()
|
||||||
|
{
|
||||||
|
ReflectionManager.Process(typeof(ReflectionTestBinding));
|
||||||
|
var target = new ReflectionTestTarget();
|
||||||
|
Assert.True(ReflectionTestBinding.TestCall.Invoke(target, 1));
|
||||||
|
Assert.False(ReflectionTestBinding.TestCall.Invoke(target, -1));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Static
|
||||||
|
[Fact]
|
||||||
|
public void TestStaticFieldGet()
|
||||||
|
{
|
||||||
|
ReflectionManager.Process(typeof(ReflectionTestBinding));
|
||||||
|
int testNumber = AcquireRandomNum();
|
||||||
|
ReflectionTestTarget.TestFieldStatic = testNumber;
|
||||||
|
Assert.Equal(testNumber, ReflectionTestBinding.TestStaticFieldGetter.Invoke());
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void TestStaticFieldSet()
|
||||||
|
{
|
||||||
|
ReflectionManager.Process(typeof(ReflectionTestBinding));
|
||||||
|
int testNumber = AcquireRandomNum();
|
||||||
|
ReflectionTestBinding.TestStaticFieldSetter.Invoke(testNumber);
|
||||||
|
Assert.Equal(testNumber, ReflectionTestTarget.TestFieldStatic);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TestStaticPropertyGet()
|
||||||
|
{
|
||||||
|
ReflectionManager.Process(typeof(ReflectionTestBinding));
|
||||||
|
int testNumber = AcquireRandomNum();
|
||||||
|
ReflectionTestTarget.TestPropertyStatic = testNumber;
|
||||||
|
Assert.Equal(testNumber, ReflectionTestBinding.TestStaticPropertyGetter.Invoke());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TestStaticPropertySet()
|
||||||
|
{
|
||||||
|
ReflectionManager.Process(typeof(ReflectionTestBinding));
|
||||||
|
int testNumber = AcquireRandomNum();
|
||||||
|
ReflectionTestBinding.TestStaticPropertySetter.Invoke(testNumber);
|
||||||
|
Assert.Equal(testNumber, ReflectionTestTarget.TestPropertyStatic);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TestStaticInvoke()
|
||||||
|
{
|
||||||
|
ReflectionManager.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
|
||||||
|
}
|
||||||
|
}
|
76
Torch.Tests/Torch.Tests.csproj
Normal file
76
Torch.Tests/Torch.Tests.csproj
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<?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>{C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>Torch.Tests</RootNamespace>
|
||||||
|
<AssemblyName>Torch.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.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="ReflectionTests.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\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>
|
10
Torch.Tests/packages.config
Normal file
10
Torch.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>
|
23
Torch.sln
23
Torch.sln
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio 15
|
||||||
VisualStudioVersion = 15.0.26430.14
|
VisualStudioVersion = 15.0.26730.8
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch", "Torch\Torch.csproj", "{7E01635C-3B67-472E-BCD6-C5539564F214}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch", "Torch\Torch.csproj", "{7E01635C-3B67-472E-BCD6-C5539564F214}"
|
||||||
EndProject
|
EndProject
|
||||||
@@ -16,30 +16,51 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||||||
NLog.config = NLog.config
|
NLog.config = NLog.config
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.Tests", "Torch.Tests\Torch.Tests.csproj", "{C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
Debug|x64 = Debug|x64
|
Debug|x64 = Debug|x64
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
Release|x64 = Release|x64
|
Release|x64 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{7E01635C-3B67-472E-BCD6-C5539564F214}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||||
{7E01635C-3B67-472E-BCD6-C5539564F214}.Debug|x64.ActiveCfg = Debug|x64
|
{7E01635C-3B67-472E-BCD6-C5539564F214}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
{7E01635C-3B67-472E-BCD6-C5539564F214}.Debug|x64.Build.0 = Debug|x64
|
{7E01635C-3B67-472E-BCD6-C5539564F214}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{7E01635C-3B67-472E-BCD6-C5539564F214}.Release|Any CPU.ActiveCfg = Release|x64
|
||||||
{7E01635C-3B67-472E-BCD6-C5539564F214}.Release|x64.ActiveCfg = Release|x64
|
{7E01635C-3B67-472E-BCD6-C5539564F214}.Release|x64.ActiveCfg = Release|x64
|
||||||
{7E01635C-3B67-472E-BCD6-C5539564F214}.Release|x64.Build.0 = Release|x64
|
{7E01635C-3B67-472E-BCD6-C5539564F214}.Release|x64.Build.0 = Release|x64
|
||||||
|
{FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||||
{FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}.Debug|x64.ActiveCfg = Debug|x64
|
{FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
{FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}.Debug|x64.Build.0 = Debug|x64
|
{FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}.Release|Any CPU.ActiveCfg = Release|x64
|
||||||
{FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}.Release|x64.ActiveCfg = Release|x64
|
{FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}.Release|x64.ActiveCfg = Release|x64
|
||||||
{FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}.Release|x64.Build.0 = Release|x64
|
{FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}.Release|x64.Build.0 = Release|x64
|
||||||
|
{E36DF745-260B-4956-A2E8-09F08B2E7161}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||||
{E36DF745-260B-4956-A2E8-09F08B2E7161}.Debug|x64.ActiveCfg = Debug|x64
|
{E36DF745-260B-4956-A2E8-09F08B2E7161}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
{E36DF745-260B-4956-A2E8-09F08B2E7161}.Debug|x64.Build.0 = Debug|x64
|
{E36DF745-260B-4956-A2E8-09F08B2E7161}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{E36DF745-260B-4956-A2E8-09F08B2E7161}.Release|Any CPU.ActiveCfg = Release|x64
|
||||||
{E36DF745-260B-4956-A2E8-09F08B2E7161}.Release|x64.ActiveCfg = Release|x64
|
{E36DF745-260B-4956-A2E8-09F08B2E7161}.Release|x64.ActiveCfg = Release|x64
|
||||||
{E36DF745-260B-4956-A2E8-09F08B2E7161}.Release|x64.Build.0 = Release|x64
|
{E36DF745-260B-4956-A2E8-09F08B2E7161}.Release|x64.Build.0 = Release|x64
|
||||||
|
{CA50886B-7B22-4CD8-93A0-C06F38D4F77D}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||||
{CA50886B-7B22-4CD8-93A0-C06F38D4F77D}.Debug|x64.ActiveCfg = Debug|x64
|
{CA50886B-7B22-4CD8-93A0-C06F38D4F77D}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
{CA50886B-7B22-4CD8-93A0-C06F38D4F77D}.Debug|x64.Build.0 = Debug|x64
|
{CA50886B-7B22-4CD8-93A0-C06F38D4F77D}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{CA50886B-7B22-4CD8-93A0-C06F38D4F77D}.Release|Any CPU.ActiveCfg = Release|x64
|
||||||
{CA50886B-7B22-4CD8-93A0-C06F38D4F77D}.Release|x64.ActiveCfg = Release|x64
|
{CA50886B-7B22-4CD8-93A0-C06F38D4F77D}.Release|x64.ActiveCfg = Release|x64
|
||||||
{CA50886B-7B22-4CD8-93A0-C06F38D4F77D}.Release|x64.Build.0 = Release|x64
|
{CA50886B-7B22-4CD8-93A0-C06F38D4F77D}.Release|x64.Build.0 = Release|x64
|
||||||
|
{C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||||
|
{C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{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
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {BB51D91F-958D-4B63-A897-3C40642ACD3E}
|
||||||
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
@@ -52,7 +52,9 @@ namespace Torch.Managers
|
|||||||
public IMyPlayer LocalPlayer => MySession.Static.LocalHumanPlayer;
|
public IMyPlayer LocalPlayer => MySession.Static.LocalHumanPlayer;
|
||||||
private static readonly Logger Log = LogManager.GetLogger(nameof(MultiplayerManager));
|
private static readonly Logger Log = LogManager.GetLogger(nameof(MultiplayerManager));
|
||||||
private static readonly Logger ChatLog = LogManager.GetLogger("Chat");
|
private static readonly Logger ChatLog = LogManager.GetLogger("Chat");
|
||||||
private Dictionary<MyPlayer.PlayerId, MyPlayer> _onlinePlayers;
|
|
||||||
|
[ReflectedGetter(Name = "m_players")]
|
||||||
|
private static Func<MyPlayerCollection, Dictionary<MyPlayer.PlayerId, MyPlayer>> _onlinePlayers;
|
||||||
|
|
||||||
[Dependency]
|
[Dependency]
|
||||||
private ChatManager _chatManager;
|
private ChatManager _chatManager;
|
||||||
@@ -98,21 +100,19 @@ namespace Torch.Managers
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IMyPlayer GetPlayerByName(string name)
|
public IMyPlayer GetPlayerByName(string name)
|
||||||
{
|
{
|
||||||
ValidateOnlinePlayersList();
|
return _onlinePlayers.Invoke(MySession.Static.Players).FirstOrDefault(x => x.Value.DisplayName == name).Value;
|
||||||
return _onlinePlayers.FirstOrDefault(x => x.Value.DisplayName == name).Value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IMyPlayer GetPlayerBySteamId(ulong steamId)
|
public IMyPlayer GetPlayerBySteamId(ulong steamId)
|
||||||
{
|
{
|
||||||
ValidateOnlinePlayersList();
|
_onlinePlayers.Invoke(MySession.Static.Players).TryGetValue(new MyPlayer.PlayerId(steamId), out MyPlayer p);
|
||||||
_onlinePlayers.TryGetValue(new MyPlayer.PlayerId(steamId), out MyPlayer p);
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong GetSteamId(long identityId)
|
public ulong GetSteamId(long identityId)
|
||||||
{
|
{
|
||||||
foreach (var kv in _onlinePlayers)
|
foreach (var kv in _onlinePlayers.Invoke(MySession.Static.Players))
|
||||||
{
|
{
|
||||||
if (kv.Value.Identity.IdentityId == identityId)
|
if (kv.Value.Identity.IdentityId == identityId)
|
||||||
return kv.Key.SteamId;
|
return kv.Key.SteamId;
|
||||||
@@ -153,20 +153,12 @@ namespace Torch.Managers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ValidateOnlinePlayersList()
|
|
||||||
{
|
|
||||||
if (_onlinePlayers == null)
|
|
||||||
_onlinePlayers = MySession.Static.Players.GetPrivateField<Dictionary<MyPlayer.PlayerId, MyPlayer>>("m_players");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSessionLoaded()
|
private void OnSessionLoaded()
|
||||||
{
|
{
|
||||||
Log.Info("Initializing Steam auth");
|
Log.Info("Initializing Steam auth");
|
||||||
MyMultiplayer.Static.ClientKicked += OnClientKicked;
|
MyMultiplayer.Static.ClientKicked += OnClientKicked;
|
||||||
MyMultiplayer.Static.ClientLeft += OnClientLeft;
|
MyMultiplayer.Static.ClientLeft += OnClientLeft;
|
||||||
|
|
||||||
ValidateOnlinePlayersList();
|
|
||||||
|
|
||||||
//TODO: Move these with the methods?
|
//TODO: Move these with the methods?
|
||||||
if (!RemoveHandlers())
|
if (!RemoveHandlers())
|
||||||
{
|
{
|
||||||
@@ -175,15 +167,15 @@ namespace Torch.Managers
|
|||||||
}
|
}
|
||||||
MyGameService.GameServer.ValidateAuthTicketResponse += ValidateAuthTicketResponse;
|
MyGameService.GameServer.ValidateAuthTicketResponse += ValidateAuthTicketResponse;
|
||||||
MyGameService.GameServer.UserGroupStatusResponse += UserGroupStatusResponse;
|
MyGameService.GameServer.UserGroupStatusResponse += UserGroupStatusResponse;
|
||||||
_members = MyMultiplayer.Static.GetPrivateField<List<ulong>>("m_members", true);
|
// _members = MyMultiplayer.Static.GetPrivateField<List<ulong>>("m_members", true);
|
||||||
if (_members == null)
|
// if (_members == null)
|
||||||
throw new InvalidOperationException("Unable to get m_members from MyMultiplayer.Static. Is this a dedicated server?");
|
// 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);
|
// _waitingForGroup = MyMultiplayer.Static.GetPrivateField<HashSet<ulong>>("m_waitingForGroup", true);
|
||||||
if (_waitingForGroup == null)
|
// if (_waitingForGroup == null)
|
||||||
throw new InvalidOperationException("Unable to get m_waitingForGroup from MyMultiplayer.Static. Is this a dedicated server?");
|
// 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);
|
// _kickedClients = MyMultiplayer.Static.GetPrivateField<Dictionary<ulong, int>>("m_kickedClients", true);
|
||||||
if (_kickedClients == null)
|
// if (_kickedClients == null)
|
||||||
throw new InvalidOperationException("Unable to get m_kickedClients from MyMultiplayer.Static. Is this a dedicated server?");
|
// throw new InvalidOperationException("Unable to get m_kickedClients from MyMultiplayer.Static. Is this a dedicated server?");
|
||||||
Log.Info("Steam auth initialized");
|
Log.Info("Steam auth initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,9 +197,12 @@ namespace Torch.Managers
|
|||||||
//TODO: Split the following into a new file?
|
//TODO: Split the following into a new file?
|
||||||
//These methods override some Keen code to allow us full control over client authentication.
|
//These methods override some Keen code to allow us full control over client authentication.
|
||||||
//This lets us have a server set to private (admins only) or friends (friends of all listed admins)
|
//This lets us have a server set to private (admins only) or friends (friends of all listed admins)
|
||||||
private List<ulong> _members;
|
[ReflectedGetter(Name = "m_members")]
|
||||||
private HashSet<ulong> _waitingForGroup;
|
private static Func<MyDedicatedServerBase, List<ulong>> _members;
|
||||||
private Dictionary<ulong, int> _kickedClients;
|
[ReflectedGetter(Name = "m_waitingForGroup")]
|
||||||
|
private static Func<MyDedicatedServerBase, HashSet<ulong>> _waitingForGroup;
|
||||||
|
[ReflectedGetter(Name = "m_kickedClients")]
|
||||||
|
private static Func<MyMultiplayerBase, Dictionary<ulong, int>> _kickedClients;
|
||||||
//private HashSet<ulong> _waitingForFriends;
|
//private HashSet<ulong> _waitingForFriends;
|
||||||
private Dictionary<ulong, ulong> _gameOwnerIds = new Dictionary<ulong, ulong>();
|
private Dictionary<ulong, ulong> _gameOwnerIds = new Dictionary<ulong, ulong>();
|
||||||
//private IMultiplayer _multiplayerImplementation;
|
//private IMultiplayer _multiplayerImplementation;
|
||||||
@@ -269,24 +264,24 @@ namespace Torch.Managers
|
|||||||
private void ValidateAuthTicketResponse(ulong steamID, JoinResult response, ulong steamOwner)
|
private void ValidateAuthTicketResponse(ulong steamID, JoinResult response, ulong steamOwner)
|
||||||
{
|
{
|
||||||
Log.Debug($"ValidateAuthTicketResponse(user={steamID}, response={response}, owner={steamOwner}");
|
Log.Debug($"ValidateAuthTicketResponse(user={steamID}, response={response}, owner={steamOwner}");
|
||||||
if (IsClientBanned(steamOwner) || MySandboxGame.ConfigDedicated.Banned.Contains(steamOwner))
|
if (IsClientBanned.Invoke(MyMultiplayer.Static, steamOwner) || MySandboxGame.ConfigDedicated.Banned.Contains(steamOwner))
|
||||||
{
|
{
|
||||||
this.UserRejected(steamID, JoinResult.BannedByAdmins);
|
UserRejected.Invoke((MyDedicatedServerBase)MyMultiplayer.Static, steamID, JoinResult.BannedByAdmins);
|
||||||
RaiseClientKicked(steamID);
|
RaiseClientKicked.Invoke((MyDedicatedServerBase)MyMultiplayer.Static, steamID);
|
||||||
}
|
}
|
||||||
else if (IsClientKicked(steamOwner))
|
else if (IsClientKicked.Invoke(MyMultiplayer.Static, steamOwner))
|
||||||
{
|
{
|
||||||
UserRejected(steamID, JoinResult.KickedRecently);
|
UserRejected.Invoke((MyDedicatedServerBase)MyMultiplayer.Static, steamID, JoinResult.KickedRecently);
|
||||||
RaiseClientKicked(steamID);
|
RaiseClientKicked.Invoke((MyDedicatedServerBase)MyMultiplayer.Static, steamID);
|
||||||
}
|
}
|
||||||
if (response != JoinResult.OK)
|
if (response != JoinResult.OK)
|
||||||
{
|
{
|
||||||
UserRejected(steamID, response);
|
UserRejected.Invoke((MyDedicatedServerBase)MyMultiplayer.Static, steamID, response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (MyMultiplayer.Static.MemberLimit > 0 && this._members.Count - 1 >= MyMultiplayer.Static.MemberLimit)
|
if (MyMultiplayer.Static.MemberLimit > 0 && _members.Invoke((MyDedicatedServerBase) MyMultiplayer.Static).Count - 1 >= MyMultiplayer.Static.MemberLimit)
|
||||||
{
|
{
|
||||||
UserRejected(steamID, JoinResult.ServerFull);
|
UserRejected.Invoke((MyDedicatedServerBase)MyMultiplayer.Static, steamID, JoinResult.ServerFull);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (MySandboxGame.ConfigDedicated.GroupID == 0uL ||
|
if (MySandboxGame.ConfigDedicated.GroupID == 0uL ||
|
||||||
@@ -298,25 +293,25 @@ namespace Torch.Managers
|
|||||||
}
|
}
|
||||||
if ((MyGameServiceAccountType)Reflection.InvokeStaticMethod(typeof(MyGameService), "GetServerAccountType", MySandboxGame.ConfigDedicated.GroupID) != MyGameServiceAccountType.Clan)
|
if ((MyGameServiceAccountType)Reflection.InvokeStaticMethod(typeof(MyGameService), "GetServerAccountType", MySandboxGame.ConfigDedicated.GroupID) != MyGameServiceAccountType.Clan)
|
||||||
{
|
{
|
||||||
this.UserRejected(steamID, JoinResult.GroupIdInvalid);
|
UserRejected.Invoke((MyDedicatedServerBase)MyMultiplayer.Static, steamID, JoinResult.GroupIdInvalid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (MyGameService.GameServer.RequestGroupStatus(steamID, MySandboxGame.ConfigDedicated.GroupID))
|
if (MyGameService.GameServer.RequestGroupStatus(steamID, MySandboxGame.ConfigDedicated.GroupID))
|
||||||
{
|
{
|
||||||
this._waitingForGroup.Add(steamID);
|
_waitingForGroup.Invoke((MyDedicatedServerBase)MyMultiplayer.Static).Add(steamID);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.UserRejected(steamID, JoinResult.SteamServersOffline);
|
UserRejected.Invoke((MyDedicatedServerBase)MyMultiplayer.Static, steamID, JoinResult.SteamServersOffline);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UserGroupStatusResponse(ulong userId, ulong groupId, bool member, bool officer)
|
private void UserGroupStatusResponse(ulong userId, ulong groupId, bool member, bool officer)
|
||||||
{
|
{
|
||||||
if (groupId == MySandboxGame.ConfigDedicated.GroupID && _waitingForGroup.Remove(userId))
|
if (groupId == MySandboxGame.ConfigDedicated.GroupID && _waitingForGroup.Invoke((MyDedicatedServerBase)MyMultiplayer.Static).Remove(userId))
|
||||||
{
|
{
|
||||||
if (member || officer)
|
if (member || officer)
|
||||||
UserAccepted(userId);
|
UserAccepted(userId);
|
||||||
else
|
else
|
||||||
UserRejected(userId, JoinResult.NotInGroup);
|
UserRejected.Invoke((MyDedicatedServerBase)MyMultiplayer.Static, userId, JoinResult.NotInGroup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,24 +325,13 @@ namespace Torch.Managers
|
|||||||
PlayerJoined?.Invoke(vm);
|
PlayerJoined?.Invoke(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UserRejected(ulong steamId, JoinResult reason)
|
[ReflectedMethod]
|
||||||
{
|
private static Action<MyDedicatedServerBase, ulong, JoinResult> UserRejected;
|
||||||
Reflection.InvokePrivateMethod(MyMultiplayer.Static, "UserRejected", steamId, reason);
|
[ReflectedMethod]
|
||||||
}
|
private static Func<MyMultiplayerBase, ulong, bool> IsClientBanned;
|
||||||
|
[ReflectedMethod]
|
||||||
private bool IsClientBanned(ulong steamId)
|
private static Func<MyMultiplayerBase, ulong, bool> IsClientKicked;
|
||||||
{
|
[ReflectedMethod]
|
||||||
return (bool)Reflection.InvokePrivateMethod(MyMultiplayer.Static, "IsClientBanned", steamId);
|
private static Action<MyMultiplayerBase, ulong> RaiseClientKicked;
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsClientKicked(ulong steamId)
|
|
||||||
{
|
|
||||||
return (bool)Reflection.InvokePrivateMethod(MyMultiplayer.Static, "IsClientKicked", steamId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RaiseClientKicked(ulong steamId)
|
|
||||||
{
|
|
||||||
Reflection.InvokePrivateMethod(MyMultiplayer.Static, "RaiseClientKicked", steamId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@@ -10,10 +12,17 @@ using Torch.API;
|
|||||||
|
|
||||||
namespace Torch.Managers
|
namespace Torch.Managers
|
||||||
{
|
{
|
||||||
internal interface IReflectedFieldAttribute
|
public abstract class ReflectedMemberAttribute : Attribute
|
||||||
{
|
{
|
||||||
string Name { get; set; }
|
/// <summary>
|
||||||
Type Type { get; set; }
|
/// Name of the member to access. If null, the tagged field's name.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Declaring type of the member to access. If null, inferred from the instance argument type.
|
||||||
|
/// </summary>
|
||||||
|
public Type Type { get; set; } = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -36,16 +45,8 @@ namespace Torch.Managers
|
|||||||
/// </code>
|
/// </code>
|
||||||
/// </example>
|
/// </example>
|
||||||
[AttributeUsage(AttributeTargets.Field)]
|
[AttributeUsage(AttributeTargets.Field)]
|
||||||
public class ReflectedGetterAttribute : Attribute, IReflectedFieldAttribute
|
public class ReflectedGetterAttribute : ReflectedMemberAttribute
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Name of the field to get. If null, the tagged field's name.
|
|
||||||
/// </summary>
|
|
||||||
public string Name { get; set; } = null;
|
|
||||||
/// <summary>
|
|
||||||
/// Declaring type of the field to get. If null, inferred from the instance argument type.
|
|
||||||
/// </summary>
|
|
||||||
public Type Type { get; set; } = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -68,16 +69,8 @@ namespace Torch.Managers
|
|||||||
/// </code>
|
/// </code>
|
||||||
/// </example>
|
/// </example>
|
||||||
[AttributeUsage(AttributeTargets.Field)]
|
[AttributeUsage(AttributeTargets.Field)]
|
||||||
public class ReflectedSetterAttribute : Attribute, IReflectedFieldAttribute
|
public class ReflectedSetterAttribute : ReflectedMemberAttribute
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Name of the field to get. If null, the tagged field's name.
|
|
||||||
/// </summary>
|
|
||||||
public string Name { get; set; } = null;
|
|
||||||
/// <summary>
|
|
||||||
/// Declaring type of the field to get. If null, inferred from the instance argument type.
|
|
||||||
/// </summary>
|
|
||||||
public Type Type { get; set; } = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -98,16 +91,8 @@ namespace Torch.Managers
|
|||||||
/// </code>
|
/// </code>
|
||||||
/// </example>
|
/// </example>
|
||||||
[AttributeUsage(AttributeTargets.Field)]
|
[AttributeUsage(AttributeTargets.Field)]
|
||||||
public class ReflectedMethodAttribute : Attribute
|
public class ReflectedMethodAttribute : ReflectedMemberAttribute
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Name of the method to invoke. If null, the tagged field's name.
|
|
||||||
/// </summary>
|
|
||||||
public string Name { get; set; } = null;
|
|
||||||
/// <summary>
|
|
||||||
/// Declaring type of the method to invoke. If null, inferred from the instance argument type.
|
|
||||||
/// </summary>
|
|
||||||
public Type Type { get; set; } = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -176,7 +161,7 @@ namespace Torch.Managers
|
|||||||
foreach (string ns in _namespaceBlacklist)
|
foreach (string ns in _namespaceBlacklist)
|
||||||
if (t.FullName.StartsWith(ns))
|
if (t.FullName.StartsWith(ns))
|
||||||
return;
|
return;
|
||||||
foreach (FieldInfo field in t.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
|
foreach (FieldInfo field in t.GetFields(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
|
||||||
Process(field);
|
Process(field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,18 +187,27 @@ namespace Torch.Managers
|
|||||||
var attr = field.GetCustomAttribute<ReflectedMethodAttribute>();
|
var attr = field.GetCustomAttribute<ReflectedMethodAttribute>();
|
||||||
if (attr != null)
|
if (attr != null)
|
||||||
{
|
{
|
||||||
|
if (!field.IsStatic)
|
||||||
|
throw new ArgumentException("Field must be static to be reflected");
|
||||||
ProcessReflectedMethod(field, attr);
|
ProcessReflectedMethod(field, attr);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
var attr2 = field.GetCustomAttribute<ReflectedGetterAttribute>();
|
var attr2 = field.GetCustomAttribute<ReflectedGetterAttribute>();
|
||||||
if (attr2 != null)
|
if (attr2 != null)
|
||||||
{
|
{
|
||||||
|
if (!field.IsStatic)
|
||||||
|
throw new ArgumentException("Field must be static to be reflected");
|
||||||
ProcessReflectedField(field, attr2);
|
ProcessReflectedField(field, attr2);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
var attr3 = field.GetCustomAttribute<ReflectedSetterAttribute>();
|
var attr3 = field.GetCustomAttribute<ReflectedSetterAttribute>();
|
||||||
if (attr3 != null)
|
if (attr3 != null)
|
||||||
{
|
{
|
||||||
|
if (!field.IsStatic)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Field must be static to be reflected");
|
||||||
|
}
|
||||||
|
|
||||||
ProcessReflectedField(field, attr3);
|
ProcessReflectedField(field, attr3);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -241,6 +235,14 @@ namespace Torch.Managers
|
|||||||
(attr is ReflectedStaticMethodAttribute ? BindingFlags.Static : BindingFlags.Instance) |
|
(attr is ReflectedStaticMethodAttribute ? BindingFlags.Static : BindingFlags.Instance) |
|
||||||
BindingFlags.Public |
|
BindingFlags.Public |
|
||||||
BindingFlags.NonPublic, null, CallingConventions.Any, trueParameterTypes, null);
|
BindingFlags.NonPublic, null, CallingConventions.Any, trueParameterTypes, null);
|
||||||
|
if (methodInstance == null)
|
||||||
|
{
|
||||||
|
string methodType = attr is ReflectedStaticMethodAttribute ? "static" : "instance";
|
||||||
|
string methodParams = string.Join(", ",
|
||||||
|
trueParameterTypes.Select(x => x.Name));
|
||||||
|
throw new NoNullAllowedException(
|
||||||
|
$"Unable to find {methodType} method {attr.Name ?? field.Name} in type {trueType.FullName} with parameters {methodParams}");
|
||||||
|
}
|
||||||
|
|
||||||
if (attr is ReflectedStaticMethodAttribute)
|
if (attr is ReflectedStaticMethodAttribute)
|
||||||
field.SetValue(null, Delegate.CreateDelegate(field.FieldType, methodInstance));
|
field.SetValue(null, Delegate.CreateDelegate(field.FieldType, methodInstance));
|
||||||
@@ -267,7 +269,7 @@ namespace Torch.Managers
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ProcessReflectedField(FieldInfo field, IReflectedFieldAttribute attr)
|
private static void ProcessReflectedField(FieldInfo field, ReflectedMemberAttribute attr)
|
||||||
{
|
{
|
||||||
MethodInfo delegateMethod = field.FieldType.GetMethod("Invoke");
|
MethodInfo delegateMethod = field.FieldType.GetMethod("Invoke");
|
||||||
ParameterInfo[] parameters = delegateMethod.GetParameters();
|
ParameterInfo[] parameters = delegateMethod.GetParameters();
|
||||||
@@ -312,7 +314,7 @@ namespace Torch.Managers
|
|||||||
GetFieldPropRecursive(trueType, trueName, bindingFlags, (a, b, c) => a.GetProperty(b, c));
|
GetFieldPropRecursive(trueType, trueName, bindingFlags, (a, b, c) => a.GetProperty(b, c));
|
||||||
if (sourceField == null && sourceProperty == null)
|
if (sourceField == null && sourceProperty == null)
|
||||||
throw new ArgumentException(
|
throw new ArgumentException(
|
||||||
$"Unable to find field or property for {trueName} in {trueType} or its base types", nameof(field));
|
$"Unable to find field or property for {trueName} in {trueType.FullName} or its base types", nameof(field));
|
||||||
|
|
||||||
ParameterExpression[] paramExp = parameters.Select(x => Expression.Parameter(x.ParameterType)).ToArray();
|
ParameterExpression[] paramExp = parameters.Select(x => Expression.Parameter(x.ParameterType)).ToArray();
|
||||||
|
|
||||||
|
@@ -179,6 +179,7 @@
|
|||||||
<Compile Include="PluginManifest.cs" />
|
<Compile Include="PluginManifest.cs" />
|
||||||
<Compile Include="Reflection.cs" />
|
<Compile Include="Reflection.cs" />
|
||||||
<Compile Include="Managers\ScriptingManager.cs" />
|
<Compile Include="Managers\ScriptingManager.cs" />
|
||||||
|
<Compile Include="TorchAssemblyResolver.cs" />
|
||||||
<Compile Include="TorchBase.cs" />
|
<Compile Include="TorchBase.cs" />
|
||||||
<Compile Include="SteamService.cs" />
|
<Compile Include="SteamService.cs" />
|
||||||
<Compile Include="TorchPluginBase.cs" />
|
<Compile Include="TorchPluginBase.cs" />
|
||||||
|
@@ -19,7 +19,7 @@ namespace Torch.Client
|
|||||||
|
|
||||||
public TorchAssemblyResolver(params string[] paths)
|
public TorchAssemblyResolver(params string[] paths)
|
||||||
{
|
{
|
||||||
string location = Assembly.GetEntryAssembly().Location;
|
string location = Assembly.GetEntryAssembly()?.Location ?? GetType().Assembly.Location;
|
||||||
location = location != null ? Path.GetDirectoryName(location) + Path.DirectorySeparatorChar : null;
|
location = location != null ? Path.GetDirectoryName(location) + Path.DirectorySeparatorChar : null;
|
||||||
_removablePathPrefix = location ?? "";
|
_removablePathPrefix = location ?? "";
|
||||||
_paths = paths;
|
_paths = paths;
|
Reference in New Issue
Block a user