Compare commits

...

6 Commits

Author SHA1 Message Date
John Gross
82815f66e5 # Torch 1.1.229.265
* Features
    - Added more lenient version parsing for plugins (v#.# should work)
    - Added countdown option to restart command (!restart [seconds])
* Fixes
    - General fixes to work with the latest SE version
    - Fixed config changes not saving
    - Fixed crash on servers using the Windows Classic theme
2017-08-17 09:09:51 -07:00
John Gross
97da740e7e Catch errors in updater and fix loading error 2017-08-01 13:01:10 -07:00
John Gross
42bb24ca6a Hotfix for save issues 2017-08-01 12:31:49 -07:00
John Gross
2f3b6cdda7 Fix crashes and save issues 2017-07-31 13:12:01 -07:00
John Michael Gross
525b496774 Update README.md 2017-07-26 09:35:43 -07:00
John Michael Gross
562bb77dda Update README.md 2017-07-26 00:57:47 -07:00
26 changed files with 284 additions and 129 deletions

View File

@@ -1,4 +1,13 @@
# Torch 1.1.205.478 # Torch 1.1.229.265
* Features
- Added more lenient version parsing for plugins (v#.# should work)
- Added countdown option to restart command (!restart [seconds])
* Fixes
- General fixes to work with the latest SE version
- Fixed config changes not saving
- (hopefully) Fixed issue causing crashes on servers using the Windows Classic theme
# Torch 1.1.207.7
* Notes * Notes
- This release makes significant changes to TorchConfig.xml. It has been renamed to Torch.cfg and has different options. - This release makes significant changes to TorchConfig.xml. It has been renamed to Torch.cfg and has different options.
* Features * Features

View File

@@ -10,17 +10,15 @@ Torch is the successor to SE Server Extender and gives server admins the tools t
* Organized, easy to use configuration editor * Organized, easy to use configuration editor
* Extensible using the Torch plugin system * Extensible using the Torch plugin system
# Installation
* Get the latest Torch release here: https://github.com/TorchAPI/Torch/releases
* 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.
- If you already have a DS installed you can unzip the Torch files into the folder that contains the DedicatedServer64 folder.
# Building # Building
To build Torch you must first have a complete SE Dedicated installation somewhere. Before you open the solution, run the Setup batch file and enter the path of that installation's DedicatedServer64 folder. The script will make a symlink to that folder so the Torch solution can find the DLL references it needs. To build Torch you must first have a complete SE Dedicated installation somewhere. Before you open the solution, run the Setup batch file and enter the path of that installation's DedicatedServer64 folder. The script will make a symlink to that folder so the Torch solution can find the DLL references it needs.
# Installation Guide
### Automatic (recommended)
* Unzip Torch to its own folder, run Torch.Server.exe and enter 'y' in the prompt for automatic updates. Torch will automatically download the Space Engineers files and generate all of the configs/folders necessary.
### Manual (for hosting companies or the paranoid)
* Install the Space Engineers DS and then unzip the Torch files into the server's DedicatedServer64 directory. It will automatically detect the manual install and disable automatic updates.
In both cases you will need to set the InstancePath in TorchConfig.xml to an existing dedicated server instance as Torch can't fully generate it on its own yet. In both cases you will need to set the InstancePath in TorchConfig.xml to an existing dedicated server instance as Torch can't fully generate it on its own yet.
# Official Plugins # Official Plugins
@@ -28,4 +26,5 @@ Install plugins by unzipping them into the 'Plugins' folder which should be in t
* [Essentials](https://github.com/TorchAPI/Essentials): Adds a slew of chat commands and other tools to help manage your server. * [Essentials](https://github.com/TorchAPI/Essentials): Adds a slew of chat commands and other tools to help manage your server.
* [Concealment](https://github.com/TorchAPI/Concealment): Adds game logic and physics optimizations that significantly improve sim speed. * [Concealment](https://github.com/TorchAPI/Concealment): Adds game logic and physics optimizations that significantly improve sim speed.
If you have a more enjoyable server experience because of Torch, please consider supporting us on [Patreon](https://www.patreon.com/bePatron?u=847269)! If you have a more enjoyable server experience because of Torch, please consider supporting us on Patreon.
[![Patreon](http://i.imgur.com/VzzIMgn.png)](https://www.patreon.com/bePatron?u=847269)!

View File

@@ -1,4 +1,4 @@
using System.Reflection; using System.Reflection;
[assembly: AssemblyVersion("1.0.207.7")] [assembly: AssemblyVersion("1.0.229.265")]
[assembly: AssemblyFileVersion("1.0.207.7")] [assembly: AssemblyFileVersion("1.0.229.265")]

View File

@@ -103,6 +103,9 @@
<HintPath>..\GameBinaries\VRage.Render11.dll</HintPath> <HintPath>..\GameBinaries\VRage.Render11.dll</HintPath>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
<Reference Include="VRage.Steam">
<HintPath>..\..\..\..\..\..\..\steamcmd\steamapps\common\SpaceEngineersDedicatedServer\DedicatedServer64\VRage.Steam.dll</HintPath>
</Reference>
<Reference Include="WindowsBase" /> <Reference Include="WindowsBase" />
<Reference Include="PresentationCore" /> <Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" /> <Reference Include="PresentationFramework" />

View File

@@ -11,6 +11,7 @@ using Sandbox.Engine.Utils;
using Sandbox.Game; using Sandbox.Game;
using Sandbox.ModAPI; using Sandbox.ModAPI;
using SpaceEngineers.Game; using SpaceEngineers.Game;
using VRage.Steam;
using Torch.API; using Torch.API;
using VRage.FileSystem; using VRage.FileSystem;
using VRageRender; using VRageRender;
@@ -22,7 +23,6 @@ namespace Torch.Client
private MyCommonProgramStartup _startup; private MyCommonProgramStartup _startup;
private IMyRender _renderer; private IMyRender _renderer;
private const uint APP_ID = 244850; private const uint APP_ID = 244850;
private VRageGameServices _services;
public override void Init() public override void Init()
{ {
@@ -59,7 +59,6 @@ namespace Torch.Client
InitializeRender(); InitializeRender();
_services = new VRageGameServices(mySteamService);
if (!Game.IsDedicated) if (!Game.IsDedicated)
MyFileSystem.InitUserSpecific(mySteamService.UserId.ToString()); MyFileSystem.InitUserSpecific(mySteamService.UserId.ToString());
} }
@@ -85,7 +84,7 @@ namespace Torch.Client
public override void Start() public override void Start()
{ {
using (var spaceEngineersGame = new SpaceEngineersGame(_services, RunArgs)) using (var spaceEngineersGame = new SpaceEngineersGame(RunArgs))
{ {
Log.Info("Starting client"); Log.Info("Starting client");
spaceEngineersGame.OnGameLoaded += SpaceEngineersGame_OnGameLoaded; spaceEngineersGame.OnGameLoaded += SpaceEngineersGame_OnGameLoaded;

View File

@@ -0,0 +1,59 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
namespace Torch.Server
{
public static class ListBoxExtensions
{
//https://stackoverflow.com/questions/28689125/how-to-autoscroll-listbox-to-bottom-wpf-c
public static void ScrollToItem(this ListBox listBox, int index)
{
// Find a container
UIElement container = null;
for (int i = index; i > 0; i--)
{
container = listBox.ItemContainerGenerator.ContainerFromIndex(i) as UIElement;
if (container != null)
{
break;
}
}
if (container == null)
return;
// Find the ScrollContentPresenter
ScrollContentPresenter presenter = null;
for (Visual vis = container; vis != null && vis != listBox; vis = VisualTreeHelper.GetParent(vis) as Visual)
if ((presenter = vis as ScrollContentPresenter) != null)
break;
if (presenter == null)
return;
// Find the IScrollInfo
var scrollInfo =
!presenter.CanContentScroll ? presenter :
presenter.Content as IScrollInfo ??
FirstVisualChild(presenter.Content as ItemsPresenter) as IScrollInfo ??
presenter;
// Find the amount of items that is "Visible" in the ListBox
var height = (container as ListBoxItem).ActualHeight;
var lbHeight = listBox.ActualHeight;
var showCount = (int)Math.Floor(lbHeight / height) - 1;
//Set the scrollbar
if (scrollInfo.CanVerticallyScroll)
scrollInfo.SetVerticalOffset(index - showCount);
}
private static DependencyObject FirstVisualChild(Visual visual)
{
if (visual == null) return null;
if (VisualTreeHelper.GetChildrenCount(visual) == 0) return null;
return VisualTreeHelper.GetChild(visual, 0);
}
}
}

View File

@@ -34,7 +34,10 @@ namespace Torch.Server.Managers
/// <inheritdoc /> /// <inheritdoc />
public override void Init() public override void Init()
{ {
LoadInstance(Torch.Config.InstancePath); MyFileSystem.ExePath = Path.Combine(Torch.GetManager<FilesystemManager>().TorchDirectory, "DedicatedServer64");
MyFileSystem.Init("Content", Torch.Config.InstancePath);
//Initializes saves path. Why this isn't in Init() we may never know.
MyFileSystem.InitUserSpecific(null);
} }
public void LoadInstance(string path, bool validate = true) public void LoadInstance(string path, bool validate = true)
@@ -45,6 +48,8 @@ namespace Torch.Server.Managers
MyFileSystem.Reset(); MyFileSystem.Reset();
MyFileSystem.ExePath = Path.Combine(Torch.GetManager<FilesystemManager>().TorchDirectory, "DedicatedServer64"); MyFileSystem.ExePath = Path.Combine(Torch.GetManager<FilesystemManager>().TorchDirectory, "DedicatedServer64");
MyFileSystem.Init("Content", path); MyFileSystem.Init("Content", path);
//Initializes saves path. Why this isn't in Init() we may never know.
MyFileSystem.InitUserSpecific(null);
var configPath = Path.Combine(path, CONFIG_NAME); var configPath = Path.Combine(path, CONFIG_NAME);
if (!File.Exists(configPath)) if (!File.Exists(configPath))
@@ -68,6 +73,8 @@ namespace Torch.Server.Managers
return; return;
} }
ImportWorldConfig();
/* /*
if (string.IsNullOrEmpty(DedicatedConfig.LoadWorld)) if (string.IsNullOrEmpty(DedicatedConfig.LoadWorld))
{ {
@@ -79,13 +86,13 @@ namespace Torch.Server.Managers
public void SelectWorld(string worldPath, bool modsOnly = true) public void SelectWorld(string worldPath, bool modsOnly = true)
{ {
DedicatedConfig.LoadWorld = worldPath; DedicatedConfig.LoadWorld = worldPath;
LoadWorldMods(modsOnly); ImportWorldConfig(modsOnly);
} }
private void LoadWorldMods(bool modsOnly = true) private void ImportWorldConfig(bool modsOnly = true)
{ {
if (DedicatedConfig.LoadWorld == null) if (string.IsNullOrEmpty(DedicatedConfig.LoadWorld))
return; return;
var sandboxPath = Path.Combine(DedicatedConfig.LoadWorld, "Sandbox.sbc"); var sandboxPath = Path.Combine(DedicatedConfig.LoadWorld, "Sandbox.sbc");
@@ -93,6 +100,8 @@ namespace Torch.Server.Managers
if (!File.Exists(sandboxPath)) if (!File.Exists(sandboxPath))
return; return;
try
{
MyObjectBuilderSerializer.DeserializeXML(sandboxPath, out MyObjectBuilder_Checkpoint checkpoint, out ulong sizeInBytes); MyObjectBuilderSerializer.DeserializeXML(sandboxPath, out MyObjectBuilder_Checkpoint checkpoint, out ulong sizeInBytes);
if (checkpoint == null) if (checkpoint == null)
{ {
@@ -106,15 +115,21 @@ namespace Torch.Server.Managers
DedicatedConfig.Mods = sb.ToString(); DedicatedConfig.Mods = sb.ToString();
Log.Info("Loaded mod list from world"); Log.Debug("Loaded mod list from world");
if (!modsOnly) if (!modsOnly)
DedicatedConfig.SessionSettings = new SessionSettingsViewModel(checkpoint.Settings); DedicatedConfig.SessionSettings = new SessionSettingsViewModel(checkpoint.Settings);
} }
catch (Exception e)
{
Log.Error($"Error loading mod list from world, verify that your mod list is accurate. '{DedicatedConfig.LoadWorld}'.");
Log.Error(e);
}
}
public void SaveConfig() public void SaveConfig()
{ {
DedicatedConfig.Model.Save(); DedicatedConfig.Save();
Log.Info("Saved dedicated config."); Log.Info("Saved dedicated config.");
try try

View File

@@ -84,10 +84,14 @@ namespace Torch.Server
{ {
var pid = int.Parse(_config.WaitForPID); var pid = int.Parse(_config.WaitForPID);
var waitProc = Process.GetProcessById(pid); var waitProc = Process.GetProcessById(pid);
_log.Warn($"Waiting for process {pid} to exit.");
waitProc.WaitForExit();
_log.Info("Continuing in 5 seconds."); _log.Info("Continuing in 5 seconds.");
Thread.Sleep(5000); Thread.Sleep(5000);
if (!waitProc.HasExited)
{
_log.Warn($"Killing old process {pid}.");
waitProc.Kill();
}
} }
catch catch
{ {

View File

@@ -1,4 +1,4 @@
using System.Reflection; using System.Reflection;
[assembly: AssemblyVersion("1.1.207.7")] [assembly: AssemblyVersion("1.1.229.265")]
[assembly: AssemblyFileVersion("1.1.207.7")] [assembly: AssemblyFileVersion("1.1.229.265")]

View File

@@ -185,6 +185,7 @@
<Reference Include="PresentationFramework" /> <Reference Include="PresentationFramework" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="ListBoxExtensions.cs" />
<Compile Include="Managers\InstanceManager.cs" /> <Compile Include="Managers\InstanceManager.cs" />
<Compile Include="NativeMethods.cs" /> <Compile Include="NativeMethods.cs" />
<Compile Include="Properties\AssemblyInfo.cs"> <Compile Include="Properties\AssemblyInfo.cs">

View File

@@ -77,10 +77,9 @@ namespace Torch.Server
MySessionComponentExtDebug.ForceDisable = true; MySessionComponentExtDebug.ForceDisable = true;
MyPerServerSettings.AppId = 244850; MyPerServerSettings.AppId = 244850;
MyFinalBuildConstants.APP_VERSION = MyPerGameSettings.BasicGameInfo.GameVersion; MyFinalBuildConstants.APP_VERSION = MyPerGameSettings.BasicGameInfo.GameVersion;
MyObjectBuilderSerializer.RegisterFromAssembly(typeof(MyObjectBuilder_CheckpointSerializer).Assembly);
InvokeBeforeRun(); InvokeBeforeRun();
//MyObjectBuilderSerializer.RegisterFromAssembly(typeof(MyObjectBuilder_CheckpointSerializer).Assembly);
MyPlugins.RegisterGameAssemblyFile(MyPerGameSettings.GameModAssembly); MyPlugins.RegisterGameAssemblyFile(MyPerGameSettings.GameModAssembly);
MyPlugins.RegisterGameObjectBuildersAssemblyFile(MyPerGameSettings.GameModObjBuildersAssembly); MyPlugins.RegisterGameObjectBuildersAssemblyFile(MyPerGameSettings.GameModObjBuildersAssembly);
MyPlugins.RegisterSandboxAssemblyFile(MyPerGameSettings.SandboxAssembly); MyPlugins.RegisterSandboxAssemblyFile(MyPerGameSettings.SandboxAssembly);
@@ -88,6 +87,7 @@ namespace Torch.Server
MyPlugins.Load(); MyPlugins.Load();
MyGlobalTypeMetadata.Static.Init(); MyGlobalTypeMetadata.Static.Init();
GetManager<InstanceManager>().LoadInstance(Config.InstancePath);
Plugins.LoadPlugins(); Plugins.LoadPlugins();
} }
@@ -131,7 +131,6 @@ namespace Torch.Server
_uptime = Stopwatch.StartNew(); _uptime = Stopwatch.StartNew();
IsRunning = true; IsRunning = true;
GameThread = Thread.CurrentThread; GameThread = Thread.CurrentThread;
Config.Save();
State = ServerState.Starting; State = ServerState.Starting;
Log.Info("Starting server."); Log.Info("Starting server.");
@@ -143,6 +142,8 @@ namespace Torch.Server
VRage.Service.ExitListenerSTA.OnExit += delegate { MySandboxGame.Static?.Exit(); }; VRage.Service.ExitListenerSTA.OnExit += delegate { MySandboxGame.Static?.Exit(); };
base.Start(); base.Start();
//Stops RunInternal from calling MyFileSystem.InitUserSpecific(null), we call it in InstanceManager.
MySandboxGame.IsReloading = true;
runInternal.Invoke(null, null); runInternal.Invoke(null, null);
MySandboxGame.Log.Close(); MySandboxGame.Log.Close();

View File

@@ -74,6 +74,12 @@ namespace Torch.Server.ViewModels
{ {
get => _settings.HackSpeedMultiplier; set { _settings.HackSpeedMultiplier = value; OnPropertyChanged(); } get => _settings.HackSpeedMultiplier; set { _settings.HackSpeedMultiplier = value; OnPropertyChanged(); }
} }
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.WelderSpeedMultiplier"/>
public float WelderSpeedMultiplier
{
get => _settings.WelderSpeedMultiplier; set { _settings.WelderSpeedMultiplier = value; OnPropertyChanged(); }
}
#endregion #endregion
#region NPCs #region NPCs

View File

@@ -49,12 +49,15 @@ namespace Torch.Server
private void ChatHistory_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) private void ChatHistory_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{ {
ChatItems.ScrollToItem(ChatItems.Items.Count - 1);
/*
if (VisualTreeHelper.GetChildrenCount(ChatItems) > 0) if (VisualTreeHelper.GetChildrenCount(ChatItems) > 0)
{ {
Border border = (Border)VisualTreeHelper.GetChild(ChatItems, 0); Border border = (Border)VisualTreeHelper.GetChild(ChatItems, 0);
ScrollViewer scrollViewer = (ScrollViewer)VisualTreeHelper.GetChild(border, 0); ScrollViewer scrollViewer = (ScrollViewer)VisualTreeHelper.GetChild(border, 0);
scrollViewer.ScrollToBottom(); scrollViewer.ScrollToBottom();
} }*/
} }
private void SendButton_Click(object sender, RoutedEventArgs e) private void SendButton_Click(object sender, RoutedEventArgs e)

View File

@@ -104,6 +104,10 @@
<TextBox Text="{Binding AssemblerSpeedMultiplier}" Margin="3" Width="70" /> <TextBox Text="{Binding AssemblerSpeedMultiplier}" Margin="3" Width="70" />
<Label Content="Assembler Speed" /> <Label Content="Assembler Speed" />
</StackPanel> </StackPanel>
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding WelderSpeedMultiplier}" Margin="3" Width="70" />
<Label Content="Welder Speed" />
</StackPanel>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<TextBox Text="{Binding GrinderSpeedMultiplier}" Margin="3" Width="70" /> <TextBox Text="{Binding GrinderSpeedMultiplier}" Margin="3" Width="70" />
<Label Content="Grinder Speed" /> <Label Content="Grinder Speed" />

View File

@@ -1,34 +1,7 @@
using System; using System.Windows;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
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.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml.Serialization;
using NLog;
using Sandbox;
using Sandbox.Engine.Networking;
using Sandbox.Engine.Utils;
using Torch.Server.Managers; using Torch.Server.Managers;
using Torch.Server.ViewModels; using Torch.Server.ViewModels;
using Torch.Views;
using VRage;
using VRage.Dedicated;
using VRage.Game;
using VRage.ObjectBuilders;
using Path = System.IO.Path;
namespace Torch.Server.Views namespace Torch.Server.Views
{ {

View File

@@ -39,7 +39,7 @@
</StackPanel> </StackPanel>
<TabControl Grid.Row="1" Height="Auto" x:Name="TabControl" Margin="5,0,5,5"> <TabControl Grid.Row="1" Height="Auto" x:Name="TabControl" Margin="5,0,5,5">
<TabItem Header="Configuration"> <TabItem Header="Configuration">
<Grid> <Grid IsEnabled="{Binding IsRunning, Converter={StaticResource InverseBool}}">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
<RowDefinition/> <RowDefinition/>

View File

@@ -65,7 +65,7 @@ namespace Torch.Server
private void BtnStart_Click(object sender, RoutedEventArgs e) private void BtnStart_Click(object sender, RoutedEventArgs e)
{ {
_config.Save(); _server.GetManager<InstanceManager>().SaveConfig();
new Thread(_server.Start).Start(); new Thread(_server.Start).Start();
} }
@@ -80,7 +80,6 @@ namespace Torch.Server
_config.WindowSize = newSize; _config.WindowSize = newSize;
var newPos = new Point((int)Left, (int)Top); var newPos = new Point((int)Left, (int)Top);
_config.WindowPosition = newPos; _config.WindowPosition = newPos;
_config.Save();
if (_server?.State == ServerState.Running) if (_server?.State == ServerState.Running)
_server.Stop(); _server.Stop();

View File

@@ -40,7 +40,7 @@ namespace Torch.Commands
public bool IsCommand(string command) public bool IsCommand(string command)
{ {
return command.Length > 1 && command[0] == Prefix; return !string.IsNullOrEmpty(command) && command[0] == Prefix;
} }
public void RegisterCommandModule(Type moduleType, ITorchPlugin plugin = null) public void RegisterCommandModule(Type moduleType, ITorchPlugin plugin = null)

View File

@@ -1,8 +1,11 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Timers;
using Sandbox.ModAPI; using Sandbox.ModAPI;
using Torch; using Torch;
using Torch.Commands.Permissions; using Torch.Commands.Permissions;
@@ -106,12 +109,48 @@ namespace Torch.Commands
} }
[Command("restart", "Restarts the server.")] [Command("restart", "Restarts the server.")]
public void Restart(bool save = true) public void Restart(int countdownSeconds = 10, bool save = true)
{ {
Context.Respond("Restarting server."); Task.Run(() =>
if (save) {
Context.Torch.Save(Context.Player?.IdentityId ?? 0).Wait(); var countdown = RestartCountdown(countdownSeconds).GetEnumerator();
while (countdown.MoveNext())
{
Thread.Sleep(1000);
}
});
}
private IEnumerable RestartCountdown(int countdown)
{
for (var i = countdown; i >= 0; i--)
{
if (i >= 60 && i % 60 == 0)
{
Context.Torch.Multiplayer.SendMessage($"Restarting server in {i / 60} minute{Pluralize(i / 60)}.");
yield return null;
}
else if (i > 0)
{
if (i < 11)
Context.Torch.Multiplayer.SendMessage($"Restarting server in {i} second{Pluralize(i)}.");
yield return null;
}
else
{
Context.Torch.Invoke(() =>
{
Context.Torch.Save(0).Wait();
Context.Torch.Restart(); Context.Torch.Restart();
});
yield break;
}
}
}
private string Pluralize(int num)
{
return num == 1 ? "" : "s";
} }
/// <summary> /// <summary>

View File

@@ -45,7 +45,7 @@ namespace Torch.Managers
} }
} }
private void Static_ChatMessageReceived(ulong arg1, string arg2, SteamSDK.ChatEntryTypeEnum arg3) private void Static_ChatMessageReceived(ulong arg1, string arg2)
{ {
var msg = new ChatMsg {Author = arg1, Text = arg2}; var msg = new ChatMsg {Author = arg1, Text = arg2};
var sendToOthers = true; var sendToOthers = true;

View File

@@ -28,6 +28,7 @@ using Torch.Commands;
using Torch.ViewModels; using Torch.ViewModels;
using VRage.Game; using VRage.Game;
using VRage.Game.ModAPI; using VRage.Game.ModAPI;
using VRage.GameServices;
using VRage.Library.Collections; using VRage.Library.Collections;
using VRage.Network; using VRage.Network;
using VRage.Utils; using VRage.Utils;
@@ -120,6 +121,9 @@ namespace Torch.Managers
/// <inheritdoc /> /// <inheritdoc />
public void SendMessage(string message, string author = "Server", long playerId = 0, string font = MyFontEnum.Red) public void SendMessage(string message, string author = "Server", long playerId = 0, string font = MyFontEnum.Red)
{ {
if (string.IsNullOrEmpty(message))
return;
ChatHistory.Add(new ChatMessage(DateTime.Now, 0, author, message)); ChatHistory.Add(new ChatMessage(DateTime.Now, 0, author, message));
var commands = Torch.GetManager<CommandManager>(); var commands = Torch.GetManager<CommandManager>();
if (commands.IsCommand(message)) if (commands.IsCommand(message))
@@ -166,10 +170,10 @@ namespace Torch.Managers
private void OnClientKicked(ulong steamId) private void OnClientKicked(ulong steamId)
{ {
OnClientLeft(steamId, ChatMemberStateChangeEnum.Kicked); OnClientLeft(steamId, MyChatMemberStateChangeEnum.Kicked);
} }
private void OnClientLeft(ulong steamId, ChatMemberStateChangeEnum stateChange) private void OnClientLeft(ulong steamId, MyChatMemberStateChangeEnum stateChange)
{ {
Players.TryGetValue(steamId, out PlayerViewModel vm); Players.TryGetValue(steamId, out PlayerViewModel vm);
if (vm == null) if (vm == null)

View File

@@ -126,8 +126,7 @@ namespace Torch.Managers
} }
catch (Exception ex) catch (Exception ex)
{ {
_log.Fatal(ex); _log.Error(ex);
_log.Fatal(ex, "~Error processing event!");
//crash after logging, bad things could happen if we continue on with bad data //crash after logging, bad things could happen if we continue on with bad data
throw; throw;
} }
@@ -200,8 +199,8 @@ namespace Torch.Managers
} }
catch (Exception ex) catch (Exception ex)
{ {
_log.Fatal(ex); _log.Error(ex, "Error processing network event!");
_log.Fatal(ex, "Error when returning control to game server!"); _log.Error(ex);
//crash after logging, bad things could happen if we continue on with bad data //crash after logging, bad things could happen if we continue on with bad data
throw; throw;
} }

View File

@@ -121,9 +121,10 @@ namespace Torch.Managers
commands.RegisterPluginCommands(plugin); commands.RegisterPluginCommands(plugin);
} }
catch catch (Exception e)
{ {
_log.Error($"Error loading plugin '{type.FullName}'"); _log.Error($"Error loading plugin '{type.FullName}'");
_log.Error(e);
throw; throw;
} }
} }

