Skip to content

Commit f265f7e

Browse files
Tobias Krexxar-tc
authored andcommitted
Replace mod text box by separate tab with workshop support (#263)
* Implement ModList tab which fetches and displays mod information from the workshop. * ModListEditor: Implement drag and drop ordering, adding, removing and saving. * Add SteamWorkshopService to VCS * Add missing file to SteamworkshopService project. * ModlistControl: Implement checkbox for hiding/showing dependency mods disable until config is loaded. design improvements. * Add documentation for the new classes. * Comply to naming conventions. * Update Torch.Server.csproj * Fix Mod.IsDependency not being serialized when saving * Remove superfluous update of mod meta data. Remove commented section in ConfigControl.xaml. * Optimized SteamworkshopService according to commit review. * Move SteamWorkshopService to Torch.Utils.SteamworkshopTools * Remove debug output. * Don't break stack trace with custom exception in SteamWorkshopTools. * User ViewModel base class for ModItemInfo instead of implementing INotifyProperty directly. * Wrap ModListControl in ScrollViewer. * Rename SteamWorkshopTools utility to WebAPI. * Revert steamkit call to use dynamic typing for clarity :/ * Mark webAPI based method for downloading workshop content as obsolete. * Update Torch project definition. * Disable building Torch client * Update readme * Change init order to ensure paths are initialized for plugins * Reorder exception logging to reduce duplication * Use thread safe queues in MtObservableCollectionBase * Revert "Change init order to ensure paths are initialized for plugins" This reverts commit 3f803b8. * Fix layout of ModListControl * Combine Invokes to reduce allocations * Replace string comparisons by string.Equals / string.IsNullOrEmpty * Replace string comparisons by string.Equals / string.IsNullOrEmpty * Use MtObservableList for Modlist to avoid race conditions.
1 parent 4e2e58b commit f265f7e

21 files changed

Lines changed: 1148 additions & 38 deletions

‎README.md‎

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,10 @@ Torch is the successor to SE Server Extender and gives server admins the tools t
1818
* 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.
1919
- If you already have a DS installed you can unzip the Torch files into the folder that contains the DedicatedServer64 folder.
2020

21-
## Torch.Client
22-
* An optional client-side version of Torch. More documentation to come.
23-
2421
# Building
2522
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.
2623

2724
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.
2825

29-
# Official Plugins
30-
Install plugins by unzipping them into the 'Plugins' folder which should be in the same location as the Torch files. If it doesn't exist you can simply create it.
31-
* [Essentials](https://github.com/TorchAPI/Essentials): Adds a slew of chat commands and other tools to help manage your server.
32-
* [Concealment](https://github.com/TorchAPI/Concealment): Adds game logic and physics optimizations that significantly improve sim speed.
33-
3426
If you have a more enjoyable server experience because of Torch, please consider supporting us on Patreon.
3527
[![Patreon](http://i.imgur.com/VzzIMgn.png)](https://www.patreon.com/bePatron?u=847269)!

‎Torch.Server/Initializer.cs‎

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -190,21 +190,29 @@ public static void RunSteamCmd()
190190
}
191191

192192
private void LogException(Exception ex)
193-
{
194-
if (ex.InnerException != null)
193+
{
194+
if (ex is AggregateException ag)
195195
{
196-
LogException(ex.InnerException);
197-
}
196+
foreach (var e in ag.InnerExceptions)
197+
LogException(e);
198198

199+
return;
200+
}
201+
199202
Log.Fatal(ex);
200203

201-
if (ex is ReflectionTypeLoadException exti)
202-
foreach (Exception exl in exti.LoaderExceptions)
204+
if (ex is ReflectionTypeLoadException extl)
205+
{
206+
foreach (var exl in extl.LoaderExceptions)
203207
LogException(exl);
208+
209+
return;
210+
}
204211

205-
if (ex is AggregateException ag)
206-
foreach (Exception e in ag.InnerExceptions)
207-
LogException(e);
212+
if (ex.InnerException != null)
213+
{
214+
LogException(ex.InnerException);
215+
}
208216
}
209217

210218
private void HandleException(object sender, UnhandledExceptionEventArgs e)

‎Torch.Server/Managers/InstanceManager.cs‎

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Collections.ObjectModel;
34
using System.ComponentModel;
45
using System.IO;
56
using System.Linq;
@@ -14,6 +15,7 @@
1415
using Sandbox.Game.Gui;
1516
using Torch.API;
1617
using Torch.API.Managers;
18+
using Torch.Collections;
1719
using Torch.Managers;
1820
using Torch.Mod;
1921
using Torch.Server.ViewModels;
@@ -94,7 +96,8 @@ public void SelectWorld(string worldPath, bool modsOnly = true)
9496
//remove the Torch mod to avoid running multiple copies of it
9597
DedicatedConfig.SelectedWorld.Checkpoint.Mods.RemoveAll(m => m.PublishedFileId == TorchModCore.MOD_ID);
9698
foreach (var m in DedicatedConfig.SelectedWorld.Checkpoint.Mods)
97-
DedicatedConfig.Mods.Add(m.PublishedFileId);
99+
DedicatedConfig.Mods.Add(new ModItemInfo(m));
100+
Task.Run(() => DedicatedConfig.UpdateAllModInfosAsync());
98101
}
99102
}
100103

@@ -108,7 +111,8 @@ public void SelectWorld(WorldViewModel world, bool modsOnly = true)
108111
//remove the Torch mod to avoid running multiple copies of it
109112
DedicatedConfig.SelectedWorld.Checkpoint.Mods.RemoveAll(m => m.PublishedFileId == TorchModCore.MOD_ID);
110113
foreach (var m in DedicatedConfig.SelectedWorld.Checkpoint.Mods)
111-
DedicatedConfig.Mods.Add(m.PublishedFileId);
114+
DedicatedConfig.Mods.Add(new ModItemInfo(m));
115+
Task.Run(() => DedicatedConfig.UpdateAllModInfosAsync());
112116
}
113117
}
114118

