From 8560694dc8bbf7a8cad64745751abad4c947a462 Mon Sep 17 00:00:00 2001 From: starfish <50672801+starfi5h@users.noreply.github.com> Date: Fri, 5 Apr 2024 17:22:08 +0800 Subject: [PATCH 1/5] Move SaveManager to namespace NebulaWorld --- NebulaWorld/Chat/Commands/PlayerDataCommandHandler.cs | 5 ++--- {NebulaNetwork => NebulaWorld}/SaveManager.cs | 8 ++++++-- 2 files changed, 8 insertions(+), 5 deletions(-) rename {NebulaNetwork => NebulaWorld}/SaveManager.cs (97%) diff --git a/NebulaWorld/Chat/Commands/PlayerDataCommandHandler.cs b/NebulaWorld/Chat/Commands/PlayerDataCommandHandler.cs index aac8e4af5..ac66ff738 100644 --- a/NebulaWorld/Chat/Commands/PlayerDataCommandHandler.cs +++ b/NebulaWorld/Chat/Commands/PlayerDataCommandHandler.cs @@ -26,8 +26,7 @@ public void Execute(ChatWindow window, string[] parameters) } // Due to dependency order, get SaveManager.playerSaves by reflection - var saveManagerType = AccessTools.TypeByName("NebulaNetwork.SaveManager"); - var playerSaves = (Dictionary)AccessTools.Field(saveManagerType, "playerSaves").GetValue(null); + var playerSaves = SaveManager.PlayerSaves; switch (parameters[0]) { @@ -72,7 +71,7 @@ public void Execute(ChatWindow window, string[] parameters) break; } } - playerSaves.Remove(removeHash); + SaveManager.TryRemove(removeHash); break; } } diff --git a/NebulaNetwork/SaveManager.cs b/NebulaWorld/SaveManager.cs similarity index 97% rename from NebulaNetwork/SaveManager.cs rename to NebulaWorld/SaveManager.cs index c8b8a8107..fcc773538 100644 --- a/NebulaNetwork/SaveManager.cs +++ b/NebulaWorld/SaveManager.cs @@ -8,11 +8,10 @@ using NebulaModel.Logger; using NebulaModel.Networking.Serialization; using NebulaModel.Utils; -using NebulaWorld; #endregion -namespace NebulaNetwork; +namespace NebulaWorld; public static class SaveManager { @@ -176,4 +175,9 @@ public static bool TryAdd(string clientCertHash, IPlayerData playerData) playerSaves.Add(clientCertHash, playerData); return true; } + + public static bool TryRemove(string clientCertHash) + { + return playerSaves.Remove(clientCertHash); + } } From 097c139c72ce90b31332a601c9bc80c0740da09f Mon Sep 17 00:00:00 2001 From: starfish <50672801+starfi5h@users.noreply.github.com> Date: Fri, 5 Apr 2024 18:35:43 +0800 Subject: [PATCH 2/5] Add PlayerDataCommandPacket for client --- .../Packets/Chat/PlayerDataCommandPacket.cs | 19 ++++++ .../Chat/PlyaerDataCommmandProcessor.cs | 62 +++++++++++++++++++ .../Chat/Commands/PlayerDataCommandHandler.cs | 47 +++++++++++--- 3 files changed, 118 insertions(+), 10 deletions(-) create mode 100644 NebulaModel/Packets/Chat/PlayerDataCommandPacket.cs create mode 100644 NebulaNetwork/PacketProcessors/Chat/PlyaerDataCommmandProcessor.cs diff --git a/NebulaModel/Packets/Chat/PlayerDataCommandPacket.cs b/NebulaModel/Packets/Chat/PlayerDataCommandPacket.cs new file mode 100644 index 000000000..1ab088229 --- /dev/null +++ b/NebulaModel/Packets/Chat/PlayerDataCommandPacket.cs @@ -0,0 +1,19 @@ +using NebulaModel.DataStructures; + +namespace NebulaModel.Packets.Chat; + +public class PlayerDataCommandPacket +{ + public PlayerDataCommandPacket() { } + + public PlayerDataCommandPacket(string command, string message, PlayerData playerData = null) + { + Command = command; + Message = message; + PlayerData = playerData; + } + + public string Command { get; set; } + public string Message { get; set; } + public PlayerData PlayerData { get; set; } +} diff --git a/NebulaNetwork/PacketProcessors/Chat/PlyaerDataCommmandProcessor.cs b/NebulaNetwork/PacketProcessors/Chat/PlyaerDataCommmandProcessor.cs new file mode 100644 index 000000000..f8705d78c --- /dev/null +++ b/NebulaNetwork/PacketProcessors/Chat/PlyaerDataCommmandProcessor.cs @@ -0,0 +1,62 @@ +#region + +using NebulaAPI.Packets; +using NebulaModel.DataStructures.Chat; +using NebulaModel.Networking; +using NebulaModel.Packets; +using NebulaModel.Packets.Chat; +using NebulaWorld; +using NebulaWorld.Chat.Commands; +using NebulaWorld.MonoBehaviours.Local.Chat; + +#endregion + +namespace NebulaNetwork.PacketProcessors.Chat; + +[RegisterPacketProcessor] +internal class PlyaerDataCommmandProcessor : PacketProcessor +{ + protected override void ProcessPacket(PlayerDataCommandPacket packet, NebulaConnection conn) + { + if (IsHost) + { + packet.PlayerData = null; + var playerSaves = SaveManager.PlayerSaves; + switch (packet.Command) + { + case "list": + packet.Message = PlayerDataCommandHandler.GetPlayerDataListString(); + break; + + case "load": + var input = packet.Message; + packet.Message = "Unable to find the target player data!"; + foreach (var pair in playerSaves) + { + if (input == pair.Key.Substring(0, input.Length) || input == pair.Value.Username) + { + packet.Message = $"Load [{pair.Key.Substring(0, 5)}] {pair.Value.Username}"; + packet.PlayerData = (NebulaModel.DataStructures.PlayerData)pair.Value; + break; + } + } + break; + + default: + packet.Message = "Unknown command: " + packet.Command; + break; + } + conn.SendPacket(packet); + return; + } + + if (IsClient) + { + ChatManager.Instance.SendChatMessage(packet.Message, ChatMessageType.CommandOutputMessage); + if (packet.PlayerData != null) + { + PlayerDataCommandHandler.LoadPlayerData(packet.PlayerData); + } + } + } +} diff --git a/NebulaWorld/Chat/Commands/PlayerDataCommandHandler.cs b/NebulaWorld/Chat/Commands/PlayerDataCommandHandler.cs index ac66ff738..6ade168d8 100644 --- a/NebulaWorld/Chat/Commands/PlayerDataCommandHandler.cs +++ b/NebulaWorld/Chat/Commands/PlayerDataCommandHandler.cs @@ -1,9 +1,7 @@ #region using NebulaWorld.MonoBehaviours.Local.Chat; -using System.Collections.Generic; using NebulaAPI.GameState; -using HarmonyLib; using NebulaModel.DataStructures.Chat; using System.IO; using NebulaModel; @@ -11,6 +9,7 @@ using NebulaAPI.DataStructures; using NebulaModel.Networking; using NebulaModel.Packets.Players; +using NebulaModel.Packets.Chat; #endregion @@ -32,19 +31,26 @@ public void Execute(ChatWindow window, string[] parameters) { case "list": { - var resp = $"Player count in .server file: {playerSaves.Count}\n"; - foreach (var pair in playerSaves) + if (Multiplayer.Session.IsClient) { - resp += $"[{pair.Key.Substring(0, 5)}] {pair.Value.Username}"; + Multiplayer.Session.Client.SendPacket(new PlayerDataCommandPacket("list", "")); + return; } - window.SendLocalChatMessage(resp, ChatMessageType.CommandOutputMessage); - break; + + window.SendLocalChatMessage(GetPlayerDataListString(), ChatMessageType.CommandOutputMessage); + return; } case "load" when parameters.Length < 2: throw new ChatCommandUsageException("Need to specifiy hash string or name of a player!"); case "load": { var input = parameters[1]; + if (Multiplayer.Session.IsClient) + { + Multiplayer.Session.Client.SendPacket(new PlayerDataCommandPacket("load", input)); + return; + } + foreach (var pair in playerSaves) { if (input == pair.Key.Substring(0, input.Length) || input == pair.Value.Username) @@ -54,12 +60,18 @@ public void Execute(ChatWindow window, string[] parameters) return; } } - break; + window.SendLocalChatMessage("Unable to find the target player data!", ChatMessageType.CommandOutputMessage); + return; } case "remove" when parameters.Length < 2: throw new ChatCommandUsageException("Need to specifiy hash string or name of a player!"); case "remove": { + if (Multiplayer.Session.IsClient) + { + throw new ChatCommandUsageException("remove command is not available in client!"); + } + var input = parameters[1]; var removeHash = ""; foreach (var pair in playerSaves) @@ -71,7 +83,10 @@ public void Execute(ChatWindow window, string[] parameters) break; } } - SaveManager.TryRemove(removeHash); + if (!SaveManager.TryRemove(removeHash)) + { + window.SendLocalChatMessage("Unable to find the target player data!", ChatMessageType.CommandOutputMessage); + } break; } } @@ -87,7 +102,19 @@ public string[] GetUsage() return ["list", "load ", "remove "]; } - static void LoadPlayerData(IPlayerData playerData) + public static string GetPlayerDataListString() + { + var playerSaves = SaveManager.PlayerSaves; + + var resp = $"Player count in .server file: {playerSaves.Count}\n"; + foreach (var pair in playerSaves) + { + resp += $"[{pair.Key.Substring(0, 5)}] {pair.Value.Username}\n"; + } + return resp; + } + + public static void LoadPlayerData(IPlayerData playerData) { Log.Info($"Teleporting to target planet {GameMain.localPlanet?.id ?? 0} => {playerData.LocalPlanetId}"); var actionSail = GameMain.mainPlayer.controller.actionSail; From 198e9ae20a2ad1c11c17a0ec973006242dca8679 Mon Sep 17 00:00:00 2001 From: starfish <50672801+starfi5h@users.noreply.github.com> Date: Fri, 5 Apr 2024 21:16:39 +0800 Subject: [PATCH 3/5] Add chat config Show Timestamp --- NebulaModel/MultiplayerOptions.cs | 6 ++- .../Chat/NewChatMessageProcessor.cs | 7 +-- .../Chat/Commands/WhisperCommandHandler.cs | 6 +-- .../MonoBehaviours/Local/Chat/ChatManager.cs | 44 +++++++++++++++++++ .../MonoBehaviours/Local/Chat/ChatWindow.cs | 2 +- 5 files changed, 55 insertions(+), 10 deletions(-) diff --git a/NebulaModel/MultiplayerOptions.cs b/NebulaModel/MultiplayerOptions.cs index b9eed4492..a9d4cf5fb 100644 --- a/NebulaModel/MultiplayerOptions.cs +++ b/NebulaModel/MultiplayerOptions.cs @@ -132,7 +132,11 @@ public bool StreamerMode [DisplayName("Auto Open Chat")] [Category("Chat")] [Description("Auto open chat window when receiving message from other players")] - public bool AutoOpenChat { get; set; } = true; + public bool AutoOpenChat { get; set; } = false; + + [DisplayName("Show Timestamp")] + [Category("Chat")] + public bool EnableTimestamp { get; set; } = true; [DisplayName("Show system warn message")] [Category("Chat")] diff --git a/NebulaNetwork/PacketProcessors/Chat/NewChatMessageProcessor.cs b/NebulaNetwork/PacketProcessors/Chat/NewChatMessageProcessor.cs index a31fda5e6..94c94203d 100644 --- a/NebulaNetwork/PacketProcessors/Chat/NewChatMessageProcessor.cs +++ b/NebulaNetwork/PacketProcessors/Chat/NewChatMessageProcessor.cs @@ -26,14 +26,11 @@ protected override void ProcessPacket(NewChatMessagePacket packet, NebulaConnect if (IsHost) { - var player = Players.Get(conn); Server.SendPacketExclude(packet, conn); } var sentAt = packet.SentAt == 0 ? DateTime.Now : DateTime.FromBinary(packet.SentAt); - ChatManager.Instance.SendChatMessage( - string.IsNullOrEmpty(packet.UserName) - ? $"[{sentAt:HH:mm}] {packet.MessageText}" - : $"[{sentAt:HH:mm}] [{packet.UserName}] : {packet.MessageText}", packet.MessageType); + ChatManager.Instance.SendChatMessage(ChatManager.FormatChatMessage(sentAt, packet.UserName, packet.MessageText), + packet.MessageType); } } diff --git a/NebulaWorld/Chat/Commands/WhisperCommandHandler.cs b/NebulaWorld/Chat/Commands/WhisperCommandHandler.cs index 81624a216..a16bec60c 100644 --- a/NebulaWorld/Chat/Commands/WhisperCommandHandler.cs +++ b/NebulaWorld/Chat/Commands/WhisperCommandHandler.cs @@ -29,8 +29,8 @@ public void Execute(ChatWindow window, string[] parameters) var recipientUserName = parameters[0]; var fullMessageBody = string.Join(" ", parameters.Skip(1)); // first echo what the player typed so they know something actually happened - ChatManager.Instance.SendChatMessage($"[{DateTime.Now:HH:mm}] [To: {recipientUserName}] : {fullMessageBody}", - ChatMessageType.PlayerMessage); + ChatManager.Instance.SendChatMessage(ChatManager.FormatChatMessage(DateTime.Now, $"[To {recipientUserName}]", fullMessageBody), + ChatMessageType.PlayerMessagePrivate); var packet = new ChatCommandWhisperPacket(senderUsername, recipientUserName, fullMessageBody); @@ -64,7 +64,7 @@ public string[] GetUsage() public static void SendWhisperToLocalPlayer(string sender, string mesageBody) { - ChatManager.Instance.SendChatMessage($"[{DateTime.Now:HH:mm}] [{sender} whispered] : {mesageBody}", + ChatManager.Instance.SendChatMessage(ChatManager.FormatChatMessage(DateTime.Now, $"[From {sender}]", mesageBody), ChatMessageType.PlayerMessagePrivate); } } diff --git a/NebulaWorld/MonoBehaviours/Local/Chat/ChatManager.cs b/NebulaWorld/MonoBehaviours/Local/Chat/ChatManager.cs index d414ac332..f4e293a6b 100644 --- a/NebulaWorld/MonoBehaviours/Local/Chat/ChatManager.cs +++ b/NebulaWorld/MonoBehaviours/Local/Chat/ChatManager.cs @@ -1,11 +1,13 @@ #region using System; +using System.Linq; using NebulaModel; using NebulaModel.DataStructures.Chat; using NebulaModel.Logger; using NebulaModel.Packets.Chat; using NebulaModel.Utils; +using NebulaWorld.Chat.ChatLinks; using UnityEngine; using UnityEngine.UI; @@ -16,6 +18,7 @@ namespace NebulaWorld.MonoBehaviours.Local.Chat; public class ChatManager : MonoBehaviour { public static ChatManager Instance; + private static bool showedWelcome = false; private Image backgroundImage; private ChatWindow chatWindow; @@ -81,6 +84,13 @@ private void Awake() chatWindow.UserName = GetUserName(); chatWindow.Toggle(true); Config.OnConfigApplied += UpdateChatPosition; + + if (!showedWelcome) + { + showedWelcome = true; + SendChatMessage(string.Format("Welcome to Nebula multiplayer mod! Press {0} to open chat window, type /help to see all commands.".Translate() + , Config.Options.ChatHotkey.ToString()), ChatMessageType.SystemInfoMessage); + } } private void Update() @@ -135,6 +145,40 @@ private static string GetUserName() return Multiplayer.Session?.LocalPlayer?.Data?.Username ?? "Unknown"; } + public static string FormatChatMessage(in DateTime sentTime, string userName, string messageBody) + { + // format: $"[{sentTime:HH:mm}] {userName} : {messageBody} + + var formattedString = ""; + if (!string.IsNullOrEmpty(userName)) + { + ushort playerId = 0; + if (Multiplayer.IsActive) + { + using (Multiplayer.Session.World.GetRemotePlayersModels(out var remotePlayersModels)) + { + playerId = remotePlayersModels.FirstOrDefault(x => x.Value.Username == userName).Key; + } + } + if (playerId > 0) + { + formattedString = NavigateChatLinkHandler.FormatNavigateToPlayerString(playerId, userName); + } + else + { + formattedString = userName; + } + } + if (Config.Options.EnableTimestamp) + { + formattedString = $"[{sentTime:HH:mm}] {formattedString} : "; + } + else if (!string.IsNullOrEmpty(formattedString)) + { + formattedString += " : "; + } + return formattedString + messageBody; + } // Queue a message to appear in chat window public void SendChatMessage(string text, ChatMessageType messageType) diff --git a/NebulaWorld/MonoBehaviours/Local/Chat/ChatWindow.cs b/NebulaWorld/MonoBehaviours/Local/Chat/ChatWindow.cs index 820d8a8e3..63b2030a8 100644 --- a/NebulaWorld/MonoBehaviours/Local/Chat/ChatWindow.cs +++ b/NebulaWorld/MonoBehaviours/Local/Chat/ChatWindow.cs @@ -182,7 +182,7 @@ private void TrySendMessage() private void BroadcastChatMessage(string message, ChatMessageType chatMessageType = ChatMessageType.PlayerMessage) { QueueOutgoingChatMessage(message, chatMessageType); - var formattedMessage = $"[{DateTime.Now:HH:mm}] [{UserName}] : {message}"; + var formattedMessage = ChatManager.FormatChatMessage(DateTime.Now, UserName, message); SendLocalChatMessage(formattedMessage, chatMessageType); } From 1b5ef60e088ca85c1efe58b1f8a05dd50ad92fbc Mon Sep 17 00:00:00 2001 From: starfish <50672801+starfi5h@users.noreply.github.com> Date: Fri, 5 Apr 2024 23:26:28 +0800 Subject: [PATCH 4/5] Add CLI argument -newgame-cfg to start with parameters in nebulaGameDescSettings.cfg --- NebulaPatcher/NebulaPlugin.cs | 63 +++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/NebulaPatcher/NebulaPlugin.cs b/NebulaPatcher/NebulaPlugin.cs index e9cc706a0..f5872d3a9 100644 --- a/NebulaPatcher/NebulaPlugin.cs +++ b/NebulaPatcher/NebulaPlugin.cs @@ -4,6 +4,7 @@ using System.IO; using System.Reflection; using BepInEx; +using BepInEx.Configuration; using HarmonyLib; using NebulaAPI.Interfaces; using NebulaModel.Logger; @@ -79,6 +80,18 @@ private void Awake() } } + if (args[i] == "-newgame-cfg") + { + newgameArgExists = true; + var gameDesc = new GameDesc(); + var random = new DotNet35Random((int)(DateTime.UtcNow.Ticks / 10000L)); + gameDesc.SetForNewGame(UniverseGen.algoVersion, random.Next(100000000), 64, 1, 1f); + SetGameDescFromConfigFile(gameDesc); + Log.Info($">> Creating new game ({gameDesc.galaxySeed}, {gameDesc.starCount}, {gameDesc.resourceMultiplier:F1})"); + GameStatesManager.NewGameDesc = gameDesc; + didLoad = true; + } + if (args[i] == "-load" && i + 1 < args.Length) { loadArgExists = true; @@ -232,6 +245,56 @@ public static void StartDedicatedServer(GameDesc gameDesc) } } + public static void SetGameDescFromConfigFile(GameDesc gameDesc) + { + var customFile = new ConfigFile(Path.Combine(Paths.ConfigPath, "nebulaGameDescSettings.cfg"), true); + + var galaxySeed = customFile.Bind("Basic", "galaxySeed", -1, + "Cluster Seed. Negative value: Random or remain the same.").Value; + if (galaxySeed >= 0) + { + gameDesc.galaxySeed = galaxySeed; + } + + var starCount = customFile.Bind("Basic", "starCount", -1, + "Number of Stars. Negative value: Default(64) or remain the same.").Value; + if (starCount >= 0) + { + gameDesc.starCount = starCount; + } + + var resourceMultiplier = customFile.Bind("Basic", "resourceMultiplier", -1f, + "Resource Multiplier. Infinte = 100. Negative value: Default(1.0f) or remain the same.").Value; + if (resourceMultiplier >= 0f) + { + gameDesc.resourceMultiplier = resourceMultiplier; + } + + gameDesc.isPeaceMode = customFile.Bind("General", "isPeaceMode", false, + "False: Enable enemy force (combat mode)").Value; + gameDesc.isSandboxMode = customFile.Bind("General", "isSandboxMode", false, + "True: Enable creative mode").Value; + + gameDesc.combatSettings.aggressiveness = customFile.Bind("Combat", "aggressiveness", 1f, + new ConfigDescription("Aggressiveness (Dummy = -1, Rampage = 3)", new AcceptableValueList(-1f, 0f, 0.5f, 1f, 2f, 3f))).Value; + gameDesc.combatSettings.initialLevel = customFile.Bind("Combat", "initialLevel", 0, + new ConfigDescription("Initial Level (Original range: 0 to 10)", new AcceptableValueRange(0, 30))).Value; + gameDesc.combatSettings.initialGrowth = customFile.Bind("Combat", "initialGrowth", 1f, + "Initial Growth (Original range: 0 to 200%)").Value; + gameDesc.combatSettings.initialColonize = customFile.Bind("Combat", "initialColonize", 1f, + "Initial Occupation (Original range: 1% to 200%").Value; + gameDesc.combatSettings.maxDensity = customFile.Bind("Combat", "maxDensity", 1f, + "Max Density (Original range: 1 to 3)").Value; + gameDesc.combatSettings.growthSpeedFactor = customFile.Bind("Combat", "growthSpeedFactor", 1f, + "Growth Speed (Original range: 25% to 300%)").Value; + gameDesc.combatSettings.powerThreatFactor = customFile.Bind("Combat", "powerThreatFactor", 1f, + "Power Threat Factor (Original range: 1% to 1000%)").Value; + gameDesc.combatSettings.battleThreatFactor = customFile.Bind("Combat", "battleThreatFactor", 1f, + "Combat Threat Factor (Original range: 1% to 1000%)").Value; + gameDesc.combatSettings.battleExpFactor = customFile.Bind("Combat", "battleExpFactor", 1f, + "Combat XP Factor (Original range: 1% to 1000%)").Value; + } + private static async void ActivityManager_OnActivityJoin(string secret) { if (Multiplayer.IsActive) From 8942c9bd7969d484aa0518028657a30cc337a4b5 Mon Sep 17 00:00:00 2001 From: starfish <50672801+starfi5h@users.noreply.github.com> Date: Sat, 6 Apr 2024 01:26:00 +0800 Subject: [PATCH 5/5] Add command /dev --- NebulaWorld/Chat/ChatCommandRegistry.cs | 1 + .../Chat/Commands/DevCommandHandler.cs | 57 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 NebulaWorld/Chat/Commands/DevCommandHandler.cs diff --git a/NebulaWorld/Chat/ChatCommandRegistry.cs b/NebulaWorld/Chat/ChatCommandRegistry.cs index d6d2ed9e3..c255fd375 100644 --- a/NebulaWorld/Chat/ChatCommandRegistry.cs +++ b/NebulaWorld/Chat/ChatCommandRegistry.cs @@ -28,6 +28,7 @@ static ChatCommandRegistry() RegisterCommand("reconnect", new ReconnectCommandHandler(), "r"); RegisterCommand("server", new ServerCommandHandler()); RegisterCommand("playerdata", new PlayerDataCommandHandler()); + RegisterCommand("dev", new DevCommandHandler()); } private static void RegisterCommand(string commandName, IChatCommandHandler commandHandlerHandler, params string[] aliases) diff --git a/NebulaWorld/Chat/Commands/DevCommandHandler.cs b/NebulaWorld/Chat/Commands/DevCommandHandler.cs new file mode 100644 index 000000000..fa930a289 --- /dev/null +++ b/NebulaWorld/Chat/Commands/DevCommandHandler.cs @@ -0,0 +1,57 @@ +#region + +using NebulaWorld.MonoBehaviours.Local.Chat; +using NebulaModel.DataStructures.Chat; +using HarmonyLib; + +#endregion + +namespace NebulaWorld.Chat.Commands; + +public class DevCommandHandler : IChatCommandHandler +{ + public void Execute(ChatWindow window, string[] parameters) + { + if (parameters.Length < 1) + { + throw new ChatCommandUsageException("Not enough arguments!".Translate()); + } + + switch (parameters[0]) + { + case "sandbox": + { + GameMain.sandboxToolsEnabled = !GameMain.sandboxToolsEnabled; + GameMain.data.gameDesc.isSandboxMode = GameMain.sandboxToolsEnabled; + window.SendLocalChatMessage("SandboxTool enable: " + GameMain.sandboxToolsEnabled, ChatMessageType.CommandOutputMessage); + return; + } + case "load-cfg": + { + window.SendLocalChatMessage("Overwrite settings from nebulaGameDescSettings.cfg", ChatMessageType.CommandOutputMessage); + AccessTools.Method(AccessTools.TypeByName("NebulaPatcher.NebulaPlugin"), "SetGameDescFromConfigFile").Invoke(null, [GameMain.data.gameDesc]); + return; + } + + case "self-destruct": + { + GameMain.mainPlayer.Kill(); + return; + } + + default: + window.SendLocalChatMessage("Unknown command: " + parameters[0], ChatMessageType.CommandOutputMessage); + return; + } + } + + public string GetDescription() + { + return "Developer/Sandbox tool commands".Translate(); + } + + public string[] GetUsage() + { + return ["sandbox", "load-cfg", "self-destruct"]; + } +}