From 2968e23ae8a1e061106e13a41a71009cde7ed554 Mon Sep 17 00:00:00 2001 From: Markus Isberg <3e849f2e5c@pm.me> Date: Wed, 30 Mar 2022 00:06:59 +0900 Subject: [PATCH] Unstable 0.17.2.0 --- .../Characters/AI/EnemyAIController.cs | 2 +- .../Characters/CharacterNetworking.cs | 17 +- .../Characters/Health/CharacterHealth.cs | 2 +- .../ContentPackageManager.cs | 24 +- .../ClientSource/GUI/GUIPrefab.cs | 2 +- .../ClientSource/GUI/MedicalClinicUI.cs | 2 +- .../ClientSource/GUI/TabMenu.cs | 44 +--- .../GameSession/GameModes/CampaignMode.cs | 4 - .../GameModes/MultiPlayerCampaign.cs | 2 +- .../ClientSource/GameSession/RoundSummary.cs | 2 +- .../ClientSource/Items/CharacterInventory.cs | 2 +- .../Items/Components/ItemContainer.cs | 7 +- .../Items/Components/ItemLabel.cs | 51 +--- .../ClientSource/Items/Components/Rope.cs | 20 +- .../ClientSource/Items/Inventory.cs | 2 +- .../ClientSource/Items/Item.cs | 4 +- .../Map/Creatures/BallastFloraBehavior.cs | 4 +- .../ClientSource/Map/WayPoint.cs | 12 +- .../Networking/Voip/VoipCapture.cs | 13 +- .../Networking/Voip/VoipClient.cs | 12 +- .../CharacterEditor/CharacterEditorScreen.cs | 3 +- .../ClientSource/Screens/GameScreen.cs | 25 +- .../ClientSource/Screens/LevelEditorScreen.cs | 10 +- .../ClientSource/Screens/MainMenuScreen.cs | 149 +++++------- .../ClientSource/Screens/ModDownloadScreen.cs | 9 - .../ClientSource/Screens/SubEditorScreen.cs | 107 +++------ .../Serialization/SerializableEntityEditor.cs | 30 +-- .../ClientSource/Steam/PublishTab.cs | 98 ++++---- .../ClientSource/Steam/Workshop.cs | 5 - .../BarotraumaClient/LinuxClient.csproj | 4 +- Barotrauma/BarotraumaClient/MacClient.csproj | 4 +- .../BarotraumaClient/WindowsClient.csproj | 4 +- .../BarotraumaServer/LinuxServer.csproj | 4 +- Barotrauma/BarotraumaServer/MacServer.csproj | 4 +- .../ServerSource/Characters/Character.cs | 2 +- .../Characters/CharacterNetworking.cs | 2 +- .../ServerSource/GameSession/CargoManager.cs | 2 +- .../GameModes/MultiPlayerCampaign.cs | 8 +- .../ServerSource/Items/Item.cs | 3 +- .../Map/Creatures/BallastFloraBehavior.cs | 32 +-- .../Networking/FileTransfer/ModSender.cs | 6 +- .../ServerSource/Networking/GameServer.cs | 2 +- .../ServerSource/Networking/ServerSettings.cs | 7 +- .../ServerSource/Traitors/Traitor.cs | 2 +- .../BarotraumaServer/WindowsServer.csproj | 4 +- .../SharedSource}/CameraTransition.cs | 0 .../Characters/AI/EnemyAIController.cs | 225 ++++++++---------- .../SharedSource/Characters/AI/LatchOntoAI.cs | 10 +- .../Characters/Animation/AnimController.cs | 3 +- .../Animation/FishAnimController.cs | 19 +- .../Animation/HumanoidAnimController.cs | 74 ++---- .../Characters/Animation/Ragdoll.cs | 2 +- .../SharedSource/Characters/Attack.cs | 13 +- .../SharedSource/Characters/Character.cs | 32 +-- .../Characters/CharacterEventData.cs | 2 +- .../SharedSource/Characters/CharacterInfo.cs | 24 +- .../Characters/Health/CharacterHealth.cs | 16 +- .../SharedSource/Characters/Limb.cs | 2 - .../Params/Animation/HumanoidAnimations.cs | 10 +- .../Characters/Params/CharacterParams.cs | 6 - .../ContentFile/ContentFile.cs | 10 +- .../ContentFile/ServerExecutableFile.cs | 28 --- .../ContentPackage/ContentPackage.cs | 2 +- .../ContentPackage/CorePackage.cs | 4 +- .../ContentPackageManager.cs | 3 +- .../SharedSource/DebugConsole.cs | 57 ++--- .../Events/Missions/BeaconMission.cs | 7 - .../Events/Missions/CargoMission.cs | 9 +- .../SharedSource/Events/Missions/Mission.cs | 33 ++- .../Events/Missions/MonsterMission.cs | 2 +- .../SharedSource/GameSession/CargoManager.cs | 14 +- .../SharedSource/GameSession/Data/Wallet.cs | 18 +- .../GameSession/GameModes/CampaignMode.cs | 23 +- .../SharedSource/GameSession/GameSession.cs | 17 +- .../GameSession/UpgradeManager.cs | 2 +- .../Items/Components/DockingPort.cs | 2 +- .../Items/Components/ItemContainer.cs | 9 - .../Items/Components/Machines/Pump.cs | 2 +- .../Items/Components/Power/Powered.cs | 31 ++- .../Items/Components/Projectile.cs | 79 +++--- .../SharedSource/Items/Components/Rope.cs | 62 +---- .../SharedSource/Items/Item.cs | 7 +- .../SharedSource/Items/ItemEventData.cs | 2 +- .../Map/Creatures/BallastFloraBehavior.cs | 57 ++--- .../SharedSource/Map/ItemAssemblyPrefab.cs | 17 +- .../SharedSource/Map/Levels/Level.cs | 4 +- .../SharedSource/Map/Levels/LevelData.cs | 14 +- .../SharedSource/Map/Map/Map.cs | 3 +- .../Map/Outposts/OutpostGenerator.cs | 166 ++++--------- .../Map/Outposts/OutpostModuleInfo.cs | 3 - .../SharedSource/Map/RoundEndCinematic.cs | 4 +- .../SharedSource/Map/StructurePrefab.cs | 2 +- .../SharedSource/Networking/NetworkMember.cs | 2 +- .../Serialization/XMLExtensions.cs | 8 +- .../SharedSource/Settings/GameSettings.cs | 25 +- .../StatusEffects/StatusEffect.cs | 24 +- .../SharedSource/Utils/SafeIO.cs | 26 +- Barotrauma/BarotraumaShared/changelog.txt | 59 ----- .../LICENSE_webm_mem_playback.txt | 2 +- README.md | 2 +- 100 files changed, 654 insertions(+), 1379 deletions(-) rename Barotrauma/{BarotraumaClient/ClientSource => BarotraumaShared/SharedSource}/CameraTransition.cs (100%) delete mode 100644 Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentFile/ServerExecutableFile.cs diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/AI/EnemyAIController.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/AI/EnemyAIController.cs index bfb8b7202..9b31bf9bf 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/AI/EnemyAIController.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/AI/EnemyAIController.cs @@ -39,7 +39,7 @@ namespace Barotrauma targetPos.Y = -targetPos.Y; GUI.DrawLine(spriteBatch, pos, targetPos, GUIStyle.Red * 0.5f, 0, 4); - if (wallTarget != null && !IsCoolDownRunning) + if (wallTarget != null) { Vector2 wallTargetPos = wallTarget.Position; if (wallTarget.Structure.Submarine != null) { wallTargetPos += wallTarget.Structure.Submarine.Position; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs index 28c3230ac..22d741e27 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterNetworking.cs @@ -152,7 +152,7 @@ namespace Barotrauma case TreatmentEventData _: msg.Write(AnimController.Anim == AnimController.Animation.CPR); break; - case CharacterStatusEventData _: + case StatusEventData _: //do nothing break; case UpdateTalentsEventData _: @@ -343,12 +343,8 @@ namespace Barotrauma if (controlled == this) { Controlled = null; + IsRemotePlayer = ownerID > 0; } - if (GameMain.Client?.Character == this) - { - GameMain.Client.Character = null; - } - IsRemotePlayer = ownerID > 0; } break; case EventType.Status: @@ -375,9 +371,7 @@ namespace Barotrauma if (attackLimbIndex == 255 || Removed) { break; } if (attackLimbIndex >= AnimController.Limbs.Length) { - string errorMsg = $"Received invalid {(eventType == EventType.SetAttackTarget ? "SetAttackTarget" : "ExecuteAttack")} message. Limb index out of bounds (character: {Name}, limb index: {attackLimbIndex}, limb count: {AnimController.Limbs.Length})"; - DebugConsole.ThrowError(errorMsg); - GameAnalyticsManager.AddErrorEventOnce("Character.ClientEventRead:AttackLimbOutOfBounds", GameAnalyticsManager.ErrorSeverity.Error, errorMsg); + DebugConsole.ThrowError($"Received invalid {(eventType == EventType.SetAttackTarget ? "SetAttackTarget" : "ExecuteAttack")} message. Limb index out of bounds (character: {Name}, limb index: {attackLimbIndex}, limb count: {AnimController.Limbs.Length})"); break; } Limb attackLimb = AnimController.Limbs[attackLimbIndex]; @@ -386,16 +380,13 @@ namespace Barotrauma if (targetEntity == null && eventType == EventType.SetAttackTarget) { DebugConsole.ThrowError($"Received invalid SetAttackTarget message. Target entity not found (ID {targetEntityID})"); - GameAnalyticsManager.AddErrorEventOnce("Character.ClientEventRead:TargetNotFound", GameAnalyticsManager.ErrorSeverity.Error, "Received invalid SetAttackTarget message. Target entity not found."); break; } - if (targetEntity is Character targetCharacter && targetLimbIndex != 255) + if (targetEntity is Character targetCharacter) { if (targetLimbIndex >= targetCharacter.AnimController.Limbs.Length) { DebugConsole.ThrowError($"Received invalid {(eventType == EventType.SetAttackTarget ? "SetAttackTarget" : "ExecuteAttack")} message. Target limb index out of bounds (target character: {targetCharacter.Name}, limb index: {targetLimbIndex}, limb count: {targetCharacter.AnimController.Limbs.Length})"); - string errorMsgWithoutName = $"Received invalid {(eventType == EventType.SetAttackTarget ? "SetAttackTarget" : "ExecuteAttack")} message. Target limb index out of bounds (target character: {targetCharacter.SpeciesName}, limb index: {targetLimbIndex}, limb count: {targetCharacter.AnimController.Limbs.Length})"; - GameAnalyticsManager.AddErrorEventOnce("Character.ClientEventRead:TargetLimbOutOfBounds", GameAnalyticsManager.ErrorSeverity.Error, errorMsgWithoutName); break; } targetLimb = targetCharacter.AnimController.Limbs[targetLimbIndex]; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/Health/CharacterHealth.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/Health/CharacterHealth.cs index 436e47141..b61c76669 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/Health/CharacterHealth.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/Health/CharacterHealth.cs @@ -400,7 +400,7 @@ namespace Barotrauma { if (GameMain.Client != null) { - GameMain.Client.CreateEntityEvent(Character.Controlled, new Character.CharacterStatusEventData()); + GameMain.Client.CreateEntityEvent(Character.Controlled, new Character.StatusEventData()); } else { diff --git a/Barotrauma/BarotraumaClient/ClientSource/ContentManagement/ContentPackageManager.cs b/Barotrauma/BarotraumaClient/ClientSource/ContentManagement/ContentPackageManager.cs index 86a971bf5..3ae094982 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/ContentManagement/ContentPackageManager.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/ContentManagement/ContentPackageManager.cs @@ -12,30 +12,22 @@ namespace Barotrauma { public sealed partial class PackageSource : ICollection { - public string SaveRegularMod(ModProject modProject) + public ContentPackage SaveAndEnableRegularMod(ModProject modProject) { if (modProject.IsCore) { throw new ArgumentException("ModProject must not be a core package"); } - + + //save the content package string fileListPath = Path.Combine(directory, ToolBox.RemoveInvalidFileNameChars(modProject.Name), ContentPackage.FileListFileName) .CleanUpPathCrossPlatform(correctFilenameCase: false); + Directory.CreateDirectory(Path.GetDirectoryName(fileListPath)!); modProject.Save(fileListPath); Refresh(); EnabledPackages.DisableRemovedMods(); + var newPackage = Regular.First(p => p.Path == fileListPath); - return fileListPath; - } + //enable it + EnabledPackages.EnableRegular(newPackage); - public RegularPackage GetRegularModByPath(string fileListPath) - { - return Regular.First(p => p.Path == fileListPath); - } - - public RegularPackage SaveAndEnableRegularMod(ModProject modProject) - { - string fileListPath = SaveRegularMod(modProject); - var package = GetRegularModByPath(fileListPath); - EnabledPackages.EnableRegular(package); - - return package; + return newPackage; } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIPrefab.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIPrefab.cs index 1487d6943..ccef64092 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIPrefab.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIPrefab.cs @@ -65,7 +65,7 @@ namespace Barotrauma LoadFont(); } - public void LoadFont() + private void LoadFont() { string fontPath = GetFontFilePath(element); uint size = GetFontSize(element); diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/MedicalClinicUI.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/MedicalClinicUI.cs index 1ea2828e2..ed32a00b9 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/MedicalClinicUI.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/MedicalClinicUI.cs @@ -931,7 +931,7 @@ namespace Barotrauma }); } - public static void EnsureTextDoesntOverflow(string? text, GUITextBlock textBlock, Rectangle bounds, ImmutableArray? layoutGroups = null) + private static void EnsureTextDoesntOverflow(string? text, GUITextBlock textBlock, Rectangle bounds, ImmutableArray? layoutGroups = null) { if (string.IsNullOrWhiteSpace(text)) { return; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs index 62b0364d2..201d8d242 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs @@ -218,7 +218,7 @@ namespace Barotrauma public void AddToGUIUpdateList() { - infoFrame?.AddToGUIUpdateList(order: 1); + infoFrame?.AddToGUIUpdateList(); NetLobbyScreen.JobInfoFrame?.AddToGUIUpdateList(); } @@ -379,7 +379,8 @@ namespace Barotrauma private void CreateCrewListFrame(GUIFrame crewFrame) { - crew = GameMain.GameSession?.CrewManager?.GetCharacters() ?? Array.Empty(); + // FIXME remove TestScreen stuff + crew = GameMain.GameSession?.CrewManager?.GetCharacters() ?? new []{ TestScreen.dummyCharacter }; teamIDs = crew.Select(c => c.TeamID).Distinct().ToList(); // Show own team first when there's more than one team @@ -816,7 +817,7 @@ namespace Barotrauma else if (client != null) { GUIComponent preview = CreateClientInfoFrame(background, client, GetPermissionIcon(client)); - GameMain.Client?.SelectCrewClient(client, preview); + if (GameMain.NetworkMember != null) { GameMain.Client.SelectCrewClient(client, preview); } CreateWalletFrame(background, client.Character); } @@ -849,18 +850,17 @@ namespace Barotrauma GUILayoutGroup middleLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.66f), walletLayout.RectTransform)); GUILayoutGroup salaryTextLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), middleLayout.RectTransform), isHorizontal: true); GUITextBlock salaryTitle = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), salaryTextLayout.RectTransform), TextManager.Get("crewwallet.salary"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.BottomLeft); - GUITextBlock rewardBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), salaryTextLayout.RectTransform), string.Empty, textAlignment: Alignment.BottomRight); + GUITextBlock rewardBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), salaryTextLayout.RectTransform), TextManager.GetWithVariable("percentageformat", "[value]", GetSharePercentage()), textAlignment: Alignment.BottomRight); GUILayoutGroup sliderLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), middleLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.Center); GUIScrollBar salarySlider = new GUIScrollBar(new RectTransform(new Vector2(0.9f, 1f), sliderLayout.RectTransform), style: "GUISlider", barSize: 0.03f) { - ToolTip = TextManager.Get("crewwallet.salary.tooltip"), - Range = new Vector2(0, 1), + Range = Vector2.UnitY, BarScrollValue = targetWallet.RewardDistribution / 100f, Step = 0.01f, BarSize = 0.1f, OnMoved = (bar, scroll) => { - SetRewardText((int)(scroll * 100), rewardBlock); + rewardBlock.Text = TextManager.GetWithVariable("percentageformat", "[value]", GetSharePercentage()); return true; }, OnReleased = (bar, scroll) => @@ -871,9 +871,6 @@ namespace Barotrauma return true; } }; - - SetRewardText(targetWallet.RewardDistribution, rewardBlock); - // @formatter:off GUIScissorComponent scissorComponent = new GUIScissorComponent(new RectTransform(new Vector2(0.85f, 1.25f), walletFrame.RectTransform, Anchor.BottomCenter, Pivot.TopCenter)) { @@ -905,11 +902,8 @@ namespace Barotrauma GUIButton confirmButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1f), centerButtonLayout.RectTransform), TextManager.Get("confirm"), style: "GUIButtonFreeScale") { Enabled = false }; GUIButton resetButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1f), centerButtonLayout.RectTransform), TextManager.Get("reset"), style: "GUIButtonFreeScale") { Enabled = false }; // @formatter:on - ImmutableArray layoutGroups = ImmutableArray.Create(transferMenuLayout, paddedTransferMenuLayout, mainLayout, leftLayout, rightLayout); - MedicalClinicUI.EnsureTextDoesntOverflow(character.Name, leftName, leftLayout.Rect, layoutGroups); transferMenuButton = new GUIButton(new RectTransform(new Vector2(0.5f, 0.2f), walletFrame.RectTransform, Anchor.BottomCenter, Pivot.TopCenter), style: "UIToggleButtonVertical") { - ToolTip = TextManager.Get("crewwallet.transfer.tooltip"), OnClicked = (button, o) => { isTransferMenuOpen = !isTransferMenuOpen; @@ -957,8 +951,6 @@ namespace Barotrauma break; } - MedicalClinicUI.EnsureTextDoesntOverflow(rightName.Text.ToString(), rightName, rightLayout.Rect, layoutGroups); - if (!hasPermissions) { centerButton.Enabled = centerButton.CanBeFocused = false; @@ -1081,14 +1073,14 @@ namespace Barotrauma Receiver = to.Select(option => option.ID), Amount = amount }; - IWriteMessage msg = new WriteOnlyMessage().WithHeader(ClientPacketHeader.TRANSFER_MONEY); + IWriteMessage msg = new WriteOnlyMessage().WithHeader(ClientPacketHeader.MONEY); transfer.Write(msg); GameMain.Client?.ClientPeer?.Send(msg, DeliveryMethod.Reliable); } static void SetRewardDistribution(Character character, int newValue) { - INetSerializableStruct transfer = new NetWalletSetSalaryUpdate + INetSerializableStruct transfer = new NetWalletSalaryUpdate { Target = character.ID, NewRewardDistribution = newValue @@ -1098,23 +1090,7 @@ namespace Barotrauma GameMain.Client?.ClientPeer?.Send(msg, DeliveryMethod.Reliable); } - void SetRewardText(int value, GUITextBlock block) - { - var (_, percentage, sum) = Mission.GetRewardShare(value, salaryCrew, Option.None()); - LocalizedString tooltip = string.Empty; - block.TextColor = GUIStyle.TextColorNormal; - - if (sum > 100) - { - tooltip = TextManager.GetWithVariables("crewwallet.salary.over100toolitp", ("[sum]", $"{(int)sum}"), ("[newvalue]", $"{percentage}")); - block.TextColor = GUIStyle.Orange; - } - - LocalizedString text = TextManager.GetWithVariable("percentageformat", "[value]", $"{value}"); - - block.Text = text; - block.ToolTip = RichString.Rich(tooltip); - } + string GetSharePercentage() => Mission.GetRewardShare(targetWallet.RewardDistribution, salaryCrew, Option.None()).Percentage.ToString(); } private GUIComponent CreateClientInfoFrame(GUIFrame frame, Client client, Sprite permissionIcon = null) diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/CampaignMode.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/CampaignMode.cs index 824d1c178..7186c3bd9 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/CampaignMode.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/CampaignMode.cs @@ -63,10 +63,6 @@ namespace Barotrauma } } - /// - /// Gets the current personal wallet - /// In singleplayer this is the campaign bank and in multiplayer this is the personal wallet - /// public virtual Wallet Wallet => GetWallet(); public override void ShowStartMessage() diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/MultiPlayerCampaign.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/MultiPlayerCampaign.cs index 2cf62767f..597939e79 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/MultiPlayerCampaign.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/MultiPlayerCampaign.cs @@ -914,7 +914,7 @@ namespace Barotrauma WalletInfo info = transaction.Info; switch (transaction.CharacterID) { - case Some { Value: var charID }: + case Some { Value: var charID}: { Character targetCharacter = Character.CharacterList?.FirstOrDefault(c => c.ID == charID); if (targetCharacter is null) { break; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/RoundSummary.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/RoundSummary.cs index abe401df3..2770fc3c0 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/RoundSummary.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/RoundSummary.cs @@ -318,7 +318,7 @@ namespace Barotrauma new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), RichString.Rich(displayedMission.GetMissionRewardText(Submarine.MainSub))); if (GameMain.IsMultiplayer && Character.Controlled is { } controlled) { - var (share, percentage, _) = Mission.GetRewardShare(controlled.Wallet.RewardDistribution, Mission.GetSalaryEligibleCrew().Where(c => c != controlled), Option.Some(reward)); + var (share, percentage) = Mission.GetRewardShare(controlled.Wallet.RewardDistribution, Mission.GetSalaryEligibleCrew(), Option.Some(reward)); if (share > 0) { string shareFormatted = string.Format(CultureInfo.InvariantCulture, "{0:N0}", share); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/CharacterInventory.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/CharacterInventory.cs index 4746f0e9f..e19ace1a9 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/CharacterInventory.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/CharacterInventory.cs @@ -966,7 +966,7 @@ namespace Barotrauma } else if (character.HeldItems.Any(i => i.OwnInventory != null && - ((i.OwnInventory.CanBePut(item) && allowInventorySwap) || (i.OwnInventory.Capacity == 1 && i.OwnInventory.AllowSwappingContainedItems && i.OwnInventory.Container.CanBeContained(item))))) + (i.OwnInventory.CanBePut(item) || (i.OwnInventory.Capacity == 1 && i.OwnInventory.AllowSwappingContainedItems && i.OwnInventory.Container.CanBeContained(item))))) { return QuickUseAction.PutToEquippedItem; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemContainer.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemContainer.cs index 5fe3adde1..597c90daa 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemContainer.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemContainer.cs @@ -1,7 +1,8 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using System; +using System; using System.Linq; +using System.Xml.Linq; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; namespace Barotrauma.Items.Components { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemLabel.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemLabel.cs index 01742a2d0..7c7821844 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemLabel.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemLabel.cs @@ -2,14 +2,12 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; -using System.Collections.Generic; -using System.Linq; using System.Text; using System.Xml.Linq; namespace Barotrauma.Items.Components { - partial class ItemLabel : ItemComponent, IDrawableComponent, IHasExtraTextPickerEntries + partial class ItemLabel : ItemComponent, IDrawableComponent { private GUITextBlock textBlock; @@ -108,7 +106,7 @@ namespace Barotrauma.Items.Components set { scrollable = value; - IsActive = value || parseSpecialTextTagOnStart; + IsActive = value; TextBlock.Wrap = !scrollable; TextBlock.TextAlignment = scrollable ? Alignment.CenterLeft : Alignment.Center; } @@ -138,11 +136,6 @@ namespace Barotrauma.Items.Components { } - public IEnumerable GetExtraTextPickerEntries() - { - return SpecialTextTags; - } - private void SetScrollingText() { if (!scrollable) { return; } @@ -181,18 +174,9 @@ namespace Barotrauma.Items.Components scrollIndex = MathHelper.Clamp(scrollIndex, 0, DisplayText.Length); } - private static readonly string[] SpecialTextTags = new string[] { "[CurrentLocationName]", "[CurrentBiomeName]", "[CurrentSubName]" }; - private bool parseSpecialTextTagOnStart; private void SetDisplayText(string value) { - if (SpecialTextTags.Contains(value)) - { - parseSpecialTextTagOnStart = true; - IsActive = true; - } - DisplayText = IgnoreLocalization ? value : TextManager.Get(value).Fallback(value); - TextBlock.Text = DisplayText; if (Screen.Selected == GameMain.SubEditorScreen && Scrollable) { @@ -214,37 +198,9 @@ namespace Barotrauma.Items.Components }; } - private void ParseSpecialTextTag() - { - switch (text) - { - case "[CurrentLocationName]": - SetDisplayText(Level.Loaded?.StartLocation?.Name ?? string.Empty); - break; - case "[CurrentBiomeName]": - SetDisplayText(Level.Loaded?.LevelData?.Biome?.DisplayName.Value ?? string.Empty); - break; - case "[CurrentSubName]": - SetDisplayText(item.Submarine?.Info?.DisplayName.Value ?? string.Empty); - break; - default: - break; - } - } - public override void Update(float deltaTime, Camera cam) { - if (parseSpecialTextTagOnStart) - { - ParseSpecialTextTag(); - parseSpecialTextTagOnStart = false; - } - - if (!scrollable) - { - IsActive = false; - return; - } + if (!scrollable) { return; } if (scrollingText == null) { @@ -330,6 +286,5 @@ namespace Barotrauma.Items.Components { Text = msg.ReadString(); } - } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Rope.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Rope.cs index 36713eab5..2dc8ec191 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Rope.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Rope.cs @@ -34,13 +34,6 @@ namespace Barotrauma.Items.Components [Serialize("0.5,0.5)", IsPropertySaveable.No)] public Vector2 Origin { get; set; } = new Vector2(0.5f, 0.5f); - [Serialize(true, IsPropertySaveable.No, description: "")] - public bool BreakFromMiddle - { - get; - set; - } - public Vector2 DrawSize { get @@ -131,14 +124,9 @@ namespace Barotrauma.Items.Components int width = (int)(SpriteWidth * snapState); if (width > 0.0f) - { - float positionMultiplier = snapState; - if (BreakFromMiddle) - { - positionMultiplier /= 2; - DrawRope(spriteBatch, endPos - diff * positionMultiplier, endPos, width); - } - DrawRope(spriteBatch, startPos, startPos + diff * positionMultiplier, width); + { + DrawRope(spriteBatch, endPos - diff * snapState * 0.5f, endPos, width); + DrawRope(spriteBatch, startPos, startPos + diff * snapState * 0.5f, width); } } else @@ -155,7 +143,7 @@ namespace Barotrauma.Items.Components float depth = Math.Min(item.GetDrawDepth() + (startSprite.Depth - item.Sprite.Depth), 0.999f); startSprite?.Draw(spriteBatch, startPos, SpriteColor, angle, depth: depth); } - if (endSprite != null && (!Snapped || BreakFromMiddle)) + if (endSprite != null) { float depth = Math.Min(item.GetDrawDepth() + (endSprite.Depth - item.Sprite.Depth), 0.999f); endSprite?.Draw(spriteBatch, endPos, SpriteColor, angle, depth: depth); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs index 6224c628c..1c27aaf3c 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Inventory.cs @@ -1846,7 +1846,7 @@ namespace Barotrauma yield return CoroutineStatus.Success; } - public void ApplyReceivedState() + private void ApplyReceivedState() { if (receivedItemIDs == null || (Owner != null && Owner.Removed)) { return; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Item.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Item.cs index 3cc3610e0..8cb513864 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Item.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Item.cs @@ -1198,9 +1198,9 @@ namespace Barotrauma Color color = Color.Gray; if (ic.HasRequiredItems(character, false)) { - if (ic is Repairable r) + if (ic is Repairable) { - if (r.IsBelowRepairThreshold) { color = Color.Cyan; } + if (!IsFullCondition) { color = Color.Cyan; } } else { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/Creatures/BallastFloraBehavior.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/Creatures/BallastFloraBehavior.cs index 264b5b2e7..80d814e5f 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/Creatures/BallastFloraBehavior.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/Creatures/BallastFloraBehavior.cs @@ -370,7 +370,6 @@ namespace Barotrauma.MapCreatures.Behavior private BallastFloraBranch ReadBranch(IReadMessage msg) { int id = msg.ReadInt32(); - bool isRootGrowth = msg.ReadBoolean(); byte type = (byte)msg.ReadRangedInteger(0b0000, 0b1111); byte sides = (byte)msg.ReadRangedInteger(0b0000, 0b1111); int flowerConfig = msg.ReadRangedInteger(0, 0xFFF); @@ -386,8 +385,7 @@ namespace Barotrauma.MapCreatures.Behavior { ID = id, MaxHealth = maxHealth, - Sides = (TileSide) sides, - IsRootGrowth = isRootGrowth + Sides = (TileSide) sides }; } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/WayPoint.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/WayPoint.cs index e69d0bbb0..8cd2acaaf 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/WayPoint.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/WayPoint.cs @@ -272,7 +272,11 @@ namespace Barotrauma private GUIComponent CreateEditingHUD() { - editingHUD = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.15f), GUI.Canvas, Anchor.CenterRight) { MinSize = new Point(400, 0) }) + int width = 500; + int height = spawnType == SpawnType.Path ? 80 : 200; + int x = GameMain.GraphicsWidth / 2 - width / 2, y = 30; + + editingHUD = new GUIFrame(new RectTransform(new Point(width, height), GUI.Canvas) { ScreenSpaceOffset = new Point(x, y) }) { UserData = this }; @@ -280,7 +284,7 @@ namespace Barotrauma var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.85f), editingHUD.RectTransform, Anchor.Center)) { Stretch = true, - AbsoluteSpacing = (int)(GUI.Scale * 5) + RelativeSpacing = 0.05f }; if (spawnType == SpawnType.Path) @@ -414,10 +418,6 @@ namespace Barotrauma }; } - editingHUD.RectTransform.Resize(new Point( - editingHUD.Rect.Width, - (int)(paddedFrame.Children.Sum(c => c.Rect.Height + paddedFrame.AbsoluteSpacing) / paddedFrame.RectTransform.RelativeSize.Y))); - PositionEditingHUD(); return editingHUD; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/Voip/VoipCapture.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/Voip/VoipCapture.cs index cf2caabed..98073f188 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/Voip/VoipCapture.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/Voip/VoipCapture.cs @@ -163,11 +163,16 @@ namespace Barotrauma.Networking public static void ChangeCaptureDevice(string deviceName) { - if (Instance == null) { return; } + var config = GameSettings.CurrentConfig; + config.Audio.VoiceCaptureDevice = deviceName; + GameSettings.SetCurrentConfig(config); - UInt16 storedBufferID = Instance.LatestBufferID; - Instance.Dispose(); - Create(GameSettings.CurrentConfig.Audio.VoiceCaptureDevice, storedBufferID); + if (Instance != null) + { + UInt16 storedBufferID = Instance.LatestBufferID; + Instance.Dispose(); + Create(GameSettings.CurrentConfig.Audio.VoiceCaptureDevice, storedBufferID); + } } IntPtr nativeBuffer; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/Voip/VoipClient.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/Voip/VoipClient.cs index 8916fc81e..85570fcbd 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/Voip/VoipClient.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/Voip/VoipClient.cs @@ -54,17 +54,7 @@ namespace Barotrauma.Networking } else { - try - { - if (VoipCapture.Instance == null) { VoipCapture.Create(GameSettings.CurrentConfig.Audio.VoiceCaptureDevice, storedBufferID); } - } - catch (Exception e) - { - DebugConsole.ThrowError($"VoipCature.Create failed: {e.Message} {e.StackTrace.CleanupStackTrace()}"); - var config = GameSettings.CurrentConfig; - config.Audio.VoiceSetting = VoiceMode.Disabled; - GameSettings.SetCurrentConfig(config); - } + if (VoipCapture.Instance == null) { VoipCapture.Create(GameSettings.CurrentConfig.Audio.VoiceCaptureDevice, storedBufferID); } if (VoipCapture.Instance == null || VoipCapture.Instance.EnqueuedTotalLength <= 0) { return; } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs index e9de25b54..56032d102 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/CharacterEditor/CharacterEditorScreen.cs @@ -2805,8 +2805,7 @@ namespace Barotrauma.CharacterEditor return false; } #endif - ContentPath texturePath = ContentPath.FromRaw(character.Prefab.ContentPackage, RagdollParams.Texture); - if (!character.IsHuman && (texturePath.IsNullOrWhiteSpace() || !File.Exists(texturePath.Value))) + if (!character.IsHuman && !string.IsNullOrEmpty(RagdollParams.Texture) && !File.Exists(RagdollParams.Texture)) { DebugConsole.ThrowError($"Invalid texture path: {RagdollParams.Texture}"); return false; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/GameScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/GameScreen.cs index 2b01b3ff2..e58af763e 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/GameScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/GameScreen.cs @@ -248,24 +248,17 @@ namespace Barotrauma } spriteBatch.End(); - DrawDeformed(firstPass: true); - DrawDeformed(firstPass: false); - - void DrawDeformed(bool firstPass) + //draw characters with deformable limbs last, because they can't be batched into SpriteBatch + //pretty hacky way of preventing draw order issues between normal and deformable sprites + spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform); + //backwards order to render the most recently spawned characters in front (characters spawned later have a larger sprite depth) + for (int i = Character.CharacterList.Count - 1; i >= 0; i--) { - spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform); - //backwards order to render the most recently spawned characters in front (characters spawned later have a larger sprite depth) - for (int i = Character.CharacterList.Count - 1; i >= 0; i--) - { - Character c = Character.CharacterList[i]; - if (!c.IsVisible) { continue; } - if (c.Params.DrawLast == firstPass) { continue; } - if (c.AnimController.Limbs.All(l => l.DeformSprite == null)) { continue; } - c.Draw(spriteBatch, Cam); - } - spriteBatch.End(); + Character c = Character.CharacterList[i]; + if (!c.IsVisible || c.AnimController.Limbs.All(l => l.DeformSprite == null)) { continue; } + c.Draw(spriteBatch, Cam); } - + spriteBatch.End(); Level.Loaded?.DrawFront(spriteBatch, cam); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/LevelEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/LevelEditorScreen.cs index a1bbea8ab..470977caf 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/LevelEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/LevelEditorScreen.cs @@ -32,7 +32,7 @@ namespace Barotrauma private readonly GUITextBox seedBox; - private readonly GUITickBox lightingEnabled, cursorLightEnabled, allowInvalidOutpost, mirrorLevel; + private readonly GUITickBox lightingEnabled, cursorLightEnabled, mirrorLevel; private Sprite editingSprite; @@ -126,7 +126,6 @@ namespace Barotrauma OnClicked = (btn, obj) => { SerializeAll(); - GUI.AddMessage(TextManager.Get("leveleditor.allsaved"), GUIStyle.Green); return true; } }; @@ -170,12 +169,6 @@ namespace Barotrauma mirrorLevel = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.02f), paddedRightPanel.RectTransform), TextManager.Get("mirrorentityx")); - allowInvalidOutpost = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.025f), paddedRightPanel.RectTransform), - TextManager.Get("leveleditor.allowinvalidoutpost")) - { - ToolTip = TextManager.Get("leveleditor.allowinvalidoutpost.tooltip") - }; - new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), paddedRightPanel.RectTransform), TextManager.Get("leveleditor.generate")) { @@ -186,7 +179,6 @@ namespace Barotrauma GameMain.LightManager.ClearLights(); LevelData levelData = LevelData.CreateRandom(seedBox.Text, generationParams: selectedParams); levelData.ForceOutpostGenerationParams = outpostParamsList.SelectedData as OutpostGenerationParams; - levelData.AllowInvalidOutpost = allowInvalidOutpost.Selected; Level.Generate(levelData, mirror: mirrorLevel.Selected); GameMain.LightManager.AddLight(pointerLightSource); if (!wasLevelLoaded || Cam.Position.X < 0 || Cam.Position.Y < 0 || Cam.Position.Y > Level.Loaded.Size.X || Cam.Position.Y > Level.Loaded.Size.Y) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/MainMenuScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/MainMenuScreen.cs index 5f574156c..0ff737f3c 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/MainMenuScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/MainMenuScreen.cs @@ -46,7 +46,6 @@ namespace Barotrauma private GUITextBox serverNameBox, passwordBox, maxPlayersBox; private GUITickBox isPublicBox, wrongPasswordBanBox, karmaBox; - private GUIDropDown serverExecutableDropdown; private readonly GUIButton joinServerButton, hostServerButton, steamWorkshopButton; private readonly GameMain game; @@ -558,35 +557,6 @@ namespace Barotrauma GameMain.Instance.ShowCampaignDisclaimer(() => { SelectTab(null, Tab.HostServer); }); return true; } - - serverExecutableDropdown.ListBox.Content.Children.ToArray() - .Where(c => c.UserData is ServerExecutableFile f && !ContentPackageManager.EnabledPackages.All.Contains(f.ContentPackage)) - .ForEach(serverExecutableDropdown.ListBox.RemoveChild); - var newServerExes - = ContentPackageManager.EnabledPackages.All.SelectMany(p => p.GetFiles()) - .Where(f => serverExecutableDropdown.ListBox.Content.Children.None(c => c.UserData == f)) - .ToArray(); - foreach (var newServerExe in newServerExes) - { - serverExecutableDropdown.AddItem($"{newServerExe.ContentPackage.Name} - {Path.GetFileNameWithoutExtension(newServerExe.Path.Value)}", userData: newServerExe); - } - serverExecutableDropdown.ListBox.Content.Children.ForEach(c => - { - c.RectTransform.RelativeSize = (1.0f, c.RectTransform.RelativeSize.Y); - c.ForceLayoutRecalculation(); - }); - bool serverExePickable = serverExecutableDropdown.ListBox.Content.CountChildren > 1; - serverExecutableDropdown.Parent.Visible - = serverExePickable; - serverExecutableDropdown.Parent.RectTransform.RelativeSize - = (1.0f, serverExePickable ? 0.1f : 0.0f); - serverExecutableDropdown.Parent.ForceLayoutRecalculation(); - (serverExecutableDropdown.Parent.Parent as GUILayoutGroup)?.Recalculate(); - if (serverExecutableDropdown.SelectedComponent is null) - { - serverExecutableDropdown.Select(0); - } - break; case Tab.Tutorials: if (!GameSettings.CurrentConfig.CampaignDisclaimerShown) @@ -814,7 +784,7 @@ namespace Barotrauma GameMain.ResetNetLobbyScreen(); try { - string exeName = serverExecutableDropdown.SelectedComponent?.UserData is ServerExecutableFile f ? f.Path.Value : "DedicatedServer"; + string exeName = "DedicatedServer.exe"; string arguments = "-name \"" + ToolBox.EscapeCharacters(name) + "\"" + " -public " + isPublicBox.Selected.ToString() + @@ -844,20 +814,15 @@ namespace Barotrauma arguments += " -ownerkey " + ownerKey; } - string filename = Path.Combine( - Path.GetDirectoryName(exeName), - Path.GetFileNameWithoutExtension(exeName)); -#if WINDOWS - filename += ".exe"; -#else - filename = "./" + exeName; + string filename = exeName; +#if LINUX || OSX + filename = "./" + Path.GetFileNameWithoutExtension(exeName); + //arguments = ToolBox.EscapeCharacters(arguments); #endif - var processInfo = new ProcessStartInfo { FileName = filename, Arguments = arguments, - WorkingDirectory = Directory.GetCurrentDirectory(), #if !DEBUG CreateNoWindow = true, UseShellExecute = false, @@ -1219,12 +1184,12 @@ namespace Barotrauma label.RectTransform.MaxSize = serverNameBox.RectTransform.MaxSize; var maxPlayersLabel = new GUITextBlock(new RectTransform(textLabelSize, parent.RectTransform), TextManager.Get("MaxPlayers"), textAlignment: textAlignment); - var buttonContainer = new GUILayoutGroup(new RectTransform(textFieldSize, maxPlayersLabel.RectTransform, Anchor.CenterRight), isHorizontal: true, childAnchor: Anchor.CenterLeft) + var buttonContainer = new GUILayoutGroup(new RectTransform(textFieldSize, maxPlayersLabel.RectTransform, Anchor.CenterRight), isHorizontal: true) { Stretch = true, RelativeSpacing = 0.1f }; - new GUIButton(new RectTransform(Vector2.One, buttonContainer.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUIMinusButton", textAlignment: Alignment.Center) + new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonContainer.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUIMinusButton", textAlignment: Alignment.Center) { UserData = -1, OnClicked = ChangeMaxPlayers @@ -1244,7 +1209,7 @@ namespace Barotrauma currMaxPlayers = (int)MathHelper.Clamp(currMaxPlayers, 1, NetConfig.MaxPlayers); maxPlayersBox.Text = currMaxPlayers.ToString(); }; - new GUIButton(new RectTransform(Vector2.One, buttonContainer.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUIPlusButton", textAlignment: Alignment.Center) + new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonContainer.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUIPlusButton", textAlignment: Alignment.Center) { UserData = 1, OnClicked = ChangeMaxPlayers @@ -1258,41 +1223,6 @@ namespace Barotrauma }; label.RectTransform.MaxSize = passwordBox.RectTransform.MaxSize; - var serverExecutableLabel = new GUITextBlock(new RectTransform(textLabelSize, parent.RectTransform), - TextManager.Get("ServerExecutable"), textAlignment: textAlignment); - const string vanillaServerOption = "Vanilla"; - serverExecutableDropdown - = new GUIDropDown(new RectTransform(textFieldSize, serverExecutableLabel.RectTransform, Anchor.CenterRight), - vanillaServerOption); - var listBoxSize = serverExecutableDropdown.ListBox.RectTransform.RelativeSize; - serverExecutableDropdown.ListBox.RectTransform.RelativeSize = new Vector2(listBoxSize.X * 1.5f, listBoxSize.Y); - serverExecutableDropdown.AddItem(vanillaServerOption, userData: null); - serverExecutableDropdown.OnSelected = (selected, userData) => - { - if (userData != null) - { - var warningBox = new GUIMessageBox(headerText: TextManager.Get("Warning"), - text: TextManager.GetWithVariable("ModServerExesAtYourOwnRisk", "[exename]", serverExecutableDropdown.Text), - new LocalizedString[] { TextManager.Get("Yes"), TextManager.Get("No") }); - warningBox.Buttons[0].OnClicked = (_, __) => - { - warningBox.Close(); - return false; - }; - warningBox.Buttons[1].OnClicked = (_, __) => - { - serverExecutableDropdown.Select(0); - warningBox.Close(); - return false; - }; - } - - serverExecutableDropdown.Text = ToolBox.LimitString(serverExecutableDropdown.Text, - serverExecutableDropdown.Font, serverExecutableDropdown.Rect.Width * 8 / 10); - - return true; - }; - // tickbox upper --------------- var tickboxAreaUpper = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, tickBoxSize.Y), parent.RectTransform), isHorizontal: true); @@ -1382,8 +1312,8 @@ namespace Barotrauma { var client = new RestClient(RemoteContentUrl); var request = new RestRequest("MenuContent.xml", Method.GET); - TaskPool.Add("RequestMainMenuRemoteContent", client.ExecuteAsync(request), - RemoteContentReceived); + client.ExecuteAsync(request, RemoteContentReceived); + CoroutineManager.StartCoroutine(WairForRemoteContentReceived()); } catch (Exception e) @@ -1397,31 +1327,58 @@ namespace Barotrauma } } - private void RemoteContentReceived(Task t) + private IEnumerable WairForRemoteContentReceived() { - try + while (true) { - if (!t.TryGetResult(out IRestResponse remoteContentResponse)) { throw new Exception("Task did not return a valid result"); } - string xml = remoteContentResponse.Content; - int index = xml.IndexOf('<'); - if (index > 0) { xml = xml.Substring(index, xml.Length - index); } - if (!string.IsNullOrWhiteSpace(xml)) + lock (remoteContentLock) { - remoteContentDoc = XDocument.Parse(xml); - foreach (var subElement in remoteContentDoc?.Root.Elements()) + if (remoteContentResponse != null) { break; } + } + yield return new WaitForSeconds(0.1f); + } + lock (remoteContentLock) + { + if (remoteContentResponse.ResponseStatus != ResponseStatus.Completed || remoteContentResponse.StatusCode != HttpStatusCode.OK) + { + yield return CoroutineStatus.Success; + } + + try + { + string xml = remoteContentResponse.Content; + int index = xml.IndexOf('<'); + if (index > 0) { xml = xml.Substring(index, xml.Length - index); } + if (!string.IsNullOrWhiteSpace(xml)) { - GUIComponent.FromXML(subElement.FromPackage(null), remoteContentContainer.RectTransform); + remoteContentDoc = XDocument.Parse(xml); + foreach (var subElement in remoteContentDoc?.Root.Elements()) + { + GUIComponent.FromXML(subElement.FromPackage(null), remoteContentContainer.RectTransform); + } } } - } - catch (Exception e) - { + catch (Exception e) + { #if DEBUG - DebugConsole.ThrowError("Reading received remote main menu content failed.", e); + DebugConsole.ThrowError("Reading received remote main menu content failed.", e); #endif - GameAnalyticsManager.AddErrorEventOnce("MainMenuScreen.RemoteContentReceived:Exception", GameAnalyticsManager.ErrorSeverity.Error, - "Reading received remote main menu content failed. " + e.Message); + GameAnalyticsManager.AddErrorEventOnce("MainMenuScreen.WairForRemoteContentReceived:Exception", GameAnalyticsManager.ErrorSeverity.Error, + "Reading received remote main menu content failed. " + e.Message); + } + } + yield return CoroutineStatus.Success; + } + + private readonly object remoteContentLock = new object(); + private IRestResponse remoteContentResponse; + + private void RemoteContentReceived(IRestResponse response, RestRequestAsyncHandle handle) + { + lock (remoteContentLock) + { + remoteContentResponse = response; } } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/ModDownloadScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/ModDownloadScreen.cs index 71646a819..478571b01 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/ModDownloadScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/ModDownloadScreen.cs @@ -29,19 +29,10 @@ namespace Barotrauma currentDownload = null; confirmDownload = false; } - - private void DeletePrevDownloads() - { - if (Directory.Exists(ModReceiver.DownloadFolder)) - { - Directory.Delete(ModReceiver.DownloadFolder, recursive: true); - } - } public override void Select() { base.Select(); - DeletePrevDownloads(); Reset(); Frame.ClearChildren(); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs index 886cf512b..2e55fe64b 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs @@ -9,7 +9,11 @@ using System.Linq; using System.Threading; using System.Xml.Linq; using Microsoft.Xna.Framework.Input; +#if DEBUG +using System.IO; +#else using Barotrauma.IO; +#endif namespace Barotrauma { @@ -1258,9 +1262,7 @@ namespace Barotrauma } textBlock.Text = ToolBox.LimitString(textBlock.Text, textBlock.Font, textBlock.Rect.Width); - if (ep.Category == MapEntityCategory.ItemAssembly - && ep.ContentPackage?.Files.Length == 1 - && ContentPackageManager.LocalPackages.Contains(ep.ContentPackage)) + if (ep.Category == MapEntityCategory.ItemAssembly) { var deleteButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform, Anchor.BottomCenter) { MinSize = new Point(0, 20) }, TextManager.Get("Delete"), style: "GUIButtonSmall") @@ -2223,7 +2225,9 @@ namespace Barotrauma // gap positions --------------------- var gapPositionGroup = new GUILayoutGroup(new RectTransform(new Vector2(.975f, 0.1f), outpostSettingsContainer.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft); + new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), gapPositionGroup.RectTransform), TextManager.Get("outpostmodulegappositions"), textAlignment: Alignment.CenterLeft); + var gapPositionDropDown = new GUIDropDown(new RectTransform(new Vector2(0.5f, 1f), gapPositionGroup.RectTransform), text: "", selectMultiple: true); @@ -2267,49 +2271,6 @@ namespace Barotrauma }; gapPositionGroup.RectTransform.MinSize = new Point(0, gapPositionGroup.RectTransform.Children.Max(c => c.MinSize.Y)); - var canAttachToPrevGroup = new GUILayoutGroup(new RectTransform(new Vector2(.975f, 0.1f), outpostSettingsContainer.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft); - new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), canAttachToPrevGroup.RectTransform), TextManager.Get("canattachtoprevious"), textAlignment: Alignment.CenterLeft) - { - ToolTip = TextManager.Get("canattachtoprevious.tooltip") - }; - var canAttachToPrevDropDown = new GUIDropDown(new RectTransform(new Vector2(0.5f, 1f), canAttachToPrevGroup.RectTransform), - text: "", selectMultiple: true); - if (outpostModuleInfo != null) - { - foreach (var gapPos in Enum.GetValues(typeof(OutpostModuleInfo.GapPosition))) - { - if ((OutpostModuleInfo.GapPosition)gapPos == OutpostModuleInfo.GapPosition.None) { continue; } - canAttachToPrevDropDown.AddItem(TextManager.Capitalize(gapPos.ToString()), gapPos); - if (outpostModuleInfo.CanAttachToPrevious.HasFlag((OutpostModuleInfo.GapPosition)gapPos)) - { - canAttachToPrevDropDown.SelectItem(gapPos); - } - } - } - - canAttachToPrevDropDown.OnSelected += (_, __) => - { - if (Submarine.MainSub.Info?.OutpostModuleInfo == null) { return false; } - Submarine.MainSub.Info.OutpostModuleInfo.CanAttachToPrevious = OutpostModuleInfo.GapPosition.None; - if (canAttachToPrevDropDown.SelectedDataMultiple.Any()) - { - List gapPosTexts = new List(); - foreach (OutpostModuleInfo.GapPosition gapPos in canAttachToPrevDropDown.SelectedDataMultiple) - { - Submarine.MainSub.Info.OutpostModuleInfo.CanAttachToPrevious |= gapPos; - gapPosTexts.Add(TextManager.Capitalize(gapPos.ToString()).Value); - } - canAttachToPrevDropDown.Text = ToolBox.LimitString(string.Join(", ", gapPosTexts), canAttachToPrevDropDown.Font, canAttachToPrevDropDown.Rect.Width); - } - else - { - canAttachToPrevDropDown.Text = ToolBox.LimitString("None", canAttachToPrevDropDown.Font, canAttachToPrevDropDown.Rect.Width); - } - return true; - }; - canAttachToPrevGroup.RectTransform.MinSize = new Point(0, gapPositionGroup.RectTransform.Children.Max(c => c.MinSize.Y)); - - // ------------------- var maxModuleCountGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), outpostSettingsContainer.RectTransform), isHorizontal: true) @@ -2622,18 +2583,7 @@ namespace Barotrauma //don't show content packages that only define submarine files //(it doesn't make sense to require another sub to be installed to install this one) if (contentPack.Files.All(f => f is SubmarineFile)) { continue; } - - if (!contentPacks.Contains(contentPack.Name)) - { - string altName = contentPack.AltNames.FirstOrDefault(n => contentPacks.Contains(n)); - if (!string.IsNullOrEmpty(altName)) - { - MainSub.Info.RequiredContentPackages.Remove(altName); - MainSub.Info.RequiredContentPackages.Add(contentPack.Name); - contentPacks.Remove(altName); - } - contentPacks.Add(contentPack.Name); - } + if (!contentPacks.Contains(contentPack.Name)) { contentPacks.Add(contentPack.Name); } } foreach (string contentPackageName in contentPacks) @@ -2799,7 +2749,11 @@ namespace Barotrauma } bool hideInMenus = nameBox.Parent.GetChildByUserData("hideinmenus") is GUITickBox hideInMenusTickBox && hideInMenusTickBox.Selected; +#if DEBUG + string saveFolder = ItemAssemblyPrefab.VanillaSaveFolder; +#else string saveFolder = Path.Combine(ContentPackage.LocalModsDir, nameBox.Text); +#endif string filePath = Path.Combine(saveFolder, $"{nameBox.Text}.xml").CleanUpPathCrossPlatform(); if (File.Exists(filePath)) { @@ -2828,26 +2782,26 @@ namespace Barotrauma void Save() { - ContentPackage existingContentPackage = ContentPackageManager.LocalPackages.Regular.FirstOrDefault(p => p.Files.Any(f => f.Path == filePath)); + XDocument doc = new XDocument(ItemAssemblyPrefab.Save(MapEntity.SelectedList.ToList(), nameBox.Text, descriptionBox.Text, hideInMenus)); +#if DEBUG + doc.Save(filePath); +#else + doc.SaveSafe(filePath); +#endif + ContentPackage existingContentPackage = ContentPackageManager.LocalPackages.FirstOrDefault(p => p.Files.Any(f => f.Path == filePath)); if (existingContentPackage == null) { //content package doesn't exist, create one ModProject modProject = new ModProject() { Name = nameBox.Text }; - var newFile = ModProject.File.FromPath(Path.Combine(ContentPath.ModDirStr, $"{nameBox.Text}.xml")); + var newFile = ModProject.File.FromPath(filePath); modProject.AddFile(newFile); - string newPackagePath = ContentPackageManager.LocalPackages.SaveRegularMod(modProject); - existingContentPackage = ContentPackageManager.LocalPackages.GetRegularModByPath(newPackagePath); + ContentPackageManager.LocalPackages.SaveAndEnableRegularMod(modProject); } - - XDocument doc = new XDocument(ItemAssemblyPrefab.Save(MapEntity.SelectedList.ToList(), nameBox.Text, descriptionBox.Text, hideInMenus)); - doc.SaveSafe(filePath); - - var resultPackage = ContentPackageManager.ReloadContentPackage(existingContentPackage) as RegularPackage; - if (!ContentPackageManager.EnabledPackages.Regular.Contains(resultPackage)) + else { - ContentPackageManager.EnabledPackages.EnableRegular(resultPackage); + EnqueueForReload(existingContentPackage); } - + UpdateEntityList(); } @@ -2930,7 +2884,11 @@ namespace Barotrauma { if (deleteButtonHolder.FindChild("delete") is GUIButton deleteBtn) { - deleteBtn.Enabled = userData is SubmarineInfo subInfo && GetContentPackageIntrinsicallyTiedToSub(subInfo) != null; +#if DEBUG + deleteBtn.Enabled = true; +#else + deleteBtn.Enabled = userData is SubmarineInfo subInfo && !subInfo.IsVanillaSubmarine(); +#endif } return true; } @@ -3183,7 +3141,7 @@ namespace Barotrauma ReconstructLayers(); } - private static RegularPackage GetContentPackageIntrinsicallyTiedToSub(SubmarineInfo sub) + private RegularPackage GetContentPackageIntrinsicallyTiedToSub(SubmarineInfo sub) { foreach (RegularPackage regularPackage in ContentPackageManager.RegularPackages) { @@ -3213,11 +3171,10 @@ namespace Barotrauma { try { - Directory.Delete(Path.GetDirectoryName(subPackage.Path), recursive: true); - ContentPackageManager.LocalPackages.Refresh(); - ContentPackageManager.EnabledPackages.DisableRemovedMods(); + Directory.Delete(Path.GetDirectoryName(subPackage.Path), true); sub.Dispose(); + File.Delete(sub.FilePath); SubmarineInfo.RefreshSavedSubs(); CreateLoadScreen(); } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Serialization/SerializableEntityEditor.cs b/Barotrauma/BarotraumaClient/ClientSource/Serialization/SerializableEntityEditor.cs index af4eba036..f8186ff57 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Serialization/SerializableEntityEditor.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Serialization/SerializableEntityEditor.cs @@ -390,13 +390,13 @@ namespace Barotrauma } GUIComponent propertyField = null; - if (value is bool boolVal) + if (value is bool) { - propertyField = CreateBoolField(entity, property, boolVal, displayName, toolTip); + propertyField = CreateBoolField(entity, property, (bool)value, displayName, toolTip); } - else if (value is string stringVal) + else if (value is string) { - propertyField = CreateStringField(entity, property, stringVal, displayName, toolTip); + propertyField = CreateStringField(entity, property, (string)value, displayName, toolTip); } else if (value.GetType().IsEnum) { @@ -1277,7 +1277,7 @@ namespace Barotrauma public void CreateTextPicker(string textTag, ISerializableEntity entity, SerializableProperty property, GUITextBox textBox) { - var msgBox = new GUIMessageBox("", "", new LocalizedString[] { TextManager.Get("Ok") }, new Vector2(0.2f, 0.5f), new Point(300, 400)); + var msgBox = new GUIMessageBox("", "", new LocalizedString[] { TextManager.Get("Cancel") }, new Vector2(0.2f, 0.5f), new Point(300, 400)); msgBox.Buttons[0].OnClicked = msgBox.Close; var textList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.8f), msgBox.Content.RectTransform, Anchor.TopCenter)) @@ -1307,18 +1307,6 @@ namespace Barotrauma UserData = tagTextPair.Key.ToString() }; } - - if (entity is IHasExtraTextPickerEntries hasExtraTextPickerEntries) - { - foreach (string extraEntry in hasExtraTextPickerEntries.GetExtraTextPickerEntries()) - { - new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), textList.Content.RectTransform) { MinSize = new Point(0, 20) }, - ToolBox.LimitString(extraEntry, GUIStyle.Font, textList.Content.Rect.Width), GUIStyle.Green) - { - UserData = extraEntry - }; - } - } } private void TrySendNetworkUpdate(ISerializableEntity entity, SerializableProperty property) @@ -1457,12 +1445,4 @@ namespace Barotrauma } } } - - /// - /// Implement this interface to insert extra entires to the text pickers created for the SerializableEntityEditors of the entity - /// - interface IHasExtraTextPickerEntries - { - public IEnumerable GetExtraTextPickerEntries(); - } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Steam/PublishTab.cs b/Barotrauma/BarotraumaClient/ClientSource/Steam/PublishTab.cs index 978e6d971..45fa95f50 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Steam/PublishTab.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Steam/PublishTab.cs @@ -89,22 +89,23 @@ namespace Barotrauma.Steam return (fileCount, byteCount); } - - private void DeselectPublishedItem() - { - var deselectCarrier = selfModsList.Parent.FindChild(c => c.UserData is ActionCarrier { Id: var id } && id == "deselect"); - Action? deselectAction = deselectCarrier.UserData is ActionCarrier { Action: var action } - ? action - : null; - deselectAction?.Invoke(); - SelectTab(Tab.Publish); - } private void PopulatePublishTab(ItemOrPackage itemOrPackage, GUIFrame parentFrame) { ContentPackageManager.LocalPackages.Refresh(); ContentPackageManager.WorkshopPackages.Refresh(); + var deselectCarrier = selfModsList.Parent.FindChild(c => c.UserData is ActionCarrier { Id: var id } && id == "deselect"); + Action? deselectAction = deselectCarrier.UserData is ActionCarrier { Action: var action } + ? action + : null; + + void deselectItem() + { + deselectAction?.Invoke(); + SelectTab(Tab.Publish); + } + parentFrame.ClearChildren(); GUILayoutGroup mainLayout = new GUILayoutGroup(new RectTransform(Vector2.One, parentFrame.RectTransform), childAnchor: Anchor.TopCenter); @@ -145,7 +146,7 @@ namespace Barotrauma.Steam { OnClicked = (button, o) => { - DeselectPublishedItem(); + deselectItem(); return false; } }; @@ -333,7 +334,7 @@ namespace Barotrauma.Steam t => { confirmDeletion.Close(); - DeselectPublishedItem(); + deselectItem(); }); return false; }; @@ -363,10 +364,24 @@ namespace Barotrauma.Steam return false; }; - var coroutineEval = subcoroutine(messageBox.Text, messageBox).GetEnumerator(); + var coroutineEval = subcoroutine(messageBox.Text, messageBox); while (true) { - var status = coroutineEval.Current; + bool moveNext = true; + try + { + moveNext = coroutineEval.GetEnumerator().MoveNext(); + } + catch (Exception e) + { + DebugConsole.ThrowError($"{e.Message} {e.StackTrace.CleanupStackTrace()}"); + messageBox.Close(); + } + if (!moveNext) + { + messageBox.Close(); + } + var status = coroutineEval.GetEnumerator().Current; if (messageBox.Closed) { yield return CoroutineStatus.Success; @@ -382,20 +397,6 @@ namespace Barotrauma.Steam { yield return status; } - bool moveNext = true; - try - { - moveNext = coroutineEval.MoveNext(); - } - catch (Exception e) - { - DebugConsole.ThrowError($"{e.Message} {e.StackTrace.CleanupStackTrace()}"); - messageBox.Close(); - } - if (!moveNext) - { - messageBox.Close(); - } } } @@ -407,9 +408,26 @@ namespace Barotrauma.Steam { if (!SteamManager.Workshop.CanBeInstalled(workshopItem)) { - SteamManager.Workshop.NukeDownload(workshopItem); + //Must download! + while (!SteamManager.Workshop.CanBeInstalled(workshopItem)) + { + bool shouldForceInstall = workshopItem.IsInstalled + && Directory.Exists(workshopItem.Directory) + && !SteamManager.Workshop.IsItemDirectoryUpToDate(workshopItem); + shouldForceInstall |= workshopItem is + { IsDownloading: false, IsDownloadPending: false, IsInstalled: false }; + if (shouldForceInstall) + { + SteamManager.Workshop.ForceRedownload(workshopItem); + } + currentStepText.Text = TextManager.GetWithVariable("PublishPopupDownload", "[percentage]", Percentage(workshopItem.DownloadAmount)); + yield return new WaitForSeconds(0.5f); + } + } + else + { + SteamManager.Workshop.DownloadModThenEnqueueInstall(workshopItem); } - SteamManager.Workshop.DownloadModThenEnqueueInstall(workshopItem); TaskPool.Add($"Install {workshopItem.Title}", SteamManager.Workshop.WaitForInstall(workshopItem), (t) => @@ -418,9 +436,7 @@ namespace Barotrauma.Steam }); while (!ContentPackageManager.WorkshopPackages.Any(p => p.SteamWorkshopId == workshopItem.Id)) { - currentStepText.Text = SteamManager.Workshop.CanBeInstalled(workshopItem) - ? TextManager.Get("PublishPopupInstall") - : TextManager.GetWithVariable("PublishPopupDownload", "[percentage]", Percentage(workshopItem.DownloadAmount)); + currentStepText.Text = TextManager.Get("PublishPopupInstall"); yield return new WaitForSeconds(0.5f); } @@ -441,6 +457,7 @@ namespace Barotrauma.Steam currentStepText.Text = TextManager.Get("PublishPopupCreateLocal"); yield return new WaitForSeconds(0.5f); } + PopulatePublishTab(workshopItem, parentFrame); yield return CoroutineStatus.Success; @@ -483,10 +500,7 @@ namespace Barotrauma.Steam editor.SubmitAsync(), t => { - if (t.TryGetResult(out Steamworks.Ugc.PublishResult publishResult)) - { - result = publishResult; - } + t.TryGetResult(out result); resultException = t.Exception?.GetInnermost(); }); currentStepText.Text = TextManager.Get("PublishPopupSubmit"); @@ -509,14 +523,6 @@ namespace Barotrauma.Steam $"exception was {downloadTask.Exception?.GetInnermost()?.ToString().CleanupStackTrace() ?? "[NULL]"}"); } - ContentPackage? pkgToNuke - = ContentPackageManager.WorkshopPackages.FirstOrDefault(p => p.SteamWorkshopId == resultId); - if (pkgToNuke != null) - { - Directory.Delete(pkgToNuke.Dir, recursive: true); - ContentPackageManager.WorkshopPackages.Refresh(); - } - bool installed = false; TaskPool.Add( "InstallNewlyPublished", @@ -535,11 +541,9 @@ namespace Barotrauma.Steam { SteamWorkshopId = resultId }; - localModProject.DiscardHashAndInstallTime(); localModProject.Save(localPackage.Path); ContentPackageManager.ReloadContentPackage(localPackage); ContentPackageManager.WorkshopPackages.Refresh(); - DeselectPublishedItem(); if (result.Value.NeedsWorkshopAgreement) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Steam/Workshop.cs b/Barotrauma/BarotraumaClient/ClientSource/Steam/Workshop.cs index f865ca3f0..fe499a4d9 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Steam/Workshop.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Steam/Workshop.cs @@ -207,11 +207,6 @@ namespace Barotrauma.Steam } string newPath = $"{ContentPackage.LocalModsDir}/{sanitizedName}"; - if (File.Exists(newPath) || Directory.Exists(newPath)) - { - newPath += $"_{contentPackage.SteamWorkshopId}"; - } - if (File.Exists(newPath) || Directory.Exists(newPath)) { throw new Exception($"{newPath} already exists"); diff --git a/Barotrauma/BarotraumaClient/LinuxClient.csproj b/Barotrauma/BarotraumaClient/LinuxClient.csproj index 6a04f3da2..80a620bcc 100644 --- a/Barotrauma/BarotraumaClient/LinuxClient.csproj +++ b/Barotrauma/BarotraumaClient/LinuxClient.csproj @@ -6,8 +6,8 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.17.3.0 - Copyright © FakeFish 2018-2022 + 0.17.2.0 + Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma ..\BarotraumaShared\Icon.ico diff --git a/Barotrauma/BarotraumaClient/MacClient.csproj b/Barotrauma/BarotraumaClient/MacClient.csproj index 6d3ace4d5..20a82c153 100644 --- a/Barotrauma/BarotraumaClient/MacClient.csproj +++ b/Barotrauma/BarotraumaClient/MacClient.csproj @@ -6,8 +6,8 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.17.3.0 - Copyright © FakeFish 2018-2022 + 0.17.2.0 + Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma ..\BarotraumaShared\Icon.ico diff --git a/Barotrauma/BarotraumaClient/WindowsClient.csproj b/Barotrauma/BarotraumaClient/WindowsClient.csproj index dc69d29ec..35a96ffc0 100644 --- a/Barotrauma/BarotraumaClient/WindowsClient.csproj +++ b/Barotrauma/BarotraumaClient/WindowsClient.csproj @@ -6,8 +6,8 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.17.3.0 - Copyright © FakeFish 2018-2022 + 0.17.2.0 + Copyright © FakeFish 2018-2020 AnyCPU;x64 Barotrauma ..\BarotraumaShared\Icon.ico diff --git a/Barotrauma/BarotraumaServer/LinuxServer.csproj b/Barotrauma/BarotraumaServer/LinuxServer.csproj index cf1901a55..c599af014 100644 --- a/Barotrauma/BarotraumaServer/LinuxServer.csproj +++ b/Barotrauma/BarotraumaServer/LinuxServer.csproj @@ -6,8 +6,8 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.17.3.0 - Copyright © FakeFish 2018-2022 + 0.17.2.0 + Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer ..\BarotraumaShared\Icon.ico diff --git a/Barotrauma/BarotraumaServer/MacServer.csproj b/Barotrauma/BarotraumaServer/MacServer.csproj index 4546b9a91..036a8d02c 100644 --- a/Barotrauma/BarotraumaServer/MacServer.csproj +++ b/Barotrauma/BarotraumaServer/MacServer.csproj @@ -6,8 +6,8 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.17.3.0 - Copyright © FakeFish 2018-2022 + 0.17.2.0 + Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer ..\BarotraumaShared\Icon.ico diff --git a/Barotrauma/BarotraumaServer/ServerSource/Characters/Character.cs b/Barotrauma/BarotraumaServer/ServerSource/Characters/Character.cs index 2e5acdab7..49405004e 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Characters/Character.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Characters/Character.cs @@ -5,7 +5,7 @@ namespace Barotrauma { partial class Character { - public static Character Controlled => null; + public static Character Controlled = null; partial void OnAttackedProjSpecific(Character attacker, AttackResult attackResult, float stun) { diff --git a/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs b/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs index 10e4452f9..7d8e7791e 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterNetworking.cs @@ -424,7 +424,7 @@ namespace Barotrauma msg.Write(owner == c && owner.Character == this); msg.Write(owner != null && owner.Character == this && GameMain.Server.ConnectedClients.Contains(owner) ? owner.ID : (byte)0); break; - case CharacterStatusEventData _: + case StatusEventData _: WriteStatus(msg); break; case UpdateSkillsEventData _: diff --git a/Barotrauma/BarotraumaServer/ServerSource/GameSession/CargoManager.cs b/Barotrauma/BarotraumaServer/ServerSource/GameSession/CargoManager.cs index b84aa42af..00190b2fd 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/GameSession/CargoManager.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/GameSession/CargoManager.cs @@ -21,7 +21,7 @@ namespace Barotrauma } } - public void BuyBackSoldItems(List itemsToBuy) + public void BuyBackSoldItems(List itemsToBuy, Client client) { // Check all the prices before starting the transaction // to make sure the modifiers stay the same for the whole transaction diff --git a/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs b/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs index d64ecfb71..fbd7d030e 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs @@ -859,19 +859,19 @@ namespace Barotrauma { // for some reason CargoManager.SoldItem is never cleared by the server, I've added a check to SellItems that ignores all // sold items that are removed so they should be discarded on the next message - CargoManager.BuyBackSoldItems(new List(CargoManager.SoldItems)); + CargoManager.BuyBackSoldItems(new List(CargoManager.SoldItems), sender); CargoManager.SellItems(soldItems, sender); } else if (allowedToSellInventoryItems || allowedToSellSubItems) { if (allowedToSellInventoryItems) { - CargoManager.BuyBackSoldItems(new List(CargoManager.SoldItems.Where(i => i.Origin == SoldItem.SellOrigin.Character))); + CargoManager.BuyBackSoldItems(new List(CargoManager.SoldItems.Where(i => i.Origin == SoldItem.SellOrigin.Character)), sender); soldItems.RemoveAll(i => i.Origin != SoldItem.SellOrigin.Character); } else { - CargoManager.BuyBackSoldItems(new List(CargoManager.SoldItems.Where(i => i.Origin == SoldItem.SellOrigin.Submarine))); + CargoManager.BuyBackSoldItems(new List(CargoManager.SoldItems.Where(i => i.Origin == SoldItem.SellOrigin.Submarine)), sender); soldItems.RemoveAll(i => i.Origin != SoldItem.SellOrigin.Submarine); } CargoManager.SellItems(soldItems, sender); @@ -960,7 +960,7 @@ namespace Barotrauma public void ServerReadRewardDistribution(IReadMessage msg, Client sender) { - NetWalletSetSalaryUpdate update = INetSerializableStruct.Read(msg); + NetWalletSalaryUpdate update = INetSerializableStruct.Read(msg); if (!AllowedToManageCampaign(sender)) { return; } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Items/Item.cs b/Barotrauma/BarotraumaServer/ServerSource/Items/Item.cs index f7db7648e..8f1783707 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Items/Item.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Items/Item.cs @@ -56,6 +56,7 @@ namespace Barotrauma if (containerIndex < 0) { throw error($"container index out of range ({containerIndex})"); + break; } if (!(components[containerIndex] is ItemContainer itemContainer)) { @@ -65,7 +66,7 @@ namespace Barotrauma msg.Write(GameMain.Server.EntityEventManager.Events.Last()?.ID ?? (ushort)0); itemContainer.Inventory.ServerEventWrite(msg, c); break; - case ItemStatusEventData _: + case StatusEventData _: msg.Write(condition); break; case AssignCampaignInteractionEventData _: diff --git a/Barotrauma/BarotraumaServer/ServerSource/Map/Creatures/BallastFloraBehavior.cs b/Barotrauma/BarotraumaServer/ServerSource/Map/Creatures/BallastFloraBehavior.cs index 9645311ce..0707bd526 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Map/Creatures/BallastFloraBehavior.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Map/Creatures/BallastFloraBehavior.cs @@ -1,13 +1,12 @@ using Barotrauma.Items.Components; using Barotrauma.Networking; using System; +using System.Xml.Linq; namespace Barotrauma.MapCreatures.Behavior { partial class BallastFloraBehavior { - const float DamageUpdateInterval = 1.0f; - private float damageUpdateTimer; partial void LoadPrefab(ContentXElement element) @@ -32,38 +31,16 @@ namespace Barotrauma.MapCreatures.Behavior } } - partial void UpdateDamage(float deltaTime) - { - damageUpdateTimer -= deltaTime; - if (damageUpdateTimer > 0.0f) { return; } - - const int maxMessagesPerSecond = 10; - int messages = 0; - foreach (BallastFloraBranch branch in Branches) - { - //don't notify about minuscule amounts of damage (<= 1.0f) - if (branch.AccumulatedDamage > 1.0f) - { - CreateNetworkMessage(new BranchDamageEventData(branch)); - branch.AccumulatedDamage = 0.0f; - messages++; - //throttle a bit: if a large ballast flora is withering, it can lead to a very large number of events otherwise - if (messages > maxMessagesPerSecond) { break; } - } - } - damageUpdateTimer = DamageUpdateInterval; - } - public void ServerWrite(IWriteMessage msg, IEventData eventData) { msg.Write((byte)eventData.NetworkHeader); switch (eventData) { - case SpawnEventData _: + case SpawnEventData spawnEventData: ServerWriteSpawn(msg); break; - case KillEventData _: + case KillEventData killEventData: //do nothing break; case BranchCreateEventData branchCreateEventData: @@ -95,7 +72,6 @@ namespace Barotrauma.MapCreatures.Behavior var (x, y) = branch.Position; msg.Write(parentId); msg.Write((int)branch.ID); - msg.Write(branch.IsRootGrowth); msg.WriteRangedInteger((byte)branch.Type, 0b0000, 0b1111); msg.WriteRangedInteger((byte)branch.Sides, 0b0000, 0b1111); msg.WriteRangedInteger(branch.FlowerConfig.Serialize(), 0, 0xFFF); @@ -127,7 +103,7 @@ namespace Barotrauma.MapCreatures.Behavior msg.Write(branch.ID); } - public void CreateNetworkMessage(IEventData extraData) + public void SendNetworkMessage(IEventData extraData) { GameMain.Server.CreateEntityEvent(Parent, new Hull.BallastFloraEventData(this, extraData)); } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/FileTransfer/ModSender.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/FileTransfer/ModSender.cs index 93a36099e..7a8d742eb 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/FileTransfer/ModSender.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/FileTransfer/ModSender.cs @@ -28,11 +28,7 @@ namespace Barotrauma.Networking public static string GetCompressedModPath(ContentPackage mod) { string dir = mod.Dir; - string resultFileName - = dir.StartsWith(ContentPackage.LocalModsDir) - ? $"Local_{mod.Name}" - : $"Workshop_{mod.Name}"; - resultFileName = ToolBox.RemoveInvalidFileNameChars(resultFileName.Replace('\\', '_').Replace('/', '_')); + string resultFileName = dir.Replace('\\', '_').Replace('/', '_'); resultFileName = $"{resultFileName}{Extension}"; return Path.Combine(UploadFolder, resultFileName); } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs index 4373de52d..804c11d40 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs @@ -814,7 +814,7 @@ namespace Barotrauma.Networking case ClientPacketHeader.CREW: ReadCrewMessage(inc, connectedClient); break; - case ClientPacketHeader.TRANSFER_MONEY: + case ClientPacketHeader.MONEY: ReadMoneyMessage(inc, connectedClient); break; case ClientPacketHeader.REWARD_DISTRIBUTION: diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/ServerSettings.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/ServerSettings.cs index 5580a12fe..334e62414 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/ServerSettings.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/ServerSettings.cs @@ -321,16 +321,11 @@ namespace Barotrauma.Networking GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled); HiddenSubs.UnionWith(doc.Root.GetAttributeStringArray("HiddenSubs", Array.Empty())); - if (HiddenSubs.Any()) - { - UpdateFlag(NetFlags.HiddenSubs); - } SelectedSubmarine = SelectNonHiddenSubmarine(SelectedSubmarine); string[] defaultAllowedClientNameChars = - new string[] - { + new string[] { "32-33", "38-46", "48-57", diff --git a/Barotrauma/BarotraumaServer/ServerSource/Traitors/Traitor.cs b/Barotrauma/BarotraumaServer/ServerSource/Traitors/Traitor.cs index ba77838e6..715ef5a3a 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Traitors/Traitor.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Traitors/Traitor.cs @@ -16,7 +16,7 @@ namespace Barotrauma Role = role; Character = character; Character.IsTraitor = true; - GameMain.NetworkMember.CreateEntityEvent(Character, new Character.CharacterStatusEventData()); + GameMain.NetworkMember.CreateEntityEvent(Character, new Character.StatusEventData()); } public delegate void MessageSender(string message); diff --git a/Barotrauma/BarotraumaServer/WindowsServer.csproj b/Barotrauma/BarotraumaServer/WindowsServer.csproj index 0b4d31d6b..989383c24 100644 --- a/Barotrauma/BarotraumaServer/WindowsServer.csproj +++ b/Barotrauma/BarotraumaServer/WindowsServer.csproj @@ -6,8 +6,8 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.17.3.0 - Copyright © FakeFish 2018-2022 + 0.17.2.0 + Copyright © FakeFish 2018-2020 AnyCPU;x64 DedicatedServer ..\BarotraumaShared\Icon.ico diff --git a/Barotrauma/BarotraumaClient/ClientSource/CameraTransition.cs b/Barotrauma/BarotraumaShared/SharedSource/CameraTransition.cs similarity index 100% rename from Barotrauma/BarotraumaClient/ClientSource/CameraTransition.cs rename to Barotrauma/BarotraumaShared/SharedSource/CameraTransition.cs diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs index 25e64fa6b..48ef25dce 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/EnemyAIController.cs @@ -56,7 +56,7 @@ namespace Barotrauma private readonly float updateTargetsInterval = 1; private readonly float updateMemoriesInverval = 1; - private readonly float attackLimbSelectionInterval = 3; + private readonly float attackLimbResetInterval = 2; // Min priority for the memorized targets. The actual value fades gradually, unless kept fresh by selecting the target. private const float minPriority = 10; @@ -65,10 +65,10 @@ namespace Barotrauma private float updateTargetsTimer; private float updateMemoriesTimer; - private float attackLimbSelectionTimer; + private float attackLimbResetTimer; - private bool IsAttackRunning => AttackLimb != null && AttackLimb.attack.IsRunning; - private bool IsCoolDownRunning => AttackLimb != null && AttackLimb.attack.CoolDownTimer > 0 || _previousAttackLimb != null && _previousAttackLimb.attack.CoolDownTimer > 0; + private bool IsAttackRunning => AttackingLimb != null && AttackingLimb.attack.IsRunning; + private bool IsCoolDownRunning => AttackingLimb != null && AttackingLimb.attack.CoolDownTimer > 0 || _previousAttackingLimb != null && _previousAttackingLimb.attack.CoolDownTimer > 0; public float CombatStrength => AIParams.CombatStrength; private float Sight => AIParams.Sight; private float Hearing => AIParams.Hearing; @@ -77,25 +77,25 @@ namespace Barotrauma private FishAnimController FishAnimController => Character.AnimController as FishAnimController; - private Limb _attackLimb; - private Limb _previousAttackLimb; - public Limb AttackLimb + private Limb _attackingLimb; + private Limb _previousAttackingLimb; + public Limb AttackingLimb { - get { return _attackLimb; } + get { return _attackingLimb; } private set { - if (_attackLimb != value) + attackLimbResetTimer = 0; + if (_attackingLimb != value) { - _previousAttackLimb = _attackLimb; - _previousAttackLimb?.AttachedRope?.Snap(); + _previousAttackingLimb = _attackingLimb; } - else if (_attackLimb != null && _attackLimb.attack.CoolDownTimer <= 0) + if (_attackingLimb != null && value != _attackingLimb && _attackingLimb.attack.CoolDownTimer > 0) { - _attackLimb.AttachedRope?.Snap(); + SetAimTimer(); } - _attackLimb = value; + _attackingLimb = value; attackVector = null; - Reverse = _attackLimb != null && _attackLimb.attack.Reverse; + Reverse = _attackingLimb != null && _attackingLimb.attack.Reverse; } } @@ -425,8 +425,7 @@ namespace Barotrauma private void ReleaseDragTargets() { - AttackLimb?.AttachedRope?.Snap(); - if (Character.Params.CanInteract && Character.Inventory != null) + if (Character.Inventory != null) { Character.HeldItems.ForEach(i => i.GetComponent()?.GetRope()?.Snap()); } @@ -601,7 +600,7 @@ namespace Barotrauma UpdatePatrol(deltaTime); break; case AIState.Attack: - run = !IsCoolDownRunning || AttackLimb != null && AttackLimb.attack.FullSpeedAfterAttack; + run = !IsCoolDownRunning || AttackingLimb != null && AttackingLimb.attack.FullSpeedAfterAttack; UpdateAttack(deltaTime); break; case AIState.Eat: @@ -621,7 +620,7 @@ namespace Barotrauma return; } float squaredDistance = Vector2.DistanceSquared(WorldPosition, SelectedAiTarget.WorldPosition); - var attackLimb = AttackLimb ?? GetAttackLimb(SelectedAiTarget.WorldPosition); + var attackLimb = AttackingLimb ?? GetAttackLimb(SelectedAiTarget.WorldPosition); if (attackLimb != null && squaredDistance <= Math.Pow(attackLimb.attack.Range, 2)) { run = true; @@ -876,10 +875,7 @@ namespace Barotrauma if (followLastTarget) { var target = SelectedAiTarget ?? _lastAiTarget; - if (target?.Entity != null && !target.Entity.Removed && - PreviousState == AIState.Attack && Character.CurrentHull == null && - (_previousAttackLimb?.attack == null || - _previousAttackLimb?.attack is Attack previousAttack && (previousAttack.AfterAttack != AIBehaviorAfterAttack.FallBack || previousAttack.CoolDownTimer <= 0))) + if (target?.Entity != null && !target.Entity.Removed && PreviousState == AIState.Attack && Character.CurrentHull == null) { // Keep heading to the last known position of the target var memory = GetTargetMemory(target, false); @@ -1130,42 +1126,31 @@ namespace Barotrauma return; } } - - attackLimbSelectionTimer -= deltaTime; - if (AttackLimb == null || attackLimbSelectionTimer <= 0) - { - attackLimbSelectionTimer = attackLimbSelectionInterval * Rand.Range(0.9f, 1.1f); - if (!IsAttackRunning && !IsCoolDownRunning) - { - AttackLimb = GetAttackLimb(attackWorldPos); - } - } bool canAttack = true; bool pursue = false; - if (IsCoolDownRunning && (_previousAttackLimb == null || AttackLimb == null || AttackLimb.attack.CoolDownTimer > 0)) + if (IsCoolDownRunning) { - var currentAttackLimb = AttackLimb ?? _previousAttackLimb; + var currentAttackLimb = AttackingLimb ?? _previousAttackingLimb; if (currentAttackLimb.attack.CoolDownTimer >= currentAttackLimb.attack.CoolDown + currentAttackLimb.attack.CurrentRandomCoolDown - currentAttackLimb.attack.AfterAttackDelay) { return; } - AIBehaviorAfterAttack activeBehavior = currentAttackLimb.attack.AfterAttack; - switch (activeBehavior) + switch (currentAttackLimb.attack.AfterAttack) { case AIBehaviorAfterAttack.Pursue: case AIBehaviorAfterAttack.PursueIfCanAttack: if (currentAttackLimb.attack.SecondaryCoolDown <= 0) { // No (valid) secondary cooldown defined. - if (activeBehavior == AIBehaviorAfterAttack.Pursue) + if (currentAttackLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue) { canAttack = false; pursue = true; } else { - UpdateFallBack(attackWorldPos, deltaTime, followThrough: true); + UpdateFallBack(attackWorldPos, deltaTime, true); return; } } @@ -1177,13 +1162,13 @@ namespace Barotrauma if (_previousAiTarget != null && SelectedAiTarget != _previousAiTarget) { canAttack = false; - if (activeBehavior == AIBehaviorAfterAttack.PursueIfCanAttack) + if (currentAttackLimb.attack.AfterAttack == AIBehaviorAfterAttack.PursueIfCanAttack) { // Fall back if cannot attack. - UpdateFallBack(attackWorldPos, deltaTime, followThrough: true); + UpdateFallBack(attackWorldPos, deltaTime, true); return; } - AttackLimb = null; + AttackingLimb = null; } else { @@ -1192,19 +1177,19 @@ namespace Barotrauma if (newLimb != null) { // Attack with the new limb - AttackLimb = newLimb; + AttackingLimb = newLimb; } else { // No new limb was found. - if (activeBehavior == AIBehaviorAfterAttack.Pursue) + if (currentAttackLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue) { canAttack = false; pursue = true; } else { - UpdateFallBack(attackWorldPos, deltaTime, followThrough: true); + UpdateFallBack(attackWorldPos, deltaTime, true); return; } } @@ -1219,15 +1204,10 @@ namespace Barotrauma break; case AIBehaviorAfterAttack.FallBackUntilCanAttack: case AIBehaviorAfterAttack.FollowThroughUntilCanAttack: - case AIBehaviorAfterAttack.ReverseUntilCanAttack: - if (activeBehavior == AIBehaviorAfterAttack.ReverseUntilCanAttack) - { - Reverse = true; - } if (currentAttackLimb.attack.SecondaryCoolDown <= 0) { // No (valid) secondary cooldown defined. - UpdateFallBack(attackWorldPos, deltaTime, activeBehavior == AIBehaviorAfterAttack.FollowThroughUntilCanAttack); + UpdateFallBack(attackWorldPos, deltaTime, currentAttackLimb.attack.AfterAttack == AIBehaviorAfterAttack.FollowThroughUntilCanAttack); return; } else @@ -1237,7 +1217,7 @@ namespace Barotrauma // Don't allow attacking when the attack target has just changed. if (_previousAiTarget != null && SelectedAiTarget != _previousAiTarget) { - UpdateFallBack(attackWorldPos, deltaTime, activeBehavior == AIBehaviorAfterAttack.FollowThroughUntilCanAttack); + UpdateFallBack(attackWorldPos, deltaTime, currentAttackLimb.attack.AfterAttack == AIBehaviorAfterAttack.FollowThroughUntilCanAttack); return; } else @@ -1247,12 +1227,12 @@ namespace Barotrauma if (newLimb != null) { // Attack with the new limb - AttackLimb = newLimb; + AttackingLimb = newLimb; } else { // No new limb was found. - UpdateFallBack(attackWorldPos, deltaTime, activeBehavior == AIBehaviorAfterAttack.FollowThroughUntilCanAttack); + UpdateFallBack(attackWorldPos, deltaTime, currentAttackLimb.attack.AfterAttack == AIBehaviorAfterAttack.FollowThroughUntilCanAttack); return; } } @@ -1260,7 +1240,7 @@ namespace Barotrauma else { // Cooldown not yet expired -> steer away from the target - UpdateFallBack(attackWorldPos, deltaTime, activeBehavior == AIBehaviorAfterAttack.FollowThroughUntilCanAttack); + UpdateFallBack(attackWorldPos, deltaTime, currentAttackLimb.attack.AfterAttack == AIBehaviorAfterAttack.FollowThroughUntilCanAttack); return; } } @@ -1289,7 +1269,7 @@ namespace Barotrauma if (newLimb != null) { // Attack with the new limb - AttackLimb = newLimb; + AttackingLimb = newLimb; } else { @@ -1311,12 +1291,7 @@ namespace Barotrauma UpdateFallBack(attackWorldPos, deltaTime, followThrough: true); return; case AIBehaviorAfterAttack.FallBack: - case AIBehaviorAfterAttack.Reverse: default: - if (activeBehavior == AIBehaviorAfterAttack.Reverse) - { - Reverse = true; - } UpdateFallBack(attackWorldPos, deltaTime, followThrough: false); return; } @@ -1328,13 +1303,12 @@ namespace Barotrauma if (canAttack) { - if (AttackLimb == null || !IsValidAttack(AttackLimb, Character.GetAttackContexts(), SelectedAiTarget?.Entity)) + if (AttackingLimb == null || !IsValidAttack(AttackingLimb, Character.GetAttackContexts(), SelectedAiTarget?.Entity as IDamageable)) { - AttackLimb = GetAttackLimb(attackWorldPos); + AttackingLimb = GetAttackLimb(attackWorldPos); } - canAttack = AttackLimb != null && AttackLimb.attack.CoolDownTimer <= 0; + canAttack = AttackingLimb != null && AttackingLimb.attack.CoolDownTimer <= 0; } - if (!AIParams.CanOpenDoors) { if (!Character.AnimController.SimplePhysicsEnabled && SelectedAiTarget.Entity.Submarine != null && Character.Submarine == null && (!canAttackDoors || !canAttackWalls || !AIParams.TargetOuterWalls)) @@ -1373,8 +1347,8 @@ namespace Barotrauma // Target a specific limb instead of the target center position if (wallTarget == null && targetCharacter != null) { - var targetLimbType = AttackLimb.Params.Attack.Attack.TargetLimbType; - attackTargetLimb = GetTargetLimb(AttackLimb, targetCharacter, targetLimbType); + var targetLimbType = AttackingLimb.Params.Attack.Attack.TargetLimbType; + attackTargetLimb = GetTargetLimb(AttackingLimb, targetCharacter, targetLimbType); if (attackTargetLimb == null) { State = AIState.Idle; @@ -1387,7 +1361,7 @@ namespace Barotrauma } } - Vector2 attackLimbPos = Character.AnimController.SimplePhysicsEnabled ? Character.WorldPosition : AttackLimb.WorldPosition; + Vector2 attackLimbPos = Character.AnimController.SimplePhysicsEnabled ? Character.WorldPosition : AttackingLimb.WorldPosition; Vector2 toTarget = attackWorldPos - attackLimbPos; // Add a margin when the target is moving away, because otherwise it might be difficult to reach it if the attack takes some time to execute if (wallTarget != null && Character.Submarine == null) @@ -1415,23 +1389,23 @@ namespace Barotrauma Vector2 CalculateMargin(Vector2 targetVelocity) { if (targetVelocity == Vector2.Zero) { return Vector2.Zero; } - float diff = AttackLimb.attack.Range - AttackLimb.attack.DamageRange; - if (diff <= 0 || toTarget.LengthSquared() <= MathUtils.Pow2(AttackLimb.attack.DamageRange)) { return Vector2.Zero; } + float diff = AttackingLimb.attack.Range - AttackingLimb.attack.DamageRange; + if (diff <= 0 || toTarget.LengthSquared() <= MathUtils.Pow2(AttackingLimb.attack.DamageRange)) { return Vector2.Zero; } float dot = Vector2.Dot(Vector2.Normalize(targetVelocity), Vector2.Normalize(Character.AnimController.Collider.LinearVelocity)); if (dot <= 0 || !MathUtils.IsValid(dot)) { return Vector2.Zero; } - float distanceOffset = diff * AttackLimb.attack.Duration; + float distanceOffset = diff * AttackingLimb.attack.Duration; // Intentionally omit the unit conversion because we use distanceOffset as a multiplier. return targetVelocity * distanceOffset * dot; } // Check that we can reach the target distance = toTarget.Length(); - canAttack = distance < AttackLimb.attack.Range; + canAttack = distance < AttackingLimb.attack.Range; // Crouch if the target is down (only humanoids), so that we can reach it. - if (Character.AnimController is HumanoidAnimController humanoidAnimController && distance < AttackLimb.attack.Range * 2) + if (Character.AnimController is HumanoidAnimController humanoidAnimController && distance < AttackingLimb.attack.Range * 2) { - if (Math.Abs(toTarget.Y) > AttackLimb.attack.Range / 2 && Math.Abs(toTarget.X) <= AttackLimb.attack.Range) + if (Math.Abs(toTarget.Y) > AttackingLimb.attack.Range / 2 && Math.Abs(toTarget.X) <= AttackingLimb.attack.Range) { humanoidAnimController.Crouching = true; } @@ -1439,14 +1413,14 @@ namespace Barotrauma if (canAttack) { - if (AttackLimb.attack.Ranged) + if (AttackingLimb.attack.Ranged) { // Check that is facing the target - float offset = AttackLimb.Params.GetSpriteOrientation() - MathHelper.PiOver2; - Vector2 forward = VectorExtensions.Forward(AttackLimb.body.TransformedRotation - offset * Character.AnimController.Dir); + float offset = AttackingLimb.Params.GetSpriteOrientation() - MathHelper.PiOver2; + Vector2 forward = VectorExtensions.Forward(AttackingLimb.body.TransformedRotation - offset * Character.AnimController.Dir); float angle = VectorExtensions.Angle(forward, toTarget); - canAttack = angle < MathHelper.ToRadians(AttackLimb.attack.RequiredAngle); - if (canAttack && AttackLimb.attack.AvoidFriendlyFire) + canAttack = angle < MathHelper.ToRadians(AttackingLimb.attack.RequiredAngle); + if (canAttack && AttackingLimb.attack.AvoidFriendlyFire) { float minDistance = MathUtils.Pow(ConvertUnits.ToDisplayUnits(Character.AnimController.Collider.GetMaxExtent() * 3), 2); bool IsFarEnough(Character other) => Vector2.DistanceSquared(Character.WorldPosition, other.WorldPosition) > minDistance; @@ -1460,11 +1434,11 @@ namespace Barotrauma } if (canAttack) { - canAttack = !IsBlocked(attackSimPos) && !IsBlocked(AttackLimb.SimPosition + forward * ConvertUnits.ToSimUnits(AttackLimb.attack.Range)); + canAttack = !IsBlocked(attackSimPos) && !IsBlocked(AttackingLimb.SimPosition + forward * ConvertUnits.ToSimUnits(AttackingLimb.attack.Range)); bool IsBlocked(Vector2 targetPosition) { - foreach (var body in Submarine.PickBodies(AttackLimb.SimPosition, targetPosition, myBodies, Physics.CollisionCharacter)) + foreach (var body in Submarine.PickBodies(AttackingLimb.SimPosition, targetPosition, myBodies, Physics.CollisionCharacter)) { Character hitTarget = null; if (body.UserData is Character c) @@ -1486,8 +1460,22 @@ namespace Barotrauma } } } + else if (!IsAttackRunning && !IsCoolDownRunning) + { + // If not, reset the attacking limb, if the cooldown is not running + // Don't use the property, because we don't want cancel reversing, if we are reversing. + if (attackLimbResetTimer > attackLimbResetInterval) + { + _attackingLimb = null; + attackLimbResetTimer = 0; + } + else + { + attackLimbResetTimer += deltaTime; + } + } } - Limb steeringLimb = canAttack && !AttackLimb.attack.Ranged ? AttackLimb : null; + Limb steeringLimb = canAttack && !AttackingLimb.attack.Ranged ? AttackingLimb : null; if (steeringLimb == null) { // If the attacking limb is a hand or claw, for example, using it as the steering limb can end in the result where the character circles around the target. @@ -1502,9 +1490,9 @@ namespace Barotrauma var pathSteering = SteeringManager as IndoorsSteeringManager; - if (AttackLimb != null && AttackLimb.attack.Retreat) + if (AttackingLimb != null && AttackingLimb.attack.Retreat) { - UpdateFallBack(attackWorldPos, deltaTime, followThrough: false); + UpdateFallBack(attackWorldPos, deltaTime, false); } else { @@ -1539,7 +1527,7 @@ namespace Barotrauma } // When pursuing, we don't want to pursue too close float max = 300; - float margin = AttackLimb != null ? Math.Min(AttackLimb.attack.Range * 0.9f, max) : max; + float margin = AttackingLimb != null ? Math.Min(AttackingLimb.attack.Range * 0.9f, max) : max; if (!canAttack || distance > margin) { // Steer towards the target if in the same room and swimming @@ -1570,10 +1558,10 @@ namespace Barotrauma } else { - if (AttackLimb.attack.Ranged) + if (AttackingLimb.attack.Ranged) { float dir = Character.AnimController.Dir; - if (dir > 0 && attackWorldPos.X > AttackLimb.WorldPosition.X + margin || dir < 0 && attackWorldPos.X < AttackLimb.WorldPosition.X - margin) + if (dir > 0 && attackWorldPos.X > AttackingLimb.WorldPosition.X + margin || dir < 0 && attackWorldPos.X < AttackingLimb.WorldPosition.X - margin) { SteeringManager.Reset(); } @@ -1670,9 +1658,9 @@ namespace Barotrauma } break; case CirclePhase.CloseIn: - if (AttackLimb != null && distance > 0 && distance < AttackLimb.attack.Range * GetStrikeDistanceMultiplier(targetSub.Velocity)) + if (AttackingLimb != null && distance > 0 && distance < AttackingLimb.attack.Range * GetStrikeDistanceMultiplier(targetSub.Velocity)) { - strikeTimer = AttackLimb.attack.CoolDown; + strikeTimer = AttackingLimb.attack.CoolDown; CirclePhase = CirclePhase.Strike; } else if (!breakCircling && sqrDistToSub <= MathUtils.Pow2(subSize + selectedTargetingParams.CircleStartDistance / 2) && targetSub.Velocity.LengthSquared() <= MathUtils.Pow2(GetTargetMaxSpeed())) @@ -1715,10 +1703,10 @@ namespace Barotrauma // When the offset position is outside of the sub it happens that the creature sometimes reaches the target point, // which makes it continue circling around the point (as supposed) // But when there is some offset and the offset is too near, this is not what we want. - if (AttackLimb != null && sqrDistToSub < MathUtils.Pow2(subSize + circleFallbackDistance)) + if (AttackingLimb != null && sqrDistToSub < MathUtils.Pow2(subSize + circleFallbackDistance)) { CirclePhase = CirclePhase.Strike; - strikeTimer = AttackLimb.attack.CoolDown; + strikeTimer = AttackingLimb.attack.CoolDown; } else { @@ -1753,9 +1741,9 @@ namespace Barotrauma } } } - if (AttackLimb != null && distance > 0 && distance < AttackLimb.attack.Range * requiredDistMultiplier && IsFacing(margin: MathHelper.Lerp(0.5f, 0.9f, currentAttackIntensity))) + if (AttackingLimb != null && distance > 0 && distance < AttackingLimb.attack.Range * requiredDistMultiplier && IsFacing(margin: MathHelper.Lerp(0.5f, 0.9f, currentAttackIntensity))) { - strikeTimer = AttackLimb.attack.CoolDown; + strikeTimer = AttackingLimb.attack.CoolDown; CirclePhase = CirclePhase.Strike; } canAttack = false; @@ -1812,7 +1800,7 @@ namespace Barotrauma } } - if (!canAttack || distance > Math.Min(AttackLimb.attack.Range * 0.9f, 100)) + if (!canAttack || distance > Math.Min(AttackingLimb.attack.Range * 0.9f, 100)) { if (pathSteering != null) { @@ -1823,7 +1811,7 @@ namespace Barotrauma SteeringManager.SteeringSeek(steerPos, 10); } } - else if (AttackLimb.attack.Ranged) + else if (AttackingLimb.attack.Ranged) { // Too close UpdateFallBack(attackWorldPos, deltaTime, followThrough: false); @@ -1836,18 +1824,18 @@ namespace Barotrauma } if (canAttack) { - if (!UpdateLimbAttack(deltaTime, AttackLimb, attackSimPos, distance, attackTargetLimb)) + if (!UpdateLimbAttack(deltaTime, AttackingLimb, attackSimPos, distance, attackTargetLimb)) { IgnoreTarget(SelectedAiTarget); } } else if (IsAttackRunning) { - AttackLimb.attack.ResetAttackTimer(); + AttackingLimb.attack.ResetAttackTimer(); } } - private bool IsValidAttack(Limb attackingLimb, IEnumerable currentContexts, Entity target) + private bool IsValidAttack(Limb attackingLimb, IEnumerable currentContexts, IDamageable target) { if (attackingLimb == null) { return false; } if (target == null) { return false; } @@ -1866,11 +1854,10 @@ namespace Barotrauma // Check that is approximately facing the target Vector2 attackLimbPos = Character.AnimController.SimplePhysicsEnabled ? Character.WorldPosition : attackingLimb.WorldPosition; Vector2 toTarget = attackWorldPos - attackLimbPos; - if (attack.MinRange > 0 && toTarget.LengthSquared() < MathUtils.Pow2(attack.MinRange)) { return false; } float offset = attackingLimb.Params.GetSpriteOrientation() - MathHelper.PiOver2; Vector2 forward = VectorExtensions.Forward(attackingLimb.body.TransformedRotation - offset * Character.AnimController.Dir); - float angle = MathHelper.ToDegrees(VectorExtensions.Angle(forward, toTarget)); - if (angle > attack.RequiredAngle) { return false; } + float angle = VectorExtensions.Angle(forward, toTarget); + if (angle > MathHelper.ToRadians(attack.RequiredAngle)) { return false; } } return true; } @@ -1880,7 +1867,7 @@ namespace Barotrauma private Limb GetAttackLimb(Vector2 attackWorldPos, Limb ignoredLimb = null) { var currentContexts = Character.GetAttackContexts(); - Entity target = wallTarget != null ? wallTarget.Structure : SelectedAiTarget?.Entity; + IDamageable target = wallTarget != null ? wallTarget.Structure : SelectedAiTarget?.Entity as IDamageable; if (target == null) { return null; } Limb selectedLimb = null; float currentPriority = -1; @@ -1914,13 +1901,12 @@ namespace Barotrauma float CalculatePriority(Limb limb, Vector2 attackPos) { - float prio = 1 + limb.attack.Priority; - if (Character.AnimController.SimplePhysicsEnabled) { return prio; } + if (Character.AnimController.SimplePhysicsEnabled) { return 1 + limb.attack.Priority; } float dist = Vector2.Distance(limb.WorldPosition, attackPos); // The limb is ignored if the target is not close. Prevents character going in reverse if very far away from it. // We also need a max value that is more than the actual range. float distanceFactor = MathHelper.Lerp(1, 0, MathUtils.InverseLerp(0, limb.attack.Range * 3, dist)); - return prio * distanceFactor; + return (1 + limb.attack.Priority) * distanceFactor; } } @@ -1933,7 +1919,7 @@ namespace Barotrauma Character.AnimController.ReleaseStuckLimbs(); LatchOntoAI?.DeattachFromBody(reset: true, cooldown: 1); if (attacker == null || attacker.AiTarget == null || attacker.Removed || attacker.IsDead) { return; } - if (attackResult.Damage >= AIParams.DamageThreshold) + if (Character.Params.CanInteract && attackResult.Damage > 10) { ReleaseDragTargets(); } @@ -2021,11 +2007,9 @@ namespace Barotrauma if (State == AIState.Attack && (IsAttackRunning || IsCoolDownRunning)) { + // Don't retaliate or escape while performing an attack/under cooldown retaliate = false; - if (IsAttackRunning) - { - avoidGunFire = false; - } + avoidGunFire = false; } if (retaliate) { @@ -2038,7 +2022,7 @@ namespace Barotrauma } } } - else if (avoidGunFire && attackResult.Damage >= AIParams.DamageThreshold) + else if (avoidGunFire) { State = AIState.Escape; avoidTimer = AIParams.AvoidTime * Rand.Range(0.75f, 1.25f); @@ -2130,7 +2114,7 @@ namespace Barotrauma { if (attackingLimb.attack.CoolDownTimer > 0) { - SetAimTimer(Math.Min(attackingLimb.attack.CoolDown, 1.5f)); + SetAimTimer(); // Managed to hit a living/non-destroyed target. Increase the priority more if the target is low in health -> dies easily/soon float greed = AIParams.AggressionGreed; if (!(damageTarget is Character)) @@ -2261,19 +2245,19 @@ namespace Barotrauma // TODO: test adding some random variance here? attackVector = attackWorldPos - WorldPosition; } - Vector2 dir = Vector2.Normalize(followThrough ? attackVector.Value : -attackVector.Value); - if (!MathUtils.IsValid(dir)) + Vector2 attackDir = Vector2.Normalize(followThrough ? attackVector.Value : -attackVector.Value); + if (!MathUtils.IsValid(attackDir)) { - dir = Vector2.UnitY; + attackDir = Vector2.UnitY; } - steeringManager.SteeringManual(deltaTime, dir); - if (Character.AnimController.InWater && !Reverse) + steeringManager.SteeringManual(deltaTime, attackDir); + if (Character.AnimController.InWater) { SteeringManager.SteeringAvoid(deltaTime, lookAheadDistance: avoidLookAheadDistance, weight: 15); } if (checkBlocking) { - return !IsBlocked(deltaTime, SimPosition + dir * (avoidLookAheadDistance / 2)); + return !IsBlocked(deltaTime, SimPosition + attackDir * (avoidLookAheadDistance / 2)); } return true; } @@ -3006,7 +2990,7 @@ namespace Barotrauma if (HasValidPath(requireNonDirty: true)) { return; } wallHits.Clear(); Structure wall = null; - Vector2 rayStart = AttackLimb != null ? AttackLimb.SimPosition : SimPosition; + Vector2 rayStart = AttackingLimb != null ? AttackingLimb.SimPosition : SimPosition; if (AIParams.WallTargetingMethod.HasFlag(WallTargetingMethod.Target)) { Vector2 rayEnd = SelectedAiTarget.SimPosition; @@ -3319,7 +3303,6 @@ namespace Barotrauma foreach (var triggerObject in activeTriggers) { AITrigger trigger = triggerObject.Key; - if (trigger.IsPermanent) { continue; } trigger.UpdateTimer(deltaTime); if (!trigger.IsActive) { @@ -3488,7 +3471,7 @@ namespace Barotrauma disableTailCoroutine = null; } Character.AnimController.ReleaseStuckLimbs(); - AttackLimb = null; + AttackingLimb = null; movementMargin = 0; ResetEscape(); if (isStateChanged && to == AIState.Idle && from != to) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/LatchOntoAI.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/LatchOntoAI.cs index 5dc813a8c..a98cef44d 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/LatchOntoAI.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/AI/LatchOntoAI.cs @@ -148,14 +148,14 @@ namespace Barotrauma } if (TargetCharacter != null) { - if (enemyAI.AttackLimb?.attack == null) + if (enemyAI.AttackingLimb?.attack == null) { DeattachFromBody(reset: true, cooldown: 1); } else { - float range = enemyAI.AttackLimb.attack.DamageRange * 2f; - if (Vector2.DistanceSquared(TargetCharacter.WorldPosition, enemyAI.AttackLimb.WorldPosition) > range * range) + float range = enemyAI.AttackingLimb.attack.DamageRange * 2f; + if (Vector2.DistanceSquared(TargetCharacter.WorldPosition, enemyAI.AttackingLimb.WorldPosition) > range * range) { DeattachFromBody(reset: true, cooldown: 1); } @@ -265,11 +265,11 @@ namespace Barotrauma if (enemyAI.IsSteeringThroughGap) { break; } if (_attachPos == Vector2.Zero) { break; } if (!AttachToSub && !AttachToCharacters) { break; } - if (enemyAI.AttackLimb == null) { break; } + if (enemyAI.AttackingLimb == null) { break; } if (targetBody == null) { break; } if (IsAttached && AttachJoints[0].BodyB == targetBody) { break; } Vector2 referencePos = TargetCharacter != null ? TargetCharacter.WorldPosition : ConvertUnits.ToDisplayUnits(transformedAttachPos); - if (Vector2.DistanceSquared(referencePos, enemyAI.AttackLimb.WorldPosition) < enemyAI.AttackLimb.attack.DamageRange * enemyAI.AttackLimb.attack.DamageRange) + if (Vector2.DistanceSquared(referencePos, enemyAI.AttackingLimb.WorldPosition) < enemyAI.AttackingLimb.attack.DamageRange * enemyAI.AttackingLimb.attack.DamageRange) { AttachToBody(transformedAttachPos); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/AnimController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/AnimController.cs index e282061e2..65597452e 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/AnimController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/AnimController.cs @@ -99,7 +99,8 @@ namespace Barotrauma { if (InWater || !CanWalk) { - return TargetMovement.LengthSquared() > SwimSlowParams.MovementSpeed; + float avg = (SwimSlowParams.MovementSpeed + SwimFastParams.MovementSpeed) / 2.0f; + return TargetMovement.LengthSquared() > avg * avg; } else { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/FishAnimController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/FishAnimController.cs index f898ac8d4..699f94e37 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/FishAnimController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/FishAnimController.cs @@ -448,18 +448,21 @@ namespace Barotrauma movement = TargetMovement; bool isMoving = movement.LengthSquared() > 0.00001f; var mainLimb = MainLimb; - float t = 0.5f; - if (isMoving && !SimplePhysicsEnabled && CurrentSwimParams.RotateTowardsMovement) + if (isMoving) { - Vector2 forward = VectorExtensions.Forward(Collider.Rotation + MathHelper.PiOver2); - float dot = Vector2.Dot(forward, Vector2.Normalize(movement)); - if (dot < 0) + float t = 0.5f; + if (!SimplePhysicsEnabled && CurrentSwimParams.RotateTowardsMovement) { - // Reduce the linear movement speed when not facing the movement direction - t = MathHelper.Clamp((1 + dot) / 10, 0.01f, 0.1f); + Vector2 forward = VectorExtensions.Forward(Collider.Rotation + MathHelper.PiOver2); + float dot = Vector2.Dot(forward, Vector2.Normalize(movement)); + if (dot < 0) + { + // Reduce the linear movement speed when not facing the movement direction + t = MathHelper.Clamp((1 + dot) / 10, 0.01f, 0.1f); + } } + Collider.LinearVelocity = Vector2.Lerp(Collider.LinearVelocity, movement, t); } - Collider.LinearVelocity = Vector2.Lerp(Collider.LinearVelocity, movement, t); //limbs are disabled when simple physics is enabled, no need to move them if (SimplePhysicsEnabled) { return; } mainLimb.PullJointEnabled = true; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/HumanoidAnimController.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/HumanoidAnimController.cs index 30fc791e6..b386fdd83 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/HumanoidAnimController.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/HumanoidAnimController.cs @@ -443,6 +443,8 @@ namespace Barotrauma if (CurrentGroundedParams == null) { return; } Vector2 handPos; + //if you're allergic to magic numbers, stop reading now + Limb leftFoot = GetLimb(LimbType.LeftFoot); Limb rightFoot = GetLimb(LimbType.RightFoot); Limb head = GetLimb(LimbType.Head); @@ -597,20 +599,16 @@ namespace Barotrauma { float torsoAngle = TorsoAngle.Value; float herpesStrength = character.CharacterHealth.GetAfflictionStrength("spaceherpes"); - if (Crouching && !movingHorizontally && !aiming) { torsoAngle -= HumanCrouchParams.ExtraTorsoAngleWhenStationary; } + if (Crouching && !movingHorizontally) { torsoAngle -= HumanCrouchParams.ExtraTorsoAngleWhenStationary; } torsoAngle -= herpesStrength / 150.0f; torso.body.SmoothRotate(torsoAngle * Dir, CurrentGroundedParams.TorsoTorque); } - if (!aiming && CurrentGroundedParams.FixedHeadAngle && HeadAngle.HasValue) + if (HeadAngle.HasValue) { float headAngle = HeadAngle.Value; if (Crouching && !movingHorizontally) { headAngle -= HumanCrouchParams.ExtraHeadAngleWhenStationary; } head.body.SmoothRotate(headAngle * Dir, CurrentGroundedParams.HeadTorque); } - else - { - RotateHead(head); - } if (!onGround) { @@ -885,17 +883,23 @@ namespace Barotrauma } } float targetSpeed = TargetMovement.Length(); - if (aiming) + if (targetSpeed > 0.1f) { - Vector2 mousePos = ConvertUnits.ToSimUnits(character.CursorPosition); - Vector2 diff = (mousePos - torso.SimPosition) * Dir; - float newRotation = MathUtils.VectorToAngle(diff); - Collider.SmoothRotate(newRotation, CurrentSwimParams.SteerTorque * character.SpeedMultiplier); + if (!aiming) + { + float newRotation = MathUtils.VectorToAngle(TargetMovement) - MathHelper.PiOver2; + Collider.SmoothRotate(newRotation, CurrentSwimParams.SteerTorque * character.SpeedMultiplier); + } } - else if (targetSpeed > 0.1f) + else { - float newRotation = MathUtils.VectorToAngle(TargetMovement) - MathHelper.PiOver2; - Collider.SmoothRotate(newRotation, CurrentSwimParams.SteerTorque * character.SpeedMultiplier); + if (aiming) + { + Vector2 mousePos = ConvertUnits.ToSimUnits(character.CursorPosition); + Vector2 diff = (mousePos - torso.SimPosition) * Dir; + float newRotation = MathUtils.VectorToAngle(diff); + Collider.SmoothRotate(newRotation, CurrentSwimParams.SteerTorque * character.SpeedMultiplier); + } } torso.body.MoveToPos(Collider.SimPosition + new Vector2((float)Math.Sin(-Collider.Rotation), (float)Math.Cos(-Collider.Rotation)) * 0.4f, 5.0f); @@ -910,14 +914,13 @@ namespace Barotrauma { torso.body.SmoothRotate(Collider.Rotation, CurrentSwimParams.TorsoTorque); } - - if (!aiming && CurrentSwimParams.FixedHeadAngle && HeadAngle.HasValue) + if (HeadAngle.HasValue) { head.body.SmoothRotate(Collider.Rotation + HeadAngle.Value * Dir, CurrentSwimParams.HeadTorque); } else { - RotateHead(head); + head.body.SmoothRotate(Collider.Rotation, CurrentSwimParams.HeadTorque); } //dont try to move upwards if head is already out of water @@ -948,18 +951,7 @@ namespace Barotrauma if (isNotRemote) { - float t = movementLerp; - if (targetSpeed > 0.00001f && !SimplePhysicsEnabled) - { - Vector2 forward = VectorExtensions.Forward(Collider.Rotation + MathHelper.PiOver2); - float dot = Vector2.Dot(forward, Vector2.Normalize(movement)); - if (dot < 0) - { - // Reduce the linear movement speed when not facing the movement direction - t = MathHelper.Clamp((1 + dot) / 10, 0.01f, 0.1f); - } - } - Collider.LinearVelocity = Vector2.Lerp(Collider.LinearVelocity, movement, t); + Collider.LinearVelocity = Vector2.Lerp(Collider.LinearVelocity, movement, movementLerp); } WalkPos += movement.Length(); @@ -1235,11 +1227,7 @@ namespace Barotrauma //apply forces to the collider to move the Character up/down Collider.ApplyForce((climbForce * 20.0f + subSpeed * 50.0f) * Collider.Mass); - if (aiming) - { - RotateHead(head); - } - else + if (!aiming) { float movementMultiplier = targetMovement.Y < 0 ? 0 : 1; head.body.SmoothRotate(MathHelper.PiOver4 * movementMultiplier * Dir, WalkParams.HeadTorque); @@ -1722,24 +1710,6 @@ namespace Barotrauma } } - private void RotateHead(Limb head) - { - Vector2 mousePos = ConvertUnits.ToSimUnits(character.CursorPosition); - Vector2 dir = (mousePos - head.SimPosition) * Dir; - float rot = MathUtils.VectorToAngle(dir); - var neckJoint = GetJointBetweenLimbs(LimbType.Head, LimbType.Torso); - if (neckJoint != null) - { - float offset = MathUtils.WrapAnglePi(GetLimb(LimbType.Torso).body.Rotation); - float lowerLimit = neckJoint.LowerLimit + offset; - float upperLimit = neckJoint.UpperLimit + offset; - float min = Math.Min(lowerLimit, upperLimit); - float max = Math.Max(lowerLimit, upperLimit); - rot = Math.Clamp(rot, min, max); - } - head.body.SmoothRotate(rot, CurrentAnimationParams.HeadTorque); - } - private void FootIK(Limb foot, Vector2 pos, float legTorque, float footTorque, float footAngle) { if (!MathUtils.IsValid(pos)) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs index 9277a79ee..874e6e000 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs @@ -805,7 +805,7 @@ namespace Barotrauma SeverLimbJointProjSpecific(limbJoint, playSound: true); if (GameMain.NetworkMember is { IsServer: true }) { - GameMain.NetworkMember.CreateEntityEvent(character, new Character.CharacterStatusEventData()); + GameMain.NetworkMember.CreateEntityEvent(character, new Character.StatusEventData()); } return true; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Attack.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Attack.cs index 53b7ee230..ff3af7ccf 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Attack.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Attack.cs @@ -37,9 +37,7 @@ namespace Barotrauma Pursue, FollowThrough, FollowThroughUntilCanAttack, - IdleUntilCanAttack, - Reverse, - ReverseUntilCanAttack + IdleUntilCanAttack } struct AttackResult @@ -104,7 +102,7 @@ namespace Barotrauma public bool Retreat { get; private set; } private float _range; - [Serialize(0.0f, IsPropertySaveable.Yes, description: "The min distance from the attack limb to the target before the AI tries to attack."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10000.0f)] + [Serialize(0.0f, IsPropertySaveable.Yes, description: "The min distance from the attack limb to the target before the AI tries to attack."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 2000.0f)] public float Range { get => _range * RangeMultiplier; @@ -112,16 +110,13 @@ namespace Barotrauma } private float _damageRange; - [Serialize(0.0f, IsPropertySaveable.Yes, description: "The min distance from the attack limb to the target to do damage. In distance-based hit detection, the hit will be registered as soon as the target is within the damage range, unless the attack duration has expired."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10000.0f)] + [Serialize(0.0f, IsPropertySaveable.Yes, description: "The min distance from the attack limb to the target to do damage. In distance-based hit detection, the hit will be registered as soon as the target is within the damage range, unless the attack duration has expired."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 2000.0f)] public float DamageRange { get => _damageRange * RangeMultiplier; set => _damageRange = value; } - [Serialize(0.0f, IsPropertySaveable.Yes, description: ""), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10000.0f)] - public float MinRange { get; private set; } - [Serialize(0.25f, IsPropertySaveable.Yes, description: "An approximation of the attack duration. Effectively defines the time window in which the hit can be registered. If set to too low value, it's possible that the attack won't hit the target in time."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f, DecimalCount = 2)] public float Duration { get; private set; } @@ -691,7 +686,7 @@ namespace Barotrauma public bool IsValidTarget(AttackTarget targetType) => TargetType == AttackTarget.Any || TargetType == targetType; - public bool IsValidTarget(Entity target) + public bool IsValidTarget(IDamageable target) { return TargetType switch { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs index 4978d0f49..3f6245bc7 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs @@ -1885,7 +1885,7 @@ namespace Barotrauma if (!attack.IsValidContext(currentContexts)) { return false; } if (attackTarget != null) { - if (!attack.IsValidTarget(attackTarget as Entity)) { return false; } + if (!attack.IsValidTarget(attackTarget)) { return false; } if (attackTarget is ISerializableEntity se && attackTarget is Character) { if (attack.Conditionals.Any(c => !c.TargetSelf && !c.Matches(se))) { return false; } @@ -3148,8 +3148,7 @@ namespace Barotrauma var itemContainer = item?.GetComponent(); if (itemContainer == null) { return; } - List inventoryItems = new List(Inventory.AllItemsMod); - foreach (Item inventoryItem in inventoryItems) + foreach (Item inventoryItem in Inventory.AllItemsMod) { if (!itemContainer.Inventory.TryPutItem(inventoryItem, user: null, createNetworkEvent: createNetworkEvents)) { @@ -3157,25 +3156,17 @@ namespace Barotrauma inventoryItem.Drop(dropper: this, createNetworkEvent: createNetworkEvents); } } - //this needs to happen after the items have been dropped (we can no longer sync dropping the items if the character has been removed) - Spawner.AddEntityToRemoveQueue(this); } } - else - { - Spawner.AddEntityToRemoveQueue(this); - } + + Spawner.AddEntityToRemoveQueue(this); } public void DespawnNow(bool createNetworkEvents = true) { despawnTimer = GameSettings.CurrentConfig.CorpseDespawnDelay; UpdateDespawn(1.0f, ignoreThresholds: true, createNetworkEvents: createNetworkEvents); - //update twice: first to spawn the duffel bag and move the items into it, then to remove the character - for (int i = 0; i < 2; i++) - { - Spawner.Update(createNetworkEvents); - } + Spawner.Update(createNetworkEvents); } public static void RemoveByPrefab(CharacterPrefab prefab) @@ -4021,7 +4012,7 @@ namespace Barotrauma if (GameMain.NetworkMember is { IsServer: true }) { - GameMain.NetworkMember.CreateEntityEvent(this, new CharacterStatusEventData()); + GameMain.NetworkMember.CreateEntityEvent(this, new StatusEventData()); } isDead = true; @@ -4177,11 +4168,6 @@ namespace Barotrauma } DebugConsole.Log("Removing character " + Name + " (ID: " + ID + ")"); -#if CLIENT - //ensure we apply any pending inventory updates to drop any items that need to be dropped when the character despawns - Inventory?.ApplyReceivedState(); -#endif - base.Remove(); foreach (Item heldItem in HeldItems.ToList()) @@ -4193,12 +4179,12 @@ namespace Barotrauma #if CLIENT GameMain.GameSession?.CrewManager?.KillCharacter(this, resetCrewListIndex: false); - - if (Controlled == this) { Controlled = null; } #endif CharacterList.Remove(this); + if (Controlled == this) { Controlled = null; } + if (Inventory != null) { foreach (Item item in Inventory.AllItems) @@ -4280,7 +4266,7 @@ namespace Barotrauma if (!MathUtils.NearlyEqual(newItem.Condition, newItem.MaxCondition) && GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer) { - newItem.CreateStatusEvent(); + GameMain.NetworkMember.CreateEntityEvent(newItem, new StatusEventData()); } #if SERVER newItem.GetComponent()?.SyncHistory(); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterEventData.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterEventData.cs index 731461475..11eab9eba 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterEventData.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterEventData.cs @@ -51,7 +51,7 @@ namespace Barotrauma } } - public struct CharacterStatusEventData : IEventData + public struct StatusEventData : IEventData { public EventType EventType => EventType.Status; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs index df1cede68..f2bc10d8b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/CharacterInfo.cs @@ -852,19 +852,6 @@ namespace Barotrauma #if CLIENT public void RecreateHead(MultiplayerPreferences characterSettings) { - if (characterSettings.HairIndex == -1 && - characterSettings.BeardIndex == -1 && - characterSettings.MoustacheIndex == -1 && - characterSettings.FaceAttachmentIndex == -1) - { - //randomize if nothing is set - SetAttachments(Rand.RandSync.Unsynced); - characterSettings.HairIndex = Head.HairIndex; - characterSettings.BeardIndex = Head.BeardIndex; - characterSettings.MoustacheIndex = Head.MoustacheIndex; - characterSettings.FaceAttachmentIndex = Head.FaceAttachmentIndex; - } - RecreateHead( characterSettings.TagSet.ToImmutableHashSet(), characterSettings.HairIndex, @@ -872,14 +859,9 @@ namespace Barotrauma characterSettings.MoustacheIndex, characterSettings.FaceAttachmentIndex); - Head.SkinColor = ChooseColor(SkinColors, characterSettings.SkinColor); - Head.HairColor = ChooseColor(HairColors, characterSettings.HairColor); - Head.FacialHairColor = ChooseColor(FacialHairColors, characterSettings.FacialHairColor); - - Color ChooseColor(in ImmutableArray<(Color Color, float Commonness)> availableColors, Color chosenColor) - { - return availableColors.Any(c => c.Color == chosenColor) ? chosenColor : SelectRandomColor(availableColors, Rand.RandSync.Unsynced); - } + Head.SkinColor = characterSettings.SkinColor; + Head.HairColor = characterSettings.HairColor; + Head.FacialHairColor = characterSettings.FacialHairColor; } #endif diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs index a83def334..320d295d0 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Health/CharacterHealth.cs @@ -52,19 +52,17 @@ namespace Barotrauma DebugConsole.ThrowError("Error in character health config (" + characterHealth.Character.Name + ") - define vitality multipliers using affliction identifiers or types instead of names."); continue; } - var vitalityMultipliers = subElement.GetAttributeIdentifierArray("identifier", null) ?? subElement.GetAttributeIdentifierArray("identifiers", null); - if (vitalityMultipliers == null) + + Identifier afflictionIdentifier = subElement.GetAttributeIdentifier("identifier", ""); + Identifier afflictionType = subElement.GetAttributeIdentifier("type", ""); + float multiplier = subElement.GetAttributeFloat("multiplier", 1.0f); + if (!afflictionIdentifier.IsEmpty) { - vitalityMultipliers = subElement.GetAttributeIdentifierArray("type", null) ?? subElement.GetAttributeIdentifierArray("types", null); - } - if (vitalityMultipliers != null) - { - float multiplier = subElement.GetAttributeFloat("multiplier", 1.0f); - vitalityMultipliers.ForEach(i => VitalityMultipliers.Add(i, multiplier)); + VitalityMultipliers.Add(afflictionIdentifier, multiplier); } else { - DebugConsole.ThrowError($"Error in character health config {characterHealth.Character.Name}: affliction identifier(s) or type(s) not defined in the \"VitalityMultiplier\" elements!"); + VitalityTypeMultipliers.Add(afflictionType, multiplier); } break; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Limb.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Limb.cs index c430090d1..b08cafe51 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Limb.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Limb.cs @@ -540,8 +540,6 @@ namespace Barotrauma private set; } - public Items.Components.Rope AttachedRope { get; set; } - public string Name => Params.Name; // These properties are exposed for status effects diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/Animation/HumanoidAnimations.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/Animation/HumanoidAnimations.cs index a1920a820..2fdb19b98 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/Animation/HumanoidAnimations.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/Animation/HumanoidAnimations.cs @@ -103,9 +103,6 @@ namespace Barotrauma [Serialize(1f, IsPropertySaveable.Yes, description: "How much force is used to move the hands."), Editable(MinValueFloat = 0, MaxValueFloat = 10, DecimalCount = 2)] public float HandMoveStrength { get; set; } - - [Serialize(true, IsPropertySaveable.Yes, description: "Is the head angle fixed or does the angle follow the mouse position?"), Editable] - public bool FixedHeadAngle { get; set; } } abstract class HumanGroundedParams : GroundedMovementParams, IHumanAnimation @@ -134,7 +131,7 @@ namespace Barotrauma get => MathHelper.ToDegrees(FootAngleInRadians); set { - FootAngleInRadians = MathHelper.ToRadians(value); + FootAngleInRadians = MathHelper.ToRadians(value); } } public float FootAngleInRadians { get; private set; } @@ -159,9 +156,6 @@ namespace Barotrauma [Serialize(1f, IsPropertySaveable.Yes, description: "How much force is used to move the hands."), Editable(MinValueFloat = 0, MaxValueFloat = 10, DecimalCount = 2)] public float HandMoveStrength { get; set; } - - [Serialize(true, IsPropertySaveable.Yes, description: "Is the head angle fixed or does the angle follow the mouse position?"), Editable] - public bool FixedHeadAngle { get; set; } } public interface IHumanAnimation @@ -172,7 +166,5 @@ namespace Barotrauma float ArmMoveStrength { get; set; } float HandMoveStrength { get; set; } - - bool FixedHeadAngle { get; set; } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs index 08cc0f106..640bf791c 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Params/CharacterParams.cs @@ -104,9 +104,6 @@ namespace Barotrauma [Serialize(10f, IsPropertySaveable.Yes, "How frequent the recurring idle and attack sounds are?"), Editable(MinValueFloat = 1f, MaxValueFloat = 100f)] public float SoundInterval { get; set; } - [Serialize(false, IsPropertySaveable.Yes), Editable] - public bool DrawLast { get; set; } - public readonly CharacterFile File; public XDocument VariantFile { get; private set; } @@ -577,9 +574,6 @@ namespace Barotrauma [Serialize(false, IsPropertySaveable.Yes, description: "The character will flee for a brief moment when being shot at if not performing an attack."), Editable] public bool AvoidGunfire { get; private set; } - [Serialize(0f, IsPropertySaveable.Yes, description: "How much damage is required for single attack to trigger avoiding/releasing targets."), Editable(minValue: 0f, maxValue: 1000f)] - public float DamageThreshold { get; private set; } - [Serialize(3f, IsPropertySaveable.Yes, description: "How long the creature avoids gunfire. Also used when the creature is unlatched."), Editable(minValue: 0f, maxValue: 100f)] public float AvoidTime { get; private set; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentFile/ContentFile.cs b/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentFile/ContentFile.cs index 35865bb05..73e07dcf1 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentFile/ContentFile.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentFile/ContentFile.cs @@ -30,7 +30,6 @@ namespace Barotrauma public readonly bool NotSyncedInMultiplayer; public readonly ImmutableHashSet? AlternativeTypes; public readonly ImmutableHashSet Names; - private readonly MethodInfo? contentPathMutator; public TypeInfo(Type type) { @@ -41,11 +40,9 @@ namespace Barotrauma var notSyncedInMultiplayerAttribute = type.GetCustomAttribute(); NotSyncedInMultiplayer = notSyncedInMultiplayerAttribute != null; AlternativeTypes = reqByCoreAttribute?.AlternativeTypes; - contentPathMutator - = Type.GetMethod(nameof(MutateContentPath), BindingFlags.Static | BindingFlags.Public); HashSet names = new HashSet { type.Name.RemoveFromEnd("File").ToIdentifier() }; - if (type.GetCustomAttribute(inherit: false)?.Names is { } altNames) + if (type.GetCustomAttribute()?.Names is { } altNames) { names.UnionWith(altNames); } @@ -53,10 +50,6 @@ namespace Barotrauma Names = names.ToImmutableHashSet(); } - public ContentPath MutateContentPath(ContentPath path) - => (ContentPath?)contentPathMutator?.Invoke(null, new object[] { path }) - ?? path; - public ContentFile? CreateInstance(ContentPackage contentPackage, ContentPath path) => (ContentFile?)Activator.CreateInstance(Type, contentPackage, path); } @@ -87,7 +80,6 @@ namespace Barotrauma } try { - filePath = type.MutateContentPath(filePath); if (!File.Exists(filePath.FullPath)) { return fail($"Failed to load file \"{filePath}\" of type \"{elemName}\": file not found."); diff --git a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentFile/ServerExecutableFile.cs b/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentFile/ServerExecutableFile.cs deleted file mode 100644 index 85f6a6fa1..000000000 --- a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentFile/ServerExecutableFile.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using Barotrauma.IO; - -namespace Barotrauma -{ - sealed class ServerExecutableFile : OtherFile - { - //This content type doesn't do very much on its own, it's handled manually by the Host Server menu - public ServerExecutableFile(ContentPackage contentPackage, ContentPath path) : base(contentPackage, path) { } - - public static ContentPath MutateContentPath(ContentPath path) - { - if (File.Exists(path.FullPath)) { return path; } - - string rawValueWithoutExtension() - => Barotrauma.IO.Path.Combine( - Barotrauma.IO.Path.GetDirectoryName(path.RawValue ?? ""), - Barotrauma.IO.Path.GetFileNameWithoutExtension(path.RawValue ?? "")).CleanUpPath(); - - path = ContentPath.FromRaw(path.ContentPackage, rawValueWithoutExtension()); - if (File.Exists(path.FullPath)) { return path; } - - path = ContentPath.FromRaw(path.ContentPackage, - rawValueWithoutExtension() + ".exe"); - return path; - } - } -} diff --git a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPackage/ContentPackage.cs b/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPackage/ContentPackage.cs index 586da6857..dae572835 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPackage/ContentPackage.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPackage/ContentPackage.cs @@ -110,7 +110,7 @@ namespace Barotrauma !expectedHash.IsNullOrWhiteSpace() && !expectedHash.Equals(Hash.StringRepresentation, StringComparison.OrdinalIgnoreCase); - public IEnumerable GetFiles() where T : ContentFile => Files.OfType(); + public IEnumerable GetFiles() where T : ContentFile => Files.Where(f => f is T).Cast(); public IEnumerable GetFiles(Type type) => !type.IsSubclassOf(typeof(ContentFile)) diff --git a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPackage/CorePackage.cs b/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPackage/CorePackage.cs index 02a6f4401..33daaec39 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPackage/CorePackage.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPackage/CorePackage.cs @@ -8,7 +8,7 @@ using System.Xml.Linq; namespace Barotrauma { - [AttributeUsage(AttributeTargets.Class, Inherited = false)] + [AttributeUsage(AttributeTargets.Class)] public class RequiredByCorePackage : Attribute { public readonly ImmutableHashSet AlternativeTypes; @@ -18,7 +18,7 @@ namespace Barotrauma } } - [AttributeUsage(AttributeTargets.Class, Inherited = false)] + [AttributeUsage(AttributeTargets.Class)] public class AlternativeContentTypeNames : Attribute { public readonly ImmutableHashSet Names; diff --git a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPackageManager.cs b/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPackageManager.cs index a437d78cc..bf2faed95 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPackageManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/ContentManagement/ContentPackageManager.cs @@ -327,8 +327,7 @@ namespace Barotrauma => LocalPackages.Regular.CollectionConcat(WorkshopPackages.Regular); public static IEnumerable AllPackages - => VanillaCorePackage.ToEnumerable().CollectionConcat(LocalPackages).CollectionConcat(WorkshopPackages) - .OfType(); + => LocalPackages.CollectionConcat(WorkshopPackages); public static void UpdateContentPackageList() { diff --git a/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs b/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs index 5274ff2e9..8562d6800 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/DebugConsole.cs @@ -168,34 +168,25 @@ namespace Barotrauma }; })); - void printMapEntityPrefabs(IEnumerable prefabs) where T : MapEntityPrefab - { - NewMessage("***************", Color.Cyan); - foreach (T prefab in prefabs) - { - if (prefab.Name.IsNullOrEmpty()) { continue; } - string text = $"- {prefab.Name}"; - if (prefab.Tags.Any()) - { - text += $" ({string.Join(", ", prefab.Tags)})"; - } - if (prefab.AllowedLinks?.Any() ?? false) - { - text += $", Links: {string.Join(", ", prefab.AllowedLinks)}"; - } - NewMessage(text, prefab.ContentPackage == ContentPackageManager.VanillaCorePackage ? Color.Cyan : Color.Purple); - } - NewMessage("***************", Color.Cyan); - } commands.Add(new Command("items|itemlist", "itemlist: List all the item prefabs available for spawning.", (string[] args) => { - printMapEntityPrefabs(ItemPrefab.Prefabs); - })); - - commands.Add(new Command("itemassemblies", "itemassemblies: List all the item assemblies available for spawning.", (string[] args) => - { - printMapEntityPrefabs(ItemAssemblyPrefab.Prefabs); + NewMessage("***************", Color.Cyan); + foreach (ItemPrefab itemPrefab in ItemPrefab.Prefabs) + { + if (itemPrefab.Name.IsNullOrEmpty()) { continue; } + string text = $"- {itemPrefab.Name}"; + if (itemPrefab.Tags.Any()) + { + text += $" ({string.Join(", ", itemPrefab.Tags)})"; + } + if (itemPrefab.AllowedLinks.Any()) + { + text += $", Links: {string.Join(", ", itemPrefab.AllowedLinks)}"; + } + NewMessage(text, Color.Cyan); + } + NewMessage("***************", Color.Cyan); })); @@ -211,7 +202,6 @@ namespace Barotrauma string[] creatureAndJobNames = CharacterPrefab.Prefabs.Select(p => p.Identifier.Value) .Concat(JobPrefab.Prefabs.Select(p => p.Identifier.Value)) - .OrderBy(s => s) .ToArray(); return new string[][] @@ -742,16 +732,9 @@ namespace Barotrauma { #if CLIENT if (Screen.Selected == GameMain.SubEditorScreen) { return; } - - if (GameMain.Client == null) - { - Character.Controlled = null; - GameMain.GameScreen.Cam.TargetPos = Vector2.Zero; - } - else - { - GameMain.Client?.SendConsoleCommand("freecam"); - } + Character.Controlled = null; + GameMain.GameScreen.Cam.TargetPos = Vector2.Zero; + GameMain.Client?.SendConsoleCommand("freecam"); #endif }, isCheat: true)); @@ -2399,7 +2382,7 @@ namespace Barotrauma public static void ThrowError(LocalizedString error, Exception e = null, bool createMessageBox = false, bool appendStackTrace = false) { - ThrowError(error.Value, e, createMessageBox, appendStackTrace); + ThrowError(error.Value); } public static void ThrowError(string error, Exception e = null, bool createMessageBox = false, bool appendStackTrace = false) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/BeaconMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/BeaconMission.cs index d7d042774..6b09ce371 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/BeaconMission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/BeaconMission.cs @@ -153,13 +153,6 @@ namespace Barotrauma swarmSpawned = true; } -#if DEBUG || UNSTABLE - if (State == 1 && !level.CheckBeaconActive()) - { - DebugConsole.ThrowError("Beacon became inactive!"); - State = 2; - } -#endif } public override void End() diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/CargoMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/CargoMission.cs index 8a02928df..934b9df66 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/CargoMission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/CargoMission.cs @@ -248,7 +248,7 @@ namespace Barotrauma { if (Submarine.MainSub != null && Submarine.MainSub.AtEndExit) { - int deliveredItemCount = items.Count(it => IsItemDelivered(it)); + int deliveredItemCount = items.Count(i => i.CurrentHull != null && !i.Removed && i.Condition > 0.0f); if (deliveredItemCount / (float)items.Count >= requiredDeliveryAmount) { GiveReward(); @@ -267,12 +267,5 @@ namespace Barotrauma items.Clear(); failed = !completed; } - - private bool IsItemDelivered(Item item) - { - if (item.Removed || item.Condition <= 0.0f || Submarine.MainSub == null) { return false; } - var submarine = item.Submarine ?? item.GetRootContainer()?.Submarine; - return submarine == Submarine.MainSub || Submarine.MainSub.GetConnectedSubs().Contains(submarine); - } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/Mission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/Mission.cs index 413e835e1..a525764bd 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/Mission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/Mission.cs @@ -419,17 +419,17 @@ namespace Barotrauma public static int DistributeRewardsToCrew(IEnumerable crew, int totalReward) { int remainingRewards = totalReward; - float sum = GetRewardDistibutionSum(crew); - if (MathUtils.NearlyEqual(sum, 0)) { return remainingRewards; } - foreach (Character character in crew) + HashSet nonBotCrew = crew.Where(c => !c.IsBot).ToHashSet(); + float sum = nonBotCrew.Sum(c => c.Wallet.RewardDistribution); + if (sum == 0) { return remainingRewards; } + foreach (Character character in nonBotCrew) { - int rewardDistribution = character.Wallet.RewardDistribution; - float rewardWeight = sum > 100 ? rewardDistribution / sum : rewardDistribution / 100f; - int reward = (int)(totalReward * rewardWeight); - reward = Math.Min(remainingRewards, reward); + float rewardWeight = character.Wallet.RewardDistribution / sum; + int reward = (int)Math.Floor(totalReward * rewardWeight); + reward = Math.Max(remainingRewards, reward); character.Wallet.Give(reward); remainingRewards -= reward; - if (remainingRewards <= 0) { break; } + if (0 >= remainingRewards) { break; } } return remainingRewards; @@ -442,27 +442,26 @@ namespace Barotrauma IEnumerable characters = crewManager.GetCharacters(); #if SERVER - return GameMain.Server.ConnectedClients.Select(c => c.Character).Where(c => c?.Info != null && !c.IsDead).Concat(characters); + return GameMain.Server.ConnectedClients.Select(c => c.Character).Where(IsAlive).Concat(characters); #elif CLIENT return characters; #endif + static bool IsAlive(Character c) { return c?.Info != null && !c.IsDead; } } - public static int GetRewardDistibutionSum(IEnumerable crew, int rewardDistribution = 0) => crew.Sum(c => c.Wallet.RewardDistribution) + rewardDistribution; - - public static (int Amount, int Percentage, float Sum) GetRewardShare(int rewardDistribution, IEnumerable crew, Option reward) + public static (int Amount, int Percentage) GetRewardShare(int rewardDistribution, IEnumerable crew, Option reward) { - float sum = GetRewardDistibutionSum(crew, rewardDistribution); - if (MathUtils.NearlyEqual(sum, 0)) { return (0, 0, sum); } + float sum = crew.Sum(c => c.Wallet.RewardDistribution) + rewardDistribution; + if (sum == 0) { return (0, 0); } - float rewardWeight = sum > 100 ? rewardDistribution / sum : rewardDistribution / 100f; + float rewardWeight = rewardDistribution / sum; int rewardPercentage = (int)(rewardWeight * 100); return reward switch { - Some { Value: var amount } => ((int)(amount * rewardWeight), rewardPercentage, sum), - None _ => (0, rewardPercentage, sum), + Some { Value: var amount } => ((int)(amount * rewardWeight), rewardPercentage), + None _ => (0, rewardPercentage), _ => throw new ArgumentOutOfRangeException() }; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MonsterMission.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MonsterMission.cs index c51ad855c..ec2aea487 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MonsterMission.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MonsterMission.cs @@ -228,7 +228,7 @@ namespace Barotrauma } GiveReward(); completed = true; - if (level?.LevelData != null && Prefab.Tags.Any(t => t.Equals("huntinggrounds", StringComparison.OrdinalIgnoreCase))) + if (level?.LevelData != null && Prefab.Tags.Any(t => t.Equals("huntinggrounds", StringComparison.OrdinalIgnoreCase) || t.Equals("huntinggroundsnoreward", StringComparison.OrdinalIgnoreCase))) { level.LevelData.HasHuntingGrounds = false; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/CargoManager.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/CargoManager.cs index fcd724d2d..585de85c8 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/CargoManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/CargoManager.cs @@ -30,16 +30,22 @@ namespace Barotrauma } #if CLIENT - public PurchasedItem(ItemPrefab itemPrefab, int quantity) - : this(itemPrefab, quantity, buyer: null) { } -#endif - public PurchasedItem(ItemPrefab itemPrefab, int quantity, Client buyer) + public PurchasedItem(ItemPrefab itemPrefab, int quantity, Client buyer = null) { ItemPrefab = itemPrefab; Quantity = quantity; IsStoreComponentEnabled = null; BuyerCharacterInfoId = buyer?.Character?.Info?.ID ?? Character.Controlled?.Info?.ID ?? 0; } +#elif SERVER + public PurchasedItem(ItemPrefab itemPrefab, int quantity, Client buyer) + { + ItemPrefab = itemPrefab; + Quantity = quantity; + IsStoreComponentEnabled = null; + BuyerCharacterInfoId = buyer?.Character?.Info?.ID ?? 0; + } +#endif } diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Wallet.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Wallet.cs index abd84ef03..d32c25575 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Wallet.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Wallet.cs @@ -25,18 +25,12 @@ namespace Barotrauma public int Balance; } - /// - /// Network message for the server to update wallet values to clients - /// internal struct NetWalletUpdate : INetSerializableStruct { [NetworkSerialize(ArrayMaxSize = NetConfig.MaxPlayers + 1)] public NetWalletTransaction[] Transactions; } - /// - /// Network message for the client to transfer money between wallets - /// [NetworkSerialize] internal struct NetWalletTransfer : INetSerializableStruct { @@ -45,10 +39,7 @@ namespace Barotrauma public int Amount; } - /// - /// Network message for the client to set the salary of someone - /// - internal struct NetWalletSetSalaryUpdate : INetSerializableStruct + internal struct NetWalletSalaryUpdate : INetSerializableStruct { [NetworkSerialize] public ushort Target; @@ -57,10 +48,6 @@ namespace Barotrauma public int NewRewardDistribution; } - /// - /// Represents the difference in balance and salary when a wallet gets updated - /// Not really used right now but could be used for notifications when receiving funds similar to how talents do it - /// [NetworkSerialize] internal struct WalletChangedData : INetSerializableStruct { @@ -95,9 +82,6 @@ namespace Barotrauma } } - /// - /// Represents an update that changed the amount of money or salary of the wallet - /// [NetworkSerialize] internal struct NetWalletTransaction : INetSerializableStruct { diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs index 8f1f97323..dbde33069 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/CampaignMode.cs @@ -321,32 +321,15 @@ namespace Barotrauma } if (levelData.HasHuntingGrounds) { - var huntingGroundsMissionPrefabs = MissionPrefab.Prefabs.Where(m => m.Tags.Any(t => t.Equals("huntinggrounds", StringComparison.OrdinalIgnoreCase))); + var huntingGroundsMissionPrefabs = MissionPrefab.Prefabs.Where(m => m.Tags.Any(t => t.Equals("huntinggroundsnoreward", StringComparison.OrdinalIgnoreCase))); if (!huntingGroundsMissionPrefabs.Any()) { - DebugConsole.AddWarning("Could not find a hunting grounds mission for the level. No mission with the tag \"huntinggrounds\" found."); + DebugConsole.AddWarning("Could not find a hunting grounds mission for the level. No mission with the tag \"huntinggroundsnoreward\" found."); } else { Random rand = new MTRandom(ToolBox.StringToInt(levelData.Seed)); - // Adjust the prefab commonness based on the difficulty tag - var prefabs = huntingGroundsMissionPrefabs.ToList(); - var weights = prefabs.Select(p => (float)Math.Max(p.Commonness, 1)).ToList(); - for (int i = 0; i < prefabs.Count; i++) - { - var prefab = prefabs[i]; - var weight = weights[i]; - if (prefab.Tags.Contains("easy")) - { - weight *= MathHelper.Lerp(0.2f, 2f, MathUtils.InverseLerp(80, LevelData.HuntingGroundsDifficultyThreshold, levelData.Difficulty)); - } - else if (prefab.Tags.Contains("hard")) - { - weight *= MathHelper.Lerp(0.5f, 1.5f, MathUtils.InverseLerp(LevelData.HuntingGroundsDifficultyThreshold + 10, 80, levelData.Difficulty)); - } - weights[i] = weight; - } - var huntingGroundsMissionPrefab = ToolBox.SelectWeightedRandom(prefabs, weights, rand); + var huntingGroundsMissionPrefab = ToolBox.SelectWeightedRandom(huntingGroundsMissionPrefabs, p => (float)Math.Max(p.Commonness, 0.1f), rand); if (!Missions.Any(m => m.Prefab.Tags.Any(t => t.Equals("huntinggrounds", StringComparison.OrdinalIgnoreCase)))) { extraMissions.Add(huntingGroundsMissionPrefab.Instantiate(Map.SelectedConnection.Locations, Submarine.MainSub)); diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs index e6fc1f3e8..0da770a21 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameSession.cs @@ -754,9 +754,9 @@ namespace Barotrauma try { - ImmutableArray crewCharacters = GetSessionCrewCharacters().ToImmutableArray(); + IEnumerable crewCharacters = GetSessionCrewCharacters(); - int prevMoney = GetAmountOfMoney(crewCharacters); + int prevMoney = (GameMode as CampaignMode)?.Bank.Balance ?? 0; // FIXME personal wallets - reward distribution foreach (Mission mission in missions) { @@ -828,7 +828,7 @@ namespace Barotrauma LogEndRoundStats(eventId); if (GameMode is CampaignMode campaignMode) { - GameAnalyticsManager.AddDesignEvent(eventId + "MoneyEarned", GetAmountOfMoney(crewCharacters) - prevMoney); + GameAnalyticsManager.AddDesignEvent(eventId + "MoneyEarned", campaignMode.Bank.Balance - prevMoney); // FIXME personal wallets - reward distrubiton campaignMode.TotalPlayTime += roundDuration; } #if CLIENT @@ -840,17 +840,6 @@ namespace Barotrauma { RoundEnding = false; } - - int GetAmountOfMoney(IEnumerable crew) - { - if (!(GameMode is CampaignMode campaign)) { return 0; } - - return GameMain.NetworkMember switch - { - null => campaign.Bank.Balance, - _ => crew.Sum(c => c.Wallet.Balance) + campaign.Bank.Balance - }; - } } public void LogEndRoundStats(string eventId) diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/UpgradeManager.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/UpgradeManager.cs index f85b6bafe..6a8df4f5e 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/UpgradeManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/UpgradeManager.cs @@ -216,7 +216,7 @@ namespace Barotrauma price = 0; } - if (Campaign.GetWallet(client).TryDeduct(price)) + if (Campaign.GetWallet(client).TryDeduct(price)) // FIXME personal wallets { if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/DockingPort.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/DockingPort.cs index f8249369e..e34ef8f1b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/DockingPort.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/DockingPort.cs @@ -74,7 +74,7 @@ namespace Barotrauma.Items.Components set; } - [Editable, Serialize(true, IsPropertySaveable.No, description: "Should the OnUse StatusEffects trigger when docking (on vanilla docking ports these effects emit particles and play a sound).)")] + [Serialize(true, IsPropertySaveable.No, description: "Should the OnUse StatusEffects trigger when docking (on vanilla docking ports these effects emit particles and play a sound).)")] public bool ApplyEffectsOnDocking { get; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemContainer.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemContainer.cs index 891fc3fce..40bd8a5b0 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemContainer.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ItemContainer.cs @@ -424,15 +424,6 @@ namespace Barotrauma.Items.Components } } - public override void UpdateBroken(float deltaTime, Camera cam) - { - //update when the item is broken too to get OnContaining effects to execute and contained item positions to update - if (IsActive) - { - Update(deltaTime, cam); - } - } - public override bool HasRequiredItems(Character character, bool addMessage, LocalizedString msg = null) { return AllowAccess && (!AccessOnlyWhenBroken || Item.Condition <= 0) && base.HasRequiredItems(character, addMessage, msg); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Pump.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Pump.cs index 0ee0d9d50..b375eb205 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Pump.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Pump.cs @@ -169,7 +169,7 @@ namespace Barotrauma.Items.Components hull.BallastFlora = new BallastFloraBehavior(hull, ballastFloraPrefab, offset, firstGrowth: true); #if SERVER - hull.BallastFlora.CreateNetworkMessage(new BallastFloraBehavior.SpawnEventData()); + hull.BallastFlora.SendNetworkMessage(new BallastFloraBehavior.SpawnEventData()); #endif } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Power/Powered.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Power/Powered.cs index 0a0d2af0d..be83e2267 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Power/Powered.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Power/Powered.cs @@ -1,4 +1,5 @@ using System; +using System.Xml.Linq; using Microsoft.Xna.Framework; using System.Collections.Generic; #if CLIENT @@ -150,6 +151,20 @@ namespace Barotrauma.Items.Components } set { + if (powerIn != null) + { + if (powerIn.Grid != null) + { + powerIn.Grid.Voltage = Math.Max(0.0f, value); + } + } + else if (powerOut != null) + { + if (powerOut.Grid != null) + { + powerOut.Grid.Voltage = Math.Max(0.0f, value); + } + } voltage = Math.Max(0.0f, value); } } @@ -198,6 +213,11 @@ namespace Barotrauma.Items.Components powerOnSoundPlayed = false; } #endif + if (powerIn == null) + { + //power down the device here if it has no power connection (= receives power from contained battery cells instead of the "normal" power logic) + Voltage -= deltaTime; + } } public override void Update(float deltaTime, Camera cam) @@ -450,11 +470,6 @@ namespace Barotrauma.Items.Components //Determine if devices are adding a load or providing power, also resolve solo nodes foreach (Powered powered in poweredList) { - //Make voltage decay to ensure the device powers down. - //This only effects devices with no power input (whose voltage is set by other means, e.g. status effects from a contained battery) - //or devices that have been disconnected from the power grid - other devices use the voltage of the grid instead. - powered.Voltage -= deltaTime; - //Handle the device if it's got a power connection if (powered.powerIn != null && powered.powerOut != powered.powerIn) { @@ -485,7 +500,7 @@ namespace Barotrauma.Items.Components } else { - powered.CurrPowerConsumption = -powered.GetConnectionPowerOut(powered.powerIn, 0, powered.MinMaxPowerOut(powered.powerIn, 0), 0); + powered.CurrPowerConsumption = powered.GetConnectionPowerOut(powered.powerIn, 0, powered.MinMaxPowerOut(powered.powerIn, 0), 0); powered.GridResolved(powered.powerIn); } } @@ -526,7 +541,7 @@ namespace Barotrauma.Items.Components else { //Perform power calculations for the singular connection - float loadOut = -powered.GetConnectionPowerOut(powered.powerOut, 0, powered.MinMaxPowerOut(powered.powerOut, 0), 0); + float loadOut = powered.GetConnectionPowerOut(powered.powerOut, 0, powered.MinMaxPowerOut(powered.powerOut, 0), 0); if (powered is PowerTransfer pt2) { pt2.PowerLoad = loadOut; @@ -652,7 +667,7 @@ namespace Barotrauma.Items.Components public static bool ValidPowerConnection(Connection conn1, Connection conn2) { - return conn1.IsPower && conn2.IsPower && (conn1.Item.HasTag("junctionbox") || conn2.Item.HasTag("junctionbox") || conn1.Item.HasTag("dock") || conn2.Item.HasTag("dock") || conn1.IsOutput != conn2.IsOutput); + return conn1.IsPower && conn2.IsPower && (conn1.Item.HasTag("junctionbox") || conn2.Item.HasTag("junctionbox") || conn1.IsOutput != conn2.IsOutput || (conn1.Item.HasTag("dock") && conn2.Item.HasTag("dock"))); } /// diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs index 37c5e5533..fcddb442b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs @@ -49,6 +49,8 @@ namespace Barotrauma.Items.Components //continuous collision detection is used while the projectile is moving faster than this const float ContinuousCollisionThreshold = 5.0f; + //a duration during which the projectile won't drop from the body it's stuck to + private const float PersistentStickJointDuration = 1.0f; private PrismaticJoint stickJoint; public Attack Attack { get; private set; } @@ -84,6 +86,8 @@ namespace Barotrauma.Items.Components get { return hits; } } + private float persistentStickJointTimer; + [Serialize(10.0f, IsPropertySaveable.No, description: "The impulse applied to the physics body of the item when it's launched. Higher values make the projectile faster.")] public float LaunchImpulse { get; set; } @@ -112,6 +116,13 @@ namespace Barotrauma.Items.Components set; } + [Serialize(false, IsPropertySaveable.No, description: "When set to true, the item won't fall of a target it's stuck to unless removed.")] + public bool StickPermanently + { + get; + set; + } + [Serialize(false, IsPropertySaveable.No, description: "Can the item stick to the character it hits.")] public bool StickToCharacters { @@ -140,13 +151,6 @@ namespace Barotrauma.Items.Components set; } - [Serialize(false, IsPropertySaveable.No, description: "")] - public bool StickToLightTargets - { - get; - set; - } - [Serialize(false, IsPropertySaveable.No, description: "Hitscan projectiles cast a ray forwards and immediately hit whatever the ray hits. "+ "It is recommended to use hitscans for very fast-moving projectiles such as bullets, because using extremely fast launch velocities may cause physics glitches.")] public bool Hitscan @@ -208,29 +212,16 @@ namespace Barotrauma.Items.Components set; } - private float stickTimer; - [Serialize(0f, IsPropertySaveable.No)] - public float StickDuration - { - get; - set; - } - - [Serialize(-1f, IsPropertySaveable.No)] - public float MaxJointTranslation - { - get; - set; - } - private float _maxJointTranslation = -1; - public Body StickTarget { get; private set; } - public bool IsStuckToTarget => StickTarget != null; + public bool IsStuckToTarget + { + get { return StickTarget != null; } + } private Category originalCollisionCategories; private Category originalCollisionTargets; @@ -669,22 +660,23 @@ namespace Barotrauma.Items.Components if (stickJoint == null) { return; } - if (StickDuration > 0 && stickTimer > 0) + if (persistentStickJointTimer > 0.0f && !StickPermanently) { - stickTimer -= deltaTime; + persistentStickJointTimer -= deltaTime; return; } - float absoluteMaxTranslation = 100; // Update the item's transform to make sure it's inside the same sub as the target (or outside) - if (StickTarget?.UserData is Limb target && target.Submarine != item.Submarine || Math.Abs(stickJoint.JointTranslation) > absoluteMaxTranslation) + if (StickTarget?.UserData is Limb target && target.Submarine != item.Submarine || Math.Abs(stickJoint.JointTranslation) > 100.0f) { item.UpdateTransform(); } if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer) { - if (StickTargetRemoved() || Math.Abs(stickJoint.JointTranslation) > _maxJointTranslation) + if (StickTargetRemoved() || + (!StickPermanently && (stickJoint.JointTranslation < stickJoint.LowerLimit * 0.9f || stickJoint.JointTranslation > stickJoint.UpperLimit * 0.9f)) || + Math.Abs(stickJoint.JointTranslation) > 100.0f) //failsafe unstick if the target is still extremely far { Unstick(); #if SERVER @@ -944,12 +936,14 @@ namespace Barotrauma.Items.Components { item.body.LinearVelocity *= deflectedSpeedMultiplier; } - else if ( stickJoint == null && StickTarget == null && - StickToStructures && target.Body.UserData is Structure || - ((StickToLightTargets || target.Body.Mass > item.body.Mass * 0.5f) && + else if ( // When hitting characters the collision normal seems to sometimes point into wrong direction, resulting in a failed attempt to stick + //Vector2.Dot(Vector2.Normalize(velocity), collisionNormal) < 0.0f && + hits.Count() >= MaxTargetsToHit && + target.Body.Mass > item.body.Mass * 0.5f && (DoesStick || (StickToCharacters && (target.Body.UserData is Limb || target.Body.UserData is Character)) || - (StickToItems && target.Body.UserData is Item)))) + (StickToStructures && target.Body.UserData is Structure) || + (StickToItems && target.Body.UserData is Item))) { Vector2 dir = new Vector2( (float)Math.Cos(item.body.Rotation), @@ -1032,8 +1026,6 @@ namespace Barotrauma.Items.Components { if (stickJoint != null) { return; } - item.body.ResetDynamics(); - stickJoint = new PrismaticJoint(targetBody, item.body.FarseerBody, item.body.SimPosition, axis, true) { MotorEnabled = true, @@ -1042,17 +1034,18 @@ namespace Barotrauma.Items.Components Breakpoint = 1000.0f }; - if (_maxJointTranslation == -1) + if (StickPermanently) { - if (item.Sprite != null && MaxJointTranslation < 0) - { - MaxJointTranslation = item.Sprite.size.X / 2 * item.Scale; - } - MaxJointTranslation = Math.Min(MaxJointTranslation, 1000); - _maxJointTranslation = ConvertUnits.ToSimUnits(MaxJointTranslation); + stickJoint.LowerLimit = stickJoint.UpperLimit = 0.0f; + item.body.ResetDynamics(); + } + else if (item.Sprite != null) + { + stickJoint.LowerLimit = ConvertUnits.ToSimUnits(item.Sprite.size.X * -0.3f * item.Scale); + stickJoint.UpperLimit = ConvertUnits.ToSimUnits(item.Sprite.size.X * 0.3f * item.Scale); } - stickTimer = StickDuration; + persistentStickJointTimer = PersistentStickJointDuration; StickTarget = targetBody; GameMain.World.Add(stickJoint); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Rope.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Rope.cs index d77939f02..7c5b320ba 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Rope.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Rope.cs @@ -1,9 +1,9 @@ -using Barotrauma.Extensions; -using Barotrauma.Networking; +using Barotrauma.Networking; using FarseerPhysics; using FarseerPhysics.Dynamics; using Microsoft.Xna.Framework; using System; +using System.Xml.Linq; namespace Barotrauma.Items.Components { @@ -12,36 +12,8 @@ namespace Barotrauma.Items.Components private ISpatialEntity source; private Item target; - private Vector2? launchDir; - - private void SetSource(ISpatialEntity source) - { - this.source = source; - if (source is Limb sourceLimb) - { - sourceLimb.AttachedRope = this; - float offset = sourceLimb.Params.GetSpriteOrientation() - MathHelper.PiOver2; - launchDir = VectorExtensions.Forward(sourceLimb.body.TransformedRotation - offset * sourceLimb.character.AnimController.Dir); - } - } - - private void ResetSource() - { - if (source is Limb sourceLimb && sourceLimb.AttachedRope == this) - { - sourceLimb.AttachedRope = null; - } - source = null; - } - private float snapTimer; - - [Serialize(1.0f, IsPropertySaveable.No, description: "")] - public float SnapAnimDuration - { - get; - set; - } + private const float SnapAnimDuration = 1.0f; private float raycastTimer; private const float RayCastInterval = 0.2f; @@ -74,13 +46,6 @@ namespace Barotrauma.Items.Components set; } - [Serialize(360.0f, IsPropertySaveable.No, description: "How far the source item can be from the projectile until the rope breaks.")] - public float MaxAngle - { - get; - set; - } - [Serialize(true, IsPropertySaveable.No, description: "Should the rope snap when it collides with a structure/submarine (if not, it will just go through it).")] public bool SnapOnCollision { @@ -150,8 +115,8 @@ namespace Barotrauma.Items.Components { System.Diagnostics.Debug.Assert(source != null); System.Diagnostics.Debug.Assert(target != null); + this.source = source; this.target = target; - SetSource(source); Snapped = false; ApplyStatusEffects(ActionType.OnUse, 1.0f, worldPosition: item.WorldPosition); IsActive = true; @@ -162,7 +127,7 @@ namespace Barotrauma.Items.Components if (source == null || target == null || target.Removed || (source is Entity sourceEntity && sourceEntity.Removed)) { - ResetSource(); + source = null; target = null; IsActive = false; return; @@ -179,27 +144,12 @@ namespace Barotrauma.Items.Components } Vector2 diff = target.WorldPosition - source.WorldPosition; - float lengthSqr = diff.LengthSquared(); - if (lengthSqr > MaxLength * MaxLength) + if (diff.LengthSquared() > MaxLength * MaxLength) { Snap(); return; } - if (MaxAngle < 180 && lengthSqr > 2500) - { - if (launchDir == null) - { - launchDir = diff; - } - float angle = MathHelper.ToDegrees(VectorExtensions.Angle(launchDir.Value, diff)); - if (angle > MaxAngle) - { - Snap(); - return; - } - } - #if CLIENT item.ResetCachedVisibleSize(); #endif diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs index 094d5a973..1e2638509 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Item.cs @@ -1677,17 +1677,12 @@ namespace Barotrauma if (!(GameMain.NetworkMember is { IsServer: true })) { return; } if (!conditionUpdatePending) { return; } - CreateStatusEvent(); + GameMain.NetworkMember.CreateEntityEvent(this, new StatusEventData()); lastSentCondition = condition; sendConditionUpdateTimer = NetConfig.ItemConditionUpdateInterval; conditionUpdatePending = false; } - public void CreateStatusEvent() - { - GameMain.NetworkMember.CreateEntityEvent(this, new ItemStatusEventData()); - } - private bool isActive = true; public override void Update(float deltaTime, Camera cam) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/ItemEventData.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/ItemEventData.cs index e0c65a747..a4a939944 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/ItemEventData.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/ItemEventData.cs @@ -63,7 +63,7 @@ namespace Barotrauma } } - private readonly struct ItemStatusEventData : IEventData + private readonly struct StatusEventData : IEventData { public EventType EventType => EventType.Status; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Creatures/BallastFloraBehavior.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Creatures/BallastFloraBehavior.cs index 2be6ddb93..9708fd2e4 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Creatures/BallastFloraBehavior.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Creatures/BallastFloraBehavior.cs @@ -520,9 +520,8 @@ namespace Barotrauma.MapCreatures.Behavior if (branch.Health > branch.MaxHealth * 0.9f || branch.DisconnectedFromRoot) { continue; } float branchHealAmount = (float)(MaxBranchHealthRegenDistance - branch.BranchDepth) / MaxBranchHealthRegenDistance * healAmount; if (branchHealAmount <= 0.0f) { continue; } - float prevHealth = branch.Health; branch.Health += branchHealAmount; - branch.AccumulatedDamage += (prevHealth - branch.Health); + branch.AccumulatedDamage -= branchHealAmount; } } StateMachine.Update(deltaTime); @@ -634,8 +633,7 @@ namespace Barotrauma.MapCreatures.Behavior { if (branch.ParentBranch != null && (branch.ParentBranch.DisconnectedFromRoot || branch.ParentBranch.Health <= 0.0f)) { - float speed = MathHelper.Lerp(5.0f, 0.1f, branch.ParentBranch.Health / branch.ParentBranch.MaxHealth); - DamageBranch(branch, speed * speed * deltaTime, AttackType.CutFromRoot); + DamageBranch(branch, deltaTime * MathHelper.Lerp(10.0f, 0.01f, branch.ParentBranch.Health / branch.ParentBranch.MaxHealth), AttackType.CutFromRoot); } if (branch.Health <= 0.0f) { @@ -838,7 +836,7 @@ namespace Barotrauma.MapCreatures.Behavior } #if SERVER - CreateNetworkMessage(new BranchCreateEventData(newBranch, parent)); + SendNetworkMessage(new BranchCreateEventData(newBranch, parent)); #endif return true; } @@ -880,7 +878,7 @@ namespace Barotrauma.MapCreatures.Behavior #if SERVER if (!load) { - CreateNetworkMessage(new InfectEventData(target, InfectEventData.InfectState.Yes, branch)); + SendNetworkMessage(new InfectEventData(target, InfectEventData.InfectState.Yes, branch)); } #endif } @@ -957,6 +955,8 @@ namespace Barotrauma.MapCreatures.Behavior /// private void CreateBody(BallastFloraBranch branch) { + if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; } + Rectangle rect = branch.Rect; Vector2 pos = Parent.Position + Offset + branch.Position; @@ -975,14 +975,6 @@ namespace Barotrauma.MapCreatures.Behavior public void DamageBranch(BallastFloraBranch branch, float amount, AttackType type, Character? attacker = null) { float damage = amount; - if (damage > 0) - { - damage = Math.Min(damage, branch.Health); - } - else - { - damage = Math.Max(damage, branch.Health - branch.MaxHealth); - } if (type != AttackType.Other && type != AttackType.CutFromRoot) { @@ -991,28 +983,8 @@ namespace Barotrauma.MapCreatures.Behavior if (branch.IsRootGrowth && root != null && root.Health > 0.0f) { return; } - if (type != AttackType.Other && type != AttackType.CutFromRoot) - { - branch.AccumulatedDamage += damage; - Anger += damage * 0.001f; - } - - if (GameMain.NetworkMember != null) - { - // damage is handled server side - if (GameMain.NetworkMember.IsClient) - { - return; - } - else - { - //accumulate damage on the server's side to ensure clients get notified - if (type == AttackType.Other || type == AttackType.CutFromRoot) - { - branch.AccumulatedDamage += damage; - } - } - } + // damage is handled server side currently + if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; } if (attacker != null && toxinsCooldown <= 0) { @@ -1042,6 +1014,11 @@ namespace Barotrauma.MapCreatures.Behavior } branch.Health -= damage; + if (type != AttackType.Other && type != AttackType.CutFromRoot) + { + branch.AccumulatedDamage += damage; + Anger += damage * 0.001f; + } #if SERVER GameMain.Server?.KarmaManager?.OnBallastFloraDamaged(attacker, damage); @@ -1133,7 +1110,7 @@ namespace Barotrauma.MapCreatures.Behavior #if SERVER if (!wasRemoved) { - CreateNetworkMessage(new BranchRemoveEventData(branch)); + SendNetworkMessage(new BranchRemoveEventData(branch)); } #endif } @@ -1164,7 +1141,7 @@ namespace Barotrauma.MapCreatures.Behavior } }); #if SERVER - CreateNetworkMessage(new InfectEventData(item, InfectEventData.InfectState.No, null)); + SendNetworkMessage(new InfectEventData(item, InfectEventData.InfectState.No, null)); #endif } @@ -1182,7 +1159,7 @@ namespace Barotrauma.MapCreatures.Behavior StateMachine?.State?.Exit(); #if SERVER - CreateNetworkMessage(new KillEventData()); + SendNetworkMessage(new KillEventData()); #endif } @@ -1204,7 +1181,7 @@ namespace Barotrauma.MapCreatures.Behavior _entityList.Remove(this); #if SERVER - CreateNetworkMessage(new KillEventData()); + SendNetworkMessage(new KillEventData()); #endif } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/ItemAssemblyPrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/ItemAssemblyPrefab.cs index 05539c6e2..13d72bc6a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/ItemAssemblyPrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/ItemAssemblyPrefab.cs @@ -160,19 +160,16 @@ namespace Barotrauma public void Delete() { Dispose(); - try + if (File.Exists(ContentFile.Path)) { - if (ContentPackage is { Files: { Length: 1 } } - && ContentPackageManager.LocalPackages.Contains(ContentPackage)) + try { - Directory.Delete(ContentPackage.Dir, recursive: true); - ContentPackageManager.LocalPackages.Refresh(); - ContentPackageManager.EnabledPackages.DisableRemovedMods(); + File.Delete(ContentFile.Path); + } + catch (Exception e) + { + DebugConsole.ThrowError("Deleting item assembly \"" + Name + "\" failed.", e); } - } - catch (Exception e) - { - DebugConsole.ThrowError("Deleting item assembly \"" + Name + "\" failed.", e); } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs index f184f08f4..42b982c38 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs @@ -3826,12 +3826,12 @@ namespace Barotrauma if (location != null) { DebugConsole.NewMessage($"Generating an outpost for the {(isStart ? "start" : "end")} of the level... (Location: {location.Name}, level type: {LevelData.Type})"); - outpost = OutpostGenerator.Generate(outpostGenerationParams, location, onlyEntrance: LevelData.Type != LevelData.LevelType.Outpost, LevelData.AllowInvalidOutpost); + outpost = OutpostGenerator.Generate(outpostGenerationParams, location, onlyEntrance: LevelData.Type != LevelData.LevelType.Outpost); } else { DebugConsole.NewMessage($"Generating an outpost for the {(isStart ? "start" : "end")} of the level... (Location type: {locationType}, level type: {LevelData.Type})"); - outpost = OutpostGenerator.Generate(outpostGenerationParams, locationType, onlyEntrance: LevelData.Type != LevelData.LevelType.Outpost, LevelData.AllowInvalidOutpost); + outpost = OutpostGenerator.Generate(outpostGenerationParams, locationType, onlyEntrance: LevelData.Type != LevelData.LevelType.Outpost); } foreach (string categoryToHide in locationType.HideEntitySubcategories) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelData.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelData.cs index cc0a5bd5d..4fd6d7166 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelData.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/LevelData.cs @@ -31,16 +31,8 @@ namespace Barotrauma public bool HasHuntingGrounds, OriginallyHadHuntingGrounds; - //minimum difficulty of the level before hunting grounds can appear - public const float HuntingGroundsDifficultyThreshold = 25; - - //probability of hunting grounds appearing in 100% difficulty levels - public const float MaxHuntingGroundsProbability = 0.3f; - public OutpostGenerationParams ForceOutpostGenerationParams; - public bool AllowInvalidOutpost; - public readonly Point Size; public readonly int InitialDepth; @@ -158,7 +150,11 @@ namespace Barotrauma } else { - HasHuntingGrounds = OriginallyHadHuntingGrounds = rand.NextDouble() < MathUtils.InverseLerp(HuntingGroundsDifficultyThreshold, 100.0f, Difficulty) * MaxHuntingGroundsProbability; + //minimum difficulty of the level before hunting grounds can appear + float huntingGroundsDifficultyThreshold = 25; + //probability of hunting grounds appearing in 100% difficulty levels + float maxHuntingGroundsProbability = 0.3f; + HasHuntingGrounds = OriginallyHadHuntingGrounds = rand.NextDouble() < MathUtils.InverseLerp(huntingGroundsDifficultyThreshold, 100.0f, Difficulty) * maxHuntingGroundsProbability; HasBeaconStation = !HasHuntingGrounds && rand.NextDouble() < locationConnection.Locations.Select(l => l.Type.BeaconStationChance).Max(); } IsBeaconActive = false; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Map.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Map.cs index 2a1bbd3bf..f7b648463 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Map.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Map/Map.cs @@ -182,7 +182,8 @@ namespace Barotrauma { for (int i = 0; i < Connections.Count; i++) { - Connections[i].LevelData.HasHuntingGrounds = Rand.Range(0.0f, 1.0f) < Connections[i].Difficulty / 100.0f * LevelData.MaxHuntingGroundsProbability; + float maxHuntingGroundsProbability = 0.3f; + Connections[i].LevelData.HasHuntingGrounds = Rand.Range(0.0f, 1.0f) < Connections[i].Difficulty / 100.0f * maxHuntingGroundsProbability; connectionElements[i].SetAttributeValue("hashuntinggrounds", true); } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs index 336462b62..8a92048f3 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs @@ -57,17 +57,17 @@ namespace Barotrauma } } - public static Submarine Generate(OutpostGenerationParams generationParams, LocationType locationType, bool onlyEntrance = false, bool allowInvalidOutpost = false) + public static Submarine Generate(OutpostGenerationParams generationParams, LocationType locationType, bool onlyEntrance = false) { - return Generate(generationParams, locationType, location: null, onlyEntrance, allowInvalidOutpost); + return Generate(generationParams, locationType, location: null, onlyEntrance); } - public static Submarine Generate(OutpostGenerationParams generationParams, Location location, bool onlyEntrance = false, bool allowInvalidOutpost = false) + public static Submarine Generate(OutpostGenerationParams generationParams, Location location, bool onlyEntrance = false) { - return Generate(generationParams, location.Type, location, onlyEntrance, allowInvalidOutpost); + return Generate(generationParams, location.Type, location, onlyEntrance); } - private static Submarine Generate(OutpostGenerationParams generationParams, LocationType locationType, Location location, bool onlyEntrance = false, bool allowInvalidOutpost = false) + private static Submarine Generate(OutpostGenerationParams generationParams, LocationType locationType, Location location, bool onlyEntrance = false) { var outpostModuleFiles = ContentPackageManager.EnabledPackages.All .SelectMany(p => p.GetFiles()) @@ -197,19 +197,12 @@ namespace Barotrauma AppendToModule(selectedModules.Last(), outpostModules.ToList(), pendingModuleFlags, selectedModules, locationType, allowExtendBelowInitialModule: generationParams is RuinGeneration.RuinGenerationParams); if (pendingModuleFlags.Any(flag => flag != "none")) { - if (!allowInvalidOutpost) + remainingTries--; + if (remainingTries <= 0) { - remainingTries--; - if (remainingTries <= 0) - { - DebugConsole.ThrowError("Could not generate an outpost with all of the required modules. Some modules may not have enough connections at the edges to generate a valid layout. Pending modules: " + string.Join(", ", pendingModuleFlags)); - } - continue; - } - else - { - DebugConsole.ThrowError("Could not generate an outpost with all of the required modules. Some modules may not have enough connections at the edges to generate a valid layout. Pending modules: " + string.Join(", ", pendingModuleFlags) + ". Won't retry because invalid outposts are allowed."); + DebugConsole.ThrowError("Could not generate an outpost with all of the required modules. Some modules may not have enough doors at the edges to generate a valid layout. Pending modules: " + string.Join(", ", pendingModuleFlags)); } + continue; } var outpostInfo = new SubmarineInfo() @@ -335,10 +328,7 @@ namespace Barotrauma selectedModule.Offset = (selectedModule.PreviousGap.WorldPosition + selectedModule.PreviousModule.Offset) - selectedModule.ThisGap.WorldPosition; - if (selectedModule.PreviousGap.ConnectedDoor != null || selectedModule.ThisGap.ConnectedDoor != null) - { - selectedModule.Offset += moveDir * generationParams.MinHallwayLength; - } + selectedModule.Offset += moveDir * generationParams.MinHallwayLength; } entities[selectedModule] = moduleEntities; } @@ -474,16 +464,6 @@ namespace Barotrauma pendingModuleFlags.Remove(initialModuleFlag); pendingModuleFlags.Insert(0, initialModuleFlag); - if (pendingModuleFlags.Count > totalModuleCount) - { - DebugConsole.ThrowError($"Error during outpost generation. {pendingModuleFlags.Count} modules set to be used the outpost, but total module count is only {totalModuleCount}. Leaving out some of the modules..."); - int removeCount = pendingModuleFlags.Count - totalModuleCount; - for (int i = 0; i < removeCount; i++) - { - pendingModuleFlags.Remove(pendingModuleFlags.Last()); - } - } - return pendingModuleFlags; } @@ -506,71 +486,46 @@ namespace Barotrauma if (pendingModuleFlags.Count == 0) { return true; } List placedModules = new List(); - for (int i = 0; i < 2; i++) + foreach (OutpostModuleInfo.GapPosition gapPosition in GapPositions.Randomize(Rand.RandSync.ServerAndClient)) { - //try placing a module meant for this location type first, and if that fails, try choosing whatever fits - bool allowDifferentLocationType = i > 0; - foreach (OutpostModuleInfo.GapPosition gapPosition in GapPositions.Randomize(Rand.RandSync.ServerAndClient)) + if (currentModule.UsedGapPositions.HasFlag(gapPosition)) { continue; } + if (!allowExtendBelowInitialModule) { - if (currentModule.UsedGapPositions.HasFlag(gapPosition)) { continue; } - if (!allowExtendBelowInitialModule) - { - //don't continue downwards if it'd extend below the airlock - if (gapPosition == OutpostModuleInfo.GapPosition.Bottom && currentModule.Offset.Y <= 1) { continue; } - } - - PlacedModule newModule = null; - //try appending to the current module if possible - if (currentModule.Info.OutpostModuleInfo.GapPositions.HasFlag(gapPosition)) - { - newModule = AppendModule(currentModule, GetOpposingGapPosition(gapPosition), availableModules, pendingModuleFlags, selectedModules, locationType, allowDifferentLocationType); - } - - if (newModule != null) - { - placedModules.Add(newModule); - } - else - { - //couldn't append to current module, try one of the other placed modules - foreach (PlacedModule otherModule in selectedModules) - { - if (otherModule == currentModule) { continue; } - foreach (OutpostModuleInfo.GapPosition otherGapPosition in - GapPositions.Where(g => !otherModule.UsedGapPositions.HasFlag(g) && otherModule.Info.OutpostModuleInfo.GapPositions.HasFlag(g))) - { - newModule = AppendModule(otherModule, GetOpposingGapPosition(otherGapPosition), availableModules, pendingModuleFlags, selectedModules, locationType, allowDifferentLocationType); - if (newModule != null) - { - placedModules.Add(newModule); - break; - } - } - if (newModule != null) { break; } - } - } - if (pendingModuleFlags.Count == 0) { return true; } + //don't continue downwards if it'd extend below the airlock + if (gapPosition == OutpostModuleInfo.GapPosition.Bottom && currentModule.Offset.Y <= 1) { continue; } + } + if (currentModule.Info.OutpostModuleInfo.GapPositions.HasFlag(gapPosition)) + { + var newModule = AppendModule(currentModule, GetOpposingGapPosition(gapPosition), availableModules, pendingModuleFlags, selectedModules, locationType); + if (newModule != null) { placedModules.Add(newModule); } + if (pendingModuleFlags.Count == 0) { return true; } } } - //couldn't place a module anywhere, we're probably fucked! - if (placedModules.Count == 0 && retry && currentModule.PreviousModule != null && !selectedModules.Any(m => m != currentModule && m.PreviousModule == currentModule)) + //couldn't place anything, retry + if (placedModules.Count == 0 && retry && !selectedModules.Any(m => m != currentModule && m.PreviousModule == currentModule.PreviousModule)) { + //try to append to some other module first + foreach (PlacedModule otherModule in selectedModules) + { + if (AppendToModule(otherModule, availableModules, pendingModuleFlags, selectedModules, locationType, retry: false, allowExtendBelowInitialModule: allowExtendBelowInitialModule)) + { + return true; + } + } //try to replace the previously placed module with something else that we can append to + var failedModule = currentModule; for (int i = 0; i < 10; i++) { selectedModules.Remove(currentModule); - assertAllPreviousModulesPresent(); //readd the module types that the previous module was supposed to fulfill to the pending module types pendingModuleFlags.AddRange(currentModule.FulfilledModuleTypes); if (!availableModules.Contains(currentModule.Info)) { availableModules.Add(currentModule.Info); } //retry - currentModule = AppendModule(currentModule.PreviousModule, currentModule.ThisGapPosition, availableModules, pendingModuleFlags, selectedModules, locationType, allowDifferentLocationType: true); - assertAllPreviousModulesPresent(); + currentModule = AppendModule(currentModule.PreviousModule, currentModule.ThisGapPosition, availableModules, pendingModuleFlags, selectedModules, locationType); if (currentModule == null) { break; } if (AppendToModule(currentModule, availableModules, pendingModuleFlags, selectedModules, locationType, retry: false, allowExtendBelowInitialModule: allowExtendBelowInitialModule)) { - assertAllPreviousModulesPresent(); return true; } } @@ -579,14 +534,9 @@ namespace Barotrauma foreach (PlacedModule placedModule in placedModules) { - AppendToModule(placedModule, availableModules, pendingModuleFlags, selectedModules, locationType, allowExtendBelowInitialModule: allowExtendBelowInitialModule); + AppendToModule(placedModule, availableModules, pendingModuleFlags, selectedModules, locationType); } return placedModules.Count > 0; - - void assertAllPreviousModulesPresent() - { - System.Diagnostics.Debug.Assert(selectedModules.All(m => m.PreviousModule == null || selectedModules.Contains(m.PreviousModule))); - } } /// @@ -603,8 +553,7 @@ namespace Barotrauma List availableModules, List pendingModuleFlags, List selectedModules, - LocationType locationType, - bool allowDifferentLocationType) + LocationType locationType) { if (pendingModuleFlags.Count == 0) { return null; } @@ -613,7 +562,7 @@ namespace Barotrauma foreach (Identifier moduleFlag in pendingModuleFlags) { flagToPlace = moduleFlag; - nextModule = GetRandomModule(currentModule?.Info?.OutpostModuleInfo, availableModules, flagToPlace, gapPosition, locationType, allowDifferentLocationType); + nextModule = GetRandomModule(currentModule?.Info?.OutpostModuleInfo, availableModules, flagToPlace, gapPosition, locationType); if (nextModule != null) { break; } } @@ -654,7 +603,6 @@ namespace Barotrauma foreach (PlacedModule otherModule in modules2) { if (module == otherModule) { continue; } - if (module.PreviousModule == otherModule && module.PreviousGap.ConnectedDoor == null && module.ThisGap.ConnectedDoor == null) { continue; } if (ModulesOverlap(module, otherModule)) { module1 = module; @@ -827,25 +775,22 @@ namespace Barotrauma } } - private static SubmarineInfo GetRandomModule(OutpostModuleInfo prevModule, IEnumerable modules, Identifier moduleFlag, OutpostModuleInfo.GapPosition gapPosition, LocationType locationType, bool allowDifferentLocationType) + private static SubmarineInfo GetRandomModule(OutpostModuleInfo prevModule, IEnumerable modules, Identifier moduleFlag, OutpostModuleInfo.GapPosition gapPosition, LocationType locationType) { IEnumerable availableModules = null; if (moduleFlag.IsEmpty || moduleFlag.Equals("none")) { availableModules = modules - .Where(m => !m.OutpostModuleInfo.ModuleFlags.Any() || (m.OutpostModuleInfo.ModuleFlags.Count() == 1 && m.OutpostModuleInfo.ModuleFlags.Contains("none".ToIdentifier()))); + .Where(m => !m.OutpostModuleInfo.ModuleFlags.Any() || (m.OutpostModuleInfo.ModuleFlags.Count() == 1 && m.OutpostModuleInfo.ModuleFlags.Contains("none".ToIdentifier())) && m.OutpostModuleInfo.GapPositions.HasFlag(gapPosition)); } else { availableModules = modules - .Where(m => m.OutpostModuleInfo.ModuleFlags.Contains(moduleFlag)); + .Where(m => m.OutpostModuleInfo.ModuleFlags.Contains(moduleFlag) && m.OutpostModuleInfo.GapPositions.HasFlag(gapPosition)); } - - availableModules = availableModules.Where(m => m.OutpostModuleInfo.GapPositions.HasFlag(gapPosition) && m.OutpostModuleInfo.CanAttachToPrevious.HasFlag(gapPosition)); - if (prevModule != null) { - availableModules = availableModules.Where(m => CanAttachTo(m.OutpostModuleInfo, prevModule));// && CanAttachTo(prevModule, m.OutpostModuleInfo)); + availableModules = availableModules.Where(m => CanAttachTo(m.OutpostModuleInfo, prevModule) && CanAttachTo(prevModule, m.OutpostModuleInfo)); } if (availableModules.Count() == 0) { return null; } @@ -855,22 +800,15 @@ namespace Barotrauma availableModules.Where(m => m.OutpostModuleInfo.AllowedLocationTypes.Contains(locationType.Identifier)); //if not found, search for modules suitable for any location type - if (allowDifferentLocationType && !modulesSuitableForLocationType.Any()) + if (!modulesSuitableForLocationType.Any()) { modulesSuitableForLocationType = availableModules.Where(m => !m.OutpostModuleInfo.AllowedLocationTypes.Any()); } if (!modulesSuitableForLocationType.Any()) { - if (allowDifferentLocationType) - { - DebugConsole.NewMessage($"Could not find a suitable module for the location type {locationType}. Module flag: {moduleFlag}.", Color.Orange); - return ToolBox.SelectWeightedRandom(availableModules.ToList(), availableModules.Select(m => m.OutpostModuleInfo.Commonness).ToList(), Rand.RandSync.ServerAndClient); - } - else - { - return null; - } + DebugConsole.NewMessage($"Could not find a suitable module for the location type {locationType}. Module flag: {moduleFlag}.", Color.Orange); + return ToolBox.SelectWeightedRandom(availableModules.ToList(), availableModules.Select(m => m.OutpostModuleInfo.Commonness).ToList(), Rand.RandSync.ServerAndClient); } else { @@ -1101,20 +1039,16 @@ namespace Barotrauma if (hallwayLength <= 1.0f) { continue; } - Identifier moduleFlag = (isHorizontal ? "hallwayhorizontal" : "hallwayvertical").ToIdentifier(); - var hallwayModules = availableModules.Where(m => m.OutpostModuleInfo.ModuleFlags.Contains(moduleFlag)); - - var suitableHallwayModules = hallwayModules.Where(m => - m.OutpostModuleInfo.AllowAttachToModules.Any(s => module.Info.OutpostModuleInfo.ModuleFlags.Contains(s)) && - m.OutpostModuleInfo.AllowAttachToModules.Any(s => module.PreviousModule.Info.OutpostModuleInfo.ModuleFlags.Contains(s))); - if (suitableHallwayModules.Count() == 0) + var suitableModules = availableModules.Where(m => + m.OutpostModuleInfo.AllowAttachToModules.Any(s => module.Info.OutpostModuleInfo.ModuleFlags.Contains(s)) && + m.OutpostModuleInfo.AllowAttachToModules.Any(s => module.PreviousModule.Info.OutpostModuleInfo.ModuleFlags.Contains(s))); + if (suitableModules.Count() == 0) { - suitableHallwayModules = hallwayModules.Where(m => + suitableModules = availableModules.Where(m => !m.OutpostModuleInfo.AllowAttachToModules.Any() || m.OutpostModuleInfo.AllowAttachToModules.All(s => s == "any")); } - - var hallwayInfo = GetRandomModule(suitableHallwayModules, moduleFlag, locationType); + var hallwayInfo = GetRandomModule(suitableModules, (isHorizontal ? "hallwayhorizontal" : "hallwayvertical").ToIdentifier(), locationType); if (hallwayInfo == null) { DebugConsole.ThrowError($"Generating hallways between outpost modules failed. No {(isHorizontal ? "horizontal" : "vertical")} hallway modules suitable for use between the modules \"{module.Info.DisplayName}\" and \"{module.PreviousModule.Info.DisplayName}\"."); @@ -1236,7 +1170,7 @@ namespace Barotrauma var startWaypoint = WayPoint.WayPointList.Find(wp => wp.ConnectedGap == module.ThisGap); if (startWaypoint == null) { - DebugConsole.ThrowError($"Failed to connect waypoints between outpost modules. No waypoint in the {module.ThisGapPosition.ToString().ToLower()} gap of the module \"{module.Info.Name}\"."); + DebugConsole.ThrowError($"Failed to connect waypoints between outpost modules. No waypoint in the {GetOpposingGapPosition(module.ThisGapPosition).ToString().ToLower()} gap of the module \"{module.Info.Name}\"."); continue; } var endWaypoint = WayPoint.WayPointList.Find(wp => wp.ConnectedGap == module.PreviousGap); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostModuleInfo.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostModuleInfo.cs index 794a9671b..c79a10a64 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostModuleInfo.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostModuleInfo.cs @@ -45,9 +45,6 @@ namespace Barotrauma [Serialize(GapPosition.None, IsPropertySaveable.Yes, description: "Which sides of the module have gaps on them (i.e. from which sides the module can be attached to other modules). Center = no gaps available.")] public GapPosition GapPositions { get; set; } - [Serialize(GapPosition.Right | GapPosition.Left | GapPosition.Bottom | GapPosition.Top, IsPropertySaveable.Yes, description: "Which sides of this module are allowed to attach to the previously placed module. E.g. if you want a module to always attach to the left side of the docking module, you could set this to Right.")] - public GapPosition CanAttachToPrevious { get; set; } - public string Name { get; private set; } public Dictionary SerializableProperties { get; private set; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/RoundEndCinematic.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/RoundEndCinematic.cs index 1fb8afbae..ae5e402d5 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/RoundEndCinematic.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/RoundEndCinematic.cs @@ -48,11 +48,11 @@ namespace Barotrauma { if (!subs.Any()) yield return CoroutineStatus.Success; -#if CLIENT Character.Controlled = null; + cam.TargetPos = Vector2.Zero; +#if CLIENT GameMain.LightManager.LosEnabled = false; #endif - cam.TargetPos = Vector2.Zero; Level.Loaded.TopBarrier.Enabled = false; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/StructurePrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/StructurePrefab.cs index acdee62e9..84bf74588 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/StructurePrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/StructurePrefab.cs @@ -322,7 +322,7 @@ namespace Barotrauma #endif Tags = tags.ToImmutableHashSet(); - AllowedLinks = ImmutableHashSet.Empty; + AllowedLinks = Enumerable.Empty().ToImmutableHashSet(); } protected override void CreateInstance(Rectangle rect) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Networking/NetworkMember.cs b/Barotrauma/BarotraumaShared/SharedSource/Networking/NetworkMember.cs index e405ecb4f..90f123c95 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Networking/NetworkMember.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Networking/NetworkMember.cs @@ -31,7 +31,7 @@ namespace Barotrauma.Networking ERROR, //tell the server that an error occurred CREW, //hiring UI MEDICAL, //medical clinic - TRANSFER_MONEY, // wallet transfers + MONEY, //wallet updates REWARD_DISTRIBUTION, // wallet reward distribution READY_CHECK, READY_TO_SPAWN diff --git a/Barotrauma/BarotraumaShared/SharedSource/Serialization/XMLExtensions.cs b/Barotrauma/BarotraumaShared/SharedSource/Serialization/XMLExtensions.cs index 89c8bc1bd..dacc2c8a7 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Serialization/XMLExtensions.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Serialization/XMLExtensions.cs @@ -172,11 +172,11 @@ namespace Barotrauma return !texName.IsNullOrEmpty() & !texName.Contains("/") && !texName.Contains("%ModDir", StringComparison.OrdinalIgnoreCase); } - public static ContentPath GetAttributeContentPath(this XElement element, string name, ContentPackage contentPackage) + public static ContentPath GetAttributeContentPath(this XElement element, string name, + ContentPackage contentPackage) { - var attribute = element?.GetAttribute(name); - if (attribute == null) { return null; } - return ContentPath.FromRaw(contentPackage, GetAttributeString(attribute, null)); + if (element?.GetAttribute(name) == null) { return null; } + return ContentPath.FromRaw(contentPackage, GetAttributeString(element.GetAttribute(name), null)); } public static Identifier GetAttributeIdentifier(this XElement element, string name, string defaultValue) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Settings/GameSettings.cs b/Barotrauma/BarotraumaShared/SharedSource/Settings/GameSettings.cs index 551b48fdc..b917b844a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Settings/GameSettings.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Settings/GameSettings.cs @@ -10,7 +10,6 @@ using System.Xml.Linq; using Barotrauma.IO; #if CLIENT using Barotrauma.ClientSource.Settings; -using Barotrauma.Networking; using Microsoft.Xna.Framework.Input; #endif @@ -454,12 +453,8 @@ namespace Barotrauma bool languageChanged = currentConfig.Language != newConfig.Language; - bool audioOutputChanged = currentConfig.Audio.AudioOutputDevice != newConfig.Audio.AudioOutputDevice; - bool voiceCaptureChanged = currentConfig.Audio.VoiceCaptureDevice != newConfig.Audio.VoiceCaptureDevice; - - bool textScaleChanged = Math.Abs(currentConfig.Graphics.TextScale - newConfig.Graphics.TextScale) > MathF.Pow(2.0f, -7); - currentConfig = newConfig; +#warning TODO: Implement program state updates; #if CLIENT if (setGraphicsMode) @@ -467,24 +462,6 @@ namespace Barotrauma GameMain.Instance.ApplyGraphicsSettings(); } - if (audioOutputChanged) - { - GameMain.SoundManager?.InitializeAlcDevice(currentConfig.Audio.AudioOutputDevice); - } - - if (voiceCaptureChanged) - { - VoipCapture.ChangeCaptureDevice(currentConfig.Audio.VoiceCaptureDevice); - } - - if (textScaleChanged) - { - foreach (var font in GUIStyle.Fonts.Values) - { - font.Prefabs.ForEach(p => p.LoadFont()); - } - } - GameMain.SoundManager?.ApplySettings(); #endif if (languageChanged) { TextManager.ClearCache(); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs b/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs index 2bdef6f7b..688ebbfbb 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/StatusEffects/StatusEffect.cs @@ -68,21 +68,15 @@ namespace Barotrauma public bool IsTriggered { get; private set; } - public float Timer { get; private set; } + public float Timer { get; private set; } = -1; public bool IsActive { get; private set; } - public bool IsPermanent { get; private set; } - public void Launch() { IsTriggered = true; IsActive = true; - IsPermanent = Duration <= 0; - if (!IsPermanent) - { - Timer = Duration; - } + Timer = Duration; } public void Reset() @@ -94,7 +88,6 @@ namespace Barotrauma public void UpdateTimer(float deltaTime) { - if (IsPermanent) { return; } Timer -= deltaTime; if (Timer < 0) { @@ -1250,27 +1243,24 @@ namespace Barotrauma { for (int i = 0; i < targets.Count; i++) { - var target = targets[i]; - Limb targetLimb = target as Limb; - if (targetLimb == null && target is Character character) + if (targets[i] is Character character) { foreach (Limb limb in character.AnimController.Limbs) { if (limb.body == sourceBody) { - targetLimb = limb; if (breakLimb) { character.TrySeverLimbJoints(limb, severLimbsProbability: 100, damage: 100, allowBeheading: true, attacker: user); } + else + { + limb.HideAndDisable(hideLimbTimer); + } break; } } } - if (hideLimb) - { - targetLimb?.HideAndDisable(hideLimbTimer); - } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Utils/SafeIO.cs b/Barotrauma/BarotraumaShared/SharedSource/Utils/SafeIO.cs index 40f135e26..fefee9d61 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Utils/SafeIO.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Utils/SafeIO.cs @@ -2,19 +2,19 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; namespace Barotrauma.IO { static class Validation { - private static readonly ImmutableArray unwritableDirs = new[] { "Content".ToIdentifier() }.ToImmutableArray(); - private static readonly ImmutableArray unwritableExtensions = new[] + private static readonly string[] unwritableDirs = new string[] { "Content" }; + private static readonly string[] unwritableExtensions = new string[] { - ".pdb", ".com", ".scr", ".dylib", ".so", ".a", ".app", //executables and libraries (.exe, .dll and .json handled separately in CanWrite) + ".pdb", ".com", ".scr", ".dylib", ".so", ".a", ".app", //executables and libraries (.exe and .dll handled separately in CanWrite) ".bat", ".sh", //shell scripts - }.ToIdentifiers().ToImmutableArray(); + ".json" //deps.json + }; /// /// When set to true, the game is allowed to modify the vanilla content in debug builds. Has no effect in non-debug builds. @@ -24,27 +24,25 @@ namespace Barotrauma.IO public static bool CanWrite(string path, bool isDirectory) { path = System.IO.Path.GetFullPath(path).CleanUpPath(); - string localModsDir = System.IO.Path.GetFullPath(ContentPackage.LocalModsDir).CleanUpPath(); - string workshopModsDir = System.IO.Path.GetFullPath(ContentPackage.WorkshopModsDir).CleanUpPath(); if (!isDirectory) { - Identifier extension = System.IO.Path.GetExtension(path).Replace(" ", "").ToIdentifier(); - if (unwritableExtensions.Any(e => e == extension)) + string extension = System.IO.Path.GetExtension(path).Replace(" ", ""); + if (unwritableExtensions.Any(e => e.Equals(extension, StringComparison.OrdinalIgnoreCase))) { return false; } - if (!path.StartsWith(workshopModsDir, StringComparison.OrdinalIgnoreCase) - && !path.StartsWith(localModsDir, StringComparison.OrdinalIgnoreCase) - && (extension == ".dll" || extension == ".exe" || extension == ".json")) + if (!path.StartsWith(System.IO.Path.GetFullPath("Mods/").CleanUpPath(), StringComparison.OrdinalIgnoreCase) + && (extension.Equals(".dll", StringComparison.OrdinalIgnoreCase) + || extension.Equals(".exe", StringComparison.OrdinalIgnoreCase))) { return false; } } - foreach (var unwritableDir in unwritableDirs) + foreach (string unwritableDir in unwritableDirs) { - string dir = System.IO.Path.GetFullPath(unwritableDir.Value).CleanUpPath(); + string dir = System.IO.Path.GetFullPath(unwritableDir).CleanUpPath(); if (path.StartsWith(dir, StringComparison.InvariantCultureIgnoreCase)) { diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index 32a3fb494..f5663e4fd 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,62 +1,3 @@ ---------------------------------------------------------------------------------------------------------- -v0.17.3.0 ---------------------------------------------------------------------------------------------------------- - -Changes: -- A new abyss monster (placeholder art and sounds, name pending) -- Overhauled colonies: completely new modules, improved layouts, new structures and items, new events. -- Adjustments to reactors and supercapacitors to prevent the increased supercapacitor loads from crippling the subs on default recharge rates: slightly increased Humpback reactor output and decreased the default recharge rate of the capacitors, reduced recharge rates in the 3 new subs and set the supercapacitor efficiency to match the rest of the subs. -- Throw an error in debug and unstable builds if beacon station becomes inactive after it's been activated (hopefully helps us diagnose why beacon missions sometimes fail after the beacon's been activated). -- Reimplemented ServerExecutable to be usable in non-core packages. Now, players must select a server executable from a dropdown in the "Host server" menu if multiple are available. -- Animation adjustment: The head now rotates towards the mouse cursor while aiming or swimming. -- Swim animation adjustment: The body now rotates towards the aim target also when the character is moving, and not only while staying still. Moving while not facing the movement direction results in reduced movement speed. -- Set the bottom hole probability to 0 in Cold Caverns, which reduces the size and the frequency of holes in the level bottom. -- Adjusted the probabilities for spawning the Thalamus in the wrecks. -- Added a (WIP) difficulty hierarchy for the abyss monsters. Easier monsters should spawn more frequently on an easier difficulty level, the harder should spawn more frequently on higher difficulty levels. Currently the new abyss monster is defined as the easiest, and Endworm the hardest. Charybdis is in between. - -Fixes: -- Re-filled Typhon 2 oxygen tank shelves. -- Fixed spawnpoint editing panel being too small on large resolutions. -- Fixed inability to equip one-handed items when there's a suitable container in the other hand (e.g. flashlight when there's a storage container in the other hand). -- Cargo missions don't require the cargo to be inside a hull: being in the sub is enough. Fixes inability to complete cargo missions with unconventional subs where the cargo is stored outside hulls. -- Fixed non-equipped items that can't be put into a duffel bag disappearing when a character despawns. -- Fixed incorrect animation parameters being used for swimming while wearing a regular diving suit. -- Fixed projectiles sometimes staying attached to the target even when they are far from it. -- Fixed monsters sometimes trying to follow targets after losing the track of them even when they should be falling back from them (according to the after attack behavior). -- Fixed monsters sometimes using the after attack behavior of the current attack even when the cooldown of that attack is not active. -- Fixed monsters sometimes being unable to target the submarine, because their attack was incorrectly considered invalid. -- Fixed fractal guardians fleeing to a shelter immediatedly after taking some damage when they have targeted the guardian pod once and have not changed the target yet (e.g. if you shoot a guardian that is returning from the pod and if it has not yet spotted you). - -Fixes (unstable only): -- Fixed text scale slider not working. -- Fixed audio capture and output settings changes not being applied until the game was restarted. -- Fixed numerous circumstances where the Publish tab could cause a crash or softlock. -- Fixed creating and deleting item assemblies in the submarine editor. -- Fixed deleting submarines in the submarine editor. -- Trimmed down the filenames of mods transferred from the server to the clients. -- Fixed ballast flora's damage visualizations (particles, branches shaking, healthbar) not working in multiplayer (unstable only). -- Fixed occasional "invalid SetAttackTarget/ExecuteAttack" errors in multiplayer (unstable only). -- Fixed clients not taking control off the previous character properly when using freecam, preventing the character from moving if another player or AI takes control of it (unstable only). -- Fixed "event data was of the wrong type" error when characters spawn with items with depleted condition in their inventory (unstable only). -- Fixed incorrect power displayed on the reactor when unwired (unstable only). -- Fixed devices not powering down if they're disconnected from the grid when their voltage has been set above 0. Could be reproduced by powering up the sub in mp campaign, entering a new level and disconnecting e.g. the oxygen generator from the grid (unstable). -- Fixed hidden subs resetting client-side when restarting a server (unstable only). -- Randomize character appearance in server lobby if it hasn't been set (= when launching the game or v0.17 for the first time). Unstable only. - -Modding: -- ItemContainers apply the OnContaining effects even when the item is broken. Doesn't affect any vanilla items. -- Ropes attached to limbs now automatically snap when another attack is chosen. -- Ropes can now be set to break from the end instead of always breaking from the middle (see the new abyss monster for an example). -- Ropes can be set to break if they are in too steep angle to the target. -- Projectiles always stick permanently unless a stick duration is defined. -- Characters (with deformable sprites) can be set to be drawn after (on top of) other characters. Normally characters are drawn in the order of spawning. -- AI Triggers can now be permanent. -- Added a generic damage threshold that currently defines how much damage the character needs to take from a single hit to hit the avoiding and releasing captured targets. -- Added a support for multiple identifiers and types in the limb health definitions. -- Added a support for min range for ranged attacks. -- Fixed monsters not being able to shoot faster than every ~1.5 second if they change the attacking limb. -- Added new after attack behaviors: Reverse and ReverseUntilCanAttack. - --------------------------------------------------------------------------------------------------------- v0.17.2.0 --------------------------------------------------------------------------------------------------------- diff --git a/Libraries/webm_mem_playback/LICENSE_webm_mem_playback.txt b/Libraries/webm_mem_playback/LICENSE_webm_mem_playback.txt index a2c5918d6..f29df7c55 100644 --- a/Libraries/webm_mem_playback/LICENSE_webm_mem_playback.txt +++ b/Libraries/webm_mem_playback/LICENSE_webm_mem_playback.txt @@ -1,4 +1,4 @@ -Copyright (c) 2019 FakeFish Ltd. +Copyright (c) 2019 FakeFish Games Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions diff --git a/README.md b/README.md index 7943f78d2..99597222e 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,6 @@ If you're interested in working on the code, either to develop mods or to contri ### Windows - [Visual Studio](https://www.visualstudio.com/vs/community/) with C# 8.0 support (VS 2019 or later recommended) ### Linux -- [.NET Core 3.1 SDK](https://docs.microsoft.com/en-us/dotnet/core/install/linux-package-manager-ubuntu-1904) +- [.NET Core 3.0 SDK](https://docs.microsoft.com/en-us/dotnet/core/install/linux-package-manager-ubuntu-1904) ### macOS - [Visual Studio 2019 for Mac](https://visualstudio.microsoft.com/vs/mac/)