View File

@@ -6,6 +6,7 @@ using System.IO.Packaging;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using NLog; using NLog;
@@ -52,7 +53,8 @@ namespace Torch.Managers
return new Tuple<Version, string>(new Version(), null); return new Tuple<Version, string>(new Version(), null);
var zip = latest.Assets.FirstOrDefault(x => x.Name.Contains(".zip")); var zip = latest.Assets.FirstOrDefault(x => x.Name.Contains(".zip"));
return new Tuple<Version, string>(new Version(latest.TagName ?? "0"), zip?.BrowserDownloadUrl); var versionName = Regex.Match(latest.TagName, "(\\d+\\.)+\\d+").ToString();
return new Tuple<Version, string>(new Version(string.IsNullOrWhiteSpace(versionName) ? versionName : "0.0"), zip?.BrowserDownloadUrl);
} }
catch (Exception e) catch (Exception e)
{ {
@@ -67,6 +69,8 @@ namespace Torch.Managers
if (!Torch.Config.GetPluginUpdates) if (!Torch.Config.GetPluginUpdates)
return; return;
try
{
var name = manifest.Repository.Split('/'); var name = manifest.Repository.Split('/');
if (name.Length != 2) if (name.Length != 2)
{ {
@@ -90,12 +94,20 @@ namespace Torch.Managers
_log.Info($"{manifest.Repository} is up to date. ({currentVersion})"); _log.Info($"{manifest.Repository} is up to date. ({currentVersion})");
} }
} }
catch (Exception e)
{
_log.Error($"An error occured downloading the plugin update for {manifest.Repository}.");
_log.Error(e);
}
}
private async void CheckAndUpdateTorch() private async void CheckAndUpdateTorch()
{ {
if (!Torch.Config.GetTorchUpdates) if (!Torch.Config.GetTorchUpdates)
return; return;
try
{
var releaseInfo = await GetLatestRelease("TorchAPI", "Torch").ConfigureAwait(false); var releaseInfo = await GetLatestRelease("TorchAPI", "Torch").ConfigureAwait(false);
if (releaseInfo.Item1 > Torch.TorchVersion) if (releaseInfo.Item1 > Torch.TorchVersion)
{ {
@@ -104,12 +116,19 @@ namespace Torch.Managers
new WebClient().DownloadFile(new Uri(releaseInfo.Item2), updateName); new WebClient().DownloadFile(new Uri(releaseInfo.Item2), updateName);
UpdateFromZip(updateName, _torchDir); UpdateFromZip(updateName, _torchDir);
File.Delete(updateName); File.Delete(updateName);
_log.Warn($"Torch version {releaseInfo.Item1} has been installed, please restart Torch to finish the process.");
} }
else else
{ {
_log.Info("Torch is up to date."); _log.Info("Torch is up to date.");
} }
} }
catch (Exception e)
{
_log.Error("An error occured downloading the Torch update.");
_log.Error(e);
}
}
private void UpdateFromZip(string zipFile, string extractPath) private void UpdateFromZip(string zipFile, string extractPath)
{ {

View File

@@ -4,6 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using SteamSDK; using SteamSDK;
using VRage.Steam;
using Sandbox; using Sandbox;
namespace Torch namespace Torch
@@ -16,34 +17,48 @@ namespace Torch
/// </summary> /// </summary>
public class SteamService : MySteamService public class SteamService : MySteamService
{ {
public SteamService(bool isDedicated, uint appId) : base(true, appId) public SteamService(bool isDedicated, uint appId)
: base(true, appId)
{ {
// TODO: Add protection for this mess... somewhere // TODO: Add protection for this mess... somewhere
SteamServerAPI.Instance.Dispose(); SteamSDK.SteamServerAPI.Instance.Dispose();
var steam = typeof(MySteamService); var steam = typeof(MySteamService);
steam.GetField("SteamServerAPI").SetValue(this, null);
steam.GetProperty("SteamServerAPI").GetSetMethod(true).Invoke(this, new object[] { null });
steam.GetField("m_gameServer", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(this, null);
steam.GetProperty("AppId").GetSetMethod(true).Invoke(this, new object[] { appId }); steam.GetProperty("AppId").GetSetMethod(true).Invoke(this, new object[] { appId });
if (isDedicated) if (isDedicated)
{ {
steam.GetField("SteamServerAPI").SetValue(this, SteamServerAPI.Instance); steam.GetProperty("SteamServerAPI").GetSetMethod(true).Invoke(this, new object[] { null });
steam.GetField("m_gameServer").SetValue(this, new MySteamGameServer());
} }
else else
{ {
var steamApi = SteamAPI.Instance; var SteamAPI = SteamSDK.SteamAPI.Instance;
steam.GetField("SteamAPI").SetValue(this, SteamAPI.Instance); steam.GetProperty("API").GetSetMethod(true).Invoke(this, new object[] { SteamAPI.Instance });
steam.GetProperty("IsActive").GetSetMethod(true).Invoke(this, new object[] { SteamAPI.Instance != null }); steam.GetProperty("IsActive").GetSetMethod(true).Invoke(this, new object[] {
SteamAPI.Instance.Init()
});
if (steamApi != null) if (IsActive)
{ {
steam.GetProperty("UserId").GetSetMethod(true).Invoke(this, new object[] { steamApi.GetSteamUserId() }); steam.GetProperty("UserId").GetSetMethod(true).Invoke(this, new object[] { SteamAPI.GetSteamUserId() });
steam.GetProperty("UserName").GetSetMethod(true).Invoke(this, new object[] { steamApi.GetSteamName() }); steam.GetProperty("UserName").GetSetMethod(true).Invoke(this, new object[] { SteamAPI.GetSteamName() });
steam.GetProperty("OwnsGame").GetSetMethod(true).Invoke(this, new object[] { steamApi.HasGame() }); steam.GetProperty("OwnsGame").GetSetMethod(true).Invoke(this, new object[] { SteamAPI.HasGame() });
steam.GetProperty("UserUniverse").GetSetMethod(true).Invoke(this, new object[] { steamApi.GetSteamUserUniverse() }); steam.GetProperty("UserUniverse").GetSetMethod(true).Invoke(this, new object[] { SteamAPI.GetSteamUserUniverse() });
steam.GetProperty("BranchName").GetSetMethod(true).Invoke(this, new object[] { steamApi.GetBranchName() }); steam.GetProperty("BranchName").GetSetMethod(true).Invoke(this, new object[] { SteamAPI.GetBranchName() });
steamApi.LoadStats(); SteamAPI.LoadStats();
steam.GetProperty("InventoryAPI").GetSetMethod(true).Invoke(this, new object[] { new MySteamInventory() });
steam.GetMethod("RegisterCallbacks",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
.Invoke(this, null);
} }
} }
steam.GetProperty("Peer2Peer").GetSetMethod(true).Invoke(this, new object[] { new MySteamPeer2Peer() });
} }
} }
} }

View File

@@ -142,6 +142,9 @@
<HintPath>..\GameBinaries\VRage.Scripting.dll</HintPath> <HintPath>..\GameBinaries\VRage.Scripting.dll</HintPath>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
<Reference Include="VRage.Steam">
<HintPath>..\..\..\..\..\..\..\steamcmd\steamapps\common\SpaceEngineersDedicatedServer\DedicatedServer64\VRage.Steam.dll</HintPath>
</Reference>
<Reference Include="WindowsBase" /> <Reference Include="WindowsBase" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>