updated NLog to v5

fixed most of issues with world creating/loading
fixed log window lags
fixed some compiler warnings
fixed empty log files creating
fixed logging performance
added better logging of load process
This commit is contained in:
z__
2022-02-02 14:09:08 +07:00
parent ab61674b47
commit 70833adb44
29 changed files with 304 additions and 298 deletions

View File

@@ -4,14 +4,17 @@
<variable name="logStamp" value="${time} ${pad:padding=-8:inner=[${level:uppercase=true}]}" /> <variable name="logStamp" value="${time} ${pad:padding=-8:inner=[${level:uppercase=true}]}" />
<variable name="logContent" value="${message:withException=true}"/> <variable name="logContent" value="${message:withException=true}"/>
<targets async="true"> <targets>
<default-wrapper xsi:type="AsyncWrapper" overflowAction="Block" optimizeBufferReuse="true" />
<target xsi:type="Null" name="null" formatMessage="false" /> <target xsi:type="Null" name="null" formatMessage="false" />
<target xsi:type="File" name="keen" layout="${var:logStamp} ${logger}: ${var:logContent}" fileName="Logs\Keen-${shortdate}.log" /> <target xsi:type="File" keepFileOpen="true" concurrentWrites="false" name="keen" layout="${var:logStamp} ${logger}: ${var:logContent}"
<target xsi:type="File" name="main" layout="${var:logStamp} ${logger}: ${var:logContent}" fileName="Logs\Torch-${shortdate}.log" /> fileName="Logs\Keen-${shortdate}.log" />
<target xsi:type="File" keepFileOpen="true" concurrentWrites="false" name="main" layout="${var:logStamp} ${logger}: ${var:logContent}"
fileName="Logs\Torch-${shortdate}.log" />
<target xsi:type="File" name="chat" layout="${longdate} ${message}" fileName="Logs\Chat.log" /> <target xsi:type="File" name="chat" layout="${longdate} ${message}" fileName="Logs\Chat.log" />
<target xsi:type="ColoredConsole" name="console" layout="${var:logStamp} ${logger:shortName=true}: ${var:logContent}" /> <target xsi:type="ColoredConsole" name="console" layout="${var:logStamp} ${logger:shortName=true}: ${var:logContent}" />
<target xsi:type="File" name="patch" layout="${var:logContent}" fileName="Logs\patch.log"/> <target xsi:type="File" name="patch" layout="${var:logContent}" fileName="Logs\patch.log"/>
<target xsi:type="FlowDocument" name="wpf" layout="${var:logStamp} ${logger:shortName=true}: ${var:logContent}" /> <target xsi:type="LogViewerTarget" name="wpf" layout="[${level:uppercase=true}] ${logger:shortName=true}: ${var:logContent}" />
</targets> </targets>
<rules> <rules>

View File

@@ -29,7 +29,7 @@ namespace Torch
int WindowHeight { get; set; } int WindowHeight { get; set; }
int FontSize { get; set; } int FontSize { get; set; }
UGCServiceType UgcServiceType { get; set; } UGCServiceType UgcServiceType { get; set; }
bool EntityManagerEnabled { get; set; }
void Save(string path = null); void Save(string path = null);
} }
} }

View File

@@ -23,6 +23,11 @@ namespace Torch.API.Session
/// </summary> /// </summary>
MySession KeenSession { get; } MySession KeenSession { get; }
/// <summary>
/// Currently running world
/// </summary>
IWorld World { get; }
/// <inheritdoc cref="IDependencyManager"/> /// <inheritdoc cref="IDependencyManager"/>
IDependencyManager Managers { get; } IDependencyManager Managers { get; }

View File

@@ -17,7 +17,7 @@
</PropertyGroup> </PropertyGroup>
<!-- <Import Project="$(SolutionDir)\TransformOnBuild.targets" /> --> <!-- <Import Project="$(SolutionDir)\TransformOnBuild.targets" /> -->
<ItemGroup> <ItemGroup>
<PackageReference Include="NLog" Version="4.7.13" /> <PackageReference Include="NLog" Version="5.0.0-rc2" />
<PackageReference Include="SemanticVersioning" Version="2.0.0" /> <PackageReference Include="SemanticVersioning" Version="2.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -18,7 +18,7 @@
<!-- <Import Project="$(SolutionDir)\TransformOnBuild.targets" /> --> <!-- <Import Project="$(SolutionDir)\TransformOnBuild.targets" /> -->
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="NLog" Version="4.7.13" /> <PackageReference Include="NLog" Version="5.0.0-rc2" />
<PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit" Version="2.4.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -1,54 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Documents;
using System.Windows.Media;
using NLog;
using NLog.Targets;
namespace Torch.Server
{
/// <summary>
/// NLog target that writes to a <see cref="FlowDocument"/>.
/// </summary>
[Target("flowDocument")]
public sealed class FlowDocumentTarget : TargetWithLayout
{
private FlowDocument _document = new FlowDocument { Background = new SolidColorBrush(Colors.Black) };
private readonly Paragraph _paragraph = new Paragraph();
private readonly int _maxLines = 500;
public FlowDocument Document => _document;
public FlowDocumentTarget()
{
_document.Blocks.Add(_paragraph);
}
/// <inheritdoc />
protected override void Write(LogEventInfo logEvent)
{
_document.Dispatcher.BeginInvoke(() =>
{
var message = $"{Layout.Render(logEvent)}\n";
_paragraph.Inlines.Add(new Run(message) {Foreground = LogLevelColors[logEvent.Level]});
// A massive paragraph slows the UI down
if (_paragraph.Inlines.Count > _maxLines)
_paragraph.Inlines.Remove(_paragraph.Inlines.FirstInline);
});
}
private static readonly Dictionary<LogLevel, SolidColorBrush> LogLevelColors = new Dictionary<LogLevel, SolidColorBrush>
{
[LogLevel.Trace] = new SolidColorBrush(Colors.DimGray),
[LogLevel.Debug] = new SolidColorBrush(Colors.DarkGray),
[LogLevel.Info] = new SolidColorBrush(Colors.White),
[LogLevel.Warn] = new SolidColorBrush(Colors.Magenta),
[LogLevel.Error] = new SolidColorBrush(Colors.Yellow),
[LogLevel.Fatal] = new SolidColorBrush(Colors.Red),
};
}
}

View File

