Build 0.17.14.0

This commit is contained in:
Markus Isberg
2022-04-27 07:44:37 +09:00
parent 7a09cf3260
commit 6e38444fc4
47 changed files with 560 additions and 280 deletions
@@ -694,6 +694,7 @@ namespace Barotrauma
AssignRelayToServer("simulatedlatency", false);
AssignRelayToServer("simulatedloss", false);
AssignRelayToServer("simulatedduplicateschance", false);
AssignRelayToServer("simulatedlongloadingtime", false);
AssignRelayToServer("storeinfo", false);
#endif
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using PlayerBalanceElement = Barotrauma.CampaignUI.PlayerBalanceElement;
namespace Barotrauma
{
@@ -21,6 +22,8 @@ namespace Barotrauma
private GUIButton validateHiresButton;
private GUIButton clearAllButton;
private PlayerBalanceElement? playerBalanceElement;
private List<CharacterInfo> PendingHires => campaign.Map?.CurrentLocation?.HireManager?.PendingHires;
private bool HasPermission => campaignUI.Campaign.AllowedToManageCampaign(ClientPermissions.ManageHires);
@@ -157,23 +160,7 @@ namespace Barotrauma
RelativeSpacing = 0.02f
};
var playerBalanceContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.75f / 14.0f), pendingAndCrewMainGroup.RectTransform), childAnchor: Anchor.TopRight)
{
RelativeSpacing = 0.005f
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), playerBalanceContainer.RectTransform),
TextManager.Get("campaignstore.balance"), font: GUIStyle.Font, textAlignment: Alignment.BottomRight)
{
AutoScaleVertical = true,
ForceUpperCase = ForceUpperCase.Yes
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), playerBalanceContainer.RectTransform),
"", font: GUIStyle.SubHeadingFont, textAlignment: Alignment.TopRight)
{
AutoScaleVertical = true,
TextScale = 1.1f,
TextGetter = () => TextManager.FormatCurrency(campaign.GetBalance())
};
playerBalanceElement = CampaignUI.AddBalanceElement(pendingAndCrewMainGroup, new Vector2(1.0f, 0.75f / 14.0f));
var pendingAndCrewGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.95f), anchor: Anchor.Center,
parent: new GUIFrame(new RectTransform(new Vector2(1.0f, 13.25f / 14.0f), pendingAndCrewMainGroup.RectTransform)
@@ -792,6 +779,10 @@ namespace Barotrauma
CreateUI();
UpdateLocationView(campaign.Map.CurrentLocation, false);
}
else
{
playerBalanceElement = CampaignUI.UpdateBalanceElement(playerBalanceElement);
}
(GUIComponent highlightedFrame, CharacterInfo highlightedInfo) = FindHighlightedCharacter(GUI.MouseOn);
if (highlightedFrame != null && highlightedInfo != null)
@@ -567,9 +567,9 @@ namespace Barotrauma
GameMain.GameSession?.EventManager?.DrawPinnedEvent(spriteBatch);
if (HUDLayoutSettings.DebugDraw) HUDLayoutSettings.Draw(spriteBatch);
if (HUDLayoutSettings.DebugDraw) { HUDLayoutSettings.Draw(spriteBatch); }
if (GameMain.Client != null) GameMain.Client.Draw(spriteBatch);
GameMain.Client?.Draw(spriteBatch);
if (Character.Controlled?.Inventory != null)
{
@@ -616,28 +616,46 @@ namespace Barotrauma
}
DrawSavingIndicator(spriteBatch);
if (GameMain.WindowActive && !HideCursor)
{
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: SamplerStateClamp, rasterizerState: GameMain.ScissorTestEnable);
if (GameMain.GameSession?.CrewManager is { DraggedOrderPrefab: { SymbolSprite: { } orderSprite, Color: var color }, DragOrder: true })
{
float spriteSize = Math.Max(orderSprite.size.X, orderSprite.size.Y);
orderSprite.Draw(spriteBatch, PlayerInput.LatestMousePosition, color, orderSprite.size / 2f, scale: 32f / spriteSize * Scale);
}
var sprite = MouseCursorSprites[MouseCursor] ?? MouseCursorSprites[CursorState.Default];
sprite.Draw(spriteBatch, PlayerInput.LatestMousePosition, Color.White, sprite.Origin, 0f, Scale / 1.5f);
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: SamplerState, rasterizerState: GameMain.ScissorTestEnable);
}
DrawCursor(spriteBatch);
HideCursor = false;
}
}
public static void DrawMessageBoxesOnly(SpriteBatch spriteBatch)
{
bool anyDrawn = false;
foreach (var component in updateList)
{
component.DrawAuto(spriteBatch);
anyDrawn = true;
}
if (anyDrawn)
{
DrawCursor(spriteBatch);
}
}
private static void DrawCursor(SpriteBatch spriteBatch)
{
if (GameMain.WindowActive && !HideCursor && MouseCursorSprites.Prefabs.Any())
{
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: SamplerStateClamp, rasterizerState: GameMain.ScissorTestEnable);
if (GameMain.GameSession?.CrewManager is { DraggedOrderPrefab: { SymbolSprite: { } orderSprite, Color: var color }, DragOrder: true })
{
float spriteSize = Math.Max(orderSprite.size.X, orderSprite.size.Y);
orderSprite.Draw(spriteBatch, PlayerInput.LatestMousePosition, color, orderSprite.size / 2f, scale: 32f / spriteSize * Scale);
}
var sprite = MouseCursorSprites[MouseCursor] ?? MouseCursorSprites[CursorState.Default];
sprite.Draw(spriteBatch, PlayerInput.LatestMousePosition, Color.White, sprite.Origin, 0f, Scale / 1.5f);
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: SamplerState, rasterizerState: GameMain.ScissorTestEnable);
}
}
public static void DrawBackgroundSprite(SpriteBatch spriteBatch, Sprite backgroundSprite, float aberrationStrength = 1.0f)
{
double aberrationT = (Timing.TotalTime * 0.5f);
@@ -1204,6 +1222,17 @@ namespace Barotrauma
}
}
public static void UpdateGUIMessageBoxesOnly(float deltaTime)
{
GUIMessageBox.AddActiveToGUIUpdateList();
RefreshUpdateList();
UpdateMouseOn();
foreach (var c in updateList)
{
c.UpdateAuto(deltaTime);
}
}
private static void UpdateMessages(float deltaTime)
{
lock (mutex)
@@ -36,6 +36,8 @@ namespace Barotrauma
public string Tag { get; private set; }
public bool Closed { get; private set; }
public bool DisplayInLoadingScreens;
public GUIImage Icon
{
get;
@@ -451,6 +453,10 @@ namespace Barotrauma
continue;
}
if (messageBox.type != type) { continue; }
if (!messageBox.DisplayInLoadingScreens && GameMain.Instance.LoadingScreenOpen)
{
continue;
}
// These are handled separately in GUI.HandlePersistingElements()
if (MessageBoxes[i].UserData as string == "verificationprompt") { continue; }
@@ -1,13 +1,11 @@
using Microsoft.Xna.Framework;
using Barotrauma.Extensions;
using Barotrauma.Media;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using Barotrauma.Media;
using System.Linq;
using Barotrauma.Extensions;
using System.Collections.Immutable;
namespace Barotrauma
{
@@ -16,7 +14,7 @@ namespace Barotrauma
private readonly Texture2D defaultBackgroundTexture, overlay;
private readonly SpriteSheet decorativeGraph, decorativeMap;
private Texture2D currentBackgroundTexture;
private Sprite noiseSprite;
private readonly Sprite noiseSprite;
private string randText = "";
@@ -250,8 +248,8 @@ namespace Barotrauma
}
}
}
}
GUI.DrawMessageBoxesOnly(spriteBatch);
spriteBatch.End();
spriteBatch.Begin(blendState: BlendState.Additive);
@@ -7,6 +7,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Barotrauma.Extensions;
using Microsoft.Xna.Framework;
using PlayerBalanceElement = Barotrauma.CampaignUI.PlayerBalanceElement;
namespace Barotrauma
{
@@ -180,6 +181,8 @@ namespace Barotrauma
private const float refreshTimerMax = 3f;
private float refreshTimer = 0;
private PlayerBalanceElement? playerBalanceElement;
public MedicalClinicUI(MedicalClinic clinic, GUIComponent parent)
{
medicalClinic = clinic;
@@ -428,6 +431,7 @@ namespace Barotrauma
{
container.ClearChildren();
pendingHealList = null;
playerBalanceElement = null;
int panelMaxWidth = (int)(GUI.xScale * (GUI.HorizontalAspectRatio < 1.4f ? 650 : 560));
GUIFrame paddedParent = new GUIFrame(new RectTransform(new Vector2(0.95f), container.RectTransform, Anchor.Center), style: null);
@@ -458,19 +462,7 @@ namespace Barotrauma
RelativeSpacing = 0.01f
};
GUILayoutGroup balanceLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.1f), crewContent.RectTransform));
GUITextBlock balanceLabel = new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), balanceLayout.RectTransform), TextManager.Get("campaignstore.balance"), textAlignment: Alignment.BottomRight, font: GUIStyle.Font)
{
AutoScaleVertical = true,
ForceUpperCase = ForceUpperCase.Yes
};
GUITextBlock moneyLabel = new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), balanceLayout.RectTransform), string.Empty, textAlignment: Alignment.TopRight, font: GUIStyle.SubHeadingFont)
{
TextGetter = () => TextManager.FormatCurrency(medicalClinic.GetBalance()),
AutoScaleVertical = true,
TextScale = 1.1f
};
playerBalanceElement = CampaignUI.AddBalanceElement(crewContent, new Vector2(1f, 0.1f));
GUIFrame crewBackground = new GUIFrame(new RectTransform(Vector2.One, crewContent.RectTransform));
@@ -1050,6 +1042,10 @@ namespace Barotrauma
{
CreateUI();
}
else
{
playerBalanceElement = CampaignUI.UpdateBalanceElement(playerBalanceElement);
}
refreshTimer += deltaTime;
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using PlayerBalanceElement = Barotrauma.CampaignUI.PlayerBalanceElement;
namespace Barotrauma
{
@@ -66,6 +67,8 @@ namespace Barotrauma
private Point resolutionWhenCreated;
private PlayerBalanceElement? playerBalanceElement;
private Dictionary<ItemPrefab, ItemQuantity> OwnedItems { get; } = new Dictionary<ItemPrefab, ItemQuantity>();
private Location.StoreInfo ActiveStore { get; set; }
@@ -647,23 +650,7 @@ namespace Barotrauma
};
// Player balance ------------------------------------------------
var playerBalanceContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.75f / 14.0f), shoppingCrateContent.RectTransform), childAnchor: Anchor.TopRight)
{
RelativeSpacing = 0.005f
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), playerBalanceContainer.RectTransform),
TextManager.Get("campaignstore.balance"), font: GUIStyle.Font, textAlignment: Alignment.BottomRight)
{
AutoScaleVertical = true,
ForceUpperCase = ForceUpperCase.Yes
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), playerBalanceContainer.RectTransform),
"", textColor: Color.White, font: GUIStyle.SubHeadingFont, textAlignment: Alignment.TopRight)
{
AutoScaleVertical = true,
TextScale = 1.1f,
TextGetter = GetPlayerBalanceText
};
playerBalanceElement = CampaignUI.AddBalanceElement(shoppingCrateContent, new Vector2(1.0f, 0.75f / 14.0f));
// Divider ------------------------------------------------
var dividerFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.6f / 14.0f), shoppingCrateContent.RectTransform), style: null);
@@ -695,7 +682,7 @@ namespace Barotrauma
{
CanBeFocused = false,
TextScale = 1.1f,
TextGetter = () => IsBuying ? GetPlayerBalanceText() : GetMerchantBalanceText()
TextGetter = () => IsBuying ? CampaignUI.GetTotalBalance() : GetMerchantBalanceText()
};
var totalContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), shoppingCrateInventoryContainer.RectTransform), isHorizontal: true)
@@ -744,8 +731,6 @@ namespace Barotrauma
private LocalizedString GetMerchantBalanceText() => TextManager.FormatCurrency(ActiveStore?.Balance ?? 0);
private LocalizedString GetPlayerBalanceText() => TextManager.FormatCurrency(Balance);
private GUILayoutGroup CreateDealsGroup(GUIListBox parentList, int elementCount)
{
// Add 1 for the header
@@ -2183,6 +2168,7 @@ namespace Barotrauma
ActiveShoppingCrateList.Content.RectTransform.Children.Any();
}
private int prevBalance;
private float ownedItemsUpdateTimer = 0.0f, sellableItemsFromSubUpdateTimer = 0.0f;
private const float timerUpdateInterval = 1.5f;
private readonly Stopwatch updateStopwatch = new Stopwatch();
@@ -2198,6 +2184,8 @@ namespace Barotrauma
}
else
{
playerBalanceElement = CampaignUI.UpdateBalanceElement(playerBalanceElement);
// Update the owned items at short intervals and check if the interface should be refreshed
ownedItemsUpdateTimer += deltaTime;
if (ownedItemsUpdateTimer >= timerUpdateInterval)
@@ -2234,6 +2222,16 @@ namespace Barotrauma
}
}
}
// Refresh the interface if balance changes and the buy tab is open
if (activeTab == StoreTab.Buy)
{
int currBalance = Balance;
if (prevBalance != currBalance)
{
needsBuyingRefresh = true;
prevBalance = currBalance;
}
}
if (needsItemsToSellRefresh)
{
RefreshItemsToSell();
@@ -5,6 +5,7 @@ using System.Linq;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System.Globalization;
using PlayerBalanceElement = Barotrauma.CampaignUI.PlayerBalanceElement;
namespace Barotrauma
{
@@ -45,6 +46,8 @@ namespace Barotrauma
private static readonly Color indicatorColor = new Color(112, 149, 129);
private Point createdForResolution;
private PlayerBalanceElement? playerBalanceElement;
private struct SubmarineDisplayContent
{
public GUIFrame background;
@@ -125,10 +128,7 @@ namespace Barotrauma
content = new GUILayoutGroup(new RectTransform(new Point(background.Rect.Width - HUDLayoutSettings.Padding * 4, background.Rect.Height - HUDLayoutSettings.Padding * 4), background.RectTransform, Anchor.Center)) { AbsoluteSpacing = (int)(HUDLayoutSettings.Padding * 1.5f) };
GUITextBlock header = new GUITextBlock(new RectTransform(new Vector2(1f, 0.0f), content.RectTransform), transferService ? TextManager.Get("switchsubmarineheader") : TextManager.GetWithVariable("outpostshipyard", "[location]", GameMain.GameSession.Map.CurrentLocation.Name), font: GUIStyle.LargeFont);
header.CalculateHeightFromText(0, true);
GUITextBlock credits = new GUITextBlock(new RectTransform(Vector2.One, header.RectTransform), "", font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterRight)
{
TextGetter = CampaignUI.GetMoney
};
playerBalanceElement = CampaignUI.AddBalanceElement(header, new Vector2(1.0f, 1.5f));
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.01f), content.RectTransform), style: "HorizontalLine");
@@ -256,6 +256,10 @@ namespace Barotrauma
{
RefreshSubmarineDisplay(true);
}
else
{
playerBalanceElement = CampaignUI.UpdateBalanceElement(playerBalanceElement);
}
// Input
if (PlayerInput.KeyHit(Keys.Left))
@@ -270,9 +274,22 @@ namespace Barotrauma
public void RefreshSubmarineDisplay(bool updateSubs)
{
if (!initialized) Initialize();
if (GameMain.GraphicsWidth != createdForResolution.X || GameMain.GraphicsHeight != createdForResolution.Y) CreateGUI();
if (updateSubs) UpdateSubmarines();
if (!initialized)
{
Initialize();
}
if (GameMain.GraphicsWidth != createdForResolution.X || GameMain.GraphicsHeight != createdForResolution.Y)
{
CreateGUI();
}
else
{
playerBalanceElement = CampaignUI.UpdateBalanceElement(playerBalanceElement);
}
if (updateSubs)
{
UpdateSubmarines();
}
if (pageIndicators != null)
{
@@ -11,6 +11,7 @@ using FarseerPhysics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using PlayerBalanceElement = Barotrauma.CampaignUI.PlayerBalanceElement;
// ReSharper disable UnusedVariable
@@ -75,6 +76,8 @@ namespace Barotrauma
private bool needsRefresh = true;
private PlayerBalanceElement? playerBalanceElement;
/// <summary>
/// While set to true any call to <see cref="RefreshUpgradeList"/> will cause the buy button to be disabled and to not update the prices.
/// This is to prevent us from buying another upgrade before the server has given us the new prices and causing potential syncing issues.
@@ -293,9 +296,14 @@ namespace Barotrauma
* |---------------------------------------------------------------------------------------------------|
*/
GUILayoutGroup rightLayout = new GUILayoutGroup(rectT(0.5f, 1, topHeaderLayout), childAnchor: Anchor.TopRight);
GUILayoutGroup priceLayout = new GUILayoutGroup(rectT(1, 0.8f, rightLayout), childAnchor: Anchor.Center) { RelativeSpacing = 0.08f };
new GUITextBlock(rectT(1f, 0f, priceLayout), TextManager.Get("CampaignStore.Balance"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Right);
new GUITextBlock(rectT(1f, 0f, priceLayout), TextManager.FormatCurrency(PlayerBalance), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Right) { TextGetter = () => TextManager.FormatCurrency(PlayerBalance) };
playerBalanceElement = CampaignUI.AddBalanceElement(rightLayout, new Vector2(1.0f, 0.8f));
if (playerBalanceElement is { } balanceElement)
{
balanceElement.TotalBalanceContainer.OnAddedToGUIUpdateList += (_) =>
{
playerBalanceElement = CampaignUI.UpdateBalanceElement(playerBalanceElement);
};
}
new GUIFrame(rectT(0.5f, 0.1f, rightLayout, Anchor.BottomRight), style: "HorizontalLine") { IgnoreLayoutGroups = true };
repairButton.OnClicked = upgradeButton.OnClicked = (button, o) =>
@@ -662,6 +662,8 @@ namespace Barotrauma
if (!TitleScreen.PlayingSplashScreen)
{
SoundPlayer.Update((float)Timing.Step);
GUI.ClearUpdateList();
GUI.UpdateGUIMessageBoxesOnly((float)Timing.Step);
}
if (TitleScreen.LoadState >= 100.0f && !TitleScreen.PlayingSplashScreen &&
@@ -584,19 +584,16 @@ namespace Barotrauma.Items.Components
{
availableCharge = 0.0f;
availableCapacity = 0.0f;
if (item.Connections == null) { return; }
foreach (Connection c in item.Connections)
if (item.Connections == null || powerIn == null) { return; }
var recipients = powerIn.Recipients;
foreach (Connection recipient in recipients)
{
var recipients = c.Recipients;
foreach (Connection recipient in recipients)
{
if (!recipient.IsPower || !recipient.IsOutput) { continue; }
var battery = recipient.Item?.GetComponent<PowerContainer>();
if (battery == null) { continue; }
availableCharge += battery.Charge;
availableCapacity += battery.Capacity;
}
}
if (!recipient.IsPower || !recipient.IsOutput) { continue; }
var battery = recipient.Item?.GetComponent<PowerContainer>();
if (battery == null || battery.Item.Condition <= 0.0f) { continue; }
availableCharge += battery.Charge;
availableCapacity += battery.Capacity;
}
}
/// <summary>
@@ -273,10 +273,16 @@ namespace Barotrauma
foreach (string tag in readTags)
{
string[] s = tag.Split(':');
if (s[0] == "name")
idName = s[1];
if (s[0] == "job")
idJob = s[1];
switch (s[0])
{
case "name":
idName = s[1];
break;
case "job":
case "jobid":
idJob = s[1];
break;
}
}
if (idName != null)
{
@@ -32,11 +32,10 @@ namespace Barotrauma
base.DrawPlacing(spriteBatch, cam);
foreach ((Identifier identifier, Rectangle rect) in DisplayEntities)
{
var entityPrefab = MapEntityPrefab.Find(p => p.Identifier == identifier);
var entityPrefab = FindByIdentifier(identifier);
if (entityPrefab == null) { continue; }
Rectangle drawRect = rect;
drawRect.Location += placePosition != Vector2.Zero ? placePosition.ToPoint() : Submarine.MouseToWorldGrid(cam, Submarine.MainSub).ToPoint();
drawRect.Location += placePosition != Vector2.Zero ? placePosition.ToPoint() : Submarine.MouseToWorldGrid(cam, Submarine.MainSub).ToPoint();
entityPrefab.DrawPlacing(spriteBatch, drawRect, entityPrefab.Scale);
}
}
@@ -78,7 +78,7 @@ namespace Barotrauma.Networking
VoipSound = null;
}
public void SetPermissions(ClientPermissions permissions, List<string> permittedConsoleCommands)
public void SetPermissions(ClientPermissions permissions, IEnumerable<string> permittedConsoleCommands)
{
List<DebugConsole.Command> permittedCommands = new List<DebugConsole.Command>();
foreach (string commandName in permittedConsoleCommands)
@@ -92,14 +92,18 @@ namespace Barotrauma.Networking
SetPermissions(permissions, permittedCommands);
}
public void SetPermissions(ClientPermissions permissions, List<DebugConsole.Command> permittedConsoleCommands)
public void SetPermissions(ClientPermissions permissions, IEnumerable<DebugConsole.Command> permittedConsoleCommands)
{
if (GameMain.Client == null)
{
return;
}
Permissions = permissions;
PermittedConsoleCommands.Clear(); PermittedConsoleCommands.AddRange(permittedConsoleCommands);
PermittedConsoleCommands.Clear();
foreach (var command in permittedConsoleCommands)
{
PermittedConsoleCommands.Add(command);
}
}
public void GivePermission(ClientPermissions permission)
@@ -1,10 +1,13 @@
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using System.Collections.Generic;
namespace Barotrauma
{
partial class EntitySpawner : Entity, IServerSerializable
{
public readonly List<(Entity entity, bool isRemoval)> receivedEvents = new List<(Entity entity, bool isRemoval)>();
public void ClientEventRead(IReadMessage message, float sendingTime)
{
bool remove = message.ReadBoolean();
@@ -12,7 +15,6 @@ namespace Barotrauma
if (remove)
{
ushort entityId = message.ReadUInt16();
var entity = FindEntityByID(entityId);
if (entity != null)
{
@@ -27,6 +29,7 @@ namespace Barotrauma
{
DebugConsole.Log("Received entity removal message for ID " + entityId + ". Entity with a matching ID not found.");
}
receivedEvents.Add((entity, true));
}
else
{
@@ -34,13 +37,29 @@ namespace Barotrauma
{
case (byte)SpawnableType.Item:
var newItem = Item.ReadSpawnData(message, true);
if (newItem is Item item && item.Container?.GetComponent<Fabricator>() != null)
if (newItem == null)
{
GameAnalyticsManager.AddDesignEvent("ItemFabricated:" + (GameMain.GameSession?.GameMode?.Preset.Identifier ?? "none".ToIdentifier()) + ":" + item.Prefab.Identifier);
DebugConsole.ThrowError("Received an item spawn message, but spawning the item failed.");
}
else
{
if (newItem.Container?.GetComponent<Fabricator>() != null)
{
GameAnalyticsManager.AddDesignEvent("ItemFabricated:" + (GameMain.GameSession?.GameMode?.Preset.Identifier ?? "none".ToIdentifier()) + ":" + newItem.Prefab.Identifier);
}
receivedEvents.Add((newItem, false));
}
break;
case (byte)SpawnableType.Character:
Character.ReadSpawnData(message);
var character = Character.ReadSpawnData(message);
if (character == null)
{
DebugConsole.ThrowError("Received character spawn message, but spawning the character failed.");
}
else
{
receivedEvents.Add((character, false));
}
break;
default:
DebugConsole.ThrowError("Received invalid entity spawn message (unknown spawnable type)");
@@ -79,13 +79,14 @@ namespace Barotrauma.Networking
Starting,
WaitingForStartGameFinalize,
Started,
TimedOut,
Error,
Interrupted
}
private RoundInitStatus roundInitStatus = RoundInitStatus.NotStarted;
public bool RoundStarting => roundInitStatus == RoundInitStatus.Starting || roundInitStatus == RoundInitStatus.WaitingForStartGameFinalize;
private byte myID;
private readonly List<Client> otherClients;
@@ -690,11 +691,8 @@ namespace Barotrauma.Networking
{
ServerPacketHeader header = (ServerPacketHeader)inc.ReadByte();
if (roundInitStatus != RoundInitStatus.Started &&
roundInitStatus != RoundInitStatus.NotStarted &&
roundInitStatus != RoundInitStatus.Error &&
roundInitStatus != RoundInitStatus.Interrupted &&
header != ServerPacketHeader.STARTGAMEFINALIZE &&
if (roundInitStatus == RoundInitStatus.WaitingForStartGameFinalize &&
roundInitStatus == RoundInitStatus.Started &&
header != ServerPacketHeader.ENDGAME &&
header != ServerPacketHeader.PING_REQUEST &&
header != ServerPacketHeader.FILE_TRANSFER)
@@ -1686,12 +1684,15 @@ namespace Barotrauma.Networking
roundInitStatus = RoundInitStatus.WaitingForStartGameFinalize;
DateTime? timeOut = null;
TimeSpan timeOutDuration = new TimeSpan(0, 0, seconds: 30);
DateTime requestFinalizeTime = DateTime.Now;
TimeSpan requestFinalizeInterval = new TimeSpan(0, 0, 2);
IWriteMessage msg = new WriteOnlyMessage();
msg.Write((byte)ClientPacketHeader.REQUEST_STARTGAMEFINALIZE);
clientPeer.Send(msg, DeliveryMethod.Unreliable);
GUIMessageBox interruptPrompt = null;
while (true)
{
try
@@ -1705,11 +1706,30 @@ namespace Barotrauma.Networking
clientPeer.Send(msg, DeliveryMethod.Unreliable);
requestFinalizeTime = DateTime.Now + requestFinalizeInterval;
}
if (DateTime.Now > timeOut)
if (DateTime.Now > timeOut && interruptPrompt == null)
{
DebugConsole.ThrowError("Error while starting the round (did not receive STARTGAMEFINALIZE message from the server). Stopping the round...");
roundInitStatus = RoundInitStatus.TimedOut;
break;
interruptPrompt = new GUIMessageBox(string.Empty, TextManager.Get("WaitingForStartGameFinalizeTakingTooLong"),
new LocalizedString[] { TextManager.Get("Yes"), TextManager.Get("No") })
{
DisplayInLoadingScreens = true
};
interruptPrompt.Buttons[0].OnClicked += (btn, userData) =>
{
roundInitStatus = RoundInitStatus.Interrupted;
DebugConsole.ThrowError("Error while starting the round (did not receive STARTGAMEFINALIZE message from the server). Returning to the lobby...");
gameStarted = true;
GameMain.NetLobbyScreen.Select();
interruptPrompt.Close();
interruptPrompt = null;
return true;
};
interruptPrompt.Buttons[1].OnClicked += (btn, userData) =>
{
timeOut = DateTime.Now + timeOutDuration;
interruptPrompt.Close();
interruptPrompt = null;
return true;
};
}
}
else
@@ -1721,7 +1741,7 @@ namespace Barotrauma.Networking
}
//wait for up to 30 seconds for the server to send the STARTGAMEFINALIZE message
timeOut = DateTime.Now + new TimeSpan(0, 0, seconds: 30);
timeOut = DateTime.Now + timeOutDuration;
}
if (!connected)
@@ -1743,6 +1763,9 @@ namespace Barotrauma.Networking
yield return CoroutineStatus.Running;
}
interruptPrompt?.Close();
interruptPrompt = null;
if (roundInitStatus != RoundInitStatus.Started)
{
if (roundInitStatus != RoundInitStatus.Interrupted)
@@ -3093,7 +3116,31 @@ namespace Barotrauma.Networking
protected GUIFrame inGameHUD;
protected ChatBox chatBox;
public GUIButton ShowLogButton; //TODO: move to NetLobbyScreen
private bool hasPermissionToUseLogButton;
public void UpdateLogButtonPermissions()
{
hasPermissionToUseLogButton = GameMain.Client.HasPermission(ClientPermissions.ServerLog);
UpdateLogButtonVisibility();
}
private void UpdateLogButtonVisibility()
{
if (ShowLogButton != null)
{
if (Screen.Selected != GameMain.GameScreen)
{
ShowLogButton.Visible = hasPermissionToUseLogButton;
}
else
{
var campaign = GameMain.GameSession?.Campaign;
ShowLogButton.Visible = hasPermissionToUseLogButton && (campaign == null || !campaign.ShowCampaignUI);
}
}
}
public GUIFrame InGameHUD
{
@@ -3173,6 +3220,8 @@ namespace Barotrauma.Networking
msgBox = GameMain.NetLobbyScreen.ChatInput;
}
UpdateLogButtonVisibility();
if (gameStarted && Screen.Selected == GameMain.GameScreen)
{
var controller = Character.Controlled?.SelectedConstruction?.GetComponent<Controller>();
@@ -3648,6 +3697,19 @@ namespace Barotrauma.Networking
errorLines.Add(e.ErrorLine);
}
if (Entity.Spawner != null)
{
errorLines.Add("");
errorLines.Add("EntitySpawner events:");
foreach ((Entity entity, bool isRemoval) in Entity.Spawner.receivedEvents)
{
errorLines.Add(
(isRemoval ? "Remove " : "Create ") +
entity.ToString() +
" (" + entity.ID + ")");
}
}
errorLines.Add("");
errorLines.Add("Last debug messages:");
for (int i = DebugConsole.Messages.Count - 1; i > 0 && i > DebugConsole.Messages.Count - 15; i--)
@@ -153,7 +153,10 @@ namespace Barotrauma.Networking
{
if (!isActive) { return; }
timeout -= deltaTime;
if (GameMain.Client == null || !GameMain.Client.RoundStarting)
{
timeout -= deltaTime;
}
heartbeatTimer -= deltaTime;
if (initializationStep != ConnectionInitialization.Password &&
@@ -739,9 +739,112 @@ namespace Barotrauma
return TextManager.GetWithVariable("PlayerCredits", "[credits]", (GameMain.GameSession?.Campaign == null) ? "0" : string.Format(CultureInfo.InvariantCulture, "{0:N0}", GameMain.GameSession.Campaign.GetBalance()));
}
public static LocalizedString GetTotalBalance()
{
return TextManager.FormatCurrency(GameMain.GameSession?.Campaign is { } campaign ? campaign.GetBalance() : 0);
}
public static LocalizedString GetBankBalance()
{
return TextManager.FormatCurrency(GameMain.GameSession?.Campaign is { } campaign ? campaign.Bank.Balance : 0);
}
public static LocalizedString GetWalletBalance()
{
return TextManager.FormatCurrency(GameMain.GameSession?.Campaign is { } campaign ? campaign.Wallet.Balance : 0);
}
private void UpdateMaxMissions(Location location)
{
hasMaxMissions = Campaign.NumberOfMissionsAtLocation(location) >= Campaign.Settings.TotalMaxMissionCount;
}
public readonly struct PlayerBalanceElement
{
public readonly bool DisplaySeparateBalances;
public readonly GUILayoutGroup ParentComponent;
public readonly GUILayoutGroup TotalBalanceContainer;
public readonly GUILayoutGroup BankBalanceContainer;
public PlayerBalanceElement(bool displaySeparateBalances, GUILayoutGroup parentComponent, GUILayoutGroup totalBalanceContainer, GUILayoutGroup bankBalanceContainer)
{
DisplaySeparateBalances = displaySeparateBalances;
ParentComponent = parentComponent;
TotalBalanceContainer = totalBalanceContainer;
BankBalanceContainer = bankBalanceContainer;
}
public PlayerBalanceElement(PlayerBalanceElement element, bool displaySeparateBalances)
{
DisplaySeparateBalances = displaySeparateBalances;
ParentComponent = element.ParentComponent;
TotalBalanceContainer = element.TotalBalanceContainer;
BankBalanceContainer = element.BankBalanceContainer;
}
}
public static PlayerBalanceElement? AddBalanceElement(GUIComponent elementParent, Vector2 relativeSize)
{
var parent = new GUILayoutGroup(new RectTransform(relativeSize, elementParent.RectTransform), isHorizontal: true, childAnchor: Anchor.TopRight);
if (GameMain.IsSingleplayer)
{
AddBalance(parent, true, TextManager.Get("campaignstore.balance"), GetTotalBalance);
return null;
}
else
{
bool displaySeparateBalances = CampaignMode.AllowedToManageWallets();
var totalBalanceContainer = AddBalance(parent, displaySeparateBalances, TextManager.Get("campaignstore.total"), GetTotalBalance);
var bankBalanceContainer = AddBalance(parent, displaySeparateBalances, TextManager.Get("crewwallet.bank"), GetBankBalance);
AddBalance(parent, true, TextManager.Get("crewwallet.wallet"), GetWalletBalance);
var playerBalanceElement = new PlayerBalanceElement(displaySeparateBalances, parent, totalBalanceContainer, bankBalanceContainer);
parent.Recalculate();
return playerBalanceElement;
}
static GUILayoutGroup AddBalance(GUIComponent parent, bool visible, LocalizedString text, GUITextBlock.TextGetterHandler textGetter)
{
float balanceContainerWidth = GameMain.IsSingleplayer ? 1 : 1 / 3f;
var rt = new RectTransform(new Vector2(balanceContainerWidth, 1.0f), parent.RectTransform)
{
MaxSize = new Point(120, int.MaxValue)
};
var balanceContainer = new GUILayoutGroup(rt, childAnchor: Anchor.TopRight)
{
RelativeSpacing = 0.005f,
Visible = visible
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), balanceContainer.RectTransform), text,
font: GUIStyle.Font, textAlignment: Alignment.BottomRight)
{
AutoScaleVertical = true,
ForceUpperCase = ForceUpperCase.Yes
};
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), balanceContainer.RectTransform), "",
textColor: Color.White, font: GUIStyle.SubHeadingFont, textAlignment: Alignment.TopRight)
{
AutoScaleVertical = true,
TextScale = 1.1f,
TextGetter = textGetter
};
return balanceContainer;
}
}
public static PlayerBalanceElement? UpdateBalanceElement(PlayerBalanceElement? playerBalanceElement)
{
if (playerBalanceElement is { } balanceElement)
{
bool displaySeparateBalances = CampaignMode.AllowedToManageWallets();
if (displaySeparateBalances != balanceElement.DisplaySeparateBalances)
{
balanceElement.TotalBalanceContainer.Visible = displaySeparateBalances;
balanceElement.BankBalanceContainer.Visible = displaySeparateBalances;
playerBalanceElement = new PlayerBalanceElement(balanceElement, displaySeparateBalances);
balanceElement.ParentComponent.Recalculate();
}
}
return playerBalanceElement;
}
}
}
@@ -966,7 +966,15 @@ namespace Barotrauma
{
OnClicked = (_, __) =>
{
GameMain.Client?.RequestSelectMode(ModeList.Content.GetChildIndex(ModeList.Content.GetChildByUserData(GameModePreset.Sandbox)));
if (GameMain.Client == null) { return false; }
if (GameMain.Client.GameStarted)
{
GameMain.Client.RequestRoundEnd(save: false);
}
else
{
GameMain.Client.RequestSelectMode(ModeList.Content.GetChildIndex(ModeList.Content.GetChildByUserData(GameModePreset.Sandbox)));
}
return true;
}
};
@@ -1344,9 +1352,9 @@ namespace Barotrauma
shuttleTickBox.Enabled = GameMain.Client.HasPermission(ClientPermissions.ManageSettings) && !GameMain.Client.GameStarted;
SubList.Enabled = !CampaignFrame.Visible && (GameMain.Client.ServerSettings.AllowSubVoting || GameMain.Client.HasPermission(ClientPermissions.SelectSub));
ShuttleList.Enabled = ShuttleList.ButtonEnabled = GameMain.Client.HasPermission(ClientPermissions.SelectSub) && !GameMain.Client.GameStarted;
ModeList.Enabled = GameMain.Client.ServerSettings.AllowModeVoting || GameMain.Client.HasPermission(ClientPermissions.SelectMode);
ModeList.Enabled = !GameMain.Client.GameStarted && (GameMain.Client.ServerSettings.AllowModeVoting || GameMain.Client.HasPermission(ClientPermissions.SelectMode));
LogButtons.Visible = GameMain.Client.HasPermission(ClientPermissions.ServerLog);
GameMain.Client.ShowLogButton.Visible = GameMain.Client.HasPermission(ClientPermissions.ServerLog);
GameMain.Client.UpdateLogButtonPermissions();
roundControlsHolder.Children.ForEach(c => c.IgnoreLayoutGroups = !c.Visible);
roundControlsHolder.Children.ForEach(c => c.RectTransform.RelativeSize = Vector2.One);
roundControlsHolder.Recalculate();