From b48aa89004872d692fa852a7ad1b4bc6a75a2786 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 18 Mar 2019 22:30:27 +0200 Subject: [PATCH] bbc4a31...e6715d6 commit e6715d605db9bb1d608e4a4990ac41f6214f61d1 Author: Joonas Rikkonen Date: Tue Mar 5 17:22:31 2019 +0200 Fixed the "control" console command not being usable by clients, changed the way arguments are given to the "setclientcharacter" command (no semicolon to separate the names, quotation marks have to be used for multi-word names just like with any other command). Closes #1224 commit acb7c1e0dc05bf619e7ec4875196cc45647d3fb4 Author: Joonas Rikkonen Date: Tue Mar 5 16:30:38 2019 +0200 Steam Workshop fixes: - Install content packages for items that only contain a sub. Otherwise the system can't determine if the item has been updated (and might also be useful for toggling off incompatible subs when switching from mod to another). - Log an error instead of crashing the game if CheckWorkshopItemEnabled or CheckWorkshopItemUpToDate fails due to a missing filelist.xml. - Show a messagebox when a workshop item is updated succesfully. commit b2e8ed565bc03f466930799268c13b2fca4bb9c9 Author: Joonas Rikkonen Date: Tue Mar 5 14:43:42 2019 +0200 Fixed nullref exception when disabling a workshop item that doesn't have an update button (or when enabling the item fails) commit 26f1f285cd80ca6f023b12e6dd80dc71e87ee9c3 Author: Joonas Rikkonen Date: Tue Mar 5 14:15:14 2019 +0200 Fixed console command aliases not being taken into account in GameClient.HasConsoleCommandPermission (meaning that the client needed a permission for each name variant of a command, making it impossible to for example use "fixwalls" instead of "fixhulls"). Closes #1225 commit dee02de681a212efd0e0a82c14619f3fe4839cc4 Author: Joonas Rikkonen Date: Tue Mar 5 13:35:48 2019 +0200 Fixed traitor rounds failing to start if there's no owner client, fixed occasional "traitorCount somehow ended up less than 1" errors due to Rand.Int using 0 as the minimum value. Closes #1217 --- .../BarotraumaClient/Source/DebugConsole.cs | 183 ++++++++++++++++++ .../Source/GameSession/CrewManager.cs | 36 +++- .../BarotraumaClient/Source/GameSettings.cs | 22 +++ .../Source/Items/Components/ItemComponent.cs | 57 ++++++ .../Source/Networking/GameClient.cs | 30 ++- .../Source/Networking/SteamManager.cs | 68 ++----- .../Source/Screens/CharacterEditorScreen.cs | 37 ++++ .../Source/Screens/SteamWorkshopScreen.cs | 19 +- .../BarotraumaServer/Source/DebugConsole.cs | 42 ++-- .../GameSession/GameModes/TraitorManager.cs | 12 +- .../Source/Networking/GameServer.cs | 10 +- .../Source/Characters/Character.cs | 104 ---------- .../BarotraumaShared/Source/DebugConsole.cs | 8 +- .../BarotraumaShared/Source/GameSettings.cs | 58 +++--- .../Source/Items/Components/ItemContainer.cs | 18 ++ .../BarotraumaShared/Source/Map/Map/Map.cs | 7 + .../BarotraumaShared/Source/Map/Submarine.cs | 9 + .../BarotraumaShared/Source/PlayerInput.cs | 10 + 18 files changed, 493 insertions(+), 237 deletions(-) diff --git a/Barotrauma/BarotraumaClient/Source/DebugConsole.cs b/Barotrauma/BarotraumaClient/Source/DebugConsole.cs index 9c6563b8f..70bffec04 100644 --- a/Barotrauma/BarotraumaClient/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaClient/Source/DebugConsole.cs @@ -1233,6 +1233,189 @@ namespace Barotrauma TextManager.WriteToCSV(); NPCConversation.WriteToCSV(); })); +#endif + + 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); + + 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; + })); + + + 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 + + GameMain.Config.SaveNewPlayerConfig(); + + 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 lines = new List(); + foreach (MapEntityPrefab me in MapEntityPrefab.List) + { + lines.Add("" + me.Name + ""); + lines.Add("" + me.Description + ""); + } + File.WriteAllLines(filePath, lines); + })); +#if DEBUG + commands.Add(new Command("checkduplicates", "Checks the given language for duplicate translation keys and writes to file.", (string[] args) => + { + if (args.Length != 1) return; + TextManager.CheckForDuplicates(args[0]); + })); + + commands.Add(new Command("writetocsv", "Writes the default language (English) to a .csv file.", (string[] args) => + { + TextManager.WriteToCSV(); + NPCConversation.WriteToCSV(); + })); 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) => { diff --git a/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs b/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs index e17fe0dc9..75e0aa3d0 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSession/CrewManager.cs @@ -149,6 +149,32 @@ namespace Barotrauma CanBeFocused = false }; + //report buttons + foreach (Order order in reports) + { + if (!order.TargetAllCharacters || order.SymbolSprite == null) continue; + var btn = new GUIButton(new RectTransform(new Point(reportButtonFrame.Rect.Width), reportButtonFrame.RectTransform), style: null) + { + OnClicked = (GUIButton button, object userData) => + { + if (Character.Controlled == null || Character.Controlled.SpeechImpediment >= 100.0f) return false; + SetCharacterOrder(null, order, null, Character.Controlled); + return true; + }, + UserData = order, + ToolTip = order.Name + }; + + new GUIFrame(new RectTransform(new Vector2(1.5f), btn.RectTransform, Anchor.Center), "OuterGlow") + { + Color = Color.Red * 0.8f, + HoverColor = Color.Red * 1.0f, + PressedColor = Color.Red * 0.6f, + UserData = "highlighted", + CanBeFocused = false, + Visible = false + }; + var characterInfo = new CharacterInfo(subElement); characterInfos.Add(characterInfo); foreach (XElement invElement in subElement.Elements()) @@ -164,16 +190,6 @@ namespace Barotrauma prevUIScale = GUI.Scale; } - - #endregion - - #region Character list management - - public Rectangle GetCharacterListArea() - { - return characterListBox.Rect; - } - partial void InitProjectSpecific() { guiFrame = new GUIFrame(new RectTransform(Vector2.One, GUICanvas.Instance), null, Color.Transparent) diff --git a/Barotrauma/BarotraumaClient/Source/GameSettings.cs b/Barotrauma/BarotraumaClient/Source/GameSettings.cs index 00085898f..a111ddc03 100644 --- a/Barotrauma/BarotraumaClient/Source/GameSettings.cs +++ b/Barotrauma/BarotraumaClient/Source/GameSettings.cs @@ -626,6 +626,28 @@ namespace Barotrauma new GUIMessageBox(TextManager.Get("RestartRequiredLabel"), TextManager.Get("RestartRequiredLanguage")); + return true; + }; + + //spacing + new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), generalLayoutGroup.RectTransform), style: null); + + new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), buttonArea.RectTransform, Anchor.BottomLeft), + TextManager.Get("Cancel")) + { + IgnoreLayoutGroups = true, + OnClicked = (x, y) => + { + if (UnsavedSettings) + { + LoadPlayerConfig(); + } + if (Screen.Selected == GameMain.MainMenuScreen) GameMain.MainMenuScreen.ReturnToMainMenu(null, null); + GUI.SettingsMenuOpen = false; + return true; + } + }; + //spacing new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), generalLayoutGroup.RectTransform), style: null); diff --git a/Barotrauma/BarotraumaClient/Source/Items/Components/ItemComponent.cs b/Barotrauma/BarotraumaClient/Source/Items/Components/ItemComponent.cs index 72589ccf5..94a9eee32 100644 --- a/Barotrauma/BarotraumaClient/Source/Items/Components/ItemComponent.cs +++ b/Barotrauma/BarotraumaClient/Source/Items/Components/ItemComponent.cs @@ -184,6 +184,63 @@ namespace Barotrauma.Items.Components } } } + + public void ApplyTo(RectTransform target) + { + if (RelativeOffset.HasValue) + { + target.RelativeOffset = RelativeOffset.Value; + } + else if (AbsoluteOffset.HasValue) + { + target.AbsoluteOffset = AbsoluteOffset.Value; + } + if (RelativeSize.HasValue) + { + target.RelativeSize = RelativeSize.Value; + } + else if (AbsoluteSize.HasValue) + { + target.NonScaledSize = AbsoluteSize.Value; + } + if (Anchor.HasValue) + { + target.Anchor = Anchor.Value; + } + if (Pivot.HasValue) + { + target.Pivot = Pivot.Value; + } + else + { + target.Pivot = RectTransform.MatchPivotToAnchor(target.Anchor); + } + target.RecalculateChildren(true, true); + } + } + + public GUIFrame GuiFrame { get; protected set; } + + [Serialize(false, false)] + public bool AllowUIOverlap + { + get; + set; + } + + private ItemComponent linkToUIComponent; + [Serialize("", false)] + public string LinkUIToComponent + { + get; + set; + } + + [Serialize(0, false)] + public int HudPriority + { + get; + private set; } private bool shouldMuffleLooping; diff --git a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs index c2bc5f659..53b96b79d 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/GameClient.cs @@ -847,6 +847,16 @@ namespace Barotrauma.Networking waitInServerQueueBox = null; CoroutineManager.StopCoroutines("WaitInServerQueue"); } + else + { + string msg = ""; + if (disconnectReason == DisconnectReason.Unknown) + { + msg = disconnectMsg; + } + else + { + msg = TextManager.Get("DisconnectReason." + disconnectReason.ToString()); if (allowReconnect && disconnectReason == DisconnectReason.Unknown) { @@ -1678,12 +1688,24 @@ namespace Barotrauma.Networking return permissions.HasFlag(permission); } - public bool HasConsoleCommandPermission(string command) + public bool HasConsoleCommandPermission(string commandName) { - if (!permissions.HasFlag(ClientPermissions.ConsoleCommands)) return false; + if (!permissions.HasFlag(ClientPermissions.ConsoleCommands)) { return false; } - command = command.ToLowerInvariant(); - return permittedConsoleCommands.Any(c => c.ToLowerInvariant() == command); + commandName = commandName.ToLowerInvariant(); + if (permittedConsoleCommands.Any(c => c.ToLowerInvariant() == commandName)) { return true; } + + //check aliases + foreach (DebugConsole.Command command in DebugConsole.Commands) + { + if (command.names.Contains(commandName)) + { + if (command.names.Intersect(permittedConsoleCommands).Any()) { return true; } + break; + } + } + + return false; } public override void Disconnect() diff --git a/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs b/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs index 8aac740e5..c744d8ed0 100644 --- a/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs +++ b/Barotrauma/BarotraumaClient/Source/Networking/SteamManager.cs @@ -327,46 +327,7 @@ namespace Barotrauma.Steam item.Subscribe(); item.Download(); } - - public static void SaveToWorkshop(Submarine sub) - { - if (instance == null || !instance.isInitialized) return; - - Workshop.Editor item; - ContentPackage contentPackage; - try - { - CreateWorkshopItemStaging( - new List() { new ContentFile(sub.FilePath, ContentType.None) }, - out item, out contentPackage); - } - catch (Exception e) - { - DebugConsole.ThrowError("Creating the workshop item failed.", e); - return; - } - - item.Description = sub.Description; - item.Title = sub.Name; - item.Tags.Add("Submarine"); - - string subPreviewPath = Path.GetFullPath(Path.Combine(item.Folder, PreviewImageName)); - try - { - using (Stream s = File.Create(subPreviewPath)) - { - sub.PreviewImage.Texture.SaveAsPng(s, (int)sub.PreviewImage.size.X, (int)sub.PreviewImage.size.Y); - item.PreviewImage = subPreviewPath; - } - } - catch (Exception e) - { - DebugConsole.ThrowError("Saving submarine preview image failed.", e); - item.PreviewImage = null; - } - StartPublishItem(contentPackage, item); - } - + /// /// Creates a new folder, copies the specified files there and creates a metadata file with install instructions. /// @@ -568,14 +529,15 @@ namespace Barotrauma.Steam return false; } - ContentPackage contentPackage = new ContentPackage(Path.Combine(item.Directory.FullName, MetadataFileName)); + string metaDataFilePath = Path.Combine(item.Directory.FullName, MetadataFileName); + ContentPackage contentPackage = new ContentPackage(metaDataFilePath); string newContentPackagePath = GetWorkshopItemContentPackagePath(contentPackage); var allPackageFiles = Directory.GetFiles(item.Directory.FullName, "*", SearchOption.AllDirectories); List nonContentFiles = new List(); foreach (string file in allPackageFiles) { - if (file == MetadataFileName) { continue; } + if (file == metaDataFilePath) { continue; } string relativePath = UpdaterUtil.GetRelativePath(file, item.Directory.FullName); string fullPath = Path.GetFullPath(relativePath); if (contentPackage.Files.Any(f => { string fp = Path.GetFullPath(f.Path); return fp == fullPath; })) { continue; } @@ -612,13 +574,6 @@ namespace Barotrauma.Steam try { - //we only need to create a new content package for the item if it contains content with a type other than None or Submarine - //e.g. items that are just a sub file are just copied to the game folder - if (contentPackage.Files.Any(f => f.Type != ContentType.None && f.Type != ContentType.Submarine)) - { - File.Copy(contentPackage.Path, newContentPackagePath); - } - foreach (ContentFile contentFile in contentPackage.Files) { string sourceFile = Path.Combine(item.Directory.FullName, contentFile.Path); @@ -789,14 +744,13 @@ namespace Barotrauma.Steam string metaDataPath = Path.Combine(item.Directory.FullName, MetadataFileName); if (!File.Exists(metaDataPath)) { - throw new FileNotFoundException("Metadata file for the Workshop item \"" + item.Title + "\" not found. The file may be corrupted."); + DebugConsole.ThrowError("Metadata file for the Workshop item \"" + item.Title + "\" not found. The file may be corrupted."); + return false; } ContentPackage contentPackage = new ContentPackage(metaDataPath); //make sure the contentpackage file is present - //(unless the package only contains submarine files, in which case we don't need a content package) - if (contentPackage.Files.Any(f => f.Type != ContentType.Submarine) && - !File.Exists(GetWorkshopItemContentPackagePath(contentPackage)) && + if (!File.Exists(GetWorkshopItemContentPackagePath(contentPackage)) && !ContentPackage.List.Any(cp => cp.Name == contentPackage.Name)) { return false; @@ -819,7 +773,8 @@ namespace Barotrauma.Steam string metaDataPath = Path.Combine(item.Directory.FullName, MetadataFileName); if (!File.Exists(metaDataPath)) { - throw new FileNotFoundException("Metadata file for the Workshop item \"" + item.Title + "\" not found. The file may be corrupted."); + DebugConsole.ThrowError("Metadata file for the Workshop item \"" + item.Title + "\" not found. The file may be corrupted."); + return false; } ContentPackage steamPackage = new ContentPackage(metaDataPath); @@ -839,15 +794,20 @@ namespace Barotrauma.Steam bool itemsUpdated = false; foreach (ulong subscribedItemId in instance.client.Workshop.GetSubscribedItemIds()) { + //TODO: fix this, GetItem doesn't query item.Modified var item = instance.client.Workshop.GetItem(subscribedItemId); if (item.Installed && CheckWorkshopItemEnabled(item) && !CheckWorkshopItemUpToDate(item)) { if (!UpdateWorkshopItem(item, out string errorMsg)) { DebugConsole.ThrowError(errorMsg); + new GUIMessageBox( + TextManager.Get("Error"), + TextManager.Get("WorkshopItemUpdateFailed").Replace("[itemname]", item.Title).Replace("[errormessage]", errorMsg)); } else { + new GUIMessageBox("", TextManager.Get("WorkshopItemUpdated").Replace("[itemname]", item.Title)); itemsUpdated = true; } } diff --git a/Barotrauma/BarotraumaClient/Source/Screens/CharacterEditorScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/CharacterEditorScreen.cs index 316dd5656..a7a147242 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/CharacterEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/CharacterEditorScreen.cs @@ -475,6 +475,43 @@ namespace Barotrauma UpdateSourceRect(limb, newRect); } } + UpdateJointCreation(); + if (PlayerInput.KeyHit(Keys.Left)) + { + foreach (var limb in selectedLimbs) + { + var newRect = limb.ActiveSprite.SourceRect; + newRect.X--; + UpdateSourceRect(limb, newRect); + } + } + if (PlayerInput.KeyHit(Keys.Right)) + { + foreach (var limb in selectedLimbs) + { + var newRect = limb.ActiveSprite.SourceRect; + newRect.X++; + UpdateSourceRect(limb, newRect); + } + } + if (PlayerInput.KeyHit(Keys.Down)) + { + foreach (var limb in selectedLimbs) + { + var newRect = limb.ActiveSprite.SourceRect; + newRect.Y++; + UpdateSourceRect(limb, newRect); + } + } + if (PlayerInput.KeyHit(Keys.Up)) + { + foreach (var limb in selectedLimbs) + { + var newRect = limb.ActiveSprite.SourceRect; + newRect.Y--; + UpdateSourceRect(limb, newRect); + } + } } if (!isFreezed) { diff --git a/Barotrauma/BarotraumaClient/Source/Screens/SteamWorkshopScreen.cs b/Barotrauma/BarotraumaClient/Source/Screens/SteamWorkshopScreen.cs index 98c1af21b..651a1b8d0 100644 --- a/Barotrauma/BarotraumaClient/Source/Screens/SteamWorkshopScreen.cs +++ b/Barotrauma/BarotraumaClient/Source/Screens/SteamWorkshopScreen.cs @@ -366,7 +366,17 @@ namespace Barotrauma IgnoreLayoutGroups = true, OnClicked = (btn, userdata) => { - SteamManager.UpdateWorkshopItem(item, out string errorMsg); + if (SteamManager.UpdateWorkshopItem(item, out string errorMsg)) + { + new GUIMessageBox("", TextManager.Get("WorkshopItemUpdated").Replace("[itemname]", item.Title)); + } + else + { + DebugConsole.ThrowError(errorMsg); + new GUIMessageBox( + TextManager.Get("Error"), + TextManager.Get("WorkshopItemUpdateFailed").Replace("[itemname]", item.Title).Replace("[errormessage]", errorMsg)); + } btn.Enabled = false; btn.Visible = false; return true; @@ -544,9 +554,10 @@ namespace Barotrauma tickBox.Enabled = false; } } - if (!tickBox.Enabled && updateButton == null) + if (updateButton != null) { - updateButton.Enabled = false; + //cannot update if enabling/disabling the item failed or if the item is not enabled + updateButton.Enabled = tickBox.Enabled && tickBox.Selected; } if (!string.IsNullOrEmpty(errorMsg)) { @@ -666,7 +677,7 @@ namespace Barotrauma } catch (Exception e) { - DebugConsole.ThrowError("Failed to copy submarine file \""+sub.FilePath+"\" to the Workshop item staging folder.", e); + DebugConsole.ThrowError("Failed to copy submarine file \"" + sub.FilePath + "\" to the Workshop item staging folder.", e); return; } diff --git a/Barotrauma/BarotraumaServer/Source/DebugConsole.cs b/Barotrauma/BarotraumaServer/Source/DebugConsole.cs index 8e426cecb..a1fa5069d 100644 --- a/Barotrauma/BarotraumaServer/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaServer/Source/DebugConsole.cs @@ -641,25 +641,20 @@ namespace Barotrauma AssignOnExecute("setclientcharacter", (string[] args) => { if (GameMain.Server == null) return; - - int separatorIndex = Array.IndexOf(args, ";"); - if (separatorIndex == -1 || args.Length < 3) + + if (args.Length < 2) { - ThrowError("Invalid parameters. The command should be formatted as \"setclientcharacter [client] ; [character]\""); + ThrowError("Invalid parameters. The command should be formatted as \"setclientcharacter [client] [character]\". If the names consist of multiple words, you should surround them with quotation marks."); return; } - - string[] argsLeft = args.Take(separatorIndex).ToArray(); - string[] argsRight = args.Skip(separatorIndex + 1).ToArray(); - string clientName = string.Join(" ", argsLeft); - - var client = GameMain.Server.ConnectedClients.Find(c => c.Name == clientName); + + var client = GameMain.Server.ConnectedClients.Find(c => c.Name == args[0]); if (client == null) { - ThrowError("Client \"" + clientName + "\" not found."); + ThrowError("Client \"" + args[0] + "\" not found."); } - var character = FindMatchingCharacter(argsRight, false); + var character = FindMatchingCharacter(args.Skip(1).ToArray(), false); GameMain.Server.SetClientCharacter(client, character); }); @@ -1255,7 +1250,7 @@ namespace Barotrauma (Client client, Vector2 cursorWorldPos, string[] args) => { if (args.Length < 1) return; - var character = FindMatchingCharacter(args, true); + var character = FindMatchingCharacter(args, ignoreRemotePlayers: true, allowedRemotePlayer: client); if (character != null) { GameMain.Server.SetClientCharacter(client, character); @@ -1496,24 +1491,25 @@ namespace Barotrauma "setclientcharacter", (Client senderClient, Vector2 cursorWorldPos, string[] args) => { - int separatorIndex = Array.IndexOf(args, ";"); - if (separatorIndex == -1 || args.Length < 3) + if (args.Length < 2) { - GameMain.Server.SendConsoleMessage("Invalid parameters. The command should be formatted as \"setclientcharacter [client] ; [character]\"", senderClient); + GameMain.Server.SendConsoleMessage("Invalid parameters. The command should be formatted as \"setclientcharacter [client] [character]\". If the names consist of multiple words, you should surround them with quotation marks.", senderClient); return; } - string[] argsLeft = args.Take(separatorIndex).ToArray(); - string[] argsRight = args.Skip(separatorIndex + 1).ToArray(); - string clientName = string.Join(" ", argsLeft); - - var client = GameMain.Server.ConnectedClients.Find(c => c.Name == clientName); + if (args.Length < 2) + { + ThrowError("Invalid parameters. The command should be formatted as \"setclientcharacter [client] [character]\". If the names consist of multiple words, you should surround them with quotation marks."); + return; + } + + var client = GameMain.Server.ConnectedClients.Find(c => c.Name == args[0]); if (client == null) { - GameMain.Server.SendConsoleMessage("Client \"" + clientName + "\" not found.", senderClient); + GameMain.Server.SendConsoleMessage("Client \"" + args[0] + "\" not found.", senderClient); } - var character = FindMatchingCharacter(argsRight, false); + var character = FindMatchingCharacter(args.Skip(1).ToArray(), false); GameMain.Server.SetClientCharacter(client, character); } ); diff --git a/Barotrauma/BarotraumaServer/Source/GameSession/GameModes/TraitorManager.cs b/Barotrauma/BarotraumaServer/Source/GameSession/GameModes/TraitorManager.cs index 6346e625d..a96478b67 100644 --- a/Barotrauma/BarotraumaServer/Source/GameSession/GameModes/TraitorManager.cs +++ b/Barotrauma/BarotraumaServer/Source/GameSession/GameModes/TraitorManager.cs @@ -27,14 +27,14 @@ namespace Barotrauma var greetingMsgBox = ChatMessage.Create(null, greetingMessage, ChatMessageType.MessageBox, null); var moreAgentsMsgBox = ChatMessage.Create(null, moreAgentsMessage, ChatMessageType.MessageBox, null); - Client client = server.ConnectedClients.Find(c => c.Character == Character); - GameMain.Server.SendDirectChatMessage(greetingChatMsg, client); - GameMain.Server.SendDirectChatMessage(moreAgentsChatMsg, client); - GameMain.Server.SendDirectChatMessage(greetingMsgBox, client); - GameMain.Server.SendDirectChatMessage(moreAgentsMsgBox, client); + Client traitorClient = server.ConnectedClients.Find(c => c.Character == Character); + GameMain.Server.SendDirectChatMessage(greetingChatMsg, traitorClient); + GameMain.Server.SendDirectChatMessage(moreAgentsChatMsg, traitorClient); + GameMain.Server.SendDirectChatMessage(greetingMsgBox, traitorClient); + GameMain.Server.SendDirectChatMessage(moreAgentsMsgBox, traitorClient); Client ownerClient = server.ConnectedClients.Find(c => c.Connection == server.OwnerConnection); - if (client != ownerClient) + if (traitorClient != ownerClient && ownerClient != null && ownerClient.Character == null) { var ownerMsg = ChatMessage.Create( null,//TextManager.Get("NewTraitor"), diff --git a/Barotrauma/BarotraumaServer/Source/Networking/GameServer.cs b/Barotrauma/BarotraumaServer/Source/Networking/GameServer.cs index 1fd1335d6..dd114fd65 100644 --- a/Barotrauma/BarotraumaServer/Source/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaServer/Source/Networking/GameServer.cs @@ -1701,7 +1701,7 @@ namespace Barotrauma.Networking } int max = Math.Max(serverSettings.TraitorUseRatio ? (int)Math.Round(characters.Count * serverSettings.TraitorRatio, 1) : 1, 1); - int traitorCount = Rand.Int(max + 1); + int traitorCount = Rand.Range(1, max + 1); TraitorManager = new TraitorManager(this, traitorCount); if (TraitorManager.TraitorList.Count > 0) @@ -2054,6 +2054,14 @@ namespace Barotrauma.Networking public void SendDirectChatMessage(ChatMessage msg, Client recipient) { + if (recipient == null) + { + string errorMsg = "Attempted to send a chat message to a null client.\n" + Environment.StackTrace; + DebugConsole.ThrowError(errorMsg); + GameAnalyticsManager.AddErrorEventOnce("GameServer.SendDirectChatMessage:ClientNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg); + return; + } + msg.NetStateID = recipient.ChatMsgQueue.Count > 0 ? (ushort)(recipient.ChatMsgQueue.Last().NetStateID + 1) : (ushort)(recipient.LastRecvChatMsgID + 1); diff --git a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs index 65ca5b84e..7eb5044ed 100644 --- a/Barotrauma/BarotraumaShared/Source/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/Source/Characters/Character.cs @@ -1110,110 +1110,6 @@ namespace Barotrauma return currMaxSpeed; } - public void Control(float deltaTime, Camera cam) - { - ViewTarget = null; - if (!AllowInput) return; - - Vector2 smoothedCursorDiff = cursorPosition - SmoothedCursorPosition; - if (Controlled == this) - { - SmoothedCursorPosition = cursorPosition; - } - else - { - smoothedCursorDiff = NetConfig.InterpolateCursorPositionError(smoothedCursorDiff); - SmoothedCursorPosition = cursorPosition - smoothedCursorDiff; - } - - if (!(this is AICharacter) || Controlled == this || IsRemotePlayer) - { - Vector2 targetMovement = GetTargetMovement(); - - AnimController.TargetMovement = targetMovement; - AnimController.IgnorePlatforms = AnimController.TargetMovement.Y < -0.1f; - } - - if (AnimController is HumanoidAnimController) - { - ((HumanoidAnimController) AnimController).Crouching = IsKeyDown(InputType.Crouch); - } - - return currMaxSpeed; - } - - /// - /// Can be used to modify the character's speed via StatusEffects - /// - public float SpeedMultiplier - { - get - { - if (speedMultipliers.Count == 0) return 1f; - - float greatestPositive = 1f; - float greatestNegative = 1f; - - for (int i = 0; i < speedMultipliers.Count; i++) - { - float val = speedMultipliers[i]; - if (val < 1f) - { - if (val < greatestNegative) - { - greatestNegative = val; - } - } - else - { - if (val > greatestPositive) - { - greatestPositive = val; - } - } - } - - return greatestPositive - (1f - greatestNegative); - } - set - { - if (value == 1f) return; - speedMultipliers.Add(value); - } - } - - public void ResetSpeedMultiplier() - { - speedMultipliers.Clear(); - } - - /// - /// Applies temporary limits to the speed (damage). - /// - public float GetCurrentMaxSpeed(bool run) - { - float currMaxSpeed = AnimController.GetCurrentSpeed(run); - - //? - //currMaxSpeed *= 1.5f; - - var leftFoot = AnimController.GetLimb(LimbType.LeftFoot); - if (leftFoot != null) - { - float footAfflictionStrength = CharacterHealth.GetAfflictionStrength("damage", leftFoot, true); - currMaxSpeed *= MathHelper.Lerp(1.0f, 0.25f, MathHelper.Clamp(footAfflictionStrength / 100.0f, 0.0f, 1.0f)); - } - - var rightFoot = AnimController.GetLimb(LimbType.RightFoot); - if (rightFoot != null) - { - float footAfflictionStrength = CharacterHealth.GetAfflictionStrength("damage", rightFoot, true); - currMaxSpeed *= MathHelper.Lerp(1.0f, 0.25f, MathHelper.Clamp(footAfflictionStrength / 100.0f, 0.0f, 1.0f)); - } - - return currMaxSpeed; - } - public void Control(float deltaTime, Camera cam) { ViewTarget = null; diff --git a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs index 7bdada449..aa7095827 100644 --- a/Barotrauma/BarotraumaShared/Source/DebugConsole.cs +++ b/Barotrauma/BarotraumaShared/Source/DebugConsole.cs @@ -801,7 +801,7 @@ namespace Barotrauma } }, null, true)); - commands.Add(new Command("setclientcharacter", "setclientcharacter [client name] ; [character name]: Gives the client control of the specified character.", null, + commands.Add(new Command("setclientcharacter", "setclientcharacter [client name] [character name]: Gives the client control of the specified character.", null, () => { if (GameMain.NetworkMember == null) return null; @@ -1276,7 +1276,7 @@ namespace Barotrauma } } - private static Character FindMatchingCharacter(string[] args, bool ignoreRemotePlayers = false) + private static Character FindMatchingCharacter(string[] args, bool ignoreRemotePlayers = false, Client allowedRemotePlayer = null) { if (args.Length == 0) return null; @@ -1292,7 +1292,9 @@ namespace Barotrauma characterIndex = -1; } - var matchingCharacters = Character.CharacterList.FindAll(c => (!ignoreRemotePlayers || !c.IsRemotePlayer) && c.Name.ToLowerInvariant() == characterName); + var matchingCharacters = Character.CharacterList.FindAll(c => + c.Name.ToLowerInvariant() == characterName && + (!c.IsRemotePlayer || !ignoreRemotePlayers || allowedRemotePlayer?.Character == c)); if (!matchingCharacters.Any()) { diff --git a/Barotrauma/BarotraumaShared/Source/GameSettings.cs b/Barotrauma/BarotraumaShared/Source/GameSettings.cs index f76ee19a8..976d10556 100644 --- a/Barotrauma/BarotraumaShared/Source/GameSettings.cs +++ b/Barotrauma/BarotraumaShared/Source/GameSettings.cs @@ -65,6 +65,8 @@ namespace Barotrauma public int ParticleLimit { get; set; } + public int ParticleLimit { get; set; } + public float LightMapScale { get; set; } public bool SpecularityEnabled { get; set; } public bool ChromaticAberrationEnabled { get; set; } @@ -395,6 +397,8 @@ namespace Barotrauma AimAssistAmount = doc.Root.GetAttributeFloat("aimassistamount", 0.5f); + AimAssistAmount = doc.Root.GetAttributeFloat("aimassistamount", 0.5f); + AimAssistAmount = doc.Root.GetAttributeFloat("aimassistamount", 0.5f); keyMapping = new KeyOrMouse[Enum.GetNames(typeof(InputType)).Length]; @@ -566,34 +570,6 @@ namespace Barotrauma TextManager.LoadTextPacks(SelectedContentPackages); - //display error messages after all content packages have been loaded - //to make sure the package that contains text files has been loaded before we attempt to use TextManager - foreach (string missingPackagePath in missingPackagePaths) - { - DebugConsole.ThrowError(TextManager.Get("ContentPackageNotFound").Replace("[packagepath]", missingPackagePath)); - } - foreach (ContentPackage incompatiblePackage in incompatiblePackages) - { - DebugConsole.ThrowError(TextManager.Get(incompatiblePackage.GameVersion <= new Version(0, 0, 0, 0) ? "IncompatibleContentPackageUnknownVersion" : "IncompatibleContentPackage") - .Replace("[packagename]", incompatiblePackage.Name) - .Replace("[packageversion]", incompatiblePackage.GameVersion.ToString()) - .Replace("[gameversion]", GameMain.Version.ToString())); - } - foreach (ContentPackage contentPackage in SelectedContentPackages) - { - foreach (ContentFile file in contentPackage.Files) - { - if (!System.IO.File.Exists(file.Path)) - { - DebugConsole.ThrowError("Error in content package \"" + contentPackage.Name + "\" - file \"" + file.Path + "\" not found."); - continue; - } - ToolBox.IsProperFilenameCase(file.Path); - } - } - - TextManager.LoadTextPacks(SelectedContentPackages); - //display error messages after all content packages have been loaded //to make sure the package that contains text files has been loaded before we attempt to use TextManager foreach (string missingPackagePath in missingPackagePaths) @@ -1198,6 +1174,32 @@ namespace Barotrauma NewLineOnAttributes = true }; +#if CLIENT + if (Tutorial.Tutorials != null) + { + foreach (Tutorial tutorial in Tutorial.Tutorials) + { + if (tutorial.Completed && !CompletedTutorialNames.Contains(tutorial.Name)) + { + CompletedTutorialNames.Add(tutorial.Name); + } + } + } +#endif + var tutorialElement = new XElement("tutorials"); + foreach (string tutorialName in CompletedTutorialNames) + { + tutorialElement.Add(new XElement("Tutorial", new XAttribute("name", tutorialName))); + } + doc.Root.Add(tutorialElement); + + XmlWriterSettings settings = new XmlWriterSettings + { + Indent = true, + OmitXmlDeclaration = true, + NewLineOnAttributes = true + }; + #if CLIENT if (Tutorial.Tutorials != null) { diff --git a/Barotrauma/BarotraumaShared/Source/Items/Components/ItemContainer.cs b/Barotrauma/BarotraumaShared/Source/Items/Components/ItemContainer.cs index e1e01d372..ae63f344b 100644 --- a/Barotrauma/BarotraumaShared/Source/Items/Components/ItemContainer.cs +++ b/Barotrauma/BarotraumaShared/Source/Items/Components/ItemContainer.cs @@ -223,6 +223,24 @@ namespace Barotrauma.Items.Components return base.Select(character); } + public override bool Select(Character character) + { + if (item.Container != null) { return false; } + + if (AutoInteractWithContained) + { + foreach (Item contained in Inventory.Items) + { + if (contained == null) continue; + if (contained.TryInteract(character)) + { + return false; + } + } + } + return base.Select(character); + } + public override bool Pick(Character picker) { if (AutoInteractWithContained) diff --git a/Barotrauma/BarotraumaShared/Source/Map/Map/Map.cs b/Barotrauma/BarotraumaShared/Source/Map/Map/Map.cs index c3d5d2926..5e0b5c4dc 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Map/Map.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Map/Map.cs @@ -430,6 +430,13 @@ namespace Barotrauma } CurrentLocation.SelectedMissionIndex = missionIndex; + //the destination must be the same as the destination of the mission + if (CurrentLocation.SelectedMission != null && + CurrentLocation.SelectedMission.Locations[1] != SelectedLocation) + { + SelectLocation(CurrentLocation.SelectedMission.Locations[1]); + } + SelectedLocation = location; SelectedConnection = connections.Find(c => c.Locations.Contains(CurrentLocation) && c.Locations.Contains(SelectedLocation)); OnLocationSelected?.Invoke(SelectedLocation, SelectedConnection); diff --git a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs index 0fa62f65b..64f4ddb79 100644 --- a/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs +++ b/Barotrauma/BarotraumaShared/Source/Map/Submarine.cs @@ -526,6 +526,10 @@ namespace Barotrauma { maxX = Math.Min(maxX, ruin.Area.X - 100.0f); } + else + { + maxX = Math.Min(maxX, ruin.Area.X - 100.0f); + } if (entity.IsVisible(worldView)) { visibleEntities.Add(entity); } } @@ -550,6 +554,11 @@ namespace Barotrauma spawnPos.X = (minX + maxX) / 2; } + if (minX < 0.0f && maxX > Level.Loaded.Size.X) + { + //no walls found at either side, just use the initial spawnpos and hope for the best + } + if (minX < 0.0f && maxX > Level.Loaded.Size.X) { //no walls found at either side, just use the initial spawnpos and hope for the best diff --git a/Barotrauma/BarotraumaShared/Source/PlayerInput.cs b/Barotrauma/BarotraumaShared/Source/PlayerInput.cs index dac0e7d44..fc56c8fc7 100644 --- a/Barotrauma/BarotraumaShared/Source/PlayerInput.cs +++ b/Barotrauma/BarotraumaShared/Source/PlayerInput.cs @@ -160,6 +160,16 @@ namespace Barotrauma } #endif + public void SetState() + { + hit = binding.IsHit(); + if (hit) hitQueue = true; + + held = binding.IsDown(); + if (held) heldQueue = true; + } +#endif + public bool Hit { get