diff --git a/NLog-user.config b/NLog-user.config
deleted file mode 100644
index 9b10655..0000000
--- a/NLog-user.config
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/NLog.config b/NLog.config
index 350ac1f..deab41a 100644
--- a/NLog.config
+++ b/NLog.config
@@ -3,8 +3,6 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-
-
diff --git a/Torch.API/ModAPI/TorchAPI.cs b/Torch.API/ModAPI/TorchAPI.cs
index 60560c8..40a2822 100644
--- a/Torch.API/ModAPI/TorchAPI.cs
+++ b/Torch.API/ModAPI/TorchAPI.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices.WindowsRuntime;
using System.Text;
using System.Threading.Tasks;
diff --git a/Torch.API/Torch.API.csproj b/Torch.API/Torch.API.csproj
index 290f645..d8cf975 100644
--- a/Torch.API/Torch.API.csproj
+++ b/Torch.API/Torch.API.csproj
@@ -1,205 +1,106 @@
-
-
-
+
- {FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}
- Library
- Properties
- Torch.API
- Torch.API
- v4.6.1
- 512
-
-
-
- 7.3
-
-
- true
- $(SolutionDir)\bin\x64\Debug\
- DEBUG;TRACE
- full
+ net6-windows
+ Torch API
+ Torch
+ Copyright © Torch API 2017
+ false
+ $(SolutionDir)\bin\$(Platform)\$(Configuration)\
+ True
+ False
x64
- prompt
- MinimumRecommendedRules.ruleset
+ Debug;Release
+ AnyCPU
-
- $(SolutionDir)\bin\x64\Release\
- TRACE
- true
- pdbonly
- x64
- prompt
- MinimumRecommendedRules.ruleset
- $(SolutionDir)\bin\x64\Release\Torch.API.xml
+
+ $(SolutionDir)\bin\$(Platform)\$(Configuration)\Torch.API.xml
1591
+
-
-
+
+
- False
..\GameBinaries\HavokWrapper.dll
False
-
-
- ..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll
- True
-
-
- ..\packages\NLog.4.4.12\lib\net45\NLog.dll
- True
-
-
-
-
False
+
+
..\GameBinaries\Sandbox.Common.dll
False
+ False
- False
..\GameBinaries\Sandbox.Game.dll
False
+ False
- False
..\GameBinaries\Sandbox.Graphics.dll
False
+ False
- False
..\GameBinaries\SpaceEngineers.Game.dll
False
+ False
- False
..\GameBinaries\SpaceEngineers.ObjectBuilders.dll
False
-
-
False
- ..\GameBinaries\SpaceEngineers.ObjectBuilders.XmlSerializers.dll
- False
-
-
-
-
-
-
-
-
-
-
-
-
-
..\GameBinaries\VRage.dll
False
- False
..\GameBinaries\VRage.Audio.dll
False
+ False
..\GameBinaries\VRage.Dedicated.dll
False
- False
..\GameBinaries\VRage.Game.dll
False
-
-
False
- ..\GameBinaries\VRage.Game.XmlSerializers.dll
- False
- False
..\GameBinaries\VRage.Input.dll
False
+ False
..\GameBinaries\VRage.Library.dll
False
- False
..\GameBinaries\VRage.Math.dll
False
+ False
- False
..\GameBinaries\VRage.Render.dll
False
+ False
- False
..\GameBinaries\VRage.Render11.dll
False
+ False
- False
..\GameBinaries\VRage.Scripting.dll
False
+ False
-
- Properties\AssemblyVersion.cs
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/Torch.API/WebAPI/PluginQuery.cs b/Torch.API/WebAPI/PluginQuery.cs
index 60af524..3143f36 100644
--- a/Torch.API/WebAPI/PluginQuery.cs
+++ b/Torch.API/WebAPI/PluginQuery.cs
@@ -1,82 +1,45 @@
using System;
-using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
-using System.Text;
+using System.Net.Http.Json;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using System.Threading;
using System.Threading.Tasks;
-using Newtonsoft.Json;
using NLog;
namespace Torch.API.WebAPI
{
public class PluginQuery
{
- private const string ALL_QUERY = "https://torchapi.com/api/plugins";
- private const string PLUGIN_QUERY = "https://torchapi.com/api/plugins/item/{0}";
+ private const string ALL_QUERY = "https://torchapi.com/api/plugins/";
+ private const string PLUGIN_QUERY = "https://torchapi.com/api/plugins/item/{0}/";
private readonly HttpClient _client;
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
private static PluginQuery _instance;
- public static PluginQuery Instance => _instance ?? (_instance = new PluginQuery());
+ public static PluginQuery Instance => _instance ??= new();
private PluginQuery()
{
- _client = new HttpClient();
+ _client = new();
}
- public async Task QueryAll()
+ public async Task QueryAll()
{
- var h = await _client.GetAsync(ALL_QUERY);
- if (!h.IsSuccessStatusCode)
- {
- Log.Error($"Plugin query returned response {h.StatusCode}");
- return null;
- }
-
- var r = await h.Content.ReadAsStringAsync();
-
- PluginResponse response;
- try
- {
- response = JsonConvert.DeserializeObject(r);
- }
- catch (Exception ex)
- {
- Log.Error(ex, "Failed to deserialize plugin query response!");
- return null;
- }
- return response;
+ return (PluginsResponse) await _client.GetFromJsonAsync(ALL_QUERY, typeof(PluginsResponse), CancellationToken.None);
}
- public async Task QueryOne(Guid guid)
+ public Task QueryOne(Guid guid)
{
- return await QueryOne(guid.ToString());
+ return QueryOne(guid.ToString());
}
- public async Task QueryOne(string guid)
+ public async Task QueryOne(string guid)
{
-
- var h = await _client.GetAsync(string.Format(PLUGIN_QUERY, guid));
- if (!h.IsSuccessStatusCode)
- {
- Log.Error($"Plugin query returned response {h.StatusCode}");
- return null;
- }
-
- var r = await h.Content.ReadAsStringAsync();
-
- PluginFullItem response;
- try
- {
- response = JsonConvert.DeserializeObject(r);
- }
- catch (Exception ex)
- {
- Log.Error(ex, "Failed to deserialize plugin query response!");
- return null;
- }
- return response;
+ return (PluginItem) await _client.GetFromJsonAsync(string.Format(PLUGIN_QUERY, guid), typeof(PluginItem),
+ CancellationToken.None);
}
public async Task DownloadPlugin(Guid guid, string path = null)
@@ -91,39 +54,31 @@ namespace Torch.API.WebAPI
return await DownloadPlugin(item, path);
}
- public async Task DownloadPlugin(PluginFullItem item, string path = null)
+ public async Task DownloadPlugin(PluginItem item, string path = null)
{
try
{
- path = path ?? $"Plugins\\{item.Name}.zip";
- string relpath = Path.GetDirectoryName(path);
+ path ??= Path.Combine(Directory.GetCurrentDirectory(), "Plugins", $"{item.Name}.zip");
- Directory.CreateDirectory(relpath);
-
- var h = await _client.GetAsync(string.Format(PLUGIN_QUERY, item.ID));
- string res = await h.Content.ReadAsStringAsync();
- var response = JsonConvert.DeserializeObject(res);
+ var response = await QueryOne(item.Id);
if (response.Versions.Length == 0)
{
Log.Error($"Selected plugin {item.Name} does not have any versions to download!");
return false;
}
var version = response.Versions.FirstOrDefault(v => v.Version == response.LatestVersion);
- if (version == null)
+ if (version is null)
{
Log.Error($"Could not find latest version for selected plugin {item.Name}");
return false;
}
- var s = await _client.GetStreamAsync(version.URL);
+ var s = await _client.GetStreamAsync(version.Url);
if(File.Exists(path))
File.Delete(path);
- using (var f = File.Create(path))
- {
- await s.CopyToAsync(f);
- await f.FlushAsync();
- }
+ await using var f = File.Create(path);
+ await s.CopyToAsync(f);
}
catch (Exception ex)
{
@@ -134,37 +89,15 @@ namespace Torch.API.WebAPI
}
}
- public class PluginResponse
+ public record PluginsResponse(PluginItem[] Plugins);
+
+ public record PluginItem(Guid Id, string Name, string Author, string Description, string LatestVersion,
+ VersionItem[] Versions)
{
- public PluginItem[] Plugins;
- public int Count;
+ [JsonIgnore]
+ public bool Installed { get; set; }
}
- public class PluginItem
- {
- public string ID;
- public string Name { get; set; }
- public string Author;
- public string Description;
- public string LatestVersion;
- public bool Installed { get; set; } = false;
-
- public override string ToString()
- {
- return Name;
- }
- }
-
- public class PluginFullItem : PluginItem
- {
- public VersionItem[] Versions;
- }
-
- public class VersionItem
- {
- public string Version;
- public string Note;
- public bool IsBeta;
- public string URL;
- }
+ public record VersionItem(string Version, string Note, [property: JsonPropertyName("is_beta")] bool IsBeta,
+ string Url);
}
diff --git a/Torch.API/packages.config b/Torch.API/packages.config
deleted file mode 100644
index fbd3f14..0000000
--- a/Torch.API/packages.config
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Torch.Client.Tests/Torch.Client.Tests.csproj b/Torch.Client.Tests/Torch.Client.Tests.csproj
index c1dc43a..cf64ce4 100644
--- a/Torch.Client.Tests/Torch.Client.Tests.csproj
+++ b/Torch.Client.Tests/Torch.Client.Tests.csproj
@@ -1,98 +1,51 @@
-
-
-
+
- {632E78C0-0DAC-4B71-B411-2F1B333CC310}
- Library
- Properties
- Torch.Client.Tests
- Torch.Client.Tests
- v4.6.1
- 512
-
-
-
+ net461
1591,0649
+ Torch Client Tests
+ Torch
+ Copyright © Torch API 2017
+ false
+ MinimumRecommendedRules.ruleset
+ $(SolutionDir)\bin-test\$(Platform)\$(Configuration)\
- true
- $(SolutionDir)\bin-test\x64\Debug\
- DEBUG;TRACE
full
- x64
- prompt
- MinimumRecommendedRules.ruleset
- $(SolutionDir)\bin-test\x64\Release\
- TRACE
- true
pdbonly
- x64
- prompt
- MinimumRecommendedRules.ruleset
- $(SolutionDir)\bin-test\x64\Release\Torch.Client.Tests.xml
+ $(SolutionDir)\bin-test\$(Platform)\$(Configuration)\Torch.Client.Tests.xml
+
+
+
+
+
+
+
+
+
+
+
+ all
+
+
-
- ..\packages\NLog.4.4.12\lib\net45\NLog.dll
- True
-
-
-
-
-
-
-
- ..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll
-
-
- ..\packages\xunit.assert.2.2.0\lib\netstandard1.1\xunit.assert.dll
-
-
- ..\packages\xunit.extensibility.core.2.2.0\lib\netstandard1.1\xunit.core.dll
-
-
- ..\packages\xunit.extensibility.execution.2.2.0\lib\net452\xunit.execution.desktop.dll
-
-
- Properties\AssemblyVersion.cs
-
-
-
+
-
- {fba5d932-6254-4a1e-baf4-e229fa94e3c2}
- Torch.API
-
-
- {e36df745-260b-4956-a2e8-09f08b2e7161}
- Torch.Client
-
-
- {c3c8b671-6ad1-44aa-a8da-e0c0dc0fedf5}
- Torch.Tests
-
-
- {7e01635c-3b67-472e-bcd6-c5539564f214}
- Torch
- True
-
+
+
+
+
-
-
+
+
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Torch.Client.Tests/packages.config b/Torch.Client.Tests/packages.config
deleted file mode 100644
index 30eb495..0000000
--- a/Torch.Client.Tests/packages.config
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Torch.Client/Torch.Client.csproj b/Torch.Client/Torch.Client.csproj
index 1ecb37a..3aac86a 100644
--- a/Torch.Client/Torch.Client.csproj
+++ b/Torch.Client/Torch.Client.csproj
@@ -1,81 +1,68 @@
-
-
-
+
- {E36DF745-260B-4956-A2E8-09F08B2E7161}
WinExe
- Properties
- Torch.Client
- Torch.Client
- v4.6.1
- 512
+ net461
{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- 4
true
-
-
-
+ Torch Client
+ Torch
+ Copyright © Torch API 2017
+ false
+ MinimumRecommendedRules.ruleset
+ $(SolutionDir)\bin\$(Platform)\$(Configuration)\
+ true
+ true
+ copy "$(SolutionDir)NLog.config" "$(TargetDir)"
+
+ copy "$(SolutionDir)NLog.config" "$(TargetDir)"
+
+ copy "$(SolutionDir)NLog.config" "$(TargetDir)"
+
- true
- $(SolutionDir)\bin\x64\Debug\
- DEBUG;TRACE
full
- x64
- prompt
- MinimumRecommendedRules.ruleset
- true
- $(SolutionDir)\bin\x64\Release\
- TRACE
- true
pdbonly
- x64
- prompt
- MinimumRecommendedRules.ruleset
- true
- $(SolutionDir)\bin\x64\Release\Torch.Client.xml
+ $(SolutionDir)\bin\$(Platform)\$(Configuration)\Torch.Client.xml
1591
torchicon.ico
+
+ copy "$(SolutionDir)NLog.config" "$(TargetDir)"
+
+
+
+
+
+
+
-
- ..\packages\NLog.4.4.12\lib\net45\NLog.dll
- True
-
- False
..\GameBinaries\Sandbox.Common.dll
False
+ False
..\GameBinaries\Sandbox.Game.dll
False
- False
..\GameBinaries\Sandbox.Graphics.dll
False
+ False
..\GameBinaries\SpaceEngineers.Game.dll
False
-
-
-
-
-
-
- 4.0
-
+
..\GameBinaries\VRage.dll
False
@@ -89,18 +76,18 @@
False
- False
..\GameBinaries\VRage.Input.dll
False
+ False
..\GameBinaries\VRage.Library.dll
False
- False
..\GameBinaries\VRage.Math.dll
False
+ False
..\GameBinaries\VRage.Render.dll
@@ -119,65 +106,17 @@
-
- Properties\AssemblyVersion.cs
-
-
-
-
-
-
-
-
-
-
- True
- True
- Resources.resx
-
-
- True
- Settings.settings
- True
-
-
-
-
-
- ResXFileCodeGenerator
- Resources.Designer.cs
-
-
-
-
- SettingsSingleFileGenerator
- Settings.Designer.cs
-
-
+
-
- {fba5d932-6254-4a1e-baf4-e229fa94e3c2}
- Torch.API
- False
-
-
- {7E01635C-3B67-472E-BCD6-C5539564F214}
- Torch
- False
-
+
+
-
+
+
-
-
-
-
- copy "$(SolutionDir)NLog.config" "$(TargetDir)"
-
-
\ No newline at end of file
diff --git a/Torch.Client/packages.config b/Torch.Client/packages.config
deleted file mode 100644
index 9d88a31..0000000
--- a/Torch.Client/packages.config
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/Torch.Mod/Torch.Mod.shproj b/Torch.Mod/Torch.Mod.shproj
index bc7cbf1..68fbcbe 100644
--- a/Torch.Mod/Torch.Mod.shproj
+++ b/Torch.Mod/Torch.Mod.shproj
@@ -7,7 +7,6 @@
-
diff --git a/Torch.Server.Tests/Torch.Server.Tests.csproj b/Torch.Server.Tests/Torch.Server.Tests.csproj
index 3c02a7c..eb8f250 100644
--- a/Torch.Server.Tests/Torch.Server.Tests.csproj
+++ b/Torch.Server.Tests/Torch.Server.Tests.csproj
@@ -1,107 +1,39 @@
-
-
-
+
- {9EFD1D91-2FA2-47ED-B537-D8BC3B0E543E}
- Library
- Properties
- Torch.Server.Tests
- Torch.Server.Tests
- v4.8
- 512
-
-
-
+ net6-windows
1591,0649
-
-
- true
- $(SolutionDir)\bin-test\x64\Debug\
- DEBUG;TRACE
- full
- x64
- prompt
+ Torch Server Tests
+ Torch
+ Copyright © Torch API 2017
+ false
MinimumRecommendedRules.ruleset
-
-
- $(SolutionDir)\bin-test\x64\Release\
- TRACE
- true
- pdbonly
+ $(SolutionDir)\bin-test\$(Platform)\$(Configuration)\
x64
- prompt
- MinimumRecommendedRules.ruleset
- $(SolutionDir)\bin-test\x64\Release\Torch.Server.Tests.xml
+ Debug;Release
+ AnyCPU
+
+ $(SolutionDir)\bin-test\$(Platform)\$(Configuration)\Torch.Server.Tests.xml
+
+
-
-
+
+
+
-
- ..\packages\NLog.4.4.12\lib\net45\NLog.dll
- True
-
-
-
-
-
-
-
-
-
-
- False
..\GameBinaries\VRage.Game.dll
-
-
- ..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll
-
-
- ..\packages\xunit.assert.2.2.0\lib\netstandard1.1\xunit.assert.dll
-
-
- ..\packages\xunit.extensibility.core.2.2.0\lib\netstandard1.1\xunit.core.dll
-
-
- ..\packages\xunit.extensibility.execution.2.2.0\lib\net452\xunit.execution.desktop.dll
+ False
-
- Properties\AssemblyVersion.cs
-
-
-
-
+
-
- {fba5d932-6254-4a1e-baf4-e229fa94e3c2}
- Torch.API
-
-
- {ca50886b-7b22-4cd8-93a0-c06f38d4f77d}
- Torch.Server
-
-
- {c3c8b671-6ad1-44aa-a8da-e0c0dc0fedf5}
- Torch.Tests
-
-
- {7e01635c-3b67-472e-bcd6-c5539564f214}
- Torch
- True
-
+
+
+
+
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Torch.Server.Tests/packages.config b/Torch.Server.Tests/packages.config
deleted file mode 100644
index 30eb495..0000000
--- a/Torch.Server.Tests/packages.config
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Torch.Server/FodyWeavers.xml b/Torch.Server/FodyWeavers.xml
new file mode 100644
index 0000000..d5abfed
--- /dev/null
+++ b/Torch.Server/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/Torch.Server/FodyWeavers.xsd b/Torch.Server/FodyWeavers.xsd
new file mode 100644
index 0000000..69dbe48
--- /dev/null
+++ b/Torch.Server/FodyWeavers.xsd
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+ Used to control if the On_PropertyName_Changed feature is enabled.
+
+
+
+
+ Used to control if the Dependent properties feature is enabled.
+
+
+
+
+ Used to control if the IsChanged property feature is enabled.
+
+
+
+
+ Used to change the name of the method that fires the notify event. This is a string that accepts multiple values in a comma separated form.
+
+
+
+
+ Used to control if equality checks should be inserted. If false, equality checking will be disabled for the project.
+
+
+
+
+ Used to control if equality checks should use the Equals method resolved from the base class.
+
+
+
+
+ Used to control if equality checks should use the static Equals method resolved from the base class.
+
+
+
+
+ Used to turn off build warnings from this weaver.
+
+
+
+
+ Used to turn off build warnings about mismatched On_PropertyName_Changed methods.
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/Torch.Server/Initializer.cs b/Torch.Server/Initializer.cs
index c88e617..062b63c 100644
--- a/Torch.Server/Initializer.cs
+++ b/Torch.Server/Initializer.cs
@@ -229,37 +229,11 @@ quit";
}
}
- private void LogException(Exception ex)
- {
- if (ex is AggregateException ag)
- {
- foreach (var e in ag.InnerExceptions)
- LogException(e);
-
- return;
- }
-
- Log.Fatal(ex);
-
- if (ex is ReflectionTypeLoadException extl)
- {
- foreach (var exl in extl.LoaderExceptions)
- LogException(exl);
-
- return;
- }
-
- if (ex.InnerException != null)
- {
- LogException(ex.InnerException);
- }
- }
-
private void HandleException(object sender, UnhandledExceptionEventArgs e)
{
_server.FatalException = true;
var ex = (Exception)e.ExceptionObject;
- LogException(ex);
+ Log.Fatal(ex.ToStringDemystified());
if (MyFakes.ENABLE_MINIDUMP_SENDING)
{
string path = Path.Combine(MyFileSystem.UserDataPath, "Minidump.dmp");
@@ -274,7 +248,7 @@ quit";
Console.WriteLine("Restarting in 5 seconds.");
Thread.Sleep(5000);
var exe = typeof(Program).Assembly.Location;
- Config.WaitForPID = Process.GetCurrentProcess().Id.ToString();
+ Config.WaitForPID = Environment.ProcessId.ToString();
Process.Start(exe, Config.ToString());
}
else
@@ -282,7 +256,7 @@ quit";
MessageBox.Show("Torch encountered a fatal error and needs to close. Please check the logs for details.");
}
- Process.GetCurrentProcess().Kill();
+ Environment.Exit(1);
}
}
}
diff --git a/Torch.Server/Managers/EntityControlManager.cs b/Torch.Server/Managers/EntityControlManager.cs
index 65d1e8f..b121fdf 100644
--- a/Torch.Server/Managers/EntityControlManager.cs
+++ b/Torch.Server/Managers/EntityControlManager.cs
@@ -40,15 +40,7 @@ namespace Torch.Server.Managers
protected abstract EntityControlViewModel Create(EntityViewModel evm);
-#pragma warning disable 649
- [ReflectedGetter(Name = "Keys")]
- private static readonly Func, ICollection> _weakTableKeys;
-#pragma warning restore 649
-
- ///
- /// Warning: Creates a giant list, avoid if possible.
- ///
- internal ICollection Keys => _weakTableKeys(_models);
+ internal IEnumerable Keys => _models.Select(b => b.Key);
internal EntityControlViewModel GetOrCreate(EntityViewModel evm)
{
diff --git a/Torch.Server/Managers/InstanceManager.cs b/Torch.Server/Managers/InstanceManager.cs
index 706b81f..2fb87f8 100644
--- a/Torch.Server/Managers/InstanceManager.cs
+++ b/Torch.Server/Managers/InstanceManager.cs
@@ -319,9 +319,6 @@ namespace Torch.Server.Managers
checkpoint.Mods = null;
checkpoint.Settings = null;
}
-
- OnPropertyChanged(nameof(Checkpoint));
- OnPropertyChanged(nameof(WorldConfiguration));
}
}
}
diff --git a/Torch.Server/Patches/CheckpointLoadPatch.cs b/Torch.Server/Patches/CheckpointLoadPatch.cs
new file mode 100644
index 0000000..e4f0ef5
--- /dev/null
+++ b/Torch.Server/Patches/CheckpointLoadPatch.cs
@@ -0,0 +1,39 @@
+using System.Reflection;
+using NLog;
+using Sandbox.Engine.Networking;
+using Torch.API.Managers;
+using Torch.Managers.PatchManager;
+using Torch.Server.Managers;
+using Torch.Utils;
+using VRage.Game;
+
+namespace Torch.Patches;
+
+[PatchShim]
+public static class CheckpointLoadPatch
+{
+ private static readonly ILogger Log = LogManager.GetCurrentClassLogger();
+
+ [ReflectedMethodInfo(typeof(MyLocalCache), "LoadCheckpoint")]
+ private static MethodInfo LoadCheckpointMethod = null!;
+
+ public static void Patch(PatchContext context)
+ {
+ context.GetPattern(LoadCheckpointMethod).AddPrefix();
+ }
+
+ private static bool Prefix(ref MyObjectBuilder_Checkpoint __result)
+ {
+#pragma warning disable CS0618
+ var world = TorchBase.Instance.Managers.GetManager().DedicatedConfig.SelectedWorld;
+#pragma warning restore CS0618
+ if (world is null)
+ {
+ Log.Error("Selected world is null");
+ return false;
+ }
+
+ __result = world.Checkpoint;
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/Torch.Server/Program.cs b/Torch.Server/Program.cs
index b5265a8..a42cc5b 100644
--- a/Torch.Server/Program.cs
+++ b/Torch.Server/Program.cs
@@ -4,11 +4,12 @@ using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
-using System.Reflection;
using System.ServiceProcess;
using System.Text;
using System.Threading;
+#if TORCH_SERVICE
using Microsoft.VisualBasic.Devices;
+#endif
using NLog;
using NLog.Fluent;
using NLog.Targets;
@@ -26,46 +27,27 @@ namespace Torch.Server
{
Target.Register("FlowDocument");
//Ensures that all the files are downloaded in the Torch directory.
- var workingDir = new FileInfo(typeof(Program).Assembly.Location).Directory.ToString();
+ var workingDir = new FileInfo(typeof(Program).Assembly.Location).Directory!.FullName;
var binDir = Path.Combine(workingDir, "DedicatedServer64");
Directory.SetCurrentDirectory(workingDir);
-
- //HACK for block skins update
- var badDlls = new[]
- {
- "System.Security.Principal.Windows.dll",
- "VRage.Platform.Windows.dll"
- };
-
- try
- {
- foreach (var file in badDlls)
+
+ if (Directory.Exists(binDir))
+ foreach (var file in Directory.GetFiles(binDir, "System.*.dll"))
{
- if (File.Exists(file))
- File.Delete(file);
+ File.Delete(file);
}
- }
- catch (Exception e)
- {
- var log = LogManager.GetCurrentClassLogger();
- log.Error($"Error updating. Please delete the following files from the Torch root folder manually:\r\n{string.Join("\r\n", badDlls)}");
- log.Error(e);
- return;
- }
-
- if (!TorchLauncher.IsTorchWrapped())
- {
- TorchLauncher.Launch(Assembly.GetEntryAssembly().FullName, args, binDir);
- return;
- }
+ TorchLauncher.Launch(workingDir, binDir);
+
// Breaks on Windows Server 2019
+#if TORCH_SERVICE
if (!new ComputerInfo().OSFullName.Contains("Server 2019") && !Environment.UserInteractive)
{
using (var service = new TorchService(args))
ServiceBase.Run(service);
return;
}
+#endif
var initializer = new Initializer(workingDir);
if (!initializer.Initialize(args))
diff --git a/Torch.Server/Properties/launchSettings.json b/Torch.Server/Properties/launchSettings.json
new file mode 100644
index 0000000..84581c4
--- /dev/null
+++ b/Torch.Server/Properties/launchSettings.json
@@ -0,0 +1,11 @@
+{
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "Torch.Server": {
+ "commandName": "Project",
+ "commandLineArgs": "-noupdate",
+ "use64Bit": true,
+ "hotReloadEnabled": false
+ }
+ }
+}
diff --git a/Torch.Server/Themes/Dark Theme Animated.xaml b/Torch.Server/Themes/Dark Theme Animated.xaml
index f7f4841..c5baf1c 100644
--- a/Torch.Server/Themes/Dark Theme Animated.xaml
+++ b/Torch.Server/Themes/Dark Theme Animated.xaml
@@ -4,11 +4,9 @@
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -115,7 +23,7 @@ Markdown="{StaticResource Markdown}"/>
-
+
@@ -132,11 +40,18 @@ Markdown="{StaticResource Markdown}"/>
-
-
-
+
+
+
+
+
+
+
+
+
-
+
+
diff --git a/Torch.Server/Views/PluginBrowser.xaml.cs b/Torch.Server/Views/PluginBrowser.xaml.cs
index 485d666..f5ef714 100644
--- a/Torch.Server/Views/PluginBrowser.xaml.cs
+++ b/Torch.Server/Views/PluginBrowser.xaml.cs
@@ -31,13 +31,13 @@ namespace Torch.Server.Views
///
public partial class PluginBrowser : Window, INotifyPropertyChanged
{
- private static Logger Log = LogManager.GetCurrentClassLogger();
+ private static Logger _log = LogManager.GetCurrentClassLogger();
public MtObservableList PluginsSource { get; set; } = new MtObservableList();
public MtObservableList Plugins { get; set; } = new MtObservableList();
public PluginItem CurrentItem { get; set; }
- public const string PLUGINS_SEARCH_TEXT = "Plugins search...";
- private string PreviousSearchQuery = "";
+ public const string PluginsSearchText = "Plugins search...";
+ private string _previousSearchQuery = "";
private string _description = "Loading data from server, please wait..";
private static object _syncLock = new object();
@@ -56,24 +56,35 @@ namespace Torch.Server.Views
InitializeComponent();
var installedPlugins = pluginManager.Plugins;
- BindingOperations.EnableCollectionSynchronization(Plugins,_syncLock);
+ BindingOperations.EnableCollectionSynchronization(Plugins, _syncLock);
Task.Run(async () =>
- {
- var res = await PluginQuery.Instance.QueryAll();
- if (res == null)
- return;
- foreach (var item in res.Plugins.OrderBy(i => i.Name)) {
- lock (_syncLock)
- {
- if (installedPlugins.Keys.Contains(Guid.Parse(item.ID)))
- item.Installed = true;
- Plugins.Add(item);
- PluginsList.Dispatcher.Invoke(() => PluginsList.SelectedIndex = 0);
- PluginsSource.Add(item);
- }
- }
- CurrentDescription = "Please select a plugin...";
- });
+ {
+ try
+ {
+ var res = await PluginQuery.Instance.QueryAll();
+ foreach (var item in res.Plugins.OrderBy(i => i.Name)) {
+ lock (_syncLock)
+ {
+ var pluginItem = item with
+ {
+ Description = item.Description.Replace("<", "<").Replace(">", ">"),
+ Installed = installedPlugins.Keys.Contains(item.Id)
+ };
+ Plugins.Add(pluginItem);
+ PluginsSource.Add(pluginItem);
+ }
+ }
+
+ Dispatcher.Invoke(() => PluginsList.SelectedIndex = 0);
+ CurrentDescription = "Please select a plugin...";
+ }
+ catch (Exception e)
+ {
+ MessageBox.Show(e.ToString(), "An Error Occurred", MessageBoxButton.OK, MessageBoxImage.Error);
+ Close();
+ throw;
+ }
+ });
MarkdownFlow.CommandBindings.Add(new CommandBinding(NavigationCommands.GoToPage, (sender, e) => OpenUri((string)e.Parameter)));
}
@@ -108,36 +119,36 @@ namespace Torch.Server.Views
private void DownloadButton_OnClick(object sender, RoutedEventArgs e)
{
- var SelectedItems = PluginsList.SelectedItems;
+ var selectedItems = PluginsList.SelectedItems;
- foreach(PluginItem PluginItem in SelectedItems)
- TorchBase.Instance.Config.Plugins.Add(new Guid(PluginItem.ID));
+ foreach(PluginItem pluginItem in selectedItems)
+ TorchBase.Instance.Config.Plugins.Add(pluginItem.Id);
TorchBase.Instance.Config.Save();
- Log.Info($"Started to download {SelectedItems.Count} plugin(s)");
+ _log.Info($"Started to download {selectedItems.Count} plugin(s)");
- PluginDownloader DownloadProgress = new PluginDownloader(SelectedItems);
- DownloadProgress.Show();
+ PluginDownloader downloadProgress = new PluginDownloader(selectedItems);
+ downloadProgress.Show();
}
private void UninstallButton_OnClick(object sender, RoutedEventArgs e) {
- var SelectedItems = PluginsList.SelectedItems;
- if(SelectedItems.Cast().Any(x => x.Installed == false)) {
+ var selectedItems = PluginsList.SelectedItems;
+ if(selectedItems.Cast().Any(x => x.Installed == false)) {
MessageBox.Show($"Error! You have selected at least 1 plugin which isnt currently installed. Please de-select and try again!", "Uninstall Error", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
- var result = MessageBox.Show($"Are you sure you want to attempt uninstall of {SelectedItems.Count} plugin(s)?", "Uninstall Confirmation", MessageBoxButton.YesNo);
+ var result = MessageBox.Show($"Are you sure you want to attempt uninstall of {selectedItems.Count} plugin(s)?", "Uninstall Confirmation", MessageBoxButton.YesNo);
if (result == MessageBoxResult.Yes) {
- foreach(PluginItem PluginItem in SelectedItems) {
- if(TorchBase.Instance.Config.Plugins.Contains(Guid.Parse(PluginItem.ID))) {
- TorchBase.Instance.Config.Plugins.Remove(Guid.Parse(PluginItem.ID));
+ foreach(PluginItem pluginItem in selectedItems) {
+ if(TorchBase.Instance.Config.Plugins.Contains(pluginItem.Id)) {
+ TorchBase.Instance.Config.Plugins.Remove(pluginItem.Id);
- string path = $"Plugins\\{PluginItem.Name}.zip";
+ string path = $"Plugins\\{pluginItem.Name}.zip";
if (File.Exists(path))
File.Delete(path);
- Log.Info($"Uninstalled {PluginItem.Name}");
+ _log.Info($"Uninstalled {pluginItem.Name}");
}
}
MessageBox.Show($"Plugins removed... Please restart your server for changes to take effect.", "Uninstall Confirmation", MessageBoxButton.OK);
@@ -153,45 +164,45 @@ namespace Torch.Server.Views
}
private void TxtPluginsSearch_GotFocus(object sender, RoutedEventArgs e) {
- if (txtPluginsSearch.Text == PLUGINS_SEARCH_TEXT) {
- txtPluginsSearch.Clear();
- txtPluginsSearch.Foreground = Brushes.Black;
+ if (TxtPluginsSearch.Text == PluginsSearchText) {
+ TxtPluginsSearch.Clear();
+ TxtPluginsSearch.Foreground = Brushes.Black;
return;
}
}
private void TxtPluginsSearch_LostFocus(object sender, RoutedEventArgs e) {
- if(txtPluginsSearch.Text == "") {
- txtPluginsSearch.Foreground = Brushes.Gray;
- txtPluginsSearch.Text = PLUGINS_SEARCH_TEXT;
+ if(TxtPluginsSearch.Text == "") {
+ TxtPluginsSearch.Foreground = Brushes.Gray;
+ TxtPluginsSearch.Text = PluginsSearchText;
return;
}
}
private void TxtPluginsSearch_TextChanged(object sender, TextChangedEventArgs e) {
- string SearchQueryString = txtPluginsSearch.Text;
+ string searchQueryString = TxtPluginsSearch.Text;
- if(SearchQueryString.Length < PreviousSearchQuery.Length) {
+ if(searchQueryString.Length < _previousSearchQuery.Length) {
ResetSearchFilter();
}
- if (SearchQueryString != PLUGINS_SEARCH_TEXT && SearchQueryString != string.Empty) {
- SearchPlugins(SearchQueryString);
+ if (searchQueryString != PluginsSearchText && searchQueryString != string.Empty) {
+ SearchPlugins(searchQueryString);
} else {
ResetSearchFilter();
}
- PreviousSearchQuery = SearchQueryString;
+ _previousSearchQuery = searchQueryString;
}
- private void SearchPlugins(string SearchQueryString) {
- foreach (var plugin in Plugins.Where(p => !p.Name.Contains(SearchQueryString, StringComparison.OrdinalIgnoreCase) &&
- !p.Author.Contains(SearchQueryString, StringComparison.OrdinalIgnoreCase))) {
+ private void SearchPlugins(string searchQueryString) {
+ foreach (var plugin in Plugins.Where(p => !p.Name.Contains(searchQueryString, StringComparison.OrdinalIgnoreCase) &&
+ !p.Author.Contains(searchQueryString, StringComparison.OrdinalIgnoreCase))) {
Plugins.Remove(plugin);
}
- foreach (var plugin in Plugins.Where(p => p.Name.Contains(SearchQueryString, StringComparison.OrdinalIgnoreCase) ||
- p.Author.Contains(SearchQueryString, StringComparison.OrdinalIgnoreCase))) {
+ foreach (var plugin in Plugins.Where(p => p.Name.Contains(searchQueryString, StringComparison.OrdinalIgnoreCase) ||
+ p.Author.Contains(searchQueryString, StringComparison.OrdinalIgnoreCase))) {
if (!Plugins.Contains(plugin))
Plugins.Add(plugin);
}
diff --git a/Torch.Server/Views/PluginDownloader.xaml.cs b/Torch.Server/Views/PluginDownloader.xaml.cs
index e8e4495..ecdb8b0 100644
--- a/Torch.Server/Views/PluginDownloader.xaml.cs
+++ b/Torch.Server/Views/PluginDownloader.xaml.cs
@@ -50,7 +50,7 @@ namespace Torch.Server.Views
var PercentChangeOnDownload = 100 / PluginsToDownload.Count;
foreach (PluginItem PluginItem in PluginsToDownload) {
- if (!Task.Run(async () => await PluginQuery.Instance.DownloadPlugin(PluginItem.ID)).Result) {
+ if (!Task.Run(async () => await PluginQuery.Instance.DownloadPlugin(PluginItem.Id)).Result) {
failedDownloads++;
DownloadProgress += PercentChangeOnDownload;
(sender as BackgroundWorker).ReportProgress(DownloadProgress);
diff --git a/Torch.Server/Views/RoleEditor.xaml.cs b/Torch.Server/Views/RoleEditor.xaml.cs
index d1106ce..b8c32ff 100644
--- a/Torch.Server/Views/RoleEditor.xaml.cs
+++ b/Torch.Server/Views/RoleEditor.xaml.cs
@@ -81,25 +81,22 @@ namespace Torch.Server.Views
public class DictionaryItem : ViewModel, IDictionaryItem
{
- private TKey _key;
- private TValue _value;
+ object IDictionaryItem.Key { get; set; }
+ object IDictionaryItem.Value { get; set; }
- object IDictionaryItem.Key { get => _key; set => SetValue(ref _key, (TKey)value); }
- object IDictionaryItem.Value { get => _value; set => SetValue(ref _value, (TValue)value); }
-
- public TKey Key { get => _key; set => SetValue(ref _key, value); }
- public TValue Value { get => _value; set => SetValue(ref _value, value); }
+ public TKey Key { get; set; }
+ public TValue Value { get; set; }
public DictionaryItem()
{
- _key = default(TKey);
- _value = default(TValue);
+ Key = default(TKey);
+ Value = default(TValue);
}
public DictionaryItem(TKey key, TValue value)
{
- _key = key;
- _value = value;
+ Key = key;
+ Value = value;
}
}
diff --git a/Torch.Server/Views/TorchUI.xaml b/Torch.Server/Views/TorchUI.xaml
index 6ccaa41..5a37ce2 100644
--- a/Torch.Server/Views/TorchUI.xaml
+++ b/Torch.Server/Views/TorchUI.xaml
@@ -93,8 +93,7 @@
-
-
+
diff --git a/Torch.Server/Views/TorchUI.xaml.cs b/Torch.Server/Views/TorchUI.xaml.cs
index b973599..1850351 100644
--- a/Torch.Server/Views/TorchUI.xaml.cs
+++ b/Torch.Server/Views/TorchUI.xaml.cs
@@ -20,6 +20,7 @@ using Sandbox;
using Torch.API;
using Torch.API.Managers;
using Torch.Server.Managers;
+using Torch.Server.Views;
using MessageBoxResult = System.Windows.MessageBoxResult;
namespace Torch.Server
@@ -137,7 +138,11 @@ namespace Torch.Server
_config = config;
Dispatcher.Invoke(() =>
{
- //InstancePathBox.Text = config.InstancePath;
+ EntityManagerTab.IsEnabled = _config.EntityManagerEnabled;
+ if (_config.EntityManagerEnabled)
+ {
+ EntityManagerTab.Content = new EntitiesControl();
+ }
});
}
diff --git a/Torch.Server/app.config b/Torch.Server/app.config
deleted file mode 100644
index 3e0e37c..0000000
--- a/Torch.Server/app.config
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/Torch.Server/packages.config b/Torch.Server/packages.config
deleted file mode 100644
index e04f668..0000000
--- a/Torch.Server/packages.config
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Torch.Tests/Torch.Tests.csproj b/Torch.Tests/Torch.Tests.csproj
index 016e97b..d973b51 100644
--- a/Torch.Tests/Torch.Tests.csproj
+++ b/Torch.Tests/Torch.Tests.csproj
@@ -1,98 +1,41 @@
-
-
-
+
- {C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}
- Library
- Properties
- Torch.Tests
- Torch.Tests
- v4.8
- 512
-
-
-
+ net6-windows
1591,0649
-
-
- true
- $(SolutionDir)\bin-test\x64\Debug\
- DEBUG;TRACE
- full
- x64
- prompt
+ Torch Tests
+ Torch
+ Copyright © Torch API 2017
+ false
MinimumRecommendedRules.ruleset
-
-
- $(SolutionDir)\bin-test\x64\Release\
- TRACE
- true
- pdbonly
+ $(SolutionDir)\bin-test\$(Platform)\$(Configuration)\
+ False
x64
- prompt
- MinimumRecommendedRules.ruleset
- $(SolutionDir)\bin-test\x64\Release\Torch.Tests.xml
+ Debug;Release
+ AnyCPU
+
+ $(SolutionDir)\bin-test\$(Platform)\$(Configuration)\Torch.Tests.xml
+
+
+
+
+
+
+
-
- ..\packages\NLog.4.4.12\lib\net45\NLog.dll
- True
-
-
-
-
-
-
-
- ..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll
-
-
- ..\packages\xunit.assert.2.2.0\lib\netstandard1.1\xunit.assert.dll
-
-
- ..\packages\xunit.extensibility.core.2.2.0\lib\netstandard1.1\xunit.core.dll
-
-
- ..\packages\xunit.extensibility.execution.2.2.0\lib\net452\xunit.execution.desktop.dll
-
-
- Properties\AssemblyVersion.cs
-
-
-
-
-
-
-
+
-
- {fba5d932-6254-4a1e-baf4-e229fa94e3c2}
- Torch.API
-
-
- {7e01635c-3b67-472e-bcd6-c5539564f214}
- Torch
- True
-
+
+
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Torch.Tests/packages.config b/Torch.Tests/packages.config
deleted file mode 100644
index 30eb495..0000000
--- a/Torch.Tests/packages.config
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Torch.sln b/Torch.sln
index 2cca71d..fba04a5 100644
--- a/Torch.sln
+++ b/Torch.sln
@@ -7,22 +7,17 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch", "Torch\Torch.csproj
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.API", "Torch.API\Torch.API.csproj", "{FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.Client", "Torch.Client\Torch.Client.csproj", "{E36DF745-260B-4956-A2E8-09F08B2E7161}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.Server", "Torch.Server\Torch.Server.csproj", "{CA50886B-7B22-4CD8-93A0-C06F38D4F77D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7AD02A71-1D4C-48F9-A8C1-789A5512424F}"
ProjectSection(SolutionItems) = preProject
NLog.config = NLog.config
- NLog-user.config = NLog-user.config
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.Tests", "Torch.Tests\Torch.Tests.csproj", "{C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.Server.Tests", "Torch.Server.Tests\Torch.Server.Tests.csproj", "{9EFD1D91-2FA2-47ED-B537-D8BC3B0E543E}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.Client.Tests", "Torch.Client.Tests\Torch.Client.Tests.csproj", "{632E78C0-0DAC-4B71-B411-2F1B333CC310}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Versioning", "Versioning", "{762F6A0D-55EF-4173-8CDE-309D183F40C4}"
ProjectSection(SolutionItems) = preProject
Versioning\AssemblyVersion.cs = Versioning\AssemblyVersion.cs
@@ -37,49 +32,22 @@ Global
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
- Debug|x64 = Debug|x64
Release|Any CPU = Release|Any CPU
- Release|x64 = Release|x64
EndGlobalSection
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.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.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.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.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}.Release|Any CPU.ActiveCfg = Release|x64
- {E36DF745-260B-4956-A2E8-09F08B2E7161}.Release|x64.ActiveCfg = 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.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.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
- {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
- {632E78C0-0DAC-4B71-B411-2F1B333CC310}.Debug|Any CPU.ActiveCfg = Debug|x64
- {632E78C0-0DAC-4B71-B411-2F1B333CC310}.Debug|x64.ActiveCfg = Debug|x64
- {632E78C0-0DAC-4B71-B411-2F1B333CC310}.Release|Any CPU.ActiveCfg = Release|x64
- {632E78C0-0DAC-4B71-B411-2F1B333CC310}.Release|x64.ActiveCfg = Release|x64
+ {7E01635C-3B67-472E-BCD6-C5539564F214}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7E01635C-3B67-472E-BCD6-C5539564F214}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7E01635C-3B67-472E-BCD6-C5539564F214}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CA50886B-7B22-4CD8-93A0-C06F38D4F77D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CA50886B-7B22-4CD8-93A0-C06F38D4F77D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CA50886B-7B22-4CD8-93A0-C06F38D4F77D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9EFD1D91-2FA2-47ED-B537-D8BC3B0E543E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9EFD1D91-2FA2-47ED-B537-D8BC3B0E543E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Torch/Collections/MtObservableCollectionBase.cs b/Torch/Collections/MtObservableCollectionBase.cs
index 0473e8d..ce612f0 100644
--- a/Torch/Collections/MtObservableCollectionBase.cs
+++ b/Torch/Collections/MtObservableCollectionBase.cs
@@ -8,6 +8,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using PropertyChanged;
using Torch.Utils;
namespace Torch.Collections
@@ -112,6 +113,7 @@ namespace Torch.Collections
_flushEventQueue?.Change(_eventRaiseDelay, -1);
}
+ [SuppressPropertyChangedWarnings]
protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (!NotificationsEnabled)
diff --git a/Torch/Collections/MtObservableList.cs b/Torch/Collections/MtObservableList.cs
index 0bf620b..d8ba646 100644
--- a/Torch/Collections/MtObservableList.cs
+++ b/Torch/Collections/MtObservableList.cs
@@ -5,6 +5,7 @@ using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using PropertyChanged;
using Torch.Utils;
namespace Torch.Collections
@@ -76,7 +77,9 @@ namespace Torch.Collections
}
}
+
///
+ [SuppressPropertyChangedWarnings]
public T this[int index]
{
get
@@ -181,6 +184,7 @@ namespace Torch.Collections
}
///
+ [SuppressPropertyChangedWarnings]
object IList.this[int index]
{
get => this[index];
diff --git a/Torch/Collections/MtObservableSortedDictionary.cs b/Torch/Collections/MtObservableSortedDictionary.cs
index 5f3781a..c1604ff 100644
--- a/Torch/Collections/MtObservableSortedDictionary.cs
+++ b/Torch/Collections/MtObservableSortedDictionary.cs
@@ -5,6 +5,7 @@ using System.Collections.Specialized;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading;
+using PropertyChanged;
using Torch.Utils;
namespace Torch.Collections
@@ -185,6 +186,7 @@ namespace Torch.Collections
}
///
+ [SuppressPropertyChangedWarnings]
public TV this[TK key]
{
get
diff --git a/Torch/CommandLine.cs b/Torch/CommandLine.cs
index c851427..da71001 100644
--- a/Torch/CommandLine.cs
+++ b/Torch/CommandLine.cs
@@ -20,8 +20,10 @@ namespace Torch
_argPrefix = argPrefix;
foreach (var prop in GetType().GetProperties())
{
- if (prop.HasAttribute())
- _args.Add(prop.GetCustomAttribute(), prop);
+ var attr = prop.GetCustomAttribute();
+ if (attr == null)
+ continue;
+ _args.Add(attr, prop);
}
}
diff --git a/Torch/Commands/CommandManager.cs b/Torch/Commands/CommandManager.cs
index 80fcdb4..7d5a083 100644
--- a/Torch/Commands/CommandManager.cs
+++ b/Torch/Commands/CommandManager.cs
@@ -26,7 +26,7 @@ namespace Torch.Commands
public event CommandExecutingDel OnCommandExecuting;
private Logger _log = LogManager.GetCurrentClassLogger();
[Dependency]
- private IChatManagerServer _chatManager;
+ private IChatManagerServer _chatManager = null!;
public CommandManager(ITorchBase torch, char prefix = '!') : base(torch)
{
diff --git a/Torch/Commands/ConsoleCommandContext.cs b/Torch/Commands/ConsoleCommandContext.cs
index 0cf8414..9a1cc08 100644
--- a/Torch/Commands/ConsoleCommandContext.cs
+++ b/Torch/Commands/ConsoleCommandContext.cs
@@ -12,8 +12,6 @@ namespace Torch.Commands
public List Responses = new List();
public event Action OnResponse;
- private bool _flag;
-
///
public ConsoleCommandContext(ITorchBase torch, ITorchPlugin plugin, ulong steamIdSender, string rawArgs = null, List args = null)
: base(torch, plugin, steamIdSender, rawArgs, args) { }
@@ -27,7 +25,11 @@ namespace Torch.Commands
font = null;
}
+#pragma warning disable CS0618
+#pragma warning disable CS0612
var msg = new TorchChatMessage(sender ?? TorchBase.Instance.Config.ChatName, message, font ?? TorchBase.Instance.Config.ChatColor);
+#pragma warning restore CS0612
+#pragma warning restore CS0618
Responses.Add(msg);
OnResponse?.Invoke(msg);
}
diff --git a/Torch/Extensions/ICollectionExtensions.cs b/Torch/Extensions/ICollectionExtensions.cs
index 2e6842a..a80fbfe 100644
--- a/Torch/Extensions/ICollectionExtensions.cs
+++ b/Torch/Extensions/ICollectionExtensions.cs
@@ -5,6 +5,7 @@ using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Windows.Threading;
+using PropertyChanged;
namespace Torch
{
@@ -77,27 +78,29 @@ namespace Torch
_list = list;
if (_list is INotifyPropertyChanged p)
- p.PropertyChanged += OnPropertyChanged;
+ p.PropertyChanged += OnChildPropertyChanged;
if (_list is INotifyCollectionChanged c)
- c.CollectionChanged += OnCollectionChanged;
+ c.CollectionChanged += OnChildCollectionChanged;
}
public void Dispose()
{
if (_list is INotifyPropertyChanged p)
- p.PropertyChanged -= OnPropertyChanged;
+ p.PropertyChanged -= OnChildPropertyChanged;
if (_list is INotifyCollectionChanged c)
- c.CollectionChanged -= OnCollectionChanged;
+ c.CollectionChanged -= OnChildCollectionChanged;
}
- private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+ [SuppressPropertyChangedWarnings]
+ private void OnChildCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
OnCollectionChanged(e);
}
- private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
+ [SuppressPropertyChangedWarnings]
+ private void OnChildPropertyChanged(object sender, PropertyChangedEventArgs e)
{
OnPropertyChanged(e.PropertyName);
}
@@ -124,27 +127,29 @@ namespace Torch
_dictionary = dictionary;
if (_dictionary is INotifyPropertyChanged p)
- p.PropertyChanged += OnPropertyChanged;
+ p.PropertyChanged += OnChildPropertyChanged;
if (_dictionary is INotifyCollectionChanged c)
- c.CollectionChanged += OnCollectionChanged;
+ c.CollectionChanged += OnChildCollectionChanged;
}
public void Dispose()
{
if (_dictionary is INotifyPropertyChanged p)
- p.PropertyChanged -= OnPropertyChanged;
+ p.PropertyChanged -= OnChildPropertyChanged;
if (_dictionary is INotifyCollectionChanged c)
- c.CollectionChanged -= OnCollectionChanged;
+ c.CollectionChanged -= OnChildCollectionChanged;
}
- private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+ [SuppressPropertyChangedWarnings]
+ private void OnChildCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
OnCollectionChanged(e);
}
- private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
+ [SuppressPropertyChangedWarnings]
+ private void OnChildPropertyChanged(object sender, PropertyChangedEventArgs e)
{
OnPropertyChanged(e.PropertyName);
}
diff --git a/Torch/FodyWeavers.xml b/Torch/FodyWeavers.xml
new file mode 100644
index 0000000..d5abfed
--- /dev/null
+++ b/Torch/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/Torch/FodyWeavers.xsd b/Torch/FodyWeavers.xsd
new file mode 100644
index 0000000..69dbe48
--- /dev/null
+++ b/Torch/FodyWeavers.xsd
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+ Used to control if the On_PropertyName_Changed feature is enabled.
+
+
+
+
+ Used to control if the Dependent properties feature is enabled.
+
+
+
+
+ Used to control if the IsChanged property feature is enabled.
+
+
+
+
+ Used to change the name of the method that fires the notify event. This is a string that accepts multiple values in a comma separated form.
+
+
+
+
+ Used to control if equality checks should be inserted. If false, equality checking will be disabled for the project.
+
+
+
+
+ Used to control if equality checks should use the Equals method resolved from the base class.
+
+
+
+
+ Used to control if equality checks should use the static Equals method resolved from the base class.
+
+
+
+
+ Used to turn off build warnings from this weaver.
+
+
+
+
+ Used to turn off build warnings about mismatched On_PropertyName_Changed methods.
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/Torch/Managers/ChatManager/ChatManagerClient.cs b/Torch/Managers/ChatManager/ChatManagerClient.cs
index dad004b..961d1a2 100644
--- a/Torch/Managers/ChatManager/ChatManagerClient.cs
+++ b/Torch/Managers/ChatManager/ChatManagerClient.cs
@@ -12,7 +12,6 @@ using Sandbox.Game.Gui;
using Sandbox.Game.Multiplayer;
using Sandbox.Game.World;
using Sandbox.ModAPI;
-using SteamKit2.Unified.Internal;
using Torch.API;
using Torch.API.Managers;
using Torch.Utils;
@@ -120,7 +119,9 @@ namespace Torch.Managers.ChatManager
{
if (!sendToOthers)
return;
+#pragma warning disable CS0612
var torchMsg = new TorchChatMessage(MySession.Static.LocalHumanPlayer?.DisplayName ?? "Player", Sync.MyId, messageText, ChatChannel.Global, 0);
+#pragma warning restore CS0612
bool consumed = RaiseMessageRecieved(torchMsg);
if (!consumed)
consumed = OfflineMessageProcessor(torchMsg);
@@ -139,7 +140,9 @@ namespace Torch.Managers.ChatManager
private void Multiplayer_ChatMessageReceived(ulong steamUserId, string messageText, ChatChannel channel, long targetId, string customAuthorName)
{
+#pragma warning disable CS0612
var torchMsg = new TorchChatMessage(steamUserId, messageText, channel, targetId,
+#pragma warning restore CS0612
(steamUserId == MyGameService.UserId) ? MyFontEnum.DarkBlue : MyFontEnum.Blue);
if (!RaiseMessageRecieved(torchMsg) && HasHud)
_hudChatMessageReceived.Invoke(MyHud.Chat, steamUserId, messageText, channel, targetId, customAuthorName);
@@ -147,7 +150,9 @@ namespace Torch.Managers.ChatManager
private void Multiplayer_ScriptedChatMessageReceived(string message, string author, string font, Color color)
{
+#pragma warning disable CS0612
var torchMsg = new TorchChatMessage(author, message, font);
+#pragma warning restore CS0612
if (!RaiseMessageRecieved(torchMsg) && HasHud)
_hudChatScriptedMessageReceived.Invoke(MyHud.Chat, author, message, font, color);
}
@@ -165,14 +170,14 @@ namespace Torch.Managers.ChatManager
protected static bool HasHud => !Sandbox.Engine.Platform.Game.IsDedicated;
[ReflectedMethod(Name = _hudChatMessageReceivedName)]
- private static Action _hudChatMessageReceived;
+ private static Action _hudChatMessageReceived = null!;
[ReflectedMethod(Name = _hudChatScriptedMessageReceivedName)]
- private static Action _hudChatScriptedMessageReceived;
+ private static Action _hudChatScriptedMessageReceived = null!;
[ReflectedEventReplace(typeof(MyMultiplayerBase), nameof(MyMultiplayerBase.ChatMessageReceived), typeof(MyHudChat), _hudChatMessageReceivedName)]
- private static Func _chatMessageReceivedFactory;
+ private static Func _chatMessageReceivedFactory = null!;
[ReflectedEventReplace(typeof(MyMultiplayerBase), nameof(MyMultiplayerBase.ScriptedChatMessageReceived), typeof(MyHudChat), _hudChatScriptedMessageReceivedName)]
- private static Func _scriptedChatMessageReceivedFactory;
+ private static Func _scriptedChatMessageReceivedFactory = null!;
private ReflectedEventReplacer _chatMessageRecievedReplacer;
private ReflectedEventReplacer _scriptedChatMessageRecievedReplacer;
diff --git a/Torch/Managers/ChatManager/ChatManagerServer.cs b/Torch/Managers/ChatManager/ChatManagerServer.cs
index 866feaf..bb61234 100644
--- a/Torch/Managers/ChatManager/ChatManagerServer.cs
+++ b/Torch/Managers/ChatManager/ChatManagerServer.cs
@@ -30,7 +30,9 @@ namespace Torch.Managers.ChatManager
{
private static ChatManagerServer _chatManager;
public static event ChatReceivedDel OnChatRecvAccess;
- private static ChatManagerServer ChatManager => _chatManager ?? (_chatManager = TorchBase.Instance.CurrentSession.Managers.GetManager());
+#pragma warning disable CS0618
+ private static ChatManagerServer ChatManager => _chatManager ??= TorchBase.Instance.CurrentSession.Managers.GetManager();
+#pragma warning restore CS0618
internal static void Patch(PatchContext context)
{
@@ -83,7 +85,9 @@ namespace Torch.Managers.ChatManager
{
if (targetSteamId == Sync.MyId)
{
+#pragma warning disable CS0612
RaiseMessageRecieved(new TorchChatMessage(authorId, message, ChatChannel.Global, 0));
+#pragma warning restore CS0612
return;
}
if (MyMultiplayer.Static == null)
@@ -97,7 +101,7 @@ namespace Torch.Managers.ChatManager
{
var msg = new ChatMsg() { Author = authorId, Text = message };
_dedicatedServerBaseSendChatMessage.Invoke(ref msg);
- _dedicatedServerBaseOnChatMessage.Invoke(dedicated, new object[] { msg });
+ _dedicatedServerOnChatMessage.Invoke(dedicated, new object[] { msg });
}
}
@@ -108,15 +112,15 @@ namespace Torch.Managers.ChatManager
private static MultiplayerBaseSendChatMessageDel _dedicatedServerBaseSendChatMessage;
// [ReflectedMethod] doesn't play well with instance methods and refs.
- [ReflectedMethodInfo(typeof(MyDedicatedServerBase), "OnChatMessage")]
- private static MethodInfo _dedicatedServerBaseOnChatMessage;
+ [ReflectedMethodInfo(typeof(MyDedicatedServer), "OnChatMessage")]
+ private static MethodInfo _dedicatedServerOnChatMessage;
#pragma warning restore 649
public void SendMessageAsOther(string author, string message, Color color = default, ulong targetSteamId = 0, string font = MyFontEnum.White)
{
if (targetSteamId == Sync.MyId)
{
- RaiseMessageRecieved(new TorchChatMessage(author, message, font));
+ RaiseMessageRecieved(new TorchChatMessage(author, message, color, font));
return;
}
if (MyMultiplayer.Static == null)
@@ -158,7 +162,9 @@ namespace Torch.Managers.ChatManager
internal void RaiseMessageRecieved(ChatMsg message, ref bool consumed)
{
+#pragma warning disable CS0612
var torchMsg = new TorchChatMessage(GetMemberName(message.Author), message.Author, message.Text, (ChatChannel)message.Channel, message.TargetId);
+#pragma warning restore CS0612
if (_muted.Contains(message.Author))
{
consumed = true;
diff --git a/Torch/Managers/PatchManager/AssemblyMemory.cs b/Torch/Managers/PatchManager/AssemblyMemory.cs
deleted file mode 100644
index 7af2479..0000000
--- a/Torch/Managers/PatchManager/AssemblyMemory.cs
+++ /dev/null
@@ -1,115 +0,0 @@
-using System;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using Torch.Utils;
-
-namespace Torch.Managers.PatchManager
-{
- internal class AssemblyMemory
- {
-#pragma warning disable 649
- [ReflectedMethod(Name = "GetMethodDescriptor")]
- private static Func _getMethodHandle;
-#pragma warning restore 649
-
- ///
- /// Gets the address, in RAM, where the body of a method starts.
- ///
- /// Method to find the start of
- /// Address of the method's start
- public static long GetMethodBodyStart(MethodBase method)
- {
- RuntimeMethodHandle handle;
- if (method is DynamicMethod dyn)
- handle = _getMethodHandle.Invoke(dyn);
- else
- handle = method.MethodHandle;
- RuntimeHelpers.PrepareMethod(handle);
- return handle.GetFunctionPointer().ToInt64();
- }
-
- internal static void UnprotectMemoryPage(long memory) {
- if (NativeLibrary.IsWindows) {
- var succ = NativeLibrary.VirtualProtect(
- new IntPtr(memory), new UIntPtr(1),
- NativeLibrary.Protection.PAGE_EXECUTE_READWRITE, out var _ignored);
-
- if (!succ) {
- throw new System.ComponentModel.Win32Exception();
- }
- }
- }
-
-
- // x64 ISA format:
- // [prefixes] [opcode] [mod-r/m]
- // [mod-r/m] is bitfield:
- // [7-6] = "mod" adressing mode
- // [5-3] = register or opcode extension
- // [2-0] = "r/m" extra addressing mode
-
-
- // http://ref.x86asm.net/coder64.html
- /// Direct register addressing mode. (Jump directly to register)
- private const byte MODRM_MOD_DIRECT = 0b11;
-
- /// Long-mode prefix (64-bit operand)
- private const byte REX_W = 0x48;
-
- /// Moves a 16/32/64 operand into register i when opcode is (MOV_R0+i)
- private const byte MOV_R0 = 0xB8;
-
- // Extra opcodes. Used with opcode extension.
- private const byte EXT = 0xFF;
-
- /// Opcode extension used with for the JMP opcode.
- private const byte OPCODE_EXTENSION_JMP = 4;
-
-
- ///
- /// Reads a byte array from a memory location
- ///
- /// Address to read from
- /// Number of bytes to read
- /// The bytes that were read
- public static byte[] ReadMemory(long memory, int bytes)
- {
- var data = new byte[bytes];
- Marshal.Copy(new IntPtr(memory), data,0, bytes);
- return data;
- }
-
- ///
- /// Writes a byte array to a memory location.
- ///
- /// Address to write to
- /// Data to write
- public static void WriteMemory(long memory, byte[] bytes)
- {
- Marshal.Copy(bytes,0, new IntPtr(memory), bytes.Length);
- }
-
- ///
- /// Writes an x64 assembly jump instruction at the given address.
- ///
- /// Address to write the instruction at
- /// Target address of the jump
- /// The bytes that were overwritten
- public static byte[] WriteJump(long memory, long jumpTarget)
- {
- byte[] result = ReadMemory(memory, 12);
- unsafe
- {
- var ptr = (byte*)memory;
- *ptr = REX_W;
- *(ptr + 1) = MOV_R0;
- *((long*)(ptr + 2)) = jumpTarget;
- *(ptr + 10) = EXT;
- *(ptr + 11) = (MODRM_MOD_DIRECT << 6) | (OPCODE_EXTENSION_JMP << 3) | 0;
- }
- return result;
- }
- }
-}
diff --git a/Torch/Managers/PatchManager/DecoratedMethod.cs b/Torch/Managers/PatchManager/DecoratedMethod.cs
index 018b480..6e3f606 100644
--- a/Torch/Managers/PatchManager/DecoratedMethod.cs
+++ b/Torch/Managers/PatchManager/DecoratedMethod.cs
@@ -8,6 +8,10 @@ using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using MonoMod.Cil;
+using MonoMod.RuntimeDetour;
+using MonoMod.Utils;
+using MonoMod.Utils.Cil;
using NLog;
using Torch.Managers.PatchManager.MSIL;
using Torch.Managers.PatchManager.Transpile;
@@ -17,18 +21,22 @@ namespace Torch.Managers.PatchManager
{
internal class DecoratedMethod : MethodRewritePattern
{
+ private static Action IsAppliedSetter;
+
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
private readonly MethodBase _method;
+ private ILHook _hook;
+
internal DecoratedMethod(MethodBase method) : base(null)
{
_method = method;
+ if (IsAppliedSetter == null)
+ {
+ IsAppliedSetter = typeof(ILHook).GetProperty(nameof(ILHook.IsApplied)).CreateSetter();
+ }
}
- private long _revertAddress;
- private byte[] _revertData = null;
- private GCHandle? _pinnedPatch;
-
internal bool HasChanged()
{
return Prefixes.HasChanges() || Suffixes.HasChanges() || Transpilers.HasChanges() || PostTranspilers.HasChanges();
@@ -47,60 +55,33 @@ namespace Torch.Managers.PatchManager
return;
_log.Log(PrintMode != 0 ? LogLevel.Info : LogLevel.Debug,
$"Begin patching {_method.DeclaringType?.FullName}#{_method.Name}({string.Join(", ", _method.GetParameters().Select(x => x.ParameterType.Name))})");
- var patch = ComposePatchedMethod();
- _revertAddress = AssemblyMemory.GetMethodBodyStart(_method);
- var newAddress = AssemblyMemory.GetMethodBodyStart(patch);
- AssemblyMemory.UnprotectMemoryPage(_revertAddress);
- _revertData = AssemblyMemory.WriteJump(_revertAddress, newAddress);
- _pinnedPatch = GCHandle.Alloc(patch);
+ if (_hook == null)
+ _hook = new ILHook(_method, Manipulator, new ILHookConfig {ManualApply = true});
+ IsAppliedSetter(_hook, false);
+ _hook.Apply();
+
_log.Log(PrintMode != 0 ? LogLevel.Info : LogLevel.Debug,
- $"Done patching {_method.DeclaringType?.FullName}#{_method.Name}({string.Join(", ", _method.GetParameters().Select(x => x.ParameterType.Name))})");
+ $"Done patching {_method.GetID()})");
}
catch (Exception exception)
{
- _log.Fatal(exception, $"Error patching {_method.DeclaringType?.FullName}#{_method}");
+ _log.Fatal(exception, $"Error patching {_method.GetID()}");
throw;
}
}
internal void Revert()
{
- if (_pinnedPatch.HasValue)
- {
- _log.Debug(
- $"Revert {_method.DeclaringType?.FullName}#{_method.Name}({string.Join(", ", _method.GetParameters().Select(x => x.ParameterType.Name))})");
- AssemblyMemory.WriteMemory(_revertAddress, _revertData);
- _revertData = null;
- _pinnedPatch.Value.Free();
- _pinnedPatch = null;
- }
+ if (_hook == null)
+ return;
+ _log.Debug($"Revert {_method.GetID()}");
+ _hook.Dispose();
+ _hook = null;
}
#region Create
- private int _patchSalt = 0;
-
- private DynamicMethod AllocatePatchMethod()
- {
- Debug.Assert(_method.DeclaringType != null);
- var methodName = "Patched_" + _method.DeclaringType.FullName + _method.Name + $"_{_patchSalt++}";
- var returnType = _method is MethodInfo meth ? meth.ReturnType : typeof(void);
- var parameters = _method.GetParameters();
- var parameterTypes = (_method.IsStatic ? Enumerable.Empty() : new[] {typeof(object)})
- .Concat(parameters.Select(x => x.ParameterType)).ToArray();
-
- var patchMethod = new DynamicMethod(methodName, MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard,
- returnType, parameterTypes, _method.DeclaringType, true);
- if (!_method.IsStatic)
- patchMethod.DefineParameter(0, ParameterAttributes.None, INSTANCE_PARAMETER);
- for (var i = 0; i < parameters.Length; i++)
- patchMethod.DefineParameter((patchMethod.IsStatic ? 0 : 1) + i, parameters[i].Attributes, parameters[i].Name);
-
- return patchMethod;
- }
-
-
public const string INSTANCE_PARAMETER = "__instance";
public const string RESULT_PARAMETER = "__result";
public const string PREFIX_SKIPPED_PARAMETER = "__prefixSkipped";
@@ -108,40 +89,41 @@ namespace Torch.Managers.PatchManager
private void SavePatchedMethod(string target)
{
- var asmBuilder =
- AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("SomeName"), AssemblyBuilderAccess.RunAndSave, Path.GetDirectoryName(target));
- var moduleBuilder = asmBuilder.DefineDynamicModule(Path.GetFileNameWithoutExtension(target), Path.GetFileName(target));
- var typeBuilder = moduleBuilder.DefineType("Test", TypeAttributes.Public);
-
-
- var methodName = _method.Name + $"_{_patchSalt}";
- var returnType = _method is MethodInfo meth ? meth.ReturnType : typeof(void);
- var parameters = _method.GetParameters();
- var parameterTypes = (_method.IsStatic ? Enumerable.Empty() : new[] {_method.DeclaringType})
- .Concat(parameters.Select(x => x.ParameterType)).ToArray();
-
- var patchMethod = typeBuilder.DefineMethod(methodName, MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard,
- returnType, parameterTypes);
- if (!_method.IsStatic)
- patchMethod.DefineParameter(0, ParameterAttributes.None, INSTANCE_PARAMETER);
- for (var i = 0; i < parameters.Length; i++)
- patchMethod.DefineParameter((patchMethod.IsStatic ? 0 : 1) + i, parameters[i].Attributes, parameters[i].Name);
-
- var generator = new LoggingIlGenerator(patchMethod.GetILGenerator(), LogLevel.Trace);
- List il = EmitPatched((type, pinned) => new MsilLocal(generator.DeclareLocal(type, pinned))).ToList();
-
- MethodTranspiler.EmitMethod(il, generator);
-
- Type res = typeBuilder.CreateType();
- asmBuilder.Save(Path.GetFileName(target));
- foreach (var method in res.GetMethods(BindingFlags.Public | BindingFlags.Static))
- _log.Info($"Information " + method);
+ throw new NotSupportedException();
+ // var asmBuilder =
+ // AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("SomeName"), AssemblyBuilderAccess.RunAndSave, Path.GetDirectoryName(target));
+ // var moduleBuilder = asmBuilder.DefineDynamicModule(Path.GetFileNameWithoutExtension(target), Path.GetFileName(target));
+ // var typeBuilder = moduleBuilder.DefineType("Test", TypeAttributes.Public);
+ //
+ //
+ // var methodName = _method.Name + $"_{_patchSalt}";
+ // var returnType = _method is MethodInfo meth ? meth.ReturnType : typeof(void);
+ // var parameters = _method.GetParameters();
+ // var parameterTypes = (_method.IsStatic ? Enumerable.Empty() : new[] {_method.DeclaringType})
+ // .Concat(parameters.Select(x => x.ParameterType)).ToArray();
+ //
+ // var patchMethod = typeBuilder.DefineMethod(methodName, MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard,
+ // returnType, parameterTypes);
+ // if (!_method.IsStatic)
+ // patchMethod.DefineParameter(0, ParameterAttributes.None, INSTANCE_PARAMETER);
+ // for (var i = 0; i < parameters.Length; i++)
+ // patchMethod.DefineParameter((patchMethod.IsStatic ? 0 : 1) + i, parameters[i].Attributes, parameters[i].Name);
+ //
+ // var generator = new LoggingIlGenerator(patchMethod.GetILGenerator(), LogLevel.Trace);
+ // List il = EmitPatched((type, pinned) => new MsilLocal(generator.DeclareLocal(type, pinned))).ToList();
+ //
+ // MethodTranspiler.EmitMethod(il, generator);
+ //
+ // Type res = typeBuilder.CreateType();
+ // asmBuilder.Save(Path.GetFileName(target));
+ // foreach (var method in res.GetMethods(BindingFlags.Public | BindingFlags.Static))
+ // _log.Info($"Information " + method);
}
- public DynamicMethod ComposePatchedMethod()
+ public void Manipulator(ILContext context)
{
- DynamicMethod method = AllocatePatchMethod();
- var generator = new LoggingIlGenerator(method.GetILGenerator(),
+ context.IL.Clear();
+ var generator = new LoggingIlGenerator(new CecilILGenerator(context.IL),
PrintMode.HasFlag(PrintModeEnum.EmittedReflection) ? LogLevel.Info : LogLevel.Trace);
List il = EmitPatched((type, pinned) => new MsilLocal(generator.DeclareLocal(type, pinned))).ToList();
@@ -161,7 +143,9 @@ namespace Torch.Managers.PatchManager
_log.Info(msg);
}
+#pragma warning disable CS0612
if (PrintMsil || DumpTarget != null)
+#pragma warning restore CS0612
{
lock (_log)
{
@@ -181,31 +165,16 @@ namespace Torch.Managers.PatchManager
MethodTranspiler.EmitMethod(il, generator);
- try
- {
- PatchUtilities.Compile(method);
- }
- catch (Exception failure)
- {
- lock (_log)
- {
- _log.Error(failure, $"Failed to patch method {_method}");
- var ctx = new MethodContext(method);
- ctx.Read();
- MethodTranspiler.IntegrityAnalysis((err, msg) => _log.Warn(msg), ctx.Instructions);
- LogManager.Flush();
- }
- throw;
- }
-
+#pragma warning disable CS0612
if (PrintMsil || DumpTarget != null)
+#pragma warning restore CS0612
{
lock (_log)
{
- var ctx = new MethodContext(method);
- ctx.Read();
+ var instructions = context.Body.Instructions
+ .Select(b => new MsilInstruction(b)).ToList();
LogTarget(PrintModeEnum.Patched, false, "========== Patched method ==========");
- MethodTranspiler.IntegrityAnalysis((a, b) => LogTarget(PrintModeEnum.Patched, a, b), ctx.Instructions, true);
+ MethodTranspiler.IntegrityAnalysis((a, b) => LogTarget(PrintModeEnum.Patched, a, b), instructions, true);
LogTarget(PrintModeEnum.Patched, false, gap);
}
}
@@ -214,8 +183,6 @@ namespace Torch.Managers.PatchManager
{
dumpTarget?.Close();
}
-
- return method;
}
#endregion
@@ -284,8 +251,8 @@ namespace Torch.Managers.PatchManager
if (prefix.ReturnType == typeof(bool))
instructions.Add(new MsilInstruction(OpCodes.Brfalse).InlineTarget(labelSkipMethodContent));
else if (prefix.ReturnType != typeof(void))
- throw new Exception(
- $"Prefixes must return void or bool. {prefix.DeclaringType?.FullName}.{prefix.Name} returns {prefix.ReturnType}");
+ throw new PatchException(
+ $"Prefixes must return void or bool. {prefix.DeclaringType?.FullName}.{prefix.Name} returns {prefix.ReturnType}", prefix);
}
instructions.AddRange(MethodTranspiler.Transpile(_method, (x) => declareLocal(x, false), Transpilers, labelAfterOriginalContent));
@@ -308,7 +275,7 @@ namespace Torch.Managers.PatchManager
{
instructions.AddRange(EmitMonkeyCall(suffix, specialVariables));
if (suffix.ReturnType != typeof(void))
- throw new Exception($"Suffixes must return void. {suffix.DeclaringType?.FullName}.{suffix.Name} returns {suffix.ReturnType}");
+ throw new PatchException($"Suffixes must return void. {suffix.DeclaringType?.FullName}.{suffix.Name} returns {suffix.ReturnType}", suffix);
}
if (resultVariable != null)
@@ -331,16 +298,16 @@ namespace Torch.Managers.PatchManager
case INSTANCE_PARAMETER:
{
if (_method.IsStatic)
- throw new Exception("Can't use an instance parameter for a static method");
+ throw new PatchException("Can't use an instance parameter for a static method", _method);
yield return new MsilInstruction(OpCodes.Ldarg_0);
break;
}
case PREFIX_SKIPPED_PARAMETER:
{
if (param.ParameterType != typeof(bool))
- throw new Exception($"Prefix skipped parameter {param.ParameterType} must be of type bool");
+ throw new PatchException($"Prefix skipped parameter {param.ParameterType} must be of type bool", _method);
if (param.ParameterType.IsByRef || param.IsOut)
- throw new Exception($"Prefix skipped parameter {param.ParameterType} can't be a reference type");
+ throw new PatchException($"Prefix skipped parameter {param.ParameterType} can't be a reference type", _method);
if (specialVariables.TryGetValue(PREFIX_SKIPPED_PARAMETER, out MsilLocal prefixSkip))
yield return new MsilInstruction(OpCodes.Ldloc).InlineValue(prefixSkip);
else
@@ -353,8 +320,8 @@ namespace Torch.Managers.PatchManager
? param.ParameterType.GetElementType()
: param.ParameterType;
if (retType == null || !retType.IsAssignableFrom(specialVariables[RESULT_PARAMETER].Type))
- throw new Exception(
- $"Return type {specialVariables[RESULT_PARAMETER].Type} can't be assigned to result parameter type {retType}");
+ throw new PatchException(
+ $"Return type {specialVariables[RESULT_PARAMETER].Type} can't be assigned to result parameter type {retType}", _method);
yield return new MsilInstruction(param.ParameterType.IsByRef ? OpCodes.Ldloca : OpCodes.Ldloc)
.InlineValue(specialVariables[RESULT_PARAMETER]);
break;
@@ -372,7 +339,7 @@ namespace Torch.Managers.PatchManager
{
var fieldName = param.Name.Substring(8);
var fieldDef = _method.DeclaringType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static).FirstOrDefault(x => x.Name == fieldName);
- if (fieldDef == null) throw new Exception($"Could not find field {fieldName}");
+ if (fieldDef == null) throw new PatchException($"Could not find field {fieldName}", _method);
if (fieldDef.IsStatic)
yield return new MsilInstruction(param.ParameterType.IsByRef ? OpCodes.Ldsflda : OpCodes.Ldsfld)
.InlineValue(fieldDef);
@@ -388,7 +355,7 @@ namespace Torch.Managers.PatchManager
ParameterInfo declParam = _method.GetParameters().FirstOrDefault(x => x.Name == param.Name);
if (declParam == null)
- throw new Exception($"Parameter name {param.Name} not found");
+ throw new PatchException($"Parameter name {param.Name} not found", _method);
int paramIdx = (_method.IsStatic ? 0 : 1) + declParam.Position;
bool patchByRef = param.IsOut || param.ParameterType.IsByRef;
diff --git a/Torch/Managers/PatchManager/MSIL/MsilInstruction.cs b/Torch/Managers/PatchManager/MSIL/MsilInstruction.cs
index 96bec5d..59d3723 100644
--- a/Torch/Managers/PatchManager/MSIL/MsilInstruction.cs
+++ b/Torch/Managers/PatchManager/MSIL/MsilInstruction.cs
@@ -7,8 +7,14 @@ using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Windows.Documents;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using MonoMod.Utils;
using Torch.Managers.PatchManager.Transpile;
using Torch.Utils;
+using OpCode = System.Reflection.Emit.OpCode;
+using OpCodes = System.Reflection.Emit.OpCodes;
+using OperandType = System.Reflection.Emit.OperandType;
namespace Torch.Managers.PatchManager.MSIL
{
@@ -81,6 +87,132 @@ namespace Torch.Managers.PatchManager.MSIL
throw new ArgumentOutOfRangeException();
}
}
+
+ public MsilInstruction(Instruction instruction)
+ {
+ Label CreateLabel(int pos)
+ {
+ var instance = Activator.CreateInstance(typeof(Label),
+ BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.NonPublic, null,
+ new object[] {pos}, null);
+ if (instance == null)
+ return default;
+ return (Label) instance;
+ }
+
+ if (!MethodContext.OpCodeLookup.TryGetValue(instruction.OpCode.Value, out var opCode))
+ return;
+ OpCode = opCode;
+
+ var opType = opCode.OperandType;
+ if (opType == OperandType.InlineNone)
+ {
+ Operand = null;
+ return;
+ }
+ switch (instruction.Operand)
+ {
+ case OperandType.InlineNone:
+ break;
+ case Instruction targetInstruction when opType == OperandType.InlineBrTarget || opType == OperandType.ShortInlineBrTarget:
+ Operand = new MsilOperandBrTarget(this)
+ {
+ Target = new MsilLabel(CreateLabel(targetInstruction.Offset))
+ };
+ break;
+ case FieldReference reference when opType == OperandType.InlineField:
+ Operand = new MsilOperandInline.MsilOperandReflected(this)
+ {
+ Value = reference.ResolveReflection()
+ };
+ break;
+ case int int32 when opType == OperandType.InlineI || opType == OperandType.ShortInlineI:
+ Operand = new MsilOperandInline.MsilOperandInt32(this)
+ {
+ Value = int32
+ };
+ break;
+ case long int64 when opType == OperandType.InlineI8:
+ Operand = new MsilOperandInline.MsilOperandInt64(this)
+ {
+ Value = int64
+ };
+ break;
+ case MethodReference methodReference when opType == OperandType.InlineMethod:
+ Operand = new MsilOperandInline.MsilOperandReflected(this)
+ {
+ Value = methodReference.ResolveReflection()
+ };
+ break;
+ case double @double when opType == OperandType.InlineR:
+ Operand = new MsilOperandInline.MsilOperandDouble(this)
+ {
+ Value = @double
+ };
+ break;
+ case null when opType == OperandType.InlineSig:
+ throw new NotSupportedException("InlineSignature is not supported by instruction converter");
+ case string @string when opType == OperandType.InlineString:
+ Operand = new MsilOperandInline.MsilOperandString(this)
+ {
+ Value = @string
+ };
+ break;
+ case Instruction[] targetInstructions when opType == OperandType.InlineSwitch:
+ Operand = new MsilOperandSwitch(this)
+ {
+ Labels = targetInstructions.Select(b => new MsilLabel(CreateLabel(b.Offset))).ToArray()
+ };
+ break;
+ case MemberReference memberReference when opType == OperandType.InlineTok:
+ Operand = new MsilOperandInline.MsilOperandReflected(this)
+ {
+ Value = memberReference.ResolveReflection()
+ };
+ break;
+ case TypeReference typeReference when opType == OperandType.InlineType:
+ Operand = new MsilOperandInline.MsilOperandReflected(this)
+ {
+ Value = typeReference.ResolveReflection()
+ };
+ break;
+ case VariableDefinition variableDefinition when opType == OperandType.InlineVar || opType == OperandType.ShortInlineVar:
+ if (OpCode.IsLocalStore() || OpCode.IsLocalLoad() || OpCode.IsLocalLoadByRef())
+ Operand = new MsilOperandInline.MsilOperandLocal(this)
+ {
+ Value = new MsilLocal(variableDefinition.Index)
+ };
+ else
+ Operand = new MsilOperandInline.MsilOperandArgument(this)
+ {
+ Value = new MsilArgument(variableDefinition.Index)
+ };
+ break;
+ case ParameterDefinition parameterDefinition when opType == OperandType.InlineVar || opType == OperandType.ShortInlineVar:
+ if (OpCode.IsLocalStore() || OpCode.IsLocalLoad() || OpCode.IsLocalLoadByRef())
+ Operand = new MsilOperandInline.MsilOperandLocal(this)
+ {
+ Value = new MsilLocal(parameterDefinition.Index)
+ };
+ else
+ Operand = new MsilOperandInline.MsilOperandArgument(this)
+ {
+ Value = new MsilArgument(parameterDefinition.Index)
+ };
+ break;
+ case float @float when opType == OperandType.ShortInlineR:
+ Operand = new MsilOperandInline.MsilOperandSingle(this)
+ {
+ Value = @float
+ };
+ break;
+#pragma warning disable 618
+ case null when opType == OperandType.InlinePhi:
+#pragma warning restore 618
+ default:
+ throw new ArgumentOutOfRangeException(nameof(instruction.Operand), instruction.Operand, "Invalid operand type");
+ }
+ }
///
/// Opcode of this instruction
diff --git a/Torch/Managers/PatchManager/MSIL/MsilOperandInline.cs b/Torch/Managers/PatchManager/MSIL/MsilOperandInline.cs
index 5709cc4..9a13d67 100644
--- a/Torch/Managers/PatchManager/MSIL/MsilOperandInline.cs
+++ b/Torch/Managers/PatchManager/MSIL/MsilOperandInline.cs
@@ -79,7 +79,10 @@ namespace Torch.Managers.PatchManager.MSIL
switch (Instruction.OpCode.OperandType)
{
case OperandType.ShortInlineI:
- generator.Emit(Instruction.OpCode, (byte)Value);
+ if (Instruction.OpCode == OpCodes.Ldc_I4_S)
+ generator.Emit(Instruction.OpCode, Value);
+ else
+ generator.Emit(Instruction.OpCode);
return;
case OperandType.InlineI:
generator.Emit(Instruction.OpCode, Value);
diff --git a/Torch/Managers/PatchManager/NativeLibrary.cs b/Torch/Managers/PatchManager/NativeLibrary.cs
deleted file mode 100644
index 6df98d0..0000000
--- a/Torch/Managers/PatchManager/NativeLibrary.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Torch.Managers.PatchManager {
- internal static class NativeLibrary {
- private static readonly HashSet WindowsPlatformIDSet = new HashSet
- {
- PlatformID.Win32NT, PlatformID.Win32S, PlatformID.Win32Windows, PlatformID.WinCE
- };
-
- public static bool IsWindows {
- get {
- return WindowsPlatformIDSet.Contains(Environment.OSVersion.Platform);
- }
- }
-
- [Flags]
- public enum Protection {
- PAGE_NOACCESS = 0x01,
- PAGE_READONLY = 0x02,
- PAGE_READWRITE = 0x04,
- PAGE_WRITECOPY = 0x08,
- PAGE_EXECUTE = 0x10,
- PAGE_EXECUTE_READ = 0x20,
- PAGE_EXECUTE_READWRITE = 0x40,
- PAGE_EXECUTE_WRITECOPY = 0x80,
- PAGE_GUARD = 0x100,
- PAGE_NOCACHE = 0x200,
- PAGE_WRITECOMBINE = 0x400
- }
-
- [DllImport("kernel32.dll")]
- public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize,
- Protection flNewProtect, out Protection lpflOldProtect);
- }
-}
diff --git a/Torch/Managers/PatchManager/PatchException.cs b/Torch/Managers/PatchManager/PatchException.cs
new file mode 100644
index 0000000..b4333be
--- /dev/null
+++ b/Torch/Managers/PatchManager/PatchException.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Reflection;
+
+namespace Torch.Managers.PatchManager
+{
+ public class PatchException : Exception
+ {
+ public PatchException(string message, MemberInfo targetMember) : base(
+ $"Patching exception in {targetMember.DeclaringType?.FullName}::{targetMember.Name}: {message}")
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/Torch/Managers/PatchManager/PatchUtilities.cs b/Torch/Managers/PatchManager/PatchUtilities.cs
index 50e9f0e..10cc4b0 100644
--- a/Torch/Managers/PatchManager/PatchUtilities.cs
+++ b/Torch/Managers/PatchManager/PatchUtilities.cs
@@ -53,25 +53,27 @@ namespace Torch.Managers.PatchManager
}
#pragma warning disable 649
- [ReflectedStaticMethod(Type = typeof(RuntimeHelpers), Name = "_CompileMethod", OverrideTypeNames = new[] {"System.IRuntimeMethodInfo"})]
- private static Action
public class UpdateManager : Manager
{
- private Timer _updatePollTimer;
+ private readonly Timer _updatePollTimer;
private string _torchDir = new FileInfo(typeof(UpdateManager).Assembly.Location).DirectoryName;
private Logger _log = LogManager.GetCurrentClassLogger();
[Dependency]
- private FilesystemManager _fsManager;
+ private FilesystemManager _fsManager = null!;
public UpdateManager(ITorchBase torchInstance) : base(torchInstance)
{
+ _updatePollTimer = null;
//_updatePollTimer = new Timer(TimerElapsed, this, TimeSpan.Zero, TimeSpan.FromMinutes(5));
}
diff --git a/Torch/Patches/GameStatePatchShim.cs b/Torch/Patches/GameStatePatchShim.cs
index f939189..3505cab 100644
--- a/Torch/Patches/GameStatePatchShim.cs
+++ b/Torch/Patches/GameStatePatchShim.cs
@@ -4,6 +4,7 @@ using Sandbox;
using Torch.API;
using Torch.Managers.PatchManager;
using Torch.Utils;
+#pragma warning disable CS0618
namespace Torch.Patches
{
diff --git a/Torch/Patches/KeenLogPatch.cs b/Torch/Patches/KeenLogPatch.cs
index f47aae4..13bff83 100644
--- a/Torch/Patches/KeenLogPatch.cs
+++ b/Torch/Patches/KeenLogPatch.cs
@@ -67,28 +67,17 @@ namespace Torch.Patches
}
[ReflectedMethod(Name = "GetIdentByThread")]
- private static Func _getIndentByThread;
+ private static Func GetIndentByThread = null!;
[ThreadStatic]
private static StringBuilder _tmpStringBuilder;
private static StringBuilder PrepareLog(MyLog log)
{
- if (_tmpStringBuilder == null)
- _tmpStringBuilder = new StringBuilder();
+ _tmpStringBuilder ??= new();
_tmpStringBuilder.Clear();
- var i = Thread.CurrentThread.ManagedThreadId;
- int t = 0;
-
- try
- {
- t = _getIndentByThread(log, i);
- }
- catch (Exception e)
- {
- _log.Debug(e, "Failed to get thread indent");
- }
+ var t = GetIndentByThread(log, Environment.CurrentManagedThreadId);
_tmpStringBuilder.Append(' ', t * 3);
return _tmpStringBuilder;
@@ -96,24 +85,27 @@ namespace Torch.Patches
private static bool PrefixWriteLine(MyLog __instance, string msg)
{
- _log.Debug(PrepareLog(__instance).Append(msg));
+ if (__instance.LogEnabled)
+ _log.Debug(PrepareLog(__instance).Append(msg));
return false;
}
private static bool PrefixWriteLineConsole(MyLog __instance, string msg)
{
- _log.Info(PrepareLog(__instance).Append(msg));
+ if (__instance.LogEnabled)
+ _log.Info(PrepareLog(__instance).Append(msg));
return false;
}
private static bool PrefixAppendToClosedLog(MyLog __instance, string text)
{
- _log.Info(PrepareLog(__instance).Append(text));
+ if (__instance.LogEnabled)
+ _log.Info(PrepareLog(__instance).Append(text));
return false;
}
private static bool PrefixWriteLineOptions(MyLog __instance, string message, LoggingOptions option)
{
- if (__instance.LogFlag(option))
+ if (__instance.LogEnabled && __instance.LogFlag(option))
_log.Info(PrepareLog(__instance).Append(message));
return false;
}
@@ -132,10 +124,12 @@ namespace Torch.Patches
private static bool PrefixLogFormatted(MyLog __instance, MyLogSeverity severity, string format, object[] args)
{
+ if (__instance.LogEnabled)
+ return false;
// Sometimes this is called with a pre-formatted string and no args
// and causes a crash when the format string contains braces
var sb = PrepareLog(__instance);
- if (args != null && args.Length > 0)
+ if (args is {Length: > 0})
sb.AppendFormat(format, args);
else
sb.Append(format);
@@ -146,27 +140,22 @@ namespace Torch.Patches
private static bool PrefixLogStringBuilder(MyLog __instance, MyLogSeverity severity, StringBuilder builder)
{
- _log.Log(LogLevelFor(severity), PrepareLog(__instance).Append(builder));
+ if (__instance.LogEnabled)
+ _log.Log(LogLevelFor(severity), PrepareLog(__instance).Append(builder));
return false;
}
private static LogLevel LogLevelFor(MyLogSeverity severity)
{
- switch (severity)
+ return severity switch
{
- case MyLogSeverity.Debug:
- return LogLevel.Debug;
- case MyLogSeverity.Info:
- return LogLevel.Info;
- case MyLogSeverity.Warning:
- return LogLevel.Warn;
- case MyLogSeverity.Error:
- return LogLevel.Error;
- case MyLogSeverity.Critical:
- return LogLevel.Fatal;
- default:
- return LogLevel.Info;
- }
+ MyLogSeverity.Debug => LogLevel.Debug,
+ MyLogSeverity.Info => LogLevel.Info,
+ MyLogSeverity.Warning => LogLevel.Warn,
+ MyLogSeverity.Error => LogLevel.Error,
+ MyLogSeverity.Critical => LogLevel.Fatal,
+ _ => LogLevel.Info
+ };
}
}
-}
+}
\ No newline at end of file
diff --git a/Torch/Patches/ModsDownloadingPatch.cs b/Torch/Patches/ModsDownloadingPatch.cs
index d871013..cb60e2f 100644
--- a/Torch/Patches/ModsDownloadingPatch.cs
+++ b/Torch/Patches/ModsDownloadingPatch.cs
@@ -19,7 +19,7 @@ namespace Torch.Patches
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
#pragma warning disable 649
[ReflectedMethodInfo(typeof(MyWorkshop), nameof(MyWorkshop.DownloadWorldModsBlocking))]
- private readonly static MethodInfo _downloadWorldModsBlockingMethod;
+ private static MethodInfo _downloadWorldModsBlockingMethod;
#pragma warning restore 649
public static void Patch(PatchContext ctx)
@@ -29,11 +29,15 @@ namespace Torch.Patches
ctx.GetPattern(_downloadWorldModsBlockingMethod).Suffixes
.Add(typeof(ModsDownloadingPatch).GetMethod(nameof(Postfix)));
}
- public static void Postfix(MyWorkshop.ResultData __result)
+ public static void Postfix(MyWorkshop.ResultData __result, List mods)
{
if (__result.Success) return;
_log.Warn("Missing Mods:");
- __result.MismatchMods?.ForEach(b => _log.Info($"\t{b}"));
+ var mismatchMods = mods.Where(b => __result.Mods.All(c => b.PublishedFileId != c.Id));
+ foreach (var mod in mismatchMods)
+ {
+ _log.Warn($"\t{mod.PublishedFileId} : {mod.FriendlyName}");
+ }
}
}
}
\ No newline at end of file
diff --git a/Torch/Patches/ObjectFactoryInitPatch.cs b/Torch/Patches/ObjectFactoryInitPatch.cs
index c680edd..bb38b3d 100644
--- a/Torch/Patches/ObjectFactoryInitPatch.cs
+++ b/Torch/Patches/ObjectFactoryInitPatch.cs
@@ -26,7 +26,7 @@ namespace Torch.Patches
{
#pragma warning disable 649
[ReflectedGetter(Name = "m_objectFactory", TypeName = "Sandbox.Game.Entities.MyEntityFactory, Sandbox.Game")]
- private static readonly Func> _entityFactoryObjectFactory;
+ private static Func> EntityFactoryObjectFactory;
#pragma warning restore 649
internal static void ForceRegisterAssemblies()
@@ -35,7 +35,7 @@ namespace Torch.Patches
// static MyEntities() called by MySandboxGame.ForceStaticCtor
RuntimeHelpers.RunClassConstructor(typeof(MyEntities).TypeHandle);
{
- MyObjectFactory factory = _entityFactoryObjectFactory();
+ MyObjectFactory factory = EntityFactoryObjectFactory();
ObjectFactory_RegisterFromAssemblySafe(factory, typeof(MySandboxGame).Assembly); // calling assembly
ObjectFactory_RegisterFromAssemblySafe(factory, MyPlugins.GameAssembly);
ObjectFactory_RegisterFromAssemblySafe(factory, MyPlugins.SandboxAssembly);
@@ -105,11 +105,11 @@ namespace Torch.Patches
#region MyComponentTypeFactory Adders
[ReflectedGetter(Name = "m_idToType", Type = typeof(MyComponentTypeFactory))]
- private static Func> _componentTypeFactoryIdToType;
+ private static Func> ComponentTypeFactoryIdToType = null!;
[ReflectedGetter(Name = "m_typeToId", Type = typeof(MyComponentTypeFactory))]
- private static Func> _componentTypeFactoryTypeToId;
+ private static Func> ComponentTypeFactoryTypeToId = null!;
[ReflectedGetter(Name = "m_typeToContainerComponentType", Type = typeof(MyComponentTypeFactory))]
- private static Func> _componentTypeFactoryContainerComponentType;
+ private static Func> ComponentTypeFactoryContainerComponentType = null!;
private static void ComponentTypeFactory_RegisterFromAssemblySafe(Assembly assembly)
{
@@ -127,13 +127,13 @@ namespace Torch.Patches
{
Type componentType = type.GetCustomAttribute(true)?.ComponentType;
if (componentType != null)
- _componentTypeFactoryContainerComponentType()[type] = componentType;
+ ComponentTypeFactoryContainerComponentType()[type] = componentType;
}
private static void ComponentTypeFactory_AddIdSafe(Type type, MyStringId id)
{
- _componentTypeFactoryIdToType()[id] = type;
- _componentTypeFactoryTypeToId()[type] = id;
+ ComponentTypeFactoryIdToType()[id] = type;
+ ComponentTypeFactoryTypeToId()[type] = id;
}
#endregion
}
diff --git a/Torch/Patches/PhysicsMemoryPatch.cs b/Torch/Patches/PhysicsMemoryPatch.cs
index bf94ad9..da5efee 100644
--- a/Torch/Patches/PhysicsMemoryPatch.cs
+++ b/Torch/Patches/PhysicsMemoryPatch.cs
@@ -43,10 +43,12 @@ namespace Torch.Patches
//nasty hack
Task.Run(() =>
- {
- Thread.Sleep(TimeSpan.FromSeconds(30));
- TorchBase.Instance.Restart();
- });
+ {
+ Thread.Sleep(TimeSpan.FromSeconds(30));
+#pragma warning disable CS0618
+ TorchBase.Instance.Restart();
+#pragma warning restore CS0618
+ });
return false;
}
diff --git a/Torch/Patches/ScriptCompilerPatch.cs b/Torch/Patches/ScriptCompilerPatch.cs
new file mode 100644
index 0000000..a58a330
--- /dev/null
+++ b/Torch/Patches/ScriptCompilerPatch.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Text.RegularExpressions;
+using System.Threading;
+using Microsoft.CodeAnalysis;
+using ProtoBuf;
+using Torch.Managers.PatchManager;
+using Torch.Managers.PatchManager.MSIL;
+using Torch.Utils;
+using VRage.FileSystem;
+using VRage.Scripting;
+
+namespace Torch.Patches
+{
+ [PatchShim]
+ public static class ScriptCompilerPatch
+ {
+ [ReflectedMethodInfo(typeof(MyScriptWhitelist), "Register", Parameters = new[] {typeof(MyWhitelistTarget), typeof(INamespaceSymbol), typeof(Type)})]
+ private static MethodInfo Register1Method = null!;
+
+ [ReflectedMethodInfo(typeof(MyScriptWhitelist), "Register", Parameters = new[] {typeof(MyWhitelistTarget), typeof(ITypeSymbol), typeof(Type)})]
+ private static MethodInfo Register2Method = null!;
+
+ public static void Patch(PatchContext context)
+ {
+ context.GetPattern(typeof(MyScriptWhitelist).GetConstructor(new[] {typeof(MyScriptCompiler)}))
+ .AddPrefix(nameof(WhitelistCtorPrefix));
+ context.GetPattern(Type.GetType("VRage.Scripting.MyVRageScriptingInternal, VRage.Scripting", true).GetMethod("Initialize"))
+ .AddPrefix(nameof(InitializePrefix));
+ context.GetPattern(typeof(MyScriptWhitelist).GetNestedType("MyWhitelistBatch", BindingFlags.NonPublic)!
+ .GetMethod("AllowMembers")).AddPrefix(nameof(AllowMembersPrefix));
+ context.GetPattern(Register1Method).AddTranspiler(nameof(RegisterTranspiler));
+ context.GetPattern(Register2Method).AddTranspiler(nameof(RegisterTranspiler));
+ }
+
+ private static void WhitelistCtorPrefix(MyScriptCompiler scriptCompiler)
+ {
+ scriptCompiler.AddReferencedAssemblies(
+ typeof(Regex).Assembly.Location,
+ typeof(Enumerable).Assembly.Location,
+ typeof(ConcurrentBag<>).Assembly.Location,
+ typeof(ImmutableArray).Assembly.Location,
+ typeof(System.ComponentModel.TypeConverter).Assembly.Location,
+ typeof(System.Diagnostics.TraceSource).Assembly.Location,
+ typeof(ProtoBuf.Meta.RuntimeTypeModel).Assembly.Location,
+ Path.Combine(MyFileSystem.ExePath, "Sandbox.Game.dll"),
+ Path.Combine(MyFileSystem.ExePath, "Sandbox.Common.dll"),
+ Path.Combine(MyFileSystem.ExePath, "Sandbox.Graphics.dll"),
+ Path.Combine(MyFileSystem.ExePath, "VRage.dll"),
+ Path.Combine(MyFileSystem.ExePath, "VRage.Library.dll"),
+ Path.Combine(MyFileSystem.ExePath, "VRage.Math.dll"),
+ Path.Combine(MyFileSystem.ExePath, "VRage.Game.dll"),
+ Path.Combine(MyFileSystem.ExePath, "VRage.Render.dll"),
+ Path.Combine(MyFileSystem.ExePath, "VRage.Input.dll"),
+ Path.Combine(MyFileSystem.ExePath, "SpaceEngineers.ObjectBuilders.dll"),
+ Path.Combine(MyFileSystem.ExePath, "SpaceEngineers.Game.dll"));
+ }
+
+ private static bool InitializePrefix(Thread updateThread, Type[] referencedTypes, string[] symbols)
+ {
+ MyModWatchdog.Init(updateThread);
+ MyScriptCompiler.Static.AddImplicitIngameNamespacesFromTypes(referencedTypes);
+ MyScriptCompiler.Static.AddConditionalCompilationSymbols(symbols);
+ return false;
+ }
+
+ [SuppressMessage("ReSharper", "ConditionIsAlwaysTrueOrFalse")]
+ private static void AllowMembersPrefix(ref MemberInfo[] members)
+ {
+ if (members.Any(b => b is null))
+ members = members.Where(b => b is { }).ToArray();
+ }
+
+ private static IEnumerable RegisterTranspiler(IEnumerable instructions)
+ {
+ var ins = instructions.ToList();
+ var throwIns = ins.FindAll(b => b.OpCode == OpCodes.Throw).Select(b => ins.IndexOf(b));
+ foreach (var index in throwIns)
+ {
+ var i = index;
+ do
+ {
+ ins[i] = new(OpCodes.Nop);
+ } while (ins[--i].OpCode.OperandType != OperandType.ShortInlineBrTarget);
+
+ ins[index] = new(OpCodes.Ret);
+ }
+
+ return ins;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Torch/Patches/SessionDownloadPatch.cs b/Torch/Patches/SessionDownloadPatch.cs
index d739bcd..418de8a 100644
--- a/Torch/Patches/SessionDownloadPatch.cs
+++ b/Torch/Patches/SessionDownloadPatch.cs
@@ -19,7 +19,9 @@ namespace Torch.Patches
internal static class SessionDownloadPatch
{
private static ITorchSessionManager _sessionManager;
- private static ITorchSessionManager SessionManager => _sessionManager ?? (_sessionManager = TorchBase.Instance.Managers.GetManager());
+#pragma warning disable CS0618
+ private static ITorchSessionManager SessionManager => _sessionManager ??= TorchBase.Instance.Managers.GetManager();
+#pragma warning restore CS0618
internal static void Patch(PatchContext context)
diff --git a/Torch/Patches/XmlRootWriterPatch.cs b/Torch/Patches/XmlRootWriterPatch.cs
new file mode 100644
index 0000000..5b04152
--- /dev/null
+++ b/Torch/Patches/XmlRootWriterPatch.cs
@@ -0,0 +1,45 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Xml;
+using Torch.Managers.PatchManager;
+using Torch.Managers.PatchManager.MSIL;
+using Torch.Utils;
+using VRage;
+
+namespace Torch.Patches;
+
+internal static class XmlRootWriterPatch
+{
+ [ReflectedMethodInfo(typeof(CustomRootWriter), "Init")]
+ private static MethodInfo InitMethod = null!;
+
+ public static void Patch(PatchContext context)
+ {
+ context.GetPattern(InitMethod).AddTranspiler();
+ }
+
+ private static IEnumerable Transpiler(IEnumerable instructions)
+ {
+ var ins = instructions.ToList();
+ var index = ins.FindIndex(b =>
+ b.OpCode == OpCodes.Ldstr && b.Operand is MsilOperandInline.MsilOperandString {Value: "xsi:type"});
+ ((MsilOperandInline.MsilOperandString)ins[index].Operand).Value = "xsi";
+ ins.InsertRange(index + 1, new[]
+ {
+ new MsilInstruction(OpCodes.Ldstr).InlineValue("type"),
+ new MsilInstruction(OpCodes.Ldstr).InlineValue("http://www.w3.org/2001/XMLSchema-instance")
+ });
+ var instruction = ins[ins.FindIndex(b => b.OpCode == OpCodes.Callvirt)];
+ instruction.InlineValue(typeof(XmlWriter).GetMethod(
+ "WriteAttributeString", new[]
+ {
+ typeof(string),
+ typeof(string),
+ typeof(string),
+ typeof(string)
+ }));
+ return ins;
+ }
+}
\ No newline at end of file
diff --git a/Torch/Plugins/AssemblyRewriter.cs b/Torch/Plugins/AssemblyRewriter.cs
new file mode 100644
index 0000000..27f104b
--- /dev/null
+++ b/Torch/Plugins/AssemblyRewriter.cs
@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using Mono.Cecil;
+
+namespace Torch.Plugins;
+
+internal static class AssemblyRewriter
+{
+ public static Assembly ProcessWeavers(this Stream stream)
+ {
+ using var assStream = new MemoryStream();
+ stream.CopyTo(assStream);
+ assStream.Position = 0;
+ using var module = ModuleDefinition.ReadModule(assStream);
+ foreach (var fieldDefinition in FindAllToRewrite(module))
+ {
+ fieldDefinition.IsInitOnly = false;
+ }
+
+ using var memStream = new MemoryStream();
+ module.Assembly.Write(memStream);
+ return Assembly.Load(memStream.ToArray());
+ }
+
+ private static IEnumerable FindAllToRewrite(ModuleDefinition definition)
+ {
+ return definition.Types.SelectMany(b => b.Fields.Where(HasValidAttributes));
+ }
+
+ private static bool HasValidAttributes(FieldDefinition definition) =>
+ definition.CustomAttributes.Any(b => b.AttributeType.Name.Contains("Reflected") || b.AttributeType.Name == "DependencyAttribute");
+}
\ No newline at end of file
diff --git a/Torch/Plugins/PluginManager.cs b/Torch/Plugins/PluginManager.cs
index 1267d10..e53c18a 100644
--- a/Torch/Plugins/PluginManager.cs
+++ b/Torch/Plugins/PluginManager.cs
@@ -18,6 +18,7 @@ using Torch.API.Session;
using Torch.API.WebAPI;
using Torch.Collections;
using Torch.Commands;
+using Torch.Plugins;
using Torch.Utils;
namespace Torch.Managers
@@ -331,43 +332,21 @@ namespace Torch.Managers
private void LoadPlugin(PluginItem item)
{
var assemblies = new List();
-
- var loaded = AppDomain.CurrentDomain.GetAssemblies();
if (item.IsZip)
{
- using (var zipFile = ZipFile.OpenRead(item.Path))
+ using var zipFile = ZipFile.OpenRead(item.Path);
+ foreach (var entry in zipFile.Entries)
{
- foreach (var entry in zipFile.Entries)
- {
- if (!entry.Name.EndsWith(".dll", StringComparison.CurrentCultureIgnoreCase))
- continue;
+ if (!entry.Name.EndsWith(".dll", StringComparison.CurrentCultureIgnoreCase))
+ continue;
- //if (loaded.Any(a => entry.Name.Contains(a.GetName().Name)))
- // continue;
+ //if (loaded.Any(a => entry.Name.Contains(a.GetName().Name)))
+ // continue;
- using (var stream = entry.Open())
- {
- var data = stream.ReadToEnd((int) entry.Length);
- byte[] symbol = null;
- var symbolEntryName =
- entry.FullName.Substring(0, entry.FullName.Length - "dll".Length) + "pdb";
- var symbolEntry = zipFile.GetEntry(symbolEntryName);
- if (symbolEntry != null)
- try
- {
- using (var symbolStream = symbolEntry.Open())
- symbol = symbolStream.ReadToEnd((int) symbolEntry.Length);
- }
- catch (Exception e)
- {
- _log.Warn(e, $"Failed to read debugging symbols from {item.Filename}:{symbolEntryName}");
- }
-
- assemblies.Add(symbol != null ? Assembly.Load(data, symbol) : Assembly.Load(data));
- }
- }
+ using var stream = entry.Open();
+ assemblies.Add(stream.ProcessWeavers());
}
}
else
@@ -384,25 +363,8 @@ namespace Torch.Managers
//if (loaded.Any(a => file.Contains(a.GetName().Name)))
// continue;
- using (var stream = File.OpenRead(file))
- {
- var data = stream.ReadToEnd();
- byte[] symbol = null;
- var symbolPath = Path.Combine(Path.GetDirectoryName(file) ?? ".",
- Path.GetFileNameWithoutExtension(file) + ".pdb");
- if (File.Exists(symbolPath))
- try
- {
- using (var symbolStream = File.OpenRead(symbolPath))
- symbol = symbolStream.ReadToEnd();
- }
- catch (Exception e)
- {
- _log.Warn(e, $"Failed to read debugging symbols from {symbolPath}");
- }
-
- assemblies.Add(symbol != null ? Assembly.Load(data, symbol) : Assembly.Load(data));
- }
+ using var stream = File.OpenRead(file);
+ assemblies.Add(stream.ProcessWeavers());
}
@@ -486,10 +448,12 @@ namespace Torch.Managers
}
// Backwards compatibility for PluginAttribute.
+#pragma warning disable CS0618
var pluginAttr = pluginType.GetCustomAttribute();
if (pluginAttr != null)
{
_log.Warn($"Plugin '{manifest.Name}' is using the obsolete {nameof(PluginAttribute)}, using info from attribute if necessary.");
+#pragma warning restore CS0618
manifest.Version = manifest.Version ?? pluginAttr.Version.ToString();
manifest.Name = manifest.Name ?? pluginAttr.Name;
if (manifest.Guid == default(Guid))
diff --git a/Torch/Torch.csproj b/Torch/Torch.csproj
index 318535a..fd61668 100644
--- a/Torch/Torch.csproj
+++ b/Torch/Torch.csproj
@@ -1,74 +1,49 @@
-
-
-
+
- {7E01635C-3B67-472E-BCD6-C5539564F214}
- Library
- Properties
- Torch
- Torch
- v4.8
- 512
-
-
-
- 7.3
-
-
- true
- $(SolutionDir)\bin\x64\Debug\
- DEBUG;TRACE
- full
- x64
- prompt
- MinimumRecommendedRules.ruleset
+ net6-windows
+ Torch
+ Torch
+ Copyright © Torch API 2017
+ false
true
-
-
- $(SolutionDir)\bin\x64\Release\
- TRACE
- true
- pdbonly
+ $(SolutionDir)\bin\$(Platform)\$(Configuration)\
+ True
+ False
x64
- prompt
- MinimumRecommendedRules.ruleset
- $(SolutionDir)\bin\x64\Release\Torch.xml
- true
+ Debug;Release
+ AnyCPU
+
+
+ $(SolutionDir)\bin\$(Platform)\$(Configuration)\Torch.xml
1591
-
+
+
-
-
+
+
+
+
+
+
-
- ..\packages\ControlzEx.3.0.2.4\lib\net45\ControlzEx.dll
- True
-
- False
..\GameBinaries\HavokWrapper.dll
False
-
-
- ..\packages\MahApps.Metro.1.6.1\lib\net45\MahApps.Metro.dll
-
-
- ..\packages\Microsoft.Win32.Registry.4.4.0\lib\net461\Microsoft.Win32.Registry.dll
-
-
False
- ..\GameBinaries\Newtonsoft.Json.dll
-
- ..\packages\NLog.4.4.12\lib\net45\NLog.dll
- True
+
+ ..\GameBinaries\Microsoft.CodeAnalysis.dll
+ False
-
-
-
- ..\packages\protobuf-net.2.4.0\lib\net40\protobuf-net.dll
+
+ ..\GameBinaries\ProtoBuf.Net.dll
+ False
+
+
+ ..\GameBinaries\ProtoBuf.Net.Core.dll
+ False
..\GameBinaries\Sandbox.Common.dll
@@ -86,49 +61,9 @@
..\GameBinaries\SpaceEngineers.Game.dll
False
-
- ..\GameBinaries\SpaceEngineers.ObjectBuilders.dll
- False
-
-
- ..\GameBinaries\SpaceEngineers.ObjectBuilders.XmlSerializers.dll
- False
-
-
- ..\packages\SteamKit2.2.1.0\lib\netstandard2.0\SteamKit2.dll
-
..\GameBinaries\Steamworks.NET.dll
-
-
- ..\packages\System.ComponentModel.Annotations.4.5.0\lib\net461\System.ComponentModel.Annotations.dll
- True
-
-
-
-
-
-
-
-
- ..\packages\System.Security.AccessControl.4.4.0\lib\net461\System.Security.AccessControl.dll
-
-
- ..\packages\System.Security.Principal.Windows.4.4.0\lib\net461\System.Security.Principal.Windows.dll
-
-
-
- ..\packages\ControlzEx.3.0.2.4\lib\net45\System.Windows.Interactivity.dll
- True
-
-
-
-
-
-
-
-
..\GameBinaries\VRage.dll
False
@@ -149,10 +84,6 @@
..\GameBinaries\VRage.Game.dll
False
-
- ..\GameBinaries\VRage.Game.XmlSerializers.dll
- False
-
..\GameBinaries\VRage.Input.dll
False
@@ -173,9 +104,6 @@
..\GameBinaries\VRage.Platform.Windows.dll
False
-
- ..\GameBinaries\VRage.Platform.Windows.dll
-
..\GameBinaries\VRage.Render.dll
False
@@ -192,190 +120,32 @@
..\GameBinaries\VRage.Steam.dll
False
-
-
- Properties\AssemblyVersion.cs
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
CollectionEditor.xaml
-
+
DictionaryEditor.xaml
-
-
+
EmbeddedCollectionEditor.xaml
-
+
FlagsEditor.xaml
-
+
ObjectCollectionEditor.xaml
-
+
ObjectEditor.xaml
-
+
PropertyGrid.xaml
-
+
-
- {fba5d932-6254-4a1e-baf4-e229fa94e3c2}
- Torch.API
- False
-
+
-
-
-
-
-
-
- MSBuild:Compile
- Designer
-
-
- MSBuild:Compile
- Designer
-
-
- Designer
- MSBuild:Compile
-
-
- MSBuild:Compile
- Designer
-
-
- Designer
- MSBuild:Compile
-
-
- Designer
- MSBuild:Compile
-
-
- MSBuild:Compile
- Designer
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Torch/TorchBase.cs b/Torch/TorchBase.cs
index a7c3a1f..67dcaed 100644
--- a/Torch/TorchBase.cs
+++ b/Torch/TorchBase.cs
@@ -2,30 +2,16 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
-using System.IO;
-using System.Linq;
using System.Reflection;
-using System.Runtime;
using System.Runtime.CompilerServices;
-using System.Security.Principal;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
using NLog;
-using ProtoBuf.Meta;
using Sandbox;
-using Sandbox.Engine.Multiplayer;
-using Sandbox.Engine.Networking;
-using Sandbox.Engine.Platform.VideoMode;
-using Sandbox.Engine.Utils;
using Sandbox.Game;
using Sandbox.Game.Multiplayer;
using Sandbox.Game.Screens.Helpers;
-using Sandbox.Game.World;
-using Sandbox.Graphics.GUI;
-using Sandbox.ModAPI;
using SpaceEngineers.Game;
-using SpaceEngineers.Game.GUI;
using Torch.API;
using Torch.API.Managers;
using Torch.API.ModAPI;
@@ -38,23 +24,9 @@ using Torch.Managers.PatchManager;
using Torch.Patches;
using Torch.Utils;
using Torch.Session;
-using VRage;
-using VRage.Collections;
-using VRage.FileSystem;
-using VRage.Game;
-using VRage.Game.Common;
-using VRage.Game.Components;
-using VRage.Game.ObjectBuilder;
-using VRage.Game.SessionComponents;
-using VRage.GameServices;
-using VRage.Library;
-using VRage.ObjectBuilders;
using VRage.Platform.Windows;
using VRage.Plugins;
-using VRage.Scripting;
-using VRage.Steam;
using VRage.Utils;
-using VRageRender;
namespace Torch
{
@@ -71,6 +43,7 @@ namespace Torch
PatchManager.AddPatchShim(typeof(GameStatePatchShim));
PatchManager.AddPatchShim(typeof(GameAnalyticsPatch));
PatchManager.AddPatchShim(typeof(KeenLogPatch));
+ PatchManager.AddPatchShim(typeof(XmlRootWriterPatch));
PatchManager.CommitInternal();
RegisterCoreAssembly(typeof(ITorchBase).Assembly);
RegisterCoreAssembly(typeof(TorchBase).Assembly);
@@ -134,10 +107,12 @@ namespace Torch
protected TorchBase(ITorchConfig config)
{
RegisterCoreAssembly(GetType().Assembly);
+#pragma warning disable CS0618
if (Instance != null)
throw new InvalidOperationException("A TorchBase instance already exists.");
Instance = this;
+#pragma warning restore CS0618
Config = config;
var versionString = Assembly.GetEntryAssembly()
@@ -153,7 +128,9 @@ namespace Torch
Managers = new DependencyManager();
+#pragma warning disable CS0618
Plugins = new PluginManager(this);
+#pragma warning restore CS0618
var sessionManager = new TorchSessionManager(this);
sessionManager.AddFactory((x) => Sync.IsServer ? new ChatManagerServer(this) : new ChatManagerClient(this));
@@ -165,7 +142,9 @@ namespace Torch
Managers.AddManager(new FilesystemManager(this));
Managers.AddManager(new UpdateManager(this));
Managers.AddManager(new EventManager(this));
+#pragma warning disable CS0618
Managers.AddManager(Plugins);
+#pragma warning restore CS0618
TorchAPI.Instance = this;
GameStateChanged += (game, state) =>
diff --git a/Torch/Utils/MiscExtensions.cs b/Torch/Utils/MiscExtensions.cs
index 46078dc..2292962 100644
--- a/Torch/Utils/MiscExtensions.cs
+++ b/Torch/Utils/MiscExtensions.cs
@@ -67,15 +67,7 @@ namespace Torch.Utils
var identityId = grid.BigOwners[0];
- if (MySession.Static.Players.IdentityIsNpc(identityId))
- {
- var identity = MySession.Static.Players.TryGetIdentity(identityId);
- return identity.DisplayName;
- }
- else
- {
- return MyMultiplayer.Static.GetMemberName(MySession.Static.Players.TryGetSteamId(identityId));
- }
+ return MySession.Static.Players.TryGetIdentity(identityId)?.DisplayName ?? "nobody";
}
}
}
\ No newline at end of file
diff --git a/Torch/Utils/ModItemUtils.cs b/Torch/Utils/ModItemUtils.cs
index e423a82..14e6a62 100644
--- a/Torch/Utils/ModItemUtils.cs
+++ b/Torch/Utils/ModItemUtils.cs
@@ -28,7 +28,9 @@ namespace Torch.Utils
}
catch
{
+#pragma warning disable CS0618
return TorchBase.Instance.Config.UgcServiceType.ToString();
+#pragma warning restore CS0618
}
}
}
diff --git a/Torch/Utils/PatchExtensions.cs b/Torch/Utils/PatchExtensions.cs
new file mode 100644
index 0000000..3af7389
--- /dev/null
+++ b/Torch/Utils/PatchExtensions.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Diagnostics;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using Torch.Managers.PatchManager;
+
+namespace Torch.Utils;
+
+public static class PatchExtensions
+{
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void AddPrefix(this MethodRewritePattern pattern, string methodName = "Prefix")
+ {
+ pattern.Prefixes.Add(GetPatchingMethod(methodName));
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void AddSuffix(this MethodRewritePattern pattern, string methodName = "Suffix")
+ {
+ pattern.Suffixes.Add(GetPatchingMethod(methodName));
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void AddTranspiler(this MethodRewritePattern pattern, string methodName = "Transpiler")
+ {
+ pattern.Transpilers.Add(GetPatchingMethod(methodName));
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void AddPostTranspiler(this MethodRewritePattern pattern, string methodName = "PostTranspiler")
+ {
+ pattern.PostTranspilers.Add(GetPatchingMethod(methodName));
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static MethodInfo GetPatchingMethod(string name)
+ {
+ if (new StackFrame(2, false).GetMethod()?.DeclaringType is { } type)
+ return type.GetMethod(name,
+ BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static) ??
+ throw new MissingMethodException(type.FullName, name);
+ throw new InvalidOperationException("Unable to retrieve previous stackframe method");
+ }
+}
\ No newline at end of file
diff --git a/Torch/Utils/SteamWorkshopTools/KeyValueExtensions.cs b/Torch/Utils/SteamWorkshopTools/KeyValueExtensions.cs
deleted file mode 100644
index 1b37983..0000000
--- a/Torch/Utils/SteamWorkshopTools/KeyValueExtensions.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Reflection;
-using System.Linq;
-using NLog;
-using SteamKit2;
-
-namespace Torch.Utils.SteamWorkshopTools
-{
- public static class KeyValueExtensions
- {
- private static Logger Log = LogManager.GetLogger("SteamWorkshopService");
-
- public static T GetValueOrDefault(this KeyValue kv, string key)
- {
- kv.TryGetValueOrDefault(key, out T result);
- return result;
- }
- public static bool TryGetValueOrDefault(this KeyValue kv, string key, out T typedValue)
- {
- var match = kv.Children?.Find((KeyValue item) => item.Name == key);
- object result = default(T);
- if (match == null)
- {
- typedValue = (T) result;
- return false;
- }
-
- var value = match.Value ?? "";
-
- try
- {
- var converter = TypeDescriptor.GetConverter(typeof(T));
- result = converter.ConvertFromString(value);
- typedValue = (T)result;
- return true;
- }
- catch (NotSupportedException)
- {
- throw new Exception($"Unexpected Type '{typeof(T)}'!");
- }
- }
- }
-}
diff --git a/Torch/Utils/SteamWorkshopTools/PublishedItemDetails.cs b/Torch/Utils/SteamWorkshopTools/PublishedItemDetails.cs
deleted file mode 100644
index 4842919..0000000
--- a/Torch/Utils/SteamWorkshopTools/PublishedItemDetails.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Torch.Utils.SteamWorkshopTools
-{
- public class PublishedItemDetails
- {
- public ulong PublishedFileId;
- public uint Views;
- public uint Subscriptions;
- public DateTime TimeUpdated;
- public DateTime TimeCreated;
- public string Description;
- public string Title;
- public string FileUrl;
- public long FileSize;
- public string FileName;
- public ulong ConsumerAppId;
- public ulong CreatorAppId;
- public ulong Creator;
- public string[] Tags;
- }
-}
diff --git a/Torch/Utils/SteamWorkshopTools/WebAPI.cs b/Torch/Utils/SteamWorkshopTools/WebAPI.cs
deleted file mode 100644
index f957172..0000000
--- a/Torch/Utils/SteamWorkshopTools/WebAPI.cs
+++ /dev/null
@@ -1,291 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Xml;
-using System.Xml.Serialization;
-using System.IO;
-using System.Net;
-using NLog;
-using SteamKit2;
-using System.Net.Http;
-
-namespace Torch.Utils.SteamWorkshopTools
-{
- public class WebAPI
- {
- private static Logger Log = LogManager.GetLogger("SteamWorkshopService");
- public const uint AppID = 244850U;
- public string Username { get; private set; }
- private string password;
- public bool IsReady { get; private set; }
- public bool IsRunning { get; private set; }
- private TaskCompletionSource logonTaskCompletionSource;
-
- private SteamClient steamClient;
- private CallbackManager cbManager;
- private SteamUser steamUser;
-
- private static WebAPI _instance;
- public static WebAPI Instance
- {
- get
- {
- return _instance ?? (_instance = new WebAPI());
- }
- }
-
- private WebAPI()
- {
- steamClient = new SteamClient();
- cbManager = new CallbackManager(steamClient);
-
- IsRunning = true;
- }
-
- public async Task Logon(string user = "anonymous", string pw = "")
- {
- if (string.IsNullOrEmpty(user))
- throw new ArgumentNullException("User can't be null!");
- if (!user.Equals("anonymous") && !pw.Equals(""))
- throw new ArgumentNullException("Password can't be null if user is not anonymous!");
-
- Username = user;
- password = pw;
-
- logonTaskCompletionSource = new TaskCompletionSource();
-
- steamUser = steamClient.GetHandler();
- cbManager.Subscribe(OnConnected);
- cbManager.Subscribe(OnDisconnected);
- cbManager.Subscribe(OnLoggedOn);
- cbManager.Subscribe(OnLoggedOff);
-
- Log.Info("Connecting to Steam...");
-
- steamClient.Connect();
-
- await logonTaskCompletionSource.Task;
- return logonTaskCompletionSource.Task.Result;
- }
-
- public void CancelLogon()
- {
- logonTaskCompletionSource?.SetCanceled();
- }
-
- public async Task> GetPublishedFileDetails(IEnumerable workshopIds)
- {
- //if (!IsReady)
- // throw new Exception("SteamWorkshopService not initialized!");
-
- using (dynamic remoteStorage = SteamKit2.WebAPI.GetInterface("ISteamRemoteStorage"))
- {
- KeyValue allFilesDetails = null ;
- remoteStorage.Timeout = TimeSpan.FromSeconds(30);
- allFilesDetails = await Task.Run(delegate {
- try
- {
- return remoteStorage.GetPublishedFileDetails1(
- itemcount: workshopIds.Count(),
- publishedfileids: workshopIds,
- method: HttpMethod.Post);
- // var ifaceArgs = new Dictionary();
- // ifaceArgs["itemcount"] = workshopIds.Count().ToString();
- // no idea if that formatting is correct - in fact I get a 404 response
- // ifaceArgs["publishedfileids"] = string.Join(",", workshopIds);
- // return remoteStorage.Call(HttpMethod.Post, "GetPublishedFileDetails", args: ifaceArgs);
- }
- catch (HttpRequestException e)
- {
- Log.Error($"Fetching File Details failed: {e.Message}");
- return null;
- }
- });
- if (allFilesDetails == null)
- return null;
- //fileDetails = remoteStorage.Call(HttpMethod.Post, "GetPublishedFileDetails", 1, new Dictionary() { { "itemcount", workshopIds.Count().ToString() }, { "publishedfileids", workshopIds.ToString() } });
- var detailsList = allFilesDetails?.Children.Find((KeyValue kv) => kv.Name == "publishedfiledetails")?.Children;
- var resultCount = allFilesDetails?.GetValueOrDefault("resultcount");
- if( detailsList == null || resultCount == null)
- {
- Log.Error("Received invalid data: ");
-#if DEBUG
- if(allFilesDetails != null)
- PrintKeyValue(allFilesDetails);
- return null;
-#endif
- }
- if ( detailsList.Count != workshopIds.Count() || resultCount != workshopIds.Count())
- {
- Log.Error($"Received unexpected number of fileDetails. Expected: {workshopIds.Count()}, Received: {resultCount}");
- return null;
- }
-
- var result = new Dictionary();
- for( int i = 0; i < resultCount; i++ )
- {
- var fileDetails = detailsList[i];
-
- var tagContainer = fileDetails.Children.Find(item => item.Name == "tags");
- List tags = new List();
- if (tagContainer != null)
- foreach (var tagKv in tagContainer.Children)
- {
- var tag = tagKv.Children.Find(item => item.Name == "tag")?.Value;
- if( tag != null)
- tags.Add(tag);
- }
-
- var publishedFileId = fileDetails.GetValueOrDefault("publishedfileid");
- result[publishedFileId] = new PublishedItemDetails()
- {
- PublishedFileId = publishedFileId,
- Views = fileDetails.GetValueOrDefault("views"),
- Subscriptions = fileDetails.GetValueOrDefault("subscriptions"),
- TimeUpdated = DateTimeOffset.FromUnixTimeSeconds(fileDetails.GetValueOrDefault("time_updated")).DateTime,
- TimeCreated = DateTimeOffset.FromUnixTimeSeconds(fileDetails.GetValueOrDefault("time_created")).DateTime,
- Description = fileDetails.GetValueOrDefault("description"),
- Title = fileDetails.GetValueOrDefault("title"),
- FileUrl = fileDetails.GetValueOrDefault("file_url"),
- FileSize = fileDetails.GetValueOrDefault("file_size"),
- FileName = fileDetails.GetValueOrDefault("filename"),
- ConsumerAppId = fileDetails.GetValueOrDefault("consumer_app_id"),
- CreatorAppId = fileDetails.GetValueOrDefault("creator_app_id"),
- Creator = fileDetails.GetValueOrDefault("creator"),
- Tags = tags.ToArray()
- };
- }
- return result;
- }
- }
-
- [Obsolete("Space Engineers has transitioned to Steam's UGC api, therefore this method might not always work!")]
- public async Task DownloadPublishedFile(PublishedItemDetails fileDetails, string dir, string name = null)
- {
- var fullPath = Path.Combine(dir, name);
- if (name == null)
- name = fileDetails.FileName;
- var expectedSize = (fileDetails.FileSize == 0) ? -1 : fileDetails.FileSize;
-
- using (var client = new WebClient())
- {
- try
- {
- var downloadTask = client.DownloadFileTaskAsync(fileDetails.FileUrl, Path.Combine(dir, name));
- DateTime start = DateTime.Now;
- for (int i = 0; i < 30; i++)
- {
- await Task.Delay(1000);
- if (downloadTask.IsCompleted)
- break;
- }
- if ( !downloadTask.IsCompleted )
- {
- client.CancelAsync();
- throw new Exception("Timeout while attempting to downloading published workshop item!");
- }
- //var text = await client.DownloadStringTaskAsync(url);
- //File.WriteAllText(fullPath, text);
- }
- catch (Exception e)
- {
- Log.Error("Failed to download workshop item! /n" +
- $"{e.Message} - url: {fileDetails.FileUrl}, path: {Path.Combine(dir, name)}");
- throw e;
- }
- }
-
- }
-
- class Printable
- {
- public KeyValue Data;
- public int Offset;
-
- public void Print()
- {
- Log.Info($"{new string(' ', Offset)}{Data.Name}: {Data.Value}");
- }
- }
-
- private static void PrintKeyValue(KeyValue data)
- {
-
- var dataSet = new Stack();
- dataSet.Push(new Printable()
- {
- Data = data,
- Offset = 0
- });
- while (dataSet.Count != 0)
- {
- var printable = dataSet.Pop();
- foreach (var child in printable.Data.Children)
- dataSet.Push(new Printable()
- {
- Data = child,
- Offset = printable.Offset + 2
- });
- printable.Print();
- }
- }
-
-
-#region CALLBACKS
- private void OnConnected( SteamClient.ConnectedCallback callback)
- {
- Log.Info("Connected to Steam! Logging in '{0}'...", Username);
- if( Username == "anonymous" )
- steamUser.LogOnAnonymous();
- else
- steamUser.LogOn(new SteamUser.LogOnDetails
- {
- Username = Username,
- Password = password
- });
- }
-
- private void OnDisconnected( SteamClient.DisconnectedCallback callback )
- {
- Log.Info("Disconnected from Steam");
- IsReady = false;
- IsRunning = false;
- }
-
- private void OnLoggedOn( SteamUser.LoggedOnCallback callback )
- {
- if( callback.Result != EResult.OK )
- {
- string msg;
- if( callback.Result == EResult.AccountLogonDenied )
- {
- msg = "Unable to logon to Steam: This account is Steamguard protected.";
- Log.Warn(msg);
- logonTaskCompletionSource.SetException(new Exception(msg));
- IsRunning = false;
- return;
- }
-
- msg = $"Unable to logon to Steam: {callback.Result} / {callback.ExtendedResult}";
- Log.Warn(msg);
- logonTaskCompletionSource.SetException(new Exception(msg));
- IsRunning = false;
- return;
- }
- IsReady = true;
- Log.Info("Successfully logged on!");
- logonTaskCompletionSource.SetResult(true);
- }
-
- private void OnLoggedOff( SteamUser.LoggedOffCallback callback )
- {
- IsReady = false;
- Log.Info($"Logged off of Steam: {callback.Result}");
- }
-#endregion
-
- }
-}
diff --git a/Torch/Utils/TorchLauncher.cs b/Torch/Utils/TorchLauncher.cs
index f368548..a4cc6a6 100644
--- a/Torch/Utils/TorchLauncher.cs
+++ b/Torch/Utils/TorchLauncher.cs
@@ -4,50 +4,40 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
+using System.Runtime.Loader;
using System.Text;
using System.Threading.Tasks;
+using ProtoBuf;
using Torch.API;
namespace Torch.Utils
{
public class TorchLauncher
{
- private const string TorchKey = "TorchWrapper";
+ private static readonly Dictionary Assemblies = new Dictionary();
- public static bool IsTorchWrapped()
+ public static void Launch(params string[] binaryPaths)
{
- return AppDomain.CurrentDomain.GetData(TorchKey) != null;
+ foreach (var file in binaryPaths.SelectMany(path => Directory.EnumerateFiles(path, "*.dll")))
+ {
+ try
+ {
+ var name = AssemblyName.GetAssemblyName(file);
+ Assemblies.TryAdd(name.Name ?? name.FullName.Split(',')[0], file);
+ }
+ catch (BadImageFormatException)
+ {
+ // if we are trying to load native image
+ }
+ }
+
+ AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainOnAssemblyResolve;
}
- public static void Launch(string entryPoint, string[] args, params string[] binaryPaths)
+ private static Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args)
{
- if (IsTorchWrapped())
- throw new Exception("Can't wrap torch twice");
- string exePath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)?.ToLower().Replace('/', '\\');
- if (exePath == null)
- throw new ArgumentException("Unable to determine executing assembly's path");
- var allPaths = new HashSet { exePath };
- foreach (string other in binaryPaths)
- allPaths.Add(other.ToLower().Replace('/', '\\'));
- var pathPrefix = StringUtils.CommonPrefix(allPaths);
-#pragma warning disable 618
- AppDomain.CurrentDomain.AppendPrivatePath(string.Join(Path.PathSeparator.ToString(), allPaths));
-#pragma warning restore 618
- AppDomain.CurrentDomain.SetData(TorchKey, true);
- AppDomain.CurrentDomain.ExecuteAssemblyByName(entryPoint, args);
- return;
- // this would be way better but HAVOK IS UNMANAGED :clang:
- // exclude application base from probing
-// var setup = new AppDomainSetup
-// {
-// ApplicationBase = pathPrefix.ToString(),
-// PrivateBinPathProbe = "",
-// PrivateBinPath = string.Join(";", allPaths)
-// };
-// AppDomain domain = AppDomain.CreateDomain($"TorchDomain-{Assembly.GetEntryAssembly().GetName().Name}-{new Random().Next():X}", null, setup);
-// domain.SetData(TorchKey, true);
-// domain.ExecuteAssemblyByName(entryPoint, args);
-// AppDomain.Unload(domain);
+ var name = args.Name;
+ return Assemblies.TryGetValue(name[..name.IndexOf(',')], out var path) ? Assembly.LoadFrom(path) : null;
}
}
}
diff --git a/Torch/Utils/WorkshopQueryUtils.cs b/Torch/Utils/WorkshopQueryUtils.cs
new file mode 100644
index 0000000..e25811a
--- /dev/null
+++ b/Torch/Utils/WorkshopQueryUtils.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Sandbox.Engine.Networking;
+using VRage.Game;
+using VRage.GameServices;
+
+namespace Torch.Utils;
+
+public static class WorkshopQueryUtils
+{
+ // TODO: Maybe later
+ public static async Task> GetModsInfo(IEnumerable mods)
+ {
+ throw new NotImplementedException();
+ /*return (await Task.WhenAll(mods.GroupBy(b => b.PublishedServiceName)
+ .Select(b => GetModsInfo(b.Key, b.Select(c => c.PublishedFileId)))))
+ .SelectMany(b => b).ToList();*/
+ }
+
+ public static Task GetModInfo(MyObjectBuilder_Checkpoint.ModItem item)
+ {
+ throw new NotImplementedException();
+ /*var query = MyGameService.CreateWorkshopQuery(item.PublishedServiceName);
+ query.ItemIds = new() {item.PublishedFileId};
+ var source = new TaskCompletionSource();
+
+ query.QueryCompleted += result =>
+ {
+ if (result == MyGameServiceCallResult.OK)
+ {
+ source.SetResult(query.Items[0]);
+ return;
+ }
+
+ source.SetException(new Exception($"Workshop query resulted in {result}"));
+ };
+
+ query.Run();
+ return source.Task;*/
+ }
+
+ private static Task> GetModsInfo(string serviceName, IEnumerable ids)
+ {
+ var query = MyGameService.CreateWorkshopQuery(serviceName);
+ query.ItemIds = ids.ToList();
+ var source = new TaskCompletionSource>();
+
+ query.QueryCompleted += result =>
+ {
+ if (result == MyGameServiceCallResult.OK)
+ {
+ source.SetResult(query.Items);
+ return;
+ }
+
+ source.SetException(new Exception($"Workshop query resulted in {result}"));
+ };
+
+ query.Run();
+ return source.Task;
+ }
+}
\ No newline at end of file
diff --git a/Torch/VRageGame.cs b/Torch/VRageGame.cs
index 73c32ae..af828d7 100644
--- a/Torch/VRageGame.cs
+++ b/Torch/VRageGame.cs
@@ -50,18 +50,18 @@ namespace Torch
#pragma warning disable 649
[ReflectedGetter(Name = "m_plugins", Type = typeof(MyPlugins))]
- private static readonly Func> _getVRagePluginList;
+ private static Func> _getVRagePluginList;
[ReflectedGetter(Name = "Static", TypeName = "Sandbox.Game.Audio.MyMusicController, Sandbox.Game")]
- private static readonly Func _getMusicControllerStatic;
+ private static Func _getMusicControllerStatic;
[ReflectedSetter(Name = "Static", TypeName = "Sandbox.Game.Audio.MyMusicController, Sandbox.Game")]
- private static readonly Action _setMusicControllerStatic;
+ private static Action _setMusicControllerStatic;
[ReflectedMethod(Name = "Unload", TypeName = "Sandbox.Game.Audio.MyMusicController, Sandbox.Game")]
- private static readonly Action _musicControllerUnload;
+ private static Action _musicControllerUnload;
// [ReflectedGetter(Name = "UpdateLayerDescriptors", Type = typeof(MyReplicationServer))]
// private static readonly Func _layerSettings;
@@ -168,7 +168,9 @@ namespace Torch
//Type.GetType("VRage.Steam.MySteamService, VRage.Steam").GetProperty("IsActive").GetSetMethod(true).Invoke(service, new object[] {SteamAPI.Init()});
_log.Info("Initializing network services");
+#pragma warning disable CS0618
var isEos = TorchBase.Instance.Config.UgcServiceType == UGCServiceType.EOS;
+#pragma warning restore CS0618
if (isEos)
{
@@ -334,8 +336,8 @@ namespace Torch
#pragma warning disable 649
- [ReflectedMethod(Name = "StartServer")]
- private static Action _hostServerForSession;
+ // [ReflectedMethod(Name = "StartServer")]
+ // private static Action _hostServerForSession;
#pragma warning restore 649
private void DoLoadSession(string sessionPath)
diff --git a/Torch/ViewModels/PlayerViewModel.cs b/Torch/ViewModels/PlayerViewModel.cs
index f070a3a..619ad34 100644
--- a/Torch/ViewModels/PlayerViewModel.cs
+++ b/Torch/ViewModels/PlayerViewModel.cs
@@ -15,8 +15,7 @@ namespace Torch.ViewModels
{
public ulong SteamId { get; }
public string Name { get; }
- private ConnectionState _state;
- public ConnectionState State { get => _state; set { _state = value; OnPropertyChanged(); } }
+ public ConnectionState State { get; set; }
public MyPromoteLevel PromoteLevel => MySession.Static.GetUserPromoteLevel(SteamId);
public string PromotedName
@@ -24,10 +23,7 @@ namespace Torch.ViewModels
get
{
var p = PromoteLevel;
- if (p <= MyPromoteLevel.None)
- return Name;
- else
- return $"{Name} ({p})";
+ return p <= MyPromoteLevel.None ? Name : $"{Name} ({p})";
}
}
diff --git a/Torch/ViewModels/ViewModel.cs b/Torch/ViewModels/ViewModel.cs
index f7a2160..1de99be 100644
--- a/Torch/ViewModels/ViewModel.cs
+++ b/Torch/ViewModels/ViewModel.cs
@@ -8,6 +8,7 @@ using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Threading;
+using PropertyChanged;
namespace Torch
{
@@ -27,6 +28,7 @@ namespace Torch
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
+ [SuppressPropertyChangedWarnings]
protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
NotifyCollectionChangedEventHandler collectionChanged = CollectionChanged;
diff --git a/Torch/Views/DictionaryEditor.xaml.cs b/Torch/Views/DictionaryEditor.xaml.cs
index a81a034..7d2e8c6 100644
--- a/Torch/Views/DictionaryEditor.xaml.cs
+++ b/Torch/Views/DictionaryEditor.xaml.cs
@@ -82,11 +82,11 @@ namespace Torch.Views
private TKey _key;
private TValue _value;
- object IDictionaryItem.Key { get => _key; set => SetValue(ref _key, (TKey)value); }
- object IDictionaryItem.Value { get => _value; set => SetValue(ref _value, (TValue)value); }
+ object IDictionaryItem.Key { get; set; }
+ object IDictionaryItem.Value { get; set; }
- public TKey Key { get => _key; set => SetValue(ref _key, value); }
- public TValue Value { get => _value; set => SetValue(ref _value, value); }
+ public TKey Key { get; set; }
+ public TValue Value { get; set; }
public DictionaryItem()
{
diff --git a/Torch/app.config b/Torch/app.config
deleted file mode 100644
index cf4f4e1..0000000
--- a/Torch/app.config
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Torch/packages.config b/Torch/packages.config
deleted file mode 100644
index e28ce57..0000000
--- a/Torch/packages.config
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file