v1.3.0.1 (Epic Store release)

This commit is contained in:
Regalis11
2024-03-28 18:34:33 +02:00
parent 81ca8637be
commit 3791670c42
269 changed files with 13160 additions and 2966 deletions
@@ -1,27 +0,0 @@
namespace Barotrauma.Steam
{
static partial class SteamManager
{
public static Steamworks.BeginAuthResult StartAuthSession(byte[] authTicketData, ulong clientSteamID)
{
if (!IsInitialized || !Steamworks.SteamClient.IsValid) return Steamworks.BeginAuthResult.ServerNotConnectedToSteam;
DebugConsole.Log("SteamManager authenticating Steam client " + clientSteamID);
Steamworks.BeginAuthResult startResult = Steamworks.SteamUser.BeginAuthSession(authTicketData, clientSteamID);
if (startResult != Steamworks.BeginAuthResult.OK)
{
DebugConsole.Log("Authentication failed: failed to start auth session (" + startResult.ToString() + ")");
}
return startResult;
}
public static void StopAuthSession(ulong clientSteamID)
{
if (!IsInitialized || !Steamworks.SteamClient.IsValid) return;
DebugConsole.NewMessage("SteamManager ending auth session with Steam client " + clientSteamID);
Steamworks.SteamUser.EndAuthSession(clientSteamID);
}
}
}
@@ -31,8 +31,8 @@ namespace Barotrauma.Steam
t =>
{
msgBox.Close();
if (!t.TryGetResult(out IReadOnlyList<Steamworks.Ugc.Item> items)) { return; }
if (!t.TryGetResult(out IReadOnlyList<Steamworks.Ugc.Item>? items)) { return; }
InitiateDownloads(items);
});
}
@@ -48,7 +48,7 @@ namespace Barotrauma.Steam
t =>
{
msgBox.Close();
if (!t.TryGetResult(out Steamworks.Ugc.Item?[] itemsNullable)) { return; }
if (!t.TryGetResult(out Steamworks.Ugc.Item?[]? itemsNullable)) { return; }
var items = itemsNullable
.Where(it => it.HasValue)
@@ -74,7 +74,7 @@ namespace Barotrauma.Steam
.NotNone()
.OfType<SteamWorkshopId>()
.Select(async id => await SteamManager.Workshop.GetItem(id.Value))))
.Where(p => p.HasValue).Select(p => p ?? default).ToArray();
.NotNone().ToArray();
}
public static void InitiateDownloads(IReadOnlyList<Steamworks.Ugc.Item> itemsToDownload, Action? onComplete = null)
@@ -1,6 +1,6 @@
using Barotrauma.Networking;
using System;
using System.Globalization;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@@ -26,6 +26,7 @@ namespace Barotrauma.Steam
public static void CreateLobby(ServerSettings serverSettings)
{
if (!SteamManager.IsInitialized) { return; }
if (lobbyState != LobbyState.NotConnected) { return; }
lobbyState = LobbyState.Creating;
TaskPool.Add("CreateLobbyAsync", Steamworks.SteamMatchmaking.CreateLobbyAsync(serverSettings.MaxPlayers + 10),
@@ -88,45 +89,35 @@ namespace Barotrauma.Steam
return;
}
var contentPackages = ContentPackageManager.EnabledPackages.All.Where(cp => cp.HasMultiplayerSyncedContent);
serverSettings.UpdateServerListInfo(SetServerListInfo);
currentLobby?.SetData("name", serverSettings.ServerName);
currentLobby?.SetData("playercount", (GameMain.Client?.ConnectedClients?.Count ?? 0).ToString());
currentLobby?.SetData("maxplayernum", serverSettings.MaxPlayers.ToString());
//currentLobby?.SetData("hostipaddress", lobbyIP);
string pingLocation = Steamworks.SteamNetworkingUtils.LocalPingLocation?.ToString();
currentLobby?.SetData("pinglocation", pingLocation ?? "");
currentLobby?.SetData("lobbyowner", GetSteamId().TryUnwrap(out var steamId)
? steamId.StringRepresentation
: throw new InvalidOperationException("Steamworks not initialized"));
currentLobby?.SetData("haspassword", serverSettings.HasPassword.ToString());
currentLobby?.SetData("message", serverSettings.ServerMessageText);
currentLobby?.SetData("version", GameMain.Version.ToString());
currentLobby?.SetData("contentpackage", string.Join(",", contentPackages.Select(cp => cp.Name)));
currentLobby?.SetData("contentpackagehash", string.Join(",", contentPackages.Select(cp => cp.Hash.StringRepresentation)));
currentLobby?.SetData("contentpackageid", string.Join(",", contentPackages.Select(cp
=> cp.UgcId.TryUnwrap(out var ugcId) ? ugcId.StringRepresentation : "")));
currentLobby?.SetData("modeselectionmode", serverSettings.ModeSelectionMode.ToString());
currentLobby?.SetData("subselectionmode", serverSettings.SubSelectionMode.ToString());
currentLobby?.SetData("voicechatenabled", serverSettings.VoiceChatEnabled.ToString());
currentLobby?.SetData("allowspectating", serverSettings.AllowSpectating.ToString());
currentLobby?.SetData("allowrespawn", serverSettings.AllowRespawn.ToString());
currentLobby?.SetData("karmaenabled", serverSettings.KarmaEnabled.ToString());
currentLobby?.SetData("friendlyfireenabled", serverSettings.AllowFriendlyFire.ToString());
currentLobby?.SetData("traitors", serverSettings.TraitorProbability.ToString(CultureInfo.InvariantCulture));
currentLobby?.SetData("gamestarted", GameMain.Client.GameStarted.ToString());
currentLobby?.SetData("playstyle", serverSettings.PlayStyle.ToString());
currentLobby?.SetData("gamemode", GameMain.NetLobbyScreen?.SelectedMode?.Identifier.Value ?? "");
currentLobby?.SetData("language", serverSettings.Language.ToString());
if (GameMain.NetLobbyScreen?.SelectedSub != null)
if (EosInterface.IdQueries.GetLoggedInPuids() is { Length: > 0 } puids)
{
currentLobby?.SetData("submarine", GameMain.NetLobbyScreen.SelectedSub.Name);
currentLobby?.SetData("EosEndpoint", puids[0].Value);
}
DebugConsole.Log("Lobby updated!");
}
private static void SetServerListInfo(Identifier key, object value)
{
switch (value)
{
case IEnumerable<ContentPackage> contentPackages:
currentLobby?.SetData("contentpackage", contentPackages.Select(p => p.Name).JoinEscaped(','));
currentLobby?.SetData("contentpackagehash", contentPackages.Select(p => p.Hash.StringRepresentation).JoinEscaped(','));
currentLobby?.SetData("contentpackageid", contentPackages
.Select(p => p.UgcId.Select(ugcId => ugcId.StringRepresentation).Fallback(""))
.JoinEscaped(','));
return;
}
currentLobby?.SetData(key.Value.ToLowerInvariant(), value.ToString());
}
public static void LeaveLobby()
{
@@ -42,6 +42,9 @@ namespace Barotrauma.Steam
}
Steamworks.SteamNetworkingUtils.OnDebugOutput += LogSteamworksNetworking;
// Needed to detect invites for social overlay
Steamworks.SteamFriends.ListenForFriendsMessages = true;
}
catch (DllNotFoundException)
{
@@ -145,10 +148,5 @@ namespace Barotrauma.Steam
Steamworks.SteamFriends.OpenWebOverlay(url);
return true;
}
public static void OverlayProfile(SteamId steamId)
{
OverlayCustomUrl($"https://steamcommunity.com/profiles/{steamId.Value}");
}
}
}
@@ -195,7 +195,7 @@ namespace Barotrauma.Steam
modProject.Save(stagingFileListPath);
}
public static async Task<ContentPackage?> CreateLocalCopy(ContentPackage contentPackage)
public static async Task<Option<ContentPackage>> CreateLocalCopy(ContentPackage contentPackage)
{
await Task.Yield();
@@ -234,7 +234,7 @@ namespace Barotrauma.Steam
RefreshLocalMods();
return ContentPackageManager.LocalPackages.FirstOrDefault(p => p.UgcId == contentPackage.UgcId);
return ContentPackageManager.LocalPackages.FirstOrNone(p => p.UgcId == contentPackage.UgcId);
}
private struct InstallWaiter
@@ -196,9 +196,9 @@ namespace Barotrauma.Steam
SteamManager.Workshop.GetItemAsap(workshopItem.Id.Value, withLongDescription: true),
t =>
{
if (!t.TryGetResult(out Steamworks.Ugc.Item? workshopItemWithDescription)) { return; }
if (!t.TryGetResult(out Option<Steamworks.Ugc.Item> workshopItemWithDescription)) { return; }
bbCode = workshopItemWithDescription?.Description ?? "";
bbCode = workshopItemWithDescription.TryUnwrap(out var item) ? (item.Description ?? "") : "";
forceReset();
});
@@ -21,14 +21,14 @@ namespace Barotrauma.Steam
private readonly Action<ItemOrPackage> onInstalledInfoButtonHit;
private readonly GUITextBox modsListFilter;
private readonly Dictionary<Filter, GUITickBox> modsListFilterTickboxes;
private readonly GUIButton bulkUpdateButton;
private readonly Option<GUIButton> bulkUpdateButtonOption;
private GUIComponent? draggedElement = null;
private GUIListBox? draggedElementOrigin = null;
private void UpdateSubscribedModInstalls()
{
if (!SteamManager.IsInitialized) { return; }
if (!EnableWorkshopSupport) { return; }
uint numSubscribedMods = SteamManager.GetNumSubscribedItems();
if (numSubscribedMods == memSubscribedModCount) { return; }
@@ -171,7 +171,7 @@ namespace Barotrauma.Steam
out Action<ItemOrPackage> onInstalledInfoButtonHit,
out GUITextBox modsListFilter,
out Dictionary<Filter, GUITickBox> modsListFilterTickboxes,
out GUIButton bulkUpdateButton)
out Option<GUIButton> bulkUpdateButton)
{
GUIFrame content = CreateNewContentFrame(Tab.InstalledMods);
@@ -233,18 +233,22 @@ namespace Barotrauma.Steam
},
ToolTip = TextManager.Get("RefreshModLists")
};
bulkUpdateButton
= new GUIButton(
new RectTransform(Vector2.One, topRightButtons.RectTransform, scaleBasis: ScaleBasis.BothHeight),
text: "", style: "GUIUpdateButton")
{
OnClicked = (b, o) =>
bulkUpdateButton = EnableWorkshopSupport
? Option.Some(
new GUIButton(
new RectTransform(Vector2.One, topRightButtons.RectTransform, scaleBasis: ScaleBasis.BothHeight),
text: "", style: "GUIUpdateButton")
{
BulkDownloader.PrepareUpdates();
return false;
},
Enabled = false
};
OnClicked = (b,
o) =>
{
BulkDownloader.PrepareUpdates();
return false;
},
Enabled = false
})
: Option.None;
padTopRight(width: 0.1f);
var (left, center, right) = CreateSidebars(mainLayout, centerWidth: 0.05f, leftWidth: 0.475f, rightWidth: 0.475f, height: 0.8f);
@@ -405,10 +409,13 @@ namespace Barotrauma.Steam
CanBeFocused = false
};
}
addFilterTickbox(Filter.ShowLocal, "WorkshopMenu.EditButton", selected: true);
addFilterTickbox(Filter.ShowWorkshop, "WorkshopMenu.DownloadedIcon", selected: true);
addFilterTickbox(Filter.ShowPublished, "WorkshopMenu.PublishedIcon", selected: true);
if (EnableWorkshopSupport)
{
addFilterTickbox(Filter.ShowLocal, "WorkshopMenu.EditButton", selected: true);
addFilterTickbox(Filter.ShowWorkshop, "WorkshopMenu.DownloadedIcon", selected: true);
addFilterTickbox(Filter.ShowPublished, "WorkshopMenu.PublishedIcon", selected: true);
}
addFilterTickbox(Filter.ShowOnlySubs, null, selected: false);
addFilterTickbox(Filter.ShowOnlyItemAssemblies, null, selected: false);
@@ -487,14 +494,23 @@ namespace Barotrauma.Steam
var iconBtn = guiItem.GetChild<GUILayoutGroup>()?.GetAllChildren<GUIButton>().Last();
bool matches = false;
matches |= modsListFilterTickboxes[Filter.ShowLocal].Selected
&& ContentPackageManager.LocalPackages.Contains(p);
matches |= modsListFilterTickboxes[Filter.ShowPublished].Selected
&& (ContentPackageManager.WorkshopPackages.Contains(p)
&& iconBtn?.Style?.Identifier == "WorkshopMenu.PublishedIcon");
matches |= modsListFilterTickboxes[Filter.ShowWorkshop].Selected
&& (ContentPackageManager.WorkshopPackages.Contains(p)
&& iconBtn?.Style?.Identifier != "WorkshopMenu.PublishedIcon");
if (EnableWorkshopSupport)
{
matches |= modsListFilterTickboxes[Filter.ShowLocal].Selected
&& ContentPackageManager.LocalPackages.Contains(p);
matches |= modsListFilterTickboxes[Filter.ShowPublished].Selected
&& (ContentPackageManager.WorkshopPackages.Contains(p)
&& iconBtn?.Style?.Identifier == "WorkshopMenu.PublishedIcon");
matches |= modsListFilterTickboxes[Filter.ShowWorkshop].Selected
&& (ContentPackageManager.WorkshopPackages.Contains(p)
&& iconBtn?.Style?.Identifier != "WorkshopMenu.PublishedIcon");
}
else
{
matches = true;
}
if (modsListFilterTickboxes[Filter.ShowOnlySubs].Selected
&& modsListFilterTickboxes[Filter.ShowOnlyItemAssemblies].Selected
@@ -524,17 +540,20 @@ namespace Barotrauma.Steam
TaskPool.Add($"PrepareToShow{mod.UgcId}Info", SteamManager.Workshop.GetItem(workshopId.Value),
t =>
{
if (!t.TryGetResult(out Steamworks.Ugc.Item? item)) { return; }
if (item is null) { return; }
onInstalledInfoButtonHit(item.Value);
if (!t.TryGetResult(out Option<Steamworks.Ugc.Item> itemOption)) { return; }
if (!itemOption.TryUnwrap(out var item)) { return; }
onInstalledInfoButtonHit(item);
});
}
public void PopulateInstalledModLists(bool forceRefreshEnabled = false, bool refreshDisabled = true)
{
ViewingItemDetails = false;
bulkUpdateButton.Enabled = false;
bulkUpdateButton.ToolTip = "";
if (bulkUpdateButtonOption.TryUnwrap(out var bulkUpdateButton))
{
bulkUpdateButton.Enabled = false;
bulkUpdateButton.ToolTip = "";
}
ContentPackageManager.UpdateContentPackageList();
var corePackages = ContentPackageManager.CorePackages.ToArray();
@@ -583,7 +602,7 @@ namespace Barotrauma.Steam
return false;
}
};
if (!SteamManager.IsInitialized)
if (!EnableWorkshopSupport)
{
infoButton.Enabled = false;
}
@@ -599,8 +618,11 @@ namespace Barotrauma.Steam
infoButton.CanBeSelected = true;
infoButton.ApplyStyle(GUIStyle.ComponentStyles["WorkshopMenu.InfoButtonUpdate"]);
infoButton.ToolTip = TextManager.Get("ViewModDetailsUpdateAvailable");
bulkUpdateButton.Enabled = true;
bulkUpdateButton.ToolTip = TextManager.Get("ModUpdatesAvailable");
if (bulkUpdateButtonOption.TryUnwrap(out var bulkUpdateButton))
{
bulkUpdateButton.Enabled = true;
bulkUpdateButton.ToolTip = TextManager.Get("ModUpdatesAvailable");
}
});
}
}
@@ -705,7 +727,7 @@ namespace Barotrauma.Steam
TaskPool.AddIfNotFound($"UnsubFromSelected", Task.WhenAll(workshopIds.Select(SteamManager.Workshop.GetItem)),
t =>
{
if (!t.TryGetResult(out Steamworks.Ugc.Item?[] items)) { return; }
if (!t.TryGetResult(out Steamworks.Ugc.Item?[]? items)) { return; }
items.ForEach(it =>
{
if (!(it is { } item)) { return; }
@@ -761,7 +783,7 @@ namespace Barotrauma.Steam
SteamManager.Workshop.GetPublishedItems(),
t =>
{
if (!t.TryGetResult(out ISet<Steamworks.Ugc.Item> items)) { return; }
if (!t.TryGetResult(out ISet<Steamworks.Ugc.Item>? items)) { return; }
var ids = items.Select(it => it.Id).ToHashSet();
foreach (var child in enabledRegularModsList.Content.Children
@@ -176,6 +176,8 @@ namespace Barotrauma.Steam
private void AddUnpublishedMods(ISet<Steamworks.Ugc.Item> workshopItems)
{
if (!selfModsListOption.TryUnwrap(out var selfModsList)) { return; }
//Users that don't have a proper license cannot publish Workshop items
//(see https://partner.steamgames.com/doc/features/workshop#15)
void clearWithMessage(LocalizedString message)
@@ -347,7 +349,7 @@ namespace Barotrauma.Steam
workshopItem.Subscribe();
TaskPool.Add($"DownloadSubscribedItem{workshopItem.Id}",
SteamManager.Workshop.ForceRedownload(workshopItem),
t => { });
TaskPool.IgnoredCallback);
}
else
{
@@ -27,7 +27,7 @@ namespace Barotrauma.Steam
}
public Tab CurrentTab { get; private set; }
private readonly GUILayoutGroup tabber;
private readonly Dictionary<Tab, (GUIButton Button, GUIFrame Content)> tabContents;
@@ -36,11 +36,13 @@ namespace Barotrauma.Steam
private CancellationTokenSource taskCancelSrc = new CancellationTokenSource();
private readonly HashSet<SteamManager.Workshop.ItemThumbnail> itemThumbnails = new HashSet<SteamManager.Workshop.ItemThumbnail>();
private readonly GUIListBox popularModsList;
private readonly GUIListBox selfModsList;
private readonly Option<GUIListBox> popularModsListOption;
private readonly Option<GUIListBox> selfModsListOption;
private uint memSubscribedModCount = 0;
private static bool EnableWorkshopSupport => SteamManager.IsInitialized;
public MutableWorkshopMenu(GUIFrame parent) : base(parent)
{
var mainLayout
@@ -50,25 +52,34 @@ namespace Barotrauma.Steam
AbsoluteSpacing = GUI.IntScale(4)
};
tabber = new GUILayoutGroup(new RectTransform((1.0f, 0.05f), mainLayout.RectTransform), isHorizontal: true)
Vector2 tabberSize = EnableWorkshopSupport ? (1.0f, 0.05f) : Vector2.Zero;
tabber = new GUILayoutGroup(new RectTransform(tabberSize, mainLayout.RectTransform), isHorizontal: true)
{ Stretch = true };
tabContents = new Dictionary<Tab, (GUIButton Button, GUIFrame Content)>();
new GUIButton(new RectTransform((1.0f, 0.05f), mainLayout.RectTransform, Anchor.BottomLeft),
style: "GUIButtonSmall", text: TextManager.Get("FindModsButton"))
if (EnableWorkshopSupport)
{
OnClicked = (button, o) =>
new GUIButton(new RectTransform((1.0f, 0.05f), mainLayout.RectTransform, Anchor.BottomLeft),
style: "GUIButtonSmall", text: TextManager.Get("FindModsButton"))
{
SteamManager.OverlayCustomUrl($"https://steamcommunity.com/app/{SteamManager.AppID}/workshop/");
return false;
}
};
OnClicked = (button, o) =>
{
SteamManager.OverlayCustomUrl($"https://steamcommunity.com/app/{SteamManager.AppID}/workshop/");
return false;
}
};
}
else
{
tabber.Visible = false;
}
contentFrame = new GUIFrame(new RectTransform((1.0f, 0.95f), mainLayout.RectTransform), style: null);
new GUICustomComponent(new RectTransform(Vector2.Zero, mainLayout.RectTransform),
onUpdate: (f, component) => UpdateSubscribedModInstalls());
CreateInstalledModsTab(
out enabledCoreDropdown,
out enabledRegularModsList,
@@ -76,9 +87,21 @@ namespace Barotrauma.Steam
out onInstalledInfoButtonHit,
out modsListFilter,
out modsListFilterTickboxes,
out bulkUpdateButton);
CreatePopularModsTab(out popularModsList);
CreatePublishTab(out selfModsList);
out bulkUpdateButtonOption);
if (EnableWorkshopSupport)
{
CreatePopularModsTab(out GUIListBox popularModList);
CreatePublishTab(out GUIListBox selfModsList);
popularModsListOption = Option<GUIListBox>.Some(popularModList);
selfModsListOption = Option<GUIListBox>.Some(selfModsList);
}
else
{
popularModsListOption = Option.None;
selfModsListOption = Option.None;
}
SelectTab(Tab.InstalledMods);
}
@@ -105,10 +128,10 @@ namespace Barotrauma.Steam
case Tab.InstalledMods:
PopulateInstalledModLists();
break;
case Tab.PopularMods:
case Tab.PopularMods when popularModsListOption.TryUnwrap(out var popularModsList):
PopulateItemList(popularModsList, SteamManager.Workshop.GetPopularItems(), includeSubscribeButton: true);
break;
case Tab.Publish:
case Tab.Publish when selfModsListOption.TryUnwrap(out var selfModsList):
PopulateItemList(selfModsList, SteamManager.Workshop.GetPublishedItems(), includeSubscribeButton: false, onFill: AddUnpublishedMods);
break;
}
@@ -88,17 +88,21 @@ namespace Barotrauma.Steam
private void DeselectPublishedItem()
{
var deselectCarrier = selfModsList.Parent.FindChild(c => c.UserData is ActionCarrier { Id: var id } && id == "deselect");
Action? deselectAction = deselectCarrier.UserData is ActionCarrier { Action: var action }
? action
: null;
deselectAction?.Invoke();
if (selfModsListOption.TryUnwrap(out var selfModsList))
{
var deselectCarrier = selfModsList.Parent.FindChild(c => c.UserData is ActionCarrier { Id: var id } && id == "deselect");
Action? deselectAction = deselectCarrier.UserData is ActionCarrier { Action: var action }
? action
: null;
deselectAction?.Invoke();
}
SelectTab(Tab.Publish);
}
private static bool PackageMatchesItem(ContentPackage p, Steamworks.Ugc.Item workshopItem)
=> p.TryExtractSteamWorkshopId(out var workshopId) && workshopId.Value == workshopItem.Id;
private void PopulatePublishTab(ItemOrPackage itemOrPackage, GUIFrame parentFrame)
{
ContentPackageManager.LocalPackages.Refresh();
@@ -226,9 +230,12 @@ namespace Barotrauma.Steam
SteamManager.Workshop.GetItemAsap(workshopItem.Id.Value, withLongDescription: true),
t =>
{
if (!t.TryGetResult(out Steamworks.Ugc.Item? itemWithDescription)) { return; }
if (!t.TryGetResult(out Option<Steamworks.Ugc.Item> itemWithDescriptionOption)) { return; }
descriptionTextBox.Text = itemWithDescription?.Description ?? descriptionTextBox.Text;
descriptionTextBox.Text =
itemWithDescriptionOption.TryUnwrap(out var itemWithDescription)
? itemWithDescription.Description ?? descriptionTextBox.Text
: descriptionTextBox.Text;
descriptionTextBox.Deselect();
});
}
@@ -296,7 +303,7 @@ namespace Barotrauma.Steam
var fileInfoLabel = Label(rightBottom, "", GUIStyle.Font, heightScale: 1.0f);
fileInfoLabel.TextAlignment = Alignment.CenterRight;
TaskPool.Add($"FileInfoLabel{workshopItem.Id}", GetModDirInfo(localPackage.Dir, fileInfoLabel), t => { });
TaskPool.AddWithResult($"FileInfoLabel{workshopItem.Id}", GetModDirInfo(localPackage.Dir, fileInfoLabel), t => { });
GUILayoutGroup buttonLayout = new GUILayoutGroup(NewItemRectT(rightBottom), isHorizontal: true, childAnchor: Anchor.CenterRight);
@@ -351,7 +358,7 @@ namespace Barotrauma.Steam
buttons: new[] { TextManager.Get("Yes"), TextManager.Get("No") });
confirmDeletion.Buttons[0].OnClicked = (yesBuffer, o1) =>
{
TaskPool.Add($"Delete{workshopItem.Id}", Steamworks.SteamUGC.DeleteFileAsync(workshopItem.Id),
TaskPool.AddWithResult($"Delete{workshopItem.Id}", Steamworks.SteamUGC.DeleteFileAsync(workshopItem.Id),
t =>
{
SteamManager.Workshop.Uninstall(workshopItem);
@@ -452,7 +459,7 @@ namespace Barotrauma.Steam
}
bool localCopyMade = false;
TaskPool.Add($"Create local copy {workshopItem.Title}",
TaskPool.AddWithResult($"Create local copy {workshopItem.Title}",
SteamManager.Workshop.CreateLocalCopy(workshopCopy),
(t) =>
{