@@ -119,11 +123,10 @@ public void ImportSelectedWorldConfig()
119123

120124
private void ImportWorldConfig(WorldViewModel world, bool modsOnly = true)
121125
{
122-
var sb = new StringBuilder();
126+
var mods = new MtObservableList<ModItemInfo>();
123127
foreach (var mod in world.Checkpoint.Mods)
124-
sb.AppendLine(mod.PublishedFileId.ToString());
125-
126-
DedicatedConfig.Mods = world.Checkpoint.Mods.Select(x => x.PublishedFileId).ToList();
128+
mods.Add(new ModItemInfo(mod));
129+
DedicatedConfig.Mods = mods;
127130

128131

129132
Log.Debug("Loaded mod list from world");
@@ -151,7 +154,10 @@ private void ImportWorldConfig(bool modsOnly = true)
151154
return;
152155
}
153156

154-
DedicatedConfig.Mods = checkpoint.Mods.Select(x => x.PublishedFileId).ToList();
157+
var mods = new MtObservableList<ModItemInfo>();
158+
foreach (var mod in checkpoint.Mods)
159+
mods.Add(new ModItemInfo(mod));
160+
DedicatedConfig.Mods = mods;
155161

156162
Log.Debug("Loaded mod list from world");
157163

@@ -193,9 +199,14 @@ public void SaveConfig()
193199
checkpoint.SessionName = DedicatedConfig.WorldName;
194200
checkpoint.Settings = DedicatedConfig.SessionSettings;
195201
checkpoint.Mods.Clear();
196-
197-
foreach (var modId in DedicatedConfig.Mods)
198-
checkpoint.Mods.Add(new MyObjectBuilder_Checkpoint.ModItem(modId));
202+
203+
foreach (var mod in DedicatedConfig.Mods)
204+
{
205+
var savedMod = new MyObjectBuilder_Checkpoint.ModItem(mod.Name, mod.PublishedFileId, mod.FriendlyName);
206+
savedMod.IsDependency = mod.IsDependency;
207+
checkpoint.Mods.Add(savedMod);
208+
}
209+
Task.Run(() => DedicatedConfig.UpdateAllModInfosAsync());
199210

