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