From b99e66650eec3ddbe36aaab71a5f6e88c01d4b6d Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Fri, 16 Dec 2022 19:32:28 +0200 Subject: [PATCH 1/3] Update bug_report.yml --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 70878fff6..82c028105 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -53,7 +53,7 @@ body: description: Which version of the game did the bug happen in? You can see the current version number in the bottom left corner of your screen in the main menu. options: - 0.20.15.0 - - 0.20.15.0 (Unstable) + - 0.21.0.0 (Unstable) - Faction/endgame test branch - Other validations: From 9466d2245b93c44d03235b69140fe9e04ee4fbdc Mon Sep 17 00:00:00 2001 From: Joonas Rikkonen Date: Tue, 20 Dec 2022 17:02:44 +0200 Subject: [PATCH 2/3] Update bug_report.yml --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 82c028105..81e71e1ae 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -52,7 +52,7 @@ body: label: Version description: Which version of the game did the bug happen in? You can see the current version number in the bottom left corner of your screen in the main menu. options: - - 0.20.15.0 + - 0.20.16.1 - 0.21.0.0 (Unstable) - Faction/endgame test branch - Other From b8fa67714818cc3b1f9bebb8c4e736c0db107861 Mon Sep 17 00:00:00 2001 From: Regalis11 Date: Tue, 20 Dec 2022 17:05:53 +0200 Subject: [PATCH 3/3] Build 0.20.16.1 --- .../ClientSource/Screens/MainMenuScreen.cs | 55 ++++++--- .../ClientSource/Settings/SettingsMenu.cs | 2 + .../ClientSource/Steam/WorkshopMenu/BBCode.cs | 35 +++++- .../WorkshopMenu/Mutable/InstalledTab.cs | 2 +- .../Steam/WorkshopMenu/Mutable/ItemList.cs | 2 +- .../BarotraumaClient/LinuxClient.csproj | 2 +- Barotrauma/BarotraumaClient/MacClient.csproj | 2 +- .../BarotraumaClient/WindowsClient.csproj | 2 +- .../BarotraumaServer/LinuxServer.csproj | 2 +- Barotrauma/BarotraumaServer/MacServer.csproj | 2 +- .../Items/Components/Projectile.cs | 2 +- .../BarotraumaServer/WindowsServer.csproj | 2 +- .../Abilities/CharacterAbilityModifyStat.cs | 5 + .../BarotraumaShared/SharedSource/Enums.cs | 2 +- .../Items/Components/ElectricalDischarger.cs | 3 +- .../Items/Components/Machines/Reactor.cs | 2 +- .../Items/Components/Projectile.cs | 8 +- .../SharedSource/Steam/SteamManager.cs | 9 -- .../SharedSource/Steam/Workshop.cs | 111 +++++++++++++++--- .../SharedSource/Utils/Result.cs | 4 +- Barotrauma/BarotraumaShared/changelog.txt | 53 ++------- .../Facepunch.Steamworks/Structs/UgcItem.cs | 16 +++ 22 files changed, 217 insertions(+), 106 deletions(-) diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/MainMenuScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/MainMenuScreen.cs index 799ea9c56..93e9a68ff 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/MainMenuScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/MainMenuScreen.cs @@ -51,9 +51,8 @@ namespace Barotrauma private readonly GUIFrame modsButtonContainer; private readonly GUIButton modsButton, modUpdatesButton; - private Task> modUpdateTask; - private float modUpdateTimer = 0.0f; - private const float ModUpdateInterval = 60.0f; + private (DateTime WhenToRefresh, int Count) modUpdateStatus = (DateTime.Now, 0); + private static readonly TimeSpan ModUpdateInterval = TimeSpan.FromSeconds(60.0f); private readonly GameMain game; @@ -736,8 +735,7 @@ namespace Barotrauma public void ResetModUpdateButton() { - modUpdateTask = null; - modUpdateTimer = 0; + modUpdateStatus = (DateTime.Now, 0); modUpdatesButton.Visible = false; } @@ -958,15 +956,42 @@ namespace Barotrauma } } + private void UpdateOutOfDateWorkshopItemCount() + { + if (DateTime.Now < modUpdateStatus.WhenToRefresh) { return; } + if (!SteamManager.IsInitialized) { return; } + + var installedPackages = ContentPackageManager.WorkshopPackages; + + var ids = SteamManager.Workshop.GetSubscribedItemIds() + .Select(id => id.Value) + .Union(installedPackages + .Select(pkg => pkg.UgcId) + .NotNone() + .OfType() + .Select(id => id.Value)); + var count = ids + // Deliberately construct Steamworks.Ugc.Item directly + // to not immediately generate a Workshop data request + .Select(id => new Steamworks.Ugc.Item(id)) + .Count(item => + installedPackages.FirstOrDefault(p + => p.UgcId.TryUnwrap(out SteamWorkshopId id) && id.Value == item.Id) + is { } pkg + // Checking that this item is downloading, waiting to be downloaded + // or is newer than the currently installed copy should be good enough, + // and should still not make a Workshop data request + && (item.IsDownloading + || item.IsDownloadPending + || (item.InstallTime.TryGetValue(out var workshopInstallTime) + && pkg.InstallTime.TryUnwrap(out var localInstallTime) + && localInstallTime < workshopInstallTime))); + + modUpdateStatus = (DateTime.Now + ModUpdateInterval, count); + } + public override void Update(double deltaTime) { - modUpdateTimer -= (float)deltaTime; - if (modUpdateTimer <= 0.0f && modUpdateTask is not { IsCompleted: false }) - { - modUpdateTask = BulkDownloader.GetItemsThatNeedUpdating(); - modUpdateTimer = ModUpdateInterval; - } - #if DEBUG hostServerButton.Enabled = true; #else @@ -976,10 +1001,8 @@ namespace Barotrauma } #endif - if (modUpdateTask is { IsCompletedSuccessfully: true }) - { - modUpdatesButton.Visible = modUpdateTask.Result.Count > 0; - } + UpdateOutOfDateWorkshopItemCount(); + modUpdatesButton.Visible = modUpdateStatus.Count > 0; if (modUpdatesButton.Visible) { diff --git a/Barotrauma/BarotraumaClient/ClientSource/Settings/SettingsMenu.cs b/Barotrauma/BarotraumaClient/ClientSource/Settings/SettingsMenu.cs index 594e36ad4..3214a3ff5 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Settings/SettingsMenu.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Settings/SettingsMenu.cs @@ -779,6 +779,8 @@ namespace Barotrauma workshopMenu = Screen.Selected is MainMenuScreen ? (WorkshopMenu)new MutableWorkshopMenu(content) : (WorkshopMenu)new ImmutableWorkshopMenu(content); + + GameMain.MainMenuScreen.ResetModUpdateButton(); } private void CreateBottomButtons() diff --git a/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/BBCode.cs b/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/BBCode.cs index 72a4861b5..08c6ace39 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/BBCode.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/BBCode.cs @@ -45,18 +45,26 @@ namespace Barotrauma.Steam protected static readonly Regex bbTagRegex = new Regex(@"\[(.+?)\]", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); - protected static GUICustomComponent CreateBBCodeElement(string bbCode, GUIListBox container) + protected static void CreateBBCodeElement(Steamworks.Ugc.Item workshopItem, GUIListBox container) { Point cachedContainerSize = Point.Zero; List bbWords = new List(); Stack tagStack = new Stack(); - void recalculate() + string bbCode = ""; + + void forceReset() { - if (cachedContainerSize == container.Content.RectTransform.NonScaledSize) { return; } + bbWords.Clear(); + cachedContainerSize = Point.Zero; + } + + void recalculate(GUICustomComponent component) + { + if (cachedContainerSize == component.RectTransform.NonScaledSize) { return; } bbWords.Clear(); - cachedContainerSize = container.Content.RectTransform.NonScaledSize; + cachedContainerSize = component.RectTransform.NonScaledSize; var matches = new Stack(bbTagRegex.Matches(bbCode).Reverse()); Match? nextTag = null; @@ -133,11 +141,14 @@ namespace Barotrauma.Steam { bbWords.Add(new BBWord(finalWord, currTagType)); } + + container.RecalculateChildren(); + container.UpdateScrollBarSize(); } void draw(SpriteBatch spriteBatch, GUICustomComponent component) { - recalculate(); + recalculate(component); Vector2 currPos = Vector2.Zero; Vector2 rectPos = component.Rect.Location.ToVector2(); for (int i = 0; i < bbWords.Count; i++) @@ -180,7 +191,19 @@ namespace Barotrauma.Steam = component.RectTransform.NonScaledSize.ToVector2() / component.Parent.Rect.Size.ToVector2(); } - return new GUICustomComponent(new RectTransform(Vector2.One, container.Content.RectTransform), + TaskPool.Add( + $"GetWorkshopItemLongDescriptionFor{workshopItem.Id.Value}", + SteamManager.Workshop.GetItemAsap(workshopItem.Id.Value, withLongDescription: true), + t => + { + if (!t.TryGetResult(out Steamworks.Ugc.Item? workshopItemWithDescription)) { return; } + + bbCode = workshopItemWithDescription?.Description ?? ""; + forceReset(); + }); + + new GUICustomComponent( + new RectTransform(Vector2.One, container.Content.RectTransform), onDraw: draw); } } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/InstalledTab.cs b/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/InstalledTab.cs index 4331f34bb..b8688c2f8 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/InstalledTab.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/InstalledTab.cs @@ -34,7 +34,7 @@ namespace Barotrauma.Steam if (numSubscribedMods == memSubscribedModCount) { return; } memSubscribedModCount = numSubscribedMods; - var subscribedIds = SteamManager.GetSubscribedItems().ToHashSet(); + var subscribedIds = SteamManager.Workshop.GetSubscribedItemIds(); var installedIds = ContentPackageManager.WorkshopPackages .Select(p => p.UgcId) .NotNone() diff --git a/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/ItemList.cs b/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/ItemList.cs index 62e930476..415bda37b 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/ItemList.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/ItemList.cs @@ -773,7 +773,7 @@ namespace Barotrauma.Steam #endregion var descriptionListBox = new GUIListBox(new RectTransform((1.0f, 0.38f), verticalLayout.RectTransform)); - CreateBBCodeElement(workshopItem.Description, descriptionListBox); + CreateBBCodeElement(workshopItem, descriptionListBox); var showInSteamContainer = new GUIFrame(new RectTransform((1.0f, 0.05f), verticalLayout.RectTransform), style: null); diff --git a/Barotrauma/BarotraumaClient/LinuxClient.csproj b/Barotrauma/BarotraumaClient/LinuxClient.csproj index b2401ad11..bda6bf5ac 100644 --- a/Barotrauma/BarotraumaClient/LinuxClient.csproj +++ b/Barotrauma/BarotraumaClient/LinuxClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.20.15.0 + 0.20.16.1 Copyright © FakeFish 2018-2022 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/MacClient.csproj b/Barotrauma/BarotraumaClient/MacClient.csproj index 5ec2fca2c..23448ee31 100644 --- a/Barotrauma/BarotraumaClient/MacClient.csproj +++ b/Barotrauma/BarotraumaClient/MacClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.20.15.0 + 0.20.16.1 Copyright © FakeFish 2018-2022 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/WindowsClient.csproj b/Barotrauma/BarotraumaClient/WindowsClient.csproj index 7e1afaeca..9bcc274e7 100644 --- a/Barotrauma/BarotraumaClient/WindowsClient.csproj +++ b/Barotrauma/BarotraumaClient/WindowsClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.20.15.0 + 0.20.16.1 Copyright © FakeFish 2018-2022 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaServer/LinuxServer.csproj b/Barotrauma/BarotraumaServer/LinuxServer.csproj index 81904c7cd..618ae1641 100644 --- a/Barotrauma/BarotraumaServer/LinuxServer.csproj +++ b/Barotrauma/BarotraumaServer/LinuxServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.20.15.0 + 0.20.16.1 Copyright © FakeFish 2018-2022 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/MacServer.csproj b/Barotrauma/BarotraumaServer/MacServer.csproj index 474f98777..e66c9475e 100644 --- a/Barotrauma/BarotraumaServer/MacServer.csproj +++ b/Barotrauma/BarotraumaServer/MacServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.20.15.0 + 0.20.16.1 Copyright © FakeFish 2018-2022 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/ServerSource/Items/Components/Projectile.cs b/Barotrauma/BarotraumaServer/ServerSource/Items/Components/Projectile.cs index 60cc5c609..de8517914 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Items/Components/Projectile.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Items/Components/Projectile.cs @@ -28,7 +28,7 @@ namespace Barotrauma.Items.Components msg.WriteBoolean(launch); if (launch) { - msg.WriteUInt16(User.ID); + msg.WriteUInt16(User?.ID ?? Entity.NullEntityID); msg.WriteSingle(launchPos.X); msg.WriteSingle(launchPos.Y); msg.WriteSingle(launchRot); diff --git a/Barotrauma/BarotraumaServer/WindowsServer.csproj b/Barotrauma/BarotraumaServer/WindowsServer.csproj index 8539178dd..1313a7ecd 100644 --- a/Barotrauma/BarotraumaServer/WindowsServer.csproj +++ b/Barotrauma/BarotraumaServer/WindowsServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.20.15.0 + 0.20.16.1 Copyright © FakeFish 2018-2022 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityModifyStat.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityModifyStat.cs index a1f69c328..26a1d5620 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityModifyStat.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Talents/Abilities/CharacterAbilityModifyStat.cs @@ -13,6 +13,11 @@ value = abilityElement.GetAttributeFloat("value", 0f); } + public override void InitializeAbility(bool addingFirstTime) + { + VerifyState(conditionsMatched: true, timeSinceLastUpdate: 0.0f); + } + protected override void VerifyState(bool conditionsMatched, float timeSinceLastUpdate) { if (conditionsMatched != lastState) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Enums.cs b/Barotrauma/BarotraumaShared/SharedSource/Enums.cs index baa0aecd3..8a9049030 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Enums.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Enums.cs @@ -168,7 +168,7 @@ namespace Barotrauma PumpSpeed, PumpMaxFlow, ReactorMaxOutput, - ReactorFuelEfficiency, + ReactorFuelConsumption, DeconstructorSpeed, FabricationSpeed } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ElectricalDischarger.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ElectricalDischarger.cs index 64db689bd..ff4f8b21b 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ElectricalDischarger.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/ElectricalDischarger.cs @@ -366,7 +366,6 @@ namespace Barotrauma.Items.Components for (int i = 0; i < entitiesInRange.Count; i++) { float dist = float.MaxValue; - if (entitiesInRange[i] is Structure structure) { if (structure.IsHorizontal) @@ -388,7 +387,7 @@ namespace Barotrauma.Items.Components } else if (entitiesInRange[i] is Character character) { - dist = MathUtils.LineSegmentToPointDistanceSquared(currPos, nodes[parentNodeIndex].WorldPosition, character.WorldPosition); + dist = MathF.Sqrt(MathUtils.LineSegmentToPointDistanceSquared(currPos, nodes[parentNodeIndex].WorldPosition, character.WorldPosition)); } if (dist < closestDist) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Reactor.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Reactor.cs index d19f9d7dd..cdf2c9298 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Reactor.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Reactor.cs @@ -874,6 +874,6 @@ namespace Barotrauma.Items.Components } private float GetMaxOutput() => item.StatManager.GetAdjustedValue(ItemTalentStats.ReactorMaxOutput, MaxPowerOutput); - private float GetFuelConsumption() => item.StatManager.GetAdjustedValue(ItemTalentStats.ReactorFuelEfficiency, fuelConsumptionRate); + private float GetFuelConsumption() => item.StatManager.GetAdjustedValue(ItemTalentStats.ReactorFuelConsumption, fuelConsumptionRate); } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs index d31b52edb..aecb9a670 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Projectile.cs @@ -775,7 +775,13 @@ namespace Barotrauma.Items.Components else if (target.Body.UserData is Item item) { if (item.Condition <= 0.0f) { return false; } - if (!item.Prefab.DamagedByProjectiles) { return false; } + if (!item.Prefab.DamagedByProjectiles) + { + if (item.GetComponent() == null) + { + return false; + } + } } else if (target.Body.UserData is Holdable { CanPush: false }) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Steam/SteamManager.cs b/Barotrauma/BarotraumaShared/SharedSource/Steam/SteamManager.cs index d9dd7a1eb..0cd9799f9 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Steam/SteamManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Steam/SteamManager.cs @@ -85,15 +85,6 @@ namespace Barotrauma.Steam return Steamworks.SteamUGC.NumSubscribedItems; } - public static PublishedFileId[] GetSubscribedItems() - { - if (!IsInitialized || !Steamworks.SteamClient.IsValid) - { - return Array.Empty(); - } - return Steamworks.SteamUGC.GetSubscribedItems(); - } - public static bool UnlockAchievement(string achievementIdentifier) => UnlockAchievement(achievementIdentifier.ToIdentifier()); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Steam/Workshop.cs b/Barotrauma/BarotraumaShared/SharedSource/Steam/Workshop.cs index c9cde9d90..e04405ea5 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Steam/Workshop.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Steam/Workshop.cs @@ -1,26 +1,20 @@ #nullable enable using Barotrauma.IO; using System; -using System.Collections.Concurrent; using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml.Linq; using Barotrauma.Extensions; -using Steamworks.Data; using WorkshopItemSet = System.Collections.Generic.ISet; namespace Barotrauma.Steam { static partial class SteamManager { - public const string WorkshopItemPreviewImageFolder = "Workshop"; - public const string PreviewImageName = "PreviewImage.png"; - public const string DefaultPreviewImagePath = "Content/DefaultWorkshopPreviewImage.png"; - public static bool TryExtractSteamWorkshopId(this ContentPackage contentPackage, [NotNullWhen(true)]out SteamWorkshopId? workshopId) { workshopId = null; @@ -47,16 +41,22 @@ namespace Barotrauma.Steam private static async Task GetWorkshopItems(Steamworks.Ugc.Query query, int? maxPages = null) { if (!IsInitialized) { return new HashSet(); } - + await Task.Yield(); - query = query.WithKeyValueTags(true).WithLongDescription(true); var set = new HashSet(ItemEqualityComparer.Instance); int prevSize = 0; - for (int i = 1; maxPages is null || i <= maxPages; i++) + for (int i = 1; i <= (maxPages ?? int.MaxValue); i++) { Steamworks.Ugc.ResultPage? page = await query.GetPageAsync(i); - if (page is null || !page.Value.Entries.Any()) { break; } - set.UnionWith(page.Value.Entries); + if (page is not { Entries: var entries }) { break; } + + // This queries the results on the i-th page and stores them, + // using page.Entries directly would result in two GetQueryUGCResult calls + entries = entries.ToArray(); + + if (entries.None()) { break; } + + set.UnionWith(entries); if (set.Count == prevSize) { break; } prevSize = set.Count; @@ -66,10 +66,17 @@ namespace Barotrauma.Steam // which can happen on items that are not visible to the currently // logged in player (i.e. private & friends-only items) set.RemoveWhere(it => it.ConsumerApp != AppID); - + return set; } + public static ImmutableHashSet GetSubscribedItemIds() + { + return IsInitialized + ? Steamworks.SteamUGC.GetSubscribedItems().ToImmutableHashSet() + : ImmutableHashSet.Empty; + } + public static async Task GetAllSubscribedItems() { if (!IsInitialized) { return new HashSet(); } @@ -98,14 +105,86 @@ namespace Barotrauma.Steam .WhereUserPublished()); } - public static async Task GetItem(UInt64 itemId) + private static class SingleItemRequestPool + { + private static readonly object mutex = new(); + private static readonly TimeSpan delayAfterNewRequest = TimeSpan.FromSeconds(0.5); + private static readonly HashSet ids = new(); + + private static Task? currentBatch = null; + + private static async Task PrepareNewBatch() + { + // Wait for a bunch of requests to be made + await Task.Delay(delayAfterNewRequest); + + Task queryTask; + lock (mutex) + { + DebugConsole.Log( + $"{nameof(SteamManager)}.{nameof(Workshop)}.{nameof(SingleItemRequestPool)}: " + + $"Running batch of {ids.Count} requests"); + + queryTask = GetWorkshopItems( + Steamworks.Ugc.Query.All + .WithFileId( + ids + .Select(id => (Steamworks.Data.PublishedFileId)id) + .ToArray())); + ids.Clear(); + + // Immediately clear the current batch so the next request starts a new one + currentBatch = null; + } + + return await queryTask; + } + + public static async Task MakeRequest(UInt64 id) + { + Task ourTask; + lock (mutex) + { + ids.Add(id); + if (currentBatch is not { IsCompleted: false }) + { + // There is no currently pending batch, start a new one + currentBatch = Task.Run(PrepareNewBatch); + } + ourTask = currentBatch; + } + + var items = await ourTask; + var result = items.FirstOrNull(it => it.Id == id); + return result; + } + } + + /// + /// Fetches a Workshop item's metadata. This is batched to minimize Steamworks API calls. + /// The description of the returned item is truncated to save bandwidth. + /// + /// Workshop Item ID + public static Task GetItem(UInt64 itemId) + => SingleItemRequestPool.MakeRequest(itemId); + + /// + /// Fetches a Workshop item's metadata in its own API call instead of batching. + /// This minimizes delay but needs to be used with caution to prevent rate limiting. + /// + /// Workshop Item ID + /// + /// If true, ask for the item's entire description, otherwise it'll be truncated. + /// + public static async Task GetItemAsap(UInt64 itemId, bool withLongDescription = false) { if (!IsInitialized) { return null; } var items = await GetWorkshopItems( Steamworks.Ugc.Query.All - .WithFileId(itemId)); - return items.Any() ? items.First() : (Steamworks.Ugc.Item?)null; + .WithFileId(itemId) + .WithLongDescription(withLongDescription)); + return items.Any() ? items.First() : null; } public static async Task ForceRedownload(UInt64 itemId) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Utils/Result.cs b/Barotrauma/BarotraumaShared/SharedSource/Utils/Result.cs index d6cc6a92f..20e5f3290 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Utils/Result.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Utils/Result.cs @@ -11,10 +11,10 @@ namespace Barotrauma public abstract bool IsSuccess { get; } public bool IsFailure => !IsSuccess; - public static Success Success(T value) + public static Result Success(T value) => new Success(value); - public static Failure Failure(TError error) + public static Result Failure(TError error) => new Failure(error); public abstract bool TryUnwrapSuccess([MaybeNullWhen(returnValue: false)] out T value); diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index 64c1e2aa1..51a641e51 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,53 +1,20 @@ - --------------------------------------------------------------------------------------------------------- -v0.19.14.0 +v0.20.16.1 --------------------------------------------------------------------------------------------------------- -- Fixed submarine upgrades getting clamped to the maximum of that upgrade between rounds, disregarding class/tier bonuses. +- Fixed console errors when firing a Flak Cannon using spreader ammo in multiplayer. --------------------------------------------------------------------------------------------------------- -v0.19.13.0 +v0.20.16.0 --------------------------------------------------------------------------------------------------------- -- Fixed "failed to find the end of the bit field after 100 reads" error when trying to join a server that has a large number of mods enabled. -- Fixed "Tandem Fire" talent causing a crash due to the changes in the previous version. - ---------------------------------------------------------------------------------------------------------- -v0.19.12.0 ---------------------------------------------------------------------------------------------------------- - -- Fixed submarine upgrades getting lost if you switch to a lower-tier sub that can't have as many levels of upgrades as the current sub, and then back again. -- Fixed some monster events not being as common/uncommon as intended. In more technical terms (which may be of interest to modders): the commonness defined as an attribute of an EventSet did nothing, making the event default to a commonness of 1. The commonnesses defined for specific level types worked correctly. -- Fixed clients getting stuck in a non-functional lobby if they happen to disconnect or get kicked back to the lobby at a specific point when loading a new round. -- Fixed large turret hardpoint origin being off, causing turrets installed on a large hardpoint to be misaligned. -- Attempt to fix crashing when disconnecting from the server you're hosting. -- Fixed Ctrl+Shift+S shortcut (quicksave) not working in the sub editor. -- Fixed toolbelts and storage containers in old subs going inside toolbelts. -- Fixed submarine tier resetting to default when reopening the sub editor's save dialog. -- Fixed sub editor not taking filename case into account when saving an existing sub: if you'd try to save the file with a different filename case, it'd ask about overwriting the existing sub, but save it as a new file even if you opt to overwrite. -- Fixes to Herja room names (use Engineering, Gunnery compartment, etc. labels), add camera to the front, with a periscope for the captain. -- Fixed non-purchaseable talent items not being available as extra cargo. -- Sorted extra cargo alphabetically + added a filter box. -- Fixed taking items that spawned inside another item (e.g. tanks in a diving mask) from NPCs spawned by an event not counting as stealing. -- Fixed characters falling off ladders when using aimable tools. -- Fixed money gain/lose popups no longer showing in the campaign. -- Fixed inability to manage the campaign if there's no-one with permissions alive. Previously we allowed anyone to manage the campaign if there's no-one with permissions present in the server, but that's not enough, because the players with permissions can't end the round if they're dead. Now if there's no-one with permissions alive, anyone is allowed to manage the campaign. -- If Select and Deselect have been bound to the same key, the deselect input is ignored when interacting with another item than the selected one. Prevents e.g. falling off ladders when trying to open a hatch when both Select and Deselect have been bound to E. -- Made it possible to enter a hostname (e.g. someserver.com) in the direct join prompt. -- Adjusted the size of the submarine list elements in the server lobby to reduce the amount of empty space on large resolutions. -- Fixed event texts for the "scan ruin" mission being in an incorrect language. -- Attachable items cannot be attached inside walls. -- Fixed distance at which you can attach items being slightly longer than the interact distance, making it possible to attach items out of reach. -- Fixed inability to turn when you're dual wielding melee weapons and attacking continuously. -- Fixed inability to cancel deconstruction if there's non-deconstructible items in the queue. -- Fixed local copy of a mod you're publishing not using the version number you've entered in the publish menu. -- Fixed crashing when trying to open the tab menu's character tab with a character who has no personality trait (may happen e.g. if you use a mod that adds custom personality traits and try to play that save without the mod). -- Fixed sourcerect issue in alien generator + decorative sprite not disappearing when the fuel rod is taken out. -- Fixed corrupted mods causing a nullref exception when autodetecting required mods in the sub editor. -- Fixed minerals not disappearing from mineral scanner if they get detached by something else than a character picking them up (e.g. by the destructible ice wall they're on breaking). -- Fixed event-specific metal crate deconstructing to steel. -- Fixed inability to join servers that have enabled multiple mods with identical content. -- Fixed tandem fire not working if there's a character between you and the other character on a periscope. +- Fixed non-hitscan projectiles going through doors. +- Fixed electrical discharge coils hitting characters very unreliably, unless the character happens to be right next to a wall. +- Fixed makeshift shelves being containable in crates and cabinets, allowing for infinite recursive storage space. +- Fixed the effects of the "Grid Maintainer" and "Egghead" talents. +- Fixed incorrect "I Am That Guy" description (it gives a flat 20 skill bonus, not 20%). +- Fixed "Cruisin'" talent increasing fuel consumption by 10% instead of decreasing it by 20%. +- Optimized Steam Workshop queries done by the game (less bandwidth usage and stress on Steam's servers). --------------------------------------------------------------------------------------------------------- v0.20.15.0 diff --git a/Libraries/Facepunch.Steamworks/Structs/UgcItem.cs b/Libraries/Facepunch.Steamworks/Structs/UgcItem.cs index 6eb0a9776..7a69e3819 100644 --- a/Libraries/Facepunch.Steamworks/Structs/UgcItem.cs +++ b/Libraries/Facepunch.Steamworks/Structs/UgcItem.cs @@ -192,6 +192,22 @@ namespace Steamworks.Ugc } } + /// + /// If installed, the time and date of installation + /// + public DateTime? InstallTime + { + get + { + ulong size = 0; + uint ts = 0; + if ( !SteamUGC.Internal.GetItemInstallInfo( Id, ref size, out _, ref ts ) ) + return null; + + return Epoch.ToDateTime(ts); + } + } + /// /// File size as returned by Steamworks, /// no download/install required