Unstable 0.17.4.0

This commit is contained in:
Markus Isberg
2022-03-30 00:08:09 +09:00
parent 2968e23ae8
commit c1b8e5a341
177 changed files with 3388 additions and 1977 deletions
@@ -5,7 +5,7 @@ namespace Barotrauma
{
partial class Character
{
public static Character Controlled = null;
public static Character Controlled => null;
partial void OnAttackedProjSpecific(Character attacker, AttackResult attackResult, float stun)
{
@@ -424,7 +424,7 @@ namespace Barotrauma
msg.Write(owner == c && owner.Character == this);
msg.Write(owner != null && owner.Character == this && GameMain.Server.ConnectedClients.Contains(owner) ? owner.ID : (byte)0);
break;
case StatusEventData _:
case CharacterStatusEventData _:
WriteStatus(msg);
break;
case UpdateSkillsEventData _:
@@ -657,6 +657,10 @@ namespace Barotrauma
int infoLength = msg.LengthBytes - msgLengthBeforeInfo;
msg.Write((byte)CampaignInteractionType);
if (CampaignInteractionType == CampaignMode.InteractionType.Store)
{
msg.Write(MerchantIdentifier);
}
int msgLengthBeforeOrders = msg.LengthBytes;
// Current orders
@@ -7,51 +7,57 @@ namespace Barotrauma
{
partial class CargoManager
{
public void SellBackPurchasedItems(List<PurchasedItem> itemsToSell, Client client = null)
public void SellBackPurchasedItems(Identifier storeIdentifier, List<PurchasedItem> itemsToSell, Client client = null)
{
// Check all the prices before starting the transaction
// to make sure the modifiers stay the same for the whole transaction
Dictionary<ItemPrefab, int> buyValues = GetBuyValuesAtCurrentLocation(itemsToSell.Select(i => i.ItemPrefab));
foreach (PurchasedItem item in itemsToSell)
// Check all the prices before starting the transaction to make sure the modifiers stay the same for the whole transaction
var buyValues = GetBuyValuesAtCurrentLocation(storeIdentifier, itemsToSell.Select(i => i.ItemPrefab));
var store = Location.GetStore(storeIdentifier);
if (store == null) { return; }
var storeSpecificItems = GetPurchasedItems(storeIdentifier);
foreach (var item in itemsToSell)
{
var itemValue = item.Quantity * buyValues[item.ItemPrefab];
Location.StoreCurrentBalance -= itemValue;
store.Balance -= itemValue;
campaign.GetWallet(client).Give(itemValue);
PurchasedItems.Remove(item);
storeSpecificItems?.Remove(item);
}
}
public void BuyBackSoldItems(List<SoldItem> itemsToBuy, Client client)
public void BuyBackSoldItems(Identifier storeIdentifier, List<SoldItem> itemsToBuy)
{
// Check all the prices before starting the transaction
// to make sure the modifiers stay the same for the whole transaction
var sellValues = GetSellValuesAtCurrentLocation(itemsToBuy.Select(i => i.ItemPrefab));
var store = Location.GetStore(storeIdentifier);
if (store == null) { return; }
var storeSpecificItems = SoldItems.GetValueOrDefault(storeIdentifier);
// Check all the prices before starting the transaction to make sure the modifiers stay the same for the whole transaction
var sellValues = GetSellValuesAtCurrentLocation(storeIdentifier, itemsToBuy.Select(i => i.ItemPrefab));
foreach (var item in itemsToBuy)
{
int itemValue = sellValues[item.ItemPrefab];
if (Location.StoreCurrentBalance < itemValue || item.Removed) { continue; }
Location.StoreCurrentBalance += itemValue;
if (store.Balance < itemValue || item.Removed) { continue; }
store.Balance += itemValue;
campaign.Bank.TryDeduct(itemValue);
SoldItems.Remove(item);
storeSpecificItems.Remove(item);
}
}
public void SellItems(List<SoldItem> itemsToSell, Client client)
public void SellItems(Identifier storeIdentifier, List<SoldItem> itemsToSell, Client client)
{
var store = Location.GetStore(storeIdentifier);
if (store == null) { return; }
bool canAddToRemoveQueue = (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer) && Entity.Spawner != null;
IEnumerable<Item> sellableItemsInSub = Enumerable.Empty<Item>();
if (canAddToRemoveQueue && itemsToSell.Any(i => i.Origin == SoldItem.SellOrigin.Submarine && i.ID == Entity.NullEntityID && !i.Removed))
{
sellableItemsInSub = GetSellableItemsFromSub();
}
// Check all the prices before starting the transaction
// to make sure the modifiers stay the same for the whole transaction
var sellValues = GetSellValuesAtCurrentLocation(itemsToSell.Select(i => i.ItemPrefab));
var itemsSoldAtStore = SoldItems.GetValueOrDefault(storeIdentifier);
// Check all the prices before starting the transaction to make sure the modifiers stay the same for the whole transaction
var sellValues = GetSellValuesAtCurrentLocation(storeIdentifier, itemsToSell.Select(i => i.ItemPrefab));
foreach (var item in itemsToSell)
{
int itemValue = sellValues[item.ItemPrefab];
// check if the store can afford the item and if the item hasn't been removed already
if (Location.StoreCurrentBalance < itemValue || item.Removed) { continue; }
if (store.Balance < itemValue || item.Removed) { continue; }
// Server determines the items that are sold from the sub in multiplayer
if (item.Origin == SoldItem.SellOrigin.Submarine && item.ID == Entity.NullEntityID && !item.Removed)
{
@@ -66,8 +72,8 @@ namespace Barotrauma
item.Removed = true;
Entity.Spawner.AddItemToRemoveQueue(entity);
}
SoldItems.Add(item);
Location.StoreCurrentBalance -= itemValue;
itemsSoldAtStore?.Add(item);
store.Balance -= itemValue;
campaign.Bank.Give(itemValue);
GameAnalyticsManager.AddMoneyGainedEvent(itemValue, GameAnalyticsManager.MoneySource.Store, item.ItemPrefab.Identifier.Value);
}
@@ -616,8 +616,17 @@ namespace Barotrauma
}
// Store balance
msg.Write(true);
msg.Write((UInt16)map.CurrentLocation.StoreCurrentBalance);
bool hasStores = map.CurrentLocation.Stores != null && map.CurrentLocation.Stores.Any();
msg.Write(hasStores);
if (hasStores)
{
msg.Write((byte)map.CurrentLocation.Stores.Count);
foreach (var store in map.CurrentLocation.Stores.Values)
{
msg.Write(store.Identifier);
msg.Write((UInt16)store.Balance);
}
}
}
else
{
@@ -626,36 +635,10 @@ namespace Barotrauma
msg.Write(false);
}
msg.Write((UInt16)CargoManager.ItemsInBuyCrate.Count);
foreach (PurchasedItem pi in CargoManager.ItemsInBuyCrate)
{
msg.Write(pi.ItemPrefab.Identifier);
msg.WriteRangedInteger(pi.Quantity, 0, CargoManager.MaxQuantity);
}
msg.Write((UInt16)CargoManager.ItemsInSellFromSubCrate.Count);
foreach (PurchasedItem pi in CargoManager.ItemsInSellFromSubCrate)
{
msg.Write(pi.ItemPrefab.Identifier);
msg.WriteRangedInteger(pi.Quantity, 0, CargoManager.MaxQuantity);
}
msg.Write((UInt16)CargoManager.PurchasedItems.Count);
foreach (PurchasedItem pi in CargoManager.PurchasedItems)
{
msg.Write(pi.ItemPrefab.Identifier);
msg.WriteRangedInteger(pi.Quantity, 0, CargoManager.MaxQuantity);
}
msg.Write((UInt16)CargoManager.SoldItems.Count);
foreach (SoldItem si in CargoManager.SoldItems)
{
msg.Write(si.ItemPrefab.Identifier);
msg.Write((UInt16)si.ID);
msg.Write(si.Removed);
msg.Write(si.SellerID);
msg.Write((byte)si.Origin);
}
WriteItems(msg, CargoManager.ItemsInBuyCrate);
WriteItems(msg, CargoManager.ItemsInSellFromSubCrate);
WriteItems(msg, CargoManager.PurchasedItems);
WriteItems(msg, CargoManager.SoldItems);
msg.Write((ushort)UpgradeManager.PendingUpgrades.Count);
foreach (var (prefab, category, level) in UpgradeManager.PendingUpgrades)
@@ -700,44 +683,10 @@ namespace Barotrauma
bool purchasedItemRepairs = msg.ReadBoolean();
bool purchasedLostShuttles = msg.ReadBoolean();
UInt16 buyCrateItemCount = msg.ReadUInt16();
List<PurchasedItem> buyCrateItems = new List<PurchasedItem>();
for (int i = 0; i < buyCrateItemCount; i++)
{
string itemPrefabIdentifier = msg.ReadString();
int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
buyCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity, sender));
}
UInt16 subSellCrateItemCount = msg.ReadUInt16();
List<PurchasedItem> subSellCrateItems = new List<PurchasedItem>();
for (int i = 0; i < subSellCrateItemCount; i++)
{
string itemPrefabIdentifier = msg.ReadString();
int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
subSellCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity, sender));
}
UInt16 purchasedItemCount = msg.ReadUInt16();
List<PurchasedItem> purchasedItems = new List<PurchasedItem>();
for (int i = 0; i < purchasedItemCount; i++)
{
string itemPrefabIdentifier = msg.ReadString();
int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity, sender));
}
UInt16 soldItemCount = msg.ReadUInt16();
List<SoldItem> soldItems = new List<SoldItem>();
for (int i = 0; i < soldItemCount; i++)
{
string itemPrefabIdentifier = msg.ReadString();
UInt16 id = msg.ReadUInt16();
bool removed = msg.ReadBoolean();
byte sellerId = msg.ReadByte();
byte origin = msg.ReadByte();
soldItems.Add(new SoldItem(ItemPrefab.Prefabs[itemPrefabIdentifier], id, removed, sellerId, (SoldItem.SellOrigin)origin));
}
var buyCrateItems = ReadPurchasedItems(msg, sender);
var subSellCrateItems = ReadPurchasedItems(msg, sender);
var purchasedItems = ReadPurchasedItems(msg, sender);
var soldItems = ReadSoldItems(msg);
ushort purchasedUpgradeCount = msg.ReadUInt16();
List<PurchasedUpgrade> purchasedUpgrades = new List<PurchasedUpgrade>();
@@ -839,42 +788,83 @@ namespace Barotrauma
bool allowedToUseStore = AllowedToManageCampaign(sender, ClientPermissions.CampaignStore);
if (allowedToManageCampaign || allowedToUseStore || AllowedToManageCampaign(sender, ClientPermissions.BuyItems))
{
var currentBuyCrateItems = new List<PurchasedItem>(CargoManager.ItemsInBuyCrate);
currentBuyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, -i.Quantity, sender));
buyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, i.Quantity, sender));
CargoManager.SellBackPurchasedItems(new List<PurchasedItem>(CargoManager.PurchasedItems));
CargoManager.PurchaseItems(purchasedItems, false, sender);
var prevBuyCrateItems = new Dictionary<Identifier, List<PurchasedItem>>(CargoManager.ItemsInBuyCrate);
foreach (var store in prevBuyCrateItems)
{
foreach (var item in store.Value)
{
CargoManager.ModifyItemQuantityInBuyCrate(store.Key, item.ItemPrefab, -item.Quantity, sender);
}
}
foreach (var store in buyCrateItems)
{
foreach (var item in store.Value)
{
CargoManager.ModifyItemQuantityInBuyCrate(store.Key, item.ItemPrefab, item.Quantity, sender);
}
}
var prevPurchasedItems = new Dictionary<Identifier, List<PurchasedItem>>(CargoManager.PurchasedItems);
foreach (var store in prevPurchasedItems)
{
CargoManager.SellBackPurchasedItems(store.Key, store.Value);
}
foreach (var store in purchasedItems)
{
CargoManager.PurchaseItems(store.Key, store.Value, false, sender);
}
}
bool allowedToSellSubItems = AllowedToManageCampaign(sender, ClientPermissions.SellSubItems);
if (allowedToManageCampaign || allowedToUseStore || allowedToSellSubItems)
{
var currentSubSellCrateItems = new List<PurchasedItem>(CargoManager.ItemsInSellFromSubCrate);
currentSubSellCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInSubSellCrate(i.ItemPrefab, -i.Quantity, sender));
subSellCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInSubSellCrate(i.ItemPrefab, i.Quantity, sender));
var prevSubSellCrateItems = new Dictionary<Identifier, List<PurchasedItem>>(CargoManager.ItemsInSellFromSubCrate);
foreach (var store in prevSubSellCrateItems)
{
foreach (var item in store.Value)
{
CargoManager.ModifyItemQuantityInSubSellCrate(store.Key, item.ItemPrefab, -item.Quantity, sender);
}
}
foreach (var store in subSellCrateItems)
{
foreach (var item in store.Value)
{
CargoManager.ModifyItemQuantityInSubSellCrate(store.Key, item.ItemPrefab, item.Quantity, sender);
}
}
}
bool allowedToSellInventoryItems = AllowedToManageCampaign(sender, ClientPermissions.SellInventoryItems);
if (allowedToManageCampaign || allowedToUseStore || (allowedToSellInventoryItems && allowedToSellSubItems))
{
// for some reason CargoManager.SoldItem is never cleared by the server, I've added a check to SellItems that ignores all
// sold items that are removed so they should be discarded on the next message
CargoManager.BuyBackSoldItems(new List<SoldItem>(CargoManager.SoldItems), sender);
CargoManager.SellItems(soldItems, sender);
var prevSoldItems = new Dictionary<Identifier, List<SoldItem>>(CargoManager.SoldItems);
foreach (var store in prevSoldItems)
{
CargoManager.BuyBackSoldItems(store.Key, store.Value);
}
foreach (var store in soldItems)
{
CargoManager.SellItems(store.Key, store.Value, sender);
}
}
else if (allowedToSellInventoryItems || allowedToSellSubItems)
{
if (allowedToSellInventoryItems)
var prevSoldItems = new Dictionary<Identifier, List<SoldItem>>(CargoManager.SoldItems);
foreach (var store in prevSoldItems)
{
CargoManager.BuyBackSoldItems(new List<SoldItem>(CargoManager.SoldItems.Where(i => i.Origin == SoldItem.SellOrigin.Character)), sender);
soldItems.RemoveAll(i => i.Origin != SoldItem.SellOrigin.Character);
store.Value.RemoveAll(predicate);
CargoManager.BuyBackSoldItems(store.Key, store.Value);
}
else
foreach (var store in soldItems)
{
CargoManager.BuyBackSoldItems(new List<SoldItem>(CargoManager.SoldItems.Where(i => i.Origin == SoldItem.SellOrigin.Submarine)), sender);
soldItems.RemoveAll(i => i.Origin != SoldItem.SellOrigin.Submarine);
store.Value.RemoveAll(predicate);
}
CargoManager.SellItems(soldItems, sender);
foreach (var store in soldItems)
{
CargoManager.SellItems(store.Key, store.Value, sender);
}
bool predicate(SoldItem i) => allowedToSellInventoryItems != (i.Origin == SoldItem.SellOrigin.Character);
}
if (allowedToManageCampaign)
@@ -960,7 +950,7 @@ namespace Barotrauma
public void ServerReadRewardDistribution(IReadMessage msg, Client sender)
{
NetWalletSalaryUpdate update = INetSerializableStruct.Read<NetWalletSalaryUpdate>(msg);
NetWalletSetSalaryUpdate update = INetSerializableStruct.Read<NetWalletSetSalaryUpdate>(msg);
if (!AllowedToManageCampaign(sender)) { return; }
@@ -42,8 +42,8 @@ namespace Barotrauma.Items.Components
msg.Write(item.CurrentHull?.ID ?? Entity.NullEntityID);
msg.Write(item.SimPosition.X);
msg.Write(item.SimPosition.Y);
msg.Write(stickJoint.Axis.X);
msg.Write(stickJoint.Axis.Y);
msg.Write(jointAxis.X);
msg.Write(jointAxis.Y);
if (StickTarget.UserData is Structure structure)
{
msg.Write(structure.ID);
@@ -56,7 +56,6 @@ namespace Barotrauma
if (containerIndex < 0)
{
throw error($"container index out of range ({containerIndex})");
break;
}
if (!(components[containerIndex] is ItemContainer itemContainer))
{
@@ -66,7 +65,7 @@ namespace Barotrauma
msg.Write(GameMain.Server.EntityEventManager.Events.Last()?.ID ?? (ushort)0);
itemContainer.Inventory.ServerEventWrite(msg, c);
break;
case StatusEventData _:
case ItemStatusEventData _:
msg.Write(condition);
break;
case AssignCampaignInteractionEventData _:
@@ -1,12 +1,13 @@
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using System;
using System.Xml.Linq;
namespace Barotrauma.MapCreatures.Behavior
{
partial class BallastFloraBehavior
{
const float DamageUpdateInterval = 1.0f;
private float damageUpdateTimer;
partial void LoadPrefab(ContentXElement element)
@@ -31,16 +32,38 @@ namespace Barotrauma.MapCreatures.Behavior
}
}
partial void UpdateDamage(float deltaTime)
{
damageUpdateTimer -= deltaTime;
if (damageUpdateTimer > 0.0f) { return; }
const int maxMessagesPerSecond = 10;
int messages = 0;
foreach (BallastFloraBranch branch in Branches)
{
//don't notify about minuscule amounts of damage (<= 1.0f)
if (branch.AccumulatedDamage > 1.0f)
{
CreateNetworkMessage(new BranchDamageEventData(branch));
branch.AccumulatedDamage = 0.0f;
messages++;
//throttle a bit: if a large ballast flora is withering, it can lead to a very large number of events otherwise
if (messages > maxMessagesPerSecond) { break; }
}
}
damageUpdateTimer = DamageUpdateInterval;
}
public void ServerWrite(IWriteMessage msg, IEventData eventData)
{
msg.Write((byte)eventData.NetworkHeader);
switch (eventData)
{
case SpawnEventData spawnEventData:
case SpawnEventData _:
ServerWriteSpawn(msg);
break;
case KillEventData killEventData:
case KillEventData _:
//do nothing
break;
case BranchCreateEventData branchCreateEventData:
@@ -72,6 +95,7 @@ namespace Barotrauma.MapCreatures.Behavior
var (x, y) = branch.Position;
msg.Write(parentId);
msg.Write((int)branch.ID);
msg.Write(branch.IsRootGrowth);
msg.WriteRangedInteger((byte)branch.Type, 0b0000, 0b1111);
msg.WriteRangedInteger((byte)branch.Sides, 0b0000, 0b1111);
msg.WriteRangedInteger(branch.FlowerConfig.Serialize(), 0, 0xFFF);
@@ -103,7 +127,7 @@ namespace Barotrauma.MapCreatures.Behavior
msg.Write(branch.ID);
}
public void SendNetworkMessage(IEventData extraData)
public void CreateNetworkMessage(IEventData extraData)
{
GameMain.Server.CreateEntityEvent(Parent, new Hull.BallastFloraEventData(this, extraData));
}
@@ -28,7 +28,11 @@ namespace Barotrauma.Networking
public static string GetCompressedModPath(ContentPackage mod)
{
string dir = mod.Dir;
string resultFileName = dir.Replace('\\', '_').Replace('/', '_');
string resultFileName
= dir.StartsWith(ContentPackage.LocalModsDir)
? $"Local_{mod.Name}"
: $"Workshop_{mod.Name}";
resultFileName = ToolBox.RemoveInvalidFileNameChars(resultFileName.Replace('\\', '_').Replace('/', '_'));
resultFileName = $"{resultFileName}{Extension}";
return Path.Combine(UploadFolder, resultFileName);
}
@@ -814,7 +814,7 @@ namespace Barotrauma.Networking
case ClientPacketHeader.CREW:
ReadCrewMessage(inc, connectedClient);
break;
case ClientPacketHeader.MONEY:
case ClientPacketHeader.TRANSFER_MONEY:
ReadMoneyMessage(inc, connectedClient);
break;
case ClientPacketHeader.REWARD_DISTRIBUTION:
@@ -321,11 +321,16 @@ namespace Barotrauma.Networking
GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled);
HiddenSubs.UnionWith(doc.Root.GetAttributeStringArray("HiddenSubs", Array.Empty<string>()));
if (HiddenSubs.Any())
{
UpdateFlag(NetFlags.HiddenSubs);
}
SelectedSubmarine = SelectNonHiddenSubmarine(SelectedSubmarine);
string[] defaultAllowedClientNameChars =
new string[] {
new string[]
{
"32-33",
"38-46",
"48-57",
@@ -16,7 +16,7 @@ namespace Barotrauma
Role = role;
Character = character;
Character.IsTraitor = true;
GameMain.NetworkMember.CreateEntityEvent(Character, new Character.StatusEventData());
GameMain.NetworkMember.CreateEntityEvent(Character, new Character.CharacterStatusEventData());
}
public delegate void MessageSender(string message);