200211
MyObjectBuilderSerializer.SerializeXML(sandboxPath, false, checkpoint);
201212

‎Torch.Server/Torch.Server.csproj‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,19 @@
8080
<HintPath>..\GameBinaries\Microsoft.CodeAnalysis.CSharp.dll</HintPath>
8181
<Private>False</Private>
8282
</Reference>
83+
<Reference Include="Microsoft.Win32.Registry, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
84+
<HintPath>..\packages\Microsoft.Win32.Registry.4.4.0\lib\net461\Microsoft.Win32.Registry.dll</HintPath>
85+
</Reference>
8386
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
8487
<HintPath>..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
8588
</Reference>
8689
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
8790
<HintPath>..\packages\NLog.4.4.12\lib\net45\NLog.dll</HintPath>
8891
<Private>True</Private>
8992
</Reference>
93+
<Reference Include="protobuf-net, Version=2.1.0.0, Culture=neutral, PublicKeyToken=257b51d87d2e4d67, processorArchitecture=MSIL">
94+
<HintPath>..\packages\protobuf-net.2.1.0\lib\net451\protobuf-net.dll</HintPath>
95+
</Reference>
9096
<Reference Include="Sandbox.Common, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
9197
<SpecificVersion>False</SpecificVersion>
9298
<HintPath>..\GameBinaries\Sandbox.Common.dll</HintPath>
@@ -126,6 +132,12 @@
126132
<Reference Include="System.Data" />
127133
<Reference Include="System.Drawing" />
128134
<Reference Include="System.IO.Compression.FileSystem" />
135+
<Reference Include="System.Security.AccessControl, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
136+
<HintPath>..\packages\System.Security.AccessControl.4.4.0\lib\net461\System.Security.AccessControl.dll</HintPath>
137+
</Reference>
138+
<Reference Include="System.Security.Principal.Windows, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
139+
<HintPath>..\packages\System.Security.Principal.Windows.4.4.0\lib\net461\System.Security.Principal.Windows.dll</HintPath>
140+
</Reference>
129141
<Reference Include="System.ServiceProcess" />
130142
<Reference Include="System.Windows.Forms" />
131143
<Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
@@ -245,15 +257,21 @@
245257
<Compile Include="ViewModels\Entities\CharacterViewModel.cs" />
246258
<Compile Include="ViewModels\ConfigDedicatedViewModel.cs" />
247259
<Compile Include="ViewModels\Entities\EntityControlViewModel.cs" />
260+
<Compile Include="ViewModels\ModItemInfo.cs" />
248261
<Compile Include="ViewModels\SessionSettingsViewModel.cs" />
249262
<Compile Include="Views\Converters\DefinitionToIdConverter.cs" />
250263
<Compile Include="Views\Converters\BooleanAndConverter.cs" />
251264
<Compile Include="Views\Converters\ListConverter.cs" />
252265
<Compile Include="MultiTextWriter.cs" />
253266
<Compile Include="RichTextBoxWriter.cs" />
267+
<Compile Include="Views\Converters\ListConverterWorkshopId.cs" />
268+
<Compile Include="Views\Converters\ModToIdConverter.cs" />
254269
<Compile Include="Views\Entities\CharacterView.xaml.cs">
255270
<DependentUpon>CharacterView.xaml</DependentUpon>
256271
</Compile>
272+
<Compile Include="Views\ModListControl.xaml.cs">
273+
<DependentUpon>ModListControl.xaml</DependentUpon>
274+
</Compile>
257275
<Compile Include="Views\ThemeControl.xaml.cs">
258276
<DependentUpon>ThemeControl.xaml</DependentUpon>
259277
</Compile>
@@ -414,6 +432,10 @@
414432
<SubType>Designer</SubType>
415433
<Generator>MSBuild:Compile</Generator>
416434
</Page>
435+
<Page Include="Views\ModListControl.xaml">
436+
<SubType>Designer</SubType>
437+
<Generator>MSBuild:Compile</Generator>
438+
</Page>
417439
<Page Include="Views\PluginsControl.xaml">
418440
<SubType>Designer</SubType>
419441
<Generator>MSBuild:Compile</Generator>

