Build 0.20.16.1

This commit is contained in:
Regalis11
2022-12-20 17:05:53 +02:00
parent 9466d2245b
commit b8fa677148
22 changed files with 217 additions and 106 deletions

View File

@@ -51,9 +51,8 @@ namespace Barotrauma
private readonly GUIFrame modsButtonContainer;
private readonly GUIButton modsButton, modUpdatesButton;
private Task<IReadOnlyList<Steamworks.Ugc.Item>> 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<SteamWorkshopId>()
.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)
{

View File

@@ -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()

View File

@@ -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<BBWord> bbWords = new List<BBWord>();
Stack<BBWord.TagType> tagStack = new Stack<BBWord.TagType>();
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<Match>(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);
}
}

View File

@@ -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()

View File

@@ -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);

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>0.20.15.0</Version>
<Version>0.20.16.1</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>0.20.15.0</Version>
<Version>0.20.16.1</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>0.20.15.0</Version>
<Version>0.20.16.1</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>0.20.15.0</Version>
<Version>0.20.16.1</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>0.20.15.0</Version>
<Version>0.20.16.1</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>

View File

@@ -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);

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>0.20.15.0</Version>
<Version>0.20.16.1</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>

View File

@@ -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)

View File

@@ -168,7 +168,7 @@ namespace Barotrauma
PumpSpeed,
PumpMaxFlow,
ReactorMaxOutput,
ReactorFuelEfficiency,
ReactorFuelConsumption,
DeconstructorSpeed,
FabricationSpeed
}

View File

@@ -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)

View File

@@ -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);
}
}

View File

@@ -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<Door>() == null)
{
return false;
}
}
}
else if (target.Body.UserData is Holdable { CanPush: false })
{

View File

@@ -85,15 +85,6 @@ namespace Barotrauma.Steam
return Steamworks.SteamUGC.NumSubscribedItems;
}
public static PublishedFileId[] GetSubscribedItems()
{
if (!IsInitialized || !Steamworks.SteamClient.IsValid)
{
return Array.Empty<PublishedFileId>();
}
return Steamworks.SteamUGC.GetSubscribedItems();
}
public static bool UnlockAchievement(string achievementIdentifier) =>
UnlockAchievement(achievementIdentifier.ToIdentifier());

View File

@@ -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<Steamworks.Ugc.Item>;
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<WorkshopItemSet> GetWorkshopItems(Steamworks.Ugc.Query query, int? maxPages = null)
{
if (!IsInitialized) { return new HashSet<Steamworks.Ugc.Item>(); }
await Task.Yield();
query = query.WithKeyValueTags(true).WithLongDescription(true);
var set = new HashSet<Steamworks.Ugc.Item>(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<Steamworks.Data.PublishedFileId> GetSubscribedItemIds()
{
return IsInitialized
? Steamworks.SteamUGC.GetSubscribedItems().ToImmutableHashSet()
: ImmutableHashSet<Steamworks.Data.PublishedFileId>.Empty;
}
public static async Task<WorkshopItemSet> GetAllSubscribedItems()
{
if (!IsInitialized) { return new HashSet<Steamworks.Ugc.Item>(); }
@@ -98,14 +105,86 @@ namespace Barotrauma.Steam
.WhereUserPublished());
}
public static async Task<Steamworks.Ugc.Item?> 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<UInt64> ids = new();
private static Task<WorkshopItemSet>? currentBatch = null;
private static async Task<WorkshopItemSet> PrepareNewBatch()
{
// Wait for a bunch of requests to be made
await Task.Delay(delayAfterNewRequest);
Task<WorkshopItemSet> 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<Steamworks.Ugc.Item?> MakeRequest(UInt64 id)
{
Task<WorkshopItemSet> 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;
}
}
/// <summary>
/// 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.
/// </summary>
/// <param name="itemId">Workshop Item ID</param>
public static Task<Steamworks.Ugc.Item?> GetItem(UInt64 itemId)
=> SingleItemRequestPool.MakeRequest(itemId);
/// <summary>
/// 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.
/// </summary>
/// <param name="itemId">Workshop Item ID</param>
/// <param name="withLongDescription">
/// If true, ask for the item's entire description, otherwise it'll be truncated.
/// </param>
public static async Task<Steamworks.Ugc.Item?> 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)

View File

@@ -11,10 +11,10 @@ namespace Barotrauma
public abstract bool IsSuccess { get; }
public bool IsFailure => !IsSuccess;
public static Success<T, TError> Success(T value)
public static Result<T, TError> Success(T value)
=> new Success<T, TError>(value);
public static Failure<T, TError> Failure(TError error)
public static Result<T, TError> Failure(TError error)
=> new Failure<T, TError>(error);
public abstract bool TryUnwrapSuccess([MaybeNullWhen(returnValue: false)] out T value);

View File

@@ -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

View File

@@ -192,6 +192,22 @@ namespace Steamworks.Ugc
}
}
/// <summary>
/// If installed, the time and date of installation
/// </summary>
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);
}
}
/// <summary>
/// File size as returned by Steamworks,
/// no download/install required