Merge branch 'dev' of https://github.com/Regalis11/Barotrauma.git into unstable-tests

This commit is contained in:
Evil Factory
2022-04-11 15:58:36 -03:00
38 changed files with 361 additions and 184 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -3796,20 +3796,27 @@ namespace Barotrauma
OnSelected = SelectWire
};
List<ItemPrefab> wirePrefabs = new List<ItemPrefab>();
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)
};
}

View File

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

View File

@@ -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<LocalizedString>());
TaskPool.Add(
@@ -29,6 +39,7 @@ namespace Barotrauma.Steam
internal static void SubscribeToServerMods(IEnumerable<UInt64> missingIds, string rejoinEndpoint, ulong rejoinLobby, string rejoinServerName)
{
CloseAllMessageBoxes();
GUIMessageBox msgBox = new GUIMessageBox(headerText: "", text: TextManager.Get("PreparingWorkshopDownloads"),
buttons: Array.Empty<LocalizedString>());
TaskPool.Add(

View File

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

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>0.17.8.0</Version>
<Version>0.17.9.0</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.17.8.0</Version>
<Version>0.17.9.0</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.17.8.0</Version>
<Version>0.17.9.0</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.17.8.0</Version>
<Version>0.17.9.0</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.17.8.0</Version>
<Version>0.17.9.0</Version>
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>

View File

@@ -23,7 +23,7 @@ namespace Barotrauma
}
}
public void BuyBackSoldItems(Identifier storeIdentifier, List<SoldItem> itemsToBuy)
public void BuyBackSoldItems(Identifier storeIdentifier, List<SoldItem> 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<SoldItem> itemsToSell)
public void SellItems(Identifier storeIdentifier, List<SoldItem> 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();

View File

@@ -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<PurchasedItem> newItems = new List<PurchasedItem>();
List<PurchasedItem> 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<Identifier, List<PurchasedItem>>(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<Identifier, List<SoldItem>>(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)

View File

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

View File

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

View File

@@ -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:
<contentpackage name="BestModEver" path="Mods/BestModEver/filelist.xml" gameversion="0.9.1.0" corepackage="true">
<Item file="Mods/BestModEver/items.xml" />
<Character file="Mods/BestModEver/Human/Human.xml" />
<Character file="Mods/BestModEver/Cthulhu/cthulhu.xml" />
<Character file="Content/Characters/Crawler/crawler.xml" />
<Structure file="Content/Map/StructurePrefabs.xml" />
<Jobs file="Content/Jobs.xml" />
<RandomEvents file="Mods/BestModEver/randomevents.xml" />
<Executable file="Barotrauma.exe" />
</contentpackage>
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:
<contentpackage name="BestModEver" path="Mods/PotatoGun/filelist.xml" gameversion="0.9.1.0" corepackage="false">
<Item file="Mods/PotatoGun/potatogun.xml" />
</contentpackage>
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:
<Override>
<Item name="Potato Gun" identifier="harpoongun">
...
</Item>
</Override>
This would mean that the item overrides an item that has the identifier "harpoongun",
i.e. replaces harpoon guns with the potato gun.
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.

View File

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

View File

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

View File

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

View File

@@ -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<PurchasedItem> newItems, Client client)
{
StringBuilder sb = new StringBuilder();
int price = 0;
Dictionary<ItemPrefab, int> 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<PurchasedItem> itemsToPurchase, bool removeFromCrate, Client client = null)
{
var store = Location.GetStore(storeIdentifier);

View File

@@ -32,7 +32,7 @@ namespace Barotrauma
/// </summary>
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<int> AddOptionalInt(Option<int> a, Option<int> b)
@@ -94,6 +97,16 @@ namespace Barotrauma
_ => throw new ArgumentOutOfRangeException(nameof(a))
};
}
static Option<int> TurnToNoneIfZero(Option<int> option)
{
return option switch
{
Some<int> s => s.Value == 0 ? Option<int>.None() : option,
None<int> _ => option,
_ => throw new ArgumentOutOfRangeException(nameof(option))
};
}
}
}

View File

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

View File

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

View File

@@ -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<string>());
if (prefabConnectionName == Name || aliases.Contains(Name))
{
displayNameTag = connectionElement.GetAttributeString("displayname", "");
fallbackTag = connectionElement.GetAttributeString("fallbackdisplayname", "");

View File

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

View File

@@ -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<CorpsePrefab, bool> predicate)

View File

@@ -1,5 +1,4 @@
using System;
using System.Xml.Linq;
namespace Barotrauma
{

View File

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

View File

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

View File

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

View File

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