@@ -5,6 +5,7 @@ using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Http;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
@@ -156,6 +157,10 @@ quit";
gameThread.Start(); gameThread.Start();
var ui = new TorchUI(_server); var ui = new TorchUI(_server);
SynchronizationContext.SetSynchronizationContext(
new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher));
ui.ShowDialog(); ui.ShowDialog();
} }
} }
@@ -192,8 +197,9 @@ quit";
try try
{ {
log.Info("Downloading SteamCMD."); log.Info("Downloading SteamCMD.");
using (var client = new WebClient()) using (var client = new HttpClient())
client.DownloadFile("https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip", STEAMCMD_ZIP); using (var file = File.Create(STEAMCMD_ZIP))
client.GetStreamAsync("https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip").Result.CopyTo(file);
ZipFile.ExtractToDirectory(STEAMCMD_ZIP, STEAMCMD_DIR); ZipFile.ExtractToDirectory(STEAMCMD_ZIP, STEAMCMD_DIR);
File.Delete(STEAMCMD_ZIP); File.Delete(STEAMCMD_ZIP);

View File

@@ -0,0 +1,51 @@
using System.Collections.Generic;
using System.Threading;
using System.Windows.Media;
using System.Windows.Threading;
using NLog;
using NLog.Targets;
using Torch.Server.ViewModels;
using Torch.Server.Views;
namespace Torch.Server
{
/// <summary>
/// NLog target that writes to a <see cref="LogViewerControl"/>.
/// </summary>
[Target("logViewer")]
public sealed class LogViewerTarget : TargetWithLayout
{
public IList<LogEntry> LogEntries { get; set; }
public SynchronizationContext TargetContext { get; set; }
private readonly int _maxLines = 1000;
/// <inheritdoc />
protected override void Write(LogEventInfo logEvent)
{
TargetContext?.Post(_sendOrPostCallback, logEvent);
}
private void WriteCallback(object state)
{
var logEvent = (LogEventInfo) state;
LogEntries?.Add(new(logEvent.TimeStamp, Layout.Render(logEvent), LogLevelColors[logEvent.Level]));
}
private static readonly Dictionary<LogLevel, SolidColorBrush> LogLevelColors = new()
{
[LogLevel.Trace] = new SolidColorBrush(Colors.DimGray),
[LogLevel.Debug] = new SolidColorBrush(Colors.DarkGray),
[LogLevel.Info] = new SolidColorBrush(Colors.White),
[LogLevel.Warn] = new SolidColorBrush(Colors.Magenta),
[LogLevel.Error] = new SolidColorBrush(Colors.Yellow),
[LogLevel.Fatal] = new SolidColorBrush(Colors.Red),
};
private readonly SendOrPostCallback _sendOrPostCallback;
public LogViewerTarget()
{
_sendOrPostCallback = WriteCallback;
}
}
}

View File

@@ -5,6 +5,7 @@ using System.ComponentModel;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.Serialization;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Havok; using Havok;
@@ -30,7 +31,7 @@ using VRage.Plugins;
namespace Torch.Server.Managers namespace Torch.Server.Managers
{ {
public class InstanceManager : Manager public class InstanceManager : Manager, IInstanceManager
{ {
private const string CONFIG_NAME = "SpaceEngineers-Dedicated.cfg"; private const string CONFIG_NAME = "SpaceEngineers-Dedicated.cfg";
@@ -45,6 +46,8 @@ namespace Torch.Server.Managers
} }
public IWorld SelectedWorld => DedicatedConfig.SelectedWorld;
public void LoadInstance(string path, bool validate = true) public void LoadInstance(string path, bool validate = true)
{ {
Log.Info($"Loading instance {path}"); Log.Info($"Loading instance {path}");
@@ -221,14 +224,11 @@ namespace Torch.Server.Managers
public void SaveConfig() public void SaveConfig()
{ {
if (((TorchServer)Torch).HasRun) if (!((TorchServer)Torch).HasRun)
{ {
Log.Warn("Checkpoint cache is stale, not saving dedicated config.");
return;
}
DedicatedConfig.Save(Path.Combine(Torch.Config.InstancePath, CONFIG_NAME)); DedicatedConfig.Save(Path.Combine(Torch.Config.InstancePath, CONFIG_NAME));
Log.Info("Saved dedicated config."); Log.Info("Saved dedicated config.");
}
try try
{ {
@@ -255,7 +255,7 @@ namespace Torch.Server.Managers
} }
catch (Exception e) catch (Exception e)
{ {
Log.Error("Failed to write sandbox config, changes will not appear on server"); Log.Error("Failed to write sandbox config");
Log.Error(e); Log.Error(e);
} }
} }
@@ -276,12 +276,14 @@ namespace Torch.Server.Managers
} }
} }
public class WorldViewModel : ViewModel public class WorldViewModel : ViewModel, IWorld
{ {
private static readonly Logger Log = LogManager.GetCurrentClassLogger(); private static readonly Logger Log = LogManager.GetCurrentClassLogger();
public string FolderName { get; set; } public string FolderName { get; set; }
public string WorldPath { get; } public string WorldPath { get; }
public MyObjectBuilder_SessionSettings KeenSessionSettings => WorldConfiguration.Settings;
public MyObjectBuilder_Checkpoint KeenCheckpoint => Checkpoint;
public long WorldSizeKB { get; } public long WorldSizeKB { get; }
private string _checkpointPath; private string _checkpointPath;
private string _worldConfigPath; private string _worldConfigPath;
@@ -329,13 +331,15 @@ namespace Torch.Server.Managers
public void LoadSandbox() public void LoadSandbox()
{ {
MyObjectBuilderSerializer.DeserializeXML(_checkpointPath, out MyObjectBuilder_Checkpoint checkpoint); if (!MyObjectBuilderSerializer.DeserializeXML(_checkpointPath, out MyObjectBuilder_Checkpoint checkpoint))
throw new SerializationException("Error reading checkpoint, see keen log for details");
Checkpoint = new CheckpointViewModel(checkpoint); Checkpoint = new CheckpointViewModel(checkpoint);
// migrate old saves // migrate old saves
if (File.Exists(_worldConfigPath)) if (File.Exists(_worldConfigPath))
{ {
MyObjectBuilderSerializer.DeserializeXML(_worldConfigPath, out MyObjectBuilder_WorldConfiguration worldConfig); if (!MyObjectBuilderSerializer.DeserializeXML(_worldConfigPath, out MyObjectBuilder_WorldConfiguration worldConfig))
throw new SerializationException("Error reading settings, see keen log for details");
WorldConfiguration = new WorldConfigurationViewModel(worldConfig); WorldConfiguration = new WorldConfigurationViewModel(worldConfig);
} }
else else

View File

@@ -25,7 +25,7 @@ namespace Torch.Server
[STAThread] [STAThread]
public static void Main(string[] args) public static void Main(string[] args)
{ {
Target.Register<FlowDocumentTarget>("FlowDocument"); 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 = new FileInfo(typeof(Program).Assembly.Location).Directory!.FullName; var workingDir = new FileInfo(typeof(Program).Assembly.Location).Directory!.FullName;
var binDir = Path.Combine(workingDir, "DedicatedServer64"); var binDir = Path.Combine(workingDir, "DedicatedServer64");

View File

@@ -3,7 +3,7 @@
"profiles": { "profiles": {
"Torch.Server": { "Torch.Server": {
"commandName": "Project", "commandName": "Project",
"commandLineArgs": "-noupdate",
"use64Bit": true, "use64Bit": true,
"hotReloadEnabled": false "hotReloadEnabled": false
} }

View File

@@ -39,12 +39,13 @@
</PropertyGroup> </PropertyGroup>
<!-- <Import Project="$(SolutionDir)\TransformOnBuild.targets" /> --> <!-- <Import Project="$(SolutionDir)\TransformOnBuild.targets" /> -->
<ItemGroup> <ItemGroup>
<PackageReference Include="AutoCompleteTextBox" Version="1.3.0" />
<PackageReference Include="Ben.Demystifier" Version="0.4.1" /> <PackageReference Include="Ben.Demystifier" Version="0.4.1" />
<PackageReference Include="ControlzEx" Version="5.0.1" /> <PackageReference Include="ControlzEx" Version="5.0.1" />
<PackageReference Include="MahApps.Metro" Version="2.4.9" /> <PackageReference Include="MahApps.Metro" Version="2.4.9" />
<PackageReference Include="MdXaml" Version="1.12.0" /> <PackageReference Include="MdXaml" Version="1.12.0" />
<PackageReference Include="Microsoft.Diagnostics.Runtime" Version="2.0.226801" /> <PackageReference Include="Microsoft.Diagnostics.Runtime" Version="2.0.226801" />
<PackageReference Include="NLog" Version="4.7.13" /> <PackageReference Include="NLog" Version="5.0.0-rc2" />
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" PrivateAssets="all" /> <PackageReference Include="PropertyChanged.Fody" Version="3.4.0" PrivateAssets="all" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.Management" Version="6.0.0" /> <PackageReference Include="System.Management" Version="6.0.0" />

View File

@@ -10,6 +10,7 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Diagnostics.Runtime; using Microsoft.Diagnostics.Runtime;
using NLog; using NLog;
using PropertyChanged;
using Sandbox; using Sandbox;
using Sandbox.Engine.Multiplayer; using Sandbox.Engine.Multiplayer;
using Sandbox.Game.Multiplayer; using Sandbox.Game.Multiplayer;
@@ -212,6 +213,7 @@ namespace Torch.Server
Environment.Exit(0); Environment.Exit(0);
} }
[SuppressPropertyChangedWarnings]
private void OnSessionStateChanged(ITorchSession session, TorchSessionState newState) private void OnSessionStateChanged(ITorchSession session, TorchSessionState newState)
{ {
if (newState == TorchSessionState.Unloading || newState == TorchSessionState.Unloaded) if (newState == TorchSessionState.Unloading || newState == TorchSessionState.Unloaded)

View File

@@ -18,11 +18,6 @@ namespace Torch.Server.ViewModels
private MyConfigDedicated<MyObjectBuilder_SessionSettings> _config; private MyConfigDedicated<MyObjectBuilder_SessionSettings> _config;
public MyConfigDedicated<MyObjectBuilder_SessionSettings> Model => _config; public MyConfigDedicated<MyObjectBuilder_SessionSettings> Model => _config;
public ConfigDedicatedViewModel() : this(new MyConfigDedicated<MyObjectBuilder_SessionSettings>(""))
{
}
public ConfigDedicatedViewModel(MyConfigDedicated<MyObjectBuilder_SessionSettings> configDedicated) public ConfigDedicatedViewModel(MyConfigDedicated<MyObjectBuilder_SessionSettings> configDedicated)
{ {
_config = configDedicated; _config = configDedicated;
@@ -36,8 +31,7 @@ namespace Torch.Server.ViewModels
Validate(); Validate();
_config.SessionSettings = SessionSettings; _config.SessionSettings = SessionSettings;
// Never ever _config.IgnoreLastSession = true;
//_config.IgnoreLastSession = true;
_config.Save(path); _config.Save(path);
} }
@@ -73,8 +67,9 @@ namespace Torch.Server.ViewModels
} }
} }
public async Task UpdateAllModInfosAsync() public Task UpdateAllModInfosAsync()
{ {
return Task.CompletedTask;
/*if (!Mods.Any()) /*if (!Mods.Any())
return; return;
List<MyWorkshopItem> modInfos; List<MyWorkshopItem> modInfos;

View File

@@ -85,8 +85,9 @@ namespace Torch.Server.ViewModels
/// via the Steam web API. /// via the Steam web API.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public async Task<bool> UpdateModInfoAsync() public Task<bool> UpdateModInfoAsync()
{ {
return Task.FromResult(true);
/*if (UgcService.ToLower() == "mod.io") /*if (UgcService.ToLower() == "mod.io")
return true; return true;
@@ -104,7 +105,6 @@ namespace Torch.Server.ViewModels
Log.Info("Mod Info successfully retrieved!"); Log.Info("Mod Info successfully retrieved!");
FriendlyName = modInfo.Title; FriendlyName = modInfo.Title;
Description = modInfo.Description;*/ Description = modInfo.Description;*/
return true;
} }
public override string ToString() public override string ToString()

View File

@@ -3,6 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:editors="http://wpfcontrols.com/"
mc:Ignorable="d"> mc:Ignorable="d">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
@@ -18,7 +19,7 @@
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Button Grid.Column="1" Content="Send" DockPanel.Dock="Right" Width="50" Margin="5" Click="SendButton_Click"></Button> <Button Grid.Column="1" Content="Send" DockPanel.Dock="Right" Width="50" Margin="5" Click="SendButton_Click"></Button>
<TextBox Grid.Column="0" x:Name="Message" Margin="5" KeyDown="Message_OnKeyDown"></TextBox> <editors:AutoCompleteTextBox Grid.Column="0" Margin="5" KeyDown="Message_OnKeyDown" x:Name="MessageBox" />
</Grid> </Grid>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@@ -28,7 +28,9 @@ using Torch.API.Managers;
using Torch.API.Session; using Torch.API.Session;
using Torch.Managers; using Torch.Managers;
using Torch.Server.Managers; using Torch.Server.Managers;
using Torch.Server.Views;
using VRage.Game; using VRage.Game;
using Color = VRageMath.Color;
namespace Torch.Server namespace Torch.Server
{ {
@@ -38,12 +40,17 @@ namespace Torch.Server
public partial class ChatControl : UserControl public partial class ChatControl : UserControl
{ {
private static Logger _log = LogManager.GetCurrentClassLogger(); private static Logger _log = LogManager.GetCurrentClassLogger();
private ITorchServer _server; #pragma warning disable CS0618
private ITorchServer _server = (ITorchServer) TorchBase.Instance;
#pragma warning restore CS0618
private readonly LinkedList<string> _lastMessages = new();
private LinkedListNode<string> _currentLastMessageNode;
public ChatControl() public ChatControl()
{ {
InitializeComponent(); InitializeComponent();
this.IsVisibleChanged += OnIsVisibleChanged; this.IsVisibleChanged += OnIsVisibleChanged;
MessageBox.Provider = new CommandSuggestionsProvider(_server);
} }
private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
@@ -57,8 +64,8 @@ namespace Torch.Server
Dispatcher.Invoke(() => Dispatcher.Invoke(() =>
{ {
Message.Focus(); MessageBox.Focus();
Keyboard.Focus(Message); Keyboard.Focus(MessageBox);
}); });
}); });
} }
@@ -160,35 +167,50 @@ namespace Torch.Server
private void Message_OnKeyDown(object sender, KeyEventArgs e) private void Message_OnKeyDown(object sender, KeyEventArgs e)
{ {
if (e.Key == Key.Enter) switch (e.Key)
{
case Key.Enter:
OnMessageEntered(); OnMessageEntered();
break;
case Key.Up:
_currentLastMessageNode = _currentLastMessageNode?.Previous ?? _lastMessages.Last;
MessageBox.Text = _currentLastMessageNode?.Value ?? string.Empty;
break;
case Key.Down:
_currentLastMessageNode = _currentLastMessageNode?.Next ?? _lastMessages.First;
MessageBox.Text = _currentLastMessageNode?.Value ?? string.Empty;
break;
}
} }
private void OnMessageEntered() private void OnMessageEntered()
{ {
//Can't use Message.Text directly because of object ownership in WPF. //Can't use Message.Text directly because of object ownership in WPF.
var text = Message.Text; var text = MessageBox.Text;
if (string.IsNullOrEmpty(text)) if (string.IsNullOrEmpty(text))
return; return;
var commands = _server.CurrentSession?.Managers.GetManager<Torch.Commands.CommandManager>(); var commands = _server.CurrentSession?.Managers.GetManager<Torch.Commands.CommandManager>();
if (commands != null && commands.IsCommand(text)) if (commands != null && commands.IsCommand(text))
{ {
InsertMessage(new TorchChatMessage(TorchBase.Instance.Config.ChatName, text, TorchBase.Instance.Config.ChatColor)); InsertMessage(new(_server.Config.ChatName, text, Color.Red, _server.Config.ChatColor));
_server.Invoke(() => _server.Invoke(() =>
{ {
if (!commands.HandleCommandFromServer(text, InsertMessage)) if (commands.HandleCommandFromServer(text, InsertMessage)) return;
{ InsertMessage(new(_server.Config.ChatName, "Invalid command.", Color.Red, _server.Config.ChatColor));
InsertMessage(new TorchChatMessage(TorchBase.Instance.Config.ChatName, "Invalid command.", TorchBase.Instance.Config.ChatColor));
return;
}
}); });
} }
else else
{ {
_server.CurrentSession?.Managers.GetManager<IChatManagerClient>().SendMessageAsSelf(text); _server.CurrentSession?.Managers.GetManager<IChatManagerClient>().SendMessageAsSelf(text);
} }
Message.Text = ""; if (_currentLastMessageNode is { } && _currentLastMessageNode.Value == text)
{
_lastMessages.Remove(_currentLastMessageNode);
}
_lastMessages.AddLast(text);
_currentLastMessageNode = null;
MessageBox.Text = "";
} }
} }
} }

