From ec5b730b28f9661c0791eba89f5616f5c7a7609c Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 14 Oct 2022 16:39:41 +0300 Subject: [PATCH 1/4] Update bug_report.yml --- .github/ISSUE_TEMPLATE/bug_report.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 1896aea64..4c856cd8c 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -53,6 +53,7 @@ body: description: Which version of the game did the bug happen in? You can see the current version number in the bottom left corner of your screen in the main menu. options: - 0.19.11.0 + - 0.19.12.0 (Unstable) - Other validations: required: true From 35c6bd2526e5f857782bbbf547a5c5b30a02bcbc Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Mon, 17 Oct 2022 19:01:10 +0300 Subject: [PATCH 2/4] Update bug_report.yml --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 4c856cd8c..a8248d51d 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -53,7 +53,7 @@ body: description: Which version of the game did the bug happen in? You can see the current version number in the bottom left corner of your screen in the main menu. options: - 0.19.11.0 - - 0.19.12.0 (Unstable) + - 0.19.13.0 (Unstable) - Other validations: required: true From 6cddd03918191797ad23d8b75a3d7c0accd29c8c Mon Sep 17 00:00:00 2001 From: Regalis11 Date: Thu, 20 Oct 2022 17:05:24 +0300 Subject: [PATCH 3/4] v0.19.14.0 --- .../ClientSource/GUI/CrewManagement.cs | 2 +- .../ClientSource/GUI/Store.cs | 6 +- .../ClientSource/GUI/TabMenu.cs | 11 +- .../ClientSource/GUI/UpgradeStore.cs | 30 ++-- .../GameSession/GameModes/CampaignMode.cs | 5 +- .../Components/Machines/Deconstructor.cs | 2 + .../Items/Components/Machines/Sonar.cs | 2 +- .../ClientSource/Map/Map/Map.cs | 26 +-- .../ClientSource/Networking/ServerSettings.cs | 30 +++- .../ClientSource/Screens/CampaignUI.cs | 12 +- .../Screens/CharacterEditor/Wizard.cs | 13 +- .../ClientSource/Screens/NetLobbyScreen.cs | 6 +- .../ServerListScreen/ServerListScreen.cs | 17 +- .../ClientSource/Screens/SubEditorScreen.cs | 15 +- .../ClientSource/Settings/SettingsMenu.cs | 19 ++- .../StatusEffects/StatusEffect.cs | 2 + .../Steam/WorkshopMenu/Mutable/ItemList.cs | 3 +- .../Steam/WorkshopMenu/Mutable/PublishTab.cs | 3 +- .../BarotraumaClient/LinuxClient.csproj | 2 +- Barotrauma/BarotraumaClient/MacClient.csproj | 2 +- .../BarotraumaClient/WindowsClient.csproj | 2 +- .../BarotraumaServer/LinuxServer.csproj | 2 +- Barotrauma/BarotraumaServer/MacServer.csproj | 2 +- .../GameSession/GameModes/CampaignMode.cs | 5 +- .../GameModes/MultiPlayerCampaign.cs | 2 +- .../Items/Components/DockingPort.cs | 2 +- .../ServerSource/Networking/GameServer.cs | 54 ++++--- .../BarotraumaServer/WindowsServer.csproj | 2 +- .../AI/Objectives/AIObjectiveRepairItem.cs | 4 +- .../Characters/Animation/Ragdoll.cs | 8 +- .../SharedSource/Characters/Character.cs | 15 +- .../SharedSource/Characters/CharacterInfo.cs | 6 +- .../AbilityConditionHasAffliction.cs | 2 +- .../CharacterAbilityTandemFire.cs | 10 +- .../ContentManagement/ContentPath.cs | 2 +- .../SharedSource/DebugConsole.cs | 2 +- .../Events/EventActions/SpawnAction.cs | 2 +- .../SharedSource/Events/EventSet.cs | 4 +- .../GameSession/GameModes/CampaignMode.cs | 2 +- .../GameSession/UpgradeManager.cs | 24 +-- .../Items/Components/DockingPort.cs | 7 +- .../Items/Components/Holdable/Holdable.cs | 20 ++- .../Items/Components/Holdable/MeleeWeapon.cs | 2 +- .../Items/Components/Holdable/RepairTool.cs | 2 +- .../Components/Machines/Deconstructor.cs | 3 +- .../Items/Components/Machines/Reactor.cs | 12 +- .../SharedSource/Items/ItemPrefab.cs | 4 +- .../SharedSource/Map/Levels/Level.cs | 3 +- .../SharedSource/Map/Map/Location.cs | 12 +- .../SharedSource/Map/Map/LocationType.cs | 4 +- .../SharedSource/Map/Map/Map.cs | 40 ++++- .../SharedSource/NetStructBitField.cs | 31 +--- .../Networking/ChildServerRelay.cs | 5 + .../Networking/INetSerializableStruct.cs | 102 ++++++------ .../Primitives/Address/LidgrenAddress.cs | 19 +++ .../Primitives/Endpoint/LidgrenEndpoint.cs | 8 +- .../Networking/Primitives/Message/Message.cs | 153 ++++++++++-------- .../Primitives/NetworkPeerStructs.cs | 9 +- .../StatusEffects/StatusEffect.cs | 21 +-- .../SharedSource/Upgrades/UpgradePrefab.cs | 34 ++-- Barotrauma/BarotraumaShared/changelog.txt | 51 ++++++ .../INetSerializableStructTests.cs | 14 +- 62 files changed, 578 insertions(+), 338 deletions(-) diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/CrewManagement.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/CrewManagement.cs index b25b07ca4..85afac3c9 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/CrewManagement.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/CrewManagement.cs @@ -25,7 +25,7 @@ namespace Barotrauma private PlayerBalanceElement? playerBalanceElement; private List PendingHires => campaign.Map?.CurrentLocation?.HireManager?.PendingHires; - private bool HasPermission => campaignUI.Campaign.AllowedToManageCampaign(ClientPermissions.ManageHires); + private bool HasPermission => CampaignMode.AllowedToManageCampaign(ClientPermissions.ManageHires); private Point resolutionWhenCreated; diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/Store.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/Store.cs index eca7c4334..4f87042dd 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/Store.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/Store.cs @@ -139,10 +139,10 @@ namespace Barotrauma return tab switch { StoreTab.Buy => true, - StoreTab.Sell => campaignUI.Campaign.AllowedToManageCampaign(Networking.ClientPermissions.SellInventoryItems), - StoreTab.SellSub => campaignUI.Campaign.AllowedToManageCampaign(Networking.ClientPermissions.SellSubItems), + StoreTab.Sell => CampaignMode.AllowedToManageCampaign(Networking.ClientPermissions.SellInventoryItems), + StoreTab.SellSub => CampaignMode.AllowedToManageCampaign(Networking.ClientPermissions.SellSubItems), _ => false, - }; + }; } private void UpdatePermissions() diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs index 8a9d4e8c1..295818c7b 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs @@ -1867,10 +1867,13 @@ namespace Barotrauma GUITextBlock jobBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), nameLayout.RectTransform), job.Name, font: GUIStyle.SmallFont) { TextColor = job.Prefab.UIColor }; } - LocalizedString traitString = TextManager.AddPunctuation(':', TextManager.Get("PersonalityTrait"), info.PersonalityTrait.DisplayName); - Vector2 traitSize = GUIStyle.SmallFont.MeasureString(traitString); - GUITextBlock traitBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), traitString, font: GUIStyle.SmallFont); - traitBlock.RectTransform.NonScaledSize = traitSize.Pad(traitBlock.Padding).ToPoint(); + if (info.PersonalityTrait != null) + { + LocalizedString traitString = TextManager.AddPunctuation(':', TextManager.Get("PersonalityTrait"), info.PersonalityTrait.DisplayName); + Vector2 traitSize = GUIStyle.SmallFont.MeasureString(traitString); + GUITextBlock traitBlock = new GUITextBlock(new RectTransform(Vector2.One, nameLayout.RectTransform), traitString, font: GUIStyle.SmallFont); + traitBlock.RectTransform.NonScaledSize = traitSize.Pad(traitBlock.Padding).ToPoint(); + } IEnumerable talentsOutsideTree = info.GetUnlockedTalentsOutsideTree().Select(e => TalentPrefab.TalentPrefabs.Find(c => c.Identifier == e)); if (talentsOutsideTree.Count() > 0) diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/UpgradeStore.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/UpgradeStore.cs index 08a186081..0a78a8663 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/UpgradeStore.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/UpgradeStore.cs @@ -847,7 +847,7 @@ namespace Barotrauma foreach (UpgradePrefab prefab in prefabs) { - if (prefab.MaxLevel is 0) { continue; } + if (prefab.GetMaxLevelForCurrentSub() == 0) { continue; } CreateUpgradeEntry(prefab, category, parent.Content, submarine, entitiesOnSub); } } @@ -1080,7 +1080,7 @@ namespace Barotrauma public static GUIFrame CreateUpgradeFrame(UpgradePrefab prefab, UpgradeCategory category, CampaignMode campaign, RectTransform rectTransform, bool addBuyButton = true) { - int price = prefab.Price.GetBuyprice(campaign.UpgradeManager.GetUpgradeLevel(prefab, category), campaign.Map?.CurrentLocation); + int price = prefab.Price.GetBuyPrice(campaign.UpgradeManager.GetUpgradeLevel(prefab, category), campaign.Map?.CurrentLocation); return CreateUpgradeEntry(rectTransform, prefab.Sprite, prefab.Name, prefab.Description, price, new CategoryData(category, prefab), addBuyButton, upgradePrefab: prefab, currentLevel: campaign.UpgradeManager.GetUpgradeLevel(prefab, category)); } @@ -1177,11 +1177,12 @@ namespace Barotrauma private static void UpdateUpgradePercentageText(GUITextBlock text, UpgradePrefab upgradePrefab, int currentLevel) { - float nextIncrease = upgradePrefab.IncreaseOnTooltip * (Math.Min(currentLevel + 1, upgradePrefab.MaxLevel)); + int maxLevel = upgradePrefab.GetMaxLevelForCurrentSub(); + float nextIncrease = upgradePrefab.IncreaseOnTooltip * Math.Min(currentLevel + 1, maxLevel); if (nextIncrease != 0f) { text.Text = $"{Math.Round(nextIncrease, 1)} %"; - if (currentLevel == upgradePrefab.MaxLevel) + if (currentLevel == maxLevel) { text.TextColor = Color.Gray; } @@ -1221,7 +1222,7 @@ namespace Barotrauma { LocalizedString promptBody = TextManager.GetWithVariables("Upgrades.PurchasePromptBody", ("[upgradename]", prefab.Name), - ("[amount]", prefab.Price.GetBuyprice(Campaign.UpgradeManager.GetUpgradeLevel(prefab, category), Campaign.Map?.CurrentLocation).ToString())); + ("[amount]", prefab.Price.GetBuyPrice(Campaign.UpgradeManager.GetUpgradeLevel(prefab, category), Campaign.Map?.CurrentLocation).ToString())); currectConfirmation = EventEditorScreen.AskForConfirmation(TextManager.Get("Upgrades.PurchasePromptTitle"), promptBody, () => { if (GameMain.NetworkMember != null) @@ -1617,14 +1618,15 @@ namespace Barotrauma { int currentLevel = campaign.UpgradeManager.GetUpgradeLevel(prefab, category); - LocalizedString progressText = TextManager.GetWithVariables("upgrades.progressformat", ("[level]", currentLevel.ToString()), ("[maxlevel]", prefab.MaxLevel.ToString())); + int maxLevel = prefab.GetMaxLevelForCurrentSub(); + LocalizedString progressText = TextManager.GetWithVariables("upgrades.progressformat", ("[level]", currentLevel.ToString()), ("[maxlevel]", maxLevel.ToString())); if (prefabFrame.FindChild("progressbar", true) is { } progressParent) { GUIProgressBar bar = progressParent.GetChild(); if (bar != null) { - bar.BarSize = currentLevel / (float) prefab.MaxLevel; - bar.Color = currentLevel >= prefab.MaxLevel ? GUIStyle.Green : GUIStyle.Orange; + bar.BarSize = currentLevel / (float)maxLevel; + bar.Color = currentLevel >= maxLevel ? GUIStyle.Green : GUIStyle.Orange; } GUITextBlock block = progressParent.GetChild(); @@ -1637,12 +1639,12 @@ namespace Barotrauma GUITextBlock priceLabel = textBlocks[0]; priceLabel.Visible = true; - int price = prefab.Price.GetBuyprice(campaign.UpgradeManager.GetUpgradeLevel(prefab, category), campaign.Map?.CurrentLocation); + int price = prefab.Price.GetBuyPrice(campaign.UpgradeManager.GetUpgradeLevel(prefab, category), campaign.Map?.CurrentLocation); if (priceLabel != null && !WaitForServerUpdate) { priceLabel.Text = TextManager.FormatCurrency(price); - if (currentLevel >= prefab.MaxLevel) + if (currentLevel >= maxLevel) { priceLabel.Text = TextManager.Get("Upgrade.MaxedUpgrade"); } @@ -1651,7 +1653,7 @@ namespace Barotrauma GUIButton button = buttonParent.GetChild(); if (button != null) { - button.Enabled = currentLevel < prefab.MaxLevel; + button.Enabled = currentLevel < maxLevel; if (WaitForServerUpdate || campaign.GetBalance() < price) { button.Enabled = false; @@ -1697,13 +1699,14 @@ namespace Barotrauma foreach (GUIComponent component in indicators.Children) { - if (!(component is GUIImage image)) { continue; } + if (component is not GUIImage image) { continue; } foreach (UpgradePrefab prefab in prefabs) { if (component.UserData != prefab) { continue; } - if (prefab.MaxLevel is 0) + int maxLevel = prefab.GetMaxLevelForCurrentSub(); + if (maxLevel == 0) { component.Visible = false; continue; @@ -1715,7 +1718,6 @@ namespace Barotrauma GUIComponentStyle onStyle = styles["upgradeindicatoron".ToIdentifier()]; GUIComponentStyle dimStyle = styles["upgradeindicatordim".ToIdentifier()]; GUIComponentStyle offStyle = styles["upgradeindicatoroff".ToIdentifier()]; - int maxLevel = prefab.MaxLevel; if (maxLevel == 0) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/CampaignMode.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/CampaignMode.cs index 54d942d3b..19a52394e 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/CampaignMode.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/CampaignMode.cs @@ -89,7 +89,7 @@ namespace Barotrauma /// /// There is a server-side implementation of the method in /// - public bool AllowedToManageCampaign(ClientPermissions permissions) + public static bool AllowedToManageCampaign(ClientPermissions permissions) { //allow managing the round if the client has permissions, is the owner, the only client in the server, //or if no-one has management permissions @@ -99,7 +99,8 @@ namespace Barotrauma GameMain.Client.HasPermission(ClientPermissions.ManageCampaign) || GameMain.Client.ConnectedClients.Count == 1 || GameMain.Client.IsServerOwner || - GameMain.Client.ConnectedClients.None(c => c.InGame && (c.IsOwner || c.HasPermission(permissions))); + //allow managing if no-one with permissions is alive + GameMain.Client.ConnectedClients.None(c => c.InGame && c.Character is { IsIncapacitated: false, IsDead: false } && (c.IsOwner || c.HasPermission(permissions))); } public static bool AllowedToManageWallets() diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Deconstructor.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Deconstructor.cs index dd3b30b66..71cfdb1b4 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Deconstructor.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Deconstructor.cs @@ -265,6 +265,8 @@ namespace Barotrauma.Items.Components foreach (DeconstructItem deconstructItem in it.Prefab.DeconstructItems) { if (!deconstructItem.IsValidDeconstructor(item)) { continue; } + float percentageHealth = it.Condition / it.MaxCondition; + if (percentageHealth < deconstructItem.MinCondition || percentageHealth > deconstructItem.MaxCondition) { continue; } RegisterItem(deconstructItem.ItemIdentifier, deconstructItem.Amount); } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Sonar.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Sonar.cs index 188c75cf9..b6ff975de 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Sonar.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Machines/Sonar.cs @@ -1028,7 +1028,7 @@ namespace Barotrauma.Items.Components { foreach (var c in MineralClusters) { - var unobtainedMinerals = c.resources.Where(i => i != null && i.GetRootInventoryOwner() == i); + var unobtainedMinerals = c.resources.Where(i => i != null && i.GetComponent() is { Attached: true }); if (unobtainedMinerals.None()) { continue; } if (!CheckResourceMarkerVisibility(c.center, transducerCenter)) { continue; } var i = unobtainedMinerals.FirstOrDefault(); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/Map/Map.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/Map/Map.cs index 278e3a36c..c32f82187 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/Map/Map.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/Map/Map.cs @@ -162,23 +162,27 @@ namespace Barotrauma RemoveFogOfWar(StartLocation); - GenerateLocationConnectionVisuals(); + GenerateAllLocationConnectionVisuals(); } - partial void GenerateLocationConnectionVisuals() + partial void GenerateAllLocationConnectionVisuals() { foreach (LocationConnection connection in Connections) { - Vector2 connectionStart = connection.Locations[0].MapPosition; - Vector2 connectionEnd = connection.Locations[1].MapPosition; - float connectionLength = Vector2.Distance(connectionStart, connectionEnd); - int iterations = Math.Min((int)Math.Sqrt(connectionLength * generationParams.ConnectionIndicatorIterationMultiplier), 5); - connection.CrackSegments.Clear(); - connection.CrackSegments.AddRange(MathUtils.GenerateJaggedLine( - connectionStart, connectionEnd, - iterations, connectionLength * generationParams.ConnectionIndicatorDisplacementMultiplier)); + GenerateLocationConnectionVisuals(connection); } } + partial void GenerateLocationConnectionVisuals(LocationConnection connection) + { + Vector2 connectionStart = connection.Locations[0].MapPosition; + Vector2 connectionEnd = connection.Locations[1].MapPosition; + float connectionLength = Vector2.Distance(connectionStart, connectionEnd); + int iterations = Math.Min((int)Math.Sqrt(connectionLength * generationParams.ConnectionIndicatorIterationMultiplier), 5); + connection.CrackSegments.Clear(); + connection.CrackSegments.AddRange(MathUtils.GenerateJaggedLine( + connectionStart, connectionEnd, + iterations, connectionLength * generationParams.ConnectionIndicatorDisplacementMultiplier)); + } private void LocationChanged(Location prevLocation, Location newLocation) { @@ -414,7 +418,7 @@ namespace Barotrauma new GUIMessageBox(string.Empty, TextManager.Get("LockedPathTooltip")); } //clients aren't allowed to select the location without a permission - else if ((GameMain.GameSession?.GameMode as CampaignMode)?.AllowedToManageCampaign(Networking.ClientPermissions.ManageMap) ?? false) + else if (CampaignMode.AllowedToManageCampaign(Networking.ClientPermissions.ManageMap)) { connectionHighlightState = 0.0f; SelectedConnection = connection; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/ServerSettings.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/ServerSettings.cs index 10829d4fb..b6c1b2583 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/ServerSettings.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/ServerSettings.cs @@ -702,10 +702,30 @@ namespace Barotrauma.Networking { Enabled = !GameMain.NetworkMember.GameStarted }; - var cargoFrame = new GUIListBox(new RectTransform(new Vector2(0.6f, 0.7f), settingsTabs[(int)SettingsTab.Rounds].RectTransform, Anchor.BottomRight, Pivot.BottomLeft)) + + var cargoFrame = new GUIFrame(new RectTransform(new Vector2(0.6f, 0.7f), settingsTabs[(int)SettingsTab.Rounds].RectTransform, Anchor.BottomRight, Pivot.BottomLeft)) { Visible = false }; + var cargoContent = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), cargoFrame.RectTransform, Anchor.Center)) + { + Stretch = true + }; + + var filterText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), cargoContent.RectTransform), TextManager.Get("serverlog.filter"), font: GUIStyle.SubHeadingFont); + var entityFilterBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), filterText.RectTransform, Anchor.CenterRight), font: GUIStyle.Font, createClearButton: true); + filterText.RectTransform.MinSize = new Point(0, entityFilterBox.RectTransform.MinSize.Y); + var cargoList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.8f), cargoContent.RectTransform)); + entityFilterBox.OnTextChanged += (textBox, text) => + { + foreach (var child in cargoList.Content.Children) + { + if (child.UserData is not ItemPrefab itemPrefab) { continue; } + child.Visible = string.IsNullOrEmpty(text) || itemPrefab.Name.Contains(text, StringComparison.OrdinalIgnoreCase); + } + return true; + }; + cargoButton.UserData = cargoFrame; cargoButton.OnClicked = (button, obj) => { @@ -721,7 +741,7 @@ namespace Barotrauma.Networking GUITextBlock.AutoScaleAndNormalize(buttonHolder.Children.Select(c => ((GUIButton)c).TextBlock)); - foreach (ItemPrefab ip in ItemPrefab.Prefabs) + foreach (ItemPrefab ip in ItemPrefab.Prefabs.OrderBy(ip => ip.Name)) { if (ip.AllowAsExtraCargo.HasValue) { @@ -732,10 +752,10 @@ namespace Barotrauma.Networking if (!ip.CanBeBought) { continue; } } - var itemFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.15f), cargoFrame.Content.RectTransform) { MinSize = new Point(0, 30) }, isHorizontal: true) + var itemFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.15f), cargoList.Content.RectTransform) { MinSize = new Point(0, 30) }, isHorizontal: true) { Stretch = true, - UserData = cargoFrame, + UserData = ip, RelativeSpacing = 0.05f }; @@ -778,7 +798,7 @@ namespace Barotrauma.Networking numberInput.IntValue = ExtraCargo.ContainsKey(ip) ? ExtraCargo[ip] : 0; CoroutineManager.Invoke(() => { - foreach (var child in cargoFrame.Content.GetAllChildren()) + foreach (var child in cargoList.Content.GetAllChildren()) { if (child.GetChild() is GUINumberInput otherNumberInput) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignUI.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignUI.cs index a405d730e..2b5510ab7 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignUI.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignUI.cs @@ -167,7 +167,7 @@ namespace Barotrauma foreach (GUITickBox tickBox in missionTickBoxes) { bool disable = hasMaxMissions && !tickBox.Selected; - tickBox.Enabled = Campaign.AllowedToManageCampaign(ClientPermissions.ManageMap) && !disable; + tickBox.Enabled = CampaignMode.AllowedToManageCampaign(ClientPermissions.ManageMap) && !disable; tickBox.Box.DisabledColor = disable ? tickBox.Box.Color * 0.5f : tickBox.Box.Color * 0.8f; foreach (GUIComponent child in tickBox.Parent.Parent.Children) { @@ -315,7 +315,7 @@ namespace Barotrauma if (GUI.MouseOn == tickBox) { return false; } if (tickBox != null) { - if (Campaign.AllowedToManageCampaign(ClientPermissions.ManageMap) && tickBox.Enabled) + if (CampaignMode.AllowedToManageCampaign(ClientPermissions.ManageMap) && tickBox.Enabled) { tickBox.Selected = !tickBox.Selected; } @@ -356,10 +356,10 @@ namespace Barotrauma }; tickBox.RectTransform.MinSize = new Point(tickBox.Rect.Height, 0); tickBox.RectTransform.IsFixedSize = true; - tickBox.Enabled = Campaign.AllowedToManageCampaign(ClientPermissions.ManageMap); + tickBox.Enabled = CampaignMode.AllowedToManageCampaign(ClientPermissions.ManageMap); tickBox.OnSelected += (GUITickBox tb) => { - if (!Campaign.AllowedToManageCampaign(Networking.ClientPermissions.ManageMap)) { return false; } + if (!CampaignMode.AllowedToManageCampaign(Networking.ClientPermissions.ManageMap)) { return false; } if (tb.Selected) { @@ -379,7 +379,7 @@ namespace Barotrauma UpdateMaxMissions(connection.OtherLocation(currentDisplayLocation)); if ((Campaign is MultiPlayerCampaign multiPlayerCampaign) && !multiPlayerCampaign.SuppressStateSending && - Campaign.AllowedToManageCampaign(Networking.ClientPermissions.ManageMap)) + CampaignMode.AllowedToManageCampaign(Networking.ClientPermissions.ManageMap)) { GameMain.Client?.SendCampaignState(); } @@ -500,7 +500,7 @@ namespace Barotrauma return true; }, Enabled = true, - Visible = Campaign.AllowedToManageCampaign(ClientPermissions.ManageMap) + Visible = CampaignMode.AllowedToManageCampaign(ClientPermissions.ManageMap) }; buttonArea.RectTransform.MinSize = new Point(0, StartButton.RectTransform.MinSize.Y); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/Wizard.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/Wizard.cs index 2f8f73962..642648f1b 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/Wizard.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/Wizard.cs @@ -351,7 +351,7 @@ namespace Barotrauma.CharacterEditor { if (string.IsNullOrEmpty(contentPackageNameElement.Text)) { - contentPackageNameElement.Flash(); + contentPackageNameElement.Flash(useRectangleFlash: true); return false; } if (ContentPackageManager.AllPackages.Any(cp => cp.Name.ToLower() == contentPackageNameElement.Text.ToLower())) @@ -405,7 +405,7 @@ namespace Barotrauma.CharacterEditor { if (ContentPackage == null) { - contentPackageDropDown.Flash(); + contentPackageDropDown.Flash(useRectangleFlash: true); return false; } @@ -417,7 +417,7 @@ namespace Barotrauma.CharacterEditor if (!File.Exists(evaluatedTexturePath)) { GUI.AddMessage(GetCharacterEditorTranslation("TextureDoesNotExist"), GUIStyle.Red); - texturePathElement.Flash(GUIStyle.Red); + texturePathElement.Flash(useRectangleFlash: true); return false; } } @@ -425,7 +425,7 @@ namespace Barotrauma.CharacterEditor if (!path.EndsWith(".png", StringComparison.OrdinalIgnoreCase)) { GUI.AddMessage(TextManager.Get("WrongFileType"), GUIStyle.Red); - texturePathElement.Flash(GUIStyle.Red); + texturePathElement.Flash(useRectangleFlash: true); return false; } if (IsCopy) @@ -486,7 +486,8 @@ namespace Barotrauma.CharacterEditor { PlaySoundOnSelect = true, }; - var removeLimbButton = new GUIButton(new RectTransform(new Vector2(0.05f, 1.0f), limbEditLayout.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUIMinusButton") + var limbButtonSize = Vector2.One * 0.8f; + var removeLimbButton = new GUIButton(new RectTransform(limbButtonSize, limbEditLayout.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUIMinusButton") { OnClicked = (b, d) => { @@ -497,7 +498,7 @@ namespace Barotrauma.CharacterEditor return true; } }; - var addLimbButton = new GUIButton(new RectTransform(new Vector2(0.05f, 1.0f), limbEditLayout.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUIPlusButton") + var addLimbButton = new GUIButton(new RectTransform(limbButtonSize, limbEditLayout.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUIPlusButton") { OnClicked = (b, d) => { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs index 9471d8128..6d966c50e 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/NetLobbyScreen.cs @@ -1817,7 +1817,11 @@ namespace Barotrauma subList = dropDown.ListBox.Content; } - var frame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.15f), subList.RectTransform) { MinSize = new Point(0, 25) }, + var frame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.1f), subList.RectTransform) + { + //enough space for 2 lines (price and class) + some padding + MinSize = new Point(0, (int)(GUIStyle.SmallFont.LineHeight * 2.3f)) + }, style: "ListBoxElement") { ToolTip = sub.Description, diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/ServerListScreen/ServerListScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/ServerListScreen/ServerListScreen.cs index 8e54407a4..dcb6ab842 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/ServerListScreen/ServerListScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/ServerListScreen/ServerListScreen.cs @@ -7,6 +7,8 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Net; +using System.Net.Sockets; using System.Xml.Linq; namespace Barotrauma @@ -953,8 +955,19 @@ namespace Barotrauma okButton.Enabled = false; okButton.OnClicked = (btn, userdata) => { - if (!Endpoint.Parse(endpointBox.Text).TryUnwrap(out var endpoint)) { return false; } - JoinServer(endpoint, ""); + if (Endpoint.Parse(endpointBox.Text).TryUnwrap(out var endpoint)) + { + JoinServer(endpoint, ""); + } + else if (LidgrenEndpoint.ParseFromWithHostNameCheck(endpointBox.Text, tryParseHostName: true).TryUnwrap(out var lidgrenEndpoint)) + { + JoinServer(lidgrenEndpoint, ""); + } + else + { + new GUIMessageBox(TextManager.Get("error"), TextManager.GetWithVariable("invalidipaddress", "[serverip]:[port]", endpointBox.Text)); + endpointBox.Flash(); + } msgBox.Close(); return false; }; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs index 0952422e7..aa6c37369 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs @@ -1920,9 +1920,15 @@ namespace Barotrauma { filePath = $"{ContentPath.ModDirStr}/{filePath[packageDir.Length..]}"; } - if (!modProject.Files.Any(f => f.Type == subFileType && - f.Path == filePath)) + if (!modProject.Files.Any(f => f.Type == subFileType && f.Path == filePath)) { + //check if there's a file with the same name but different filename case + var matchingFile = modProject.Files.FirstOrDefault(f => f.Type == subFileType && filePath.CleanUpPath().Equals(f.Path.CleanUpPath(), StringComparison.OrdinalIgnoreCase)); + if (matchingFile != null) + { + File.Delete(matchingFile.Path.Replace(ContentPath.ModDirStr, packageDir)); + modProject.RemoveFile(matchingFile); + } var newFile = ModProject.File.FromPath(filePath, subFileType); modProject.AddFile(newFile); } @@ -2479,7 +2485,7 @@ namespace Barotrauma new GUINumberInput(new RectTransform(new Vector2(0.4f, 1.0f), tierGroup.RectTransform), NumberType.Int) { - IntValue = SubmarineInfo.GetDefaultTier(MainSub.Info.Price), + IntValue = MainSub.Info.Tier, MinValueInt = 1, MaxValueInt = 3, OnValueChanged = (numberInput) => @@ -2821,6 +2827,7 @@ namespace Barotrauma OnClicked = (button, o) => { var requiredPackages = MapEntity.mapEntityList.Select(e => e.Prefab.ContentPackage) + .Where(cp => cp != null) .Distinct().OfType().Select(p => p.Name).ToHashSet(); var tickboxes = requiredContentPackList.Content.Children.OfType().ToArray(); tickboxes.ForEach(tb => tb.Selected = requiredPackages.Contains(tb.UserData as string ?? "")); @@ -2919,7 +2926,7 @@ namespace Barotrauma subTypeDropdown.SelectItem(MainSub.Info.Type); - if (quickSave) { SaveSub(null); } + if (quickSave) { SaveSub(packageToSaveInList.SelectedData as ContentPackage); } } private void CreateSaveAssemblyScreen() diff --git a/Barotrauma/BarotraumaClient/ClientSource/Settings/SettingsMenu.cs b/Barotrauma/BarotraumaClient/ClientSource/Settings/SettingsMenu.cs index 8e2172550..65a6e87bc 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Settings/SettingsMenu.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Settings/SettingsMenu.cs @@ -785,13 +785,7 @@ namespace Barotrauma { OnClicked = (btn, obj) => { - GameSettings.SetCurrentConfig(unsavedConfig); - if (WorkshopMenu is MutableWorkshopMenu mutableWorkshopMenu && - mutableWorkshopMenu.CurrentTab == MutableWorkshopMenu.Tab.InstalledMods) - { - mutableWorkshopMenu.Apply(); - } - GameSettings.SaveCurrentConfig(); + ApplyInstalledModChanges(); mainFrame.Flash(color: GUIStyle.Green); return false; }, @@ -804,6 +798,17 @@ namespace Barotrauma }; } + public void ApplyInstalledModChanges() + { + GameSettings.SetCurrentConfig(unsavedConfig); + if (WorkshopMenu is MutableWorkshopMenu mutableWorkshopMenu && + mutableWorkshopMenu.CurrentTab == MutableWorkshopMenu.Tab.InstalledMods) + { + mutableWorkshopMenu.Apply(); + } + GameSettings.SaveCurrentConfig(); + } + public void Close() { if (GameMain.Client is null || GameSettings.CurrentConfig.Audio.VoiceSetting == VoiceMode.Disabled) diff --git a/Barotrauma/BarotraumaClient/ClientSource/StatusEffects/StatusEffect.cs b/Barotrauma/BarotraumaClient/ClientSource/StatusEffects/StatusEffect.cs index 82f0bc176..1f59cf11e 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/StatusEffects/StatusEffect.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/StatusEffects/StatusEffect.cs @@ -96,6 +96,8 @@ namespace Barotrauma { angle = targetLimb.body.Rotation + ((targetLimb.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi); particleRotation = -targetLimb.body.Rotation; + float offset = targetLimb.Params.GetSpriteOrientation() - MathHelper.PiOver2; + particleRotation += offset; if (targetLimb.body.Dir < 0.0f) { particleRotation += MathHelper.Pi; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/ItemList.cs b/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/ItemList.cs index 17a677d57..62e930476 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/ItemList.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/ItemList.cs @@ -598,13 +598,14 @@ namespace Barotrauma.Steam bool reinstallAction(GUIButton button, object o) { + SettingsMenu.Instance?.ApplyInstalledModChanges(); int prevIndex = ContentPackageManager.EnabledPackages.Regular.IndexOf(contentPackage); TaskPool.AddIfNotFound($"Reinstall{workshopItem.Id}", SteamManager.Workshop.Reinstall(workshopItem), t => { ContentPackageManager.WorkshopPackages.Refresh(); ContentPackageManager.EnabledPackages.RefreshUpdatedMods(); - if (SettingsMenu.Instance?.WorkshopMenu is MutableWorkshopMenu mutableWorkshopMenu) + if (SettingsMenu.Instance?.WorkshopMenu is MutableWorkshopMenu mutableWorkshopMenu && !mutableWorkshopMenu.ViewingItemDetails) { mutableWorkshopMenu.PopulateInstalledModLists(forceRefreshEnabled: true); } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/PublishTab.cs b/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/PublishTab.cs index 61d849dbe..09bdaafe2 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/PublishTab.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/PublishTab.cs @@ -543,7 +543,8 @@ namespace Barotrauma.Steam var localModProject = new ModProject(localPackage) { - UgcId = Option.Some(new SteamWorkshopId(resultId)) + UgcId = Option.Some(new SteamWorkshopId(resultId)), + ModVersion = modVersion }; localModProject.DiscardHashAndInstallTime(); localModProject.Save(localPackage.Path); diff --git a/Barotrauma/BarotraumaClient/LinuxClient.csproj b/Barotrauma/BarotraumaClient/LinuxClient.csproj index 10bc6b9b4..70941d22d 100644 --- a/Barotrauma/BarotraumaClient/LinuxClient.csproj +++ b/Barotrauma/BarotraumaClient/LinuxClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.19.11.0 + 0.19.14.0 Copyright © FakeFish 2018-2022 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/MacClient.csproj b/Barotrauma/BarotraumaClient/MacClient.csproj index 7fad64083..f02309b56 100644 --- a/Barotrauma/BarotraumaClient/MacClient.csproj +++ b/Barotrauma/BarotraumaClient/MacClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.19.11.0 + 0.19.14.0 Copyright © FakeFish 2018-2022 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/WindowsClient.csproj b/Barotrauma/BarotraumaClient/WindowsClient.csproj index c88fd0394..7f0257b84 100644 --- a/Barotrauma/BarotraumaClient/WindowsClient.csproj +++ b/Barotrauma/BarotraumaClient/WindowsClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.19.11.0 + 0.19.14.0 Copyright © FakeFish 2018-2022 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaServer/LinuxServer.csproj b/Barotrauma/BarotraumaServer/LinuxServer.csproj index 91c01c717..efd06e13b 100644 --- a/Barotrauma/BarotraumaServer/LinuxServer.csproj +++ b/Barotrauma/BarotraumaServer/LinuxServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.19.11.0 + 0.19.14.0 Copyright © FakeFish 2018-2022 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/MacServer.csproj b/Barotrauma/BarotraumaServer/MacServer.csproj index 9ddb35313..2c9ca2ecf 100644 --- a/Barotrauma/BarotraumaServer/MacServer.csproj +++ b/Barotrauma/BarotraumaServer/MacServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.19.11.0 + 0.19.14.0 Copyright © FakeFish 2018-2022 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/CampaignMode.cs b/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/CampaignMode.cs index 9360c71d2..52ef55b2f 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/CampaignMode.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/CampaignMode.cs @@ -16,7 +16,7 @@ namespace Barotrauma /// /// There is a client-side implementation of the method in /// - public bool AllowedToManageCampaign(Client client, ClientPermissions permissions) + public static bool AllowedToManageCampaign(Client client, ClientPermissions permissions) { //allow managing the campaign if the client has permissions, is the owner, or the only client in the server, //or if no-one has management permissions @@ -25,7 +25,8 @@ namespace Barotrauma client.HasPermission(ClientPermissions.ManageCampaign) || GameMain.Server.ConnectedClients.Count == 1 || IsOwner(client) || - GameMain.Server.ConnectedClients.None(c => c.InGame && (IsOwner(c) || c.HasPermission(permissions))); + //allow managing if no-one with permissions is alive + GameMain.Server.ConnectedClients.None(c => c.InGame && c.Character is { IsIncapacitated: false, IsDead: false } && (IsOwner(c) || c.HasPermission(permissions))); } public bool AllowedToManageWallets(Client client) diff --git a/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs b/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs index 502f148fc..12d7a7af3 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs @@ -1019,7 +1019,7 @@ namespace Barotrauma UpgradeManager.PurchaseUpgrade(prefab, category, client: sender); // unstable logging - int price = prefab.Price.GetBuyprice(UpgradeManager.GetUpgradeLevel(prefab, category), Map?.CurrentLocation); + int price = prefab.Price.GetBuyPrice(UpgradeManager.GetUpgradeLevel(prefab, category), Map?.CurrentLocation); int level = UpgradeManager.GetUpgradeLevel(prefab, category); GameServer.Log($"SERVER: Purchased level {level} {category.Identifier}.{prefab.Identifier} for {price}", ServerLog.MessageType.ServerMessage); } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Items/Components/DockingPort.cs b/Barotrauma/BarotraumaServer/ServerSource/Items/Components/DockingPort.cs index b5349e891..c73a10dce 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Items/Components/DockingPort.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Items/Components/DockingPort.cs @@ -17,7 +17,7 @@ namespace Barotrauma.Items.Components { var allowOutpostAutoDocking = (AllowOutpostAutoDocking)msg.ReadByte(); if (outpostAutoDockingPromptShown && - (GameMain.GameSession?.Campaign?.AllowedToManageCampaign(c, ClientPermissions.ManageMap) ?? false)) + CampaignMode.AllowedToManageCampaign(c, ClientPermissions.ManageMap)) { this.allowOutpostAutoDocking = allowOutpostAutoDocking; } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs index 370627ddb..f3e37ce04 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs @@ -486,9 +486,18 @@ namespace Barotrauma.Networking // -> something wen't wrong during startup, re-enable start button and reset AutoRestartTimer if (startGameCoroutine != null && !CoroutineManager.IsCoroutineRunning(startGameCoroutine)) { - if (ServerSettings.AutoRestart) ServerSettings.AutoRestartTimer = Math.Max(ServerSettings.AutoRestartInterval, 5.0f); - //GameMain.NetLobbyScreen.StartButtonEnabled = true; + if (ServerSettings.AutoRestart) { ServerSettings.AutoRestartTimer = Math.Max(ServerSettings.AutoRestartInterval, 5.0f); } + if (startGameCoroutine.Exception != null && OwnerConnection != null) + { + SendConsoleMessage( + startGameCoroutine.Exception.Message + '\n' + + (startGameCoroutine.Exception.StackTrace?.CleanupStackTrace() ?? "null"), + connectedClients.Find(c => c.Connection == OwnerConnection), + Color.Red); + } + + EndGame(); GameMain.NetLobbyScreen.LastUpdateID++; startGameCoroutine = null; @@ -1377,9 +1386,9 @@ namespace Barotrauma.Networking bool end = inc.ReadBoolean(); if (end) { - if (mpCampaign == null || - mpCampaign.AllowedToManageCampaign(sender, ClientPermissions.ManageRound) || - mpCampaign.AllowedToManageCampaign(sender, ClientPermissions.ManageCampaign)) + if (mpCampaign == null || + CampaignMode.AllowedToManageCampaign(sender, ClientPermissions.ManageRound) || + CampaignMode.AllowedToManageCampaign(sender, ClientPermissions.ManageCampaign)) { bool save = inc.ReadBoolean(); if (GameStarted) @@ -1409,7 +1418,7 @@ namespace Barotrauma.Networking SendDirectChatMessage("Cannot continue the campaign from the previous save (round already running).", sender, ChatMessageType.Error); break; } - else if (mpCampaign.AllowedToManageCampaign(sender, ClientPermissions.ManageCampaign) || mpCampaign.AllowedToManageCampaign(sender, ClientPermissions.ManageMap)) + else if (CampaignMode.AllowedToManageCampaign(sender, ClientPermissions.ManageCampaign) || CampaignMode.AllowedToManageCampaign(sender, ClientPermissions.ManageMap)) { MultiPlayerCampaign.LoadCampaign(GameMain.GameSession.SavePath); } @@ -1420,7 +1429,7 @@ namespace Barotrauma.Networking Log("Client \"" + ClientLogName(sender) + "\" started the round.", ServerLog.MessageType.ServerMessage); StartGame(); } - else if (mpCampaign != null && (mpCampaign.AllowedToManageCampaign(sender, ClientPermissions.ManageCampaign) || mpCampaign.AllowedToManageCampaign(sender, ClientPermissions.ManageMap))) + else if (mpCampaign != null && (CampaignMode.AllowedToManageCampaign(sender, ClientPermissions.ManageCampaign) || CampaignMode.AllowedToManageCampaign(sender, ClientPermissions.ManageMap))) { var availableTransition = mpCampaign.GetAvailableTransition(out _, out _); //don't force location if we've teleported @@ -1991,7 +2000,7 @@ namespace Barotrauma.Networking //and assume the message was received, so we don't have to keep resending //these large initial messages until the client acknowledges receiving them - c.LastRecvLobbyUpdate++; + c.LastRecvLobbyUpdate = GameMain.NetLobbyScreen.LastUpdateID; } else @@ -2010,7 +2019,7 @@ namespace Barotrauma.Networking c.ChatMsgQueue.RemoveAll(cMsg => !NetIdUtils.IdMoreRecent(cMsg.NetStateID, c.LastRecvChatMsgID)); for (int i = 0; i < c.ChatMsgQueue.Count && i < ChatMessage.MaxMessagesPerPacket; i++) { - if (outmsg.LengthBytes + c.ChatMsgQueue[i].EstimateLengthBytesServer(c) > MsgConstants.MTU - 5) + if (outmsg.LengthBytes + c.ChatMsgQueue[i].EstimateLengthBytesServer(c) > MsgConstants.MTU - 5 && i > 0) { //not enough room in this packet return; @@ -2589,26 +2598,24 @@ namespace Barotrauma.Networking public void EndGame(CampaignMode.TransitionType transitionType = CampaignMode.TransitionType.None, bool wasSaved = false) { - if (!GameStarted) + if (GameStarted) { - return; - } + if (GameSettings.CurrentConfig.VerboseLogging) + { + Log("Ending the round...\n" + Environment.StackTrace.CleanupStackTrace(), ServerLog.MessageType.ServerMessage); - if (GameSettings.CurrentConfig.VerboseLogging) - { - Log("Ending the round...\n" + Environment.StackTrace.CleanupStackTrace(), ServerLog.MessageType.ServerMessage); - - } - else - { - Log("Ending the round...", ServerLog.MessageType.ServerMessage); + } + else + { + Log("Ending the round...", ServerLog.MessageType.ServerMessage); + } } string endMessage = TextManager.FormatServerMessage("RoundSummaryRoundHasEnded"); var traitorResults = TraitorManager?.GetEndResults() ?? new List(); List missions = GameMain.GameSession.Missions.ToList(); - if (GameMain.GameSession.IsRunning) + if (GameMain.GameSession is { IsRunning: true }) { GameMain.GameSession.EndRound(endMessage, traitorResults); } @@ -2634,7 +2641,10 @@ namespace Barotrauma.Networking c.PositionUpdateLastSent.Clear(); } - KarmaManager.OnRoundEnded(); + if (GameStarted) + { + KarmaManager.OnRoundEnded(); + } RespawnManager = null; GameStarted = false; diff --git a/Barotrauma/BarotraumaServer/WindowsServer.csproj b/Barotrauma/BarotraumaServer/WindowsServer.csproj index 4b9035163..55a7ace33 100644 --- a/Barotrauma/BarotraumaServer/WindowsServer.csproj +++ b/Barotrauma/BarotraumaServer/WindowsServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.19.11.0 + 0.19.14.0 Copyright © FakeFish 2018-2022 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItem.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItem.cs index 78fc1a261..e8b5dea26 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItem.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItem.cs @@ -186,8 +186,8 @@ namespace Barotrauma { if (character.SelectedItem != Item) { - if (Item.TryInteract(character, ignoreRequiredItems: true, forceSelectKey: true) || - Item.TryInteract(character, ignoreRequiredItems: true, forceUseKey: true)) + if (Item.TryInteract(character, ignoreRequiredItems: true, forceUseKey: true) || + Item.TryInteract(character, ignoreRequiredItems: true, forceSelectKey: true)) { character.SelectedItem = Item; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs index 8c90345cf..affc19c14 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs @@ -1337,7 +1337,7 @@ namespace Barotrauma bool limbsValid = true; foreach (Limb limb in limbs) { - if (limb.body == null || !limb.body.Enabled) { continue; } + if (limb?.body == null || !limb.body.Enabled) { continue; } if (!CheckValidity(limb.body)) { limbsValid = false; @@ -1959,7 +1959,7 @@ namespace Barotrauma { foreach (Limb l in Limbs) { - l.Remove(); + l?.Remove(); } limbs = null; } @@ -1968,7 +1968,7 @@ namespace Barotrauma { foreach (PhysicsBody b in collider) { - b.Remove(); + b?.Remove(); } collider = null; } @@ -1977,7 +1977,7 @@ namespace Barotrauma { foreach (var joint in LimbJoints) { - var j = joint.Joint; + var j = joint?.Joint; if (GameMain.World.JointList.Contains(j)) { GameMain.World.Remove(j); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs index b03d51803..0da21fd42 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs @@ -2721,6 +2721,11 @@ namespace Barotrauma } } + bool selectInputSameAsDeselect = false; +#if CLIENT + selectInputSameAsDeselect = GameSettings.CurrentConfig.KeyMap.Bindings[InputType.Select] == GameSettings.CurrentConfig.KeyMap.Bindings[InputType.Deselect]; +#endif + if (SelectedCharacter != null && (IsKeyHit(InputType.Grab) || IsKeyHit(InputType.Health))) //Let people use ladders and buttons and stuff when dragging chars { DeselectCharacter(); @@ -2760,14 +2765,16 @@ namespace Barotrauma { FocusedCharacter.onCustomInteract(FocusedCharacter, this); } - else if (IsKeyHit(InputType.Deselect) && SelectedItem != null) + else if (IsKeyHit(InputType.Deselect) && SelectedItem != null && + (focusedItem == null || focusedItem == SelectedItem || !selectInputSameAsDeselect)) { SelectedItem = null; #if CLIENT CharacterHealth.OpenHealthWindow = null; #endif } - else if (IsKeyHit(InputType.Deselect) && SelectedSecondaryItem != null) + else if (IsKeyHit(InputType.Deselect) && SelectedSecondaryItem != null && SelectedSecondaryItem.GetComponent() == null && + (focusedItem == null || focusedItem == SelectedSecondaryItem || !selectInputSameAsDeselect)) { SelectedSecondaryItem = null; #if CLIENT @@ -2782,6 +2789,10 @@ namespace Barotrauma { #if CLIENT if (CharacterInventory.DraggingItemToWorld) { return; } + if (selectInputSameAsDeselect) + { + keys[(int)InputType.Deselect].Reset(); + } #endif bool canInteract = focusedItem.TryInteract(this); #if CLIENT diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs index b524580df..6876a6a22 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs @@ -543,7 +543,7 @@ namespace Barotrauma private void GetName(Rand.RandSync randSync, out string name) { - var nameElement = CharacterConfigElement.GetChildElement("names") ?? CharacterConfigElement.GetChildElement("name"); + ContentXElement nameElement = CharacterConfigElement.GetChildElement("names") ?? CharacterConfigElement.GetChildElement("name"); ContentPath namesXmlFile = nameElement?.GetAttributeContentPath("path") ?? ContentPath.Empty; XElement namesXml = null; if (!namesXmlFile.IsNullOrEmpty()) //names.xml is defined @@ -554,8 +554,8 @@ namespace Barotrauma else //the legacy firstnames.txt/lastnames.txt shit is defined { namesXml = new XElement("names", new XAttribute("format", "[firstname] [lastname]")); - var firstNamesPath = ReplaceVars(nameElement.GetAttributeContentPath("firstname")?.Value ?? ""); - var lastNamesPath = ReplaceVars(nameElement.GetAttributeContentPath("lastname")?.Value ?? ""); + string firstNamesPath = nameElement == null ? string.Empty : ReplaceVars(nameElement.GetAttributeContentPath("firstname")?.Value ?? ""); + string lastNamesPath = nameElement == null ? string.Empty : ReplaceVars(nameElement.GetAttributeContentPath("lastname")?.Value ?? ""); if (File.Exists(firstNamesPath) && File.Exists(lastNamesPath)) { var firstNames = File.ReadAllLines(firstNamesPath); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityConditionals/AbilityConditionDataless/AbilityConditionHasAffliction.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityConditionals/AbilityConditionDataless/AbilityConditionHasAffliction.cs index 8470362c8..bc1e1e71f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityConditionals/AbilityConditionDataless/AbilityConditionHasAffliction.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/AbilityConditionals/AbilityConditionDataless/AbilityConditionHasAffliction.cs @@ -17,7 +17,7 @@ { var affliction = character.CharacterHealth.GetAffliction(afflictionIdentifier); if (affliction == null) { return false; } - return minimumPercentage <= affliction.Strength / affliction.Prefab.MaxStrength; + return affliction.Strength >= affliction.Prefab.ActivationThreshold && minimumPercentage <= affliction.Strength / affliction.Prefab.MaxStrength; } return false; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CustomAbilities/CharacterAbilityTandemFire.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CustomAbilities/CharacterAbilityTandemFire.cs index d58d73b49..ff1e5ccde 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CustomAbilities/CharacterAbilityTandemFire.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CustomAbilities/CharacterAbilityTandemFire.cs @@ -13,21 +13,23 @@ namespace Barotrauma.Abilities protected override void ApplyEffect() { - if (!SelectedItemHasTag(Character)) { return; } + if (!SelectedItemHasTag(Character, tag)) { return; } Character closestCharacter = null; float closestDistance = squaredMaxDistance; foreach (Character crewCharacter in Character.GetFriendlyCrew(Character)) { - if (crewCharacter != Character && Vector2.DistanceSquared(Character.SimPosition, Character.GetRelativeSimPosition(crewCharacter)) is float tempDistance && tempDistance < closestDistance) + if (crewCharacter != Character && + Vector2.DistanceSquared(Character.WorldPosition, crewCharacter.WorldPosition) is float tempDistance && tempDistance < closestDistance && + SelectedItemHasTag(crewCharacter, tag)) { closestCharacter = crewCharacter; closestDistance = tempDistance; } } - if (closestCharacter == null || !SelectedItemHasTag(closestCharacter)) { return; } + if (closestCharacter == null) { return; } if (closestDistance < squaredMaxDistance) { @@ -35,7 +37,7 @@ namespace Barotrauma.Abilities ApplyEffectSpecific(closestCharacter); } - bool SelectedItemHasTag(Character character) => + static bool SelectedItemHasTag(Character character, string tag) => (character.SelectedItem != null && character.SelectedItem.HasTag(tag)) || (character.SelectedSecondaryItem != null && character.SelectedSecondaryItem.HasTag(tag)); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPath.cs b/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPath.cs index 4e0a4328b..18da93f92 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPath.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPath.cs @@ -57,7 +57,7 @@ namespace Barotrauma { Option ugcId = ContentPackageId.Parse(otherModName.Value); ContentPackage? otherMod = - allPackages.FirstOrDefault(p => ugcId == p.UgcId) + allPackages.FirstOrDefault(p => ugcId.IsSome() && ugcId == p.UgcId) ?? allPackages.FirstOrDefault(p => p.Name == otherModName) ?? allPackages.FirstOrDefault(p => p.NameMatches(otherModName)) ?? throw new MissingContentPackageException(ContentPackage, otherModName.Value); diff --git a/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs b/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs index 9a7710898..d8b9730c9 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs @@ -1334,7 +1334,7 @@ namespace Barotrauma if (!prefab.UpgradeCategories.Contains(category)) { continue; } if (!string.IsNullOrWhiteSpace(prefabIdentifier) && prefab.Identifier != prefabIdentifier) { continue; } - int targetLevel = prefab.MaxLevel - upgradeManager.GetRealUpgradeLevel(prefab, category); + int targetLevel = prefab.GetMaxLevelForCurrentSub() - upgradeManager.GetRealUpgradeLevel(prefab, category); for (int i = 0; i < targetLevel; i++) { upgradeManager.PurchaseUpgrade(prefab, category, force: true); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/SpawnAction.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/SpawnAction.cs index 657c6af21..a3aa06d7a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/SpawnAction.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/SpawnAction.cs @@ -139,7 +139,7 @@ namespace Barotrauma humanPrefab.GiveItems(newCharacter, newCharacter.Submarine); if (LootingIsStealing) { - foreach (Item item in newCharacter.Inventory.AllItems) + foreach (Item item in newCharacter.Inventory.FindAllItems(recursive: true)) { item.SpawnedInCurrentOutpost = true; item.AllowStealing = false; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/EventSet.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/EventSet.cs index 9b397d4be..cd6a3cae6 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/EventSet.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/EventSet.cs @@ -273,13 +273,13 @@ namespace Barotrauma IsCampaignSet = element.GetAttributeBool("campaign", LevelType == LevelData.LevelType.Outpost || (parentSet?.IsCampaignSet ?? false)); ResetTime = element.GetAttributeFloat("resettime", 0); - DefaultCommonness = 1.0f; + DefaultCommonness = element.GetAttributeFloat("commonness", 1.0f); foreach (var subElement in element.Elements()) { switch (subElement.Name.ToString().ToLowerInvariant()) { case "commonness": - DefaultCommonness = subElement.GetAttributeFloat("commonness", 0.0f); + DefaultCommonness = subElement.GetAttributeFloat("commonness", DefaultCommonness); foreach (XElement overrideElement in subElement.Elements()) { if (overrideElement.NameAsIdentifier() == "override") diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs index b6868a586..1fa50625a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs @@ -156,7 +156,7 @@ namespace Barotrauma { if (!(e.ChangedData.BalanceChanged is Some { Value: var changed })) { return; } - if (changed != 0) { return; } + if (changed == 0) { return; } bool isGain = changed > 0; Color clr = isGain ? GUIStyle.Yellow : GUIStyle.Red; diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/UpgradeManager.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/UpgradeManager.cs index a35b86654..a46d24b71 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/UpgradeManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/UpgradeManager.cs @@ -177,12 +177,13 @@ namespace Barotrauma return; } - int price = prefab.Price.GetBuyprice(GetUpgradeLevel(prefab, category), Campaign.Map?.CurrentLocation); + int price = prefab.Price.GetBuyPrice(GetUpgradeLevel(prefab, category), Campaign.Map?.CurrentLocation); int currentLevel = GetUpgradeLevel(prefab, category); - if (currentLevel + 1 > prefab.MaxLevel) + int maxLevel = prefab.GetMaxLevelForCurrentSub(); + if (currentLevel + 1 > maxLevel) { - DebugConsole.ThrowError($"Tried to purchase \"{prefab.Name}\" over the max level! ({currentLevel + 1} > {prefab.MaxLevel}). The transaction has been cancelled."); + DebugConsole.ThrowError($"Tried to purchase \"{prefab.Name}\" over the max level! ({currentLevel + 1} > {maxLevel}). The transaction has been cancelled."); return; } @@ -472,7 +473,7 @@ namespace Barotrauma { int newLevel = BuyUpgrade(prefab, category, Submarine.MainSub, level); DebugConsole.Log($" - {category.Identifier}.{prefab.Identifier} lvl. {level}, new: ({newLevel})"); - SetUpgradeLevel(prefab, category, Math.Clamp(GetRealUpgradeLevel(prefab, category) + level, 0, prefab.MaxLevel)); + SetUpgradeLevel(prefab, category, GetRealUpgradeLevel(prefab, category) + level); } PendingUpgrades.Clear(); @@ -652,16 +653,13 @@ namespace Barotrauma /// /// Gets the progress that is shown on the store interface. - /// Includes values stored in the metadata and + /// Includes values stored in the metadata and , and takes submarine tier and class restrictions into account /// - /// - /// - /// public int GetUpgradeLevel(UpgradePrefab prefab, UpgradeCategory category) { if (!Metadata.HasKey(FormatIdentifier(prefab, category))) { return GetPendingLevel(); } - return GetRealUpgradeLevel(prefab, category) + GetPendingLevel(); + return Math.Min(GetRealUpgradeLevel(prefab, category) + GetPendingLevel(), prefab.GetMaxLevelForCurrentSub()); int GetPendingLevel() { @@ -671,11 +669,8 @@ namespace Barotrauma } /// - /// Gets the level of the upgrade that is stored in the metadata. + /// Gets the level of the upgrade that is stored in the metadata. May be higher than the apparent level on the current sub if the player has switched to a lower-tier sub /// - /// - /// - /// public int GetRealUpgradeLevel(UpgradePrefab prefab, UpgradeCategory category) { return !Metadata.HasKey(FormatIdentifier(prefab, category)) ? 0 : Metadata.GetInt(FormatIdentifier(prefab, category), 0); @@ -684,9 +679,6 @@ namespace Barotrauma /// /// Stores the target upgrade level in the campaign metadata. /// - /// - /// - /// private void SetUpgradeLevel(UpgradePrefab prefab, UpgradeCategory category, int level) { Metadata.SetValue(FormatIdentifier(prefab, category), level); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/DockingPort.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/DockingPort.cs index 8ef6c05ad..40585fad2 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/DockingPort.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/DockingPort.cs @@ -1164,11 +1164,14 @@ namespace Barotrauma.Items.Components public override void ReceiveSignal(Signal signal, Connection connection) { #if CLIENT - if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient && - !(GameMain.GameSession?.Campaign?.AllowedToManageCampaign(ClientPermissions.ManageMap) ?? false)) + if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; } + if (GameMain.GameSession?.Campaign != null && !CampaignMode.AllowedToManageCampaign(ClientPermissions.ManageMap)) + { + return; + } #endif if (dockingCooldown > 0.0f) { return; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Holdable.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Holdable.cs index 5641b078f..1c5986b4d 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Holdable.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/Holdable.cs @@ -22,7 +22,7 @@ namespace Barotrauma.Items.Components } } - const float MaxAttachDistance = 150.0f; + private const float MaxAttachDistance = ItemPrefab.DefaultInteractDistance * 0.95f; //the position(s) in the item that the Character grabs protected Vector2[] handlePos; @@ -731,10 +731,24 @@ namespace Barotrauma.Items.Components mouseDiff = mouseDiff.ClampLength(MaxAttachDistance); Vector2 userPos = useWorldCoordinates ? user.WorldPosition : user.Position; - Vector2 attachPos = userPos + mouseDiff; - if (user.Submarine == null && Level.Loaded != null) + if (user.Submarine != null) + { + if (Submarine.PickBody( + ConvertUnits.ToSimUnits(user.Position), + ConvertUnits.ToSimUnits(user.Position + mouseDiff), collisionCategory: Physics.CollisionWall) != null) + { + attachPos = userPos + mouseDiff * Submarine.LastPickedFraction; + + //round down if we're placing on the right side and vice versa: ensures we don't round the position inside a wall + return + new Vector2( + mouseDiff.X > 0 ? (float)Math.Floor(attachPos.X / Submarine.GridSize.X) * Submarine.GridSize.X : (float)Math.Ceiling(attachPos.X / Submarine.GridSize.X) * Submarine.GridSize.X, + mouseDiff.Y > 0 ? (float)Math.Floor(attachPos.Y / Submarine.GridSize.Y) * Submarine.GridSize.X : (float)Math.Ceiling(attachPos.Y / Submarine.GridSize.Y) * Submarine.GridSize.Y); + } + } + else if (Level.Loaded != null) { bool edgeFound = false; foreach (var cell in Level.Loaded.GetCells(attachPos)) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/MeleeWeapon.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/MeleeWeapon.cs index da4e9b663..d0d0fc59a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/MeleeWeapon.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/MeleeWeapon.cs @@ -112,7 +112,7 @@ namespace Barotrauma.Items.Components reloadTimer = reload; reloadTimer /= 1f + character.GetStatValue(StatTypes.MeleeAttackSpeed); reloadTimer /= 1f + item.GetQualityModifier(Quality.StatType.StrikingSpeedMultiplier); - character.AnimController.LockFlippingUntil = (float)Timing.TotalTime + reloadTimer; + character.AnimController.LockFlippingUntil = (float)Timing.TotalTime + reloadTimer * 0.9f; item.body.FarseerBody.CollisionCategories = Physics.CollisionProjectile; item.body.FarseerBody.CollidesWith = Physics.CollisionCharacter | Physics.CollisionWall | Physics.CollisionItemBlocking; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/RepairTool.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/RepairTool.cs index 9986d7130..e7658a80b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/RepairTool.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/RepairTool.cs @@ -514,7 +514,7 @@ namespace Barotrauma.Items.Components if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer) { - if (Rand.Range(0.0f, 1.0f) < FireProbability * deltaTime) + if (Rand.Range(0.0f, 1.0f) < FireProbability * deltaTime && item.CurrentHull != null) { Vector2 displayPos = ConvertUnits.ToDisplayUnits(rayStart + (rayEnd - rayStart) * lastPickedFraction * 0.9f); if (item.CurrentHull.Submarine != null) { displayPos += item.CurrentHull.Submarine.Position; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Deconstructor.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Deconstructor.cs index 1de5e3c80..7f307471f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Deconstructor.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Deconstructor.cs @@ -284,9 +284,10 @@ namespace Barotrauma.Items.Components { Entity.Spawner.AddItemToSpawnQueue(itemPrefab, outputContainer.Inventory, condition, onSpawned: (Item spawnedItem) => { - spawnedItem.SpawnedInCurrentOutpost = item.SpawnedInCurrentOutpost; spawnedItem.StolenDuringRound = targetItem.StolenDuringRound; spawnedItem.AllowStealing = targetItem.AllowStealing; + spawnedItem.OriginalOutpost = targetItem.OriginalOutpost; + spawnedItem.SpawnedInCurrentOutpost = targetItem.SpawnedInCurrentOutpost; for (int i = 0; i < outputContainer.Capacity; i++) { var containedItem = outputContainer.Inventory.GetItemAt(i); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Reactor.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Reactor.cs index 4630a0bf2..7fc66baf2 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Reactor.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Reactor.cs @@ -83,8 +83,16 @@ namespace Barotrauma.Items.Components { if (lastUser == value) { return; } lastUser = value; - degreeOfSuccess = lastUser == null ? 0.0f : Math.Min(DegreeOfSuccess(lastUser), 1.0f); - LastUserWasPlayer = lastUser.IsPlayer; + if (lastUser == null) + { + degreeOfSuccess = 0.0f; + LastUserWasPlayer = false; + } + else + { + degreeOfSuccess = Math.Min(DegreeOfSuccess(lastUser), 1.0f); + LastUserWasPlayer = lastUser.IsPlayer; + } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs index 59ee01824..9dd19dc7f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/ItemPrefab.cs @@ -390,6 +390,8 @@ namespace Barotrauma { public static readonly PrefabCollection Prefabs = new PrefabCollection(); + public const float DefaultInteractDistance = 120.0f; + //default size public Vector2 Size { get; private set; } @@ -590,7 +592,7 @@ namespace Barotrauma public override ImmutableHashSet Aliases => aliases; //how close the Character has to be to the item to pick it up - [Serialize(120.0f, IsPropertySaveable.No)] + [Serialize(DefaultInteractDistance, IsPropertySaveable.No)] public float InteractDistance { get; private set; } // this can be used to allow items which are behind other items tp diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs index 508032303..1665d6a7f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs @@ -3015,6 +3015,7 @@ namespace Barotrauma var selectedLocation = allValidLocations.FirstOrDefault(l => Vector2.Distance(l.Edge.Point1, l.Edge.Point2) is float edgeLength && !l.Edge.OutsideLevel && + ((l.Edge.Cell1?.IsDestructible ?? false) || (l.Edge.Cell2?.IsDestructible ?? false)) && requiredAmount <= (int)Math.Floor(edgeLength / ((1.0f - maxResourceOverlap) * prefab.Size.X))); @@ -3905,7 +3906,7 @@ namespace Barotrauma private bool HasEndOutpost() { - if (preSelectedStartOutpost != null) { return true; } + if (preSelectedEndOutpost != null) { return true; } //don't create an end outpost for locations if (LevelData.Type == LevelData.LevelType.Outpost) { return false; } if (EndLocation != null && !EndLocation.Type.HasOutpost) { return false; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Location.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Location.cs index cb1861ec7..2efccc7e5 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Location.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Location.cs @@ -906,11 +906,17 @@ namespace Barotrauma public LocationType GetLocationType() { - if (IsCriticallyRadiated() && LocationType.Prefabs[Type.ReplaceInRadiation] is { } newLocationType) + if (IsCriticallyRadiated() && !Type.ReplaceInRadiation.IsEmpty) { - return newLocationType; + if (LocationType.Prefabs.TryGet(Type.ReplaceInRadiation, out LocationType newLocationType)) + { + return newLocationType; + } + else + { + DebugConsole.ThrowError($"Error when trying to get a new location type for an irradiated location - location type \"{newLocationType}\" not found."); + } } - return Type; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Map/LocationType.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Map/LocationType.cs index e402b8073..97651462a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Map/LocationType.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Map/LocationType.cs @@ -65,7 +65,7 @@ namespace Barotrauma private set; } - public string ReplaceInRadiation { get; } + public Identifier ReplaceInRadiation { get; } public Sprite Sprite { get; private set; } public Sprite RadiationSprite { get; } @@ -108,7 +108,7 @@ namespace Barotrauma HideEntitySubcategories = element.GetAttributeStringArray("hideentitysubcategories", Array.Empty()).ToList(); - ReplaceInRadiation = element.GetAttributeString(nameof(ReplaceInRadiation).ToLower(), ""); + ReplaceInRadiation = element.GetAttributeIdentifier(nameof(ReplaceInRadiation), Identifier.Empty); string teamStr = element.GetAttributeString("outpostteam", "FriendlyNPC"); Enum.TryParse(teamStr, out OutpostTeam); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Map.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Map.cs index ff196b2d6..e87fd88da 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Map.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Map.cs @@ -560,6 +560,42 @@ namespace Barotrauma } } + //make sure the location at the right side of the gate between biomes isn't a dead-end + //those may sometimes generate if all the connections of the right-side location lead to the previous biome + //(i.e. a situation where the adjacent locations happen to be at the left side of the border of the biomes, see see Regalis11/Barotrauma#10047) + for (int i = 0; i < Connections.Count; i++) + { + var connection = Connections[i]; + if (!connection.Locked) { continue; } + var rightMostLocation = + connection.Locations[0].MapPosition.X > connection.Locations[1].MapPosition.X ? + connection.Locations[0] : + connection.Locations[1]; + + //if there's only one connection (= the connection between biomes), create a new connection to the closest location to the right + if (rightMostLocation.Connections.Count == 1) + { + Location closestLocation = null; + float closestDist = float.PositiveInfinity; + foreach (Location otherLocation in Locations) + { + if (otherLocation == rightMostLocation || otherLocation.MapPosition.X < rightMostLocation.MapPosition.X) { continue; } + float dist = Vector2.DistanceSquared(rightMostLocation.MapPosition, otherLocation.MapPosition); + if (dist < closestDist || closestLocation == null) + { + closestLocation = otherLocation; + closestDist = dist; + } + } + + var newConnection = new LocationConnection(rightMostLocation, closestLocation); + rightMostLocation.Connections.Add(newConnection); + closestLocation.Connections.Add(newConnection); + Connections.Add(newConnection); + GenerateLocationConnectionVisuals(newConnection); + } + } + //remove orphans Locations.RemoveAll(l => !Connections.Any(c => c.Locations.Contains(l))); @@ -606,7 +642,9 @@ namespace Barotrauma } } - partial void GenerateLocationConnectionVisuals(); + partial void GenerateAllLocationConnectionVisuals(); + + partial void GenerateLocationConnectionVisuals(LocationConnection connection); private int GetZoneIndex(float xPos) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/NetStructBitField.cs b/Barotrauma/BarotraumaShared/SharedSource/NetStructBitField.cs index 4885dd27a..f28300c70 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/NetStructBitField.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/NetStructBitField.cs @@ -8,23 +8,7 @@ using Lidgren.Network; namespace Barotrauma { - interface IWritableBitField - { - public void WriteBoolean(bool b); - public void WriteInteger(int value, int min, int max); - public void WriteFloat(float value, float min, float max, int numberOfBits); - - public void WriteToMessage(IWriteMessage msg); - } - - interface IReadableBitField - { - public bool ReadBoolean(); - public int ReadInteger(int min, int max); - public float ReadFloat(float min, float max, int numberOfBits); - } - - sealed class WriteOnlyBitField : IWritableBitField, IDisposable + sealed class WriteOnlyBitField : IDisposable { private const int AmountOfBoolsInByte = 7; // Reserve last bit for end marker private readonly List Buffer = new List(); @@ -100,7 +84,7 @@ namespace Barotrauma } } - sealed class ReadOnlyBitField : IReadableBitField + sealed class ReadOnlyBitField { private const int AmountOfBoolsInByte = 7; // Reserve last bit for end marker private readonly ImmutableArray buffer; @@ -110,17 +94,14 @@ namespace Barotrauma { List bytes = new List(); byte currentByte; - int reads = 0; do { + if (inc.BitPosition >= inc.LengthBits) + { + throw new Exception("Failed to find the end of the bit field: end of the message reached."); + } currentByte = inc.ReadByte(); bytes.Add(currentByte); - - reads++; - if (reads > 100) - { - throw new Exception($"Failed to find the end of the bit field after 100 reads. Terminating to prevent the game from freezing."); - } } while (!IsBitSet(currentByte, AmountOfBoolsInByte)); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Networking/ChildServerRelay.cs b/Barotrauma/BarotraumaShared/SharedSource/Networking/ChildServerRelay.cs index 8cb93bbb2..cd1b6ad8a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Networking/ChildServerRelay.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Networking/ChildServerRelay.cs @@ -113,6 +113,11 @@ namespace Barotrauma.Networking break; } } + catch (AggregateException aggregateException) + { + if (aggregateException.InnerException is OperationCanceledException) { return -1; } + throw; + } catch (OperationCanceledException) { return -1; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Networking/INetSerializableStruct.cs b/Barotrauma/BarotraumaShared/SharedSource/Networking/INetSerializableStruct.cs index b8e4460b7..e3f946325 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Networking/INetSerializableStruct.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Networking/INetSerializableStruct.cs @@ -61,9 +61,9 @@ namespace Barotrauma { public interface IReadWriteBehavior { - public delegate object? ReadDelegate(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField); + public delegate object? ReadDelegate(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField); - public delegate void WriteDelegate(object? obj, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField); + public delegate void WriteDelegate(object? obj, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField); public ReadDelegate ReadAction { get; } public WriteDelegate WriteAction { get; } @@ -71,9 +71,9 @@ namespace Barotrauma public readonly struct ReadWriteBehavior : IReadWriteBehavior { - public delegate T ReadDelegate(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField); + public delegate T ReadDelegate(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField); - public delegate void WriteDelegate(T obj, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField); + public delegate void WriteDelegate(T obj, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField); public IReadWriteBehavior.ReadDelegate ReadAction { get; } public IReadWriteBehavior.WriteDelegate WriteAction { get; } @@ -256,18 +256,18 @@ namespace Barotrauma ReadImmutableArray, WriteImmutableArray); - private static ImmutableArray ReadImmutableArray(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) where T : notnull + private static ImmutableArray ReadImmutableArray(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) where T : notnull { return ReadArray(inc, attribute, bitField).ToImmutableArray(); } - private static void WriteImmutableArray(ImmutableArray array, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) where T : notnull + private static void WriteImmutableArray(ImmutableArray array, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) where T : notnull { ToolBox.ThrowIfNull(array); WriteIReadOnlyCollection(array, attribute, msg, bitField); } - private static T[] ReadArray(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) where T : notnull + private static T[] ReadArray(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) where T : notnull { int length = bitField.ReadInteger(0, attribute.ArrayMaxSize); @@ -286,13 +286,13 @@ namespace Barotrauma return array; } - private static void WriteArray(T[] array, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) where T : notnull + private static void WriteArray(T[] array, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) where T : notnull { ToolBox.ThrowIfNull(array); WriteIReadOnlyCollection(array, attribute, msg, bitField); } - private static void WriteIReadOnlyCollection(IReadOnlyCollection array, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) where T : notnull + private static void WriteIReadOnlyCollection(IReadOnlyCollection array, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) where T : notnull { bitField.WriteInteger(array.Count, 0, attribute.ArrayMaxSize); @@ -307,18 +307,18 @@ namespace Barotrauma } } - private static T ReadINetSerializableStruct(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) where T : INetSerializableStruct + private static T ReadINetSerializableStruct(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) where T : INetSerializableStruct { return INetSerializableStruct.ReadInternal(inc, bitField); } - private static void WriteINetSerializableStruct(T serializableStruct, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) where T : INetSerializableStruct + private static void WriteINetSerializableStruct(T serializableStruct, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) where T : INetSerializableStruct { ToolBox.ThrowIfNull(serializableStruct); serializableStruct.WriteInternal(msg, bitField); } - private static T ReadEnum(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) where T : Enum + private static T ReadEnum(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) where T : Enum { var type = typeof(T); @@ -338,7 +338,7 @@ namespace Barotrauma throw new InvalidOperationException($"An enum {type} with value {enumIndex} could not be found in {nameof(ReadEnum)}"); } - private static void WriteEnum(T value, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) where T : Enum + private static void WriteEnum(T value, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) where T : Enum { ToolBox.ThrowIfNull(value); @@ -346,7 +346,7 @@ namespace Barotrauma bitField.WriteInteger((int)Convert.ChangeType(value, value.GetTypeCode()), range.Start, range.End); } - private static T? ReadNullable(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) where T : struct => + private static T? ReadNullable(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) where T : struct => ReadOption(inc, attribute, bitField) switch { Some { Value: var value } => value, @@ -354,10 +354,10 @@ namespace Barotrauma _ => throw new ArgumentOutOfRangeException() }; - private static void WriteNullable(T? value, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) where T : struct => + private static void WriteNullable(T? value, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) where T : struct => WriteOption(value.HasValue ? Option.Some(value.Value) : Option.None(), attribute, msg, bitField); - private static Option ReadOption(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) where T : notnull + private static Option ReadOption(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) where T : notnull { bool hasValue = bitField.ReadBoolean(); if (!hasValue) @@ -373,7 +373,7 @@ namespace Barotrauma throw new InvalidOperationException($"Could not find suitable behavior for type {typeof(T)} in {nameof(ReadOption)}"); } - private static void WriteOption(Option option, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) where T : notnull + private static void WriteOption(Option option, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) where T : notnull { ToolBox.ThrowIfNull(option); @@ -391,22 +391,22 @@ namespace Barotrauma } } - private static bool ReadBoolean(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => bitField.ReadBoolean(); - private static void WriteBoolean(bool b, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) { bitField.WriteBoolean(b); } + private static bool ReadBoolean(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => bitField.ReadBoolean(); + private static void WriteBoolean(bool b, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { bitField.WriteBoolean(b); } - private static byte ReadByte(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => inc.ReadByte(); - private static void WriteByte(byte b, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) { msg.WriteByte(b); } + private static byte ReadByte(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => inc.ReadByte(); + private static void WriteByte(byte b, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { msg.WriteByte(b); } - private static ushort ReadUInt16(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => inc.ReadUInt16(); - private static void WriteUInt16(ushort b, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) { msg.WriteUInt16(b); } + private static ushort ReadUInt16(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => inc.ReadUInt16(); + private static void WriteUInt16(ushort b, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { msg.WriteUInt16(b); } - private static short ReadInt16(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => inc.ReadInt16(); - private static void WriteInt16(short b, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) { msg.WriteInt16(b); } + private static short ReadInt16(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => inc.ReadInt16(); + private static void WriteInt16(short b, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { msg.WriteInt16(b); } - private static uint ReadUInt32(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => inc.ReadUInt32(); - private static void WriteUInt32(uint b, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) { msg.WriteUInt32(b); } + private static uint ReadUInt32(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => inc.ReadUInt32(); + private static void WriteUInt32(uint b, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { msg.WriteUInt32(b); } - private static int ReadInt32(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) + private static int ReadInt32(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) { if (IsRanged(attribute.MinValueInt, attribute.MaxValueInt)) { @@ -416,7 +416,7 @@ namespace Barotrauma return inc.ReadInt32(); } - private static void WriteInt32(int i, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) + private static void WriteInt32(int i, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { ToolBox.ThrowIfNull(i); @@ -429,13 +429,13 @@ namespace Barotrauma msg.WriteInt32(i); } - private static ulong ReadUInt64(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => inc.ReadUInt64(); - private static void WriteUInt64(ulong b, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) { msg.WriteUInt64(b); } + private static ulong ReadUInt64(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => inc.ReadUInt64(); + private static void WriteUInt64(ulong b, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { msg.WriteUInt64(b); } - private static long ReadInt64(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => inc.ReadInt64(); - private static void WriteInt64(long b, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) { msg.WriteInt64(b); } + private static long ReadInt64(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => inc.ReadInt64(); + private static void WriteInt64(long b, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { msg.WriteInt64(b); } - private static float ReadSingle(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) + private static float ReadSingle(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) { if (IsRanged(attribute.MinValueFloat, attribute.MaxValueFloat)) { @@ -445,7 +445,7 @@ namespace Barotrauma return inc.ReadSingle(); } - private static void WriteSingle(float f, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) + private static void WriteSingle(float f, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { ToolBox.ThrowIfNull(f); @@ -458,16 +458,16 @@ namespace Barotrauma msg.WriteSingle(f); } - private static double ReadDouble(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => inc.ReadDouble(); - private static void WriteDouble(double b, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) { msg.WriteDouble(b); } + private static double ReadDouble(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => inc.ReadDouble(); + private static void WriteDouble(double b, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { msg.WriteDouble(b); } - private static string ReadString(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => inc.ReadString(); - private static void WriteString(string b, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) { msg.WriteString(b); } + private static string ReadString(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => inc.ReadString(); + private static void WriteString(string b, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { msg.WriteString(b); } - private static Identifier ReadIdentifier(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => inc.ReadIdentifier(); - private static void WriteIdentifier(Identifier b, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) { msg.WriteIdentifier(b); } + private static Identifier ReadIdentifier(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => inc.ReadIdentifier(); + private static void WriteIdentifier(Identifier b, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { msg.WriteIdentifier(b); } - private static AccountId ReadAccountId(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) + private static AccountId ReadAccountId(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) { string str = inc.ReadString(); return AccountId.Parse(str).TryUnwrap(out var accountId) @@ -475,14 +475,14 @@ namespace Barotrauma : throw new InvalidCastException($"Could not parse \"{str}\" as an {nameof(AccountId)}"); } - private static void WriteAccountId(AccountId accountId, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) + private static void WriteAccountId(AccountId accountId, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { msg.WriteString(accountId.StringRepresentation); } - private static Color ReadColor(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) => attribute.IncludeColorAlpha ? inc.ReadColorR8G8B8A8() : inc.ReadColorR8G8B8(); + private static Color ReadColor(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) => attribute.IncludeColorAlpha ? inc.ReadColorR8G8B8A8() : inc.ReadColorR8G8B8(); - private static void WriteColor(Color color, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) + private static void WriteColor(Color color, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { ToolBox.ThrowIfNull(color); @@ -495,7 +495,7 @@ namespace Barotrauma msg.WriteColorR8G8B8(color); } - private static Vector2 ReadVector2(IReadMessage inc, NetworkSerialize attribute, IReadableBitField bitField) + private static Vector2 ReadVector2(IReadMessage inc, NetworkSerialize attribute, ReadOnlyBitField bitField) { float x = ReadSingle(inc, attribute, bitField); float y = ReadSingle(inc, attribute, bitField); @@ -503,7 +503,7 @@ namespace Barotrauma return new Vector2(x, y); } - private static void WriteVector2(Vector2 vector2, NetworkSerialize attribute, IWriteMessage msg, IWritableBitField bitField) + private static void WriteVector2(Vector2 vector2, NetworkSerialize attribute, IWriteMessage msg, WriteOnlyBitField bitField) { ToolBox.ThrowIfNull(vector2); @@ -690,11 +690,11 @@ namespace Barotrauma /// A new struct of type T with fields and properties deserialized public static T Read(IReadMessage inc) where T : INetSerializableStruct { - IReadableBitField bitField = new ReadOnlyBitField(inc); + ReadOnlyBitField bitField = new ReadOnlyBitField(inc); return ReadInternal(inc, bitField); } - public static T ReadInternal(IReadMessage inc, IReadableBitField bitField) where T : INetSerializableStruct + public static T ReadInternal(IReadMessage inc, ReadOnlyBitField bitField) where T : INetSerializableStruct { object? newObject = Activator.CreateInstance(typeof(T)); if (newObject is null) { return default!; } @@ -744,14 +744,14 @@ namespace Barotrauma /// Outgoing network message public void Write(IWriteMessage msg) { - IWritableBitField bitField = new WriteOnlyBitField(); + WriteOnlyBitField bitField = new WriteOnlyBitField(); IWriteMessage structWriteMsg = new WriteOnlyMessage(); WriteInternal(structWriteMsg, bitField); bitField.WriteToMessage(msg); msg.WriteBytes(structWriteMsg.Buffer, 0, structWriteMsg.LengthBytes); } - public void WriteInternal(IWriteMessage msg, IWritableBitField bitField) + public void WriteInternal(IWriteMessage msg, WriteOnlyBitField bitField) { var properties = NetSerializableProperties.GetPropertiesAndFields(GetType()); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/Address/LidgrenAddress.cs b/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/Address/LidgrenAddress.cs index 5fadd7644..eaea9b556 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/Address/LidgrenAddress.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/Address/LidgrenAddress.cs @@ -40,6 +40,25 @@ namespace Barotrauma.Networking return Option.None(); } + public static Option ParseHostName(string endpointStr) + { + try + { + var resolvedAddresses = Dns.GetHostAddresses(endpointStr); + return resolvedAddresses.Any() + ? Option.Some(new LidgrenAddress(resolvedAddresses.First())) + : Option.None(); + } + catch (SocketException) + { + return Option.None(); + } + catch (ArgumentOutOfRangeException) + { + return Option.None(); + } + } + public override bool Equals(object? obj) => obj switch { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/Endpoint/LidgrenEndpoint.cs b/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/Endpoint/LidgrenEndpoint.cs index 44d20264a..8e11264c6 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/Endpoint/LidgrenEndpoint.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/Endpoint/LidgrenEndpoint.cs @@ -23,6 +23,11 @@ namespace Barotrauma.Networking } public new static Option Parse(string endpointStr) + { + return ParseFromWithHostNameCheck(endpointStr, tryParseHostName: false); + } + + public static Option ParseFromWithHostNameCheck(string endpointStr, bool tryParseHostName) { string hostName = endpointStr; int port = NetConfig.DefaultPort; @@ -33,7 +38,8 @@ namespace Barotrauma.Networking port = int.TryParse(split[1], out var tmpPort) ? tmpPort : port; } - if (LidgrenAddress.Parse(hostName).TryUnwrap(out var adr)) + if (LidgrenAddress.Parse(hostName).TryUnwrap(out var adr) || + (tryParseHostName && LidgrenAddress.ParseHostName(hostName).TryUnwrap(out adr))) { return Option.Some(new LidgrenEndpoint(adr.NetAddress, port)); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/Message/Message.cs b/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/Message/Message.cs index d4330e11e..87e0463a9 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/Message/Message.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/Message/Message.cs @@ -37,7 +37,12 @@ namespace Barotrauma.Networking internal static class MsgWriter { - internal static void Write(ref byte[] buf, ref int bitPos, bool val) + internal static void UpdateBitLength(ref int bitLength, int bitPos) + { + bitLength = Math.Max(bitLength, bitPos); + } + + internal static void WriteBoolean(ref byte[] buf, ref int bitPos, ref int bitLength, bool val) { #if DEBUG int resetPos = bitPos; @@ -52,7 +57,7 @@ namespace Barotrauma.Networking buf[bytePos] &= bitMask; if (val) buf[bytePos] |= bitFlag; bitPos++; - + UpdateBitLength(ref bitLength, bitPos); #if DEBUG bool testVal = MsgReader.ReadBoolean(buf, ref resetPos); if (testVal != val || resetPos != bitPos) @@ -62,63 +67,71 @@ namespace Barotrauma.Networking #endif } - internal static void WritePadBits(ref byte[] buf, ref int bitPos) + internal static void WritePadBits(ref byte[] buf, ref int bitPos, ref int bitLength) { int bitOffset = bitPos % 8; bitPos += ((8 - bitOffset) % 8); + UpdateBitLength(ref bitLength, bitPos); EnsureBufferSize(ref buf, bitPos); } - internal static void Write(ref byte[] buf, ref int bitPos, byte val) + internal static void WriteByte(ref byte[] buf, ref int bitPos, ref int bitLength, byte val) { EnsureBufferSize(ref buf, bitPos + 8); NetBitWriter.WriteByte(val, 8, buf, bitPos); bitPos += 8; + UpdateBitLength(ref bitLength, bitPos); } - internal static void Write(ref byte[] buf, ref int bitPos, UInt16 val) + internal static void WriteUInt16(ref byte[] buf, ref int bitPos, ref int bitLength, UInt16 val) { EnsureBufferSize(ref buf, bitPos + 16); NetBitWriter.WriteUInt16(val, 16, buf, bitPos); bitPos += 16; + UpdateBitLength(ref bitLength, bitPos); } - internal static void Write(ref byte[] buf, ref int bitPos, Int16 val) + internal static void WriteInt16(ref byte[] buf, ref int bitPos, ref int bitLength, Int16 val) { EnsureBufferSize(ref buf, bitPos + 16); NetBitWriter.WriteUInt16((UInt16)val, 16, buf, bitPos); bitPos += 16; + UpdateBitLength(ref bitLength, bitPos); } - internal static void Write(ref byte[] buf, ref int bitPos, UInt32 val) + internal static void WriteUInt32(ref byte[] buf, ref int bitPos, ref int bitLength, UInt32 val) { EnsureBufferSize(ref buf, bitPos + 32); NetBitWriter.WriteUInt32(val, 32, buf, bitPos); bitPos += 32; + UpdateBitLength(ref bitLength, bitPos); } - internal static void Write(ref byte[] buf, ref int bitPos, Int32 val) + internal static void WriteInt32(ref byte[] buf, ref int bitPos, ref int bitLength, Int32 val) { EnsureBufferSize(ref buf, bitPos + 32); NetBitWriter.WriteUInt32((UInt32)val, 32, buf, bitPos); bitPos += 32; + UpdateBitLength(ref bitLength, bitPos); } - internal static void Write(ref byte[] buf, ref int bitPos, UInt64 val) + internal static void WriteUInt64(ref byte[] buf, ref int bitPos, ref int bitLength, UInt64 val) { EnsureBufferSize(ref buf, bitPos + 64); NetBitWriter.WriteUInt64(val, 64, buf, bitPos); bitPos += 64; + UpdateBitLength(ref bitLength, bitPos); } - internal static void Write(ref byte[] buf, ref int bitPos, Int64 val) + internal static void WriteInt64(ref byte[] buf, ref int bitPos, ref int bitLength, Int64 val) { EnsureBufferSize(ref buf, bitPos + 64); NetBitWriter.WriteUInt64((UInt64)val, 64, buf, bitPos); bitPos += 64; + UpdateBitLength(ref bitLength, bitPos); } - internal static void Write(ref byte[] buf, ref int bitPos, Single val) + internal static void WriteSingle(ref byte[] buf, ref int bitPos, ref int bitLength, Single val) { // Use union to avoid BitConverter.GetBytes() which allocates memory on the heap SingleUIntUnion su; @@ -129,61 +142,62 @@ namespace Barotrauma.Networking NetBitWriter.WriteUInt32(su.UIntValue, 32, buf, bitPos); bitPos += 32; + UpdateBitLength(ref bitLength, bitPos); } - internal static void Write(ref byte[] buf, ref int bitPos, Double val) + internal static void WriteDouble(ref byte[] buf, ref int bitPos, ref int bitLength, Double val) { EnsureBufferSize(ref buf, bitPos + 64); byte[] bytes = BitConverter.GetBytes(val); - WriteBytes(ref buf, ref bitPos, bytes, 0, 8); + WriteBytes(ref buf, ref bitPos, ref bitLength, bytes, 0, 8); } - internal static void WriteColorR8G8B8(ref byte[] buf, ref int bitPos, Color val) + internal static void WriteColorR8G8B8(ref byte[] buf, ref int bitPos, ref int bitLength, Color val) { EnsureBufferSize(ref buf, bitPos + 24); - Write(ref buf, ref bitPos, val.R); - Write(ref buf, ref bitPos, val.G); - Write(ref buf, ref bitPos, val.B); + WriteByte(ref buf, ref bitPos, ref bitLength, val.R); + WriteByte(ref buf, ref bitPos, ref bitLength, val.G); + WriteByte(ref buf, ref bitPos, ref bitLength, val.B); } - internal static void WriteColorR8G8B8A8(ref byte[] buf, ref int bitPos, Color val) + internal static void WriteColorR8G8B8A8(ref byte[] buf, ref int bitPos, ref int bitLength, Color val) { EnsureBufferSize(ref buf, bitPos + 32); - Write(ref buf, ref bitPos, val.R); - Write(ref buf, ref bitPos, val.G); - Write(ref buf, ref bitPos, val.B); - Write(ref buf, ref bitPos, val.A); + WriteByte(ref buf, ref bitPos, ref bitLength, val.R); + WriteByte(ref buf, ref bitPos, ref bitLength, val.G); + WriteByte(ref buf, ref bitPos, ref bitLength, val.B); + WriteByte(ref buf, ref bitPos, ref bitLength, val.A); } - internal static void Write(ref byte[] buf, ref int bitPos, string val) + internal static void WriteString(ref byte[] buf, ref int bitPos, ref int bitLength, string val) { if (string.IsNullOrEmpty(val)) { - WriteVariableUInt32(ref buf, ref bitPos, 0u); + WriteVariableUInt32(ref buf, ref bitPos, ref bitLength, 0u); return; } byte[] bytes = Encoding.UTF8.GetBytes(val); - WriteVariableUInt32(ref buf, ref bitPos, (uint)bytes.Length); - WriteBytes(ref buf, ref bitPos, bytes, 0, bytes.Length); + WriteVariableUInt32(ref buf, ref bitPos, ref bitLength, (uint)bytes.Length); + WriteBytes(ref buf, ref bitPos, ref bitLength, bytes, 0, bytes.Length); } - internal static void WriteVariableUInt32(ref byte[] buf, ref int bitPos, uint value) + internal static void WriteVariableUInt32(ref byte[] buf, ref int bitPos, ref int bitLength, uint value) { uint remainingValue = value; while (remainingValue >= 0x80) { - Write(ref buf, ref bitPos, (byte)(remainingValue | 0x80)); + WriteByte(ref buf, ref bitPos, ref bitLength, (byte)(remainingValue | 0x80)); remainingValue >>= 7; } - Write(ref buf, ref bitPos, (byte)remainingValue); + WriteByte(ref buf, ref bitPos, ref bitLength, (byte)remainingValue); } - internal static void WriteRangedInteger(ref byte[] buf, ref int bitPos, int val, int min, int max) + internal static void WriteRangedInteger(ref byte[] buf, ref int bitPos, ref int bitLength, int val, int min, int max) { uint range = (uint)(max - min); int numberOfBits = NetUtility.BitsToHoldUInt(range); @@ -193,9 +207,10 @@ namespace Barotrauma.Networking uint rvalue = (uint)(val - min); NetBitWriter.WriteUInt32(rvalue, numberOfBits, buf, bitPos); bitPos += numberOfBits; + UpdateBitLength(ref bitLength, bitPos); } - internal static void WriteRangedSingle(ref byte[] buf, ref int bitPos, Single val, Single min, Single max, int numberOfBits) + internal static void WriteRangedSingle(ref byte[] buf, ref int bitPos, ref int bitLength, Single val, Single min, Single max, int numberOfBits) { float range = max - min; float unit = ((val - min) / range); @@ -205,13 +220,15 @@ namespace Barotrauma.Networking NetBitWriter.WriteUInt32((UInt32)(maxVal * unit), numberOfBits, buf, bitPos); bitPos += numberOfBits; + UpdateBitLength(ref bitLength, bitPos); } - internal static void WriteBytes(ref byte[] buf, ref int bitPos, byte[] val, int pos, int length) + internal static void WriteBytes(ref byte[] buf, ref int bitPos, ref int bitLength, byte[] val, int pos, int length) { EnsureBufferSize(ref buf, bitPos + length * 8); NetBitWriter.WriteBytes(val, pos, length, buf, bitPos); bitPos += length * 8; + UpdateBitLength(ref bitLength, bitPos); } internal static void EnsureBufferSize(ref byte[] buf, int numberOfBits) @@ -447,77 +464,77 @@ namespace Barotrauma.Networking public void WriteBoolean(bool val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteBoolean(ref buf, ref seekPos, ref lengthBits, val); } public void WritePadBits() { - MsgWriter.WritePadBits(ref buf, ref seekPos); + MsgWriter.WritePadBits(ref buf, ref seekPos, ref lengthBits); } public void WriteByte(byte val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteByte(ref buf, ref seekPos, ref lengthBits, val); } public void WriteUInt16(UInt16 val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteUInt16(ref buf, ref seekPos, ref lengthBits, val); } public void WriteInt16(Int16 val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteInt16(ref buf, ref seekPos, ref lengthBits, val); } public void WriteUInt32(UInt32 val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteUInt32(ref buf, ref seekPos, ref lengthBits, val); } public void WriteInt32(Int32 val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteInt32(ref buf, ref seekPos, ref lengthBits, val); } public void WriteUInt64(UInt64 val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteUInt64(ref buf, ref seekPos, ref lengthBits, val); } public void WriteInt64(Int64 val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteInt64(ref buf, ref seekPos, ref lengthBits, val); } public void WriteSingle(Single val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteSingle(ref buf, ref seekPos, ref lengthBits, val); } public void WriteDouble(Double val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteDouble(ref buf, ref seekPos, ref lengthBits, val); } public void WriteColorR8G8B8(Color val) { - MsgWriter.WriteColorR8G8B8(ref buf, ref seekPos, val); + MsgWriter.WriteColorR8G8B8(ref buf, ref seekPos, ref lengthBits, val); } public void WriteColorR8G8B8A8(Color val) { - MsgWriter.WriteColorR8G8B8A8(ref buf, ref seekPos, val); + MsgWriter.WriteColorR8G8B8A8(ref buf, ref seekPos, ref lengthBits, val); } public void WriteVariableUInt32(UInt32 val) { - MsgWriter.WriteVariableUInt32(ref buf, ref seekPos, val); + MsgWriter.WriteVariableUInt32(ref buf, ref seekPos, ref lengthBits, val); } public void WriteString(String val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteString(ref buf, ref seekPos, ref lengthBits, val); } public void WriteIdentifier(Identifier val) @@ -527,17 +544,17 @@ namespace Barotrauma.Networking public void WriteRangedInteger(int val, int min, int max) { - MsgWriter.WriteRangedInteger(ref buf, ref seekPos, val, min, max); + MsgWriter.WriteRangedInteger(ref buf, ref seekPos, ref lengthBits, val, min, max); } public void WriteRangedSingle(Single val, Single min, Single max, int bitCount) { - MsgWriter.WriteRangedSingle(ref buf, ref seekPos, val, min, max, bitCount); + MsgWriter.WriteRangedSingle(ref buf, ref seekPos, ref lengthBits, val, min, max, bitCount); } public void WriteBytes(byte[] val, int startPos, int length) { - MsgWriter.WriteBytes(ref buf, ref seekPos, val, startPos, length); + MsgWriter.WriteBytes(ref buf, ref seekPos, ref lengthBits, val, startPos, length); } public byte[] PrepareForSending(bool compressPastThreshold, out bool isCompressed, out int length) @@ -814,77 +831,77 @@ namespace Barotrauma.Networking public void WriteBoolean(bool val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteBoolean(ref buf, ref seekPos, ref lengthBits, val); } public void WritePadBits() { - MsgWriter.WritePadBits(ref buf, ref seekPos); + MsgWriter.WritePadBits(ref buf, ref seekPos, ref lengthBits); } public void WriteByte(byte val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteByte(ref buf, ref seekPos, ref lengthBits, val); } public void WriteUInt16(UInt16 val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteUInt16(ref buf, ref seekPos, ref lengthBits, val); } public void WriteInt16(Int16 val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteInt16(ref buf, ref seekPos, ref lengthBits, val); } public void WriteUInt32(UInt32 val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteUInt32(ref buf, ref seekPos, ref lengthBits, val); } public void WriteInt32(Int32 val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteInt32(ref buf, ref seekPos, ref lengthBits, val); } public void WriteUInt64(UInt64 val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteUInt64(ref buf, ref seekPos, ref lengthBits, val); } public void WriteInt64(Int64 val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteInt64(ref buf, ref seekPos, ref lengthBits, val); } public void WriteSingle(Single val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteSingle(ref buf, ref seekPos, ref lengthBits, val); } public void WriteDouble(Double val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteDouble(ref buf, ref seekPos, ref lengthBits, val); } public void WriteColorR8G8B8(Color val) { - MsgWriter.WriteColorR8G8B8(ref buf, ref seekPos, val); + MsgWriter.WriteColorR8G8B8(ref buf, ref seekPos, ref lengthBits, val); } public void WriteColorR8G8B8A8(Color val) { - MsgWriter.WriteColorR8G8B8A8(ref buf, ref seekPos, val); + MsgWriter.WriteColorR8G8B8A8(ref buf, ref seekPos, ref lengthBits, val); } public void WriteVariableUInt32(UInt32 val) { - MsgWriter.WriteVariableUInt32(ref buf, ref seekPos, val); + MsgWriter.WriteVariableUInt32(ref buf, ref seekPos, ref lengthBits, val); } public void WriteString(String val) { - MsgWriter.Write(ref buf, ref seekPos, val); + MsgWriter.WriteString(ref buf, ref seekPos, ref lengthBits, val); } public void WriteIdentifier(Identifier val) @@ -894,17 +911,17 @@ namespace Barotrauma.Networking public void WriteRangedInteger(int val, int min, int max) { - MsgWriter.WriteRangedInteger(ref buf, ref seekPos, val, min, max); + MsgWriter.WriteRangedInteger(ref buf, ref seekPos, ref lengthBits, val, min, max); } public void WriteRangedSingle(Single val, Single min, Single max, int bitCount) { - MsgWriter.WriteRangedSingle(ref buf, ref seekPos, val, min, max, bitCount); + MsgWriter.WriteRangedSingle(ref buf, ref seekPos, ref lengthBits, val, min, max, bitCount); } public void WriteBytes(byte[] val, int startPos, int length) { - MsgWriter.WriteBytes(ref buf, ref seekPos, val, startPos, length); + MsgWriter.WriteBytes(ref buf, ref seekPos, ref lengthBits, val, startPos, length); } public bool ReadBoolean() diff --git a/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/NetworkPeerStructs.cs b/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/NetworkPeerStructs.cs index 0a042c27f..2ef9e10ec 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/NetworkPeerStructs.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Networking/Primitives/NetworkPeerStructs.cs @@ -286,8 +286,13 @@ namespace Barotrauma.Networking } public DateTime InstallTime => cachedDateTime ??= DateTime.UtcNow + TimeSpan.FromSeconds(InstallTimeDiffInSeconds); - public RegularPackage? RegularPackage => ContentPackageManager.RegularPackages.FirstOrDefault(p => p.Hash.Equals(Hash)); - public CorePackage? CorePackage => ContentPackageManager.CorePackages.FirstOrDefault(p => p.Hash.Equals(Hash)); + public RegularPackage? RegularPackage => + ContentPackageManager.RegularPackages.FirstOrDefault(p => p.Name.Equals(Name) && p.Hash.Equals(Hash)) ?? + ContentPackageManager.RegularPackages.FirstOrDefault(p => p.Hash.Equals(Hash)); + + public CorePackage? CorePackage => + ContentPackageManager.CorePackages.FirstOrDefault(p => p.Name.Equals(Name) && p.Hash.Equals(Hash)) ?? + ContentPackageManager.CorePackages.FirstOrDefault(p => p.Hash.Equals(Hash)); public ContentPackage? ContentPackage => (ContentPackage?)RegularPackage ?? CorePackage; public ServerContentPackage() { } diff --git a/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs b/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs index 4b625e9e8..10c7c7527 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs @@ -1717,19 +1717,7 @@ namespace Barotrauma } float spread = Rand.Range(-chosenItemSpawnInfo.AimSpreadRad, chosenItemSpawnInfo.AimSpreadRad); float rotation = chosenItemSpawnInfo.RotationRad; - Vector2 worldPos; - if (sourceBody != null) - { - worldPos = sourceBody.Position; - if (user?.Submarine != null) - { - worldPos += user.Submarine.Position; - } - } - else - { - worldPos = entity.WorldPosition; - } + Vector2 spawnPos = sourceBody != null ? sourceBody.SimPosition : entity.SimPosition; switch (chosenItemSpawnInfo.RotationType) { case ItemSpawnInfo.SpawnRotationType.Fixed: @@ -1743,7 +1731,7 @@ namespace Barotrauma } break; case ItemSpawnInfo.SpawnRotationType.Target: - rotation = MathUtils.VectorToAngle(entity.WorldPosition - worldPos); + rotation = MathUtils.VectorToAngle(entity.SimPosition - spawnPos); break; case ItemSpawnInfo.SpawnRotationType.Limb: if (sourceBody != null) @@ -1787,10 +1775,7 @@ namespace Barotrauma rotation += spread; if (projectile != null) { - projectile.Shoot(user, - ConvertUnits.ToSimUnits(worldPos), - ConvertUnits.ToSimUnits(worldPos), - rotation, + projectile.Shoot(user, spawnPos, spawnPos, rotation, ignoredBodies: user?.AnimController.Limbs.Where(l => !l.IsSevered).Select(l => l.body.FarseerBody).ToList(), createNetworkEvent: true); } else if (newItem.body != null) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Upgrades/UpgradePrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Upgrades/UpgradePrefab.cs index f66cdcfe5..095b1bd38 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Upgrades/UpgradePrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Upgrades/UpgradePrefab.cs @@ -43,9 +43,9 @@ namespace Barotrauma } } - public int GetBuyprice(int level, Location? location = null) + public int GetBuyPrice(int level, Location? location = null) { - int maxLevel = Prefab.MaxLevel; + int maxLevel = Prefab.GetMaxLevelForCurrentSub(); if (level > maxLevel) { maxLevel = level; } @@ -292,16 +292,10 @@ namespace Barotrauma onRemoveOverrideFile: null ); - private readonly int maxLevel; - - public int MaxLevel - { - get - { - Submarine? sub = GameMain.GameSession?.Submarine ?? Submarine.MainSub; - return sub is { Info: var info } ? GetMaxLevel(info) : maxLevel; - } - } + /// + /// Maximum upgrade level without taking submarine tier or class restrictions into account + /// + public readonly int MaxLevel; public LocalizedString Name { get; } @@ -343,7 +337,7 @@ namespace Barotrauma { Name = element.GetAttributeString("name", string.Empty)!; Description = element.GetAttributeString("description", string.Empty)!; - maxLevel = element.GetAttributeInt("maxlevel", 1); + MaxLevel = element.GetAttributeInt("maxlevel", 1); SuppressWarnings = element.GetAttributeBool("supresswarnings", false); HideInMenus = element.GetAttributeBool("hideinmenus", false); SourceElement = element; @@ -428,9 +422,21 @@ namespace Barotrauma .ToImmutableHashSet() ?? ImmutableHashSet.Empty; } + /// + /// Returns the maximum upgrade level for the current sub, taking tier and class restrictions into account + /// + public int GetMaxLevelForCurrentSub() + { + Submarine? sub = GameMain.GameSession?.Submarine ?? Submarine.MainSub; + return sub is { Info: var info } ? GetMaxLevel(info) : MaxLevel; + } + + /// + /// Returns the maximum upgrade level for the specified sub, taking tier and class restrictions into account + /// public int GetMaxLevel(SubmarineInfo info) { - int level = maxLevel; + int level = MaxLevel; foreach (UpgradeMaxLevelMod mod in MaxLevelsMods) { diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index 8e9e8e7ac..3c57a94c3 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,3 +1,54 @@ + +--------------------------------------------------------------------------------------------------------- +v0.19.14.0 +--------------------------------------------------------------------------------------------------------- + +- Fixed submarine upgrades getting clamped to the maximum of that upgrade between rounds, disregarding class/tier bonuses. + +--------------------------------------------------------------------------------------------------------- +v0.19.13.0 +--------------------------------------------------------------------------------------------------------- + +- Fixed "failed to find the end of the bit field after 100 reads" error when trying to join a server that has a large number of mods enabled. +- Fixed "Tandem Fire" talent causing a crash due to the changes in the previous version. + +--------------------------------------------------------------------------------------------------------- +v0.19.12.0 +--------------------------------------------------------------------------------------------------------- + +- Fixed submarine upgrades getting lost if you switch to a lower-tier sub that can't have as many levels of upgrades as the current sub, and then back again. +- Fixed some monster events not being as common/uncommon as intended. In more technical terms (which may be of interest to modders): the commonness defined as an attribute of an EventSet did nothing, making the event default to a commonness of 1. The commonnesses defined for specific level types worked correctly. +- Fixed clients getting stuck in a non-functional lobby if they happen to disconnect or get kicked back to the lobby at a specific point when loading a new round. +- Fixed large turret hardpoint origin being off, causing turrets installed on a large hardpoint to be misaligned. +- Attempt to fix crashing when disconnecting from the server you're hosting. +- Fixed Ctrl+Shift+S shortcut (quicksave) not working in the sub editor. +- Fixed toolbelts and storage containers in old subs going inside toolbelts. +- Fixed submarine tier resetting to default when reopening the sub editor's save dialog. +- Fixed sub editor not taking filename case into account when saving an existing sub: if you'd try to save the file with a different filename case, it'd ask about overwriting the existing sub, but save it as a new file even if you opt to overwrite. +- Fixes to Herja room names (use Engineering, Gunnery compartment, etc. labels), add camera to the front, with a periscope for the captain. +- Fixed non-purchaseable talent items not being available as extra cargo. +- Sorted extra cargo alphabetically + added a filter box. +- Fixed taking items that spawned inside another item (e.g. tanks in a diving mask) from NPCs spawned by an event not counting as stealing. +- Fixed characters falling off ladders when using aimable tools. +- Fixed money gain/lose popups no longer showing in the campaign. +- Fixed inability to manage the campaign if there's no-one with permissions alive. Previously we allowed anyone to manage the campaign if there's no-one with permissions present in the server, but that's not enough, because the players with permissions can't end the round if they're dead. Now if there's no-one with permissions alive, anyone is allowed to manage the campaign. +- If Select and Deselect have been bound to the same key, the deselect input is ignored when interacting with another item than the selected one. Prevents e.g. falling off ladders when trying to open a hatch when both Select and Deselect have been bound to E. +- Made it possible to enter a hostname (e.g. someserver.com) in the direct join prompt. +- Adjusted the size of the submarine list elements in the server lobby to reduce the amount of empty space on large resolutions. +- Fixed event texts for the "scan ruin" mission being in an incorrect language. +- Attachable items cannot be attached inside walls. +- Fixed distance at which you can attach items being slightly longer than the interact distance, making it possible to attach items out of reach. +- Fixed inability to turn when you're dual wielding melee weapons and attacking continuously. +- Fixed inability to cancel deconstruction if there's non-deconstructible items in the queue. +- Fixed local copy of a mod you're publishing not using the version number you've entered in the publish menu. +- Fixed crashing when trying to open the tab menu's character tab with a character who has no personality trait (may happen e.g. if you use a mod that adds custom personality traits and try to play that save without the mod). +- Fixed sourcerect issue in alien generator + decorative sprite not disappearing when the fuel rod is taken out. +- Fixed corrupted mods causing a nullref exception when autodetecting required mods in the sub editor. +- Fixed minerals not disappearing from mineral scanner if they get detached by something else than a character picking them up (e.g. by the destructible ice wall they're on breaking). +- Fixed event-specific metal crate deconstructing to steel. +- Fixed inability to join servers that have enabled multiple mods with identical content. +- Fixed tandem fire not working if there's a character between you and the other character on a periscope. + --------------------------------------------------------------------------------------------------------- v0.19.11.0 --------------------------------------------------------------------------------------------------------- diff --git a/Barotrauma/BarotraumaTest/INetSerializableStructTests.cs b/Barotrauma/BarotraumaTest/INetSerializableStructTests.cs index e319baede..fdd87cc18 100644 --- a/Barotrauma/BarotraumaTest/INetSerializableStructTests.cs +++ b/Barotrauma/BarotraumaTest/INetSerializableStructTests.cs @@ -29,7 +29,17 @@ namespace TestProject [Fact] public void TestBitField() { + // 0-length bitfield test + SerializeDeserializeBitField(Array.Empty()); + + // Normal bitfield test Prop.ForAll(SerializeDeserializeBitField).VerboseCheckThrowOnFailure(); + + // Large bitfield test + Prop.ForAll( + Arb.Generate().Resize(1000).Where(arr => arr.Length >= 800) + .ToArbitrary(), + SerializeDeserializeBitField).VerboseCheckThrowOnFailure(); } [Fact] @@ -278,7 +288,7 @@ namespace TestProject private static void SerializeDeserializeBitField(bool[] arg) { ReadWriteMessage msg = new ReadWriteMessage(); - IWritableBitField bitFieldWrite = new WriteOnlyBitField(); + WriteOnlyBitField bitFieldWrite = new WriteOnlyBitField(); foreach (bool b in arg) { @@ -288,7 +298,7 @@ namespace TestProject bitFieldWrite.WriteToMessage(msg); msg.BitPosition = 0; - IReadableBitField bitFieldRead = new ReadOnlyBitField(msg); + ReadOnlyBitField bitFieldRead = new ReadOnlyBitField(msg); foreach (bool b in arg) { From a6ee9eadf3eda570e2bd521c9ceeed01c21d05a1 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Thu, 20 Oct 2022 17:06:20 +0300 Subject: [PATCH 4/4] Update bug_report.yml --- .github/ISSUE_TEMPLATE/bug_report.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index a8248d51d..a497ba770 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -52,8 +52,7 @@ body: label: Version description: Which version of the game did the bug happen in? You can see the current version number in the bottom left corner of your screen in the main menu. options: - - 0.19.11.0 - - 0.19.13.0 (Unstable) + - 0.19.14.0 - Other validations: required: true