diff --git a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterHUD.cs b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterHUD.cs index b6304d486..02e09c587 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterHUD.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Characters/CharacterHUD.cs @@ -3,7 +3,6 @@ using Barotrauma.Items.Components; using FarseerPhysics; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -using Microsoft.Xna.Framework.Input; using System; using System.Collections.Generic; using System.Linq; diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/ChatBox.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/ChatBox.cs index a6a44048a..114d62cdc 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/ChatBox.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/ChatBox.cs @@ -287,6 +287,11 @@ namespace Barotrauma InputBox.OnDeselected += (gui, Keys) => { ChatManager.Clear(); + if (GUIFrame.IsParentOf(GUI.MouseOn)) + { + CloseAfterMessageSent = false; + return; + } ChatMessage.GetChatMessageCommand(InputBox.Text, out var message); if (string.IsNullOrEmpty(message)) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/HUDLayoutSettings.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/HUDLayoutSettings.cs index 7afce155d..1c2e869b0 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/HUDLayoutSettings.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/HUDLayoutSettings.cs @@ -15,7 +15,7 @@ namespace Barotrauma get { return inventoryTopY; } set { - if (value == inventoryTopY) return; + if (value == inventoryTopY) { return; } inventoryTopY = value; CreateAreas(); } @@ -91,8 +91,6 @@ namespace Barotrauma if (GameMain.Instance != null) { GameMain.Instance.ResolutionChanged += CreateAreas; - #warning TODO: reimplement - //GameSettings.CurrentConfig.OnHUDScaleChanged += CreateAreas; CreateAreas(); CharacterInfo.Init(); } diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs index 47752417d..ecdb03592 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs @@ -1559,10 +1559,10 @@ namespace Barotrauma RichString missionReputationString = RichString.Rich(reputationText, wrapMissionText(GUIStyle.Font)); RichString missionDescriptionString = RichString.Rich(descriptionText, wrapMissionText(GUIStyle.Font)); - Vector2 missionNameSize = GUIStyle.LargeFont.MeasureString(missionNameString); - Vector2 missionDescriptionSize = GUIStyle.Font.MeasureString(missionDescriptionString); - Vector2 missionRewardSize = GUIStyle.Font.MeasureString(missionRewardString); - Vector2 missionReputationSize = GUIStyle.Font.MeasureString(missionReputationString); + Vector2 missionNameSize = GUIStyle.LargeFont.MeasureString(missionNameString.SanitizedValue); + Vector2 missionDescriptionSize = GUIStyle.Font.MeasureString(missionDescriptionString.SanitizedValue); + Vector2 missionRewardSize = GUIStyle.Font.MeasureString(missionRewardString.SanitizedValue); + Vector2 missionReputationSize = GUIStyle.Font.MeasureString(missionReputationString.SanitizedValue); float ySize = missionNameSize.Y + missionDescriptionSize.Y + missionRewardSize.Y + missionReputationSize.Y + missionTextGroup.AbsoluteSpacing * 4; bool displayDifficulty = mission.Difficulty.HasValue; diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/CaptainTutorial.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/CaptainTutorial.cs index 2f9e0a46f..c4ec80301 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/CaptainTutorial.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/CaptainTutorial.cs @@ -102,29 +102,11 @@ namespace Barotrauma.Tutorials radioSpeakerName = TextManager.Get("Tutorial.Radio.Watchman"); GameMain.GameSession.CrewManager.AllowCharacterSwitch = false; - var revolver = FindOrGiveItem(captain, "revolver".ToIdentifier()); - revolver.Unequip(captain); - captain.Inventory.RemoveItem(revolver); - - var captainscap = - captain.Inventory.FindItemByIdentifier("captainscap1".ToIdentifier()) ?? - captain.Inventory.FindItemByIdentifier("captainscap2".ToIdentifier()) ?? - captain.Inventory.FindItemByIdentifier("captainscap3".ToIdentifier()); - - if (captainscap != null) + foreach (Item item in captain.Inventory.AllItemsMod) { - captainscap.Unequip(captain); - captain.Inventory.RemoveItem(captainscap); - } - - var captainsuniform = - captain.Inventory.FindItemByIdentifier("captainsuniform1".ToIdentifier()) ?? - captain.Inventory.FindItemByIdentifier("captainsuniform2".ToIdentifier()) ?? - captain.Inventory.FindItemByIdentifier("captainsuniform3".ToIdentifier()); - if (captainsuniform != null) - { - captainsuniform.Unequip(captain); - captain.Inventory.RemoveItem(captainsuniform); + if (item.HasTag("identitycard") || item.HasTag("headset")) { continue; } + item.Unequip(captain); + captain.Inventory.RemoveItem(item); } var steerOrder = OrderPrefab.Prefabs["steer"]; diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/DoctorTutorial.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/DoctorTutorial.cs index 4cf46e5f1..ff73b2f00 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/DoctorTutorial.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/DoctorTutorial.cs @@ -105,21 +105,12 @@ namespace Barotrauma.Tutorials radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker"); doctor = Character.Controlled; - var bandages = FindOrGiveItem(doctor, "antibleeding1".ToIdentifier()); - bandages.Unequip(doctor); - doctor.Inventory.RemoveItem(bandages); - - var syringegun = FindOrGiveItem(doctor, "syringegun".ToIdentifier()); - syringegun.Unequip(doctor); - doctor.Inventory.RemoveItem(syringegun); - - var antibiotics = FindOrGiveItem(doctor, "antibiotics".ToIdentifier()); - antibiotics.Unequip(doctor); - doctor.Inventory.RemoveItem(antibiotics); - - var morphine = FindOrGiveItem(doctor, "antidama1".ToIdentifier()); - morphine.Unequip(doctor); - doctor.Inventory.RemoveItem(morphine); + foreach (Item item in doctor.Inventory.AllItemsMod) + { + if (item.HasTag("clothing") || item.HasTag("identitycard") || item.HasTag("headset")) { continue; } + item.Unequip(doctor); + doctor.Inventory.RemoveItem(item); + } doctor_suppliesCabinet = Item.ItemList.Find(i => i.HasTag("doctor_suppliescabinet"))?.GetComponent(); doctor_medBayCabinet = Item.ItemList.Find(i => i.HasTag("doctor_medbaycabinet"))?.GetComponent(); diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/EngineerTutorial.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/EngineerTutorial.cs index 52592248d..c30c1c346 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/EngineerTutorial.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/EngineerTutorial.cs @@ -131,9 +131,12 @@ namespace Barotrauma.Tutorials radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker"); engineer = Character.Controlled; - var toolbelt = FindOrGiveItem(engineer, "toolbelt".ToIdentifier()); - toolbelt.Unequip(engineer); - engineer.Inventory.RemoveItem(toolbelt); + foreach (Item item in engineer.Inventory.AllItemsMod) + { + if (item.HasTag("clothing") || item.HasTag("identitycard") || item.HasTag("headset")) { continue; } + item.Unequip(engineer); + engineer.Inventory.RemoveItem(item); + } var repairOrder = OrderPrefab.Prefabs["repairsystems"]; engineer_repairIcon = repairOrder.SymbolSprite; diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/MechanicTutorial.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/MechanicTutorial.cs index 71fd7e344..23b5da096 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/MechanicTutorial.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/MechanicTutorial.cs @@ -160,13 +160,12 @@ namespace Barotrauma.Tutorials radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker"); mechanic = Character.Controlled; - var toolbelt = FindOrGiveItem(mechanic, "toolbelt".ToIdentifier()); - toolbelt.Unequip(mechanic); - mechanic.Inventory.RemoveItem(toolbelt); - - var crowbar = FindOrGiveItem(mechanic, "crowbar".ToIdentifier()); - crowbar.Unequip(mechanic); - mechanic.Inventory.RemoveItem(crowbar); + foreach (Item item in mechanic.Inventory.AllItemsMod) + { + if (item.HasTag("clothing") || item.HasTag("identitycard") || item.HasTag("headset")) { continue; } + item.Unequip(mechanic); + mechanic.Inventory.RemoveItem(item); + } var repairOrder = OrderPrefab.Prefabs["repairsystems"]; mechanic_repairIcon = repairOrder.SymbolSprite; @@ -297,7 +296,10 @@ namespace Barotrauma.Tutorials public override void Update(float deltaTime) { - mechanic_brokenhull_1.WaterVolume = MathHelper.Clamp(mechanic_brokenhull_1.WaterVolume, 0, mechanic_brokenhull_1.Volume * 0.85f); + if (mechanic_brokenhull_1 != null) + { + mechanic_brokenhull_1.WaterVolume = MathHelper.Clamp(mechanic_brokenhull_1.WaterVolume, 0, mechanic_brokenhull_1.Volume * 0.85f); + } base.Update(deltaTime); } @@ -413,7 +415,7 @@ namespace Barotrauma.Tutorials } } while (mechanic_workingPump.FlowPercentage >= 0 || !mechanic_workingPump.IsActive); // Highlight until draining SetHighlight(mechanic_workingPump.Item, false); - do { yield return null; } while (mechanic_brokenhull_1.WaterPercentage > waterVolumeBeforeOpening); // Unlock door once drained + do { yield return null; } while (mechanic_brokenhull_1 != null && mechanic_brokenhull_1.WaterPercentage > waterVolumeBeforeOpening); // Unlock door once drained RemoveCompletedObjective(3); GameAnalyticsManager.AddDesignEvent("Tutorial:MechanicTutorial:Objective3"); diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/OfficerTutorial.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/OfficerTutorial.cs index b2514450f..a8ba18da8 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/OfficerTutorial.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/GameModes/Tutorials/OfficerTutorial.cs @@ -141,36 +141,12 @@ namespace Barotrauma.Tutorials radioSpeakerName = TextManager.Get("Tutorial.Radio.Speaker"); officer = Character.Controlled; - var handcuffs = FindOrGiveItem(officer, "handcuffs".ToIdentifier()); - handcuffs.Unequip(officer); - officer.Inventory.RemoveItem(handcuffs); - - var stunbaton = FindOrGiveItem(officer, "stunbaton".ToIdentifier()); - stunbaton.Unequip(officer); - officer.Inventory.RemoveItem(stunbaton); - - var smg = FindOrGiveItem(officer, "smg".ToIdentifier()); - smg.Unequip(officer); - officer.Inventory.RemoveItem(smg); - - var divingknife = FindOrGiveItem(officer, "divingknife".ToIdentifier()); - divingknife.Unequip(officer); - officer.Inventory.RemoveItem(divingknife); - - var steroids = FindOrGiveItem(officer, "steroids".ToIdentifier()); - steroids.Unequip(officer); - officer.Inventory.RemoveItem(steroids); - - var ballistichelmet = - officer.Inventory.FindItemByIdentifier("ballistichelmet1".ToIdentifier()) ?? - officer.Inventory.FindItemByIdentifier("ballistichelmet2".ToIdentifier()) ?? - FindOrGiveItem(officer, "ballistichelmet3".ToIdentifier()); - ballistichelmet.Unequip(officer); - officer.Inventory.RemoveItem(ballistichelmet); - - var bodyarmor = FindOrGiveItem(officer, "bodyarmor".ToIdentifier()); - bodyarmor.Unequip(officer); - officer.Inventory.RemoveItem(bodyarmor); + foreach (Item item in officer.Inventory.AllItemsMod) + { + if (item.HasTag("clothing") || item.HasTag("identitycard") || item.HasTag("headset")) { continue; } + item.Unequip(officer); + officer.Inventory.RemoveItem(item); + } var gunOrder = OrderPrefab.Prefabs["operateweapons"]; officer_gunIcon = gunOrder.SymbolSprite; diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/ReadyCheck.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/ReadyCheck.cs index 003816dae..4db03f290 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/ReadyCheck.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/ReadyCheck.cs @@ -28,7 +28,7 @@ namespace Barotrauma UserListData = "ReadyUserList", ReadySpriteData = "ReadySprite"; - private int lastSecond; + private int lastSecond = 1; private GUIMessageBox? msgBox; private GUIMessageBox? resultsBox; @@ -44,7 +44,7 @@ namespace Barotrauma msgBox = new GUIMessageBox(readyCheckHeader, readyCheckBody(author), new[] { yesButton, noButton }, relativeSize, minSize, type: GUIMessageBox.Type.Vote) { UserData = PromptData, Draggable = true }; GUILayoutGroup contentLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.125f), msgBox.Content.RectTransform), childAnchor: Anchor.Center); - new GUIProgressBar(new RectTransform(new Vector2(0.8f, 1f), contentLayout.RectTransform), time / endTime, GUIStyle.Orange) { UserData = TimerData }; + new GUIProgressBar(new RectTransform(new Vector2(0.8f, 1f), contentLayout.RectTransform), 0.0f, GUIStyle.Orange) { UserData = TimerData }; // Yes msgBox.Buttons[0].OnClicked = delegate @@ -116,17 +116,18 @@ namespace Barotrauma private void UpdateBar() { + double elapsedTime = (DateTime.Now - startTime).TotalSeconds; if (msgBox != null && !msgBox.Closed && GUIMessageBox.MessageBoxes.Contains(msgBox)) { if (msgBox.FindChild(TimerData, true) is GUIProgressBar bar) { - bar.BarSize = time / endTime; + bar.BarSize = (float)(elapsedTime / (endTime - startTime).TotalSeconds); } } // play click sound after a second has passed - int second = (int) Math.Ceiling(time); - if (second < lastSecond) + int second = (int)Math.Ceiling(elapsedTime); + if (second > lastSecond) { if (msgBox != null && !msgBox.Closed) { @@ -156,7 +157,8 @@ namespace Barotrauma bool isOwn = false; byte authorId = 0; - float duration = inc.ReadSingle(); + long startTime = inc.ReadInt64(); + long endTime = inc.ReadInt64(); string author = inc.ReadString(); bool hasAuthor = inc.ReadBoolean(); @@ -173,7 +175,9 @@ namespace Barotrauma clients.Add(inc.ReadByte()); } - ReadyCheck rCheck = new ReadyCheck(clients, duration); + ReadyCheck rCheck = new ReadyCheck(clients, + DateTimeOffset.FromUnixTimeSeconds(startTime).LocalDateTime, + DateTimeOffset.FromUnixTimeSeconds(endTime).LocalDateTime); crewManager.ActiveReadyCheck = rCheck; if (isOwn) @@ -192,12 +196,10 @@ namespace Barotrauma } break; case ReadyCheckState.Update: - float time = inc.ReadSingle(); ReadyStatus newState = (ReadyStatus) inc.ReadByte(); byte targetId = inc.ReadByte(); if (crewManager.ActiveReadyCheck != null) { - crewManager.ActiveReadyCheck.time = time; crewManager.ActiveReadyCheck?.UpdateState(targetId, newState); } break; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Door.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Door.cs index 3d3070aef..88bd89496 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Door.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Door.cs @@ -222,7 +222,8 @@ namespace Barotrauma.Items.Components if (brokenSprite != null && item.Health < item.MaxCondition) { - Vector2 scale = scaleBrokenSprite ? new Vector2(1.0f, 1.0f - item.Health / item.MaxCondition) : Vector2.One; + Vector2 scale = scaleBrokenSprite ? new Vector2(1.0f - item.Health / item.MaxCondition) : Vector2.One; + if (IsHorizontal) { scale.X = 1; } else { scale.Y = 1; } float alpha = fadeBrokenSprite ? 1.0f - item.Health / item.MaxCondition : 1.0f; spriteBatch.Draw(brokenSprite.Texture, pos, getSourceRect(brokenSprite, openState, IsHorizontal), diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemComponent.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemComponent.cs index 4966e5c49..9b287cbd1 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemComponent.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/ItemComponent.cs @@ -405,7 +405,7 @@ namespace Barotrauma.Items.Components float newVolume; try { - newVolume = property.GetFloatValue(this); + newVolume = Math.Min(property.GetFloatValue(this), 1.0f); } catch { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Terminal.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Terminal.cs index 8b97d27be..980a6f256 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Terminal.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Terminal.cs @@ -58,6 +58,8 @@ namespace Barotrauma.Items.Components return true; } }; + + layoutGroup.Recalculate(); } // Create fillerBlock to cover historyBox so new values appear at the bottom of historyBox diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/Gap.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/Gap.cs index 57979fdd0..088ffdf3d 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/Gap.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/Gap.cs @@ -33,7 +33,7 @@ namespace Barotrauma DrawArrow(FlowTargetHull, IsHorizontal ? rect.Height: rect.Width, Math.Abs(lerpedFlowForce.Length()), Color.Red * 0.3f); } - if (outsideCollisionBlocker.Enabled && Submarine != null) + if (Submarine != null && outsideCollisionBlocker != null && outsideCollisionBlocker.Enabled) { var edgeShape = outsideCollisionBlocker.FixtureList[0].Shape as FarseerPhysics.Collision.Shapes.EdgeShape; Vector2 startPos = ConvertUnits.ToDisplayUnits(outsideCollisionBlocker.GetWorldPoint(edgeShape.Vertex1)) + Submarine.Position; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Map/SubmarineInfo.cs b/Barotrauma/BarotraumaClient/ClientSource/Map/SubmarineInfo.cs index d0a908933..463d94253 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Map/SubmarineInfo.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Map/SubmarineInfo.cs @@ -8,7 +8,7 @@ namespace Barotrauma partial class SubmarineInfo : IDisposable { public Sprite PreviewImage; - + partial void InitProjectSpecific() { string previewImageData = SubmarineElement.GetAttributeString("previewimage", ""); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs index 4409512fb..2419901fd 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs @@ -1200,7 +1200,14 @@ namespace Barotrauma.Networking new LocalizedString[] { TextManager.Get("Cancel") }); reconnectBox.Buttons[0].OnClicked += (btn, userdata) => { CancelConnect(); return true; }; connected = false; + + var prevContentPackages = clientPeer.ServerContentPackages; ConnectToServer(serverEndpoint, serverName); + if (clientPeer != null) + { + //restore the previous list of content packages so we can reconnect immediately without having to recheck that the packages match + clientPeer.ServerContentPackages = prevContentPackages; + } } else { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/OrderChatMessage.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/OrderChatMessage.cs index 1134f3aa0..673a8423f 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/OrderChatMessage.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/OrderChatMessage.cs @@ -9,6 +9,7 @@ namespace Barotrauma.Networking msg.Write((byte)ClientNetObject.CHAT_MESSAGE); msg.Write(NetStateID); msg.WriteRangedInteger((int)ChatMessageType.Order, 0, Enum.GetValues(typeof(ChatMessageType)).Length - 1); + msg.WriteRangedInteger((int)ChatMode.None, 0, Enum.GetValues(typeof(ChatMode)).Length - 1); WriteOrder(msg); } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/Primitives/Peers/ClientPeer.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/Primitives/Peers/ClientPeer.cs index 3134ee4f8..f39baaaec 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/Primitives/Peers/ClientPeer.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/Primitives/Peers/ClientPeer.cs @@ -50,7 +50,7 @@ namespace Barotrauma.Networking } } - public ImmutableArray ServerContentPackages { get; private set; } = + public ImmutableArray ServerContentPackages { get; set; } = ImmutableArray.Empty; public delegate void MessageCallback(IReadMessage message); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/Primitives/Peers/LidgrenClientPeer.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/Primitives/Peers/LidgrenClientPeer.cs index 47201cef6..ed3738964 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/Primitives/Peers/LidgrenClientPeer.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/Primitives/Peers/LidgrenClientPeer.cs @@ -117,8 +117,6 @@ namespace Barotrauma.Networking PacketHeader packetHeader = (PacketHeader)inc.ReadByte(); - //Console.WriteLine(isCompressed + " " + isConnectionInitializationStep + " " + (int)incByte); - if (packetHeader.IsConnectionInitializationStep() && initializationStep != ConnectionInitialization.Success) { ReadConnectionInitializationStep(new ReadWriteMessage(inc.Data, (int)inc.Position, inc.LengthBits, false)); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignSetupUI/CampaignSetupUI.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignSetupUI/CampaignSetupUI.cs index 7bfeb7275..5e679768b 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignSetupUI/CampaignSetupUI.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignSetupUI/CampaignSetupUI.cs @@ -110,7 +110,7 @@ namespace Barotrauma public SettingValue Difficulty; public SettingValue StartItemSet; - public CampaignSettings CreateSettings() + public readonly CampaignSettings CreateSettings() { return new CampaignSettings(element: null) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignSetupUI/SinglePlayerCampaignSetupUI.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignSetupUI/SinglePlayerCampaignSetupUI.cs index 40737a179..b093b494d 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignSetupUI/SinglePlayerCampaignSetupUI.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/CampaignSetupUI/SinglePlayerCampaignSetupUI.cs @@ -210,8 +210,17 @@ namespace Barotrauma { CreateCustomizeWindow(CurrentSettings, settings => { + CampaignSettings prevSettings = CurrentSettings; CurrentSettings = settings; - UpdateSubList(SubmarineInfo.SavedSubmarines); + if (prevSettings.InitialMoney != settings.InitialMoney) + { + object selectedData = subList.SelectedData; + UpdateSubList(SubmarineInfo.SavedSubmarines); + if (selectedData is SubmarineInfo selectedSub && selectedSub.Price <= CurrentSettings.InitialMoney) + { + subList.Select(selectedData); + } + } }); return true; } @@ -519,7 +528,7 @@ namespace Barotrauma subsToShow = submarines.Where(s => s.IsCampaignCompatibleIgnoreClass && Path.GetDirectoryName(Path.GetFullPath(s.FilePath)) != downloadFolder).ToList(); } - subsToShow.Sort((s1, s2) => + subsToShow.Sort((s1, s2) => { int p1 = s1.Price > CurrentSettings.InitialMoney ? 10 : 0; int p2 = s2.Price > CurrentSettings.InitialMoney ? 10 : 0; @@ -537,7 +546,7 @@ namespace Barotrauma ToolTip = sub.Description, UserData = sub }; - + if (!sub.RequiredContentPackagesInstalled) { textBlock.TextColor = Color.Lerp(textBlock.TextColor, Color.DarkRed, .5f); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/LevelEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/LevelEditorScreen.cs index ed93ceee0..3d026e56a 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/LevelEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/LevelEditorScreen.cs @@ -513,18 +513,18 @@ namespace Barotrauma var moduleLabel = new GUITextBlock(new RectTransform(new Point(editorContainer.Content.Rect.Width, (int)(70 * GUI.Scale))), TextManager.Get("submarinetype.outpostmodules"), font: GUIStyle.SubHeadingFont); outpostParamsEditor.AddCustomContent(moduleLabel, 100); - foreach (KeyValuePair moduleCount in outpostGenerationParams.ModuleCounts) + foreach (var moduleCount in outpostGenerationParams.ModuleCounts) { var moduleCountGroup = new GUILayoutGroup(new RectTransform(new Point(editorContainer.Content.Rect.Width, (int)(25 * GUI.Scale))), isHorizontal: true, childAnchor: Anchor.CenterLeft); - new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), moduleCountGroup.RectTransform), TextManager.Capitalize(moduleCount.Key.Value), textAlignment: Alignment.CenterLeft); + new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), moduleCountGroup.RectTransform), TextManager.Capitalize(moduleCount.Identifier.Value), textAlignment: Alignment.CenterLeft); new GUINumberInput(new RectTransform(new Vector2(0.5f, 1f), moduleCountGroup.RectTransform), NumberType.Int) { MinValueInt = 0, MaxValueInt = 100, - IntValue = moduleCount.Value, + IntValue = moduleCount.Count, OnValueChanged = (numInput) => { - outpostGenerationParams.SetModuleCount(moduleCount.Key, numInput.IntValue); + outpostGenerationParams.SetModuleCount(moduleCount.Identifier, numInput.IntValue); if (numInput.IntValue == 0) { outpostParamsList.Select(outpostParamsList.SelectedData); @@ -540,7 +540,7 @@ namespace Barotrauma var addModuleCountGroup = new GUILayoutGroup(new RectTransform(new Point(editorContainer.Content.Rect.Width, (int)(40 * GUI.Scale))), isHorizontal: true, childAnchor: Anchor.Center); HashSet availableFlags = new HashSet(); - foreach (Identifier flag in OutpostGenerationParams.OutpostParams.SelectMany(p => p.ModuleCounts.Select(m => m.Key))) { availableFlags.Add(flag); } + foreach (Identifier flag in OutpostGenerationParams.OutpostParams.SelectMany(p => p.ModuleCounts.Select(m => m.Identifier))) { availableFlags.Add(flag); } foreach (var sub in SubmarineInfo.SavedSubmarines) { if (sub.OutpostModuleInfo == null) { continue; } @@ -551,7 +551,7 @@ namespace Barotrauma text: TextManager.Get("leveleditor.addmoduletype")); foreach (Identifier flag in availableFlags) { - if (outpostGenerationParams.ModuleCounts.Any(mc => mc.Key == flag)) { continue; } + if (outpostGenerationParams.ModuleCounts.Any(mc => mc.Identifier == flag)) { continue; } moduleTypeDropDown.AddItem(TextManager.Capitalize(flag.Value), flag); } moduleTypeDropDown.OnSelected += (_, userdata) => diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs index 442ea1bae..4ba25491a 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs @@ -1549,6 +1549,11 @@ namespace Barotrauma MapEntity.DeselectAll(); ClearUndoBuffer(); + GameMain.DebugDraw = false; + GameMain.LightManager.LightingEnabled = true; + Hull.EditWater = false; + Hull.EditFire = false; + SetMode(Mode.Default); SoundPlayer.OverrideMusicType = Identifier.Empty; @@ -1586,7 +1591,7 @@ namespace Barotrauma private void CreateDummyCharacter() { - if (dummyCharacter != null) RemoveDummyCharacter(); + if (dummyCharacter != null) { RemoveDummyCharacter(); } dummyCharacter = Character.Create(CharacterPrefab.HumanSpeciesName, Vector2.Zero, "", id: Entity.DummyID, hasAi: false); dummyCharacter.Info.Name = "Galldren"; @@ -1876,21 +1881,15 @@ namespace Barotrauma && MainSub.Info.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)) { prevSavePath = MainSub.Info.FilePath.CleanUpPath(); - string prevDir = Path.GetDirectoryName(MainSub.Info.FilePath).CleanUpPath(); - - ModProject modProject = new ModProject { Name = name }; - string fileListPath = null; - ContentPackage contentPackage = GetLocalPackageThatOwnsSub(MainSub.Info); - if (contentPackage != null) + if (contentPackage == null) { - modProject = new ModProject(contentPackage); - fileListPath = contentPackage.Path; - packageToSaveTo = contentPackage; + throw new InvalidOperationException($"Tried to overwrite a submarine ({name}) that's not in a local package!"); } - - savePath = Path.Combine(prevDir, savePath).CleanUpPath(); - addSubAndSaveModProject(modProject, savePath, fileListPath ?? Path.Combine(Path.GetDirectoryName(savePath), ContentPackage.FileListFileName)); + ModProject modProject = new ModProject(contentPackage); + packageToSaveTo = contentPackage; + savePath = prevSavePath; + addSubAndSaveModProject(modProject, savePath, contentPackage.Path); } else { @@ -2074,8 +2073,8 @@ namespace Barotrauma new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), outpostModuleGroup.RectTransform), TextManager.Get("outpostmoduletype"), textAlignment: Alignment.CenterLeft); HashSet availableFlags = new HashSet(); - foreach (Identifier flag in OutpostGenerationParams.OutpostParams.SelectMany(p => p.ModuleCounts.Select(m => m.Key))) { availableFlags.Add(flag); } - foreach (Identifier flag in RuinGeneration.RuinGenerationParams.RuinParams.SelectMany(p => p.ModuleCounts.Select(m => m.Key))) { availableFlags.Add(flag); } + foreach (Identifier flag in OutpostGenerationParams.OutpostParams.SelectMany(p => p.ModuleCounts.Select(m => m.Identifier))) { availableFlags.Add(flag); } + foreach (Identifier flag in RuinGeneration.RuinGenerationParams.RuinParams.SelectMany(p => p.ModuleCounts.Select(m => m.Identifier))) { availableFlags.Add(flag); } foreach (var sub in SubmarineInfo.SavedSubmarines) { if (sub.OutpostModuleInfo == null) { continue; } @@ -2551,11 +2550,9 @@ namespace Barotrauma { MainSub.Info.BeaconStationInfo ??= new BeaconStationInfo(MainSub.Info); } - previewImageButtonHolder.Children.ForEach(c => c.Enabled = type != SubmarineType.OutpostModule); + previewImageButtonHolder.Children.ForEach(c => c.Enabled = MainSub.Info.AllowPreviewImage); outpostSettingsContainer.Visible = type == SubmarineType.OutpostModule; - beaconSettingsContainer.Visible = type == SubmarineType.BeaconStation; - subSettingsContainer.Visible = type == SubmarineType.Player; return true; }; @@ -2572,6 +2569,7 @@ namespace Barotrauma new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), previewImageButtonHolder.RectTransform), TextManager.Get("SubPreviewImageCreate"), style: "GUIButtonSmall") { + Enabled = MainSub?.Info.AllowPreviewImage ?? false, OnClicked = (btn, userdata) => { using (System.IO.MemoryStream imgStream = new System.IO.MemoryStream()) @@ -2589,6 +2587,7 @@ namespace Barotrauma new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), previewImageButtonHolder.RectTransform), TextManager.Get("SubPreviewImageBrowse"), style: "GUIButtonSmall") { + Enabled = MainSub?.Info.AllowPreviewImage ?? false, OnClicked = (btn, userdata) => { FileSelection.OnFileSelected = (file) => diff --git a/Barotrauma/BarotraumaClient/ClientSource/Settings/SettingsMenu.cs b/Barotrauma/BarotraumaClient/ClientSource/Settings/SettingsMenu.cs index d514f6129..50edb5235 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Settings/SettingsMenu.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Settings/SettingsMenu.cs @@ -220,7 +220,7 @@ namespace Barotrauma }; } - private string Percentage(float v) => $"{Round(v * 100)}%"; + private string Percentage(float v) => TextManager.GetWithVariable("percentageformat", "[value]", Round(v * 100).ToString()).Value; private int Round(float v) => (int)MathF.Round(v); @@ -647,6 +647,8 @@ namespace Barotrauma { unsavedConfig.InventoryKeyMap = GameSettings.Config.InventoryKeyMapping.GetDefault(); unsavedConfig.KeyMap = GameSettings.Config.KeyMapping.GetDefault(); + Create(mainFrame.Parent.RectTransform); + Instance?.SelectTab(Tab.Controls); return true; } }; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Sprite/Sprite.cs b/Barotrauma/BarotraumaClient/ClientSource/Sprite/Sprite.cs index d4e1648a3..2a71f2bd7 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Sprite/Sprite.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Sprite/Sprite.cs @@ -253,12 +253,12 @@ namespace Barotrauma if (flipHorizontal) { float diff = targetSize.X % (sourceRect.Width * scale.X); - flippedDrawOffset.X = (int)((sourceRect.Width * scale.X - diff) / scale.X); + flippedDrawOffset.X = (int)MathF.Round((sourceRect.Width * scale.X - diff) / scale.X); } if (flipVertical) { float diff = targetSize.Y % (sourceRect.Height * scale.Y); - flippedDrawOffset.Y = (int)((sourceRect.Height * scale.Y - diff) / scale.Y); + flippedDrawOffset.Y = (int)MathF.Round((sourceRect.Height * scale.Y - diff) / scale.Y); } drawOffset += flippedDrawOffset; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/InstalledTab.cs b/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/InstalledTab.cs index 59624f305..27689b385 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/InstalledTab.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/InstalledTab.cs @@ -562,10 +562,10 @@ namespace Barotrauma.Steam = (parentList == enabledRegularModsList, parentList.AllSelected.Count > 1); Identifier swapLabel = (labelConditions switch { - (true, true) => "EnableSelectedWorkshopMods", - (true, false) => "EnableWorkshopMod", - (false, true) => "DisableSelectedWorkshopMods", - (false, false) => "DisableWorkshopMod" + (false, true) => "EnableSelectedWorkshopMods", + (false, false) => "EnableWorkshopMod", + (true, true) => "DisableSelectedWorkshopMods", + (true, false) => "DisableWorkshopMod" }).ToIdentifier(); contextMenuOptions.Add(new ContextMenuOption(swapLabel, diff --git a/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/ItemList.cs b/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/ItemList.cs index 7daabaacc..b739b3149 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/ItemList.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/ItemList.cs @@ -595,6 +595,12 @@ namespace Barotrauma.Steam { ContentPackageManager.WorkshopPackages.Refresh(); ContentPackageManager.EnabledPackages.RefreshUpdatedMods(); + var package = ContentPackageManager.WorkshopPackages.FirstOrDefault(p => p.SteamWorkshopId == workshopItem.Id); + if (package is RegularPackage regular) + { + ContentPackageManager.EnabledPackages.EnableRegular(regular); + } + PopulateInstalledModLists(forceRefreshEnabled: true); }); return false; } diff --git a/Barotrauma/BarotraumaClient/LinuxClient.csproj b/Barotrauma/BarotraumaClient/LinuxClient.csproj index 812630849..7e5c42815 100644 --- a/Barotrauma/BarotraumaClient/LinuxClient.csproj +++ b/Barotrauma/BarotraumaClient/LinuxClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.18.6.0 + 0.18.7.0 Copyright © FakeFish 2018-2022 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/MacClient.csproj b/Barotrauma/BarotraumaClient/MacClient.csproj index 3907f2088..8c28ff5dd 100644 --- a/Barotrauma/BarotraumaClient/MacClient.csproj +++ b/Barotrauma/BarotraumaClient/MacClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.18.6.0 + 0.18.7.0 Copyright © FakeFish 2018-2022 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/WindowsClient.csproj b/Barotrauma/BarotraumaClient/WindowsClient.csproj index 138834ca7..6db93f270 100644 --- a/Barotrauma/BarotraumaClient/WindowsClient.csproj +++ b/Barotrauma/BarotraumaClient/WindowsClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.18.6.0 + 0.18.7.0 Copyright © FakeFish 2018-2022 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaServer/LinuxServer.csproj b/Barotrauma/BarotraumaServer/LinuxServer.csproj index 6abd0ba2e..133bbd9d4 100644 --- a/Barotrauma/BarotraumaServer/LinuxServer.csproj +++ b/Barotrauma/BarotraumaServer/LinuxServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.18.6.0 + 0.18.7.0 Copyright © FakeFish 2018-2022 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/MacServer.csproj b/Barotrauma/BarotraumaServer/MacServer.csproj index fa7a15b47..961807808 100644 --- a/Barotrauma/BarotraumaServer/MacServer.csproj +++ b/Barotrauma/BarotraumaServer/MacServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.18.6.0 + 0.18.7.0 Copyright © FakeFish 2018-2022 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterInfo.cs b/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterInfo.cs index f2fde6748..197c22a26 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterInfo.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Characters/CharacterInfo.cs @@ -10,6 +10,11 @@ namespace Barotrauma { private readonly Dictionary prevSentSkill = new Dictionary(); + /// + /// The client opted to create a new character and discard this one + /// + public bool Discarded; + partial void OnSkillChanged(Identifier skillIdentifier, float prevLevel, float newLevel) { if (Character == null || Character.Removed) { return; } diff --git a/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs b/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs index a562798b2..ae5c4e510 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs @@ -230,7 +230,7 @@ namespace Barotrauma if (!matchingCharacterData.HasSpawned) { continue; } characterInfo ??= matchingCharacterData.CharacterInfo; } - if (characterInfo == null) { continue; } + if (characterInfo == null || characterInfo.Discarded) { continue; } //reduce skills if the character has died if (characterInfo.CauseOfDeath != null && characterInfo.CauseOfDeath.Type != CauseOfDeathType.Disconnected) { @@ -420,6 +420,8 @@ namespace Barotrauma { discardedCharacters.Add(data); } + DebugConsole.Log($"Client \"{client}\" discarded the character ({data.Name})"); + data.CharacterInfo.Discarded = true; characterData.Remove(data); IncrementLastUpdateIdForFlag(NetFlags.CharacterInfo); } diff --git a/Barotrauma/BarotraumaServer/ServerSource/GameSession/ReadyCheck.cs b/Barotrauma/BarotraumaServer/ServerSource/GameSession/ReadyCheck.cs index dea506acf..3ac8dd6a9 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/GameSession/ReadyCheck.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/GameSession/ReadyCheck.cs @@ -1,4 +1,5 @@ #nullable enable +using System; using System.Collections.Generic; using System.Linq; using Barotrauma.Networking; @@ -18,7 +19,8 @@ namespace Barotrauma IWriteMessage msg = new WriteOnlyMessage(); msg.Write((byte) ServerPacketHeader.READY_CHECK); msg.Write((byte) ReadyCheckState.Start); - msg.Write(endTime); + msg.Write(new DateTimeOffset(startTime).ToUnixTimeSeconds()); + msg.Write(new DateTimeOffset(endTime).ToUnixTimeSeconds()); msg.Write(author); if (sender != null) @@ -53,10 +55,9 @@ namespace Barotrauma foreach (Client client in ActivePlayers) { IWriteMessage msg = new WriteOnlyMessage(); - msg.Write((byte) ServerPacketHeader.READY_CHECK); - msg.Write((byte) ReadyCheckState.Update); - msg.Write(time); // sync time - msg.Write((byte) state); + msg.Write((byte)ServerPacketHeader.READY_CHECK); + msg.Write((byte)ReadyCheckState.Update); + msg.Write((byte)state); msg.Write(otherClient); GameMain.Server.ServerPeer.Send(msg, client.Connection, DeliveryMethod.Reliable); } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Items/Components/Machines/Pump.cs b/Barotrauma/BarotraumaServer/ServerSource/Items/Components/Machines/Pump.cs index f2249351b..125557284 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Items/Components/Machines/Pump.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Items/Components/Machines/Pump.cs @@ -1,13 +1,22 @@ using Barotrauma.Networking; -using Microsoft.Xna.Framework; -using System; -using System.Globalization; -using System.Xml.Linq; namespace Barotrauma.Items.Components { partial class Pump : Powered, IServerSerializable, IClientSerializable { + const float NetworkUpdateInterval = 5.0f; + private float networkUpdateTimer; + + partial void UpdateProjSpecific(float deltaTime) + { + networkUpdateTimer -= deltaTime; + if (networkUpdateTimer <= 0.0f) + { + item.CreateServerEvent(this); + networkUpdateTimer = NetworkUpdateInterval; + } + } + public void ServerEventRead(IReadMessage msg, Client c) { float newFlowPercentage = msg.ReadRangedInteger(-10, 10) * 10.0f; diff --git a/Barotrauma/BarotraumaServer/ServerSource/Map/Hull.cs b/Barotrauma/BarotraumaServer/ServerSource/Map/Hull.cs index 024b68518..9efc0c125 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Map/Hull.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Map/Hull.cs @@ -2,10 +2,7 @@ using Barotrauma.Networking; using Microsoft.Xna.Framework; using System; -using System.Collections.Generic; using System.Linq; -using Barotrauma.Extensions; -using Barotrauma.MapCreatures.Behavior; namespace Barotrauma { @@ -39,9 +36,9 @@ namespace Barotrauma return; } - statusUpdateTimer -= deltaTime; - decalUpdateTimer -= deltaTime; - backgroundSectionUpdateTimer -= deltaTime; + statusUpdateTimer += deltaTime; + decalUpdateTimer += deltaTime; + backgroundSectionUpdateTimer += deltaTime; //update client hulls if the amount of water has changed by >10% //or if oxygen percentage has changed by 5% @@ -49,33 +46,32 @@ namespace Barotrauma (Math.Abs(lastSentVolume - waterVolume) > Volume * 0.1f || Math.Abs(lastSentOxygen - OxygenPercentage) > 5f || lastSentFireCount != FireSources.Count) - && statusUpdateTimer <= 0.0f; + && (statusUpdateTimer > NetConfig.HullUpdateInterval); - if (shouldSendStatusUpdate) + //force an update every 5 seconds even if nothing's changed (in case a client's gotten out of sync somehow) + if (shouldSendStatusUpdate || statusUpdateTimer > NetConfig.SparseHullUpdateInterval) { - GameMain.NetworkMember.CreateEntityEvent(this, new StatusEventData()); - + GameMain.NetworkMember.CreateEntityEvent(this, new StatusEventData()); lastSentVolume = waterVolume; lastSentOxygen = OxygenPercentage; lastSentFireCount = FireSources.Count; - - statusUpdateTimer = NetConfig.SparseHullUpdateInterval; + statusUpdateTimer = 0; } - if (decalUpdatePending && decalUpdateTimer <= 0.0f) + if (decalUpdatePending && decalUpdateTimer > NetConfig.HullUpdateInterval) { GameMain.NetworkMember.CreateEntityEvent(this, new DecalEventData()); - decalUpdateTimer = NetConfig.HullUpdateInterval; + decalUpdateTimer = 0; decalUpdatePending = false; } - if (pendingSectionUpdates.Count > 0 && backgroundSectionUpdateTimer <= 0.0f) + if (pendingSectionUpdates.Count > 0 && backgroundSectionUpdateTimer > NetConfig.HullUpdateInterval) { foreach (int pendingSectionUpdate in pendingSectionUpdates) { GameMain.NetworkMember.CreateEntityEvent(this, new BackgroundSectionsEventData(pendingSectionUpdate)); } - backgroundSectionUpdateTimer = NetConfig.HullUpdateInterval; + backgroundSectionUpdateTimer = 0; pendingSectionUpdates.Clear(); } } diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/Client.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/Client.cs index ed9a1efa2..fe720421c 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/Client.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/Client.cs @@ -73,6 +73,9 @@ namespace Barotrauma.Networking characterInfo = value; } } + + public string PendingName; + public NetworkConnection Connection { get; set; } public bool SpectateOnly; diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs index bc9ae28ab..f9085de45 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs @@ -1046,7 +1046,7 @@ namespace Barotrauma.Networking c.LastRecvChatMsgID = NetIdUtils.Clamp(inc.ReadUInt16(), c.LastRecvChatMsgID, c.LastChatMsgQueueID); c.LastRecvClientListUpdate = NetIdUtils.Clamp(inc.ReadUInt16(), c.LastRecvClientListUpdate, LastClientListUpdateID); - TryChangeClientName(c, inc); + ReadClientNameChange(c, inc); c.LastRecvCampaignSave = inc.ReadUInt16(); if (c.LastRecvCampaignSave > 0) @@ -2675,7 +2675,7 @@ namespace Barotrauma.Networking base.AddChatMessage(message); } - private bool TryChangeClientName(Client c, IReadMessage inc) + private bool ReadClientNameChange(Client c, IReadMessage inc) { UInt16 nameId = inc.ReadUInt16(); string newName = inc.ReadString(); @@ -2685,16 +2685,21 @@ namespace Barotrauma.Networking if (c == null || string.IsNullOrEmpty(newName) || !NetIdUtils.IdMoreRecent(nameId, c.NameID)) { return false; } c.NameID = nameId; - newName = Client.SanitizeName(newName); if (newName == c.Name && newJob == c.PreferredJob && newTeam == c.PreferredTeam) { return false; } c.PreferredJob = newJob; c.PreferredTeam = newTeam; + return TryChangeClientName(c, newName); + } + + public bool TryChangeClientName(Client c, string newName) + { + newName = Client.SanitizeName(newName); //update client list even if the name cannot be changed to the one sent by the client, //so the client will be informed what their actual name is LastClientListUpdateID++; - if (newName == c.Name) { return false; } + if (newName == c.Name || string.IsNullOrEmpty(newName)) { return false; } if (IsNameValid(c, newName)) { @@ -2710,6 +2715,7 @@ namespace Barotrauma.Networking } } + private bool IsNameValid(Client c, string newName) { newName = Client.SanitizeName(newName); @@ -3542,6 +3548,10 @@ namespace Barotrauma.Networking { newName = sender.Name; } + else + { + sender.PendingName = newName; + } } int tagCount = message.ReadByte(); diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/RespawnManager.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/RespawnManager.cs index 28d1b91c0..889820327 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/RespawnManager.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/RespawnManager.cs @@ -392,6 +392,14 @@ namespace Barotrauma.Networking bool forceSpawnInMainSub = false; if (!bot && campaign != null) { + //the client has opted to change the name of their new character + //when the character spawns, set the client's name to match + if (clients[i].PendingName == characterInfos[i].Name) + { + GameMain.Server?.TryChangeClientName(clients[i], clients[i].PendingName); + clients[i].PendingName = null; + } + var matchingData = campaign?.GetClientCharacterData(clients[i]); if (matchingData != null) { diff --git a/Barotrauma/BarotraumaServer/WindowsServer.csproj b/Barotrauma/BarotraumaServer/WindowsServer.csproj index f8b909704..1005239b1 100644 --- a/Barotrauma/BarotraumaServer/WindowsServer.csproj +++ b/Barotrauma/BarotraumaServer/WindowsServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.18.6.0 + 0.18.7.0 Copyright © FakeFish 2018-2022 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs index b760a2b2a..bc2005a63 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Animation/Ragdoll.cs @@ -227,9 +227,13 @@ namespace Barotrauma { mainLimb = Limbs.FirstOrDefault(l => IsValid(l)); } + if (mainLimb == null) + { + DebugConsole.ThrowError("Couldn't find a valid main limb. The limb can't be hidden nor be set to ignore collisions!"); + mainLimb = Limbs.FirstOrDefault(); + } } - - bool IsValid(Limb limb) => limb != null && !limb.IsSevered && !limb.IgnoreCollisions && !limb.Hidden; + static bool IsValid(Limb limb) => limb != null && !limb.IsSevered && !limb.IgnoreCollisions && !limb.Hidden; return mainLimb; } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/SpawnAction.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/SpawnAction.cs index 8d17092d1..70f6a7b61 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/SpawnAction.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/EventActions/SpawnAction.cs @@ -49,6 +49,9 @@ namespace Barotrauma [Serialize("", IsPropertySaveable.Yes)] public Identifier SpawnPointTag { get; set; } + [Serialize(CharacterTeamType.FriendlyNPC, IsPropertySaveable.Yes)] + public CharacterTeamType Team { get; protected set; } + [Serialize(false, IsPropertySaveable.Yes, description: "Should we spawn the entity even when no spawn points with matching tags were found?")] public bool RequireSpawnPointTag { get; set; } @@ -119,7 +122,7 @@ namespace Barotrauma { if (newCharacter == null) { return; } newCharacter.HumanPrefab = humanPrefab; - newCharacter.TeamID = CharacterTeamType.FriendlyNPC; + newCharacter.TeamID = Team; newCharacter.EnableDespawn = false; humanPrefab.GiveItems(newCharacter, newCharacter.Submarine); if (LootingIsStealing) diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/ReadyCheck.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/ReadyCheck.cs index a1b6bed04..689569ff4 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/ReadyCheck.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/ReadyCheck.cs @@ -13,12 +13,26 @@ namespace Barotrauma internal partial class ReadyCheck { - private readonly float endTime; - private float time; + private readonly DateTime endTime; + private readonly DateTime startTime; public readonly Dictionary Clients; public bool IsFinished = false; - public ReadyCheck(List clients, float duration = 30) + public ReadyCheck(List clients, DateTime startTime, DateTime endTime) + : this(clients) + { + this.startTime = startTime; + this.endTime = endTime; + } + + public ReadyCheck(List clients, float duration) + : this(clients) + { + startTime = DateTime.Now; + endTime = startTime + new TimeSpan(0, 0, 0, 0, (int)(duration * 1000)); + } + + private ReadyCheck(List clients) { Clients = new Dictionary(); foreach (byte client in clients) @@ -27,24 +41,17 @@ namespace Barotrauma Clients.Add(client, ReadyStatus.Unanswered); } - - time = duration; - endTime = duration; -#if CLIENT - lastSecond = (int) Math.Ceiling(duration); -#endif } partial void EndReadyCheck(); public void Update(float deltaTime) { - if (time > 0) + if (DateTime.Now < endTime) { #if CLIENT UpdateBar(); #endif - time -= deltaTime; return; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Pump.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Pump.cs index bd0e5f161..fc0d44ebb 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Pump.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Pump.cs @@ -1,10 +1,9 @@ -using Barotrauma.Networking; +using Barotrauma.MapCreatures.Behavior; +using Barotrauma.Networking; using Microsoft.Xna.Framework; using System; using System.Globalization; using System.Linq; -using System.Xml.Linq; -using Barotrauma.MapCreatures.Behavior; namespace Barotrauma.Items.Components { @@ -24,7 +23,10 @@ namespace Barotrauma.Items.Components if (value == hijacked) { return; } hijacked = value; #if SERVER - item.CreateServerEvent(this); + if (!Submarine.Unloading) + { + item.CreateServerEvent(this); + } #endif } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Power/Powered.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Power/Powered.cs index 79e8295cf..f0dbf6fcb 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Power/Powered.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Power/Powered.cs @@ -68,7 +68,7 @@ namespace Barotrauma.Items.Components get { return poweredList; } } - public static readonly List ChangedConnections = new List(); + public static readonly HashSet ChangedConnections = new HashSet(); public readonly static Dictionary Grids = new Dictionary(); @@ -158,6 +158,12 @@ namespace Barotrauma.Items.Components } } + /// + /// Essentially Voltage / MinVoltage (= how much of the minimum required voltage has been satisfied), clamped between 0 and 1. + /// Can be used by status effects or sounds to check if the item has enough power to run + /// + public float RelativeVoltage => minVoltage <= 0.0f ? 1.0f : MathHelper.Clamp(Voltage / minVoltage, 0.0f, 1.0f); + public bool PoweredByTinkering { get; set; } [Editable, Serialize(true, IsPropertySaveable.Yes, description: "Can the item be damaged by electomagnetic pulses.")] diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/Connection.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/Connection.cs index 34256fe0c..6d3fbc207 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/Connection.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/Connection.cs @@ -170,6 +170,7 @@ namespace Barotrauma.Items.Components public void SetRecipientsDirty() { recipientsDirty = true; + if (IsPower) { Powered.ChangedConnections.Add(this); } } private void RefreshRecipients() diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Creatures/BallastFloraBehavior.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Creatures/BallastFloraBehavior.cs index ed95cba99..ba2e0b3d3 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Creatures/BallastFloraBehavior.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Creatures/BallastFloraBehavior.cs @@ -399,6 +399,7 @@ namespace Barotrauma.MapCreatures.Behavior new XAttribute("pos", XMLExtensions.Vector2ToString(branch.Position)), new XAttribute("ID", branch.ID), new XAttribute("isroot", branch.IsRoot), + new XAttribute("isrootgrowth", branch.IsRootGrowth), new XAttribute("health", branch.Health.ToString("G", CultureInfo.InvariantCulture)), new XAttribute("maxhealth", branch.MaxHealth.ToString("G", CultureInfo.InvariantCulture)), new XAttribute("sides", (int)branch.Sides), @@ -457,9 +458,16 @@ namespace Barotrauma.MapCreatures.Behavior foreach ((BallastFloraBranch branch, int parentBranchId) in branches) { - if (parentBranchId > -1 && parentBranchId < Branches.Count) + if (parentBranchId > -1) { - branch.ParentBranch = Branches[parentBranchId]; + if (parentBranchId < Branches.Count) + { + branch.ParentBranch = Branches[parentBranchId]; + } + else + { + DebugConsole.AddWarning($"Error while loading ballast flora: parent branch ID {parentBranchId} out of range (total {Branches.Count} branches)"); + } } } @@ -476,6 +484,7 @@ namespace Barotrauma.MapCreatures.Behavior { Vector2 pos = branchElement.GetAttributeVector2("pos", Vector2.Zero); bool isRoot = branchElement.GetAttributeBool("isroot", false); + bool isRootGrowth = branchElement.GetAttributeBool("isrootgrowth", false); int flowerConfig = getInt("flowerconfig"); int leafconfig = getInt("leafconfig"); int id = getInt("ID"); @@ -493,7 +502,8 @@ namespace Barotrauma.MapCreatures.Behavior MaxHealth = maxhealth, Sides = (TileSide) sides, BlockedSides = (TileSide) blockedSides, - IsRoot = isRoot + IsRoot = isRoot, + IsRootGrowth = isRootGrowth }; branches.Add((newBranch, parentBranchId)); @@ -658,11 +668,14 @@ namespace Barotrauma.MapCreatures.Behavior toBeRemoved.Clear(); foreach (BallastFloraBranch branch in Branches) { - if (branch.ParentBranch == null || branch.ParentBranch.DisconnectedFromRoot || branch.ParentBranch.Health <= 0.0f) + if (!branch.IsRoot) { - float parentHealth = branch.ParentBranch == null ? 0.0f : branch.ParentBranch.Health / branch.ParentBranch.MaxHealth; - float speed = MathHelper.Lerp(5.0f, 0.1f, parentHealth); - DamageBranch(branch, speed * speed * deltaTime, AttackType.CutFromRoot); + if (branch.ParentBranch == null || branch.ParentBranch.DisconnectedFromRoot || branch.ParentBranch.Health <= 0.0f) + { + float parentHealth = branch.ParentBranch == null ? 0.0f : branch.ParentBranch.Health / branch.ParentBranch.MaxHealth; + float speed = MathHelper.Lerp(5.0f, 0.1f, parentHealth); + DamageBranch(branch, speed * speed * deltaTime, AttackType.CutFromRoot); + } } if (branch.Health <= 0.0f) { @@ -1197,7 +1210,10 @@ namespace Barotrauma.MapCreatures.Behavior } }); #if SERVER - CreateNetworkMessage(new InfectEventData(item, InfectEventData.InfectState.No, null)); + if (!item.Removed && Parent != null && !Parent.Removed) + { + CreateNetworkMessage(new InfectEventData(item, InfectEventData.InfectState.No, null)); + } #endif } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/LinkedSubmarine.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/LinkedSubmarine.cs index 9e550b39b..5bdabf7cf 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/LinkedSubmarine.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/LinkedSubmarine.cs @@ -215,16 +215,19 @@ namespace Barotrauma saveElement = element }; - if (!string.IsNullOrWhiteSpace(levelSeed) && levelData != null && - levelData.Seed != levelSeed && !linkedSub.purchasedLostShuttles) - { - linkedSub.loadSub = false; - } - else + bool levelMatches = string.IsNullOrWhiteSpace(levelSeed) || levelData == null || levelData.Seed == levelSeed; + + //don't load a sub that was left in this level if we have a submarine switch pending + //to make sure it gets ignored during the submarine switch and item transfer (reloading and saving it during the switch makes it not considered "left behind") + if ((levelMatches || linkedSub.purchasedLostShuttles) && GameMain.GameSession?.Campaign?.PendingSubmarineSwitch == null) { linkedSub.loadSub = true; linkedSub.rect.Location = MathUtils.ToPoint(pos); } + else + { + linkedSub.loadSub = false; + } } #warning TODO: revise @@ -279,14 +282,14 @@ namespace Barotrauma if (worldPos != Vector2.Zero) { if (GameMain.GameSession != null && GameMain.GameSession.MirrorLevel) - { + { worldPos.X = GameMain.GameSession.LevelData.Size.X - worldPos.X; } sub.SetPosition(worldPos); } else { - sub.SetPosition(WorldPosition); + sub.SetPosition(WorldPosition); } DockingPort linkedPort = null; @@ -308,8 +311,17 @@ namespace Barotrauma { linkedPort = (FindEntityByID(originalLinkedToID) as Item)?.GetComponent(); } - if (linkedPort == null) { return; } } + + if (linkedPort == null) + { + if (worldPos == Vector2.Zero) + { + DebugConsole.ThrowError("Something went wrong when loading a linked submarine - the save didn't include either a world position or a linked port for the submarine."); + } + return; + } + originalLinkedPort = linkedPort; ushort originalMyId = childRemap.GetOffsetId(originalMyPortID); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerationParams.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerationParams.cs index 6d75e6916..4c65efaa3 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerationParams.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerationParams.cs @@ -1,11 +1,9 @@ using Barotrauma.Extensions; -using Microsoft.Xna.Framework; using System; using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Xml.Linq; namespace Barotrauma { @@ -98,9 +96,29 @@ namespace Barotrauma [Serialize("", IsPropertySaveable.Yes), Editable] public string ReplaceInRadiation { get; set; } - private readonly Dictionary moduleCounts = new Dictionary(); + public class ModuleCount + { + public Identifier Identifier; + public int Count; + public int Order; - public IReadOnlyDictionary ModuleCounts + public ModuleCount(ContentXElement element) + { + Identifier = element.GetAttributeIdentifier("flag", element.GetAttributeIdentifier("moduletype", "")); + Count = element.GetAttributeInt("count", 0); + Order = element.GetAttributeInt("order", 0); + } + + public ModuleCount(Identifier id, int count) + { + Identifier = id; + Count = count; + } + } + + private readonly List moduleCounts = new List(); + + public IReadOnlyList ModuleCounts { get { return moduleCounts; } } @@ -171,8 +189,7 @@ namespace Barotrauma switch (subElement.Name.ToString().ToLowerInvariant()) { case "modulecount": - Identifier moduleFlag = subElement.GetAttributeIdentifier("flag", subElement.GetAttributeIdentifier("moduletype", "")); - moduleCounts[moduleFlag] = subElement.GetAttributeInt("count", 0); + moduleCounts.Add(new ModuleCount(subElement)); break; case "npcs": var newCollection = new NpcCollection(); @@ -200,7 +217,7 @@ namespace Barotrauma public int GetModuleCount(Identifier moduleFlag) { if (moduleFlag == Identifier.Empty || moduleFlag == "none") { return int.MaxValue; } - return moduleCounts.ContainsKey(moduleFlag) ? moduleCounts[moduleFlag] : 0; + return moduleCounts.FirstOrDefault(m => m.Identifier == moduleFlag)?.Count ?? 0; } public void SetModuleCount(Identifier moduleFlag, int count) @@ -208,11 +225,19 @@ namespace Barotrauma if (moduleFlag == Identifier.Empty || moduleFlag == "none") { return; } if (count <= 0) { - moduleCounts.Remove(moduleFlag); + moduleCounts.RemoveAll(m => m.Identifier == moduleFlag); } else { - moduleCounts[moduleFlag] = count; + var moduleCount = moduleCounts.FirstOrDefault(m => m.Identifier == moduleFlag); + if (moduleCount == null) + { + moduleCounts.Add(new ModuleCount(moduleFlag, count)); + } + else + { + moduleCount.Count = count; + } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs index 1da36a5fb..a0e5ceed6 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Outposts/OutpostGenerator.cs @@ -99,7 +99,7 @@ namespace Barotrauma { //if the module doesn't have the ruin flag or any other flag used in the generation params, don't use it in ruins if (!subInfo.OutpostModuleInfo.ModuleFlags.Contains("ruin".ToIdentifier()) && - !generationParams.ModuleCounts.Any(m => subInfo.OutpostModuleInfo.ModuleFlags.Contains(m.Key))) + !generationParams.ModuleCounts.Any(m => subInfo.OutpostModuleInfo.ModuleFlags.Contains(m.Identifier))) { continue; } @@ -141,16 +141,11 @@ namespace Barotrauma selectedModules.Clear(); //select which module types the outpost should consist of - List pendingModuleFlags; - using (var md5 = MD5.Create()) - { - #warning TODO: cursed - pendingModuleFlags = onlyEntrance - ? generationParams.ModuleCounts - .Keys.OrderBy(k => ToolBox.IdentifierToUint32Hash(k, md5)) - .First().ToEnumerable().ToList() - : SelectModules(outpostModules, generationParams); - } + List pendingModuleFlags = + onlyEntrance ? + generationParams.ModuleCounts.First().Identifier.ToEnumerable().ToList() : + SelectModules(outpostModules, generationParams); + foreach (Identifier flag in pendingModuleFlags) { if (flag == "none") { continue; } @@ -437,31 +432,27 @@ namespace Barotrauma var pendingModuleFlags = new List(); bool availableModulesFound = true; - Identifier initialModuleFlag = generationParams.ModuleCounts.FirstOrDefault().Key; + Identifier initialModuleFlag = generationParams.ModuleCounts.FirstOrDefault().Identifier; pendingModuleFlags.Add(initialModuleFlag); while (pendingModuleFlags.Count < totalModuleCount && availableModulesFound) { availableModulesFound = false; foreach (var moduleFlag in generationParams.ModuleCounts) { - if (pendingModuleFlags.Count(m => m == moduleFlag.Key) >= generationParams.GetModuleCount(moduleFlag.Key)) + if (pendingModuleFlags.Count(m => m == moduleFlag.Identifier) >= generationParams.GetModuleCount(moduleFlag.Identifier)) { continue; } - if (!modules.Any(m => m.OutpostModuleInfo.ModuleFlags.Contains(moduleFlag.Key))) + if (!modules.Any(m => m.OutpostModuleInfo.ModuleFlags.Contains(moduleFlag.Identifier))) { - DebugConsole.ThrowError($"Failed to add a module to the outpost (no modules with the flag \"{moduleFlag.Key}\" found)."); + DebugConsole.ThrowError($"Failed to add a module to the outpost (no modules with the flag \"{moduleFlag.Identifier}\" found)."); continue; } availableModulesFound = true; - pendingModuleFlags.Add(moduleFlag.Key); + pendingModuleFlags.Add(moduleFlag.Identifier); } } - using (MD5 md5 = MD5.Create()) - { - pendingModuleFlags.Sort((i1, i2) => (int)ToolBox.StringToUInt32Hash(i1.Value.ToLowerInvariant(), md5) - (int)ToolBox.StringToUInt32Hash(i2.Value.ToLowerInvariant(), md5)); - } - pendingModuleFlags.Shuffle(Rand.RandSync.ServerAndClient); + pendingModuleFlags.OrderBy(f => generationParams.ModuleCounts.First(m => m.Identifier == f)).ThenBy(f => Rand.Value(Rand.RandSync.ServerAndClient)); while (pendingModuleFlags.Count < totalModuleCount) { //don't place "none" modules at the end because @@ -610,7 +601,7 @@ namespace Barotrauma Identifier flagToPlace = "none".ToIdentifier(); SubmarineInfo nextModule = null; - foreach (Identifier moduleFlag in pendingModuleFlags) + foreach (Identifier moduleFlag in pendingModuleFlags.OrderByDescending(f => currentModule?.Info?.OutpostModuleInfo.AllowAttachToModules.Contains(f) ?? false)) { flagToPlace = moduleFlag; nextModule = GetRandomModule(currentModule?.Info?.OutpostModuleInfo, availableModules, flagToPlace, gapPosition, locationType, allowDifferentLocationType); @@ -1048,6 +1039,17 @@ namespace Barotrauma module.ThisGapPosition == OutpostModuleInfo.GapPosition.Left || module.ThisGapPosition == OutpostModuleInfo.GapPosition.Right; + if (!module.ThisGap.linkedTo.Any()) + { + DebugConsole.ThrowError($"Error during outpost generation: {module.ThisGapPosition} gap in module \"{module.Info.Name}\" was not linked to any hulls."); + continue; + } + if (!module.PreviousGap.linkedTo.Any()) + { + DebugConsole.ThrowError($"Error during outpost generation: {GetOpposingGapPosition(module.ThisGapPosition)} gap in module \"{module.PreviousModule.Info.Name}\" was not linked to any hulls."); + continue; + } + MapEntity leftHull = module.ThisGap.Position.X < module.PreviousGap.Position.X ? module.ThisGap.linkedTo[0] : module.PreviousGap.linkedTo[0]; MapEntity rightHull = module.ThisGap.Position.X > module.PreviousGap.Position.X ? module.ThisGap.linkedTo.Count == 1 ? module.ThisGap.linkedTo[0] : module.ThisGap.linkedTo[1] : diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineInfo.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineInfo.cs index 3d1ca403e..1e37ab37e 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineInfo.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/SubmarineInfo.cs @@ -109,6 +109,8 @@ namespace Barotrauma public bool IsCampaignCompatible => IsPlayer && !HasTag(SubmarineTag.Shuttle) && !HasTag(SubmarineTag.HideInMenus) && SubmarineClass != SubmarineClass.Undefined; public bool IsCampaignCompatibleIgnoreClass => IsPlayer && !HasTag(SubmarineTag.Shuttle) && !HasTag(SubmarineTag.HideInMenus); + public bool AllowPreviewImage => Type == SubmarineType.Player; + public Md5Hash MD5Hash { get @@ -556,7 +558,7 @@ namespace Barotrauma XDocument doc = new XDocument(newElement); doc.Root.Add(new XAttribute("name", Name)); - if (previewImage != null) + if (previewImage != null && AllowPreviewImage) { doc.Root.Add(new XAttribute("previewimage", Convert.ToBase64String(previewImage.ToArray()))); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Serialization/SerializableProperty.cs b/Barotrauma/BarotraumaShared/SharedSource/Serialization/SerializableProperty.cs index 097f1c888..9e3417054 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Serialization/SerializableProperty.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Serialization/SerializableProperty.cs @@ -619,6 +619,11 @@ namespace Barotrauma if (parentObject is Powered powered) { value = powered.Voltage; return true; } } break; + case nameof(Powered.RelativeVoltage): + { + if (parentObject is Powered powered) { value = powered.RelativeVoltage; return true; } + } + break; case nameof(Powered.CurrPowerConsumption): { if (parentObject is Powered powered) { value = powered.CurrPowerConsumption; return true; } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Settings/GameSettings.cs b/Barotrauma/BarotraumaShared/SharedSource/Settings/GameSettings.cs index f510d30da..c95171170 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Settings/GameSettings.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Settings/GameSettings.cs @@ -480,6 +480,8 @@ namespace Barotrauma bool voiceCaptureChanged = currentConfig.Audio.VoiceCaptureDevice != newConfig.Audio.VoiceCaptureDevice; bool textScaleChanged = Math.Abs(currentConfig.Graphics.TextScale - newConfig.Graphics.TextScale) > MathF.Pow(2.0f, -7); + bool hudScaleChanged = !MathUtils.NearlyEqual(currentConfig.Graphics.HUDScale, newConfig.Graphics.HUDScale); + bool setGraphicsMode = resolutionChanged || currentConfig.Graphics.VSync != newConfig.Graphics.VSync || @@ -514,6 +516,10 @@ namespace Barotrauma componentStyle.RefreshSize(); } } + if (hudScaleChanged) + { + HUDLayoutSettings.CreateAreas(); + } GameMain.SoundManager?.ApplySettings(); #endif diff --git a/Barotrauma/BarotraumaShared/SharedSource/Utils/ToolBox.cs b/Barotrauma/BarotraumaShared/SharedSource/Utils/ToolBox.cs index e165d24e7..9922dc37f 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Utils/ToolBox.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Utils/ToolBox.cs @@ -100,13 +100,23 @@ namespace Barotrauma } #endif - if (Path.IsPathRooted(originalFilename)) + string startPath = directory ?? ""; + + string saveFolder = SaveUtil.SaveFolder.Replace('\\', '/'); + if (originalFilename.Replace('\\', '/').StartsWith(saveFolder)) { + //paths that lead to the save folder might have incorrect case, + //mainly if they come from a filelist + startPath = saveFolder.EndsWith('/') ? saveFolder : $"{saveFolder}/"; + filename = startPath; + subDirs = subDirs.Skip(saveFolder.Split('/').Length).ToArray(); + } + else if (Path.IsPathRooted(originalFilename)) + { + #warning TODO: incorrect assumption or...? Figure out what this was actually supposed to fix, if anything. Might've been a perf thing. return originalFilename; //assume that rooted paths have correct case since these are generated by the game } - string startPath = directory ?? ""; - for (int i = 0; i < subDirs.Length; i++) { if (i == subDirs.Length - 1 && string.IsNullOrEmpty(subDirs[i])) diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index 3d5d91ced..0a155659b 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,3 +1,41 @@ +--------------------------------------------------------------------------------------------------------- +v0.18.7.0 +--------------------------------------------------------------------------------------------------------- + +Unstable only: +- Reduced depth charge scale to fit in loader/racks better. +- Fixed ballast flora dying by itself client-side when transitioning to a new level. +- Disallow laying in vertically flipped normal bunks. +- Fixed broken door sprite stretching on the wrong axis when cutting a door. +- Fixed AI orders not working in multiplayer. +- Fixed tutorial characters starting with more items than they should. +- Fixed chat box closing when clicking any chat box elements after opening it with the keybind. +- Fixed submarine selection resetting when changing server settings in the campaign setup menu. +- Fixed "enable" and "disable" being wrong way around in the mod tab's context menus. +- Fixed sub editor always saving subs from a local mod in the root of that mod's folder instead of the actual location of that sub file. +- Fixed decoys not being containable in wrecked coilgun ammo shelves. +- Fixes and improvements to the new beacon stations and the enemies inside them. +- Fixed an issue during submarine switching when a drone / linked sub has been left behind (Regalis11/Barotrauma#9172): When you were switching back to a submarine whose drone you'd left behind, in the same level where you left the drone, the drone would get loaded and resaved during the item transfer, which caused it to no longer be considered "left behind". It also removed the drone's position from the save, and since it was not docked to anything either, positioning it failed at the beginning of the next round. + +Changes: +- Adding preview images to wrecks, beacon stations, outposts or enemy subs isn't allowed in the sub editor (unnecessarily bloats up their file size, as the preview images aren't visible anywhere). + +Fixes: +- Fixed server not refreshing the power grid when a client disconnects and reconnects a power wire. +- Fixed hull updates not being sent if the water/oxygen/fire in the hull doesn't change server-side, preventing the hull's status from getting corrected if a client somehow ends up out of sync. +- Fixed keybinds shown in the controls tab not refreshing when resetting the binds. +- Hopefully fixed colonies sometimes not including some modules (most often the armory module). +- Fixed ready checks sometimes ending at a slightly different time client-side compared to the server, allowing you to answer the prompt even though the time to answer already ended server-side. +- Fixed large terminal welcome messages going slightly outside the bounds of the listbox. +- Fixed overlapping in the tab menu's mission tab when there's more than one mission selected. +- Fixed fabricators and deconstructors playing the sounds even if they're out of power. +- Fixed occasional "hash mismatch for downloaded mod" errors on Linux. +- Fixed clients occasionally spawning as the old character after they've opted to create a new one. Only happened if the client hadn't died and was still controlling the old character at the end of the round. +- When a client creates a character with a new name, the client's name is changed to match it after they spawn as that character. +- Fixed enabled mods getting disabled when updating them in the mods menu. +- Fixed a rounding error in Sprite.DrawTiled that sometimes caused an extra 1-pixel line on some scaled and flipped structures (e.g. certain wall pieces scaled to 0.6). +- Fixed Orca 2 still using the old chaingun charge time. + --------------------------------------------------------------------------------------------------------- v0.18.6.0 ---------------------------------------------------------------------------------------------------------