View File

@@ -16,9 +16,6 @@
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>
</UserControl.Resources> </UserControl.Resources>
<UserControl.DataContext>
<viewModels:ConfigDedicatedViewModel />
</UserControl.DataContext>
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
@@ -58,7 +55,7 @@
<RowDefinition /> <RowDefinition />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<ScrollViewer VerticalScrollBarVisibility="Auto"> <ScrollViewer VerticalScrollBarVisibility="Auto" x:Name="DediConfigScrollViewer">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
@@ -133,7 +130,7 @@
</Grid> </Grid>
<TabControl Grid.Column="1" Margin="3"> <TabControl Grid.Column="1" Margin="3">
<TabItem Header="World"> <TabItem Header="World">
<views:PropertyGrid DataContext="{Binding SessionSettings}" IgnoreDisplay ="True" /> <views:PropertyGrid DataContext="{Binding SessionSettings}" />
</TabItem> </TabItem>
<TabItem Header="Torch"> <TabItem Header="Torch">
<views:PropertyGrid x:Name="TorchSettings" /> <views:PropertyGrid x:Name="TorchSettings" />

View File

@@ -8,6 +8,8 @@ using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Threading; using System.Windows.Threading;
using Sandbox;
using Torch.API;
using Torch.API.Managers; using Torch.API.Managers;
using Torch.Server.Annotations; using Torch.Server.Annotations;
using Torch.Server.Managers; using Torch.Server.Managers;
@@ -32,15 +34,26 @@ namespace Torch.Server.Views
public ConfigControl() public ConfigControl()
{ {
InitializeComponent(); #pragma warning disable CS0618
_instanceManager = TorchBase.Instance.Managers.GetManager<InstanceManager>(); var instance = TorchBase.Instance;
#pragma warning restore CS0618
instance.GameStateChanged += InstanceOnGameStateChanged;
_instanceManager = instance.Managers.GetManager<InstanceManager>();
_instanceManager.InstanceLoaded += _instanceManager_InstanceLoaded; _instanceManager.InstanceLoaded += _instanceManager_InstanceLoaded;
DataContext = _instanceManager.DedicatedConfig; DataContext = _instanceManager.DedicatedConfig;
TorchSettings.DataContext = (TorchConfig)TorchBase.Instance.Config; InitializeComponent();
TorchSettings.DataContext = (TorchConfig)instance.Config;
// Gets called once all children are loaded // Gets called once all children are loaded
Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(ApplyStyles)); Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(ApplyStyles));
} }
private void InstanceOnGameStateChanged(MySandboxGame game, TorchGameState newState)
{
if (newState > TorchGameState.Creating)
Dispatcher.InvokeAsync(() => DediConfigScrollViewer.IsEnabled = false);
}
private void CheckValid() private void CheckValid()
{ {
ConfigValid = !_bindingExpressions.Any(x => x.HasError); ConfigValid = !_bindingExpressions.Any(x => x.HasError);

View File

@@ -25,9 +25,6 @@
</Style> </Style>
</ResourceDictionary> </ResourceDictionary>
</UserControl.Resources> </UserControl.Resources>
<UserControl.DataContext>
<viewModels:ConfigDedicatedViewModel />
</UserControl.DataContext>
<Grid Style="{StaticResource RootGridStyle}"> <Grid Style="{StaticResource RootGridStyle}">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="500px"/> <ColumnDefinition Width="500px"/>

View File

@@ -17,11 +17,6 @@
<converters:InverseBooleanConverter x:Key="InverseBool"/> <converters:InverseBooleanConverter x:Key="InverseBool"/>
</ResourceDictionary> </ResourceDictionary>
</Window.Resources> </Window.Resources>
<!--
<Window.DataContext>
<local:TorchServer/>
</Window.DataContext>
-->
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition>
@@ -63,10 +58,10 @@
</StackPanel> </StackPanel>
<TabControl Grid.Row="2" Height="Auto" x:Name="TabControl" Margin="5,10,5,5"> <TabControl Grid.Row="2" Height="Auto" x:Name="TabControl" Margin="5,10,5,5">
<TabItem Header="Log"> <TabItem Header="Log">
<RichTextBox x:Name="ConsoleText" VerticalScrollBarVisibility="Visible" FontFamily="Consolas" IsReadOnly="True" Background="#0c0c0c"/> <views:LogViewerControl x:Name="ConsoleText" Margin="3" />
</TabItem> </TabItem>
<TabItem Header="Configuration"> <TabItem Header="Configuration">
<Grid IsEnabled="{Binding Path=HasRun, Converter={StaticResource InverseBool}}"> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
<RowDefinition/> <RowDefinition/>
@@ -93,7 +88,7 @@
<local:PlayerListControl Grid.Column="1" x:Name="PlayerList" DockPanel.Dock="Right"/> <local:PlayerListControl Grid.Column="1" x:Name="PlayerList" DockPanel.Dock="Right"/>
</Grid> </Grid>
</TabItem> </TabItem>
<TabItem Header="Entity Manager" x:Name="EntityManagerTab"> <TabItem Header="Entity Manager" x:Name="EntityManagerTab" IsEnabled="{Binding Config.EntityManagerEnabled}">
</TabItem> </TabItem>
<TabItem Header="Plugins"> <TabItem Header="Plugins">
<views:PluginsControl x:Name="Plugins" /> <views:PluginsControl x:Name="Plugins" />

View File

@@ -14,12 +14,14 @@ using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Navigation; using System.Windows.Navigation;
using System.Windows.Shapes; using System.Windows.Shapes;
using System.Windows.Threading;
using NLog; using NLog;
using NLog.Targets.Wrappers; using NLog.Targets.Wrappers;
using Sandbox; using Sandbox;
using Torch.API; using Torch.API;
using Torch.API.Managers; using Torch.API.Managers;
using Torch.Server.Managers; using Torch.Server.Managers;
using Torch.Server.ViewModels;
using Torch.Server.Views; using Torch.Server.Views;
using MessageBoxResult = System.Windows.MessageBoxResult; using MessageBoxResult = System.Windows.MessageBoxResult;
@@ -30,23 +32,22 @@ namespace Torch.Server
/// </summary> /// </summary>
public partial class TorchUI : Window public partial class TorchUI : Window
{ {
private TorchServer _server; private readonly TorchServer _server;
private TorchConfig _config; private ITorchConfig Config => _server.Config;
private bool _autoscrollLog = true;
public TorchUI(TorchServer server) public TorchUI(TorchServer server)
{ {
WindowStartupLocation = WindowStartupLocation.Manual;
_config = (TorchConfig)server.Config;
Width = _config.WindowWidth;
Height = _config.WindowHeight;
_server = server; _server = server;
//TODO: data binding for whole server //TODO: data binding for whole server
DataContext = server; DataContext = server;
InitializeComponent();
AttachConsole(); WindowStartupLocation = WindowStartupLocation.Manual;
Width = Config.WindowWidth;
Height = Config.WindowHeight;
InitializeComponent();
ConsoleText.FontSize = Config.FontSize;
Loaded += OnLoaded;
//Left = _config.WindowPosition.X; //Left = _config.WindowPosition.X;
//Top = _config.WindowPosition.Y; //Top = _config.WindowPosition.Y;
@@ -56,94 +57,35 @@ namespace Torch.Server
Chat.BindServer(server); Chat.BindServer(server);
PlayerList.BindServer(server); PlayerList.BindServer(server);
Plugins.BindServer(server); Plugins.BindServer(server);
LoadConfig((TorchConfig)server.Config);
Themes.uiSource = this; if (Config.EntityManagerEnabled)
Themes.SetConfig(_config); {
Title = $"{_config.InstanceName} - Torch {server.TorchVersion}, SE {server.GameVersion}"; EntityManagerTab.Content = new EntitiesControl();
Loaded += TorchUI_Loaded;
} }
private void TorchUI_Loaded(object sender, RoutedEventArgs e) Themes.uiSource = this;
Themes.SetConfig((TorchConfig) Config);
Title = $"{Config.InstanceName} - Torch {server.TorchVersion}, SE {server.GameVersion}";
}
private void OnLoaded(object sender, RoutedEventArgs e)
{ {
var scrollViewer = FindDescendant<ScrollViewer>(ConsoleText); AttachConsole();
scrollViewer.ScrollChanged += ConsoleText_OnScrollChanged;
} }
private void AttachConsole() private void AttachConsole()
{ {
const string target = "wpf"; const string targetName = "wpf";
var doc = LogManager.Configuration.FindTargetByName<FlowDocumentTarget>(target)?.Document; var target = LogManager.Configuration.FindTargetByName<LogViewerTarget>(targetName);
if (doc == null) if (target == null)
{ {
var wrapped = LogManager.Configuration.FindTargetByName<WrapperTargetBase>(target); var wrapped = LogManager.Configuration.FindTargetByName<WrapperTargetBase>(targetName);
doc = (wrapped?.WrappedTarget as FlowDocumentTarget)?.Document; target = wrapped?.WrappedTarget as LogViewerTarget;
} }
ConsoleText.FontSize = _config.FontSize; if (target is null) return;
ConsoleText.Document = doc ?? new FlowDocument(new Paragraph(new Run("No target!"))); var viewModel = (LogViewerViewModel)ConsoleText.DataContext;
ConsoleText.TextChanged += ConsoleText_OnTextChanged; target.LogEntries = viewModel.LogEntries;
} target.TargetContext = SynchronizationContext.Current;
public static T FindDescendant<T>(DependencyObject obj) where T : DependencyObject
{
if (obj == null) return default(T);
int numberChildren = VisualTreeHelper.GetChildrenCount(obj);
if (numberChildren == 0) return default(T);
for (int i = 0; i < numberChildren; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child is T)
{
return (T)child;
}
}
for (int i = 0; i < numberChildren; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
var potentialMatch = FindDescendant<T>(child);
if (potentialMatch != default(T))
{
return potentialMatch;
}
}
return default(T);
}
private void ConsoleText_OnTextChanged(object sender, TextChangedEventArgs args)
{
var textBox = (RichTextBox) sender;
if (_autoscrollLog)
ConsoleText.ScrollToEnd();
}
private void ConsoleText_OnScrollChanged(object sender, ScrollChangedEventArgs e)
{
var scrollViewer = (ScrollViewer) sender;
if (e.ExtentHeightChange == 0)
{
// User change.
_autoscrollLog = scrollViewer.VerticalOffset == scrollViewer.ScrollableHeight;
}
}
public void LoadConfig(TorchConfig config)
{
if (!Directory.Exists(config.InstancePath))
return;
_config = config;
Dispatcher.Invoke(() =>
{
EntityManagerTab.IsEnabled = _config.EntityManagerEnabled;
if (_config.EntityManagerEnabled)
{
EntityManagerTab.Content = new EntitiesControl();
}
});
} }
private void BtnStart_Click(object sender, RoutedEventArgs e) private void BtnStart_Click(object sender, RoutedEventArgs e)
@@ -176,21 +118,5 @@ namespace Torch.Server
Process.GetCurrentProcess().Kill(); Process.GetCurrentProcess().Kill();
} }
private void BtnRestart_Click(object sender, RoutedEventArgs e)
{
//MySandboxGame.Static.Invoke(MySandboxGame.ReloadDedicatedServerSession); use i
}
private void InstancePathBox_OnLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
var name = ((TextBox)sender).Text;
if (!Directory.Exists(name))
return;
_config.InstancePath = name;
_server.Managers.GetManager<InstanceManager>().LoadInstance(_config.InstancePath);
}
} }
} }

