Compare commits
41 Commits
v1.0.16-ma
...
v1.0.45-ma
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9c185d5577 | ||
![]() |
8b6c401531 | ||
![]() |
92db8994ef | ||
![]() |
aee36661fd | ||
![]() |
feda84fac8 | ||
![]() |
2503cd6372 | ||
![]() |
f321034eeb | ||
![]() |
7573684520 | ||
![]() |
223eaa9fd0 | ||
![]() |
d138a46f25 | ||
![]() |
ce2bbd4a61 | ||
![]() |
85dd4b46b8 | ||
![]() |
166a9d1dbe | ||
![]() |
dfc15354ca | ||
![]() |
57c977deb4 | ||
![]() |
f6cdc2fe79 | ||
![]() |
f42b9c6674 | ||
![]() |
227557f421 | ||
![]() |
0632f68aaf | ||
![]() |
0a9f299527 | ||
![]() |
67f25ab20b | ||
![]() |
ad19a7dc9e | ||
![]() |
dd854a159a | ||
![]() |
879a373e6a | ||
![]() |
ec1b017946 | ||
![]() |
cf75210304 | ||
![]() |
3696f18714 | ||
![]() |
1f7e4e869d | ||
![]() |
ba5b611994 | ||
![]() |
2bcf79efdd | ||
![]() |
d5c101bf19 | ||
![]() |
e9841b4de1 | ||
![]() |
aea0011683 | ||
![]() |
d10528f9fe | ||
![]() |
66ea4d7307 | ||
![]() |
f6ce40a854 | ||
![]() |
bd62d31298 | ||
![]() |
b1cf5fb638 | ||
![]() |
1d6a2a9a60 | ||
![]() |
455be2393e | ||
![]() |
6131a9003b |
17
Dockerfile
17
Dockerfile
@@ -1,17 +0,0 @@
|
|||||||
FROM mcr.microsoft.com/windows/servercore:ltsc2022
|
|
||||||
|
|
||||||
USER ContainerAdministrator
|
|
||||||
ADD https://aka.ms/highdpimfc2013x64enu vc_redist2013.exe
|
|
||||||
ADD https://aka.ms/vs/16/release/vc_redist.x64.exe vc_redist.exe
|
|
||||||
|
|
||||||
RUN vc_redist2013.exe /passive /norestart
|
|
||||||
RUN vc_redist.exe /passive /norestart
|
|
||||||
RUN del vc_redist2013.exe && del vc_redist.exe
|
|
||||||
|
|
||||||
USER ContainerUser
|
|
||||||
COPY . .
|
|
||||||
ENV TORCH_GAME_PATH="c:\dedi"
|
|
||||||
ENV TORCH_INSTANCE="c:\instance"
|
|
||||||
ENV TORCH_SERVICE="true"
|
|
||||||
ENTRYPOINT ["Torch.Server.exe"]
|
|
||||||
CMD ["-noupdate"]
|
|
@@ -1,4 +1,3 @@
|
|||||||
[](https://discord.gg/trK6sYdcNE)
|
|
||||||
[](https://ci.appveyor.com/project/zznty/torch/branch/master)
|
[](https://ci.appveyor.com/project/zznty/torch/branch/master)
|
||||||
|
|
||||||
# What is Torch?
|
# What is Torch?
|
||||||
@@ -17,6 +16,10 @@ Torch is the successor to SE Server Extender and gives server admins the tools t
|
|||||||
* .NET 6.0 runtime
|
* .NET 6.0 runtime
|
||||||
* Additional options & features
|
* Additional options & features
|
||||||
|
|
||||||
|
### Discord
|
||||||
|
|
||||||
|
If you have any questions or issues please join our [discord](https://discord.gg/UyYFSe3TyQ)
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
* Unzip the Torch release into its own directory and run the executable. It will automatically download the SE DS and generate the other necessary files.
|
* Unzip the Torch release into its own directory and run the executable. It will automatically download the SE DS and generate the other necessary files.
|
||||||
|
@@ -17,7 +17,7 @@ namespace Torch.Server
|
|||||||
{
|
{
|
||||||
public IList<LogEntry> LogEntries { get; set; }
|
public IList<LogEntry> LogEntries { get; set; }
|
||||||
public SynchronizationContext TargetContext { get; set; }
|
public SynchronizationContext TargetContext { get; set; }
|
||||||
private readonly int _maxLines = 1000;
|
private const int MAX_LINES = 1000;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Write(LogEventInfo logEvent)
|
protected override void Write(LogEventInfo logEvent)
|
||||||
@@ -29,6 +29,11 @@ namespace Torch.Server
|
|||||||
{
|
{
|
||||||
var logEvent = (LogEventInfo) state;
|
var logEvent = (LogEventInfo) state;
|
||||||
LogEntries?.Add(new(logEvent.TimeStamp, Layout.Render(logEvent), LogLevelColors[logEvent.Level]));
|
LogEntries?.Add(new(logEvent.TimeStamp, Layout.Render(logEvent), LogLevelColors[logEvent.Level]));
|
||||||
|
if (LogEntries is not {Count: > MAX_LINES}) return;
|
||||||
|
for (var i = 0; LogEntries.Count > MAX_LINES; i++)
|
||||||
|
{
|
||||||
|
LogEntries.RemoveAt(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly Dictionary<LogLevel, SolidColorBrush> LogLevelColors = new()
|
private static readonly Dictionary<LogLevel, SolidColorBrush> LogLevelColors = new()
|
||||||
|
@@ -234,9 +234,11 @@ namespace Torch.Server.Managers
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var world = DedicatedConfig.Worlds.FirstOrDefault(x => x.WorldPath == DedicatedConfig.LoadWorld) ?? new WorldViewModel(DedicatedConfig.LoadWorld);
|
var world = DedicatedConfig.SelectedWorld;
|
||||||
|
|
||||||
world.Checkpoint.SessionName = DedicatedConfig.WorldName;
|
world.Checkpoint.SessionName = string.IsNullOrEmpty(DedicatedConfig.WorldName)
|
||||||
|
? Path.GetDirectoryName(DedicatedConfig.LoadWorld)
|
||||||
|
: DedicatedConfig.WorldName;
|
||||||
world.WorldConfiguration.Settings = DedicatedConfig.SessionSettings;
|
world.WorldConfiguration.Settings = DedicatedConfig.SessionSettings;
|
||||||
world.WorldConfiguration.Mods.Clear();
|
world.WorldConfiguration.Mods.Clear();
|
||||||
|
|
||||||
@@ -268,7 +270,7 @@ namespace Torch.Server.Managers
|
|||||||
private void ValidateInstance(string path)
|
private void ValidateInstance(string path)
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(Path.Combine(path, "Saves"));
|
Directory.CreateDirectory(Path.Combine(path, "Saves"));
|
||||||
Directory.CreateDirectory(Path.Combine(path, "Mods"));
|
// Directory.CreateDirectory(Path.Combine(path, "Mods"));
|
||||||
var configPath = Path.Combine(path, CONFIG_NAME);
|
var configPath = Path.Combine(path, CONFIG_NAME);
|
||||||
if (File.Exists(configPath))
|
if (File.Exists(configPath))
|
||||||
return;
|
return;
|
||||||
|
@@ -33,6 +33,9 @@ public static class CheckpointLoadPatch
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
world.KeenCheckpoint.Settings = world.WorldConfiguration.Settings;
|
||||||
|
world.KeenCheckpoint.Mods = world.WorldConfiguration.Mods;
|
||||||
|
|
||||||
__result = world.Checkpoint;
|
__result = world.Checkpoint;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
@@ -8,6 +9,7 @@ using NLog;
|
|||||||
using Sandbox;
|
using Sandbox;
|
||||||
using Torch.Managers.PatchManager;
|
using Torch.Managers.PatchManager;
|
||||||
using Torch.Managers.PatchManager.MSIL;
|
using Torch.Managers.PatchManager.MSIL;
|
||||||
|
using Torch.Utils;
|
||||||
|
|
||||||
namespace Torch.Patches
|
namespace Torch.Patches
|
||||||
{
|
{
|
||||||
@@ -17,12 +19,14 @@ namespace Torch.Patches
|
|||||||
[PatchShim]
|
[PatchShim]
|
||||||
public static class WorldLoadExceptionPatch
|
public static class WorldLoadExceptionPatch
|
||||||
{
|
{
|
||||||
private static readonly ILogger _log = LogManager.GetCurrentClassLogger();
|
private static readonly ILogger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
[ReflectedMethodInfo(typeof(MySandboxGame), "InitQuickLaunch")]
|
||||||
|
private static MethodInfo _quickLaunchMethod = null!;
|
||||||
|
|
||||||
public static void Patch(PatchContext ctx)
|
public static void Patch(PatchContext ctx)
|
||||||
{
|
{
|
||||||
ctx.GetPattern(typeof(MySandboxGame).GetMethod("InitQuickLaunch", BindingFlags.Instance | BindingFlags.NonPublic))
|
ctx.GetPattern(_quickLaunchMethod).AddTranspiler(nameof(Transpile));
|
||||||
.Transpilers.Add(typeof(WorldLoadExceptionPatch).GetMethod(nameof(Transpile), BindingFlags.Static | BindingFlags.NonPublic));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<MsilInstruction> Transpile(IEnumerable<MsilInstruction> method)
|
private static IEnumerable<MsilInstruction> Transpile(IEnumerable<MsilInstruction> method)
|
||||||
@@ -30,19 +34,19 @@ namespace Torch.Patches
|
|||||||
var msil = method.ToList();
|
var msil = method.ToList();
|
||||||
for (var i = 0; i < msil.Count; i++)
|
for (var i = 0; i < msil.Count; i++)
|
||||||
{
|
{
|
||||||
if (msil[i].TryCatchOperations.All(x => x.Type != MsilTryCatchOperationType.BeginClauseBlock))
|
var instruction = msil[i];
|
||||||
continue;
|
if (instruction.IsLocalStore() && instruction.Operand is MsilOperandInline.MsilOperandLocal {Value.Index: 19} operand)
|
||||||
|
|
||||||
for (; i < msil.Count; i++)
|
|
||||||
{
|
{
|
||||||
if (msil[i].OpCode != OpCodes.Leave)
|
msil.InsertRange(i + 1, new []
|
||||||
continue;
|
{
|
||||||
|
operand.Instruction.CopyWith(OpCodes.Ldloc_S),
|
||||||
msil[i] = new MsilInstruction(OpCodes.Rethrow);
|
new MsilInstruction(OpCodes.Call).InlineValue(new Action<Exception>(LogFatal).Method)
|
||||||
break;
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return msil;
|
return msil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void LogFatal(Exception e) => Log.Fatal(e.ToStringDemystified());
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,5 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using NLog;
|
||||||
|
using NLog.Config;
|
||||||
using NLog.Targets;
|
using NLog.Targets;
|
||||||
using Torch.Utils;
|
using Torch.Utils;
|
||||||
|
|
||||||
@@ -7,11 +9,11 @@ namespace Torch.Server
|
|||||||
{
|
{
|
||||||
internal static class Program
|
internal static class Program
|
||||||
{
|
{
|
||||||
|
[STAThread]
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
var isService = Environment.GetEnvironmentVariable("TORCH_SERVICE")
|
var isService = Environment.GetEnvironmentVariable("TORCH_SERVICE")
|
||||||
?.Equals(bool.TrueString, StringComparison.OrdinalIgnoreCase) ?? false;
|
?.Equals(bool.TrueString, StringComparison.OrdinalIgnoreCase) ?? false;
|
||||||
Target.Register<LogViewerTarget>(nameof(LogViewerTarget));
|
|
||||||
//Ensures that all the files are downloaded in the Torch directory.
|
//Ensures that all the files are downloaded in the Torch directory.
|
||||||
var workingDir = AppContext.BaseDirectory;
|
var workingDir = AppContext.BaseDirectory;
|
||||||
var binDir = Path.Combine(Environment.GetEnvironmentVariable("TORCH_GAME_PATH") ?? workingDir, "DedicatedServer64");
|
var binDir = Path.Combine(Environment.GetEnvironmentVariable("TORCH_GAME_PATH") ?? workingDir, "DedicatedServer64");
|
||||||
@@ -23,8 +25,6 @@ namespace Torch.Server
|
|||||||
File.Delete(file);
|
File.Delete(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
TorchLauncher.Launch(workingDir, binDir);
|
|
||||||
|
|
||||||
// Breaks on Windows Server 2019
|
// Breaks on Windows Server 2019
|
||||||
#if TORCH_SERVICE
|
#if TORCH_SERVICE
|
||||||
if (!new ComputerInfo().OSFullName.Contains("Server 2019") && !Environment.UserInteractive)
|
if (!new ComputerInfo().OSFullName.Contains("Server 2019") && !Environment.UserInteractive)
|
||||||
@@ -45,9 +45,17 @@ namespace Torch.Server
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
instancePath = Path.GetFullPath(instanceName);
|
instancePath = Directory.CreateDirectory(instanceName).FullName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var oldNlog = Path.Combine(workingDir, "NLog.config");
|
||||||
|
var newNlog = Path.Combine(instancePath, "NLog.config");
|
||||||
|
if (File.Exists(oldNlog) && !File.ReadAllText(oldNlog).Contains("FlowDocument", StringComparison.Ordinal))
|
||||||
|
File.Move(oldNlog, newNlog, true);
|
||||||
|
else if (!File.Exists(newNlog))
|
||||||
|
using (var f = File.Create(newNlog))
|
||||||
|
typeof(Program).Assembly.GetManifestResourceStream("Torch.Server.NLog.config")!.CopyTo(f);
|
||||||
|
|
||||||
var oldTorchCfg = Path.Combine(workingDir, "Torch.cfg");
|
var oldTorchCfg = Path.Combine(workingDir, "Torch.cfg");
|
||||||
var torchCfg = Path.Combine(instancePath, "Torch.cfg");
|
var torchCfg = Path.Combine(instancePath, "Torch.cfg");
|
||||||
|
|
||||||
@@ -66,18 +74,38 @@ namespace Torch.Server
|
|||||||
var handler = new UnhandledExceptionHandler(config.Data, isService);
|
var handler = new UnhandledExceptionHandler(config.Data, isService);
|
||||||
AppDomain.CurrentDomain.UnhandledException += handler.OnUnhandledException;
|
AppDomain.CurrentDomain.UnhandledException += handler.OnUnhandledException;
|
||||||
|
|
||||||
|
Target.Register<LogViewerTarget>(nameof(LogViewerTarget));
|
||||||
|
TorchLogManager.RegisterTargets(Environment.GetEnvironmentVariable("TORCH_LOG_EXTENSIONS_PATH") ??
|
||||||
|
Path.Combine(instancePath, "LoggingExtensions"));
|
||||||
|
|
||||||
|
TorchLogManager.SetConfiguration(new XmlLoggingConfiguration(newNlog));
|
||||||
|
|
||||||
var initializer = new Initializer(workingDir, config);
|
var initializer = new Initializer(workingDir, config);
|
||||||
if (!initializer.Initialize(args))
|
if (!initializer.Initialize(args))
|
||||||
Environment.Exit(1);
|
Environment.Exit(1);
|
||||||
|
|
||||||
|
TorchLauncher.Launch(workingDir, binDir);
|
||||||
|
|
||||||
CopyNative(binDir);
|
CopyNative(binDir);
|
||||||
|
|
||||||
initializer.Run(isService, instanceName, instancePath);
|
initializer.Run(isService, instanceName, instancePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void CopyNative(string binPath)
|
private static void CopyNative(string binPath)
|
||||||
|
{
|
||||||
|
var log = LogManager.GetLogger("TorchLauncher");
|
||||||
|
|
||||||
|
var workingDir = new DirectoryInfo(Directory.GetCurrentDirectory());
|
||||||
|
if (workingDir.Attributes.HasFlag(FileAttributes.ReadOnly))
|
||||||
|
{
|
||||||
|
log.Warn("Game directory is readonly. You should copy steam_api64.dll, Havok.dll from bin manually");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
var apiSource = Path.Combine(binPath, "steam_api64.dll");
|
var apiSource = Path.Combine(binPath, "steam_api64.dll");
|
||||||
var apiTarget = Path.Combine(AppContext.BaseDirectory, "steam_api64.dll");
|
var apiTarget = Path.Combine(workingDir.FullName, "steam_api64.dll");
|
||||||
if (!File.Exists(apiTarget))
|
if (!File.Exists(apiTarget))
|
||||||
{
|
{
|
||||||
File.Copy(apiSource, apiTarget);
|
File.Copy(apiSource, apiTarget);
|
||||||
@@ -89,7 +117,7 @@ namespace Torch.Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
var havokSource = Path.Combine(binPath, "Havok.dll");
|
var havokSource = Path.Combine(binPath, "Havok.dll");
|
||||||
var havokTarget = Path.Combine(AppContext.BaseDirectory, "Havok.dll");
|
var havokTarget = Path.Combine(workingDir.FullName, "Havok.dll");
|
||||||
|
|
||||||
if (!File.Exists(havokTarget))
|
if (!File.Exists(havokTarget))
|
||||||
{
|
{
|
||||||
@@ -101,5 +129,14 @@ namespace Torch.Server
|
|||||||
File.Copy(havokSource, havokTarget);
|
File.Copy(havokSource, havokTarget);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (UnauthorizedAccessException)
|
||||||
|
{
|
||||||
|
// file is being used by another process, probably previous torch has not been closed yet
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
log.Error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -140,12 +140,6 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Update="TorchService.cs">
|
|
||||||
<SubType>Component</SubType>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="TorchServiceInstaller.cs">
|
|
||||||
<SubType>Component</SubType>
|
|
||||||
</Compile>
|
|
||||||
<Compile Remove="ServerManager.cs" />
|
<Compile Remove="ServerManager.cs" />
|
||||||
<Compile Remove="ViewModels\SessionSettingsViewModel1.cs" />
|
<Compile Remove="ViewModels\SessionSettingsViewModel1.cs" />
|
||||||
<Compile Remove="Views\WorldSelectControl.xaml.cs" />
|
<Compile Remove="Views\WorldSelectControl.xaml.cs" />
|
||||||
@@ -160,7 +154,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Page Remove="Views\WorldSelectControl.xaml" />
|
<Page Remove="Views\WorldSelectControl.xaml" />
|
||||||
<None Include="..\NLog.config" Visible="false" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="Always" />
|
<EmbeddedResource Include="..\NLog.config" Visible="false" />
|
||||||
<None Include="..\Dockerfile" Visible="false" CopyToPublishDirectory="Always" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@@ -107,7 +107,7 @@ namespace Torch.Server
|
|||||||
public TimeSpan ElapsedPlayTime { get => _elapsedPlayTime; set => SetValue(ref _elapsedPlayTime, value); }
|
public TimeSpan ElapsedPlayTime { get => _elapsedPlayTime; set => SetValue(ref _elapsedPlayTime, value); }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Thread GameThread { get; private set; }
|
public Thread GameThread => MySandboxGame.Static?.UpdateThread;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool IsRunning { get => _isRunning; set => SetValue(ref _isRunning, value); }
|
public bool IsRunning { get => _isRunning; set => SetValue(ref _isRunning, value); }
|
||||||
@@ -178,6 +178,17 @@ namespace Torch.Server
|
|||||||
{
|
{
|
||||||
if (State == ServerState.Stopped)
|
if (State == ServerState.Stopped)
|
||||||
Log.Error("Server is already stopped");
|
Log.Error("Server is already stopped");
|
||||||
|
if (Thread.CurrentThread == GameThread)
|
||||||
|
new Thread(StopInternal)
|
||||||
|
{
|
||||||
|
Name = "Stopping Thread"
|
||||||
|
}.Start();
|
||||||
|
else
|
||||||
|
StopInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StopInternal()
|
||||||
|
{
|
||||||
Log.Info("Stopping server.");
|
Log.Info("Stopping server.");
|
||||||
base.Stop();
|
base.Stop();
|
||||||
Log.Info("Server stopped.");
|
Log.Info("Server stopped.");
|
||||||
@@ -185,6 +196,7 @@ namespace Torch.Server
|
|||||||
State = ServerState.Stopped;
|
State = ServerState.Stopped;
|
||||||
IsRunning = false;
|
IsRunning = false;
|
||||||
CanRun = true;
|
CanRun = true;
|
||||||
|
SimulationRatio = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -202,8 +214,9 @@ namespace Torch.Server
|
|||||||
Log.Info("Ejected all players from server for restart.");
|
Log.Info("Ejected all players from server for restart.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Stop();
|
new Thread(() =>
|
||||||
// TODO clone this
|
{
|
||||||
|
StopInternal();
|
||||||
var config = (TorchConfig)Config;
|
var config = (TorchConfig)Config;
|
||||||
LogManager.Flush();
|
LogManager.Flush();
|
||||||
|
|
||||||
@@ -213,6 +226,10 @@ namespace Torch.Server
|
|||||||
Process.Start(exe, config.ToString());
|
Process.Start(exe, config.ToString());
|
||||||
|
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
|
})
|
||||||
|
{
|
||||||
|
Name = "Restart thread"
|
||||||
|
}.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
[SuppressPropertyChangedWarnings]
|
[SuppressPropertyChangedWarnings]
|
||||||
@@ -228,11 +245,23 @@ namespace Torch.Server
|
|||||||
if (newState == TorchSessionState.Loaded)
|
if (newState == TorchSessionState.Loaded)
|
||||||
{
|
{
|
||||||
_multiplayerManagerDedicated = CurrentSession.Managers.GetManager<MultiplayerManagerDedicated>();
|
_multiplayerManagerDedicated = CurrentSession.Managers.GetManager<MultiplayerManagerDedicated>();
|
||||||
|
_multiplayerManagerDedicated.PlayerJoined += MultiplayerManagerDedicatedOnPlayerJoined;
|
||||||
|
_multiplayerManagerDedicated.PlayerLeft += MultiplayerManagerDedicatedOnPlayerLeft;
|
||||||
CurrentSession.Managers.GetManager<CommandManager>().RegisterCommandModule(typeof(WhitelistCommands));
|
CurrentSession.Managers.GetManager<CommandManager>().RegisterCommandModule(typeof(WhitelistCommands));
|
||||||
ModCommunication.Register();
|
ModCommunication.Register();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void MultiplayerManagerDedicatedOnPlayerLeft(IPlayer player)
|
||||||
|
{
|
||||||
|
OnlinePlayers--;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MultiplayerManagerDedicatedOnPlayerJoined(IPlayer player)
|
||||||
|
{
|
||||||
|
OnlinePlayers++;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Init(object gameInstance)
|
public override void Init(object gameInstance)
|
||||||
{
|
{
|
||||||
@@ -251,7 +280,6 @@ namespace Torch.Server
|
|||||||
SimulationRatio = Math.Min(Sync.ServerSimulationRatio, 1);
|
SimulationRatio = Math.Min(Sync.ServerSimulationRatio, 1);
|
||||||
var elapsed = TimeSpan.FromSeconds(Math.Floor(_uptime.Elapsed.TotalSeconds));
|
var elapsed = TimeSpan.FromSeconds(Math.Floor(_uptime.Elapsed.TotalSeconds));
|
||||||
ElapsedPlayTime = elapsed;
|
ElapsedPlayTime = elapsed;
|
||||||
OnlinePlayers = _multiplayerManagerDedicated?.Players.Count ?? 0;
|
|
||||||
|
|
||||||
if (_watchdog == null && Config.TickTimeout > 0)
|
if (_watchdog == null && Config.TickTimeout > 0)
|
||||||
{
|
{
|
||||||
@@ -350,17 +378,6 @@ namespace Torch.Server
|
|||||||
|
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
sb.AppendFormat(
|
|
||||||
"ManagedThreadId: {0}, Name: {1}, OSThreadId: {2}, Thread: IsAlive: {3}, IsBackground: {4}, IsThreadPool: {5}",
|
|
||||||
thread.ManagedThreadId,
|
|
||||||
thread.Name,
|
|
||||||
clrThread.OSThreadId,
|
|
||||||
thread.IsAlive,
|
|
||||||
thread.IsBackground,
|
|
||||||
thread.IsThreadPoolThread)
|
|
||||||
.AppendLine();
|
|
||||||
|
|
||||||
sb.AppendLine("Stack trace:");
|
|
||||||
foreach (var frame in clrThread.EnumerateStackTrace())
|
foreach (var frame in clrThread.EnumerateStackTrace())
|
||||||
{
|
{
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
|
@@ -144,22 +144,17 @@ namespace Torch.Server.Views
|
|||||||
{
|
{
|
||||||
//var w = new RoleEditor(_instanceManager.DedicatedConfig.SelectedWorld);
|
//var w = new RoleEditor(_instanceManager.DedicatedConfig.SelectedWorld);
|
||||||
//w.Show();
|
//w.Show();
|
||||||
var d = new RoleEditor();
|
|
||||||
var w = _instanceManager.DedicatedConfig.SelectedWorld;
|
var w = _instanceManager.DedicatedConfig.SelectedWorld;
|
||||||
|
|
||||||
if(w.Checkpoint.PromotedUsers == null) {
|
if (w is null)
|
||||||
w.Checkpoint.PromotedUsers = new VRage.Serialization.SerializableDictionary<ulong, MyPromoteLevel>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (w == null)
|
|
||||||
{
|
{
|
||||||
MessageBox.Show("A world is not selected.");
|
MessageBox.Show("A world is not selected.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (w.Checkpoint.PromotedUsers == null)
|
w.Checkpoint.PromotedUsers ??= new();
|
||||||
w.Checkpoint.PromotedUsers = new SerializableDictionary<ulong, MyPromoteLevel>();
|
|
||||||
d.Edit(w.Checkpoint.PromotedUsers.Dictionary);
|
new RoleEditor().Edit(w.Checkpoint.PromotedUsers.Dictionary);
|
||||||
_instanceManager.DedicatedConfig.Administrators = w.Checkpoint.PromotedUsers.Dictionary.Where(k => k.Value >= MyPromoteLevel.Admin).Select(k => k.Key.ToString()).ToList();
|
_instanceManager.DedicatedConfig.Administrators = w.Checkpoint.PromotedUsers.Dictionary.Where(k => k.Value >= MyPromoteLevel.Admin).Select(k => k.Key.ToString()).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,58 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Windows.Data;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Torch.Server.ViewModels;
|
|
||||||
using NLog;
|
|
||||||
using Torch.Collections;
|
|
||||||
|
|
||||||
namespace Torch.Server.Views.Converters
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A converter to get the index of a ModItemInfo object within a collection of ModItemInfo objects
|
|
||||||
/// </summary>
|
|
||||||
public class ModToListIdConverter : IMultiValueConverter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Converts a ModItemInfo object into its index within a Collection of ModItemInfo objects
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="values">
|
|
||||||
/// Expected to contain a ModItemInfo object at index 0
|
|
||||||
/// and a Collection of ModItemInfo objects at index 1
|
|
||||||
/// </param>
|
|
||||||
/// <param name="targetType">This parameter will be ignored</param>
|
|
||||||
/// <param name="parameter">This parameter will be ignored</param>
|
|
||||||
/// <param name="culture"> This parameter will be ignored</param>
|
|
||||||
/// <returns>the index of the mod within the provided mod list.</returns>
|
|
||||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
//if (targetType != typeof(int))
|
|
||||||
// throw new NotSupportedException("ModToIdConverter can only convert mods into int values or vise versa!");
|
|
||||||
if (values[0] is ModItemInfo mod && values[1] is MtObservableList<ModItemInfo> modList)
|
|
||||||
{
|
|
||||||
return modList.IndexOf(mod);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// It is not supported to reverse this converter
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="values"></param>
|
|
||||||
/// <param name="targetType"></param>
|
|
||||||
/// <param name="parameter"></param>
|
|
||||||
/// <param name="culture"></param>
|
|
||||||
/// <returns>Raises a NotSupportedException</returns>
|
|
||||||
public object[] ConvertBack(object values, Type[] targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("ModToIdConverter can not convert back!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -5,8 +5,7 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:viewModels="clr-namespace:Torch.Server.ViewModels"
|
xmlns:viewModels="clr-namespace:Torch.Server.ViewModels"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800"
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
MouseMove="UserControl_MouseMove">
|
|
||||||
<!--<UserControl.DataContext>
|
<!--<UserControl.DataContext>
|
||||||
<viewModels:ConfigDedicatedViewModel />
|
<viewModels:ConfigDedicatedViewModel />
|
||||||
</UserControl.DataContext>-->
|
</UserControl.DataContext>-->
|
||||||
@@ -18,7 +17,7 @@
|
|||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
<Style TargetType="Grid" x:Key="RootGridStyle">
|
<Style TargetType="Grid" x:Key="RootGridStyle">
|
||||||
<Style.Triggers>
|
<Style.Triggers>
|
||||||
<DataTrigger Binding="{Binding Mode=OneWay, UpdateSourceTrigger=PropertyChanged, BindingGroupName=RootEnabledBinding}" Value="{x:Null}">
|
<DataTrigger Binding="{Binding Mode=OneWay, BindingGroupName=RootEnabledBinding}" Value="{x:Null}">
|
||||||
<Setter Property="IsEnabled" Value="False"/>
|
<Setter Property="IsEnabled" Value="False"/>
|
||||||
</DataTrigger>
|
</DataTrigger>
|
||||||
</Style.Triggers>
|
</Style.Triggers>
|
||||||
@@ -36,38 +35,25 @@
|
|||||||
<RowDefinition Height="80px"/>
|
<RowDefinition Height="80px"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<DataGrid Name="ModList" Grid.Column="0" Grid.ColumnSpan="1" ItemsSource="{Binding UpdateSourceTrigger=PropertyChanged}"
|
<DataGrid Name="ModList" Grid.Column="0" ItemsSource="{Binding Mods}"
|
||||||
Sorting="ModList_Sorting"
|
|
||||||
SelectionMode="Single"
|
SelectionMode="Single"
|
||||||
SelectionUnit="FullRow"
|
SelectionUnit="FullRow"
|
||||||
AllowDrop="True"
|
AllowDrop="True"
|
||||||
CanUserReorderColumns="False"
|
CanUserReorderColumns="False"
|
||||||
CanUserSortColumns="True"
|
CanUserSortColumns="True"
|
||||||
PreviewMouseLeftButtonDown="ModList_MouseLeftButtonDown"
|
|
||||||
MouseLeftButtonUp="ModList_MouseLeftButtonUp"
|
|
||||||
SelectedCellsChanged="ModList_Selected"
|
SelectedCellsChanged="ModList_Selected"
|
||||||
AutoGenerateColumns="False">
|
AutoGenerateColumns="False">
|
||||||
<!--:DesignSource="{d:DesignInstance Type={x:Type MyObjectBuilder_Checkpoint:ModItem, CreateList=True}}">-->
|
<!--:DesignSource="{d:DesignInstance Type={x:Type MyObjectBuilder_Checkpoint:ModItem, CreateList=True}}">-->
|
||||||
<DataGrid.Columns>
|
<DataGrid.Columns>
|
||||||
<DataGridTextColumn Header="Load Order"
|
|
||||||
Width="Auto"
|
|
||||||
IsReadOnly="True">
|
|
||||||
<DataGridTextColumn.Binding>
|
|
||||||
<MultiBinding Converter="{StaticResource ModToListIdConverter}" StringFormat="{}{0}">
|
|
||||||
<Binding />
|
|
||||||
<Binding ElementName="ModList" Path="DataContext"></Binding>
|
|
||||||
</MultiBinding>
|
|
||||||
</DataGridTextColumn.Binding>
|
|
||||||
</DataGridTextColumn>
|
|
||||||
<DataGridTextColumn Header="Workshop Id"
|
<DataGridTextColumn Header="Workshop Id"
|
||||||
IsReadOnly="True"
|
IsReadOnly="True"
|
||||||
Binding="{Binding PublishedFileId, NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged}">
|
Binding="{Binding PublishedFileId}">
|
||||||
|
|
||||||
</DataGridTextColumn>
|
</DataGridTextColumn>
|
||||||
<DataGridTextColumn Header="Name"
|
<DataGridTextColumn Header="Name"
|
||||||
Width="*"
|
Width="*"
|
||||||
IsReadOnly="True"
|
IsReadOnly="True"
|
||||||
Binding="{Binding FriendlyName, NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged}">
|
Binding="{Binding FriendlyName}">
|
||||||
</DataGridTextColumn>
|
</DataGridTextColumn>
|
||||||
</DataGrid.Columns>
|
</DataGrid.Columns>
|
||||||
<DataGrid.ItemContainerStyle>
|
<DataGrid.ItemContainerStyle>
|
||||||
@@ -88,12 +74,12 @@
|
|||||||
</Style>
|
</Style>
|
||||||
</DataGrid.ItemContainerStyle>
|
</DataGrid.ItemContainerStyle>
|
||||||
</DataGrid>
|
</DataGrid>
|
||||||
<ScrollViewer Grid.Column="2" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Background="#1b2838">
|
<ScrollViewer Grid.Row="0" Grid.Column="2" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Background="#1b2838">
|
||||||
<TextBlock Name="ModDescription" TextWrapping="Wrap" Foreground="White" Padding="2px"
|
<TextBlock Name="ModDescription" TextWrapping="Wrap" Foreground="White" Padding="2px"
|
||||||
Text="{Binding ElementName=ModList, Path=SelectedItem.Description}">
|
Text="{Binding ElementName=ModList, Path=SelectedItem.Description}">
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
<Grid Grid.Row="2" Margin="0 0 0 6px">
|
<Grid Grid.Row="1" Grid.Column="0" Margin="0 0 0 6px">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
@@ -108,10 +94,10 @@
|
|||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<CheckBox Name="ShowDependencyModsCheckBox" VerticalAlignment="Center"
|
<CheckBox Name="ShowDependencyModsCheckBox" VerticalAlignment="Center"
|
||||||
HorizontalAlignment="Left" Margin="6px 0" Grid.Column="0" Grid.Row="0"/>
|
HorizontalAlignment="Left" Margin="6px 0" Grid.Column="0" Grid.Row="0"/>
|
||||||
<Label Content="Show Dependency Mods" Padding="0" Margin="6px 0" Grid.Column="1" VerticalAlignment="Center"/>
|
<Label Content="Show Dependency Mods" Padding="0" Margin="6px 0" Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"/>
|
||||||
<Label Content="ID/URL:" Padding="0" Margin="6px 0" HorizontalAlignment="Left"
|
<Label Content="ID/URL:" Padding="0" Margin="6px 0" HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center" Grid.Column="0" Grid.Row="1"/>
|
VerticalAlignment="Center" Grid.Column="0" Grid.Row="1"/>
|
||||||
<TextBox Name="AddModIDTextBox" Grid.Column="1" VerticalContentAlignment="Center"
|
<TextBox Name="AddModIdTextBox" Grid.Column="1" VerticalContentAlignment="Center"
|
||||||
HorizontalAlignment="Stretch" MinWidth="100px" Margin="6px 4px" Grid.Row="1"/>
|
HorizontalAlignment="Stretch" MinWidth="100px" Margin="6px 4px" Grid.Row="1"/>
|
||||||
<ComboBox Grid.Column="2" Grid.Row="1" x:Name="UgcServiceTypeBox" SelectionChanged="UgcServiceTypeBox_OnSelectionChanged" SelectedValuePath="Value" DisplayMemberPath="Key"/>
|
<ComboBox Grid.Column="2" Grid.Row="1" x:Name="UgcServiceTypeBox" SelectionChanged="UgcServiceTypeBox_OnSelectionChanged" SelectedValuePath="Value" DisplayMemberPath="Key"/>
|
||||||
<Button Content="Add" Grid.Column="3" Margin="6px 0" Width="60px" Height="40px" Click="AddBtn_OnClick" Grid.Row="1"/>
|
<Button Content="Add" Grid.Column="3" Margin="6px 0" Width="60px" Height="40px" Click="AddBtn_OnClick" Grid.Row="1"/>
|
||||||
@@ -120,6 +106,6 @@
|
|||||||
<Button Content="Bulk Edit" Grid.Column="5" Margin="6px 0" Width="60px" Height="40px" Click="BulkButton_OnClick" Grid.Row="1"/>
|
<Button Content="Bulk Edit" Grid.Column="5" Margin="6px 0" Width="60px" Height="40px" Click="BulkButton_OnClick" Grid.Row="1"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Button Content="Save Config" Grid.Row="2" VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="6px" Grid.Column="3" Width="80px" Height="40px" Click="SaveBtn_OnClick"/>
|
<Button Content="Save Config" Grid.Row="1" VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="6px" Grid.Column="3" Width="80px" Height="40px" Click="SaveBtn_OnClick"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
@@ -1,32 +1,15 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Data;
|
|
||||||
using System.Windows.Documents;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
using System.Windows.Navigation;
|
|
||||||
using System.Windows.Shapes;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Windows.Threading;
|
|
||||||
using VRage.Game;
|
|
||||||
using NLog;
|
using NLog;
|
||||||
using Sandbox.Engine.Networking;
|
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
using Torch.Server.Managers;
|
using Torch.Server.Managers;
|
||||||
using Torch.API.Managers;
|
using Torch.API.Managers;
|
||||||
using Torch.Server.ViewModels;
|
using Torch.Server.ViewModels;
|
||||||
using Torch.Server.Annotations;
|
|
||||||
using Torch.Collections;
|
|
||||||
using Torch.Utils;
|
using Torch.Utils;
|
||||||
using Torch.Views;
|
using Torch.Views;
|
||||||
|
|
||||||
@@ -35,14 +18,12 @@ namespace Torch.Server.Views
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for ModListControl.xaml
|
/// Interaction logic for ModListControl.xaml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class ModListControl : UserControl, INotifyPropertyChanged
|
public partial class ModListControl : UserControl
|
||||||
{
|
{
|
||||||
private static Logger Log = LogManager.GetLogger(nameof(ModListControl));
|
private static Logger Log = LogManager.GetLogger(nameof(ModListControl));
|
||||||
private InstanceManager _instanceManager;
|
private InstanceManager _instanceManager;
|
||||||
ModItemInfo _draggedMod;
|
|
||||||
bool _hasOrderChanged = false;
|
|
||||||
bool _isSortedByLoadOrder = true;
|
|
||||||
private readonly ITorchConfig _config;
|
private readonly ITorchConfig _config;
|
||||||
|
private ConfigDedicatedViewModel _viewModel;
|
||||||
|
|
||||||
//private List<BindingExpression> _bindingExpressions = new List<BindingExpression>();
|
//private List<BindingExpression> _bindingExpressions = new List<BindingExpression>();
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -51,9 +32,11 @@ namespace Torch.Server.Views
|
|||||||
public ModListControl()
|
public ModListControl()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
#pragma warning disable CS0618
|
||||||
_instanceManager = TorchBase.Instance.Managers.GetManager<InstanceManager>();
|
_instanceManager = TorchBase.Instance.Managers.GetManager<InstanceManager>();
|
||||||
_instanceManager.InstanceLoaded += _instanceManager_InstanceLoaded;
|
|
||||||
_config = TorchBase.Instance.Config;
|
_config = TorchBase.Instance.Config;
|
||||||
|
#pragma warning restore CS0618
|
||||||
|
_instanceManager.InstanceLoaded += _instanceManager_InstanceLoaded;
|
||||||
//var mods = _instanceManager.DedicatedConfig?.Mods;
|
//var mods = _instanceManager.DedicatedConfig?.Mods;
|
||||||
//if( mods != null)
|
//if( mods != null)
|
||||||
// DataContext = new ObservableCollection<MyObjectBuilder_Checkpoint.ModItem>();
|
// DataContext = new ObservableCollection<MyObjectBuilder_Checkpoint.ModItem>();
|
||||||
@@ -67,24 +50,14 @@ namespace Torch.Server.Views
|
|||||||
//Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(ApplyStyles));
|
//Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(ApplyStyles));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ModListControl_SizeChanged(object sender, SizeChangedEventArgs e)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ResetSorting()
|
|
||||||
{
|
|
||||||
CollectionViewSource.GetDefaultView(ModList.ItemsSource).SortDescriptions.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void _instanceManager_InstanceLoaded(ConfigDedicatedViewModel obj)
|
private void _instanceManager_InstanceLoaded(ConfigDedicatedViewModel obj)
|
||||||
{
|
{
|
||||||
Dispatcher.Invoke(() => {
|
Dispatcher.InvokeAsync(() =>
|
||||||
DataContext = obj?.Mods ?? new MtObservableList<ModItemInfo>();
|
{
|
||||||
|
_viewModel = obj;
|
||||||
|
DataContext = obj;
|
||||||
UpdateLayout();
|
UpdateLayout();
|
||||||
((MtObservableList<ModItemInfo>)DataContext).CollectionChanged += OnModlistUpdate;
|
|
||||||
if (obj is { })
|
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await obj.UpdateAllModInfosAsync();
|
await obj.UpdateAllModInfosAsync();
|
||||||
@@ -93,13 +66,6 @@ namespace Torch.Server.Views
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnModlistUpdate(object sender, NotifyCollectionChangedEventArgs e)
|
|
||||||
{
|
|
||||||
ModList.Items.Refresh();
|
|
||||||
//if (e.Action == NotifyCollectionChangedAction.Remove)
|
|
||||||
// _instanceManager.SaveConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SaveBtn_OnClick(object sender, RoutedEventArgs e)
|
private void SaveBtn_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
_instanceManager.SaveConfig();
|
_instanceManager.SaveConfig();
|
||||||
@@ -108,31 +74,28 @@ namespace Torch.Server.Views
|
|||||||
|
|
||||||
private void AddBtn_OnClick(object sender, RoutedEventArgs e)
|
private void AddBtn_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (TryExtractId(AddModIDTextBox.Text, out ulong id))
|
if (TryExtractId(AddModIdTextBox.Text, out ulong id))
|
||||||
{
|
{
|
||||||
var mod = new ModItemInfo(ModItemUtils.Create(id, UgcServiceTypeBox.SelectedValue?.ToString()));
|
var mod = new ModItemInfo(ModItemUtils.Create(id, UgcServiceTypeBox.SelectedValue?.ToString()));
|
||||||
|
|
||||||
_instanceManager.DedicatedConfig.Mods.Add(mod);
|
_instanceManager.DedicatedConfig.Mods.Add(mod);
|
||||||
Task.Run(mod.UpdateModInfoAsync)
|
Task.Run(mod.UpdateModInfoAsync)
|
||||||
.ContinueWith((t) =>
|
.ContinueWith(_ =>
|
||||||
{
|
|
||||||
Dispatcher.Invoke(() =>
|
|
||||||
{
|
{
|
||||||
_instanceManager.DedicatedConfig.Save();
|
_instanceManager.DedicatedConfig.Save();
|
||||||
});
|
});
|
||||||
});
|
AddModIdTextBox.Text = "";
|
||||||
AddModIDTextBox.Text = "";
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddModIDTextBox.BorderBrush = Brushes.Red;
|
AddModIdTextBox.BorderBrush = Brushes.Red;
|
||||||
Log.Warn("Invalid mod id!");
|
Log.Warn("Invalid mod id!");
|
||||||
MessageBox.Show("Invalid mod id!");
|
MessageBox.Show("Invalid mod id!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void RemoveBtn_OnClick(object sender, RoutedEventArgs e)
|
private void RemoveBtn_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var modList = ((MtObservableList<ModItemInfo>)DataContext);
|
var modList = _viewModel.Mods;
|
||||||
if (ModList.SelectedItem is ModItemInfo mod && modList.Contains(mod))
|
if (ModList.SelectedItem is ModItemInfo mod && modList.Contains(mod))
|
||||||
modList.Remove(mod);
|
modList.Remove(mod);
|
||||||
}
|
}
|
||||||
@@ -150,113 +113,9 @@ namespace Torch.Server.Views
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ModList_Sorting(object sender, DataGridSortingEventArgs e)
|
|
||||||
{
|
|
||||||
Log.Info($"Sorting by '{e.Column.Header}'");
|
|
||||||
if (e.Column == ModList.Columns[0])
|
|
||||||
{
|
|
||||||
var dataView = CollectionViewSource.GetDefaultView(ModList.ItemsSource);
|
|
||||||
dataView.SortDescriptions.Clear();
|
|
||||||
dataView.Refresh();
|
|
||||||
_isSortedByLoadOrder = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
_isSortedByLoadOrder = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ModList_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
|
||||||
{
|
|
||||||
//return;
|
|
||||||
|
|
||||||
_draggedMod = (ModItemInfo) TryFindRowAtPoint((UIElement) sender, e.GetPosition(ModList))?.DataContext;
|
|
||||||
|
|
||||||
//DraggedMod = (ModItemInfo) ModList.SelectedItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static DataGridRow TryFindRowAtPoint(UIElement reference, Point point)
|
|
||||||
{
|
|
||||||
var element = reference.InputHitTest(point) as DependencyObject;
|
|
||||||
if (element == null)
|
|
||||||
return null;
|
|
||||||
if (element is DataGridRow row)
|
|
||||||
return row;
|
|
||||||
else
|
|
||||||
return TryFindParent<DataGridRow>(element);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static T TryFindParent<T>(DependencyObject child) where T : DependencyObject
|
|
||||||
{
|
|
||||||
DependencyObject parent;
|
|
||||||
if (child == null)
|
|
||||||
return null;
|
|
||||||
if (child is ContentElement contentElement)
|
|
||||||
{
|
|
||||||
parent = ContentOperations.GetParent(contentElement);
|
|
||||||
if (parent == null && child is FrameworkContentElement fce)
|
|
||||||
parent = fce.Parent;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
parent = VisualTreeHelper.GetParent(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parent is T result)
|
|
||||||
return result;
|
|
||||||
else
|
|
||||||
return TryFindParent<T>(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UserControl_MouseMove(object sender, MouseEventArgs e)
|
|
||||||
{
|
|
||||||
if (_draggedMod == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!_isSortedByLoadOrder)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var targetMod = (ModItemInfo)TryFindRowAtPoint((UIElement)sender, e.GetPosition(ModList))?.DataContext;
|
|
||||||
if( targetMod != null && !ReferenceEquals(_draggedMod, targetMod))
|
|
||||||
{
|
|
||||||
_hasOrderChanged = true;
|
|
||||||
var modList = (MtObservableList<ModItemInfo>)DataContext;
|
|
||||||
modList.Move(modList.IndexOf(targetMod), _draggedMod);
|
|
||||||
//modList.RemoveAt(modList.IndexOf(_draggedMod));
|
|
||||||
//modList.Insert(modList.IndexOf(targetMod), _draggedMod);
|
|
||||||
ModList.Items.Refresh();
|
|
||||||
ModList.SelectedItem = _draggedMod;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ModList_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
|
||||||
{
|
|
||||||
if (!_isSortedByLoadOrder)
|
|
||||||
{
|
|
||||||
var targetMod = (ModItemInfo)TryFindRowAtPoint((UIElement)sender, e.GetPosition(ModList))?.DataContext;
|
|
||||||
if (targetMod != null && !ReferenceEquals(_draggedMod, targetMod))
|
|
||||||
{
|
|
||||||
var msg = "Drag and drop is only available when sorted by load order!";
|
|
||||||
Log.Warn(msg);
|
|
||||||
MessageBox.Show(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//if (DraggedMod != null && HasOrderChanged)
|
|
||||||
//Log.Info("Dragging over, saving...");
|
|
||||||
//_instanceManager.SaveConfig();
|
|
||||||
_draggedMod = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
|
||||||
[NotifyPropertyChangedInvocator]
|
|
||||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
|
||||||
{
|
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ModList_Selected(object sender, SelectedCellsChangedEventArgs e)
|
private void ModList_Selected(object sender, SelectedCellsChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (_draggedMod != null)
|
if( e.AddedCells.Count > 0)
|
||||||
ModList.SelectedItem = _draggedMod;
|
|
||||||
else if( e.AddedCells.Count > 0)
|
|
||||||
ModList.SelectedItem = e.AddedCells[0].Item;
|
ModList.SelectedItem = e.AddedCells[0].Item;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,23 +124,23 @@ namespace Torch.Server.Views
|
|||||||
var editor = new CollectionEditor();
|
var editor = new CollectionEditor();
|
||||||
|
|
||||||
//let's see just how poorly we can do this
|
//let's see just how poorly we can do this
|
||||||
var modList = ((MtObservableList<ModItemInfo>)DataContext).ToList();
|
var modList = _viewModel.Mods.ToList();
|
||||||
var idList = modList.Select(m => m.ToString()).ToList();
|
var idList = modList.Select(m => m.ToString()).ToList();
|
||||||
var tasks = new List<Task>();
|
var tasks = new List<Task>();
|
||||||
//blocking
|
//blocking
|
||||||
editor.Edit<string>(idList, "Mods");
|
editor.Edit<string>(idList, "Mods");
|
||||||
|
|
||||||
modList.RemoveAll(m =>
|
modList.Clear();
|
||||||
{
|
|
||||||
var mod = m.ToString();
|
|
||||||
return idList.Any(mod.Equals);
|
|
||||||
});
|
|
||||||
modList.AddRange(idList.Select(id =>
|
modList.AddRange(idList.Select(id =>
|
||||||
{
|
{
|
||||||
var info = new ModItemInfo(ModItemUtils.Create(id));
|
if (!ModItemUtils.TryParse(id, out var item))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var info = new ModItemInfo(item);
|
||||||
tasks.Add(Task.Run(info.UpdateModInfoAsync));
|
tasks.Add(Task.Run(info.UpdateModInfoAsync));
|
||||||
return info;
|
return info;
|
||||||
}));
|
}).Where(b => b is not null));
|
||||||
|
|
||||||
_instanceManager.DedicatedConfig.Mods.Clear();
|
_instanceManager.DedicatedConfig.Mods.Clear();
|
||||||
foreach (var mod in modList)
|
foreach (var mod in modList)
|
||||||
_instanceManager.DedicatedConfig.Mods.Add(mod);
|
_instanceManager.DedicatedConfig.Mods.Add(mod);
|
||||||
|
@@ -18,7 +18,6 @@
|
|||||||
</Style>
|
</Style>
|
||||||
<converters:ListConverter x:Key="ListConverterString" Type="system:String"/>
|
<converters:ListConverter x:Key="ListConverterString" Type="system:String"/>
|
||||||
<converters:ListConverter x:Key="ListConverterUInt64" Type="system:UInt64"/>
|
<converters:ListConverter x:Key="ListConverterUInt64" Type="system:UInt64"/>
|
||||||
<converters:ModToListIdConverter x:Key="ModToListIdConverter"/>
|
|
||||||
<converters:ListConverterWorkshopId x:Key="ListConverterWorkshopId"/>
|
<converters:ListConverterWorkshopId x:Key="ListConverterWorkshopId"/>
|
||||||
<converters:BooleanAndConverter x:Key="BooleanAndConverter"/>
|
<converters:BooleanAndConverter x:Key="BooleanAndConverter"/>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
@@ -12,7 +12,6 @@ EndProject
|
|||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7AD02A71-1D4C-48F9-A8C1-789A5512424F}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7AD02A71-1D4C-48F9-A8C1-789A5512424F}"
|
||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
NLog.config = NLog.config
|
NLog.config = NLog.config
|
||||||
Dockerfile = Dockerfile
|
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.Tests", "Torch.Tests\Torch.Tests.csproj", "{C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.Tests", "Torch.Tests\Torch.Tests.csproj", "{C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}"
|
||||||
|
@@ -197,7 +197,7 @@ namespace Torch.Managers.PatchManager
|
|||||||
lock (_log)
|
lock (_log)
|
||||||
{
|
{
|
||||||
var instructions = context.Body.Instructions
|
var instructions = context.Body.Instructions
|
||||||
.Select(b => new MsilInstruction(b)).ToList();
|
.Select(b => b.ToMsilInstruction()).ToList();
|
||||||
LogTarget(PrintModeEnum.Patched, false, "========== Patched method ==========");
|
LogTarget(PrintModeEnum.Patched, false, "========== Patched method ==========");
|
||||||
MethodTranspiler.IntegrityAnalysis((a, b) => LogTarget(PrintModeEnum.Patched, a, b), instructions, true);
|
MethodTranspiler.IntegrityAnalysis((a, b) => LogTarget(PrintModeEnum.Patched, a, b), instructions, true);
|
||||||
LogTarget(PrintModeEnum.Patched, false, gap);
|
LogTarget(PrintModeEnum.Patched, false, gap);
|
||||||
|
136
Torch/Managers/PatchManager/MSIL/InstructionExtensions.cs
Normal file
136
Torch/Managers/PatchManager/MSIL/InstructionExtensions.cs
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using Mono.Cecil;
|
||||||
|
using Mono.Cecil.Cil;
|
||||||
|
using MonoMod.Utils;
|
||||||
|
using Torch.Managers.PatchManager.Transpile;
|
||||||
|
using OperandType = System.Reflection.Emit.OperandType;
|
||||||
|
|
||||||
|
namespace Torch.Managers.PatchManager.MSIL;
|
||||||
|
|
||||||
|
internal static class InstructionExtensions
|
||||||
|
{
|
||||||
|
public static MsilInstruction ToMsilInstruction(this Instruction instruction)
|
||||||
|
{
|
||||||
|
static System.Reflection.Emit.Label CreateLabel(int pos)
|
||||||
|
{
|
||||||
|
var instance = Activator.CreateInstance(typeof(System.Reflection.Emit.Label),
|
||||||
|
BindingFlags.CreateInstance | BindingFlags.Instance | BindingFlags.NonPublic, null,
|
||||||
|
new object[] {pos}, null);
|
||||||
|
if (instance == null)
|
||||||
|
return default;
|
||||||
|
return (System.Reflection.Emit.Label) instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
var systemOpCode = MethodContext.OpCodeLookup[instruction.OpCode.Value];
|
||||||
|
var msil = new MsilInstruction(systemOpCode);
|
||||||
|
if (instruction.Operand is null || instruction.OpCode.OperandType == Mono.Cecil.Cil.OperandType.InlineNone)
|
||||||
|
return msil;
|
||||||
|
|
||||||
|
var opType = systemOpCode.OperandType;
|
||||||
|
|
||||||
|
switch (instruction.Operand)
|
||||||
|
{
|
||||||
|
case Instruction targetInstruction when opType is OperandType.InlineBrTarget or OperandType.ShortInlineBrTarget:
|
||||||
|
msil.Operand = new MsilOperandBrTarget(msil)
|
||||||
|
{
|
||||||
|
Target = new MsilLabel(CreateLabel(targetInstruction.Offset))
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case FieldReference reference when opType == OperandType.InlineField:
|
||||||
|
msil.Operand = new MsilOperandInline.MsilOperandReflected<FieldInfo>(msil)
|
||||||
|
{
|
||||||
|
Value = reference.ResolveReflection()
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case int int32 when opType is OperandType.InlineI or OperandType.ShortInlineI:
|
||||||
|
msil.Operand = new MsilOperandInline.MsilOperandInt32(msil)
|
||||||
|
{
|
||||||
|
Value = int32
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case long int64 when opType is OperandType.InlineI8:
|
||||||
|
msil.Operand = new MsilOperandInline.MsilOperandInt64(msil)
|
||||||
|
{
|
||||||
|
Value = int64
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case MethodReference methodReference when opType is OperandType.InlineMethod:
|
||||||
|
msil.Operand = new MsilOperandInline.MsilOperandReflected<MethodBase>(msil)
|
||||||
|
{
|
||||||
|
Value = methodReference.ResolveReflection()
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case double @double when opType is OperandType.InlineR:
|
||||||
|
msil.Operand = new MsilOperandInline.MsilOperandDouble(msil)
|
||||||
|
{
|
||||||
|
Value = @double
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case null when opType is OperandType.InlineSig:
|
||||||
|
throw new NotSupportedException("InlineSignature is not supported by instruction converter");
|
||||||
|
case string @string when opType == OperandType.InlineString:
|
||||||
|
msil.Operand = new MsilOperandInline.MsilOperandString(msil)
|
||||||
|
{
|
||||||
|
Value = @string
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case Instruction[] targetInstructions when opType is OperandType.InlineSwitch:
|
||||||
|
msil.Operand = new MsilOperandSwitch(msil)
|
||||||
|
{
|
||||||
|
Labels = targetInstructions.Select(b => new MsilLabel(CreateLabel(b.Offset))).ToArray()
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case MemberReference memberReference when opType is OperandType.InlineTok:
|
||||||
|
msil.Operand = new MsilOperandInline.MsilOperandReflected<MemberInfo>(msil)
|
||||||
|
{
|
||||||
|
Value = memberReference.ResolveReflection()
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case TypeReference typeReference when opType is OperandType.InlineType:
|
||||||
|
msil.Operand = new MsilOperandInline.MsilOperandReflected<Type>(msil)
|
||||||
|
{
|
||||||
|
Value = typeReference.ResolveReflection()
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case VariableDefinition variableDefinition when opType is OperandType.InlineVar or OperandType.ShortInlineVar:
|
||||||
|
if (systemOpCode.IsLocalStore() || systemOpCode.IsLocalLoad() || systemOpCode.IsLocalLoadByRef())
|
||||||
|
msil.Operand = new MsilOperandInline.MsilOperandLocal(msil)
|
||||||
|
{
|
||||||
|
Value = new MsilLocal(variableDefinition.Index)
|
||||||
|
};
|
||||||
|
else
|
||||||
|
msil.Operand = new MsilOperandInline.MsilOperandArgument(msil)
|
||||||
|
{
|
||||||
|
Value = new MsilArgument(variableDefinition.Index)
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case ParameterDefinition parameterDefinition when opType is OperandType.InlineVar or OperandType.ShortInlineVar:
|
||||||
|
if (systemOpCode.IsLocalStore() || systemOpCode.IsLocalLoad() || systemOpCode.IsLocalLoadByRef())
|
||||||
|
msil.Operand = new MsilOperandInline.MsilOperandLocal(msil)
|
||||||
|
{
|
||||||
|
Value = new MsilLocal(parameterDefinition.Index)
|
||||||
|
};
|
||||||
|
else
|
||||||
|
msil.Operand = new MsilOperandInline.MsilOperandArgument(msil)
|
||||||
|
{
|
||||||
|
Value = new MsilArgument(parameterDefinition.Index)
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case float @float when opType == OperandType.ShortInlineR:
|
||||||
|
msil.Operand = new MsilOperandInline.MsilOperandSingle(msil)
|
||||||
|
{
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
return msil;
|
||||||
|
}
|
||||||
|
}
|
@@ -12,6 +12,7 @@ using Mono.Cecil.Cil;
|
|||||||
using MonoMod.Utils;
|
using MonoMod.Utils;
|
||||||
using Torch.Managers.PatchManager.Transpile;
|
using Torch.Managers.PatchManager.Transpile;
|
||||||
using Torch.Utils;
|
using Torch.Utils;
|
||||||
|
using VRage.Game.VisualScripting;
|
||||||
using OpCode = System.Reflection.Emit.OpCode;
|
using OpCode = System.Reflection.Emit.OpCode;
|
||||||
using OpCodes = System.Reflection.Emit.OpCodes;
|
using OpCodes = System.Reflection.Emit.OpCodes;
|
||||||
using OperandType = System.Reflection.Emit.OperandType;
|
using OperandType = System.Reflection.Emit.OperandType;
|
||||||
@@ -88,132 +89,6 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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<FieldInfo>(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<MethodBase>(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<MemberInfo>(this)
|
|
||||||
{
|
|
||||||
Value = memberReference.ResolveReflection()
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case TypeReference typeReference when opType == OperandType.InlineType:
|
|
||||||
Operand = new MsilOperandInline.MsilOperandReflected<Type>(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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Opcode of this instruction
|
/// Opcode of this instruction
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -227,7 +102,7 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The operand for this instruction, or null.
|
/// The operand for this instruction, or null.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MsilOperand Operand { get; }
|
public MsilOperand Operand { get; internal set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Labels pointing to this instruction.
|
/// Labels pointing to this instruction.
|
||||||
@@ -284,7 +159,11 @@ namespace Torch.Managers.PatchManager.MSIL
|
|||||||
type = type.BaseType;
|
type = type.BaseType;
|
||||||
}
|
}
|
||||||
|
|
||||||
((MsilOperandInline<T>) Operand).Value = o;
|
if (Operand is not MsilOperandInline<T> operandInline)
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Type {typeof(T).FullName} is not valid operand for {Operand?.GetType().Signature()}");
|
||||||
|
|
||||||
|
operandInline.Value = o;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,6 +5,7 @@ using System.Runtime.CompilerServices;
|
|||||||
using NLog;
|
using NLog;
|
||||||
using NLog.Config;
|
using NLog.Config;
|
||||||
using Torch.Managers.PatchManager;
|
using Torch.Managers.PatchManager;
|
||||||
|
using Torch.Utils;
|
||||||
|
|
||||||
namespace Torch.Patches
|
namespace Torch.Patches
|
||||||
{
|
{
|
||||||
@@ -36,16 +37,13 @@ namespace Torch.Patches
|
|||||||
_log.Warn("GALogger constructor is unknown. Logging may not function.");
|
_log.Warn("GALogger constructor is unknown. Logging may not function.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ctx.GetPattern(ctor).Prefixes.Add(typeof(GameAnalyticsPatch).GetMethod(nameof(PatchLogger),
|
ctx.GetPattern(ctor).AddPrefix(nameof(PatchLogger));
|
||||||
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void FixLogging()
|
private static void FixLogging()
|
||||||
{
|
{
|
||||||
|
TorchLogManager.RestoreGlobalConfiguration();
|
||||||
_setLogger(null, LogManager.GetLogger("GameAnalytics"));
|
_setLogger(null, LogManager.GetLogger("GameAnalytics"));
|
||||||
if (!(LogManager.Configuration is XmlLoggingConfiguration))
|
|
||||||
LogManager.Configuration = new XmlLoggingConfiguration(Path.Combine(
|
|
||||||
Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) ?? Environment.CurrentDirectory, "NLog.config"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool PatchLogger()
|
private static bool PatchLogger()
|
||||||
|
@@ -17,6 +17,7 @@ internal static class GcCollectPatch
|
|||||||
{
|
{
|
||||||
// FUCK YO KEEN
|
// FUCK YO KEEN
|
||||||
// every call results in freeze for seconds
|
// every call results in freeze for seconds
|
||||||
|
|
||||||
private static readonly MethodBase[] _targets =
|
private static readonly MethodBase[] _targets =
|
||||||
{
|
{
|
||||||
Info.OfMethod<MyPlanetTextureMapProvider>(nameof(MyPlanetTextureMapProvider.GetHeightmap)),
|
Info.OfMethod<MyPlanetTextureMapProvider>(nameof(MyPlanetTextureMapProvider.GetHeightmap)),
|
||||||
|
@@ -103,27 +103,27 @@ namespace Torch.Patches
|
|||||||
private static bool PrefixWriteLine(MyLog __instance, string msg)
|
private static bool PrefixWriteLine(MyLog __instance, string msg)
|
||||||
{
|
{
|
||||||
if (__instance.LogEnabled && _log.IsDebugEnabled)
|
if (__instance.LogEnabled && _log.IsDebugEnabled)
|
||||||
_log.Debug($"{" ".PadRight(3 * GetIndentByCurrentThread())}{msg}");
|
_log.Debug($"{string.Empty.PadRight(3 * GetIndentByCurrentThread(), ' ')}{msg}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool PrefixWriteLineConsole(MyLog __instance, string msg)
|
private static bool PrefixWriteLineConsole(MyLog __instance, string msg)
|
||||||
{
|
{
|
||||||
if (__instance.LogEnabled && _log.IsInfoEnabled)
|
if (__instance.LogEnabled && _log.IsInfoEnabled)
|
||||||
_log.Info($"{" ".PadRight(3 * GetIndentByCurrentThread())}{msg}");
|
_log.Info($"{string.Empty.PadRight(3 * GetIndentByCurrentThread(), ' ')}{msg}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool PrefixAppendToClosedLog(MyLog __instance, string text)
|
private static bool PrefixAppendToClosedLog(MyLog __instance, string text)
|
||||||
{
|
{
|
||||||
if (__instance.LogEnabled && _log.IsDebugEnabled)
|
if (__instance.LogEnabled && _log.IsDebugEnabled)
|
||||||
_log.Debug($"{" ".PadRight(3 * GetIndentByCurrentThread())}{text}");
|
_log.Debug($"{string.Empty.PadRight(3 * GetIndentByCurrentThread(), ' ')}{text}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
private static bool PrefixWriteLineOptions(MyLog __instance, string message, LoggingOptions option)
|
private static bool PrefixWriteLineOptions(MyLog __instance, string message, LoggingOptions option)
|
||||||
{
|
{
|
||||||
if (__instance.LogEnabled && __instance.LogFlag(option) && _log.IsDebugEnabled)
|
if (__instance.LogEnabled && __instance.LogFlag(option) && _log.IsDebugEnabled)
|
||||||
_log.Info($"{" ".PadRight(3 * GetIndentByCurrentThread())}{message}");
|
_log.Info($"{string.Empty.PadRight(3 * GetIndentByCurrentThread(), ' ')}{message}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +145,7 @@ namespace Torch.Patches
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// ReSharper disable once TemplateIsNotCompileTimeConstantProblem
|
// ReSharper disable once TemplateIsNotCompileTimeConstantProblem
|
||||||
_log.Log(new(LogLevelFor(severity), _log.Name, $"{" ".PadRight(3 * GetIndentByCurrentThread())}{string.Format(format, args)}"));
|
_log.Log(new(LogLevelFor(severity), _log.Name, $"{string.Empty.PadRight(3 * GetIndentByCurrentThread(), ' ')}{string.Format(format, args)}"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -10,7 +11,6 @@ using System.Reflection.Emit;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using ProtoBuf;
|
|
||||||
using Torch.Managers.PatchManager;
|
using Torch.Managers.PatchManager;
|
||||||
using Torch.Managers.PatchManager.MSIL;
|
using Torch.Managers.PatchManager.MSIL;
|
||||||
using Torch.Utils;
|
using Torch.Utils;
|
||||||
@@ -40,16 +40,24 @@ namespace Torch.Patches
|
|||||||
context.GetPattern(Register2Method).AddTranspiler(nameof(RegisterTranspiler));
|
context.GetPattern(Register2Method).AddTranspiler(nameof(RegisterTranspiler));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WhitelistCtorPrefix(MyScriptCompiler scriptCompiler)
|
private static void WhitelistCtorPrefix(MyScriptCompiler scriptCompiler, MyScriptWhitelist __instance)
|
||||||
{
|
{
|
||||||
|
var basePath = new FileInfo(typeof(object).Assembly.Location).DirectoryName!;
|
||||||
|
|
||||||
scriptCompiler.AddReferencedAssemblies(
|
scriptCompiler.AddReferencedAssemblies(
|
||||||
|
Path.Combine(basePath, "netstandard.dll"),
|
||||||
|
Path.Combine(basePath, "mscorlib.dll"),
|
||||||
|
Path.Combine(basePath, "System.Runtime.dll"),
|
||||||
|
typeof(LinkedList<>).Assembly.Location,
|
||||||
typeof(Regex).Assembly.Location,
|
typeof(Regex).Assembly.Location,
|
||||||
typeof(Enumerable).Assembly.Location,
|
typeof(Enumerable).Assembly.Location,
|
||||||
typeof(ConcurrentBag<>).Assembly.Location,
|
typeof(ConcurrentBag<>).Assembly.Location,
|
||||||
typeof(ImmutableArray).Assembly.Location,
|
typeof(ImmutableArray).Assembly.Location,
|
||||||
typeof(System.ComponentModel.TypeConverter).Assembly.Location,
|
typeof(PropertyChangedEventArgs).Assembly.Location,
|
||||||
|
typeof(TypeConverter).Assembly.Location,
|
||||||
typeof(System.Diagnostics.TraceSource).Assembly.Location,
|
typeof(System.Diagnostics.TraceSource).Assembly.Location,
|
||||||
typeof(ProtoBuf.Meta.RuntimeTypeModel).Assembly.Location,
|
typeof(ProtoBuf.Meta.RuntimeTypeModel).Assembly.Location,
|
||||||
|
typeof(ProtoBuf.ProtoMemberAttribute).Assembly.Location,
|
||||||
Path.Combine(MyFileSystem.ExePath, "Sandbox.Game.dll"),
|
Path.Combine(MyFileSystem.ExePath, "Sandbox.Game.dll"),
|
||||||
Path.Combine(MyFileSystem.ExePath, "Sandbox.Common.dll"),
|
Path.Combine(MyFileSystem.ExePath, "Sandbox.Common.dll"),
|
||||||
Path.Combine(MyFileSystem.ExePath, "Sandbox.Graphics.dll"),
|
Path.Combine(MyFileSystem.ExePath, "Sandbox.Graphics.dll"),
|
||||||
@@ -68,6 +76,9 @@ namespace Torch.Patches
|
|||||||
MyModWatchdog.Init(updateThread);
|
MyModWatchdog.Init(updateThread);
|
||||||
MyScriptCompiler.Static.AddImplicitIngameNamespacesFromTypes(referencedTypes);
|
MyScriptCompiler.Static.AddImplicitIngameNamespacesFromTypes(referencedTypes);
|
||||||
MyScriptCompiler.Static.AddConditionalCompilationSymbols(symbols);
|
MyScriptCompiler.Static.AddConditionalCompilationSymbols(symbols);
|
||||||
|
using var batch = MyScriptCompiler.Static.Whitelist.OpenBatch();
|
||||||
|
// Dict and queue in different assemblies, microsoft being microsoft
|
||||||
|
batch.AllowNamespaceOfTypes(MyWhitelistTarget.ModApi, typeof(ConcurrentQueue<>));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,34 +1,52 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Mono.Cecil;
|
using Mono.Cecil;
|
||||||
using NLog;
|
|
||||||
|
|
||||||
namespace Torch.Plugins;
|
namespace Torch.Plugins;
|
||||||
|
|
||||||
internal static class AssemblyRewriter
|
internal static class AssemblyRewriter
|
||||||
{
|
{
|
||||||
private static readonly ILogger Log = LogManager.GetCurrentClassLogger();
|
private static readonly ZipResolver _zipResolver;
|
||||||
|
private static readonly DefaultAssemblyResolver _defaultResolver;
|
||||||
private static readonly IAssemblyResolver Resolver;
|
|
||||||
|
|
||||||
static AssemblyRewriter()
|
static AssemblyRewriter()
|
||||||
{
|
{
|
||||||
var resolver = new DefaultAssemblyResolver();
|
_defaultResolver = new();
|
||||||
Resolver = resolver;
|
_zipResolver = new(_defaultResolver);
|
||||||
resolver.AddSearchDirectory(Directory.GetCurrentDirectory());
|
_defaultResolver.AddSearchDirectory(Directory.GetCurrentDirectory());
|
||||||
resolver.AddSearchDirectory(Path.Combine(Directory.GetCurrentDirectory(), "DedicatedServer64"));
|
_defaultResolver.AddSearchDirectory(Path.Combine(Directory.GetCurrentDirectory(), "DedicatedServer64"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Assembly ProcessWeavers(this Stream stream)
|
public static Assembly ProcessWeavers(this Stream stream, ZipArchive archive)
|
||||||
{
|
{
|
||||||
|
_zipResolver.Archive = archive;
|
||||||
using var assStream = new MemoryStream();
|
using var assStream = new MemoryStream();
|
||||||
stream.CopyTo(assStream);
|
stream.CopyTo(assStream);
|
||||||
assStream.Position = 0;
|
assStream.Position = 0;
|
||||||
using var module = ModuleDefinition.ReadModule(assStream, new()
|
var ass = ProcessInternal(assStream, _zipResolver);
|
||||||
|
_zipResolver.Archive = null;
|
||||||
|
return ass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Assembly ProcessWeavers(this Stream stream, string path)
|
||||||
{
|
{
|
||||||
AssemblyResolver = Resolver
|
_defaultResolver.AddSearchDirectory(path);
|
||||||
|
using var assStream = new MemoryStream();
|
||||||
|
stream.CopyTo(assStream);
|
||||||
|
assStream.Position = 0;
|
||||||
|
var ass = ProcessInternal(assStream, _defaultResolver);
|
||||||
|
_defaultResolver.RemoveSearchDirectory(path);
|
||||||
|
return ass;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Assembly ProcessInternal(Stream inputStream, IAssemblyResolver resolver)
|
||||||
|
{
|
||||||
|
using var module = ModuleDefinition.ReadModule(inputStream, new()
|
||||||
|
{
|
||||||
|
AssemblyResolver = _zipResolver
|
||||||
});
|
});
|
||||||
foreach (var fieldDefinition in FindAllToRewrite(module))
|
foreach (var fieldDefinition in FindAllToRewrite(module))
|
||||||
{
|
{
|
||||||
@@ -47,4 +65,40 @@ internal static class AssemblyRewriter
|
|||||||
|
|
||||||
private static bool HasValidAttributes(FieldDefinition definition) =>
|
private static bool HasValidAttributes(FieldDefinition definition) =>
|
||||||
definition.CustomAttributes.Any(b => b.AttributeType.Name.Contains("Reflected") || b.AttributeType.Name == "DependencyAttribute");
|
definition.CustomAttributes.Any(b => b.AttributeType.Name.Contains("Reflected") || b.AttributeType.Name == "DependencyAttribute");
|
||||||
|
|
||||||
|
private class ZipResolver : IAssemblyResolver
|
||||||
|
{
|
||||||
|
private readonly IAssemblyResolver _fallbackResolver;
|
||||||
|
public ZipArchive Archive { get; set; }
|
||||||
|
|
||||||
|
public ZipResolver(IAssemblyResolver fallbackResolver)
|
||||||
|
{
|
||||||
|
_fallbackResolver = fallbackResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_fallbackResolver.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssemblyDefinition Resolve(AssemblyNameReference name)
|
||||||
|
{
|
||||||
|
return Resolve(name, new());
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
|
||||||
|
{
|
||||||
|
var fileName = $"{name.Name}.dll";
|
||||||
|
|
||||||
|
if (Archive.Entries.FirstOrDefault(entry => entry.Name == fileName) is not { } archiveEntry)
|
||||||
|
return _fallbackResolver.Resolve(name, parameters);
|
||||||
|
|
||||||
|
using var stream = archiveEntry.Open();
|
||||||
|
using var memStream = new MemoryStream();
|
||||||
|
stream.CopyTo(memStream);
|
||||||
|
memStream.Position = 0;
|
||||||
|
|
||||||
|
return AssemblyDefinition.ReadAssembly(memStream, parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@@ -360,7 +360,7 @@ namespace Torch.Managers
|
|||||||
|
|
||||||
|
|
||||||
using var stream = entry.Open();
|
using var stream = entry.Open();
|
||||||
assemblies.Add(stream.ProcessWeavers());
|
assemblies.Add(stream.ProcessWeavers(zipFile));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -378,7 +378,7 @@ namespace Torch.Managers
|
|||||||
// continue;
|
// continue;
|
||||||
|
|
||||||
using var stream = File.OpenRead(file);
|
using var stream = File.OpenRead(file);
|
||||||
assemblies.Add(stream.ProcessWeavers());
|
assemblies.Add(stream.ProcessWeavers(item.Path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -122,31 +122,6 @@
|
|||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<Compile Update="Views\CollectionEditor.xaml.cs">
|
|
||||||
<DependentUpon>CollectionEditor.xaml</DependentUpon>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Views\DictionaryEditor.xaml.cs">
|
|
||||||
<DependentUpon>DictionaryEditor.xaml</DependentUpon>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Views\EmbeddedCollectionEditor.xaml.cs">
|
|
||||||
<DependentUpon>EmbeddedCollectionEditor.xaml</DependentUpon>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Views\FlagsEditor.xaml.cs">
|
|
||||||
<DependentUpon>FlagsEditor.xaml</DependentUpon>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Views\ObjectCollectionEditor.xaml.cs">
|
|
||||||
<DependentUpon>ObjectCollectionEditor.xaml</DependentUpon>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Views\ObjectEditor.xaml.cs">
|
|
||||||
<DependentUpon>ObjectEditor.xaml</DependentUpon>
|
|
||||||
</Compile>
|
|
||||||
<Compile Update="Views\PropertyGrid.xaml.cs">
|
|
||||||
<DependentUpon>PropertyGrid.xaml</DependentUpon>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="..\Versioning\AssemblyVersion.cs" Link="Properties/AssemblyVersion.cs" />
|
|
||||||
<Compile Remove="Commands\Permissions\PermissionManager.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Torch.API\Torch.API.csproj" />
|
<ProjectReference Include="..\Torch.API\Torch.API.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Sandbox.Engine.Networking;
|
using Sandbox.Engine.Networking;
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
@@ -19,6 +20,43 @@ namespace Torch.Utils
|
|||||||
return new MyObjectBuilder_Checkpoint.ModItem(ulong.Parse(arr[0]), arr[1]);
|
return new MyObjectBuilder_Checkpoint.ModItem(ulong.Parse(arr[0]), arr[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool TryParse(string str, out MyObjectBuilder_Checkpoint.ModItem item)
|
||||||
|
{
|
||||||
|
item = default;
|
||||||
|
|
||||||
|
var arr = str.Split('-');
|
||||||
|
|
||||||
|
if (arr.Length is 0 or > 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!ulong.TryParse(arr[0], out var id))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (arr.Length == 1 || !TryParseServiceName(arr[1], out var serviceName))
|
||||||
|
serviceName = GetDefaultServiceName();
|
||||||
|
|
||||||
|
item = new(id, serviceName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryParseServiceName(string str, out string serviceName)
|
||||||
|
{
|
||||||
|
if (str.Equals("steam", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
serviceName = "Steam";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (str.Equals("mod.io", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
str.Equals("eos", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
serviceName = "mod.io";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceName = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//because KEEEN!
|
//because KEEEN!
|
||||||
public static string GetDefaultServiceName()
|
public static string GetDefaultServiceName()
|
||||||
{
|
{
|
||||||
|
41
Torch/Utils/TorchLogManager.cs
Normal file
41
Torch/Utils/TorchLogManager.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.Loader;
|
||||||
|
using NLog;
|
||||||
|
using NLog.Config;
|
||||||
|
using NLog.Targets;
|
||||||
|
|
||||||
|
namespace Torch.Utils;
|
||||||
|
|
||||||
|
public static class TorchLogManager
|
||||||
|
{
|
||||||
|
private static AssemblyLoadContext LoadContext = new("TorchLog");
|
||||||
|
|
||||||
|
public static LoggingConfiguration Configuration { get; private set; }
|
||||||
|
|
||||||
|
public static void SetConfiguration(LoggingConfiguration configuration)
|
||||||
|
{
|
||||||
|
Configuration = configuration;
|
||||||
|
LogManager.Configuration = configuration;
|
||||||
|
LogManager.ReconfigExistingLoggers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RegisterTargets(string dir)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(dir)) return;
|
||||||
|
|
||||||
|
foreach (var type in Directory.EnumerateFiles(dir, "*.dll").Select(LoadContext.LoadFromAssemblyPath)
|
||||||
|
.SelectMany(b => b.ExportedTypes)
|
||||||
|
.Where(b => b.GetCustomAttribute<TargetAttribute>() is { }))
|
||||||
|
{
|
||||||
|
Target.Register(type.GetCustomAttribute<TargetAttribute>()!.Name, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RestoreGlobalConfiguration()
|
||||||
|
{
|
||||||
|
SetConfiguration(Configuration);
|
||||||
|
}
|
||||||
|
}
|
@@ -472,7 +472,8 @@ namespace Torch
|
|||||||
{
|
{
|
||||||
// Kinda icky, but we can't block the update and expect the state to change.
|
// Kinda icky, but we can't block the update and expect the state to change.
|
||||||
if (Thread.CurrentThread == _updateThread)
|
if (Thread.CurrentThread == _updateThread)
|
||||||
return _state == state;
|
throw new InvalidOperationException(
|
||||||
|
"Waiting for game state is not possible from update thread (deadlock)");
|
||||||
|
|
||||||
DateTime? end = timeout.HasValue ? (DateTime?) (DateTime.Now + timeout.Value) : null;
|
DateTime? end = timeout.HasValue ? (DateTime?) (DateTime.Now + timeout.Value) : null;
|
||||||
while (_state != state && (!end.HasValue || end > DateTime.Now + TimeSpan.FromSeconds(1)))
|
while (_state != state && (!end.HasValue || end > DateTime.Now + TimeSpan.FromSeconds(1)))
|
||||||
|
21
appveyor.yml
21
appveyor.yml
@@ -11,7 +11,7 @@ platform: x64
|
|||||||
shallow_clone: true
|
shallow_clone: true
|
||||||
assembly_info:
|
assembly_info:
|
||||||
patch: true
|
patch: true
|
||||||
file: '**\AssemblyInfo.*'
|
file: '**\AssemblyVersion.*'
|
||||||
assembly_version: '{version}'
|
assembly_version: '{version}'
|
||||||
assembly_file_version: '{version}'
|
assembly_file_version: '{version}'
|
||||||
assembly_informational_version: v{version}
|
assembly_informational_version: v{version}
|
||||||
@@ -37,24 +37,21 @@ install:
|
|||||||
|
|
||||||
& "$steamCMDPath/steamcmd.exe" "+login anonymous" "+force_install_dir $steamData" "+app_update 298740" "+quit"
|
& "$steamCMDPath/steamcmd.exe" "+login anonymous" "+force_install_dir $steamData" "+app_update 298740" "+quit"
|
||||||
|
|
||||||
$dataPath = $steamData.Replace("/", "\")
|
$dataPath = $steamData.Replace("/", "\");
|
||||||
|
$contentPath = "$dataPath\Content";
|
||||||
Remove-Item -LiteralPath $dataPath\Content -Force -Recurse
|
if (Test-Path $contentPath) {
|
||||||
|
Remove-Item -LiteralPath $contentPath -Force -Recurse
|
||||||
|
}
|
||||||
|
|
||||||
cmd /S /C mklink /J .\GameBinaries $dataPath\DedicatedServer64
|
cmd /S /C mklink /J .\GameBinaries $dataPath\DedicatedServer64
|
||||||
cache:
|
cache:
|
||||||
- c:\steam\dedi\
|
- c:\steam\dedi\
|
||||||
- c:\steam\cmd\
|
- c:\steam\cmd\
|
||||||
before_build:
|
build_script:
|
||||||
- pwsh: dotnet restore .\Torch.Server\Torch.Server.csproj
|
|
||||||
build:
|
|
||||||
project: Torch.Server/Torch.Server.csproj
|
|
||||||
verbosity: minimal
|
|
||||||
after_build:
|
|
||||||
- pwsh: >-
|
- pwsh: >-
|
||||||
dotnet publish .\Torch.Server\Torch.Server.csproj --self-contained -c Release -o .\publish\ --no-build
|
dotnet publish .\Torch.Server\Torch.Server.csproj --self-contained -f net6-windows -r win-x64 -c Release -o .\publish\
|
||||||
|
|
||||||
Compress-Archive -Path .\publish\ -DestinationPath torch-server.zip
|
Compress-Archive -Path .\publish\* -DestinationPath .\torch-server.zip
|
||||||
artifacts:
|
artifacts:
|
||||||
- path: torch-server.zip
|
- path: torch-server.zip
|
||||||
deploy:
|
deploy:
|
||||||
|
Reference in New Issue
Block a user