‎Torch.Server/ViewModels/ConfigDedicatedViewModel.cs‎

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
using Torch.Server.Managers;
1111
using VRage.Game;
1212
using VRage.Game.ModAPI;
13+
using Torch.Utils.SteamWorkshopTools;
14+
using Torch.Collections;
1315

1416
namespace Torch.Server.ViewModels
1517
{
@@ -29,6 +31,7 @@ public ConfigDedicatedViewModel(MyConfigDedicated<MyObjectBuilder_SessionSetting
2931
_config = configDedicated;
3032
_config.IgnoreLastSession = true;
3133
SessionSettings = new SessionSettingsViewModel(_config.SessionSettings);
34+
Task.Run(() => UpdateAllModInfosAsync());
3235
}
3336

3437
public void Save(string path = null)
@@ -73,14 +76,61 @@ public WorldViewModel SelectedWorld
7376
}
7477
}
7578

79+
public async Task UpdateAllModInfosAsync(Action<string> messageHandler = null)
80+
{
81+
if (Mods.Count() == 0)
82+
return;
83+
84+
var ids = Mods.Select(m => m.PublishedFileId);
85+
var workshopService = WebAPI.Instance;
86+
Dictionary<ulong, PublishedItemDetails> modInfos = null;
87+
88+
try
89+
{
90+
modInfos = (await workshopService.GetPublishedFileDetails(ids.ToArray()));
91+
}
92+
catch (Exception e)
93+
{
94+
Log.Error(e.Message);
95+
return;
96+
}
97+
98+
Log.Info($"Mods Info successfully retrieved!");
99+
100+
foreach (var mod in Mods)
101+
{
102+
if (!modInfos.ContainsKey(mod.PublishedFileId) || modInfos[mod.PublishedFileId] == null)
103+
{
104+
Log.Error($"Failed to retrieve info for mod with workshop id '{mod.PublishedFileId}'!");
105+
}
106+
//else if (!modInfo.Tags.Contains(""))
107+
else
108+
{
109+
mod.FriendlyName = modInfos[mod.PublishedFileId].Title;
110+
mod.Description = modInfos[mod.PublishedFileId].Description;
111+
//mod.Name = modInfos[mod.PublishedFileId].FileName;
112+
}
113+
}
114+
115+
}
116+
76117
public List<string> Administrators { get => _config.Administrators; set => SetValue(x => _config.Administrators = x, value); }
77118

78119
public List<ulong> Banned { get => _config.Banned; set => SetValue(x => _config.Banned = x, value); }
79120

121+
private MtObservableList<ModItemInfo> _mods = new MtObservableList<ModItemInfo>();
122+
public MtObservableList<ModItemInfo> Mods
123+
{
124+
get => _mods;
125+
set
126+
{
127+
SetValue(x => _mods = x, value);
128+
Task.Run(() => UpdateAllModInfosAsync());
129+
}
130+
}
131+
80132
public List<ulong> Reserved { get => _config.Reserved; set => SetValue(x => _config.Reserved = x, value); }
81133

82-
private List<ulong> _mods = new List<ulong>();
83-
public List<ulong> Mods { get => _mods; set => SetValue(x => _mods = x, value); }
84134

85135
public int AsteroidAmount { get => _config.AsteroidAmount; set => SetValue(x => _config.AsteroidAmount = x, value); }
86136

0 commit comments

Comments
 (0)