View File

@@ -19,7 +19,7 @@
<!-- <Import Project="$(SolutionDir)\TransformOnBuild.targets" /> --> <!-- <Import Project="$(SolutionDir)\TransformOnBuild.targets" /> -->
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="NLog" Version="4.7.13" /> <PackageReference Include="NLog" Version="5.0.0-rc2" />
<PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit" Version="2.4.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -50,11 +50,12 @@ namespace Torch.Commands
return !string.IsNullOrEmpty(command) && command[0] == Prefix; return !string.IsNullOrEmpty(command) && command[0] == Prefix;
} }
public void RegisterCommandModule(Type moduleType, ITorchPlugin plugin = null) public int RegisterCommandModule(Type moduleType, ITorchPlugin plugin = null)
{ {
if (!moduleType.IsSubclassOf(typeof(CommandModule))) if (!moduleType.IsSubclassOf(typeof(CommandModule)))
return; return 0;
var i = 0;
foreach (var method in moduleType.GetMethods()) foreach (var method in moduleType.GetMethods())
{ {
var commandAttrib = method.GetCustomAttribute<CommandAttribute>(); var commandAttrib = method.GetCustomAttribute<CommandAttribute>();
@@ -63,11 +64,14 @@ namespace Torch.Commands
var command = new Command(plugin, method); var command = new Command(plugin, method);
var cmdPath = string.Join(".", command.Path); var cmdPath = string.Join(".", command.Path);
_log.Info($"Registering command '{cmdPath}'"); _log.Debug($"Registering command '{cmdPath}'");
i++;
if (!Commands.AddCommand(command)) if (!Commands.AddCommand(command))
_log.Error($"Command path {cmdPath} is already registered."); _log.Error($"Command path {cmdPath} is already registered.");
} }
return i;
} }
public void UnregisterPluginCommands(ITorchPlugin plugin) public void UnregisterPluginCommands(ITorchPlugin plugin)
@@ -78,10 +82,9 @@ namespace Torch.Commands
public void RegisterPluginCommands(ITorchPlugin plugin) public void RegisterPluginCommands(ITorchPlugin plugin)
{ {
var assembly = plugin.GetType().Assembly; var assembly = plugin.GetType().Assembly;
foreach (var type in assembly.ExportedTypes) var count = assembly.ExportedTypes.Sum(type => RegisterCommandModule(type, plugin));
{ if (count > 0)
RegisterCommandModule(type, plugin); _log.Info($"Registered {count} commands from {plugin.Name}");
}
} }
private List<TorchChatMessage> HandleCommandFromServerInternal(string message, Action<TorchChatMessage> subscriber = null) private List<TorchChatMessage> HandleCommandFromServerInternal(string message, Action<TorchChatMessage> subscriber = null)

