diff --git a/Torch.Mod/Messages/DialogMessage.cs b/Torch.Mod/Messages/DialogMessage.cs
new file mode 100644
index 0000000..ae54317
--- /dev/null
+++ b/Torch.Mod/Messages/DialogMessage.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using ProtoBuf;
+using Sandbox.ModAPI;
+
+namespace Torch.Mod.Messages
+{
+ /// Dialogs are structured as follows
+ ///
+ /// _____________________________________
+ /// | Title |
+ /// --------------------------------------
+ /// | Prefix Subtitle |
+ /// --------------------------------------
+ /// | ________________________________ |
+ /// | | Content | |
+ /// | --------------------------------- |
+ /// | ____________ |
+ /// | | ButtonText | |
+ /// | -------------- |
+ /// --------------------------------------
+ ///
+ /// Button has a callback on click option,
+ /// but can't serialize that, so ¯\_(ツ)_/¯
+ [ProtoContract]
+ public class DialogMessage : MessageBase
+ {
+ [ProtoMember(201)]
+ public string Title;
+ [ProtoMember(202)]
+ public string Subtitle;
+ [ProtoMember(203)]
+ public string Prefix;
+ [ProtoMember(204)]
+ public string Content;
+ [ProtoMember(205)]
+ public string ButtonText;
+
+ public DialogMessage()
+ { }
+
+ public DialogMessage(string title, string subtitle, string content)
+ {
+ Title = title;
+ Subtitle = subtitle;
+ Content = content;
+ Prefix = String.Empty;
+ }
+
+ public DialogMessage(string title = null, string prefix = null, string subtitle = null, string content = null, string buttonText = null)
+ {
+ Title = title;
+ Subtitle = subtitle;
+ Prefix = prefix ?? String.Empty;
+ Content = content;
+ ButtonText = buttonText;
+ }
+
+ public override void ProcessClient()
+ {
+ MyAPIGateway.Utilities.ShowMissionScreen(Title, Prefix, Subtitle, Content, null, ButtonText);
+ }
+
+ public override void ProcessServer()
+ {
+ throw new Exception();
+ }
+ }
+}
diff --git a/Torch.Mod/Messages/MessageBase.cs b/Torch.Mod/Messages/MessageBase.cs
new file mode 100644
index 0000000..ce8f1a5
--- /dev/null
+++ b/Torch.Mod/Messages/MessageBase.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using ProtoBuf;
+
+namespace Torch.Mod.Messages
+{
+ #region Includes
+ [ProtoInclude(1, typeof(DialogMessage))]
+ [ProtoInclude(2, typeof(NotificationMessage))]
+ #endregion
+
+ [ProtoContract]
+ public abstract class MessageBase
+ {
+ [ProtoMember(101)]
+ public ulong SenderId;
+
+ public abstract void ProcessClient();
+ public abstract void ProcessServer();
+
+ //members below not serialized, they're just metadata about the intended target(s) of this message
+ internal MessageTarget TargetType;
+ internal ulong Target;
+ internal ulong[] Ignore;
+ internal byte[] CompressedData;
+ }
+
+ public enum MessageTarget
+ {
+ ///
+ /// Send to Target
+ ///
+ Single,
+ ///
+ /// Send to Server
+ ///
+ Server,
+ ///
+ /// Send to all Clients (only valid from server)
+ ///
+ AllClients,
+ ///
+ /// Send to all except those steam ID listed in Ignore
+ ///
+ AllExcept,
+ }
+}
diff --git a/Torch.Mod/Messages/NotificationMessage.cs b/Torch.Mod/Messages/NotificationMessage.cs
new file mode 100644
index 0000000..951f053
--- /dev/null
+++ b/Torch.Mod/Messages/NotificationMessage.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using ProtoBuf;
+using Sandbox.ModAPI;
+
+namespace Torch.Mod.Messages
+{
+ [ProtoContract]
+ public class NotificationMessage : MessageBase
+ {
+ [ProtoMember(201)]
+ public string Message;
+ [ProtoMember(202)]
+ public string Font;
+ [ProtoMember(203)]
+ public int DisappearTimeMs;
+
+ public NotificationMessage()
+ { }
+
+ public NotificationMessage(string message, int disappearTimeMs, string font)
+ {
+ Message = message;
+ DisappearTimeMs = disappearTimeMs;
+ Font = font;
+ }
+
+ public override void ProcessClient()
+ {
+ MyAPIGateway.Utilities.ShowNotification(Message, DisappearTimeMs, Font);
+ }
+
+ public override void ProcessServer()
+ {
+ throw new Exception();
+ }
+ }
+}
diff --git a/Torch.Mod/ModCommunication.cs b/Torch.Mod/ModCommunication.cs
new file mode 100644
index 0000000..0295e26
--- /dev/null
+++ b/Torch.Mod/ModCommunication.cs
@@ -0,0 +1,198 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Sandbox.ModAPI;
+using Torch.Mod.Messages;
+using VRage;
+using VRage.Game.ModAPI;
+using VRage.Utils;
+using Task = ParallelTasks.Task;
+
+namespace Torch.Mod
+{
+ public static class ModCommunication
+ {
+ public const ushort NET_ID = 4352;
+ private static bool _closing;
+ private static ConcurrentQueue _outgoing;
+ private static ConcurrentQueue _incoming;
+ private static List _playerCache;
+ private static FastResourceLock _lock;
+ private static Task _task;
+
+ public static void Register()
+ {
+ MyLog.Default.WriteLineAndConsole("TORCH MOD: Registering mod communication.");
+ _outgoing = new ConcurrentQueue();
+ _incoming = new ConcurrentQueue();
+ _playerCache = new List();
+ _lock = new FastResourceLock();
+
+
+ MyAPIGateway.Multiplayer.RegisterMessageHandler(NET_ID, MessageHandler);
+ //background thread to handle de/compression and processing
+ _task = MyAPIGateway.Parallel.StartBackground(DoProcessing);
+ MyLog.Default.WriteLineAndConsole("TORCH MOD: Mod communication registered successfully.");
+ }
+
+ public static void Unregister()
+ {
+ MyLog.Default.WriteLineAndConsole("TORCH MOD: Unregistering mod communication.");
+ MyAPIGateway.Multiplayer.UnregisterMessageHandler(NET_ID, MessageHandler);
+ _closing = true;
+ ReleaseLock();
+ _task.Wait();
+ }
+
+ private static void MessageHandler(byte[] bytes)
+ {
+ _incoming.Enqueue(bytes);
+ ReleaseLock();
+ }
+
+ public static void DoProcessing()
+ {
+ while (!_closing)
+ {
+ try
+ {
+ byte[] incoming;
+ while (_incoming.TryDequeue(out incoming))
+ {
+ MessageBase m;
+ try
+ {
+ var o = MyCompression.Decompress(incoming);
+ m = MyAPIGateway.Utilities.SerializeFromBinary(o);
+ }
+ catch (Exception ex)
+ {
+ MyLog.Default.WriteLineAndConsole($"TORCH MOD: Failed to deserialize message! {ex}");
+ continue;
+ }
+ if (MyAPIGateway.Multiplayer.IsServer)
+ m.ProcessServer();
+ else
+ m.ProcessClient();
+ }
+
+ if (!_outgoing.IsEmpty)
+ {
+ List tosend = new List(_outgoing.Count);
+ MessageBase outMessage;
+ while (_outgoing.TryDequeue(out outMessage))
+ {
+ var b = MyAPIGateway.Utilities.SerializeToBinary(outMessage);
+ outMessage.CompressedData = MyCompression.Compress(b);
+ tosend.Add(outMessage);
+ }
+
+ MyAPIGateway.Utilities.InvokeOnGameThread(() =>
+ {
+ MyAPIGateway.Players.GetPlayers(_playerCache);
+ foreach (var outgoing in tosend)
+ {
+ switch (outgoing.TargetType)
+ {
+ case MessageTarget.Single:
+ MyAPIGateway.Multiplayer.SendMessageTo(NET_ID, outgoing.CompressedData, outgoing.Target);
+ break;
+ case MessageTarget.Server:
+ MyAPIGateway.Multiplayer.SendMessageToServer(NET_ID, outgoing.CompressedData);
+ break;
+ case MessageTarget.AllClients:
+ foreach (var p in _playerCache)
+ {
+ if (p.SteamUserId == MyAPIGateway.Multiplayer.MyId)
+ continue;
+ MyAPIGateway.Multiplayer.SendMessageTo(NET_ID, outgoing.CompressedData, p.SteamUserId);
+ }
+ break;
+ case MessageTarget.AllExcept:
+ foreach (var p in _playerCache)
+ {
+ if (p.SteamUserId == MyAPIGateway.Multiplayer.MyId || outgoing.Ignore.Contains(p.SteamUserId))
+ continue;
+ MyAPIGateway.Multiplayer.SendMessageTo(NET_ID, outgoing.CompressedData, p.SteamUserId);
+ }
+ break;
+ default:
+ throw new Exception();
+ }
+ }
+ _playerCache.Clear();
+ });
+ }
+
+ AcquireLock();
+ }
+ catch (Exception ex)
+ {
+ MyLog.Default.WriteLineAndConsole($"TORCH MOD: Exception occurred in communication thread! {ex}");
+ }
+ }
+
+ MyLog.Default.WriteLineAndConsole("TORCH MOD: COMMUNICATION THREAD: EXIT SIGNAL RECIEVED!");
+ //exit signal received. Clean everything and GTFO
+ _outgoing = null;
+ _incoming = null;
+ _playerCache = null;
+ _lock = null;
+ }
+
+ public static void SendMessageTo(MessageBase message, ulong target)
+ {
+ if (!MyAPIGateway.Multiplayer.IsServer)
+ throw new Exception("Only server can send targeted messages");
+ message.Target = target;
+ message.TargetType = MessageTarget.Single;
+ MyLog.Default.WriteLineAndConsole($"Sending message of type {message.GetType().FullName}");
+ _outgoing.Enqueue(message);
+ ReleaseLock();
+ }
+
+ public static void SendMessageToClients(MessageBase message)
+ {
+ if (!MyAPIGateway.Multiplayer.IsServer)
+ throw new Exception("Only server can send targeted messages");
+ message.TargetType = MessageTarget.AllClients;
+ _outgoing.Enqueue(message);
+ ReleaseLock();
+ }
+
+ public static void SendMessageExcept(MessageBase message, params ulong[] ignoredUsers)
+ {
+ if (MyAPIGateway.Multiplayer.IsServer)
+ throw new Exception("Only server can send targeted messages");
+ message.TargetType = MessageTarget.AllExcept;
+ message.Ignore = ignoredUsers;
+ _outgoing.Enqueue(message);
+ ReleaseLock();
+ }
+
+ public static void SendMessageToServer(MessageBase message)
+ {
+ message.TargetType = MessageTarget.Server;
+ _outgoing.Enqueue(message);
+ ReleaseLock();
+ }
+
+ private static void ReleaseLock()
+ {
+ while(!_lock.TryAcquireExclusive())
+ _lock.ReleaseExclusive();
+ _lock.ReleaseExclusive();
+ }
+
+ private static void AcquireLock()
+ {
+ ReleaseLock();
+ _lock.AcquireExclusive();
+ _lock.AcquireExclusive();
+ }
+ }
+}
diff --git a/Torch.Mod/Torch.Mod.projitems b/Torch.Mod/Torch.Mod.projitems
new file mode 100644
index 0000000..a6b330f
--- /dev/null
+++ b/Torch.Mod/Torch.Mod.projitems
@@ -0,0 +1,18 @@
+
+
+
+ $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
+ true
+ 3ce4d2e9-b461-4f19-8233-f87e0dfddd74
+
+
+ Torch.Mod
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Torch.Mod/Torch.Mod.shproj b/Torch.Mod/Torch.Mod.shproj
new file mode 100644
index 0000000..bc7cbf1
--- /dev/null
+++ b/Torch.Mod/Torch.Mod.shproj
@@ -0,0 +1,13 @@
+
+
+
+ 3ce4d2e9-b461-4f19-8233-f87e0dfddd74
+ 14.0
+
+
+
+
+
+
+
+
diff --git a/Torch.Mod/TorchModCore.cs b/Torch.Mod/TorchModCore.cs
new file mode 100644
index 0000000..b058636
--- /dev/null
+++ b/Torch.Mod/TorchModCore.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using VRage.Game.Components;
+
+namespace Torch.Mod
+{
+ [MySessionComponentDescriptor(MyUpdateOrder.AfterSimulation)]
+ public class TorchModCore : MySessionComponentBase
+ {
+ public const long MOD_ID = 1406994352;
+ private static bool _init;
+
+ public override void UpdateAfterSimulation()
+ {
+ if (_init)
+ return;
+
+ _init = true;
+ ModCommunication.Register();
+ }
+
+ protected override void UnloadData()
+ {
+ ModCommunication.Unregister();
+ }
+ }
+}
diff --git a/Torch.Server/TorchServer.cs b/Torch.Server/TorchServer.cs
index 21aa84e..42d1aa0 100644
--- a/Torch.Server/TorchServer.cs
+++ b/Torch.Server/TorchServer.cs
@@ -18,6 +18,7 @@ using Torch.API;
using Torch.API.Managers;
using Torch.API.Session;
using Torch.Commands;
+using Torch.Mod;
using Torch.Server.Commands;
using Torch.Server.Managers;
using Torch.Utils;
@@ -45,7 +46,7 @@ namespace Torch.Server
private Timer _watchdog;
///
- public TorchServer(TorchConfig config = null)
+ public TorchServer(TorchConfig config = null)
{
DedicatedInstance = new InstanceManager(this);
AddManager(DedicatedInstance);
@@ -174,10 +175,14 @@ namespace Torch.Server
{
_watchdog?.Dispose();
_watchdog = null;
+ ModCommunication.Unregister();
}
if (newState == TorchSessionState.Loaded)
+ {
CurrentSession.Managers.GetManager().RegisterCommandModule(typeof(WhitelistCommands));
+ ModCommunication.Register();
+ }
}
///
diff --git a/Torch.sln b/Torch.sln
index e78e377..9f2f29b 100644
--- a/Torch.sln
+++ b/Torch.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
-VisualStudioVersion = 15.0.27004.2010
+VisualStudioVersion = 15.0.26430.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch", "Torch\Torch.csproj", "{7E01635C-3B67-472E-BCD6-C5539564F214}"
EndProject
@@ -27,41 +27,60 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Versioning", "Versioning",
Versioning\AssemblyVersion.cs = Versioning\AssemblyVersion.cs
EndProjectSection
EndProject
+Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Torch.Mod", "Torch.Mod\Torch.Mod.shproj", "{3CE4D2E9-B461-4F19-8233-F87E0DFDDD74}"
+EndProject
Global
- GlobalSection(Performance) = preSolution
- HasPerformanceSessions = true
+ GlobalSection(SharedMSBuildProjectFiles) = preSolution
+ Torch.Mod\Torch.Mod.projitems*{3ce4d2e9-b461-4f19-8233-f87e0dfddd74}*SharedItemsImports = 13
+ Torch.Mod\Torch.Mod.projitems*{7e01635c-3b67-472e-bcd6-c5539564f214}*SharedItemsImports = 4
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
+ Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7E01635C-3B67-472E-BCD6-C5539564F214}.Debug|Any CPU.ActiveCfg = Debug|x64
{7E01635C-3B67-472E-BCD6-C5539564F214}.Debug|x64.ActiveCfg = Debug|x64
{7E01635C-3B67-472E-BCD6-C5539564F214}.Debug|x64.Build.0 = Debug|x64
+ {7E01635C-3B67-472E-BCD6-C5539564F214}.Release|Any CPU.ActiveCfg = Release|x64
{7E01635C-3B67-472E-BCD6-C5539564F214}.Release|x64.ActiveCfg = Release|x64
{7E01635C-3B67-472E-BCD6-C5539564F214}.Release|x64.Build.0 = Release|x64
+ {FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}.Debug|Any CPU.ActiveCfg = Debug|x64
{FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}.Debug|x64.ActiveCfg = Debug|x64
{FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}.Debug|x64.Build.0 = Debug|x64
+ {FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}.Release|Any CPU.ActiveCfg = Release|x64
{FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}.Release|x64.ActiveCfg = Release|x64
{FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}.Release|x64.Build.0 = Release|x64
+ {E36DF745-260B-4956-A2E8-09F08B2E7161}.Debug|Any CPU.ActiveCfg = Debug|x64
{E36DF745-260B-4956-A2E8-09F08B2E7161}.Debug|x64.ActiveCfg = Debug|x64
{E36DF745-260B-4956-A2E8-09F08B2E7161}.Debug|x64.Build.0 = Debug|x64
+ {E36DF745-260B-4956-A2E8-09F08B2E7161}.Release|Any CPU.ActiveCfg = Release|x64
{E36DF745-260B-4956-A2E8-09F08B2E7161}.Release|x64.ActiveCfg = Release|x64
{E36DF745-260B-4956-A2E8-09F08B2E7161}.Release|x64.Build.0 = Release|x64
+ {CA50886B-7B22-4CD8-93A0-C06F38D4F77D}.Debug|Any CPU.ActiveCfg = Debug|x64
{CA50886B-7B22-4CD8-93A0-C06F38D4F77D}.Debug|x64.ActiveCfg = Debug|x64
{CA50886B-7B22-4CD8-93A0-C06F38D4F77D}.Debug|x64.Build.0 = Debug|x64
+ {CA50886B-7B22-4CD8-93A0-C06F38D4F77D}.Release|Any CPU.ActiveCfg = Release|x64
{CA50886B-7B22-4CD8-93A0-C06F38D4F77D}.Release|x64.ActiveCfg = Release|x64
{CA50886B-7B22-4CD8-93A0-C06F38D4F77D}.Release|x64.Build.0 = Release|x64
+ {C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}.Debug|Any CPU.ActiveCfg = Debug|x64
{C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}.Debug|x64.ActiveCfg = Debug|x64
{C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}.Debug|x64.Build.0 = Debug|x64
+ {C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}.Release|Any CPU.ActiveCfg = Release|x64
{C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}.Release|x64.ActiveCfg = Release|x64
{C3C8B671-6AD1-44AA-A8DA-E0C0DC0FEDF5}.Release|x64.Build.0 = Release|x64
+ {9EFD1D91-2FA2-47ED-B537-D8BC3B0E543E}.Debug|Any CPU.ActiveCfg = Debug|x64
{9EFD1D91-2FA2-47ED-B537-D8BC3B0E543E}.Debug|x64.ActiveCfg = Debug|x64
{9EFD1D91-2FA2-47ED-B537-D8BC3B0E543E}.Debug|x64.Build.0 = Debug|x64
+ {9EFD1D91-2FA2-47ED-B537-D8BC3B0E543E}.Release|Any CPU.ActiveCfg = Release|x64
{9EFD1D91-2FA2-47ED-B537-D8BC3B0E543E}.Release|x64.ActiveCfg = Release|x64
{9EFD1D91-2FA2-47ED-B537-D8BC3B0E543E}.Release|x64.Build.0 = Release|x64
+ {632E78C0-0DAC-4B71-B411-2F1B333CC310}.Debug|Any CPU.ActiveCfg = Debug|x64
{632E78C0-0DAC-4B71-B411-2F1B333CC310}.Debug|x64.ActiveCfg = Debug|x64
{632E78C0-0DAC-4B71-B411-2F1B333CC310}.Debug|x64.Build.0 = Debug|x64
+ {632E78C0-0DAC-4B71-B411-2F1B333CC310}.Release|Any CPU.ActiveCfg = Release|x64
{632E78C0-0DAC-4B71-B411-2F1B333CC310}.Release|x64.ActiveCfg = Release|x64
{632E78C0-0DAC-4B71-B411-2F1B333CC310}.Release|x64.Build.0 = Release|x64
EndGlobalSection
@@ -74,4 +93,7 @@ Global
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB51D91F-958D-4B63-A897-3C40642ACD3E}
EndGlobalSection
+ GlobalSection(Performance) = preSolution
+ HasPerformanceSessions = true
+ EndGlobalSection
EndGlobal
diff --git a/Torch/Commands/TorchCommands.cs b/Torch/Commands/TorchCommands.cs
index e3affc8..1879bae 100644
--- a/Torch/Commands/TorchCommands.cs
+++ b/Torch/Commands/TorchCommands.cs
@@ -17,6 +17,8 @@ using Torch.API.Managers;
using Torch.API.Session;
using Torch.Commands.Permissions;
using Torch.Managers;
+using Torch.Mod;
+using Torch.Mod.Messages;
using VRage.Game.ModAPI;
namespace Torch.Commands
@@ -75,7 +77,7 @@ namespace Torch.Commands
}
}
- [Command("longhelp", "Get verbose help. Will send a long message, check the Comms tab.")]
+ [Command("longhelp", "Get verbose help. Will send a long message in a dialog window.")]
[Permission(MyPromoteLevel.None)]
public void LongHelp()
{
@@ -107,13 +109,20 @@ namespace Torch.Commands
}
else
{
- var sb = new StringBuilder("Available commands:\n");
+ var sb = new StringBuilder();
foreach (var command in commandManager.Commands.WalkTree())
{
if (command.IsCommand)
sb.AppendLine($"{command.Command.SyntaxHelp}\n {command.Command.HelpText}");
}
- Context.Respond(sb.ToString());
+
+ if (!Context.SentBySelf)
+ {
+ var m = new DialogMessage("Torch Help", subtitle: "Available commands:", content: sb.ToString());
+ ModCommunication.SendMessageTo(m, Context.Player.SteamUserId);
+ }
+ else
+ Context.Respond($"Available commands: {sb}");
}
}
@@ -169,6 +178,13 @@ namespace Torch.Commands
});
}
+ [Command("notify", "Shows a message as a notification in the middle of all players' screens.")]
+ [Permission(MyPromoteLevel.Admin)]
+ public void Notify(string message, int disappearTimeMs = 2000, string font = "White")
+ {
+ ModCommunication.SendMessageToClients(new NotificationMessage(message, disappearTimeMs, font));
+ }
+
[Command("restart cancel", "Cancel a pending restart.")]
public void CancelRestart()
{
diff --git a/Torch/Patches/SessionDownloadPatch.cs b/Torch/Patches/SessionDownloadPatch.cs
new file mode 100644
index 0000000..fc81ad5
--- /dev/null
+++ b/Torch/Patches/SessionDownloadPatch.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using Sandbox.Game.World;
+using Torch.Managers.PatchManager;
+using Torch.Mod;
+using VRage.Game;
+
+namespace Torch.Patches
+{
+ [PatchShim]
+ internal class SessionDownloadPatch
+ {
+ internal static void Patch(PatchContext context)
+ {
+ context.GetPattern(typeof(MySession).GetMethod(nameof(MySession.GetWorld))).Suffixes.Add(typeof(SessionDownloadPatch).GetMethod(nameof(SuffixGetWorld), BindingFlags.Static | BindingFlags.NonPublic));
+ }
+
+ // ReSharper disable once InconsistentNaming
+ private static void SuffixGetWorld(ref MyObjectBuilder_World __result)
+ {
+ if (!__result.Checkpoint.Mods.Any(m => m.PublishedFileId == TorchModCore.MOD_ID))
+ __result.Checkpoint.Mods.Add(new MyObjectBuilder_Checkpoint.ModItem(TorchModCore.MOD_ID));
+ }
+ }
+}
diff --git a/Torch/Torch.csproj b/Torch/Torch.csproj
index e9791ac..b10ede3 100644
--- a/Torch/Torch.csproj
+++ b/Torch/Torch.csproj
@@ -209,6 +209,7 @@
+
@@ -318,6 +319,7 @@
+
\ No newline at end of file