diff --git a/NLog.config b/NLog.config index d1c94c7..c47561e 100644 --- a/NLog.config +++ b/NLog.config @@ -11,15 +11,16 @@ + - + - + diff --git a/Torch.API/ITorchBase.cs b/Torch.API/ITorchBase.cs index 1afdf9d..b8b2e68 100644 --- a/Torch.API/ITorchBase.cs +++ b/Torch.API/ITorchBase.cs @@ -149,6 +149,11 @@ namespace Torch.API /// Path of the dedicated instance folder. /// string InstancePath { get; } + + /// + /// Raised when the server's Init() method has completed. + /// + event Action Initialized; } /// diff --git a/Torch.Server/FlowDocumentTarget.cs b/Torch.Server/FlowDocumentTarget.cs new file mode 100644 index 0000000..daef655 --- /dev/null +++ b/Torch.Server/FlowDocumentTarget.cs @@ -0,0 +1,46 @@ +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 +{ + [Target("flowDocument")] + public sealed class FlowDocumentTarget : TargetWithLayout + { + private FlowDocument _document = new FlowDocument { Background = new SolidColorBrush(Colors.Black) }; + private readonly Paragraph _paragraph = new Paragraph(); + + public FlowDocument Document => _document; + + public FlowDocumentTarget() + { + _document.Blocks.Add(_paragraph); + } + + /// + 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]}); + }); + } + + private static readonly Dictionary LogLevelColors = new Dictionary + { + [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), + }; + } +} diff --git a/Torch.Server/Initializer.cs b/Torch.Server/Initializer.cs index ffe5503..d3f9205 100644 --- a/Torch.Server/Initializer.cs +++ b/Torch.Server/Initializer.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; using System.Windows; using System.Windows.Threading; using NLog; +using NLog.Targets; using Torch.Utils; namespace Torch.Server @@ -85,23 +86,26 @@ quit"; public void Run() { _server = new TorchServer(_config); - try { - _server.Init(); + var init = Task.Run(() => _server.Init()); if (!_config.NoGui) { if (_config.Autostart) - Task.Run(() => _server.Start()); + init.ContinueWith(x => _server.Start()); + Log.Info("Showing UI"); + Console.SetOut(TextWriter.Null); + NativeMethods.FreeConsole(); new TorchUI(_server).ShowDialog(); } else { + init.Wait(); _server.Start(); } } - finally + catch { if (_server.IsRunning) _server.Stop(); diff --git a/Torch.Server/Program.cs b/Torch.Server/Program.cs index 401696a..99fad9b 100644 --- a/Torch.Server/Program.cs +++ b/Torch.Server/Program.cs @@ -2,6 +2,7 @@ using System.IO; using System.Reflection; using System.ServiceProcess; +using NLog.Targets; using Torch.Utils; namespace Torch.Server @@ -14,6 +15,7 @@ namespace Torch.Server [STAThread] public static void Main(string[] args) { + Target.Register("FlowDocument"); //Ensures that all the files are downloaded in the Torch directory. var workingDir = new FileInfo(typeof(Program).Assembly.Location).Directory.ToString(); var binDir = Path.Combine(workingDir, "DedicatedServer64"); diff --git a/Torch.Server/Torch.Server.csproj b/Torch.Server/Torch.Server.csproj index ff54836..4400e35 100644 --- a/Torch.Server/Torch.Server.csproj +++ b/Torch.Server/Torch.Server.csproj @@ -15,6 +15,21 @@ + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true true @@ -195,6 +210,7 @@ Properties\AssemblyVersion.cs + @@ -411,6 +427,18 @@ SessionSettingsViewModel.cs + + + False + Microsoft .NET Framework 4.6.1 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + diff --git a/Torch.Server/TorchServer.cs b/Torch.Server/TorchServer.cs index 5f1ac45..0e76378 100644 --- a/Torch.Server/TorchServer.cs +++ b/Torch.Server/TorchServer.cs @@ -75,6 +75,8 @@ namespace Torch.Server private bool _hasRun; + public event Action Initialized; + /// public InstanceManager DedicatedInstance { get; } @@ -112,13 +114,15 @@ namespace Torch.Server /// public override void Init() { + Log.Info("Initializing server"); Sandbox.Engine.Platform.Game.IsDedicated = true; base.Init(); - Log.Info($"Init server '{Config.InstanceName}' at '{Config.InstancePath}'"); Managers.GetManager().SessionStateChanged += OnSessionStateChanged; GetManager().LoadInstance(Config.InstancePath); CanRun = true; + Initialized?.Invoke(this); + Log.Info($"Initialized server '{Config.InstanceName}' at '{Config.InstancePath}'"); } private void OnSessionStateChanged(ITorchSession session, TorchSessionState newState) @@ -216,7 +220,8 @@ namespace Torch.Server public override void Update() { base.Update(); - SimulationRatio = Sync.ServerSimulationRatio; + // Stops 1.00-1.02 flicker. + SimulationRatio = Math.Min(Sync.ServerSimulationRatio, 1); var elapsed = TimeSpan.FromSeconds(Math.Floor(_uptime.Elapsed.TotalSeconds)); ElapsedPlayTime = elapsed; diff --git a/Torch.Server/Views/ChatControl.xaml.cs b/Torch.Server/Views/ChatControl.xaml.cs index d88d8e4..5cce943 100644 --- a/Torch.Server/Views/ChatControl.xaml.cs +++ b/Torch.Server/Views/ChatControl.xaml.cs @@ -34,7 +34,7 @@ namespace Torch.Server /// public partial class ChatControl : UserControl { - private TorchBase _server; + private ITorchServer _server; public ChatControl() { @@ -43,13 +43,19 @@ namespace Torch.Server public void BindServer(ITorchServer server) { - _server = (TorchBase)server; + _server = server; + + server.Initialized += Server_Initialized ; + } + + private void Server_Initialized(ITorchServer obj) + { Dispatcher.InvokeAsync(() => { ChatItems.Inlines.Clear(); }); - var sessionManager = server.Managers.GetManager(); + var sessionManager = _server.Managers.GetManager(); if (sessionManager != null) sessionManager.SessionStateChanged += SessionStateChanged; } diff --git a/Torch.Server/Views/PlayerListControl.xaml.cs b/Torch.Server/Views/PlayerListControl.xaml.cs index 49c40a7..d7c2179 100644 --- a/Torch.Server/Views/PlayerListControl.xaml.cs +++ b/Torch.Server/Views/PlayerListControl.xaml.cs @@ -47,8 +47,12 @@ namespace Torch.Server public void BindServer(ITorchServer server) { _server = server; + _server.Initialized += Server_Initialized ; + } - var sessionManager = server.Managers.GetManager(); + private void Server_Initialized(ITorchServer obj) + { + var sessionManager = _server.Managers.GetManager(); sessionManager.SessionStateChanged += SessionStateChanged; } diff --git a/Torch.Server/Views/PluginsControl.xaml.cs b/Torch.Server/Views/PluginsControl.xaml.cs index 6b54f26..b990f5b 100644 --- a/Torch.Server/Views/PluginsControl.xaml.cs +++ b/Torch.Server/Views/PluginsControl.xaml.cs @@ -38,9 +38,18 @@ namespace Torch.Server.Views public void BindServer(ITorchServer server) { _server = server; - _plugins = _server.Managers.GetManager(); - var pluginManager = new PluginManagerViewModel(_plugins); - DataContext = pluginManager; + _server.Initialized += Server_Initialized; + } + + private void Server_Initialized(ITorchServer obj) + { + Dispatcher.InvokeAsync(() => + { + _plugins = _server.Managers.GetManager(); + var pluginManager = new PluginManagerViewModel(_plugins); + DataContext = pluginManager; + }); + } private void OpenFolder_OnClick(object sender, RoutedEventArgs e) diff --git a/Torch.Server/Views/TorchUI.xaml b/Torch.Server/Views/TorchUI.xaml index 5f61026..bdda27d 100644 --- a/Torch.Server/Views/TorchUI.xaml +++ b/Torch.Server/Views/TorchUI.xaml @@ -57,7 +57,7 @@ - + diff --git a/Torch.Server/Views/TorchUI.xaml.cs b/Torch.Server/Views/TorchUI.xaml.cs index e3980c1..a274676 100644 --- a/Torch.Server/Views/TorchUI.xaml.cs +++ b/Torch.Server/Views/TorchUI.xaml.cs @@ -8,10 +8,12 @@ using System.Timers; using System.Windows; using System.Windows.Controls; using System.Windows.Data; +using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; +using NLog; using Sandbox; using Torch.API; using Torch.Server.Managers; @@ -36,6 +38,8 @@ namespace Torch.Server DataContext = server; InitializeComponent(); + AttachConsole(); + Left = _config.WindowPosition.X; Top = _config.WindowPosition.Y; Width = _config.WindowSize.X; @@ -45,13 +49,13 @@ namespace Torch.Server PlayerList.BindServer(server); Plugins.BindServer(server); LoadConfig((TorchConfig)server.Config); - - AttachConsole(); } private void AttachConsole() { - Console.SetOut(new MultiTextWriter(new RichTextBoxWriter(ConsoleText), Console.Out)); + var doc = LogManager.Configuration.FindTargetByName("wpf")?.Document; + ConsoleText.Document = doc ?? new FlowDocument(new Paragraph(new Run("No target!"))); + ConsoleText.TextChanged += (sender, args) => ConsoleText.ScrollToEnd(); } public void LoadConfig(TorchConfig config)