View File

@@ -23,6 +23,12 @@ namespace Torch.Managers.PatchManager
{ {
private static Action<ILHook, bool> IsAppliedSetter; private static Action<ILHook, bool> IsAppliedSetter;
[ReflectedMethodInfo(typeof(MethodBase), nameof(MethodBase.GetMethodFromHandle), Parameters = new[] {typeof(RuntimeMethodHandle)})]
private static MethodInfo _getMethodFromHandle = null!;
[ReflectedMethodInfo(typeof(MethodBase), nameof(MethodBase.GetMethodFromHandle), Parameters = new[] {typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle)})]
private static MethodInfo _getMethodFromHandleGeneric = null!;
private static readonly Logger _log = LogManager.GetCurrentClassLogger(); private static readonly Logger _log = LogManager.GetCurrentClassLogger();
private readonly MethodBase _method; private readonly MethodBase _method;
@@ -103,6 +109,7 @@ namespace Torch.Managers.PatchManager
public const string INSTANCE_PARAMETER = "__instance"; public const string INSTANCE_PARAMETER = "__instance";
public const string RESULT_PARAMETER = "__result"; public const string RESULT_PARAMETER = "__result";
public const string PREFIX_SKIPPED_PARAMETER = "__prefixSkipped"; public const string PREFIX_SKIPPED_PARAMETER = "__prefixSkipped";
public const string ORIGINAL_PARAMETER = "__original";
public const string LOCAL_PARAMETER = "__local"; public const string LOCAL_PARAMETER = "__local";
private void SavePatchedMethod(string target) private void SavePatchedMethod(string target)
@@ -320,6 +327,24 @@ namespace Torch.Managers.PatchManager
yield return new MsilInstruction(OpCodes.Ldarg_0); yield return new MsilInstruction(OpCodes.Ldarg_0);
break; break;
} }
case ORIGINAL_PARAMETER:
{
if (!typeof(MethodBase).IsAssignableFrom(param.ParameterType))
throw new PatchException($"Original parameter should be assignable to {nameof(MethodBase)}",
_method);
yield return new MsilInstruction(OpCodes.Ldtoken).InlineValue(_method);
if (_method.DeclaringType!.ContainsGenericParameters)
{
yield return new MsilInstruction(OpCodes.Ldtoken).InlineValue(_method.DeclaringType);
yield return new MsilInstruction(OpCodes.Call).InlineValue(_getMethodFromHandleGeneric);
}
else
yield return new MsilInstruction(OpCodes.Call).InlineValue(_getMethodFromHandle);
if (param.ParameterType != typeof(MethodBase))
yield return new MsilInstruction(OpCodes.Castclass).InlineValue(param.ParameterType);
break;
}
case PREFIX_SKIPPED_PARAMETER: case PREFIX_SKIPPED_PARAMETER:
{ {
if (param.ParameterType != typeof(bool)) if (param.ParameterType != typeof(bool))

View File

@@ -9,6 +9,7 @@ using NLog;
using Torch.API; using Torch.API;
using Torch.Managers.PatchManager; using Torch.Managers.PatchManager;
using Torch.Utils; using Torch.Utils;
using VRage;
using VRage.Utils; using VRage.Utils;
namespace Torch.Patches namespace Torch.Patches
@@ -42,71 +43,81 @@ namespace Torch.Patches
[ReflectedMethodInfo(typeof(MyLog), nameof(MyLog.WriteLineAndConsole), Parameters = new[] { typeof(string) })] [ReflectedMethodInfo(typeof(MyLog), nameof(MyLog.WriteLineAndConsole), Parameters = new[] { typeof(string) })]
private static MethodInfo _logWriteLineAndConsole; private static MethodInfo _logWriteLineAndConsole;
[ReflectedMethodInfo(typeof(MyLog), nameof(MyLog.Init))]
private static MethodInfo _logInit;
#pragma warning restore 649 #pragma warning restore 649
public static void Patch(PatchContext context) public static void Patch(PatchContext context)
{ {
context.GetPattern(_logStringBuilder).Prefixes.Add(Method(nameof(PrefixLogStringBuilder))); context.GetPattern(_logStringBuilder).AddPrefix(nameof(PrefixLogStringBuilder));
context.GetPattern(_logFormatted).Prefixes.Add(Method(nameof(PrefixLogFormatted))); context.GetPattern(_logFormatted).AddPrefix(nameof(PrefixLogFormatted));
context.GetPattern(_logWriteLine).Prefixes.Add(Method(nameof(PrefixWriteLine))); context.GetPattern(_logWriteLine).AddPrefix(nameof(PrefixWriteLine));
context.GetPattern(_logAppendToClosedLog).Prefixes.Add(Method(nameof(PrefixAppendToClosedLog))); context.GetPattern(_logAppendToClosedLog).AddPrefix(nameof(PrefixAppendToClosedLog));
context.GetPattern(_logWriteLineAndConsole).Prefixes.Add(Method(nameof(PrefixWriteLineConsole))); context.GetPattern(_logWriteLineAndConsole).AddPrefix(nameof(PrefixWriteLineConsole));
context.GetPattern(_logWriteLineException).Prefixes.Add(Method(nameof(PrefixWriteLineException))); context.GetPattern(_logWriteLineException).AddPrefix(nameof(PrefixWriteLineException));
context.GetPattern(_logAppendToClosedLogException).Prefixes.Add(Method(nameof(PrefixAppendToClosedLogException))); context.GetPattern(_logAppendToClosedLogException).AddPrefix(nameof(PrefixAppendToClosedLogException));
context.GetPattern(_logWriteLineOptions).Prefixes.Add(Method(nameof(PrefixWriteLineOptions))); context.GetPattern(_logWriteLineOptions).AddPrefix(nameof(PrefixWriteLineOptions));
} context.GetPattern(_logInit).AddPrefix(nameof(PrefixInit));
private static MethodInfo Method(string name)
{
return typeof(KeenLogPatch).GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
} }
[ReflectedMethod(Name = "GetIdentByThread")] [ReflectedMethod(Name = "GetIdentByThread")]
private static Func<MyLog, int, int> GetIndentByThread = null!; private static Func<MyLog, int, int> _getIndentByThread = null!;
[ThreadStatic] [ReflectedGetter(Name = "m_lock")]
private static StringBuilder _tmpStringBuilder; private static Func<MyLog, FastResourceLock> _lockGetter = null!;
private static StringBuilder PrepareLog(MyLog log) [ReflectedSetter(Name = "m_enabled")]
private static Action<MyLog, bool> _enabledSetter = null!;
private static int GetIndentByCurrentThread()
{ {
_tmpStringBuilder ??= new(); using var l = _lockGetter(MyLog.Default).AcquireExclusiveUsing();
return _getIndentByThread(MyLog.Default, Environment.CurrentManagedThreadId);
}
_tmpStringBuilder.Clear(); private static bool PrefixInit(MyLog __instance, StringBuilder appVersionString)
var t = GetIndentByThread(log, Environment.CurrentManagedThreadId); {
__instance.WriteLine("Log Started");
var byThreadField =
typeof(MyLog).GetField("m_indentsByThread", BindingFlags.Instance | BindingFlags.NonPublic)!;
var indentsField = typeof(MyLog).GetField("m_indents", BindingFlags.Instance | BindingFlags.NonPublic)!;
_tmpStringBuilder.Append(' ', t * 3); byThreadField.SetValue(__instance, Activator.CreateInstance(byThreadField.FieldType));
return _tmpStringBuilder; indentsField.SetValue(__instance, Activator.CreateInstance(indentsField.FieldType));
_enabledSetter(__instance, true);
return false;
} }
private static bool PrefixWriteLine(MyLog __instance, string msg) private static bool PrefixWriteLine(MyLog __instance, string msg)
{ {
if (__instance.LogEnabled) if (__instance.LogEnabled && _log.IsDebugEnabled)
_log.Debug(PrepareLog(__instance).Append(msg)); _log.Debug($"{" ".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) if (__instance.LogEnabled && _log.IsInfoEnabled)
_log.Info(PrepareLog(__instance).Append(msg)); _log.Info($"{" ".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) if (__instance.LogEnabled && _log.IsDebugEnabled)
_log.Info(PrepareLog(__instance).Append(text)); _log.Debug($"{" ".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)) if (__instance.LogEnabled && __instance.LogFlag(option) && _log.IsDebugEnabled)
_log.Info(PrepareLog(__instance).Append(message)); _log.Info($"{" ".PadRight(3 * GetIndentByCurrentThread())}{message}");
return false; return false;
} }
@@ -126,22 +137,22 @@ namespace Torch.Patches
{ {
if (__instance.LogEnabled) if (__instance.LogEnabled)
return false; 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 is {Length: > 0})
sb.AppendFormat(format, args);
else
sb.Append(format);
_log.Log(LogLevelFor(severity), sb); // ReSharper disable once TemplateIsNotCompileTimeConstantProblem
_log.Log(new(LogLevelFor(severity), _log.Name, $"{" ".PadRight(3 * GetIndentByCurrentThread())}{string.Format(format, args)}"));
return false; return false;
} }
private static bool PrefixLogStringBuilder(MyLog __instance, MyLogSeverity severity, StringBuilder builder) private static bool PrefixLogStringBuilder(MyLog __instance, MyLogSeverity severity, StringBuilder builder)
{ {
if (__instance.LogEnabled) if (!__instance.LogEnabled) return false;
_log.Log(LogLevelFor(severity), PrepareLog(__instance).Append(builder)); var indent = GetIndentByCurrentThread() * 3;
// because append resizes every char
builder.EnsureCapacity(indent);
builder.Append(' ', indent);
_log.Log(LogLevelFor(severity), builder);
return false; return false;
} }

View File

@@ -26,13 +26,16 @@ namespace Torch.Session
/// </summary> /// </summary>
public MySession KeenSession { get; } public MySession KeenSession { get; }
public IWorld World { get; }
/// <inheritdoc cref="IDependencyManager"/> /// <inheritdoc cref="IDependencyManager"/>
public IDependencyManager Managers { get; } public IDependencyManager Managers { get; }
public TorchSession(ITorchBase torch, MySession keenSession) public TorchSession(ITorchBase torch, MySession keenSession, IWorld world)
{ {
Torch = torch; Torch = torch;
KeenSession = keenSession; KeenSession = keenSession;
World = world;
Managers = new DependencyManager(torch.Managers); Managers = new DependencyManager(torch.Managers);
} }

View File

@@ -28,6 +28,9 @@ namespace Torch.Session
private readonly Dictionary<ulong, MyObjectBuilder_Checkpoint.ModItem> _overrideMods; private readonly Dictionary<ulong, MyObjectBuilder_Checkpoint.ModItem> _overrideMods;
[Dependency]
private IInstanceManager _instanceManager = null!;
public event Action<CollectionChangeEventArgs> OverrideModsChanged; public event Action<CollectionChangeEventArgs> OverrideModsChanged;
/// <summary> /// <summary>
@@ -101,15 +104,18 @@ namespace Torch.Session
{ {
try try
{ {
if (_instanceManager.SelectedWorld is null)
throw new InvalidOperationException("No valid worlds selected! Please select world first.");
if (_currentSession != null) if (_currentSession != null)
{ {
_log.Warn($"Override old torch session {_currentSession.KeenSession.Name}"); _log.Warn($"Override old torch session {_currentSession.KeenSession.Name}");
_currentSession.Detach(); _currentSession.Detach();
} }
_log.Info($"Starting new torch session for {MySession.Static.Name}"); _log.Info($"Starting new torch session for {_instanceManager.SelectedWorld.FolderName}");
_currentSession = new TorchSession(Torch, MySession.Static); _currentSession = new TorchSession(Torch, MySession.Static, _instanceManager.SelectedWorld);
SetState(TorchSessionState.Loading); SetState(TorchSessionState.Loading);
} }
catch (Exception e) catch (Exception e)
@@ -123,11 +129,9 @@ namespace Torch.Session
{ {
try try
{ {
if (_currentSession == null) if (_currentSession is null)
{ throw new InvalidOperationException("Session loaded event occurred when we don't have a session.");
_log.Warn("Session loaded event occurred when we don't have a session.");
return;
}
foreach (SessionManagerFactoryDel factory in _factories) foreach (SessionManagerFactoryDel factory in _factories)
{ {
IManager manager = factory(CurrentSession); IManager manager = factory(CurrentSession);
@@ -135,7 +139,7 @@ namespace Torch.Session
CurrentSession.Managers.AddManager(manager); CurrentSession.Managers.AddManager(manager);
} }
(CurrentSession as TorchSession)?.Attach(); (CurrentSession as TorchSession)?.Attach();
_log.Info($"Loaded torch session for {MySession.Static.Name}"); _log.Info($"Loaded torch session for {CurrentSession.World.FolderName}");
SetState(TorchSessionState.Loaded); SetState(TorchSessionState.Loaded);
} }
catch (Exception e) catch (Exception e)
@@ -149,12 +153,10 @@ namespace Torch.Session
{ {
try try
{ {
if (_currentSession == null) if (_currentSession is null)
{ throw new InvalidOperationException("Session loaded event occurred when we don't have a session.");
_log.Warn("Session unloading event occurred when we don't have a session.");
return; _log.Info($"Unloading torch session for {_currentSession.World.FolderName}");
}
_log.Info($"Unloading torch session for {_currentSession.KeenSession.Name}");
SetState(TorchSessionState.Unloading); SetState(TorchSessionState.Unloading);
_currentSession.Detach(); _currentSession.Detach();
} }
@@ -169,12 +171,10 @@ namespace Torch.Session
{ {
try try
{ {
if (_currentSession == null) if (_currentSession is null)
{ throw new InvalidOperationException("Session loaded event occurred when we don't have a session.");
_log.Warn("Session unloading event occurred when we don't have a session.");
return; _log.Info($"Unloaded torch session for {_currentSession.World.FolderName}");
}
_log.Info($"Unloaded torch session for {_currentSession.KeenSession.Name}");
SetState(TorchSessionState.Unloaded); SetState(TorchSessionState.Unloaded);
_currentSession = null; _currentSession = null;
} }

View File

@@ -20,10 +20,10 @@
<!-- <Import Project="$(SolutionDir)\TransformOnBuild.targets" /> --> <!-- <Import Project="$(SolutionDir)\TransformOnBuild.targets" /> -->
<ItemGroup> <ItemGroup>
<PackageReference Include="ControlzEx" Version="5.0.1" /> <PackageReference Include="ControlzEx" Version="5.0.1" />
<PackageReference Include="InfoOf.Fody" Version="2.1.0" /> <PackageReference Include="InfoOf.Fody" Version="2.1.0" PrivateAssets="all" />
<PackageReference Include="MahApps.Metro" Version="2.4.9" /> <PackageReference Include="MahApps.Metro" Version="2.4.9" />
<PackageReference Include="MonoMod.RuntimeDetour" Version="22.1.4.3" /> <PackageReference Include="MonoMod.RuntimeDetour" Version="22.1.4.3" />
<PackageReference Include="NLog" Version="4.7.13" /> <PackageReference Include="NLog" Version="5.0.0-rc2" />
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" PrivateAssets="all" /> <PackageReference Include="PropertyChanged.Fody" Version="3.4.0" PrivateAssets="all" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="Torch.SixLabors.ImageSharp" Version="1.0.0-beta6" /> <PackageReference Include="Torch.SixLabors.ImageSharp" Version="1.0.0-beta6" />