Unstable 0.17.1.0

This commit is contained in:
Markus Isberg
2022-03-17 01:25:04 +09:00
parent 3974067915
commit 6d410cc1b7
302 changed files with 5878 additions and 3317 deletions
@@ -12,6 +12,22 @@ namespace Barotrauma
partial class MultiPlayerCampaign : CampaignMode
{
private readonly List<CharacterCampaignData> characterData = new List<CharacterCampaignData>();
private readonly Dictionary<ushort, Wallet> walletsToCheck = new Dictionary<ushort, Wallet>();
private readonly HashSet<NetWalletTransaction> transactions = new HashSet<NetWalletTransaction>();
private const float clientCheckInterval = 10;
private float clientCheckTimer = clientCheckInterval;
public override Wallet GetWallet(Client client = null)
{
if (client is null) { throw new ArgumentNullException(nameof(client), "Client should not be null in multiplayer"); }
if (client.Character is { } character)
{
return character.Wallet;
}
return Wallet.Invalid;
}
private bool forceMapUI;
public bool ForceMapUI
@@ -229,8 +245,7 @@ namespace Barotrauma
characterInfo.CauseOfDeath = null;
}
c.CharacterInfo = characterInfo;
characterData.RemoveAll(cd => cd.MatchesClient(c));
characterData.Add(new CharacterCampaignData(c));
SetClientCharacterData(c);
}
//refresh the character data of clients who aren't in the server anymore
@@ -412,8 +427,8 @@ namespace Barotrauma
LastSaveID++;
}
public bool CanPurchaseSub(SubmarineInfo info)
=> info.Price <= Money && GetCampaignSubs().Contains(info);
public bool CanPurchaseSub(SubmarineInfo info, Client client)
=> GetWallet(client).CanAfford(info.Price) && GetCampaignSubs().Contains(info);
public void DiscardClientCharacterData(Client client)
{
@@ -487,6 +502,54 @@ namespace Barotrauma
KeepCharactersCloseToOutpost(deltaTime);
}
}
UpdateClientsToCheck(deltaTime);
UpdateWallets();
}
private void UpdateClientsToCheck(float deltaTime)
{
if (clientCheckTimer < clientCheckInterval)
{
clientCheckTimer += deltaTime;
return;
}
clientCheckTimer = 0;
walletsToCheck.Clear();
walletsToCheck.Add(0, Bank);
foreach (Character character in Mission.GetSalaryEligibleCrew())
{
walletsToCheck.Add(character.ID, character.Wallet);
}
}
private void UpdateWallets()
{
foreach (var (id, wallet) in walletsToCheck)
{
if (wallet.HasTransactions())
{
transactions.Add(wallet.DequeueAndMergeTransactions(id));
}
}
if (transactions.Count == 0) { return; }
NetWalletUpdate walletUpdate = new NetWalletUpdate
{
Transactions = transactions.ToArray()
};
transactions.Clear();
foreach (Client client in GameMain.Server.ConnectedClients)
{
IWriteMessage msg = new WriteOnlyMessage().WithHeader(ServerPacketHeader.MONEY);
((INetSerializableStruct)walletUpdate).Write(msg);
GameMain.Server?.ServerPeer?.Send(msg, client.Connection, DeliveryMethod.Reliable);
}
}
public override void End(TransitionType transitionType = TransitionType.None)
@@ -530,7 +593,6 @@ namespace Barotrauma
msg.Write(ForceMapUI);
msg.Write(Money);
msg.Write(PurchasedHullRepairs);
msg.Write(PurchasedItemRepairs);
msg.Write(PurchasedLostShuttles);
@@ -644,7 +706,7 @@ namespace Barotrauma
{
string itemPrefabIdentifier = msg.ReadString();
int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
buyCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
buyCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity, sender));
}
UInt16 subSellCrateItemCount = msg.ReadUInt16();
@@ -653,7 +715,7 @@ namespace Barotrauma
{
string itemPrefabIdentifier = msg.ReadString();
int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
subSellCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
subSellCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity, sender));
}
UInt16 purchasedItemCount = msg.ReadUInt16();
@@ -662,7 +724,7 @@ namespace Barotrauma
{
string itemPrefabIdentifier = msg.ReadString();
int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity, sender));
}
UInt16 soldItemCount = msg.ReadUInt16();
@@ -711,57 +773,63 @@ namespace Barotrauma
int hullRepairCost = location?.GetAdjustedMechanicalCost(HullRepairCost) ?? HullRepairCost;
int itemRepairCost = location?.GetAdjustedMechanicalCost(ItemRepairCost) ?? ItemRepairCost;
int shuttleRetrieveCost = location?.GetAdjustedMechanicalCost(ShuttleReplaceCost) ?? ShuttleReplaceCost;
if (purchasedHullRepairs != this.PurchasedHullRepairs)
Wallet personalWallet = GetWallet(sender);
if (purchasedHullRepairs != PurchasedHullRepairs)
{
if (purchasedHullRepairs && Money >= hullRepairCost)
switch (purchasedHullRepairs)
{
this.PurchasedHullRepairs = true;
Money -= hullRepairCost;
GameAnalyticsManager.AddMoneySpentEvent(hullRepairCost, GameAnalyticsManager.MoneySink.Service, "hullrepairs");
}
else if (!purchasedHullRepairs)
{
this.PurchasedHullRepairs = false;
Money += hullRepairCost;
case true when personalWallet.CanAfford(hullRepairCost):
personalWallet.Deduct(hullRepairCost);
PurchasedHullRepairs = true;
GameAnalyticsManager.AddMoneySpentEvent(hullRepairCost, GameAnalyticsManager.MoneySink.Service, "hullrepairs");
break;
case false:
PurchasedHullRepairs = false;
personalWallet.Refund(hullRepairCost);
break;
}
}
if (purchasedItemRepairs != this.PurchasedItemRepairs)
if (purchasedItemRepairs != PurchasedItemRepairs)
{
if (purchasedItemRepairs && Money >= itemRepairCost)
switch (purchasedItemRepairs)
{
this.PurchasedItemRepairs = true;
Money -= itemRepairCost;
GameAnalyticsManager.AddMoneySpentEvent(itemRepairCost, GameAnalyticsManager.MoneySink.Service, "devicerepairs");
}
else if (!purchasedItemRepairs)
{
this.PurchasedItemRepairs = false;
Money += itemRepairCost;
case true when personalWallet.CanAfford(itemRepairCost):
personalWallet.Deduct(itemRepairCost);
PurchasedItemRepairs = true;
GameAnalyticsManager.AddMoneySpentEvent(itemRepairCost, GameAnalyticsManager.MoneySink.Service, "devicerepairs");
break;
case false:
PurchasedItemRepairs = false;
personalWallet.Refund(itemRepairCost);
break;
}
}
if (purchasedLostShuttles != this.PurchasedLostShuttles)
if (purchasedLostShuttles != PurchasedLostShuttles)
{
if (GameMain.GameSession?.SubmarineInfo != null &&
GameMain.GameSession.SubmarineInfo.LeftBehindSubDockingPortOccupied)
if (GameMain.GameSession?.SubmarineInfo != null && GameMain.GameSession.SubmarineInfo.LeftBehindSubDockingPortOccupied)
{
GameMain.Server.SendDirectChatMessage(TextManager.FormatServerMessage("ReplaceShuttleDockingPortOccupied"), sender, ChatMessageType.MessageBox);
}
else if (purchasedLostShuttles && Money >= shuttleRetrieveCost)
else if (purchasedLostShuttles && personalWallet.TryDeduct(shuttleRetrieveCost))
{
this.PurchasedLostShuttles = true;
Money -= shuttleRetrieveCost;
PurchasedLostShuttles = true;
GameAnalyticsManager.AddMoneySpentEvent(shuttleRetrieveCost, GameAnalyticsManager.MoneySink.Service, "retrieveshuttle");
}
else if (!purchasedItemRepairs)
{
this.PurchasedLostShuttles = false;
Money += shuttleRetrieveCost;
PurchasedLostShuttles = false;
personalWallet.Refund(shuttleRetrieveCost);
}
}
if (currentLocIndex < Map.Locations.Count && Map.AllowDebugTeleport)
{
Map.SetLocation(currentLocIndex);
}
Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);
if (Map.SelectedLocation == null) { Map.SelectRandomLocation(preferUndiscovered: true); }
if (Map.SelectedConnection != null) { Map.SelectMission(selectedMissionIndices); }
@@ -772,18 +840,18 @@ namespace Barotrauma
if (allowedToManageCampaign || allowedToUseStore || AllowedToManageCampaign(sender, ClientPermissions.BuyItems))
{
var currentBuyCrateItems = new List<PurchasedItem>(CargoManager.ItemsInBuyCrate);
currentBuyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, -i.Quantity));
buyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, i.Quantity));
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);
CargoManager.PurchaseItems(purchasedItems, 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));
subSellCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInSubSellCrate(i.ItemPrefab, i.Quantity));
currentSubSellCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInSubSellCrate(i.ItemPrefab, -i.Quantity, sender));
subSellCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInSubSellCrate(i.ItemPrefab, i.Quantity, sender));
}
bool allowedToSellInventoryItems = AllowedToManageCampaign(sender, ClientPermissions.SellInventoryItems);
@@ -791,29 +859,29 @@ namespace Barotrauma
{
// 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));
CargoManager.SellItems(soldItems);
CargoManager.BuyBackSoldItems(new List<SoldItem>(CargoManager.SoldItems), sender);
CargoManager.SellItems(soldItems, sender);
}
else if (allowedToSellInventoryItems || allowedToSellSubItems)
{
if (allowedToSellInventoryItems)
{
CargoManager.BuyBackSoldItems(new List<SoldItem>(CargoManager.SoldItems.Where(i => i.Origin == SoldItem.SellOrigin.Character)));
CargoManager.BuyBackSoldItems(new List<SoldItem>(CargoManager.SoldItems.Where(i => i.Origin == SoldItem.SellOrigin.Character)), sender);
soldItems.RemoveAll(i => i.Origin != SoldItem.SellOrigin.Character);
}
else
{
CargoManager.BuyBackSoldItems(new List<SoldItem>(CargoManager.SoldItems.Where(i => i.Origin == SoldItem.SellOrigin.Submarine)));
CargoManager.BuyBackSoldItems(new List<SoldItem>(CargoManager.SoldItems.Where(i => i.Origin == SoldItem.SellOrigin.Submarine)), sender);
soldItems.RemoveAll(i => i.Origin != SoldItem.SellOrigin.Submarine);
}
CargoManager.SellItems(soldItems);
CargoManager.SellItems(soldItems, sender);
}
if (allowedToManageCampaign)
{
foreach (var (prefab, category, _) in purchasedUpgrades)
{
UpgradeManager.PurchaseUpgrade(prefab, category);
UpgradeManager.PurchaseUpgrade(prefab, category, client: sender);
// unstable logging
int price = prefab.Price.GetBuyprice(UpgradeManager.GetUpgradeLevel(prefab, category), Map?.CurrentLocation);
@@ -828,7 +896,7 @@ namespace Barotrauma
}
else
{
UpgradeManager.PurchaseItemSwap(purchasedItemSwap.ItemToRemove, purchasedItemSwap.ItemToInstall);
UpgradeManager.PurchaseItemSwap(purchasedItemSwap.ItemToRemove, purchasedItemSwap.ItemToInstall, client: sender);
}
}
foreach (Item item in Item.ItemList)
@@ -842,6 +910,64 @@ namespace Barotrauma
}
}
public void ServerReadMoney(IReadMessage msg, Client sender)
{
NetWalletTransfer transfer = INetSerializableStruct.Read<NetWalletTransfer>(msg);
switch (transfer.Sender)
{
case Some<ushort> { Value: var id }:
if (id != sender.CharacterID && !AllowedToManageCampaign(sender)) { return; }
Wallet wallet = GetWalletByID(id);
if (wallet is InvalidWallet) { return; }
TransferMoney(wallet);
break;
case None<ushort> _:
if (!AllowedToManageCampaign(sender)) { return; }
TransferMoney(Bank);
break;
}
void TransferMoney(Wallet from)
{
if (!from.TryDeduct(transfer.Amount)) { return; }
switch (transfer.Receiver)
{
case Some<ushort> { Value: var id }:
Wallet wallet = GetWalletByID(id);
if (wallet is InvalidWallet) { return; }
wallet.Give(transfer.Amount);
break;
case None<ushort> _:
Bank.Give(transfer.Amount);
break;
}
}
Wallet GetWalletByID(ushort id)
{
Character targetCharacter = Character.CharacterList.FirstOrDefault(c => c.ID == id);
return targetCharacter is null ? Wallet.Invalid : targetCharacter.Wallet;
}
}
public void ServerReadRewardDistribution(IReadMessage msg, Client sender)
{
NetWalletSalaryUpdate update = INetSerializableStruct.Read<NetWalletSalaryUpdate>(msg);
if (!AllowedToManageCampaign(sender)) { return; }
Character targetCharacter = Character.CharacterList.FirstOrDefault(c => c.ID == update.Target);
targetCharacter?.Wallet.SetRewardDistrubiton(update.NewRewardDistribution);
}
public void ServerReadCrew(IReadMessage msg, Client sender)
{
int[] pendingHires = null;
@@ -928,7 +1054,7 @@ namespace Barotrauma
{
foreach (CharacterInfo hireInfo in location.HireManager.PendingHires)
{
if (TryHireCharacter(location, hireInfo))
if (TryHireCharacter(location, hireInfo, sender))
{
hiredCharacters.Add(hireInfo);
};
@@ -1045,7 +1171,6 @@ namespace Barotrauma
{
element.Add(new XAttribute("campaignid", CampaignID));
XElement modeElement = new XElement("MultiPlayerCampaign",
new XAttribute("money", Money),
new XAttribute("purchasedlostshuttles", PurchasedLostShuttles),
new XAttribute("purchasedhullrepairs", PurchasedHullRepairs),
new XAttribute("purchaseditemrepairs", PurchasedItemRepairs),
@@ -1053,6 +1178,7 @@ namespace Barotrauma
modeElement.Add(Settings.Save());
modeElement.Add(SaveStats());
modeElement.Add(Bank.Save());
CampaignMetadata?.Save(modeElement);
Map.Save(modeElement);
CargoManager?.SavePurchasedItems(modeElement);