d4c8fd5649
commit 1ec6577ad95e1d7ebc8cbfa261c9893c55ea987c Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 17:10:31 2019 +0200 Don't attempt to move character's hands in UpdateUseItem if the character is disabled. May be causing "attempted to move pulljoint extremely far" errors (see #895) commit 1aabc5110ce8e0ec208adce6380cbafd255b576f Author: ezjamsen <ezjames.fi@gmail.com> Date: Mon Feb 4 16:47:50 2019 +0200 removed syringes from the fabricator commit 0a80a2d8029275f6cffdae580d1ba86cd44dd1a2 Merge: 039c04818 686d4c482 Author: Eetu <pitkanen.eetu@gmail.com> Date: Mon Feb 4 16:43:55 2019 +0200 Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into dev commit 039c04818e3598f2e4cdef4065434000a48bb229 Author: Eetu <pitkanen.eetu@gmail.com> Date: Mon Feb 4 16:43:51 2019 +0200 Updated: Alien artifacts to spawn inside containers tagged artifactholders in salvage missions & artifact events commit 686d4c482f692bcc31eb37aeaea0d5074a537fe9 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 16:42:11 2019 +0200 Fixed a bunch more buttons/sliders being invisible while pressed commit 823728511547f14a3dcb4fcf5025db592ea3dac9 Author: itchyOwl <lauri.harkanen@gmail.com> Date: Mon Feb 4 16:13:36 2019 +0200 Reset the unsaved changes when exitting the character editor (Not applied when the switching between the game view and the character editor). commit 9ecc56db4e73dd2ccd577130014020a1a502ae15 Merge: efbeda895 b824fc3f2 Author: itchyOwl <lauri.harkanen@gmail.com> Date: Mon Feb 4 16:04:57 2019 +0200 Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into dev commit efbeda895fceecb8b4701f23ae5a51057aa44efb Author: itchyOwl <lauri.harkanen@gmail.com> Date: Mon Feb 4 16:03:54 2019 +0200 Fix crash on trying to undo limb/joint deletion. Undo does not currently work on these cases, but the ragdoll can be reset to the original state from the reset button. commit b824fc3f281aed76e8e0ed78ffb16d2213d2fda1 Author: ezjamsen <ezjames.fi@gmail.com> Date: Mon Feb 4 16:03:03 2019 +0200 removed syringe from medical doctor default kit commit c40c716962c7ae1a16d791b0fbd744627a2283c5 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 16:01:33 2019 +0200 Nerfed door welding (takes 4x longer to weld a door shut now) commit 7a27fcab1cec322fe75bcfad553aa42a37ec7d53 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 16:01:09 2019 +0200 Fixed StatusEffects not being able to target item components. Caused doors to be impossible to weld and most likely other issues with item StatusEffects as well. Closes #1053 commit 50c09ad85ee44018418f537827c009892f4feb23 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 15:52:38 2019 +0200 Fixed depth charges disappearing from loaders when interacting them with both hand slots full. Closes #1046 commit 648a5ba889623f776f184fb30b99133a8551234a Author: itchyOwl <lauri.harkanen@gmail.com> Date: Mon Feb 4 15:47:16 2019 +0200 Allow to delete the main limb in the character editor. Should not crash anymore. commit 751bda4d29b81c58c1b1df1653158543a3b7710d Author: itchyOwl <lauri.harkanen@gmail.com> Date: Mon Feb 4 15:46:53 2019 +0200 Add a bunch of null checks to prevent crashes when the main limb is null. commit 05c068f7aa35f7070e2cf19c526eff0c8d196b53 Author: ezjamsen <ezjames.fi@gmail.com> Date: Mon Feb 4 15:35:20 2019 +0200 Syringes removed from medical.xml due to being legacy items we should no longer support. commit 74389aa95e29fc7415de48230c8f12fd4a0a6847 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 15:30:13 2019 +0200 Attempt to fix LightSource removal causing nullref exceptions. commit 0907516bcac599b5ae20dc8e35f3a66adb8704b5 Merge: 659e1c58d f042994f4 Author: Eetu <pitkanen.eetu@gmail.com> Date: Mon Feb 4 15:25:07 2019 +0200 Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into dev commit 659e1c58d3fb03d21acf2bb6065d07d1ac2ab914 Author: Eetu <pitkanen.eetu@gmail.com> Date: Mon Feb 4 15:24:59 2019 +0200 Added: Yes to All / No to All to the prompts when deleting multiple containers with contents. Fixed: Aforementioned prompts staying active when quitting the submarine editor. Moved: Logic for the prompts from ItemContainer.cs to SubEditorScreen.cs commit f042994f4b7eeff8cf5a6a68715c7c6aa6b8ddfb Merge: 70a968a16 5a2ca22bd Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 15:08:15 2019 +0200 Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into dev commit 70a968a165c383c2ee765164b4507aa6072e0504 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 15:08:01 2019 +0200 Use inventory icons in the extra cargo menu, layout fixes commit 5a2ca22bde4be43f4577d20ae4e0a1ec20a23497 Merge: b2f89ea59 9ca7440be Author: ezjamsen <ezjames.fi@gmail.com> Date: Mon Feb 4 15:06:11 2019 +0200 Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into dev commit b2f89ea59d481c109046d1edbd2807a516502b0c Author: ezjamsen <ezjames.fi@gmail.com> Date: Mon Feb 4 15:05:39 2019 +0200 redesigned walls in junction compartment of Typhon, closing #1042 commit 9ca7440be41a4fc2082b73618e90312af57c0817 Author: itchyOwl <lauri.harkanen@gmail.com> Date: Mon Feb 4 15:05:35 2019 +0200 Add some null checks to prevent crashing if the xml document or the source element is not found. commit 6d1331e9b86a5583761bc374c5dfb42868b03f45 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 15:03:53 2019 +0200 Fixed the layout of the extra cargo menu in server settings. Closes #1038 commit 02ac14076ace0418a5d35df7a574f99811d56017 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 14:10:34 2019 +0200 Fixed fire sounds persisting in menus. Closes #1047 commit d7d4516ddc9e21a2dba8f7bfd14a61ba7a805d4a Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 14:06:03 2019 +0200 Added a null check to CampaignUI to help diagnose #1029 commit 0fee58808c261cecd4a602db22e39dfb855ee018 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 13:55:50 2019 +0200 Fixed "attempting to remove an already removed item" console errors when ending a round. commit 5e4448024ce00231e9e479aa238ed4b134b07321 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 13:53:59 2019 +0200 Fixed crashing when ending a round while a character is outside the sub. Closes #1040 commit e3ff050561a8f823fc8abfddfec9d22ad4dc14a5 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 13:35:28 2019 +0200 Fixed battery positioning in charging docks. Closes #1041 commit d383aec6cb7f4525906fa858375729d4ad4fc0d4 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 13:26:00 2019 +0200 Fixed debugconsole adding the file number after the extension ("file123.txt (2)" instead of "file123 (2).txt"). Closes #1043 commit fee18b7ebcaea949c3f7d0c8027ab6253769b49c Merge: d03807237 c06e8990f Author: Eetu <pitkanen.eetu@gmail.com> Date: Mon Feb 4 12:10:12 2019 +0200 Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into dev commit d038072372ab1993a44542298fe4031db6448ae4 Author: Eetu <pitkanen.eetu@gmail.com> Date: Mon Feb 4 12:10:04 2019 +0200 Fixed: Setting an item's condition to zero in the SubmarineEditor causing its OnBroken status effects to be fired commit c06e8990f97af7ae9b4788b281bf2801cdd8e2ff Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 11:43:35 2019 +0200 Fixed chatbox being deselected in the net lobby when receiving a lobby update from the server. Closes #1019 commit 2962647c37cec01fdb01092b94c25063c74c9ee0 Merge: b77bc3654 c89df8750 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 10:41:24 2019 +0200 Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into dev commit b77bc365470c8cfb86dc83e4b21e5b36e0e28918 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 10:41:08 2019 +0200 Warning about automatic hull generation not working correctly with sloped walls when using the autohull command commit 85ef20a48532e06ef0c2774aa81e1fb517814b14 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 10:40:20 2019 +0200 Log the name of the item in the "attempting to remove an already removed item" error commit b6e32d4009a898db9c97316bcb6236170a7a92fe Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 10:39:46 2019 +0200 Fixed sliders not moving in the PowerContainer interface when an AI character is operating it commit 4b4848b5caa7bf3893e4ae2f5afef3c980f60e46 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 10:39:09 2019 +0200 Nullref fix in AIObjectiveGoto commit c89df87500c9026b3a6e75139391e64a4b1073e7 Author: Juan Pablo Arce <juanjp600@users.noreply.github.com> Date: Sun Feb 3 21:02:59 2019 -0300 whoops commit a85cc7705ea7611fff02fff7c18bc9826f03029a Author: Juan Pablo Arce <juanjp600@users.noreply.github.com> Date: Sun Feb 3 21:01:51 2019 -0300 ReduceAffliction loops back around if there's a surplus on index 0 commit e0047df3e089fd8be1646aecbd53b86b69949b13 Author: Juan Pablo Arce <juanjp600@users.noreply.github.com> Date: Sun Feb 3 19:45:52 2019 -0300 Fixed ReduceAffliction freezing Thanks to nilanthanimosus for catching this
1258 lines
58 KiB
C#
1258 lines
58 KiB
C#
using Barotrauma.Items.Components;
|
|
using Barotrauma.Networking;
|
|
using Microsoft.Xna.Framework;
|
|
using Microsoft.Xna.Framework.Graphics;
|
|
using Microsoft.Xna.Framework.Input;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Xml.Linq;
|
|
using System.Globalization;
|
|
|
|
namespace Barotrauma
|
|
{
|
|
static partial class DebugConsole
|
|
{
|
|
private static bool isOpen;
|
|
public static bool IsOpen => isOpen;
|
|
|
|
private static Queue<ColoredText> queuedMessages = new Queue<ColoredText>();
|
|
|
|
private static GUITextBlock activeQuestionText;
|
|
|
|
private static GUIFrame frame;
|
|
private static GUIListBox listBox;
|
|
private static GUITextBox textBox;
|
|
|
|
public static GUITextBox TextBox => textBox;
|
|
|
|
public static void Init()
|
|
{
|
|
frame = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.45f), GUI.Canvas) { MinSize = new Point(400, 300), AbsoluteOffset = new Point(10, 10) },
|
|
color: new Color(0.4f, 0.4f, 0.4f, 0.8f));
|
|
var paddedFrame = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.9f), frame.RectTransform, Anchor.Center), style: null);
|
|
|
|
listBox = new GUIListBox(new RectTransform(new Point(paddedFrame.Rect.Width, paddedFrame.Rect.Height - 30), paddedFrame.RectTransform)
|
|
{
|
|
IsFixedSize = false
|
|
}, color: Color.Black * 0.9f);
|
|
|
|
textBox = new GUITextBox(new RectTransform(new Point(paddedFrame.Rect.Width, 20), paddedFrame.RectTransform, Anchor.BottomLeft)
|
|
{
|
|
IsFixedSize = false
|
|
});
|
|
textBox.OnKeyHit += (sender, key) =>
|
|
{
|
|
if (key != Keys.Tab)
|
|
{
|
|
ResetAutoComplete();
|
|
}
|
|
};
|
|
|
|
NewMessage("Press F3 to open/close the debug console", Color.Cyan);
|
|
NewMessage("Enter \"help\" for a list of available console commands", Color.Cyan);
|
|
}
|
|
|
|
public static void AddToGUIUpdateList()
|
|
{
|
|
if (isOpen)
|
|
{
|
|
frame.AddToGUIUpdateList();
|
|
}
|
|
}
|
|
|
|
public static void Update(GameMain game, float deltaTime)
|
|
{
|
|
lock (queuedMessages)
|
|
{
|
|
while (queuedMessages.Count > 0)
|
|
{
|
|
var newMsg = queuedMessages.Dequeue();
|
|
AddMessage(newMsg);
|
|
|
|
if (GameSettings.SaveDebugConsoleLogs)
|
|
{
|
|
unsavedMessages.Add(newMsg);
|
|
if (unsavedMessages.Count >= messagesPerFile)
|
|
{
|
|
SaveLogs();
|
|
unsavedMessages.Clear();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
activeQuestionText?.SetAsLastChild();
|
|
|
|
if (PlayerInput.KeyHit(Keys.F3))
|
|
{
|
|
isOpen = !isOpen;
|
|
if (isOpen)
|
|
{
|
|
textBox.Select();
|
|
AddToGUIUpdateList();
|
|
}
|
|
else
|
|
{
|
|
GUI.ForceMouseOn(null);
|
|
textBox.Deselect();
|
|
}
|
|
}
|
|
|
|
if (isOpen)
|
|
{
|
|
frame.UpdateManually(deltaTime);
|
|
|
|
Character.DisableControls = true;
|
|
|
|
if (PlayerInput.KeyHit(Keys.Up))
|
|
{
|
|
textBox.Text = SelectMessage(-1, textBox.Text);
|
|
}
|
|
else if (PlayerInput.KeyHit(Keys.Down))
|
|
{
|
|
textBox.Text = SelectMessage(1, textBox.Text);
|
|
}
|
|
else if (PlayerInput.KeyHit(Keys.Tab))
|
|
{
|
|
textBox.Text = AutoComplete(textBox.Text);
|
|
}
|
|
|
|
if (PlayerInput.KeyHit(Keys.Enter))
|
|
{
|
|
ExecuteCommand(textBox.Text);
|
|
textBox.Text = "";
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void Draw(SpriteBatch spriteBatch)
|
|
{
|
|
if (!isOpen) return;
|
|
|
|
frame.DrawManually(spriteBatch);
|
|
}
|
|
|
|
private static bool IsCommandPermitted(string command, GameClient client)
|
|
{
|
|
switch (command)
|
|
{
|
|
case "kick":
|
|
return client.HasPermission(ClientPermissions.Kick);
|
|
case "ban":
|
|
case "banip":
|
|
return client.HasPermission(ClientPermissions.Ban);
|
|
case "unban":
|
|
case "unbanip":
|
|
return client.HasPermission(ClientPermissions.Unban);
|
|
case "netstats":
|
|
case "help":
|
|
case "dumpids":
|
|
case "admin":
|
|
case "entitylist":
|
|
return true;
|
|
default:
|
|
return client.HasConsoleCommandPermission(command);
|
|
}
|
|
}
|
|
|
|
public static void DequeueMessages()
|
|
{
|
|
while (queuedMessages.Count > 0)
|
|
{
|
|
var newMsg = queuedMessages.Dequeue();
|
|
if (listBox == null)
|
|
{
|
|
//don't attempt to add to the listbox if it hasn't been created yet
|
|
Messages.Add(newMsg);
|
|
}
|
|
else
|
|
{
|
|
AddMessage(newMsg);
|
|
}
|
|
|
|
if (GameSettings.SaveDebugConsoleLogs) unsavedMessages.Add(newMsg);
|
|
}
|
|
}
|
|
|
|
private static void AddMessage(ColoredText msg)
|
|
{
|
|
//listbox not created yet, don't attempt to add
|
|
if (listBox == null) return;
|
|
|
|
if (listBox.Content.CountChildren > MaxMessages)
|
|
{
|
|
listBox.RemoveChild(listBox.Content.Children.First());
|
|
}
|
|
|
|
Messages.Add(msg);
|
|
if (Messages.Count > MaxMessages)
|
|
{
|
|
Messages.RemoveRange(0, Messages.Count - MaxMessages);
|
|
}
|
|
|
|
try
|
|
{
|
|
var textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), listBox.Content.RectTransform),
|
|
msg.Text, font: GUI.SmallFont, wrap: true)
|
|
{
|
|
CanBeFocused = false,
|
|
TextColor = msg.Color
|
|
};
|
|
listBox.UpdateScrollBarSize();
|
|
listBox.BarScroll = 1.0f;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
ThrowError("Failed to add a message to the debug console.", e);
|
|
}
|
|
|
|
selectedIndex = Messages.Count;
|
|
}
|
|
|
|
private static void AddHelpMessage(Command command)
|
|
{
|
|
if (listBox.Content.CountChildren > MaxMessages)
|
|
{
|
|
listBox.RemoveChild(listBox.Content.Children.First());
|
|
}
|
|
|
|
var textContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.0f), listBox.Content.RectTransform),
|
|
style: "InnerFrame", color: Color.White * 0.6f)
|
|
{
|
|
CanBeFocused = false
|
|
};
|
|
var textBlock = new GUITextBlock(new RectTransform(new Point(listBox.Content.Rect.Width - 170, 0), textContainer.RectTransform, Anchor.TopRight) { AbsoluteOffset = new Point(20, 0) },
|
|
command.help, textAlignment: Alignment.TopLeft, font: GUI.SmallFont, wrap: true)
|
|
{
|
|
CanBeFocused = false,
|
|
TextColor = Color.White
|
|
};
|
|
textContainer.RectTransform.NonScaledSize = new Point(textContainer.RectTransform.NonScaledSize.X, textBlock.RectTransform.NonScaledSize.Y + 5);
|
|
textBlock.SetTextPos();
|
|
var nameBlock = new GUITextBlock(new RectTransform(new Point(150, textContainer.Rect.Height), textContainer.RectTransform),
|
|
command.names[0], textAlignment: Alignment.TopLeft);
|
|
|
|
listBox.UpdateScrollBarSize();
|
|
listBox.BarScroll = 1.0f;
|
|
|
|
selectedIndex = Messages.Count;
|
|
}
|
|
|
|
private static void InitProjectSpecific()
|
|
{
|
|
commands.Add(new Command("autohull", "", (string[] args) =>
|
|
{
|
|
if (Screen.Selected != GameMain.SubEditorScreen) return;
|
|
|
|
if (MapEntity.mapEntityList.Any(e => e is Hull || e is Gap))
|
|
{
|
|
ShowQuestionPrompt("This submarine already has hulls and/or gaps. This command will delete them. Do you want to continue? Y/N",
|
|
(option) =>
|
|
{
|
|
ShowQuestionPrompt("The automatic hull generation may not work correctly if your submarine uses curved walls. Do you want to continue? Y/N",
|
|
(option2) =>
|
|
{
|
|
if (option2.ToLower() == "y") { GameMain.SubEditorScreen.AutoHull(); }
|
|
});
|
|
});
|
|
}
|
|
else
|
|
{
|
|
ShowQuestionPrompt("The automatic hull generation may not work correctly if your submarine uses curved walls. Do you want to continue? Y/N",
|
|
(option) => { if (option.ToLower() == "y") GameMain.SubEditorScreen.AutoHull(); });
|
|
}
|
|
}));
|
|
|
|
commands.Add(new Command("startclient", "", (string[] args) =>
|
|
{
|
|
if (args.Length == 0) return;
|
|
|
|
if (GameMain.Client == null)
|
|
{
|
|
GameMain.NetworkMember = new GameClient("Name");
|
|
GameMain.Client.ConnectToServer(args[0]);
|
|
}
|
|
}));
|
|
|
|
commands.Add(new Command("mainmenuscreen|mainmenu|menu", "mainmenu/menu: Go to the main menu.", (string[] args) =>
|
|
{
|
|
GameMain.GameSession = null;
|
|
|
|
List<Character> characters = new List<Character>(Character.CharacterList);
|
|
foreach (Character c in characters)
|
|
{
|
|
c.Remove();
|
|
}
|
|
|
|
GameMain.MainMenuScreen.Select();
|
|
}));
|
|
|
|
commands.Add(new Command("gamescreen|game", "gamescreen/game: Go to the \"in-game\" view.", (string[] args) =>
|
|
{
|
|
GameMain.GameScreen.Select();
|
|
}));
|
|
|
|
commands.Add(new Command("editsubscreen|editsub|subeditor", "editsub/subeditor: Switch to the submarine editor.", (string[] args) =>
|
|
{
|
|
if (args.Length > 0)
|
|
{
|
|
Submarine.Load(string.Join(" ", args), true);
|
|
}
|
|
GameMain.SubEditorScreen.Select();
|
|
}));
|
|
|
|
commands.Add(new Command("editparticles|particleeditor", "", (string[] args) =>
|
|
{
|
|
GameMain.ParticleEditorScreen.Select();
|
|
}));
|
|
|
|
commands.Add(new Command("editlevels|editlevel|leveleditor", "", (string[] args) =>
|
|
{
|
|
GameMain.LevelEditorScreen.Select();
|
|
}));
|
|
|
|
commands.Add(new Command("editsprites|editsprite|spriteeditor|spriteedit", "", (string[] args) =>
|
|
{
|
|
GameMain.SpriteEditorScreen.Select();
|
|
}));
|
|
|
|
commands.Add(new Command("charactereditor|editcharacter|editcharacters|editanimation|editanimations|animedit|animationeditor|animeditor|animationedit", "charactereditor: Edit characters, animations, ragdolls....", (string[] args) =>
|
|
{
|
|
GameMain.CharacterEditorScreen.Select();
|
|
}));
|
|
|
|
commands.Add(new Command("control|controlcharacter", "control [character name]: Start controlling the specified character.", (string[] args) =>
|
|
{
|
|
if (args.Length < 1) return;
|
|
|
|
var character = FindMatchingCharacter(args, true);
|
|
|
|
if (character != null)
|
|
{
|
|
Character.Controlled = character;
|
|
}
|
|
},
|
|
() =>
|
|
{
|
|
return new string[][]
|
|
{
|
|
Character.CharacterList.Select(c => c.Name).Distinct().ToArray()
|
|
};
|
|
}, isCheat: true));
|
|
|
|
commands.Add(new Command("shake", "", (string[] args) =>
|
|
{
|
|
GameMain.GameScreen.Cam.Shake = 10.0f;
|
|
}));
|
|
|
|
commands.Add(new Command("los", "los: Toggle the line of sight effect on/off.", (string[] args) =>
|
|
{
|
|
GameMain.LightManager.LosEnabled = !GameMain.LightManager.LosEnabled;
|
|
NewMessage("Line of sight effect " + (GameMain.LightManager.LosEnabled ? "enabled" : "disabled"), Color.White);
|
|
}, isCheat: true));
|
|
|
|
commands.Add(new Command("lighting|lights", "Toggle lighting on/off.", (string[] args) =>
|
|
{
|
|
GameMain.LightManager.LightingEnabled = !GameMain.LightManager.LightingEnabled;
|
|
NewMessage("Lighting " + (GameMain.LightManager.LightingEnabled ? "enabled" : "disabled"), Color.White);
|
|
}, isCheat: true));
|
|
|
|
commands.Add(new Command("multiplylights", "Multiplies the colors of all the static lights in the sub with the given Vector4 value (for example, 1,1,1,0.5).", (string[] args) =>
|
|
{
|
|
if (Screen.Selected != GameMain.SubEditorScreen || args.Length < 1)
|
|
{
|
|
ThrowError("The multiplylights command can only be used in the submarine editor.");
|
|
}
|
|
if (args.Length < 1) return;
|
|
|
|
//join args in case there's spaces between the components
|
|
Vector4 value = XMLExtensions.ParseVector4(string.Join("", args));
|
|
foreach (Item item in Item.ItemList)
|
|
{
|
|
if (item.ParentInventory != null || item.body != null) continue;
|
|
var lightComponent = item.GetComponent<LightComponent>();
|
|
if (lightComponent != null) lightComponent.LightColor =
|
|
new Color(
|
|
(lightComponent.LightColor.R / 255.0f) * value.X,
|
|
(lightComponent.LightColor.G / 255.0f) * value.Y,
|
|
(lightComponent.LightColor.B / 255.0f) * value.Z,
|
|
(lightComponent.LightColor.A / 255.0f) * value.W);
|
|
}
|
|
}, isCheat: false));
|
|
|
|
commands.Add(new Command("color|colour", "Change color (as bytes from 0 to 255) of the selected item/structure instances. Applied only in the subeditor.", (string[] args) =>
|
|
{
|
|
if (Screen.Selected == GameMain.SubEditorScreen)
|
|
{
|
|
if (!MapEntity.SelectedAny)
|
|
{
|
|
ThrowError("You have to select item(s)/structure(s) first!");
|
|
}
|
|
else
|
|
{
|
|
if (args.Length < 3)
|
|
{
|
|
ThrowError("Not enough arguments provided! At least three required.");
|
|
}
|
|
if (!byte.TryParse(args[0], out byte r))
|
|
{
|
|
ThrowError($"Failed to parse value for RED from {args[0]}");
|
|
}
|
|
if (!byte.TryParse(args[1], out byte g))
|
|
{
|
|
ThrowError($"Failed to parse value for GREEN from {args[1]}");
|
|
}
|
|
if (!byte.TryParse(args[2], out byte b))
|
|
{
|
|
ThrowError($"Failed to parse value for BLUE from {args[2]}");
|
|
}
|
|
Color color = new Color(r, g, b);
|
|
if (args.Length > 3)
|
|
{
|
|
if (!byte.TryParse(args[3], out byte a))
|
|
{
|
|
ThrowError($"Failed to parse value for ALPHA from {args[3]}");
|
|
}
|
|
else
|
|
{
|
|
color.A = a;
|
|
}
|
|
}
|
|
foreach (var mapEntity in MapEntity.SelectedList)
|
|
{
|
|
if (mapEntity is Structure s)
|
|
{
|
|
s.SpriteColor = color;
|
|
}
|
|
else if (mapEntity is Item i)
|
|
{
|
|
i.SpriteColor = color;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}, isCheat: true));
|
|
|
|
commands.Add(new Command("alpha", "Change the alpha (as bytes from 0 to 255) of the selected item/structure instances. Applied only in the subeditor.", (string[] args) =>
|
|
{
|
|
if (Screen.Selected == GameMain.SubEditorScreen)
|
|
{
|
|
if (!MapEntity.SelectedAny)
|
|
{
|
|
ThrowError("You have to select item(s)/structure(s) first!");
|
|
}
|
|
else
|
|
{
|
|
if (args.Length > 0)
|
|
{
|
|
if (!byte.TryParse(args[0], out byte a))
|
|
{
|
|
ThrowError($"Failed to parse value for ALPHA from {args[0]}");
|
|
}
|
|
else
|
|
{
|
|
foreach (var mapEntity in MapEntity.SelectedList)
|
|
{
|
|
if (mapEntity is Structure s)
|
|
{
|
|
s.SpriteColor = new Color(s.SpriteColor.R, s.SpriteColor.G, s.SpriteColor.G, a);
|
|
}
|
|
else if (mapEntity is Item i)
|
|
{
|
|
i.SpriteColor = new Color(i.SpriteColor.R, i.SpriteColor.G, i.SpriteColor.G, a);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ThrowError("Not enough arguments provided! One required!");
|
|
}
|
|
}
|
|
}
|
|
}, isCheat: true));
|
|
|
|
commands.Add(new Command("tutorial", "", (string[] args) =>
|
|
{
|
|
TutorialMode.StartTutorial(Tutorials.Tutorial.Tutorials[0]);
|
|
}));
|
|
|
|
commands.Add(new Command("lobby|lobbyscreen", "", (string[] args) =>
|
|
{
|
|
GameMain.LobbyScreen.Select();
|
|
}));
|
|
|
|
commands.Add(new Command("save|savesub", "save [submarine name]: Save the currently loaded submarine using the specified name.", (string[] args) =>
|
|
{
|
|
if (args.Length < 1) return;
|
|
|
|
if (GameMain.SubEditorScreen.CharacterMode)
|
|
{
|
|
GameMain.SubEditorScreen.SetCharacterMode(false);
|
|
}
|
|
|
|
string fileName = string.Join(" ", args);
|
|
if (fileName.Contains("../"))
|
|
{
|
|
ThrowError("Illegal symbols in filename (../)");
|
|
return;
|
|
}
|
|
|
|
if (Submarine.SaveCurrent(System.IO.Path.Combine(Submarine.SavePath, fileName + ".sub")))
|
|
{
|
|
NewMessage("Sub saved", Color.Green);
|
|
}
|
|
}));
|
|
|
|
commands.Add(new Command("load|loadsub", "load [submarine name]: Load a submarine.", (string[] args) =>
|
|
{
|
|
if (args.Length == 0) return;
|
|
Submarine.Load(string.Join(" ", args), true);
|
|
}));
|
|
|
|
commands.Add(new Command("cleansub", "", (string[] args) =>
|
|
{
|
|
for (int i = MapEntity.mapEntityList.Count - 1; i >= 0; i--)
|
|
{
|
|
MapEntity me = MapEntity.mapEntityList[i];
|
|
|
|
if (me.SimPosition.Length() > 2000.0f)
|
|
{
|
|
NewMessage("Removed " + me.Name + " (simposition " + me.SimPosition + ")", Color.Orange);
|
|
MapEntity.mapEntityList.RemoveAt(i);
|
|
}
|
|
else if (!me.ShouldBeSaved)
|
|
{
|
|
NewMessage("Removed " + me.Name + " (!ShouldBeSaved)", Color.Orange);
|
|
MapEntity.mapEntityList.RemoveAt(i);
|
|
}
|
|
else if (me is Item)
|
|
{
|
|
Item item = me as Item;
|
|
var wire = item.GetComponent<Wire>();
|
|
if (wire == null) continue;
|
|
|
|
if (wire.GetNodes().Count > 0 && !wire.Connections.Any(c => c != null))
|
|
{
|
|
wire.Item.Drop(null);
|
|
NewMessage("Dropped wire (ID: " + wire.Item.ID + ") - attached on wall but no connections found", Color.Orange);
|
|
}
|
|
}
|
|
}
|
|
}, isCheat: true));
|
|
|
|
commands.Add(new Command("messagebox", "", (string[] args) =>
|
|
{
|
|
new GUIMessageBox("", string.Join(" ", args));
|
|
}));
|
|
|
|
commands.Add(new Command("debugdraw", "debugdraw: Toggle the debug drawing mode on/off.", (string[] args) =>
|
|
{
|
|
GameMain.DebugDraw = !GameMain.DebugDraw;
|
|
NewMessage("Debug draw mode " + (GameMain.DebugDraw ? "enabled" : "disabled"), Color.White);
|
|
}, isCheat: true));
|
|
|
|
commands.Add(new Command("fpscounter", "fpscounter: Toggle the FPS counter.", (string[] args) =>
|
|
{
|
|
GameMain.ShowFPS = !GameMain.ShowFPS;
|
|
NewMessage("FPS counter " + (GameMain.DebugDraw ? "enabled" : "disabled"), Color.White);
|
|
}));
|
|
commands.Add(new Command("showperf", "showperf: Toggle performance statistics on/off.", (string[] args) =>
|
|
{
|
|
GameMain.ShowPerf = !GameMain.ShowPerf;
|
|
NewMessage("Performance statistics " + (GameMain.ShowPerf ? "enabled" : "disabled"), Color.White);
|
|
}));
|
|
|
|
commands.Add(new Command("hudlayoutdebugdraw|debugdrawhudlayout", "hudlayoutdebugdraw: Toggle the debug drawing mode of HUD layout areas on/off.", (string[] args) =>
|
|
{
|
|
HUDLayoutSettings.DebugDraw = !HUDLayoutSettings.DebugDraw;
|
|
NewMessage("HUD layout debug draw mode " + (HUDLayoutSettings.DebugDraw ? "enabled" : "disabled"), Color.White);
|
|
}));
|
|
|
|
commands.Add(new Command("interactdebugdraw|debugdrawinteract", "interactdebugdraw: Toggle the debug drawing mode of item interaction ranges on/off.", (string[] args) =>
|
|
{
|
|
Character.DebugDrawInteract = !Character.DebugDrawInteract;
|
|
NewMessage("Interact debug draw mode " + (Character.DebugDrawInteract ? "enabled" : "disabled"), Color.White);
|
|
}, isCheat: true));
|
|
|
|
commands.Add(new Command("togglehud|hud", "togglehud/hud: Toggle the character HUD (inventories, icons, buttons, etc) on/off.", (string[] args) =>
|
|
{
|
|
GUI.DisableHUD = !GUI.DisableHUD;
|
|
GameMain.Instance.IsMouseVisible = !GameMain.Instance.IsMouseVisible;
|
|
NewMessage(GUI.DisableHUD ? "Disabled HUD" : "Enabled HUD", Color.White);
|
|
}));
|
|
|
|
commands.Add(new Command("followsub", "followsub: Toggle whether the camera should follow the nearest submarine.", (string[] args) =>
|
|
{
|
|
Camera.FollowSub = !Camera.FollowSub;
|
|
NewMessage(Camera.FollowSub ? "Set the camera to follow the closest submarine" : "Disabled submarine following.", Color.White);
|
|
}));
|
|
|
|
commands.Add(new Command("toggleaitargets|aitargets", "toggleaitargets/aitargets: Toggle the visibility of AI targets (= targets that enemies can detect and attack/escape from).", (string[] args) =>
|
|
{
|
|
AITarget.ShowAITargets = !AITarget.ShowAITargets;
|
|
NewMessage(AITarget.ShowAITargets ? "Enabled AI target drawing" : "Disabled AI target drawing", Color.White);
|
|
}, isCheat: true));
|
|
|
|
commands.Add(new Command("checkcrafting", "checkcrafting: Checks item deconstruction & crafting recipes for inconsistencies.", (string[] args) =>
|
|
{
|
|
List<FabricableItem> fabricableItems = new List<FabricableItem>();
|
|
foreach (MapEntityPrefab mapEntityPrefab in MapEntityPrefab.List)
|
|
{
|
|
if (mapEntityPrefab is ItemPrefab itemPrefab)
|
|
{
|
|
var fabricatorElement = itemPrefab.ConfigElement.Element("Fabricator");
|
|
if (fabricatorElement == null) { continue; }
|
|
|
|
foreach (XElement element in fabricatorElement.Elements())
|
|
{
|
|
if (element.Name.ToString().ToLowerInvariant() != "fabricableitem") { continue; }
|
|
fabricableItems.Add(new FabricableItem(element));
|
|
}
|
|
|
|
}
|
|
}
|
|
foreach (MapEntityPrefab mapEntityPrefab in MapEntityPrefab.List)
|
|
{
|
|
if (mapEntityPrefab is ItemPrefab itemPrefab)
|
|
{
|
|
int? minCost = itemPrefab.GetPrices()?.Min(p => p.BuyPrice);
|
|
int? fabricationCost = null;
|
|
int? deconstructProductCost = null;
|
|
|
|
var fabricationRecipe = fabricableItems.Find(f => f.TargetItem == itemPrefab);
|
|
if (fabricationRecipe != null)
|
|
{
|
|
foreach (var ingredient in fabricationRecipe.RequiredItems)
|
|
{
|
|
int? ingredientPrice = ingredient.ItemPrefab.GetPrices()?.Min(p => p.BuyPrice);
|
|
if (ingredientPrice.HasValue)
|
|
{
|
|
if (!fabricationCost.HasValue) { fabricationCost = 0; }
|
|
float useAmount = ingredient.UseCondition ? ingredient.MinCondition : 1.0f;
|
|
fabricationCost += (int)(ingredientPrice.Value * ingredient.Amount * useAmount);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var deconstructItem in itemPrefab.DeconstructItems)
|
|
{
|
|
var targetItem = MapEntityPrefab.Find(null, deconstructItem.ItemIdentifier, showErrorMessages: false) as ItemPrefab;
|
|
if (targetItem == null)
|
|
{
|
|
ThrowError("Error in item \"" + itemPrefab.Name + "\" - could not find deconstruct item \"" + deconstructItem.ItemIdentifier + "\"!");
|
|
continue;
|
|
}
|
|
|
|
int? deconstructProductPrice = targetItem.GetPrices()?.Min(p => p.BuyPrice);
|
|
if (deconstructProductPrice.HasValue)
|
|
{
|
|
if (!deconstructProductCost.HasValue) { deconstructProductCost = 0; }
|
|
deconstructProductCost += (int)(deconstructProductPrice * deconstructItem.OutCondition);
|
|
}
|
|
|
|
if (fabricationRecipe != null)
|
|
{
|
|
if (!fabricationRecipe.RequiredItems.Any(r => r.ItemPrefab == targetItem))
|
|
{
|
|
NewMessage("Deconstructing \"" + itemPrefab.Name + "\" produces \"" + deconstructItem.ItemIdentifier + "\", which isn't required in the fabrication recipe of the item.", Color.Orange);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fabricationCost.HasValue && minCost.HasValue)
|
|
{
|
|
if (fabricationCost.Value < minCost * 0.9f)
|
|
{
|
|
float ratio = (float)fabricationCost.Value / minCost.Value;
|
|
Color color = ToolBox.GradientLerp(ratio, Color.Red, Color.Yellow, Color.Green);
|
|
NewMessage("The fabrication ingredients of \"" + itemPrefab.Name + "\" only cost " + (int)(ratio * 100) + "% of the price of the item. Item price: " + minCost.Value + ", ingredient prices: " + fabricationCost.Value, color);
|
|
}
|
|
else if (fabricationCost.Value > minCost * 1.1f)
|
|
{
|
|
float ratio = (float)fabricationCost.Value / minCost.Value;
|
|
Color color = ToolBox.GradientLerp(ratio - 1.0f, Color.Green, Color.Yellow, Color.Red);
|
|
NewMessage("The fabrication ingredients of \"" + itemPrefab.Name + "\" cost " + (int)(ratio * 100 - 100) + "% more than the price of the item. Item price: " + minCost.Value + ", ingredient prices: " + fabricationCost.Value, color);
|
|
}
|
|
}
|
|
if (deconstructProductCost.HasValue && minCost.HasValue)
|
|
{
|
|
if (deconstructProductCost.Value < minCost * 0.8f)
|
|
{
|
|
float ratio = (float)deconstructProductCost.Value / minCost.Value;
|
|
Color color = ToolBox.GradientLerp(ratio, Color.Red, Color.Yellow, Color.Green);
|
|
NewMessage("The deconstruction output of \"" + itemPrefab.Name + "\" is only worth " + (int)(ratio * 100) + "% of the price of the item. Item price: " + minCost.Value + ", output value: " + deconstructProductCost.Value, color);
|
|
}
|
|
else if (deconstructProductCost.Value > minCost * 1.1f)
|
|
{
|
|
float ratio = (float)deconstructProductCost.Value / minCost.Value;
|
|
Color color = ToolBox.GradientLerp(ratio - 1.0f, Color.Green, Color.Yellow, Color.Red);
|
|
NewMessage("The deconstruction output of \"" + itemPrefab.Name + "\" is worth " + (int)(ratio * 100 - 100) + "% more than the price of the item. Item price: " + minCost.Value + ", output value: " + deconstructProductCost.Value, color);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}, isCheat: false));
|
|
|
|
|
|
#if DEBUG
|
|
commands.Add(new Command("spamchatmessages", "", (string[] args) =>
|
|
{
|
|
int msgCount = 1000;
|
|
if (args.Length > 0) int.TryParse(args[0], out msgCount);
|
|
int msgLength = 50;
|
|
if (args.Length > 1) int.TryParse(args[1], out msgLength);
|
|
|
|
for (int i = 0; i < msgCount; i++)
|
|
{
|
|
if (GameMain.Server != null)
|
|
{
|
|
GameMain.Server.SendChatMessage(ToolBox.RandomSeed(msgLength), ChatMessageType.Default);
|
|
}
|
|
else if (GameMain.Client != null)
|
|
{
|
|
GameMain.Client.SendChatMessage(ToolBox.RandomSeed(msgLength));
|
|
}
|
|
}
|
|
}));
|
|
|
|
commands.Add(new Command("camerasettings", "camerasettings [defaultzoom] [zoomsmoothness] [movesmoothness] [minzoom] [maxzoom]: debug command for testing camera settings. The values default to 1.1, 8.0, 8.0, 0.1 and 2.0.", (string[] args) =>
|
|
{
|
|
float defaultZoom = Screen.Selected.Cam.DefaultZoom;
|
|
if (args.Length > 0) float.TryParse(args[0], NumberStyles.Number, CultureInfo.InvariantCulture, out defaultZoom);
|
|
|
|
float zoomSmoothness = Screen.Selected.Cam.ZoomSmoothness;
|
|
if (args.Length > 1) float.TryParse(args[1], NumberStyles.Number, CultureInfo.InvariantCulture, out zoomSmoothness);
|
|
float moveSmoothness = Screen.Selected.Cam.MoveSmoothness;
|
|
if (args.Length > 2) float.TryParse(args[2], NumberStyles.Number, CultureInfo.InvariantCulture, out moveSmoothness);
|
|
|
|
float minZoom = Screen.Selected.Cam.MinZoom;
|
|
if (args.Length > 3) float.TryParse(args[3], NumberStyles.Number, CultureInfo.InvariantCulture, out minZoom);
|
|
float maxZoom = Screen.Selected.Cam.MaxZoom;
|
|
if (args.Length > 4) float.TryParse(args[4], NumberStyles.Number, CultureInfo.InvariantCulture, out maxZoom);
|
|
|
|
Screen.Selected.Cam.DefaultZoom = defaultZoom;
|
|
Screen.Selected.Cam.ZoomSmoothness = zoomSmoothness;
|
|
Screen.Selected.Cam.MoveSmoothness = moveSmoothness;
|
|
Screen.Selected.Cam.MinZoom = minZoom;
|
|
Screen.Selected.Cam.MaxZoom = maxZoom;
|
|
}));
|
|
|
|
commands.Add(new Command("waterparams", "waterparams [distortionscalex] [distortionscaley] [distortionstrengthx] [distortionstrengthy] [bluramount]: default 0.5 0.5 0.5 0.5 1", (string[] args) =>
|
|
{
|
|
float distortScaleX = 0.5f, distortScaleY = 0.5f;
|
|
float distortStrengthX = 0.5f, distortStrengthY = 0.5f;
|
|
float blurAmount = 0.0f;
|
|
if (args.Length > 0) float.TryParse(args[0], NumberStyles.Number, CultureInfo.InvariantCulture, out distortScaleX);
|
|
if (args.Length > 1) float.TryParse(args[1], NumberStyles.Number, CultureInfo.InvariantCulture, out distortScaleY);
|
|
if (args.Length > 2) float.TryParse(args[2], NumberStyles.Number, CultureInfo.InvariantCulture, out distortStrengthX);
|
|
if (args.Length > 3) float.TryParse(args[3], NumberStyles.Number, CultureInfo.InvariantCulture, out distortStrengthY);
|
|
if (args.Length > 4) float.TryParse(args[4], NumberStyles.Number, CultureInfo.InvariantCulture, out blurAmount);
|
|
WaterRenderer.DistortionScale = new Vector2(distortScaleX, distortScaleY);
|
|
WaterRenderer.DistortionStrength = new Vector2(distortStrengthX, distortStrengthY);
|
|
WaterRenderer.BlurAmount = blurAmount;
|
|
},
|
|
null, null));
|
|
|
|
|
|
commands.Add(new Command("refreshrect", "Updates the dimensions of the selected items to match the ones defined in the prefab. Applied only in the subeditor.", (string[] args) =>
|
|
{
|
|
//TODO: maybe do this automatically during loading when possible?
|
|
if (Screen.Selected == GameMain.SubEditorScreen)
|
|
{
|
|
if (!MapEntity.SelectedAny)
|
|
{
|
|
ThrowError("You have to select item(s) first!");
|
|
}
|
|
else
|
|
{
|
|
foreach (var mapEntity in MapEntity.SelectedList)
|
|
{
|
|
if (mapEntity is Item item)
|
|
{
|
|
item.Rect = new Rectangle(item.Rect.X, item.Rect.Y,
|
|
(int)(item.Prefab.sprite.size.X * item.Prefab.Scale),
|
|
(int)(item.Prefab.sprite.size.Y * item.Prefab.Scale));
|
|
}
|
|
else if (mapEntity is Structure structure)
|
|
{
|
|
if (!structure.ResizeHorizontal)
|
|
{
|
|
structure.Rect = new Rectangle(structure.Rect.X, structure.Rect.Y,
|
|
(int)structure.Prefab.ScaledSize.X,
|
|
structure.Rect.Height);
|
|
}
|
|
if (!structure.ResizeVertical)
|
|
{
|
|
structure.Rect = new Rectangle(structure.Rect.X, structure.Rect.Y,
|
|
structure.Rect.Width,
|
|
(int)structure.Prefab.ScaledSize.Y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}, isCheat: false));
|
|
#endif
|
|
|
|
commands.Add(new Command("dumptexts", "dumptexts [filepath]: Extracts all the texts from the given text xml and writes them into a file (using the same filename, but with the .txt extension). If the filepath is omitted, the EnglishVanilla.xml file is used.", (string[] args) =>
|
|
{
|
|
string filePath = args.Length > 0 ? args[0] : "Content/Texts/EnglishVanilla.xml";
|
|
var doc = XMLExtensions.TryLoadXml(filePath);
|
|
if (doc?.Root == null) return;
|
|
List<string> lines = new List<string>();
|
|
foreach (XElement element in doc.Root.Elements())
|
|
{
|
|
lines.Add(element.ElementInnerText());
|
|
}
|
|
File.WriteAllLines(Path.GetFileNameWithoutExtension(filePath) + ".txt", lines);
|
|
},
|
|
() =>
|
|
{
|
|
var files = TextManager.GetTextFiles().Select(f => f.Replace("\\", "/"));
|
|
return new string[][]
|
|
{
|
|
TextManager.GetTextFiles().Where(f => Path.GetExtension(f)==".xml").ToArray()
|
|
};
|
|
}));
|
|
|
|
commands.Add(new Command("loadtexts", "loadtexts [sourcefile] [destinationfile]: Loads all lines of text from a given .txt file and inserts them sequientially into the elements of an xml file. If the file paths are omitted, EnglishVanilla.txt and EnglishVanilla.xml are used.", (string[] args) =>
|
|
{
|
|
string sourcePath = args.Length > 0 ? args[0] : "Content/Texts/EnglishVanilla.txt";
|
|
string destinationPath = args.Length > 1 ? args[1] : "Content/Texts/EnglishVanilla.xml";
|
|
|
|
string[] lines;
|
|
try
|
|
{
|
|
lines = File.ReadAllLines(sourcePath);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
ThrowError("Reading the file \"" + sourcePath + "\" failed.", e);
|
|
return;
|
|
}
|
|
var doc = XMLExtensions.TryLoadXml(destinationPath);
|
|
int i = 0;
|
|
foreach (XElement element in doc.Root.Elements())
|
|
{
|
|
if (i >= lines.Length)
|
|
{
|
|
ThrowError("Error while loading texts to the xml file. The xml has more elements than the number of lines in the text file.");
|
|
return;
|
|
}
|
|
element.Value = lines[i];
|
|
i++;
|
|
}
|
|
doc.Save(destinationPath);
|
|
},
|
|
() =>
|
|
{
|
|
var files = TextManager.GetTextFiles().Select(f => f.Replace("\\", "/"));
|
|
return new string[][]
|
|
{
|
|
files.Where(f => Path.GetExtension(f)==".txt").ToArray(),
|
|
files.Where(f => Path.GetExtension(f)==".xml").ToArray()
|
|
};
|
|
}));
|
|
|
|
commands.Add(new Command("updatetextfile", "updatetextfile [sourcefile] [destinationfile]: Inserts all the xml elements that are only present in the source file into the destination file. Can be used to update outdated translation files more easily.", (string[] args) =>
|
|
{
|
|
if (args.Length < 2) return;
|
|
string sourcePath = args[0];
|
|
string destinationPath = args[1];
|
|
|
|
var sourceDoc = XMLExtensions.TryLoadXml(sourcePath);
|
|
var destinationDoc = XMLExtensions.TryLoadXml(destinationPath);
|
|
|
|
XElement destinationElement = destinationDoc.Root.Elements().First();
|
|
foreach (XElement element in sourceDoc.Root.Elements())
|
|
{
|
|
if (destinationDoc.Root.Element(element.Name) == null)
|
|
{
|
|
element.Value = "!!!!!!!!!!!!!" + element.Value;
|
|
destinationElement.AddAfterSelf(element);
|
|
}
|
|
XNode nextNode = destinationElement.NextNode;
|
|
while ((!(nextNode is XElement) || nextNode == element) && nextNode != null) nextNode = nextNode.NextNode;
|
|
destinationElement = nextNode as XElement;
|
|
}
|
|
destinationDoc.Save(destinationPath);
|
|
},
|
|
() =>
|
|
{
|
|
var files = TextManager.GetTextFiles().Where(f => Path.GetExtension(f) == ".xml").Select(f => f.Replace("\\", "/")).ToArray();
|
|
return new string[][]
|
|
{
|
|
files,
|
|
files
|
|
};
|
|
}));
|
|
|
|
commands.Add(new Command("dumpentitytexts", "dumpentitytexts [filepath]: gets the names and descriptions of all entity prefabs and writes them into a file along with xml tags that can be used in translation files. If the filepath is omitted, the file is written to Content/Texts/EntityTexts.txt", (string[] args) =>
|
|
{
|
|
string filePath = args.Length > 0 ? args[0] : "Content/Texts/EntityTexts.txt";
|
|
List<string> lines = new List<string>();
|
|
foreach (MapEntityPrefab me in MapEntityPrefab.List)
|
|
{
|
|
lines.Add("<EntityName." + me.Identifier + ">" + me.Name + "</" + me.Identifier + ".Name>");
|
|
lines.Add("<EntityDescription." + me.Identifier + ">" + me.Description + "</" + me.Identifier + ".Description>");
|
|
}
|
|
File.WriteAllLines(filePath, lines);
|
|
}));
|
|
|
|
|
|
commands.Add(new Command("cleanbuild", "", (string[] args) =>
|
|
{
|
|
GameMain.Config.MusicVolume = 0.5f;
|
|
GameMain.Config.SoundVolume = 0.5f;
|
|
NewMessage("Music and sound volume set to 0.5", Color.Green);
|
|
|
|
GameMain.Config.GraphicsWidth = 0;
|
|
GameMain.Config.GraphicsHeight = 0;
|
|
GameMain.Config.WindowMode = WindowMode.Fullscreen;
|
|
NewMessage("Resolution set to 0 x 0 (screen resolution will be used)", Color.Green);
|
|
NewMessage("Fullscreen enabled", Color.Green);
|
|
|
|
GameSettings.ShowUserStatisticsPrompt = true;
|
|
|
|
GameSettings.VerboseLogging = false;
|
|
|
|
if (GameMain.Config.MasterServerUrl != "http://www.undertowgames.com/baromaster")
|
|
{
|
|
ThrowError("MasterServerUrl \"" + GameMain.Config.MasterServerUrl + "\"!");
|
|
}
|
|
|
|
GameMain.Config.Save();
|
|
|
|
var saveFiles = System.IO.Directory.GetFiles(SaveUtil.SaveFolder);
|
|
|
|
foreach (string saveFile in saveFiles)
|
|
{
|
|
System.IO.File.Delete(saveFile);
|
|
NewMessage("Deleted " + saveFile, Color.Green);
|
|
}
|
|
|
|
if (System.IO.Directory.Exists(System.IO.Path.Combine(SaveUtil.SaveFolder, "temp")))
|
|
{
|
|
System.IO.Directory.Delete(System.IO.Path.Combine(SaveUtil.SaveFolder, "temp"), true);
|
|
NewMessage("Deleted temp save folder", Color.Green);
|
|
}
|
|
|
|
if (System.IO.Directory.Exists(ServerLog.SavePath))
|
|
{
|
|
var logFiles = System.IO.Directory.GetFiles(ServerLog.SavePath);
|
|
|
|
foreach (string logFile in logFiles)
|
|
{
|
|
System.IO.File.Delete(logFile);
|
|
NewMessage("Deleted " + logFile, Color.Green);
|
|
}
|
|
}
|
|
|
|
if (System.IO.File.Exists("filelist.xml"))
|
|
{
|
|
System.IO.File.Delete("filelist.xml");
|
|
NewMessage("Deleted filelist", Color.Green);
|
|
}
|
|
|
|
if (System.IO.File.Exists("Data/bannedplayers.txt"))
|
|
{
|
|
System.IO.File.Delete("Data/bannedplayers.txt");
|
|
NewMessage("Deleted bannedplayers.txt", Color.Green);
|
|
}
|
|
|
|
if (System.IO.File.Exists("Submarines/TutorialSub.sub"))
|
|
{
|
|
System.IO.File.Delete("Submarines/TutorialSub.sub");
|
|
|
|
NewMessage("Deleted TutorialSub from the submarine folder", Color.Green);
|
|
}
|
|
|
|
if (System.IO.File.Exists(GameServer.SettingsFile))
|
|
{
|
|
System.IO.File.Delete(GameServer.SettingsFile);
|
|
NewMessage("Deleted server settings", Color.Green);
|
|
}
|
|
|
|
if (System.IO.File.Exists(GameServer.ClientPermissionsFile))
|
|
{
|
|
System.IO.File.Delete(GameServer.ClientPermissionsFile);
|
|
NewMessage("Deleted client permission file", Color.Green);
|
|
}
|
|
|
|
if (System.IO.File.Exists("crashreport.log"))
|
|
{
|
|
System.IO.File.Delete("crashreport.log");
|
|
NewMessage("Deleted crashreport.log", Color.Green);
|
|
}
|
|
|
|
if (!System.IO.File.Exists("Content/Map/TutorialSub.sub"))
|
|
{
|
|
ThrowError("TutorialSub.sub not found!");
|
|
}
|
|
}));
|
|
|
|
commands.Add(new Command("limbscale", "Define the limbscale for the controlled character. Provide id or name if you want to target another character. Note: the changes are not saved!", (string[] args) =>
|
|
{
|
|
var character = Character.Controlled;
|
|
if (character == null)
|
|
{
|
|
ThrowError("Not controlling any character!");
|
|
return;
|
|
}
|
|
if (args.Length == 0)
|
|
{
|
|
ThrowError("Please give the value after the command.");
|
|
return;
|
|
}
|
|
if (!float.TryParse(args[0], NumberStyles.Number, CultureInfo.InvariantCulture, out float value))
|
|
{
|
|
ThrowError("Failed to parse float value from the arguments");
|
|
return;
|
|
}
|
|
RagdollParams ragdollParams = character.AnimController.RagdollParams;
|
|
ragdollParams.LimbScale = value;
|
|
var pos = character.WorldPosition;
|
|
character.AnimController.Recreate();
|
|
character.TeleportTo(pos);
|
|
}, isCheat: true));
|
|
|
|
commands.Add(new Command("jointscale", "Define the jointscale for the controlled character. Provide id or name if you want to target another character. Note: the changes are not saved!", (string[] args) =>
|
|
{
|
|
var character = Character.Controlled;
|
|
if (character == null)
|
|
{
|
|
ThrowError("Not controlling any character!");
|
|
return;
|
|
}
|
|
if (args.Length == 0)
|
|
{
|
|
ThrowError("Please give the value after the command.");
|
|
return;
|
|
}
|
|
if (!float.TryParse(args[0], NumberStyles.Number, CultureInfo.InvariantCulture, out float value))
|
|
{
|
|
ThrowError("Failed to parse float value from the arguments");
|
|
return;
|
|
}
|
|
RagdollParams ragdollParams = character.AnimController.RagdollParams;
|
|
ragdollParams.JointScale = value;
|
|
var pos = character.WorldPosition;
|
|
character.AnimController.Recreate();
|
|
character.TeleportTo(pos);
|
|
}, isCheat: true));
|
|
|
|
commands.Add(new Command("ragdollscale", "Rescale the ragdoll of the controlled character. Provide id or name if you want to target another character. Note: the changes are not saved!", (string[] args) =>
|
|
{
|
|
var character = Character.Controlled;
|
|
if (character == null)
|
|
{
|
|
ThrowError("Not controlling any character!");
|
|
return;
|
|
}
|
|
if (args.Length == 0)
|
|
{
|
|
ThrowError("Please give the value after the command.");
|
|
return;
|
|
}
|
|
if (!float.TryParse(args[0], NumberStyles.Number, CultureInfo.InvariantCulture, out float value))
|
|
{
|
|
ThrowError("Failed to parse float value from the arguments");
|
|
return;
|
|
}
|
|
RagdollParams ragdollParams = character.AnimController.RagdollParams;
|
|
ragdollParams.LimbScale = value;
|
|
ragdollParams.JointScale = value;
|
|
var pos = character.WorldPosition;
|
|
character.AnimController.Recreate();
|
|
character.TeleportTo(pos);
|
|
}, isCheat: true));
|
|
|
|
commands.Add(new Command("recreateragdoll", "Recreate the ragdoll of the controlled character. Provide id or name if you want to target another character.", (string[] args) =>
|
|
{
|
|
var character = (args.Length == 0) ? Character.Controlled : FindMatchingCharacter(args, true);
|
|
if (character == null)
|
|
{
|
|
ThrowError("Not controlling any character!");
|
|
return;
|
|
}
|
|
var pos = character.WorldPosition;
|
|
character.AnimController.Recreate();
|
|
character.TeleportTo(pos);
|
|
}, isCheat: true));
|
|
|
|
commands.Add(new Command("resetragdoll", "Reset the ragdoll of the controlled character. Provide id or name if you want to target another character.", (string[] args) =>
|
|
{
|
|
var character = (args.Length == 0) ? Character.Controlled : FindMatchingCharacter(args, true);
|
|
if (character == null)
|
|
{
|
|
ThrowError("Not controlling any character!");
|
|
return;
|
|
}
|
|
character.AnimController.ResetRagdoll();
|
|
}, isCheat: true));
|
|
|
|
commands.Add(new Command("reloadwearables|reloadlimbs", "Reloads the xml(s) where limbs and wearable sprites (clothing) of the controlled character are defined. Also reloads textures. Provide id or name if you want to target another character.", args =>
|
|
{
|
|
var character = (args.Length == 0) ? Character.Controlled : FindMatchingCharacter(args, true);
|
|
if (character == null)
|
|
{
|
|
ThrowError("Not controlling any character!");
|
|
return;
|
|
}
|
|
foreach (var limb in character.AnimController.Limbs)
|
|
{
|
|
limb.Sprite?.ReloadTexture();
|
|
limb.DamagedSprite?.ReloadTexture();
|
|
limb.DeformSprite?.Sprite.ReloadTexture();
|
|
foreach (var wearable in limb.WearingItems)
|
|
{
|
|
wearable.Sprite.ReloadXML();
|
|
wearable.Sprite.ReloadTexture();
|
|
}
|
|
foreach (var wearable in limb.OtherWearables)
|
|
{
|
|
wearable.Sprite.ReloadXML();
|
|
wearable.Sprite.ReloadTexture();
|
|
}
|
|
}
|
|
}, isCheat: true));
|
|
|
|
commands.Add(new Command("reloadxml", "Reloads the xml definition of the selected item(s)/structure(s) (SubEditor). Can also reload sprite xmls by entity id or by the name attribute (sprite element). Example 1: reloadxml id itemid. Example 2: reloadxml name \"Sprite name\"", args =>
|
|
{
|
|
if (Screen.Selected is SpriteEditorScreen)
|
|
{
|
|
return;
|
|
}
|
|
else if (args.Length > 1)
|
|
{
|
|
TryDoActionOnSprite(args[0], args[1], s => s.ReloadXML());
|
|
}
|
|
else if (Screen.Selected is SubEditorScreen subScreen)
|
|
{
|
|
if (!MapEntity.SelectedAny)
|
|
{
|
|
ThrowError("You have to select item(s)/structure(s) first!");
|
|
}
|
|
else
|
|
{
|
|
MapEntity.SelectedList.ForEach(e => e.Sprite?.ReloadXML());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ThrowError("Please provide the mode (name or id) and the value so that I can find the sprite for you!");
|
|
}
|
|
}, isCheat: true));
|
|
|
|
commands.Add(new Command("reloadtexture|reloadtextures", "In sub editor, reloads the xml definition of the selected item(s)/structure(s). Can also reload sprite xmls by entity id or by the name attribute (sprite element). Example 1: reloadtexture id itemid. Example 2: reloadtexture name \"Sprite name\"", args =>
|
|
{
|
|
if (Screen.Selected is SpriteEditorScreen)
|
|
{
|
|
return;
|
|
}
|
|
else if (args.Length > 1)
|
|
{
|
|
TryDoActionOnSprite(args[0], args[1], s => s.ReloadTexture());
|
|
}
|
|
else if (Screen.Selected is SubEditorScreen subScreen)
|
|
{
|
|
if (!MapEntity.SelectedAny)
|
|
{
|
|
ThrowError("You have to select item(s)/structure(s) first!");
|
|
}
|
|
else
|
|
{
|
|
MapEntity.SelectedList.ForEach(e => e.Sprite?.ReloadTexture());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ThrowError("Please provide the mode (name or id) and the value so that I can find the sprite for you!");
|
|
}
|
|
}, isCheat: true));
|
|
|
|
commands.Add(new Command("reloadsprite|reloadsprites", "Reload xml and texture of the given sprite(s). In sub editor, reloads the xml definition of the selected item(s)/structure(s). Can also reload sprite xmls by entity id or by the name attribute (sprite element). Example 1: reloadsprite id itemid. Example 2: reloadsprite name \"Sprite name\"", args =>
|
|
{
|
|
if (Screen.Selected is SpriteEditorScreen)
|
|
{
|
|
return;
|
|
}
|
|
else if (args.Length > 1)
|
|
{
|
|
TryDoActionOnSprite(args[0], args[1], s =>
|
|
{
|
|
s.ReloadXML();
|
|
s.ReloadTexture();
|
|
});
|
|
}
|
|
else if (Screen.Selected is SubEditorScreen subScreen)
|
|
{
|
|
if (!MapEntity.SelectedAny)
|
|
{
|
|
ThrowError("You have to select item(s)/structure(s) first!");
|
|
}
|
|
else
|
|
{
|
|
MapEntity.SelectedList.ForEach(e =>
|
|
{
|
|
if (e.Sprite != null)
|
|
{
|
|
e.Sprite.ReloadXML();
|
|
e.Sprite.ReloadTexture();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ThrowError("Please provide the mode (name or id) and the value so that I can find the sprite for you!");
|
|
}
|
|
}, isCheat: true));
|
|
}
|
|
|
|
private static bool TryDoActionOnSprite(string firstArg, string secondArg, Action<Sprite> action)
|
|
{
|
|
switch (firstArg)
|
|
{
|
|
case "name":
|
|
var sprites = Sprite.LoadedSprites.Where(s => s.Name?.ToLowerInvariant() == secondArg.ToLowerInvariant());
|
|
if (sprites.Any())
|
|
{
|
|
foreach (var s in sprites)
|
|
{
|
|
action(s);
|
|
}
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
ThrowError("Cannot find any matching sprites by the name: " + secondArg);
|
|
return false;
|
|
}
|
|
case "identifier":
|
|
case "id":
|
|
sprites = Sprite.LoadedSprites.Where(s => s.EntityID?.ToLowerInvariant() == secondArg.ToLowerInvariant());
|
|
if (sprites.Any())
|
|
{
|
|
foreach (var s in sprites)
|
|
{
|
|
action(s);
|
|
}
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
ThrowError("Cannot find any matching sprites by the id: " + secondArg);
|
|
return false;
|
|
}
|
|
default:
|
|
ThrowError("The first argument must be either 'name' or 'id'");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|