From d6a886bf6b4b4c36556f64905c83644e0fb59b53 Mon Sep 17 00:00:00 2001 From: Regalis11 Date: Wed, 21 Jun 2023 16:14:31 +0300 Subject: [PATCH 1/2] v1.0.21.0 (summer patch hotfix) --- .../Characters/CharacterNetworking.cs | 31 ++++++++- .../BarotraumaClient/ClientSource/GUI/GUI.cs | 15 ++++- .../ClientSource/GUI/HUDLayoutSettings.cs | 5 +- .../ClientSource/GameSession/CrewManager.cs | 1 + .../ClientSource/Map/Lights/ConvexHull.cs | 2 +- .../ClientSource/Map/Lights/LightManager.cs | 12 ++-- .../ClientSource/Map/Lights/LightSource.cs | 35 ++++++---- .../BarotraumaClient/LinuxClient.csproj | 2 +- Barotrauma/BarotraumaClient/MacClient.csproj | 2 +- .../BarotraumaClient/WindowsClient.csproj | 2 +- .../BarotraumaServer/LinuxServer.csproj | 2 +- Barotrauma/BarotraumaServer/MacServer.csproj | 2 +- .../Characters/CharacterNetworking.cs | 19 ++++-- .../BarotraumaServer/WindowsServer.csproj | 2 +- .../Characters/AI/AIController.cs | 3 - .../Characters/AI/EnemyAIController.cs | 12 ---- .../AI/Objectives/AIObjectiveFixLeak.cs | 3 +- .../AI/Objectives/AIObjectiveGoTo.cs | 29 +++++---- .../AI/Objectives/AIObjectiveRepairItem.cs | 3 +- .../AI/Objectives/AIObjectiveRescue.cs | 2 +- .../AI/Objectives/AIObjectiveRescueAll.cs | 2 +- .../SharedSource/Characters/AI/PetBehavior.cs | 41 ++++++------ .../Health/Afflictions/AfflictionPrefab.cs | 54 ++++++++++----- .../Characters/Health/CharacterHealth.cs | 2 +- .../SharedSource/GameSession/GameSession.cs | 2 +- .../Components/Holdable/LevelResource.cs | 2 +- .../SharedSource/Map/Levels/LevelData.cs | 4 +- .../Map/Outposts/OutpostGenerator.cs | 65 ++++++++++++------- Barotrauma/BarotraumaShared/changelog.txt | 21 +++++- 29 files changed, 241 insertions(+), 136 deletions(-) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs index 8cd302262..8be87d764 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs @@ -201,9 +201,9 @@ namespace Barotrauma keys[(int)InputType.Use].Held = useInput; keys[(int)InputType.Use].SetState(false, useInput); + bool crouching = msg.ReadBoolean(); if (AnimController is HumanoidAnimController) { - bool crouching = msg.ReadBoolean(); keys[(int)InputType.Crouch].Held = crouching; keys[(int)InputType.Crouch].SetState(false, crouching); } @@ -269,7 +269,34 @@ namespace Barotrauma if (readStatus) { ReadStatus(msg); - AIController?.ClientRead(msg); + bool isEnemyAi = msg.ReadBoolean(); + if (isEnemyAi) + { + byte aiState = msg.ReadByte(); + if (AIController is EnemyAIController enemyAi) + { + enemyAi.State = (AIState)aiState; + } + else + { + DebugConsole.AddWarning($"Received enemy AI data for a character with no {nameof(EnemyAIController)}. Ignoring..."); + } + bool isPet = msg.ReadBoolean(); + if (isPet) + { + byte happiness = msg.ReadByte(); + byte hunger = msg.ReadByte(); + if ((AIController as EnemyAIController)?.PetBehavior is PetBehavior petBehavior) + { + petBehavior.Happiness = (float)happiness / byte.MaxValue * petBehavior.MaxHappiness; + petBehavior.Hunger = (float)hunger / byte.MaxValue * petBehavior.MaxHunger; + } + else + { + DebugConsole.AddWarning($"Received pet AI data for a character with no {nameof(PetBehavior)}. Ignoring..."); + } + } + } } msg.ReadPadBits(); diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUI.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUI.cs index 838c2ee27..c235f0a35 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUI.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUI.cs @@ -111,7 +111,7 @@ namespace Barotrauma /// public static float AspectRatioAdjustment => HorizontalAspectRatio < 1.4f ? (1.0f - (1.4f - HorizontalAspectRatio)) : 1.0f; - public static bool IsUltrawide => HorizontalAspectRatio > 2.0f; + public static bool IsUltrawide => HorizontalAspectRatio > 2.3f; public static int UIWidth { @@ -2438,13 +2438,15 @@ namespace Barotrauma var pauseMenuInner = new GUIFrame(new RectTransform(new Vector2(0.13f, 0.3f), PauseMenu.RectTransform, Anchor.Center) { MinSize = new Point(250, 300) }); - var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.7f, 0.6f), pauseMenuInner.RectTransform, Anchor.Center)) + float padding = 0.06f; + + var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.7f, 0.8f), pauseMenuInner.RectTransform, Anchor.BottomCenter) { RelativeOffset = new Vector2(0.0f, padding) }) { Stretch = true, RelativeSpacing = 0.05f }; - new GUIButton(new RectTransform(new Vector2(0.1f, 0.1f), pauseMenuInner.RectTransform, Anchor.TopRight) { AbsoluteOffset = new Point((int)(15 * GUI.Scale)) }, + new GUIButton(new RectTransform(new Vector2(0.1f, 0.07f), pauseMenuInner.RectTransform, Anchor.TopRight) { RelativeOffset = new Vector2(padding) }, "", style: "GUIBugButton") { IgnoreLayoutGroups = true, @@ -2520,6 +2522,13 @@ namespace Barotrauma } GUITextBlock.AutoScaleAndNormalize(buttonContainer.Children.Where(c => c is GUIButton).Select(c => ((GUIButton)c).TextBlock)); + //scale to ensure there's enough room for all the buttons + pauseMenuInner.RectTransform.MinSize = new Point( + pauseMenuInner.RectTransform.MinSize.X, + Math.Max( + (int)(buttonContainer.Children.Sum(c => c.Rect.Height + buttonContainer.Rect.Height * buttonContainer.RelativeSpacing)), + pauseMenuInner.RectTransform.MinSize.X)); + } void CreateButton(string textTag, GUIComponent parent, Action action, string verificationTextTag = null) diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/HUDLayoutSettings.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/HUDLayoutSettings.cs index 8442731b2..f6bb9831e 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/HUDLayoutSettings.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/HUDLayoutSettings.cs @@ -160,8 +160,9 @@ namespace Barotrauma int crewAreaY = ButtonAreaTop.Bottom + Padding; int crewAreaHeight = ObjectiveAnchor.Top - Padding - crewAreaY; - float crewAreaWidthMultiplier = GUI.IsUltrawide ? GUI.HorizontalAspectRatio : 1.0f; - CrewArea = new Rectangle(Padding, crewAreaY, (int)(Math.Max(400 * GUI.Scale, 220) * crewAreaWidthMultiplier), crewAreaHeight); + CrewArea = new Rectangle(Padding, crewAreaY, + (int)MathHelper.Clamp(400 * GUI.Scale, 220, GameMain.GraphicsHeight * 0.4f), + crewAreaHeight); InventoryAreaLower = new Rectangle(ChatBoxArea.Right + Padding * 7, inventoryTopY, GameMain.GraphicsWidth - Padding * 9 - ChatBoxArea.Width, GameMain.GraphicsHeight - inventoryTopY); int healthWindowWidth = (int)(GameMain.GraphicsWidth * 0.5f); diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/CrewManager.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/CrewManager.cs index eddd741f2..b38ef3af7 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/CrewManager.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/CrewManager.cs @@ -95,6 +95,7 @@ namespace Barotrauma { CanBeFocused = false }; + crewArea.RectTransform.NonScaledSize = HUDLayoutSettings.CrewArea.Size; // AbsoluteOffset is set in UpdateProjectSpecific based on crewListOpenState crewList = new GUIListBox(new RectTransform(Vector2.One, crewArea.RectTransform), style: null, isScrollBarOnDefaultSide: false) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/ConvexHull.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/ConvexHull.cs index 7faf33912..82ad83280 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/ConvexHull.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/ConvexHull.cs @@ -561,7 +561,7 @@ namespace Barotrauma.Lights if (IsSegmentFacing(losVertices[0].Pos, losVertices[1].Pos, lightSourcePos)) { - Array.Reverse(ShadowVertices); + Array.Reverse(ShadowVertices, 0, ShadowVertexCount); } CalculateLosPenumbraVertices(lightSourcePos); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightManager.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightManager.cs index e846bfa4f..e179ffe94 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightManager.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightManager.cs @@ -482,7 +482,7 @@ namespace Barotrauma.Lights { foreach (MapEntity e in (Submarine.VisibleEntities ?? MapEntity.mapEntityList)) { - if (e is Item item && item.GetComponent() is Wire wire) + if (e is Item item && !item.HiddenInGame && item.GetComponent() is Wire wire) { wire.DebugDraw(spriteBatch, alpha: 0.4f); } @@ -719,6 +719,7 @@ namespace Barotrauma.Lights { foreach (var ch in convexHulls) { + if (!ch.Enabled) { continue; } Vector2 currentViewPos = pos; Vector2 defaultViewPos = ViewTarget.DrawPosition; if (ch.ParentEntity?.Submarine != null) @@ -742,10 +743,13 @@ namespace Barotrauma.Lights { if (!convexHull.Enabled || !convexHull.Intersects(camView)) { continue; } - Vector2 relativeLightPos = pos; - if (convexHull.ParentEntity?.Submarine != null) { relativeLightPos -= convexHull.ParentEntity.Submarine.Position; } + Vector2 relativeViewPos = pos; + if (convexHull.ParentEntity?.Submarine != null) + { + relativeViewPos -= convexHull.ParentEntity.Submarine.DrawPosition; + } - convexHull.CalculateLosVertices(relativeLightPos); + convexHull.CalculateLosVertices(relativeViewPos); for (int i = 0; i < convexHull.ShadowVertexCount; i++) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightSource.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightSource.cs index 9574a3d6a..20c9eb63f 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightSource.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/Lights/LightSource.cs @@ -206,6 +206,8 @@ namespace Barotrauma.Lights private readonly List convexHullsInRange; + private readonly HashSet visibleConvexHulls = new HashSet(); + public Texture2D texture; public SpriteEffects LightSpriteEffect; @@ -717,6 +719,8 @@ namespace Barotrauma.Lights public void RayCastTask(Vector2 drawPos, float rotation) { + visibleConvexHulls.Clear(); + Vector2 drawOffset = Vector2.Zero; float boundsExtended = TextureRange; if (OverrideLightTexture != null) @@ -904,17 +908,12 @@ namespace Barotrauma.Lights bool isPoint1 = MathUtils.LineToPointDistanceSquared(seg1.Start.WorldPos, seg1.End.WorldPos, p.WorldPos) < 25.0f; bool isPoint2 = MathUtils.LineToPointDistanceSquared(seg2.Start.WorldPos, seg2.End.WorldPos, p.WorldPos) < 25.0f; + bool markAsVisible = false; if (isPoint1 && isPoint2) { //hit at the current segmentpoint -> place the segmentpoint into the list verts.Add(p.WorldPos); - - foreach (ConvexHullList hullList in convexHullsInRange) - { - hullList.IsHidden.Remove(p.ConvexHull); - hullList.IsHidden.Remove(seg1.ConvexHull); - hullList.IsHidden.Remove(seg2.ConvexHull); - } + markAsVisible = true; } else if (intersection1.index != intersection2.index) { @@ -922,13 +921,13 @@ namespace Barotrauma.Lights //we definitely want to generate new geometry here verts.Add(isPoint1 ? p.WorldPos : intersection1.pos); verts.Add(isPoint2 ? p.WorldPos : intersection2.pos); - - foreach (ConvexHullList hullList in convexHullsInRange) - { - hullList.IsHidden.Remove(p.ConvexHull); - hullList.IsHidden.Remove(seg1.ConvexHull); - hullList.IsHidden.Remove(seg2.ConvexHull); - } + markAsVisible = true; + } + if (markAsVisible) + { + visibleConvexHulls.Add(p.ConvexHull); + visibleConvexHulls.Add(seg1.ConvexHull); + visibleConvexHulls.Add(seg2.ConvexHull); } //if neither of the conditions above are met, we just assume //that the raycasts both resulted on the same segment @@ -1396,6 +1395,14 @@ namespace Barotrauma.Lights return; } + foreach (var visibleConvexHull in visibleConvexHulls) + { + foreach (var convexHullList in convexHullsInRange) + { + convexHullList.IsHidden.Remove(visibleConvexHull); + } + } + CalculateLightVertices(verts); LastRecalculationTime = (float)Timing.TotalTime; diff --git a/Barotrauma/BarotraumaClient/LinuxClient.csproj b/Barotrauma/BarotraumaClient/LinuxClient.csproj index 4b5dccfa1..0d5ab41b5 100644 --- a/Barotrauma/BarotraumaClient/LinuxClient.csproj +++ b/Barotrauma/BarotraumaClient/LinuxClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 1.0.20.1 + 1.0.21.0 Copyright © FakeFish 2018-2023 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/MacClient.csproj b/Barotrauma/BarotraumaClient/MacClient.csproj index 6d8354723..231ef9033 100644 --- a/Barotrauma/BarotraumaClient/MacClient.csproj +++ b/Barotrauma/BarotraumaClient/MacClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 1.0.20.1 + 1.0.21.0 Copyright © FakeFish 2018-2023 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/WindowsClient.csproj b/Barotrauma/BarotraumaClient/WindowsClient.csproj index cec27c949..6ec5a61ad 100644 --- a/Barotrauma/BarotraumaClient/WindowsClient.csproj +++ b/Barotrauma/BarotraumaClient/WindowsClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 1.0.20.1 + 1.0.21.0 Copyright © FakeFish 2018-2023 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaServer/LinuxServer.csproj b/Barotrauma/BarotraumaServer/LinuxServer.csproj index f1b4c157c..b1013bee7 100644 --- a/Barotrauma/BarotraumaServer/LinuxServer.csproj +++ b/Barotrauma/BarotraumaServer/LinuxServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 1.0.20.1 + 1.0.21.0 Copyright © FakeFish 2018-2023 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/MacServer.csproj b/Barotrauma/BarotraumaServer/MacServer.csproj index 592c084d0..6faa3fa7e 100644 --- a/Barotrauma/BarotraumaServer/MacServer.csproj +++ b/Barotrauma/BarotraumaServer/MacServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 1.0.20.1 + 1.0.21.0 Copyright © FakeFish 2018-2023 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs index c597f599e..38598bd86 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs @@ -376,10 +376,9 @@ namespace Barotrauma tempBuffer.WriteBoolean(aiming); tempBuffer.WriteBoolean(shoot); tempBuffer.WriteBoolean(use); - if (AnimController is HumanoidAnimController) - { - tempBuffer.WriteBoolean(((HumanoidAnimController)AnimController).Crouching); - } + + tempBuffer.WriteBoolean(AnimController is HumanoidAnimController { Crouching: true }); + tempBuffer.WriteBoolean(attack); Vector2 relativeCursorPos = cursorPosition - AimRefPosition; @@ -430,7 +429,17 @@ namespace Barotrauma if (writeStatus) { WriteStatus(tempBuffer); - AIController?.ServerWrite(tempBuffer); + tempBuffer.WriteBoolean(AIController is EnemyAIController); + if (AIController is EnemyAIController enemyAi) + { + tempBuffer.WriteByte((byte)enemyAi.State); + tempBuffer.WriteBoolean(enemyAi.PetBehavior is PetBehavior); + if (enemyAi.PetBehavior is PetBehavior petBehavior) + { + tempBuffer.WriteByte((byte)((petBehavior.Happiness / petBehavior.MaxHappiness) * byte.MaxValue)); + tempBuffer.WriteByte((byte)((petBehavior.Hunger / petBehavior.MaxHunger) * byte.MaxValue)); + } + } HealthUpdatePending = false; } } diff --git a/Barotrauma/BarotraumaServer/WindowsServer.csproj b/Barotrauma/BarotraumaServer/WindowsServer.csproj index 4c66ef099..ea593140b 100644 --- a/Barotrauma/BarotraumaServer/WindowsServer.csproj +++ b/Barotrauma/BarotraumaServer/WindowsServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 1.0.20.1 + 1.0.21.0 Copyright © FakeFish 2018-2023 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AIController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AIController.cs index a5069b8f3..f079663fc 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AIController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/AIController.cs @@ -521,8 +521,5 @@ namespace Barotrauma protected virtual void OnStateChanged(AIState from, AIState to) { } protected virtual void OnTargetChanged(AITarget previousTarget, AITarget newTarget) { } - - public virtual void ClientRead(IReadMessage msg) { } - public virtual void ServerWrite(IWriteMessage msg) { } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs index caa1b2919..908f6dcff 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs @@ -4055,18 +4055,6 @@ namespace Barotrauma } return null; } - - public override void ServerWrite(IWriteMessage msg) - { - msg.WriteByte((byte)State); - PetBehavior?.ServerWrite(msg); - } - - public override void ClientRead(IReadMessage msg) - { - State = (AIState)msg.ReadByte(); - PetBehavior?.ClientRead(msg); - } } //the "memory" of the Character diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFixLeak.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFixLeak.cs index f08a264c6..a1db6b5c1 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFixLeak.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveFixLeak.cs @@ -200,7 +200,8 @@ namespace Barotrauma Leak.linkedTo.Any(e => e is Hull h && (character.CurrentHull == h || h.linkedTo.Contains(character.CurrentHull))), endNodeFilter = IsSuitableEndNode, // The Go To objective can be abandoned if the leak is fixed (in which case we don't want to use the dialogue) - SpeakCannotReachCondition = () => !CheckObjectiveSpecific() + // Only report about contextual targets. + SpeakCannotReachCondition = () => isPriority && !CheckObjectiveSpecific() }, onAbandon: () => { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs index dfc1966bf..ecde45351 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveGoTo.cs @@ -223,23 +223,30 @@ namespace Barotrauma Hull targetHull = GetTargetHull(); if (!IsFollowOrder) { + // Abandon if going through unsafe paths or targeting unsafe hulls. bool isUnreachable = HumanAIController.UnreachableHulls.Contains(targetHull); if (!objectiveManager.CurrentObjective.IgnoreUnsafeHulls) { - if (HumanAIController.UnsafeHulls.Contains(targetHull)) + // Wait orders check this so that the bot temporarily leaves the unsafe hull. + // Non-orders (that are not set to ignore the unsafe hulls) abandon. In practice this means e.g. repair and clean up item subobjectives (of the looping parent objective). + // Other orders are only abandoned if the hull is unreachable, because the path is invalid or not found at all. + if (IsWaitOrder || !objectiveManager.HasOrders()) { - isUnreachable = true; - HumanAIController.AskToRecalculateHullSafety(targetHull); - } - else if (PathSteering?.CurrentPath != null) - { - foreach (WayPoint wp in PathSteering.CurrentPath.Nodes) + if (HumanAIController.UnsafeHulls.Contains(targetHull)) { - if (wp.CurrentHull == null) { continue; } - if (HumanAIController.UnsafeHulls.Contains(wp.CurrentHull)) + isUnreachable = true; + HumanAIController.AskToRecalculateHullSafety(targetHull); + } + else if (PathSteering?.CurrentPath != null) + { + foreach (WayPoint wp in PathSteering.CurrentPath.Nodes) { - isUnreachable = true; - HumanAIController.AskToRecalculateHullSafety(wp.CurrentHull); + if (wp.CurrentHull == null) { continue; } + if (HumanAIController.UnsafeHulls.Contains(wp.CurrentHull)) + { + isUnreachable = true; + HumanAIController.AskToRecalculateHullSafety(wp.CurrentHull); + } } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItem.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItem.cs index 9c06fb8b2..63533f1e1 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItem.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRepairItem.cs @@ -222,7 +222,8 @@ namespace Barotrauma { var objective = new AIObjectiveGoTo(Item, character, objectiveManager) { - TargetName = Item.Name + TargetName = Item.Name, + SpeakCannotReachCondition = () => isPriority }; if (repairTool != null) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescue.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescue.cs index cba0a97f4..eef63cd47 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescue.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescue.cs @@ -287,7 +287,7 @@ namespace Barotrauma if (affliction.Prefab == null) { throw new Exception("Affliction prefab was null"); } float bestSuitability = 0.0f; Item bestItem = null; - foreach (KeyValuePair treatmentSuitability in affliction.Prefab.TreatmentSuitability) + foreach (KeyValuePair treatmentSuitability in affliction.Prefab.TreatmentSuitabilities) { if (currentTreatmentSuitabilities.ContainsKey(treatmentSuitability.Key) && currentTreatmentSuitabilities[treatmentSuitability.Key] > bestSuitability) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescueAll.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescueAll.cs index 97ce2855f..9e3faff48 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescueAll.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/Objectives/AIObjectiveRescueAll.cs @@ -109,6 +109,7 @@ namespace Barotrauma foreach (Affliction affliction in allAfflictions) { if (affliction.Prefab.IsBuff) { continue; } + if (!affliction.Prefab.HasTreatments) { continue; } if (!ignoreTreatmentThreshold) { //other afflictions of the same type increase the "treatability" @@ -116,7 +117,6 @@ namespace Barotrauma float totalAfflictionStrength = character.CharacterHealth.GetTotalAdjustedAfflictionStrength(affliction); if (totalAfflictionStrength < affliction.Prefab.TreatmentThreshold) { continue; } } - if (affliction.Prefab.TreatmentSuitability.None(kvp => kvp.Value > 0)) { continue; } if (allAfflictions.Any(otherAffliction => affliction.Prefab.IgnoreTreatmentIfAfflictedBy.Contains(otherAffliction.Identifier))) { continue; } yield return affliction; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/PetBehavior.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/PetBehavior.cs index 4f64dac4d..8b9598c81 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/PetBehavior.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/PetBehavior.cs @@ -435,37 +435,34 @@ namespace Barotrauma spawnPoint ??= WayPoint.WayPointList.Where(wp => wp.SpawnType == SpawnType.Human && wp.Submarine?.Info.Type == SubmarineType.Player).GetRandomUnsynced(); spawnPos = spawnPoint?.WorldPosition ?? Submarine.MainSub.WorldPosition; } - var pet = Character.Create(speciesName, spawnPos, seed, spawnInitialItems: false); - var petBehavior = (pet?.AIController as EnemyAIController)?.PetBehavior; - if (petBehavior != null) + + var characterPrefab = CharacterPrefab.FindBySpeciesName(speciesName.ToIdentifier()); + if (characterPrefab == null) { - petBehavior.Owner = owner; - var petBehaviorElement = subElement.Element("petbehavior"); - if (petBehaviorElement != null) + DebugConsole.ThrowError($"Failed to load the pet \"{speciesName}\". Character prefab not found."); + continue; + } + var pet = Character.Create(characterPrefab, spawnPos, seed, spawnInitialItems: false); + if (pet != null) + { + var petBehavior = (pet.AIController as EnemyAIController)?.PetBehavior; + if (petBehavior != null) { - petBehavior.Hunger = petBehaviorElement.GetAttributeFloat("hunger", 50.0f); - petBehavior.Happiness = petBehaviorElement.GetAttributeFloat("happiness", 50.0f); + petBehavior.Owner = owner; + var petBehaviorElement = subElement.Element("petbehavior"); + if (petBehaviorElement != null) + { + petBehavior.Hunger = petBehaviorElement.GetAttributeFloat("hunger", 50.0f); + petBehavior.Happiness = petBehaviorElement.GetAttributeFloat("happiness", 50.0f); + } } } - var inventoryElement = subElement.Element("inventory"); if (inventoryElement != null) { pet.SpawnInventoryItems(pet.Inventory, inventoryElement.FromPackage(null)); - } + } } } - - public void ServerWrite(IWriteMessage msg) - { - msg.WriteRangedSingle(Happiness, 0.0f, MaxHappiness, 8); - msg.WriteRangedSingle(Hunger, 0.0f, MaxHunger, 8); - } - - public void ClientRead(IReadMessage msg) - { - Happiness = msg.ReadRangedSingle(0.0f, MaxHappiness, 8); - Hunger = msg.ReadRangedSingle(0.0f, MaxHunger, 8); - } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionPrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionPrefab.cs index 3b65cc320..76a771c27 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionPrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/Afflictions/AfflictionPrefab.cs @@ -7,6 +7,7 @@ using System.Xml.Linq; using Barotrauma.Extensions; using System.Collections.Immutable; using Barotrauma.Items.Components; +using System.Linq; namespace Barotrauma { @@ -841,20 +842,16 @@ namespace Barotrauma /// public readonly Sprite AfflictionOverlay; - public IEnumerable> TreatmentSuitability + public ImmutableDictionary TreatmentSuitabilities { - get - { - foreach (var itemPrefab in ItemPrefab.Prefabs) - { - float suitability = itemPrefab.GetTreatmentSuitability(Identifier) + itemPrefab.GetTreatmentSuitability(AfflictionType); - if (!MathUtils.NearlyEqual(suitability, 0.0f)) - { - yield return new KeyValuePair(itemPrefab.Identifier, suitability); - } - } - } - } + get; + private set; + } = new Dictionary().ToImmutableDictionary(); + + /// + /// Can this affliction be treated with some item? + /// + public bool HasTreatments { get; private set; } public AfflictionPrefab(ContentXElement element, AfflictionsFile file, Type type) : base(file, element.GetAttributeIdentifier("identifier", "")) { @@ -974,6 +971,22 @@ namespace Barotrauma constructor = type.GetConstructor(new[] { typeof(AfflictionPrefab), typeof(float) }); } + private void RefreshTreatmentSuitabilities() + { + var newTreatmentSuitabilities = new Dictionary(); + + foreach (var itemPrefab in ItemPrefab.Prefabs) + { + float suitability = itemPrefab.GetTreatmentSuitability(Identifier) + itemPrefab.GetTreatmentSuitability(AfflictionType); + if (!MathUtils.NearlyEqual(suitability, 0.0f)) + { + newTreatmentSuitabilities.TryAdd(itemPrefab.Identifier, suitability); + } + } + HasTreatments = newTreatmentSuitabilities.Any(kvp => kvp.Value > 0); + TreatmentSuitabilities = newTreatmentSuitabilities.ToImmutableDictionary(); + } + public LocalizedString GetDescription(float strength, Description.TargetType targetType) { foreach (var description in Descriptions) @@ -993,9 +1006,16 @@ namespace Barotrauma return defaultDescription; } - public static void LoadAllEffects() + /// + /// Should be called before each round: loads all StatusEffects and refreshes treatment suitabilities. + /// + public static void LoadAllEffectsAndTreatmentSuitabilities() { - Prefabs.ForEach(p => p.LoadEffects()); + foreach (var prefab in Prefabs) + { + prefab.RefreshTreatmentSuitabilities(); + prefab.LoadEffects(); + } } public static void ClearAllEffects() @@ -1003,7 +1023,7 @@ namespace Barotrauma Prefabs.ForEach(p => p.ClearEffects()); } - public void LoadEffects() + private void LoadEffects() { ClearEffects(); foreach (var subElement in configElement.Elements()) @@ -1032,7 +1052,7 @@ namespace Barotrauma } } - public void ClearEffects() + private void ClearEffects() { effects.Clear(); periodicEffects.Clear(); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs index 95dad7ad3..7f0ad42ad 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs @@ -1136,7 +1136,7 @@ namespace Barotrauma } } - foreach (KeyValuePair treatment in affliction.Prefab.TreatmentSuitability) + foreach (KeyValuePair treatment in affliction.Prefab.TreatmentSuitabilities) { float suitability = treatment.Value * strength; if (treatment.Value > strength) diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs index 7c7c9e453..4e0370674 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs @@ -392,7 +392,7 @@ namespace Barotrauma DateTime startTime = DateTime.Now; #endif RoundDuration = 0.0f; - AfflictionPrefab.LoadAllEffects(); + AfflictionPrefab.LoadAllEffectsAndTreatmentSuitabilities(); MirrorLevel = mirrorLevel; if (SubmarineInfo == null) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/LevelResource.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/LevelResource.cs index 353d25d9a..67c3ff90d 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/LevelResource.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Holdable/LevelResource.cs @@ -135,7 +135,7 @@ namespace Barotrauma.Items.Components private void CreateTriggerBody() { System.Diagnostics.Debug.Assert(trigger == null, "LevelResource trigger already created!"); - var body = item.body ?? holdable.Body; + var body = item.body ?? holdable?.Body; if (body != null && Attached) { trigger = new PhysicsBody(body.Width, body.Height, body.Radius, diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelData.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelData.cs index b7a5aea58..3e3d51b4c 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelData.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelData.cs @@ -178,7 +178,7 @@ namespace Barotrauma if (eventSet is null) { continue; } int count = childElement.GetAttributeInt("count", 0); if (count < 1) { continue; } - FinishedEvents.Add(eventSet, count); + FinishedEvents.TryAdd(eventSet, count); } static EventSet FindSetRecursive(EventSet parentSet, Identifier setIdentifier) @@ -365,7 +365,7 @@ namespace Barotrauma if (FinishedEvents.Any()) { var finishedEventsElement = new XElement(nameof(FinishedEvents)); - foreach (var (set, count) in FinishedEvents) + foreach (var (set, count) in FinishedEvents.DistinctBy(f => f.Key.Identifier)) { var element = new XElement(nameof(FinishedEvents), new XAttribute("set", set.Identifier), diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs index 5f410a025..6b896fac7 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs @@ -1353,44 +1353,38 @@ namespace Barotrauma if (startWaypoint.WorldPosition.X > endWaypoint.WorldPosition.X) { - var temp = startWaypoint; - startWaypoint = endWaypoint; - endWaypoint = temp; + (endWaypoint, startWaypoint) = (startWaypoint, endWaypoint); } if (hallwayLength > 100 && isHorizontal) { + //if the hallway is longer than 100 pixels, generate some waypoints inside it + //for vertical hallways this isn't necessarily, it's done as a part of the ladder generation in AlignLadders WayPoint prevWayPoint = startWaypoint; + WayPoint firstWayPoint = null; for (float x = leftHull.Rect.Right + 50; x < rightHull.Rect.X - 50; x += 100.0f) { var newWayPoint = new WayPoint(new Vector2(x, hullBounds.Y + 110.0f), SpawnType.Path, sub); + firstWayPoint ??= newWayPoint; prevWayPoint.linkedTo.Add(newWayPoint); newWayPoint.linkedTo.Add(prevWayPoint); prevWayPoint = newWayPoint; } + if (firstWayPoint != null) + { + firstWayPoint.linkedTo.Add(startWaypoint); + startWaypoint.linkedTo.Add(firstWayPoint); + } if (prevWayPoint != null) { prevWayPoint.linkedTo.Add(endWaypoint); endWaypoint.linkedTo.Add(prevWayPoint); } } - - WayPoint closestWaypoint = null; - float closestDistSqr = 30.0f * 30.0f; - foreach (WayPoint waypoint in WayPoint.WayPointList) + else { - if (waypoint == startWaypoint) { continue; } - float dist = Vector2.DistanceSquared(waypoint.WorldPosition, startWaypoint.WorldPosition); - if (dist < closestDistSqr) - { - closestWaypoint = waypoint; - closestDistSqr = dist; - } - } - if (closestWaypoint != null) - { - startWaypoint.linkedTo.Add(closestWaypoint); - closestWaypoint.linkedTo.Add(startWaypoint); + startWaypoint.linkedTo.Add(endWaypoint); + endWaypoint.linkedTo.Add(startWaypoint); } } } @@ -1444,7 +1438,7 @@ namespace Barotrauma { foreach (MapEntity me in entities[module]) { - if (!(me is Gap gap)) { continue; } + if (me is not Gap gap) { continue; } var door = gap.ConnectedDoor; if (door != null && !door.UseBetweenOutpostModules) { continue; } if (placedModules.Any(m => m.PreviousGap == gap || m.ThisGap == gap)) @@ -1524,15 +1518,38 @@ namespace Barotrauma static void RemoveLinkedEntity(MapEntity linked) { - if (linked is Item linkedItem && linkedItem.Connections != null) + if (linked is Item linkedItem) { - foreach (Connection connection in linkedItem.Connections) + if (linkedItem.Connections != null) { - foreach (Wire w in connection.Wires.ToArray()) + foreach (Connection connection in linkedItem.Connections) { - w?.Item.Remove(); + foreach (Wire w in connection.Wires.ToArray()) + { + w?.Item.Remove(); + } } } + //if we end up removing a ladder, remove its waypoints too + if (linkedItem.GetComponent() is Ladder ladder) + { + var ladderWaypoints = WayPoint.WayPointList.FindAll(wp => wp.Ladders == ladder); + foreach (var ladderWaypoint in ladderWaypoints) + { + //got through all waypoints linked to the ladder waypoints, and link them together + //so we don't end up breaking up any paths by removing the ladder waypoints + for (int i = 0; i < ladderWaypoint.linkedTo.Count; i++) + { + if (ladderWaypoint.linkedTo[i] is not WayPoint waypoint1 || waypoint1.Ladders == ladder) { continue; } + for (int j = i + 1; j < ladderWaypoint.linkedTo.Count; j++) + { + if (ladderWaypoint.linkedTo[j] is not WayPoint waypoint2 || waypoint2.Ladders == ladder) { continue; } + waypoint1.ConnectTo(waypoint2); + } + } + } + ladderWaypoints.ForEach(wp => wp.Remove()); + } } linked.Remove(); } diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index 75b4957f2..a81ba4c7a 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,3 +1,22 @@ +--------------------------------------------------------------------------------------------------------- +v1.0.21.0 +--------------------------------------------------------------------------------------------------------- + +Fixes: +- Fixed LOS effect sometimes "lagging behind" when the sub is moving fast. +- Fixed some minor visual issues (occasional jitter/flickering) on the LOS effect. +- Fixed some issues in the bot AI that we're causing a large performance hit particularly in situations when there's lots of bots in a sub with leaks. +- Fixed bots abandoning their orders (such as operating a turret) if the room is unsafe (e.g. flooded). +- Fixed an issue in character syncing that occasionally caused disconnects with the error message "Exception thrown while reading segment EntityPosition, tried to read too much data from segment". +- Fixed wires set to be hidden in-game (e.g. invisible circuits built outside the sub) being visible on the Electrician's Goggles. +- Fixed an issue with level resources that caused crashes with certain mods (e.g. ones that include subs with piezo crystals). +- Fixed NPCs waiting on some outpost modules never reaching their targets, causing peculiar behavior. +- Fixed waypoints sometimes not getting connected between outpost modules if there's a very short hallway between them. Addresses some cities missing connections between waypoints, causing AI to be unable to navigate through the modules. +- Fixed some UI layout issues (most noticeably, ultra-wide crew list) on certain resolutions like 3440x1440. +- Fixed campaign saves occasionally failing to load with the error "an item with the same key has already been added". Seemed to only occur when using certain mods. +- Fixed crashing when you e.g. use a pet from some mod in the campaign, disable the mod and reload the save. +- Waypoint adjustments to most submarines, outposts, wrecks, and beacons. Especially on ladders. Should take care of the remaining AI issues on ladders (the old subs in the saves don't get updated, but the fixes apply to new subs that you don't yet own. And ofc all the subs in a new game!) + --------------------------------------------------------------------------------------------------------- v1.0.20.1 --------------------------------------------------------------------------------------------------------- @@ -5,7 +24,7 @@ v1.0.20.1 Fixes: - Fixed hidden structures not colliding anymore. - Wiring debugger: Fixed tooltip rendering under the outer frame of the connection panel. -- Wiring debugger: Fixed the glow sprite on connections having an inconsistent size in different resolutions- +- Wiring debugger: Fixed the glow sprite on connections having an inconsistent size in different resolutions. - Fixed jailbreak_sootman event getting stuck at the 1st SpawnAction, preventing most of the event from working at all. --------------------------------------------------------------------------------------------------------- From c67f6688fdf4dcffa224711a0d4f4181d9a1fad4 Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Wed, 21 Jun 2023 16:15:10 +0300 Subject: [PATCH 2/2] 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 589a3ce6e..39413a43f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -54,7 +54,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: - - v1.0.20.1 + - v1.0.21.0 - Other validations: required: true