diff --git a/Barotrauma/BarotraumaClient/ClientSource/ContentManagement/Transition/UgcTransition.cs b/Barotrauma/BarotraumaClient/ClientSource/ContentManagement/Transition/UgcTransition.cs index 537ca3df8..cbc1e3683 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/ContentManagement/Transition/UgcTransition.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/ContentManagement/Transition/UgcTransition.cs @@ -22,6 +22,12 @@ namespace Barotrauma.Transition public static class UgcTransition { private const string readmeName = "LOCALMODS_README.txt"; + + private enum ModsListChildType + { + Header, + Entry + } public static void Prepare() { @@ -34,6 +40,17 @@ namespace Barotrauma.Transition var msgBox = new GUIMessageBox(TextManager.Get("Ugc.TransferTitle"), "", relativeSize: (0.5f, 0.8f), buttons: new LocalizedString[] { TextManager.Get("Ugc.TransferButton") }); + var closeBtn = new GUIButton( + new RectTransform(Vector2.One * 1.5f, msgBox.Header.RectTransform, anchor: Anchor.CenterRight, scaleBasis: ScaleBasis.BothHeight), + style: "GUICancelButton") + { + OnClicked = (button, o) => + { + msgBox.Close(); + return false; + } + }; + var desc = new GUITextBlock(new RectTransform((1.0f, 0.24f), msgBox.Content.RectTransform), text: TextManager.Get("Ugc.TransferDesc"), wrap: true, textAlignment: Alignment.CenterLeft); @@ -45,20 +62,73 @@ namespace Barotrauma.Transition void addHeader(LocalizedString str) { - var itemFrame = new GUITextBlock(new RectTransform((1.0f, 0.08f), modsList.Content.RectTransform), - text: str, font: GUIStyle.SubHeadingFont) + var itemFrame = new GUIFrame(new RectTransform((1.0f, 0.08f), modsList.Content.RectTransform), + style: null) { - CanBeFocused = false + CanBeFocused = false, + UserData = ModsListChildType.Header }; + if (str is RawLString { Value: "" }) { return; } + + bool clicked = true; + var tickBox = new GUITickBox(new RectTransform(Vector2.One, itemFrame.RectTransform), + label: str, font: GUIStyle.SubHeadingFont) + { + Selected = false, + OnSelected = box => + { + if (!clicked) { return true; } + bool toggleTickbox = false; + foreach (var child in modsList.Content.Children) + { + if (child == itemFrame) { toggleTickbox = true; } + else if (child.UserData is ModsListChildType.Header) { toggleTickbox = false; } + else if (toggleTickbox) + { + var tb = child.GetAnyChild(); + if (tb is null) { continue; } + + tb.Selected = box.Selected; + } + } + return true; + } + }; + new GUICustomComponent(new RectTransform(Vector2.Zero, itemFrame.RectTransform), + onUpdate: (f, component) => + { + clicked = false; + bool shouldBeSelected = true; + bool toggleTickbox = false; + foreach (var child in modsList.Content.Children) + { + if (child == itemFrame) { toggleTickbox = true; } + else if (child.UserData is ModsListChildType.Header) { toggleTickbox = false; } + else if (toggleTickbox) + { + var tb = child.GetAnyChild(); + if (tb is null) { continue; } + + if (!tb.Selected) + { + shouldBeSelected = false; + break; + } + } + } + tickBox.Selected = shouldBeSelected; + clicked = true; + }); } void addTickbox(string dir, string name, bool ticked) { var itemFrame = new GUIFrame(new RectTransform((1.0f, 0.07f), modsList.Content.RectTransform), style: null) { - CanBeFocused = false + CanBeFocused = false, + UserData = ModsListChildType.Entry }; - var tickbox = new GUITickBox(new RectTransform(Vector2.One, itemFrame.RectTransform), name) + var tickbox = new GUITickBox(new RectTransform((0.97f, 1.0f), itemFrame.RectTransform, Anchor.CenterRight), name) { Selected = ticked }; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Fonts/ScalableFont.cs b/Barotrauma/BarotraumaClient/ClientSource/Fonts/ScalableFont.cs index bbcc7acca..ae0a54609 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Fonts/ScalableFont.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Fonts/ScalableFont.cs @@ -501,8 +501,8 @@ namespace Barotrauma private string ApplyUpperCase(string text, ForceUpperCase forceUpperCase) => forceUpperCase switch { - Barotrauma.ForceUpperCase.Inherit => ForceUpperCase ? text.ToUpper() : text, - Barotrauma.ForceUpperCase.Yes => text.ToUpper(), + Barotrauma.ForceUpperCase.Inherit => ForceUpperCase ? text.ToUpperInvariant() : text, + Barotrauma.ForceUpperCase.Yes => text.ToUpperInvariant(), Barotrauma.ForceUpperCase.No => text }; diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIImage.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIImage.cs index 23b891e34..c19bcc378 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIImage.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/GUIImage.cs @@ -151,8 +151,13 @@ namespace Barotrauma loadingTextures = true; loading = true; TaskPool.Add("LoadTextureAsync", - LoadTextureAsync(), (Task) => + LoadTextureAsync(), task => { + if (task.Exception != null) + { + var innerMost = task.Exception.GetInnermost(); + DebugConsole.ThrowError($"Failed to load \"{Sprite.FilePath}\"", innerMost); + } loading = false; lazyLoaded = true; RectTransform.SizeChanged += RecalculateScale; @@ -232,7 +237,7 @@ namespace Barotrauma { wait = activeTextureLoads.Contains(Sprite.FullPath); } - } + } } try { diff --git a/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs b/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs index d8125d1fb..74c244c3a 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GUI/TabMenu.cs @@ -981,17 +981,19 @@ namespace Barotrauma BarSize = 0.1f, OnMoved = (bar, scroll) => { - SetRewardText((int)(scroll * 100), rewardBlock); + int rewardDistribution = RoundRewardDistribution(scroll, bar.Step); + SetRewardText(rewardDistribution, rewardBlock); return true; }, OnReleased = (bar, scroll) => { - int newRewardDistribution = (int)(scroll * 100); + int newRewardDistribution = RoundRewardDistribution(scroll, bar.Step); if (newRewardDistribution == targetWallet.RewardDistribution) { return false; } SetRewardDistribution(character, newRewardDistribution); return true; } }; + int RoundRewardDistribution(float scroll, float step) => (int)MathUtils.RoundTowardsClosest(scroll * 100, step * 100); SetRewardText(targetWallet.RewardDistribution, rewardBlock); diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/CargoManager.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/CargoManager.cs index aa1b4528a..bbbd12105 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/CargoManager.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/CargoManager.cs @@ -182,7 +182,10 @@ namespace Barotrauma } // Exchange money store.Balance -= itemValue; - campaign.Bank.Give(itemValue); + if (GameMain.IsSingleplayer) + { + campaign.Bank.Give(itemValue); + } GameAnalyticsManager.AddMoneyGainedEvent(itemValue, GameAnalyticsManager.MoneySource.Store, item.ItemPrefab.Identifier.Value); // Remove from the sell crate diff --git a/Barotrauma/BarotraumaClient/ClientSource/GameSession/RoundSummary.cs b/Barotrauma/BarotraumaClient/ClientSource/GameSession/RoundSummary.cs index 06e09c661..b3b385acd 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/GameSession/RoundSummary.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/GameSession/RoundSummary.cs @@ -703,7 +703,7 @@ namespace Barotrauma AbsoluteSpacing = GUI.IntScale(10), Stretch = true }; - var factionIcon = new GUIImage(new RectTransform(new Point((int)(factionInfoHorizontal.Rect.Height * 0.7f)), factionInfoHorizontal.RectTransform, scaleBasis: ScaleBasis.Smallest), icon, scaleToFit: true) + var factionIcon = new GUIImage(new RectTransform(Vector2.One * 0.7f, factionInfoHorizontal.RectTransform, scaleBasis: ScaleBasis.Smallest), icon, scaleToFit: true) { Color = iconColor }; diff --git a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Connection.cs b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Connection.cs index cfe0fa95b..93c653f0b 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Connection.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Connection.cs @@ -208,7 +208,7 @@ namespace Barotrauma.Items.Components private void DrawConnection(SpriteBatch spriteBatch, ConnectionPanel panel, Vector2 position, Vector2 labelPos, Vector2 scale) { - string text = DisplayName.Value.ToUpper(); + string text = DisplayName.Value.ToUpperInvariant(); //nasty if (GUIStyle.GetComponentStyle("ConnectionPanelLabel")?.Sprites.Values.First().First() is UISprite labelSprite) @@ -401,13 +401,13 @@ namespace Barotrauma.Items.Components { if (c.IsOutput) { - var labelArea = GetLabelArea(GetOutputLabelPosition(rightPos, panel, c), c.DisplayName.Value.ToUpper(), scale); + var labelArea = GetLabelArea(GetOutputLabelPosition(rightPos, panel, c), c.DisplayName.Value.ToUpperInvariant(), scale); labelAreas.Add(labelArea); rightPos.Y += connectorIntervalLeft; } else { - var labelArea = GetLabelArea(GetInputLabelPosition(leftPos, panel, c), c.DisplayName.Value.ToUpper(), scale); + var labelArea = GetLabelArea(GetInputLabelPosition(leftPos, panel, c), c.DisplayName.Value.ToUpperInvariant(), scale); labelAreas.Add(labelArea); leftPos.Y += connectorIntervalRight; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs b/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs index 978c63676..f299141ee 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Networking/GameClient.cs @@ -415,7 +415,7 @@ namespace Barotrauma.Networking GameMain.ServerListScreen.Select(); } - GUIMessageBox.MessageBoxes.RemoveAll(m => true); + GUIMessageBox.MessageBoxes.Clear(); return true; } @@ -722,7 +722,10 @@ namespace Barotrauma.Networking //allow interpreting this packet break; case ServerPacketHeader.STARTGAME: - GameMain.NetLobbyScreen.ShowSpectateButton(); + gameStarted = true; + return; + case ServerPacketHeader.ENDGAME: + gameStarted = false; return; default: return; //ignore any other packets @@ -2112,11 +2115,11 @@ namespace Barotrauma.Networking serverSettings.ServerLog.ServerName = serverSettings.ServerName; - if (!GameMain.NetLobbyScreen.ServerName.Selected) GameMain.NetLobbyScreen.ServerName.Text = serverSettings.ServerName; - if (!GameMain.NetLobbyScreen.ServerMessage.Selected) GameMain.NetLobbyScreen.ServerMessage.Text = serverSettings.ServerMessageText; + if (!GameMain.NetLobbyScreen.ServerName.Selected) { GameMain.NetLobbyScreen.ServerName.Text = serverSettings.ServerName; } + if (!GameMain.NetLobbyScreen.ServerMessage.Selected) { GameMain.NetLobbyScreen.ServerMessage.Text = serverSettings.ServerMessageText; } GameMain.NetLobbyScreen.UsingShuttle = usingShuttle; - if (!allowSubVoting) GameMain.NetLobbyScreen.TrySelectSub(selectSubName, selectSubHash, GameMain.NetLobbyScreen.SubList); + if (!allowSubVoting) { GameMain.NetLobbyScreen.TrySelectSub(selectSubName, selectSubHash, GameMain.NetLobbyScreen.SubList); } GameMain.NetLobbyScreen.TrySelectSub(selectShuttleName, selectShuttleHash, GameMain.NetLobbyScreen.ShuttleList.ListBox); GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/ModDownloadScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/ModDownloadScreen.cs index 7edee9c1c..d0242a937 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/ModDownloadScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/ModDownloadScreen.cs @@ -67,7 +67,7 @@ namespace Barotrauma { OnClicked = (guiButton, o) => { - GameMain.Client.Disconnect(); + GameMain.Client?.Disconnect(); GameMain.MainMenuScreen.Select(); return false; } @@ -153,7 +153,7 @@ namespace Barotrauma buttonContainerSpacing(0.2f); button(TextManager.Get("No"), () => { - GameMain.Client.Disconnect(); + GameMain.Client?.Disconnect(); GameMain.MainMenuScreen.Select(); }); buttonContainerSpacing(0.1f); @@ -170,11 +170,14 @@ namespace Barotrauma buttonContainerSpacing(0.15f); button(TextManager.Get("SubscribeToAllOnWorkshop"), () => { - BulkDownloader.SubscribeToServerMods(missingIds, - rejoinEndpoint: GameMain.Client.ClientPeer.ServerConnection.EndPointString, - rejoinLobby: SteamManager.CurrentLobbyID, - rejoinServerName: GameMain.NetLobbyScreen.ServerName.Text); - GameMain.Client.Disconnect(); + if (GameMain.Client != null) + { + BulkDownloader.SubscribeToServerMods(missingIds, + rejoinEndpoint: GameMain.Client.ClientPeer.ServerConnection.EndPointString, + rejoinLobby: SteamManager.CurrentLobbyID, + rejoinServerName: GameMain.NetLobbyScreen.ServerName.Text); + GameMain.Client.Disconnect(); + } GameMain.MainMenuScreen.Select(); }, width: 0.7f); buttonContainerSpacing(0.15f); diff --git a/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs b/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs index e1c224954..3c2587f25 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Screens/SubEditorScreen.cs @@ -3796,20 +3796,27 @@ namespace Barotrauma OnSelected = SelectWire }; + List wirePrefabs = new List(); + foreach (ItemPrefab itemPrefab in ItemPrefab.Prefabs) { - if (itemPrefab.Name.IsNullOrEmpty()) { continue; } + if (itemPrefab.Name.IsNullOrEmpty() || itemPrefab.HideInMenus) { continue; } if (!itemPrefab.Tags.Contains("wire")) { continue; } + wirePrefabs.Add(itemPrefab); + } + foreach (ItemPrefab itemPrefab in wirePrefabs.OrderBy(w => !w.CanBeBought).ThenBy(w => w.UintIdentifier)) + { GUIFrame imgFrame = new GUIFrame(new RectTransform(new Point(listBox.Content.Rect.Width, listBox.Rect.Width / 2), listBox.Content.RectTransform), style: "ListBoxElement") { UserData = itemPrefab }; - var img = new GUIImage(new RectTransform(new Vector2(0.9f), imgFrame.RectTransform, Anchor.Center), itemPrefab.Sprite, scaleToFit: true) { UserData = itemPrefab, - Color = itemPrefab.SpriteColor + Color = itemPrefab.SpriteColor, + HoverColor = Color.Lerp(itemPrefab.SpriteColor, Color.White, 0.3f), + SelectedColor = Color.Lerp(itemPrefab.SpriteColor, Color.White, 0.6f) }; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Sprite/Sprite.cs b/Barotrauma/BarotraumaClient/ClientSource/Sprite/Sprite.cs index 8336320d0..6db48e03d 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Sprite/Sprite.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Sprite/Sprite.cs @@ -167,7 +167,13 @@ namespace Barotrauma Texture2D newTexture = TextureLoader.FromFile(file, compress); lock (list) { - textureRefCounts.Add(fullPath, new TextureRefCounter { RefCount = 1, Texture = newTexture }); + if (!textureRefCounts.TryAdd(fullPath, + new TextureRefCounter { RefCount = 1, Texture = newTexture })) + { + CrossThread.RequestExecutionOnMainThread(() => newTexture.Dispose()); + textureRefCounts[fullPath].RefCount++; + return textureRefCounts[fullPath].Texture; + } } return newTexture; } diff --git a/Barotrauma/BarotraumaClient/ClientSource/Steam/BulkDownloader.cs b/Barotrauma/BarotraumaClient/ClientSource/Steam/BulkDownloader.cs index 0542698d4..7a07f041b 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Steam/BulkDownloader.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Steam/BulkDownloader.cs @@ -11,8 +11,18 @@ namespace Barotrauma.Steam { public static class BulkDownloader { + private static void CloseAllMessageBoxes() + { + GUIMessageBox.MessageBoxes.ForEachMod(b => + { + if (b is GUIMessageBox m) { m.Close(); } + else { GUIMessageBox.MessageBoxes.Remove(b); } + }); + } + public static void PrepareUpdates() { + CloseAllMessageBoxes(); GUIMessageBox msgBox = new GUIMessageBox(headerText: "", text: TextManager.Get("DeterminingRequiredModUpdates"), buttons: Array.Empty()); TaskPool.Add( @@ -29,6 +39,7 @@ namespace Barotrauma.Steam internal static void SubscribeToServerMods(IEnumerable missingIds, string rejoinEndpoint, ulong rejoinLobby, string rejoinServerName) { + CloseAllMessageBoxes(); GUIMessageBox msgBox = new GUIMessageBox(headerText: "", text: TextManager.Get("PreparingWorkshopDownloads"), buttons: Array.Empty()); TaskPool.Add( diff --git a/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/ItemList.cs b/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/ItemList.cs index 3ae7116ea..dc9e38c57 100644 --- a/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/ItemList.cs +++ b/Barotrauma/BarotraumaClient/ClientSource/Steam/WorkshopMenu/Mutable/ItemList.cs @@ -202,7 +202,22 @@ namespace Barotrauma.Steam } DateTime getEditTime(ContentPackage p) - => File.GetLastWriteTime(Path.GetDirectoryName(p.Path)!); + { + DateTime writeTime = File.GetLastWriteTime(p.Dir); + + //File.GetLastWriteTime on the directory is not good enough; + //it's possible to update a file in a directory without + //updating its parent directories' write time, so let's + //look at all of those files + var files = Directory.GetFiles(p.Dir, "*", System.IO.SearchOption.AllDirectories); + foreach (var file in files) + { + DateTime newTime = File.GetLastWriteTime(file); + if (newTime > writeTime) { writeTime = newTime; } + } + + return writeTime; + } //Find local packages associated with the Workshop items if available (Steamworks.Ugc.Item WorkshopItem, ContentPackage? LocalPackage)[] publishedItems = workshopItems diff --git a/Barotrauma/BarotraumaClient/LinuxClient.csproj b/Barotrauma/BarotraumaClient/LinuxClient.csproj index 0b5e1c96e..26aacc2c2 100644 --- a/Barotrauma/BarotraumaClient/LinuxClient.csproj +++ b/Barotrauma/BarotraumaClient/LinuxClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.17.8.0 + 0.17.9.0 Copyright © FakeFish 2018-2022 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/MacClient.csproj b/Barotrauma/BarotraumaClient/MacClient.csproj index a42df692b..37d4a97cf 100644 --- a/Barotrauma/BarotraumaClient/MacClient.csproj +++ b/Barotrauma/BarotraumaClient/MacClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.17.8.0 + 0.17.9.0 Copyright © FakeFish 2018-2022 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaClient/WindowsClient.csproj b/Barotrauma/BarotraumaClient/WindowsClient.csproj index 47c587095..878ec305c 100644 --- a/Barotrauma/BarotraumaClient/WindowsClient.csproj +++ b/Barotrauma/BarotraumaClient/WindowsClient.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma - 0.17.8.0 + 0.17.9.0 Copyright © FakeFish 2018-2022 AnyCPU;x64 Barotrauma diff --git a/Barotrauma/BarotraumaServer/LinuxServer.csproj b/Barotrauma/BarotraumaServer/LinuxServer.csproj index 536c36d93..9de14390c 100644 --- a/Barotrauma/BarotraumaServer/LinuxServer.csproj +++ b/Barotrauma/BarotraumaServer/LinuxServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.17.8.0 + 0.17.9.0 Copyright © FakeFish 2018-2022 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/MacServer.csproj b/Barotrauma/BarotraumaServer/MacServer.csproj index 8fd72c650..493a1aac4 100644 --- a/Barotrauma/BarotraumaServer/MacServer.csproj +++ b/Barotrauma/BarotraumaServer/MacServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.17.8.0 + 0.17.9.0 Copyright © FakeFish 2018-2022 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaServer/ServerSource/GameSession/CargoManager.cs b/Barotrauma/BarotraumaServer/ServerSource/GameSession/CargoManager.cs index d04255896..5b041b615 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/GameSession/CargoManager.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/GameSession/CargoManager.cs @@ -23,7 +23,7 @@ namespace Barotrauma } } - public void BuyBackSoldItems(Identifier storeIdentifier, List itemsToBuy) + public void BuyBackSoldItems(Identifier storeIdentifier, List itemsToBuy, Client client) { var store = Location.GetStore(storeIdentifier); if (store == null) { return; } @@ -35,12 +35,12 @@ namespace Barotrauma int itemValue = sellValues[item.ItemPrefab]; if (store.Balance < itemValue || item.Removed) { continue; } store.Balance += itemValue; - campaign.Bank.TryDeduct(itemValue); + campaign.GetWallet(client).TryDeduct(itemValue); storeSpecificItems.Remove(item); } } - public void SellItems(Identifier storeIdentifier, List itemsToSell) + public void SellItems(Identifier storeIdentifier, List itemsToSell, Client client) { var store = Location.GetStore(storeIdentifier); if (store == null) { return; } @@ -74,7 +74,7 @@ namespace Barotrauma } itemsSoldAtStore?.Add(item); store.Balance -= itemValue; - campaign.Bank.Give(itemValue); + campaign.GetWallet(client).Give(itemValue); GameAnalyticsManager.AddMoneyGainedEvent(itemValue, GameAnalyticsManager.MoneySource.Store, item.ItemPrefab.Identifier.Value); } OnSoldItemsChanged?.Invoke(); diff --git a/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs b/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs index ff0fc0357..6fe90fcbf 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/GameSession/GameModes/MultiPlayerCampaign.cs @@ -516,7 +516,9 @@ namespace Barotrauma { if (wallet.HasTransactions()) { - transactions.Add(wallet.DequeueAndMergeTransactions(id)); + NetWalletTransaction transaction = wallet.DequeueAndMergeTransactions(id); + if (transaction.ChangedData.BalanceChanged.IsNone() && transaction.ChangedData.RewardDistributionChanged.IsNone()) { continue; } + transactions.Add(transaction); } } @@ -791,14 +793,14 @@ namespace Barotrauma } foreach (var store in prevBuyCrateItems) { - foreach (var item in store.Value) + foreach (var item in store.Value.ToList()) { CargoManager.ModifyItemQuantityInBuyCrate(store.Key, item.ItemPrefab, -item.Quantity, sender); } } foreach (var store in buyCrateItems) { - foreach (var item in store.Value) + foreach (var item in store.Value.ToList()) { CargoManager.ModifyItemQuantityInBuyCrate(store.Key, item.ItemPrefab, item.Quantity, sender); } @@ -816,7 +818,40 @@ namespace Barotrauma foreach (var store in purchasedItems) { CargoManager.PurchaseItems(store.Key, store.Value, false, sender); - } + } + + foreach (var (storeIdentifier, items) in CargoManager.PurchasedItems) + { + if (!prevPurchasedItems.ContainsKey(storeIdentifier)) + { + CargoManager.OnNewItemsPurchased(storeIdentifier, items, sender); + continue; + } + + List newItems = new List(); + List prevItems = prevPurchasedItems[storeIdentifier]; + + foreach (PurchasedItem item in items) + { + PurchasedItem matching = prevItems.FirstOrDefault(ppi => ppi.ItemPrefab == item.ItemPrefab); + if (matching is null) + { + newItems.Add(item); + continue; + } + + if (matching.Quantity < item.Quantity) + { + newItems.Add(new PurchasedItem(item.ItemPrefab, item.Quantity - matching.Quantity, sender)); + } + } + + if (newItems.Any()) + { + CargoManager.OnNewItemsPurchased(storeIdentifier, newItems, sender); + } + } + bool allowedToSellSubItems = AllowedToManageCampaign(sender, ClientPermissions.SellSubItems); if (allowedToSellSubItems) @@ -824,14 +859,14 @@ namespace Barotrauma var prevSubSellCrateItems = new Dictionary>(CargoManager.ItemsInSellFromSubCrate); foreach (var store in prevSubSellCrateItems) { - foreach (var item in store.Value) + foreach (var item in store.Value.ToList()) { CargoManager.ModifyItemQuantityInSubSellCrate(store.Key, item.ItemPrefab, -item.Quantity, sender); } } foreach (var store in subSellCrateItems) { - foreach (var item in store.Value) + foreach (var item in store.Value.ToList()) { CargoManager.ModifyItemQuantityInSubSellCrate(store.Key, item.ItemPrefab, item.Quantity, sender); } @@ -846,11 +881,11 @@ namespace Barotrauma var prevSoldItems = new Dictionary>(CargoManager.SoldItems); foreach (var store in prevSoldItems) { - CargoManager.BuyBackSoldItems(store.Key, store.Value); + CargoManager.BuyBackSoldItems(store.Key, store.Value.ToList(), sender); } foreach (var store in soldItems) { - CargoManager.SellItems(store.Key, store.Value); + CargoManager.SellItems(store.Key, store.Value.ToList(), sender); } } else if (allowedToSellInventoryItems || allowedToSellSubItems) @@ -859,7 +894,7 @@ namespace Barotrauma foreach (var store in prevSoldItems) { store.Value.RemoveAll(predicate); - CargoManager.BuyBackSoldItems(store.Key, store.Value); + CargoManager.BuyBackSoldItems(store.Key, store.Value.ToList(), sender); } foreach (var store in soldItems) { @@ -867,7 +902,7 @@ namespace Barotrauma } foreach (var store in soldItems) { - CargoManager.SellItems(store.Key, store.Value); + CargoManager.SellItems(store.Key, store.Value.ToList(), sender); } bool predicate(SoldItem i) => allowedToSellInventoryItems != (i.Origin == SoldItem.SellOrigin.Character); } @@ -899,7 +934,7 @@ namespace Barotrauma UpgradeManager.CancelItemSwap(item); item.PendingItemSwap = null; } - } + } } public void ServerReadMoney(IReadMessage msg, Client sender) diff --git a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs index 1079e0506..bf243cc17 100644 --- a/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs +++ b/Barotrauma/BarotraumaServer/ServerSource/Networking/GameServer.cs @@ -1867,7 +1867,9 @@ namespace Barotrauma.Networking outmsg.Write(GameMain.NetLobbyScreen.SelectedSub.Name); outmsg.Write(GameMain.NetLobbyScreen.SelectedSub.MD5Hash.ToString()); outmsg.Write(IsUsingRespawnShuttle()); - var selectedShuttle = gameStarted && respawnManager.UsingShuttle ? respawnManager.RespawnShuttle.Info : GameMain.NetLobbyScreen.SelectedShuttle; + var selectedShuttle = gameStarted && respawnManager != null && respawnManager.UsingShuttle ? + respawnManager.RespawnShuttle.Info : + GameMain.NetLobbyScreen.SelectedShuttle; outmsg.Write(selectedShuttle.Name); outmsg.Write(selectedShuttle.MD5Hash.ToString()); diff --git a/Barotrauma/BarotraumaServer/WindowsServer.csproj b/Barotrauma/BarotraumaServer/WindowsServer.csproj index b4a4bf530..cb01587b4 100644 --- a/Barotrauma/BarotraumaServer/WindowsServer.csproj +++ b/Barotrauma/BarotraumaServer/WindowsServer.csproj @@ -6,7 +6,7 @@ Barotrauma FakeFish, Undertow Games Barotrauma Dedicated Server - 0.17.8.0 + 0.17.9.0 Copyright © FakeFish 2018-2022 AnyCPU;x64 DedicatedServer diff --git a/Barotrauma/BarotraumaShared/LocalMods/info.txt b/Barotrauma/BarotraumaShared/LocalMods/info.txt index 290565fb3..cf60013ac 100644 --- a/Barotrauma/BarotraumaShared/LocalMods/info.txt +++ b/Barotrauma/BarotraumaShared/LocalMods/info.txt @@ -1,86 +1,6 @@ -TODO: THIS IS VERY OUTDATED ------------------------------------------------------------------------- -General ------------------------------------------------------------------------- - - This folder is the place where mods installed from the Steam Workshop go. - You should also place your own mods in this folder, under a separate - subfolder (e.g. "Mods/MyMod"). - ------------------------------------------------------------------------- -Content Packages: ------------------------------------------------------------------------- - - Content packages determine which configuration files the game will be using. - This includes the configuration files for items, map structures, characters, - monsters and jobs. - - In the multiplayer mode, players are required to use the same content package - as the server or they won't be able to join. - - All mods published in the Steam Workshop need a content package. - - If you just want to publish a custom submarine in the workshop, you - don't need to worry about content packages - you can just select the - submarine from the "Publish item" tab in the Workshop menu, and the - game automatically creates a folder and content package for your mod. - -Example - - A very simple content package could be configured as follows: - - - - - - - - - - - - - Note that this mod has been configured as a "core package". Core packages are - packages that contain all the necessary files to make the game run, instead of - just adding some extra files on top of another content package. There can only - be one core package selected at a time. - - This content package would replace all the items in the game with whatever items are - configured in the "Mods/BestModEver/items.xml" file. It would also use a modified - version of the human characters and have all the monsters in the game replaced with - crawlers and Cthulhus. The random events have also been changed - perhaps by adding - a new event that spawns Cthulhu and removing the events that spawn monsters/items - which aren't included in the mod. - - Note that the content package should be saved with the file name "filelist.xml" in - the Mods folder, in this case "Mods/BestModEver/filelist.xml". - -Non-core content packages - - Most mods are usually not core content packages, but instead add things to or - modify things in the Vanilla content package (= the default content of the game). - - Here's an example of a simple non-core package: - - - - - - This mod would simply add an extra item to the game (or items if there are multiple - ones configured in the potatogun.xml file). - -Overriding content - - You can also set your mods to override vanilla content without having to modify the - Vanilla content package. This can be done by using Override-elements in the xml - configuration files. For example, the content of the potatogun.xml file could be - something like this: - - - - ... - - - - This would mean that the item overrides an item that has the identifier "harpoongun", - i.e. replaces harpoon guns with the potato gun. \ No newline at end of file + +This folder is the place where your own mods go. +Mods installed via the Workshop go elsewhere; if +you've published a mod and you don't have a copy +in this folder, go into the Publish tab and the +game should be able to create a copy for you. diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs index 1b0557f6e..7c8ab4a94 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/Character.cs @@ -566,9 +566,13 @@ namespace Barotrauma #elif SERVER if (value is { IsDead: true, Wallet: { Balance: var balance } grabbedWallet } && balance > 0) { - Wallet.Give(balance); + if (GameMain.GameSession.Campaign is MultiPlayerCampaign mpCampaign) + { + mpCampaign.Bank.Give(balance); + } + grabbedWallet.Deduct(balance); - GameServer.Log($"{Name} grabbed {value.Name}'s body and received {grabbedWallet.Balance} mk.", ServerLog.MessageType.Money); + GameServer.Log($"{GameServer.CharacterLogName(this)} grabbed {value.Name}'s body and received {grabbedWallet.Balance} mk.", ServerLog.MessageType.Money); } #endif } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Characters/CorpsePrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Characters/CorpsePrefab.cs index 3a415130a..2b9602b33 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Characters/CorpsePrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Characters/CorpsePrefab.cs @@ -40,6 +40,12 @@ namespace Barotrauma [Serialize(Level.PositionType.Wreck, IsPropertySaveable.No)] public Level.PositionType SpawnPosition { get; private set; } + [Serialize(0, IsPropertySaveable.No)] + public int MinMoney { get; private set; } + + [Serialize(0, IsPropertySaveable.No)] + public int MaxMoney { get; private set; } + public CorpsePrefab(ContentXElement element, CorpsesFile file) : base(element, file) { } public static CorpsePrefab Random(Rand.RandSync sync = Rand.RandSync.Unsynced) => Prefabs.GetRandom(sync); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MissionPrefab.cs b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MissionPrefab.cs index 0ac70c5c4..796ae18b0 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MissionPrefab.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Events/Missions/MissionPrefab.cs @@ -165,10 +165,14 @@ namespace Barotrauma TextManager.Get("missionfailed")).Fallback( GameSettings.CurrentConfig.Language == TextManager.DefaultLanguage ? element.GetAttributeString("failuremessage", "") : ""); - SonarLabel = - TextManager.Get($"MissionSonarLabel.{TextIdentifier}").Fallback( - TextManager.Get($"MissionSonarLabel.{element.GetAttributeString("sonarlabel", "")}")).Fallback( - element.GetAttributeString("sonarlabel", "")); + string sonarLabelTag = element.GetAttributeString("sonarlabel", ""); + + SonarLabel = + TextManager.Get($"MissionSonarLabel.{sonarLabelTag}") + .Fallback(TextManager.Get(sonarLabelTag)) + .Fallback(TextManager.Get($"MissionSonarLabel.{TextIdentifier}")) + .Fallback(element.GetAttributeString("sonarlabel", "")); + SonarIconIdentifier = element.GetAttributeIdentifier("sonaricon", ""); MultiplayerOnly = element.GetAttributeBool("multiplayeronly", false); diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/CargoManager.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/CargoManager.cs index 3d60228e2..2df3d5961 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/CargoManager.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/CargoManager.cs @@ -5,6 +5,7 @@ using Microsoft.Xna.Framework; using System; using System.Collections.Generic; using System.Linq; +using System.Text; using System.Xml.Linq; using Barotrauma.Networking; #if SERVER @@ -15,7 +16,9 @@ namespace Barotrauma { class PurchasedItem { - public ItemPrefab ItemPrefab { get; } + public ItemPrefab ItemPrefab => ItemPrefab.Prefabs[ItemPrefabIdentifier]; + public Identifier ItemPrefabIdentifier { get; } + public int Quantity { get; set; } public bool? IsStoreComponentEnabled { get; set; } @@ -23,7 +26,7 @@ namespace Barotrauma public PurchasedItem(ItemPrefab itemPrefab, int quantity, int buyerCharacterInfoId) { - ItemPrefab = itemPrefab; + ItemPrefabIdentifier = itemPrefab.Identifier; Quantity = quantity; IsStoreComponentEnabled = null; BuyerCharacterInfoId = buyerCharacterInfoId; @@ -34,8 +37,11 @@ namespace Barotrauma : this(itemPrefab, quantity, buyer: null) { } #endif public PurchasedItem(ItemPrefab itemPrefab, int quantity, Client buyer) + : this(itemPrefab.Identifier, quantity, buyer) { } + + public PurchasedItem(Identifier itemPrefabId, int quantity, Client buyer) { - ItemPrefab = itemPrefab; + ItemPrefabIdentifier = itemPrefabId; Quantity = quantity; IsStoreComponentEnabled = null; BuyerCharacterInfoId = buyer?.Character?.Info?.ID ?? Character.Controlled?.Info?.ID ?? 0; @@ -269,6 +275,24 @@ namespace Barotrauma OnItemsInSellFromSubCrateChanged?.Invoke(); } +#if SERVER + public void OnNewItemsPurchased(Identifier storeIdentifier, List newItems, Client client) + { + StringBuilder sb = new StringBuilder(); + int price = 0; + Dictionary buyValues = GetBuyValuesAtCurrentLocation(storeIdentifier, newItems.Select(i => i.ItemPrefab)); + foreach (PurchasedItem item in newItems) + { + int itemValue = item.Quantity * buyValues[item.ItemPrefab]; + sb.Append($"\n - {item.ItemPrefab.Name} x{item.Quantity}"); + price += itemValue; + + } + + GameServer.Log($"{NetworkMember.ClientLogName(client, client?.Name ?? "Unknown")} purchased {newItems.Count} item(s) for {TextManager.FormatCurrency(price)}{sb.ToString()}", ServerLog.MessageType.Money); + } +#endif + public void PurchaseItems(Identifier storeIdentifier, List itemsToPurchase, bool removeFromCrate, Client client = null) { var store = Location.GetStore(storeIdentifier); diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Wallet.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Wallet.cs index 1005729bc..795cb4680 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Wallet.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/Data/Wallet.cs @@ -32,7 +32,7 @@ namespace Barotrauma /// internal struct NetWalletUpdate : INetSerializableStruct { - [NetworkSerialize(ArrayMaxSize = NetConfig.MaxPlayers + 1)] + [NetworkSerialize(ArrayMaxSize = 256)] public NetWalletTransaction[] Transactions; } @@ -73,6 +73,9 @@ namespace Barotrauma { other.BalanceChanged = AddOptionalInt(other.BalanceChanged, BalanceChanged); other.RewardDistributionChanged = AddOptionalInt(other.RewardDistributionChanged, RewardDistributionChanged); + + other.BalanceChanged = TurnToNoneIfZero(other.BalanceChanged); + other.RewardDistributionChanged = TurnToNoneIfZero(other.RewardDistributionChanged); return other; static Option AddOptionalInt(Option a, Option b) @@ -94,6 +97,16 @@ namespace Barotrauma _ => throw new ArgumentOutOfRangeException(nameof(a)) }; } + + static Option TurnToNoneIfZero(Option option) + { + return option switch + { + Some s => s.Value == 0 ? Option.None() : option, + None _ => option, + _ => throw new ArgumentOutOfRangeException(nameof(option)) + }; + } } } diff --git a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/MultiPlayerCampaign.cs b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/MultiPlayerCampaign.cs index 781b6599e..a8c7034ef 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/MultiPlayerCampaign.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/GameSession/GameModes/MultiPlayerCampaign.cs @@ -251,7 +251,7 @@ namespace Barotrauma msg.Write((UInt16)storeItems.Value.Count); foreach (var item in storeItems.Value) { - msg.Write(item.ItemPrefab.Identifier); + msg.Write(item.ItemPrefabIdentifier); msg.WriteRangedInteger(item.Quantity, 0, CargoManager.MaxQuantity); } } @@ -270,7 +270,7 @@ namespace Barotrauma { Identifier itemId = msg.ReadIdentifier(); int quantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity); - items[storeId].Add(new PurchasedItem(ItemPrefab.Prefabs[itemId], quantity, sender)); + items[storeId].Add(new PurchasedItem(itemId, quantity, sender)); } } return items; @@ -303,7 +303,7 @@ namespace Barotrauma Identifier storeId = msg.ReadIdentifier(); soldItems.Add(storeId, new List()); UInt16 itemCount = msg.ReadUInt16(); - for (int j = 0; j < storeCount; j++) + for (int j = 0; j < itemCount; j++) { Identifier prefabId = msg.ReadIdentifier(); UInt16 itemId = msg.ReadUInt16(); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Fabricator.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Fabricator.cs index 4c6a29915..1b93ba4b9 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Fabricator.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Machines/Fabricator.cs @@ -187,17 +187,6 @@ namespace Barotrauma.Items.Components if (!isClient) { MoveIngredientsToInputContainer(selectedItem); - if (selectedItem.RequiredMoney > 0 && CanBeFabricated(fabricatedItem, availableIngredients, user)) - { - if (GameMain.GameSession?.GameMode is MultiPlayerCampaign) - { - user.Wallet.Deduct(selectedItem.RequiredMoney); - } - else if (GameMain.GameSession?.GameMode is CampaignMode campaign) - { - campaign.Bank.Deduct(selectedItem.RequiredMoney); - } - } } requiredTime = GetRequiredTime(fabricatedItem, user); @@ -211,9 +200,16 @@ namespace Barotrauma.Items.Components State = FabricatorState.Active; } #if SERVER - if (user != null && addToServerLog) + if (user != null && addToServerLog && selectedItem.RequiredMoney == 0) { - GameServer.Log(GameServer.CharacterLogName(user) + " started fabricating " + selectedItem.DisplayName.Value + " in " + item.Name, ServerLog.MessageType.ItemInteraction); + if (selectedItem.RequiredMoney > 0) + { + GameServer.Log($"{GameServer.CharacterLogName(user)} bought {selectedItem.DisplayName.Value} for {selectedItem.RequiredMoney} mk from {item.Name}", ServerLog.MessageType.Money); + } + else + { + GameServer.Log($"{GameServer.CharacterLogName(user)} started fabricating {selectedItem.DisplayName.Value} in {item.Name}", ServerLog.MessageType.ItemInteraction); + } } #endif } @@ -328,6 +324,19 @@ namespace Barotrauma.Items.Components return; } + if (fabricatedItem.RequiredMoney > 0) + { + if (user == null) { return; } + if (GameMain.GameSession?.GameMode is MultiPlayerCampaign) + { + user.Wallet.Deduct(fabricatedItem.RequiredMoney); + } + else if (GameMain.GameSession?.GameMode is CampaignMode campaign) + { + campaign.Bank.Deduct(fabricatedItem.RequiredMoney); + } + } + bool ingredientsStolen = false; bool ingredientsAllowStealing = true; diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/Connection.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/Connection.cs index cf2ab8fc8..f2c20f148 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/Connection.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/Connection.cs @@ -108,7 +108,8 @@ namespace Barotrauma.Items.Components foreach (XElement connectionElement in subElement.Elements()) { string prefabConnectionName = connectionElement.GetAttributeString("name", null); - if (prefabConnectionName == Name) + string[] aliases = connectionElement.GetAttributeStringArray("aliases", Array.Empty()); + if (prefabConnectionName == Name || aliases.Contains(Name)) { displayNameTag = connectionElement.GetAttributeString("displayname", ""); fallbackTag = connectionElement.GetAttributeString("fallbackdisplayname", ""); diff --git a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/LightComponent.cs b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/LightComponent.cs index 529490ecc..df7bc1b0e 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/LightComponent.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Items/Components/Signal/LightComponent.cs @@ -2,6 +2,7 @@ using System; using System.Xml.Linq; using Barotrauma.Networking; +using Barotrauma.Extensions; #if CLIENT using Microsoft.Xna.Framework.Graphics; using Barotrauma.Lights; @@ -173,7 +174,7 @@ namespace Barotrauma.Items.Components #if CLIENT if (Light != null) { - Light.Color = IsOn ? lightColor : Color.Transparent; + Light.Color = IsOn ? lightColor.Multiply(currentBrightness) : Color.Transparent; } #endif } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs index 4db3d907b..efc2b8ea2 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Map/Levels/Level.cs @@ -4170,6 +4170,12 @@ namespace Barotrauma selectedPrefab.GiveItems(corpse, wreck); corpse.Kill(CauseOfDeathType.Unknown, causeOfDeathAffliction: null, log: false); corpse.GiveIdCardTags(sp); +#if SERVER + if (selectedPrefab.MinMoney >= 0 && selectedPrefab.MaxMoney > 0) + { + corpse.Wallet.Give(Rand.Range(selectedPrefab.MinMoney, selectedPrefab.MaxMoney, Rand.RandSync.Unsynced)); + } +#endif spawnCounter++; static CorpsePrefab GetCorpsePrefab(Func predicate) diff --git a/Barotrauma/BarotraumaShared/SharedSource/Prefabs/PrefabWithUintIdentifier.cs b/Barotrauma/BarotraumaShared/SharedSource/Prefabs/PrefabWithUintIdentifier.cs index 541f15ed4..b3e5ecd2a 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Prefabs/PrefabWithUintIdentifier.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Prefabs/PrefabWithUintIdentifier.cs @@ -1,5 +1,4 @@ using System; -using System.Xml.Linq; namespace Barotrauma { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Serialization/SerializableProperty.cs b/Barotrauma/BarotraumaShared/SharedSource/Serialization/SerializableProperty.cs index d6f2ec544..765a62374 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Serialization/SerializableProperty.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Serialization/SerializableProperty.cs @@ -1007,19 +1007,6 @@ namespace Barotrauma } } } - else if (attributeName == "move") - { - Vector2 moveAmount = subElement.GetAttributeVector2("move", Vector2.Zero); - if (entity is Structure structure) - { - structure.Move(moveAmount); - } - else if (entity is Item item) - { - item.Move(moveAmount); - } - continue; - } if (entity.SerializableProperties.TryGetValue(attributeName, out SerializableProperty property)) { diff --git a/Barotrauma/BarotraumaShared/SharedSource/Text/LocalizedString/UpperLString.cs b/Barotrauma/BarotraumaShared/SharedSource/Text/LocalizedString/UpperLString.cs index 8c75fb7f0..84f49d9e7 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Text/LocalizedString/UpperLString.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Text/LocalizedString/UpperLString.cs @@ -13,7 +13,7 @@ namespace Barotrauma public override bool Loaded => nestedStr.Loaded; public override void RetrieveValue() { - cachedValue = nestedStr.Value.ToUpper(); + cachedValue = nestedStr.Value.ToUpperInvariant(); UpdateLanguage(); } diff --git a/Barotrauma/BarotraumaShared/SharedSource/Utils/SafeIO.cs b/Barotrauma/BarotraumaShared/SharedSource/Utils/SafeIO.cs index c4acca250..8cc88aee2 100644 --- a/Barotrauma/BarotraumaShared/SharedSource/Utils/SafeIO.cs +++ b/Barotrauma/BarotraumaShared/SharedSource/Utils/SafeIO.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using Barotrauma.Networking; +using Barotrauma.Steam; namespace Barotrauma.IO { @@ -31,6 +32,7 @@ namespace Barotrauma.IO string localModsDir = getFullPath(ContentPackage.LocalModsDir); string workshopModsDir = getFullPath(ContentPackage.WorkshopModsDir); #if CLIENT + string workshopStagingDir = getFullPath(SteamManager.Workshop.PublishStagingDir); string tempDownloadDir = getFullPath(ModReceiver.DownloadFolder); #endif @@ -49,6 +51,7 @@ namespace Barotrauma.IO && !pathStartsWith(localModsDir) #if CLIENT && !pathStartsWith(tempDownloadDir) + && !pathStartsWith(workshopStagingDir) #endif && (extension == ".dll" || extension == ".exe" || extension == ".json")) { @@ -284,6 +287,11 @@ namespace Barotrauma.IO //TODO: validate recursion? System.IO.Directory.Delete(path, recursive); } + + public static DateTime GetLastWriteTime(string path) + { + return System.IO.Directory.GetLastWriteTime(path); + } } public static class File diff --git a/Barotrauma/BarotraumaShared/changelog.txt b/Barotrauma/BarotraumaShared/changelog.txt index 47b8ebbe4..477ceee04 100644 --- a/Barotrauma/BarotraumaShared/changelog.txt +++ b/Barotrauma/BarotraumaShared/changelog.txt @@ -1,3 +1,36 @@ +--------------------------------------------------------------------------------------------------------- +v0.17.9.0 +--------------------------------------------------------------------------------------------------------- + +Changes (unstable only): +- Added tickboxes to select/deselect items in bulk in the mod transfer screen + added button to skip the mod transfer screen. +- Move grabbed body wallet funds to the campaign bank instead of the personal wallet. +- Made items sold go into the personal wallet instead of campaign bank. +- Added a server log line for buying items from the store. + +Fixes (unstable only): +- Fixed local mod write time not always being correct. +- Fixed new outpost events using the same event sprite. +- Fixed "captive souls" event not giving a reward. +- Fixed conversation hanging on an option in the "explosive mishap" event. +- Spawn mudraptor eggs instead of an adult mudraptor in the "occupational hazards" event. +- Fixed latter half of the "occupational hazards" event not triggering correctly. +- Fixed vending machines stealing your money if you don't have x2 of the price of the item. +- Fixed some missions that spawn multiple monsters having incorrect/inaccurate sonar labels (e.g. giant spineling mission displaying "giant spineling" on the small ones too, same for the crawler broodmother mission). +- Fixed wallet failing to sync when the server has been modified to support more than 16 players per server. +- Fixed error when receiving a multiplayer campaign sync message while downloading mods. +- Fixed sub editor's wiring panel listing the wires in a random order. +- Fixed z-fighting plants in colonies. +- Fixed "-0 mk" popup when someone adds something to the store cart. +- Fixed "Failed to parse the string "GUI.ITEMQUALITYCOLORGOOD" to Color" errors. +- 2nd attempt to fix a null reference exception when a client joins a server where a round is running with respawns disabled. +- Fixed errors when attempting to publish a mod with exe files. +- Fixed inability to set the salary distribution to certain values (e.g. 5%, 10%, 15%). +- Fixed spectate button still not appearing if the round starts while you're downloading mods from the server, and the other way around, spectate button still being visible if the round ends. +- Fixed stores becoming unusable after items have been sold in multiplayer. +- Fixed tiny faction icons in the round summary. +- Fixed some structure/item sprites sometimes failing to load, making them appear invisible in-game. + --------------------------------------------------------------------------------------------------------- v0.17.8.0 ---------------------------------------------------------------------------------------------------------