v1.0.13.1 (first post-1.0 patch)

This commit is contained in:
Regalis11
2023-05-10 15:07:17 +03:00
parent 96fb49ba14
commit ee1db852b1
272 changed files with 5738 additions and 2413 deletions
@@ -75,7 +75,7 @@ namespace Barotrauma.Networking
float gain = 1.0f;
float noiseGain = 0.0f;
Vector3? position = null;
if (character != null)
if (character != null && !character.IsDead)
{
if (GameSettings.CurrentConfig.Audio.UseDirectionalVoiceChat)
{
@@ -8,7 +8,6 @@ using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
@@ -16,6 +15,10 @@ namespace Barotrauma.Networking
{
sealed class GameClient : NetworkMember
{
public static readonly TimeSpan CampaignSaveTransferTimeOut = new TimeSpan(0, 0, seconds: 100);
//this should be longer than CampaignSaveTransferTimeOut - we shouldn't give up starting the round if we're still waiting for the save file
public static readonly TimeSpan LevelTransitionTimeOut = new TimeSpan(0, 0, seconds: 150);
public override bool IsClient => true;
public override bool IsServer => false;
@@ -76,6 +79,8 @@ namespace Barotrauma.Networking
Interrupted
}
private UInt16? debugStartGameCampaignSaveID;
private RoundInitStatus roundInitStatus = RoundInitStatus.NotStarted;
public bool RoundStarting => roundInitStatus == RoundInitStatus.Starting || roundInitStatus == RoundInitStatus.WaitingForStartGameFinalize;
@@ -512,6 +517,7 @@ namespace Barotrauma.Networking
DisplayInLoadingScreens = true
};
Quit();
GUI.DisableHUD = false;
GameMain.ServerListScreen.Select();
return;
}
@@ -859,17 +865,24 @@ namespace Barotrauma.Networking
ContentFile file = ContentPackageManager.EnabledPackages.All
.Select(p =>
p.Files.FirstOrDefault(f => f.Path == filePath))
.FirstOrDefault(f => !(f is null));
.FirstOrDefault(f => f is not null);
contentToPreload.AddIfNotNull(file);
}
string campaignErrorInfo = string.Empty;
if (GameMain.GameSession?.Campaign is MultiPlayerCampaign campaign)
{
campaignErrorInfo = $" Round start save ID: {debugStartGameCampaignSaveID}, last save id: {campaign.LastSaveID}, pending save id: {campaign.PendingSaveID}.";
}
GameMain.GameSession.EventManager.PreloadContent(contentToPreload);
int subEqualityCheckValue = inc.ReadInt32();
if (subEqualityCheckValue != (Submarine.MainSub?.Info?.EqualityCheckVal ?? 0))
{
string errorMsg = "Submarine equality check failed. The submarine loaded at your end doesn't match the one loaded by the server." +
" There may have been an error in receiving the up-to-date submarine file from the server.";
string errorMsg =
"Submarine equality check failed. The submarine loaded at your end doesn't match the one loaded by the server. " +
$"There may have been an error in receiving the up-to-date submarine file from the server. Round init status: {roundInitStatus}." + campaignErrorInfo;
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:SubsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
throw new Exception(errorMsg);
}
@@ -886,7 +899,7 @@ namespace Barotrauma.Networking
$"Mission equality check failed. Mission count doesn't match the server. " +
$"Server: {string.Join(", ", serverMissionIdentifiers)}, " +
$"client: {string.Join(", ", GameMain.GameSession.GameMode.Missions.Select(m => m.Prefab.Identifier))}, " +
$"game session: {string.Join(", ", GameMain.GameSession.Missions.Select(m => m.Prefab.Identifier))})";
$"game session: {string.Join(", ", GameMain.GameSession.Missions.Select(m => m.Prefab.Identifier))}). Round init status: {roundInitStatus}." + campaignErrorInfo;
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:MissionsCountMismatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
throw new Exception(errorMsg);
}
@@ -899,7 +912,7 @@ namespace Barotrauma.Networking
$"Mission equality check failed. The mission selected at your end doesn't match the one loaded by the server " +
$"Server: {string.Join(", ", serverMissionIdentifiers)}, " +
$"client: {string.Join(", ", GameMain.GameSession.GameMode.Missions.Select(m => m.Prefab.Identifier))}, " +
$"game session: {string.Join(", ", GameMain.GameSession.Missions.Select(m => m.Prefab.Identifier))})";
$"game session: {string.Join(", ", GameMain.GameSession.Missions.Select(m => m.Prefab.Identifier))}). Round init status: {roundInitStatus}." + campaignErrorInfo;
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:MissionsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
throw new Exception(errorMsg);
}
@@ -922,7 +935,7 @@ namespace Barotrauma.Networking
", level value count: " + levelEqualityCheckValues.Count +
", seed: " + Level.Loaded.Seed +
", sub: " + Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash.ShortRepresentation + ")" +
", mirrored: " + Level.Loaded.Mirrored + ").";
", mirrored: " + Level.Loaded.Mirrored + "). Round init status: " + roundInitStatus + "." + campaignErrorInfo;
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
throw new Exception(errorMsg);
}
@@ -1322,6 +1335,8 @@ namespace Barotrauma.Networking
eventErrorWritten = false;
GameMain.NetLobbyScreen.StopWaitingForStartRound();
debugStartGameCampaignSaveID = null;
while (CoroutineManager.IsCoroutineRunning("EndGame"))
{
EndCinematic?.Stop();
@@ -1471,7 +1486,28 @@ namespace Barotrauma.Networking
roundInitStatus = RoundInitStatus.Interrupted;
yield return CoroutineStatus.Failure;
}
else if (campaign.Map == null)
if (NetIdUtils.IdMoreRecent(campaign.PendingSaveID, campaign.LastSaveID) ||
NetIdUtils.IdMoreRecent(campaignSaveID, campaign.PendingSaveID))
{
campaign.PendingSaveID = campaignSaveID;
DateTime saveFileTimeOut = DateTime.Now + CampaignSaveTransferTimeOut;
while (NetIdUtils.IdMoreRecent(campaignSaveID, campaign.LastSaveID))
{
if (DateTime.Now > saveFileTimeOut)
{
GameStarted = true;
new GUIMessageBox(TextManager.Get("error"), TextManager.Get("campaignsavetransfer.timeout"));
GameMain.NetLobbyScreen.Select();
roundInitStatus = RoundInitStatus.Interrupted;
//use success status, even though this is a failure (no need to show a console error because we show it in the message box)
yield return CoroutineStatus.Success;
}
yield return new WaitForSeconds(0.1f);
}
}
if (campaign.Map == null)
{
GameStarted = true;
DebugConsole.ThrowError("Failed to start campaign round (campaign map not loaded yet).");
@@ -1480,30 +1516,14 @@ namespace Barotrauma.Networking
yield return CoroutineStatus.Failure;
}
if (NetIdUtils.IdMoreRecent(campaignSaveID, campaign.PendingSaveID))
{
campaign.PendingSaveID = campaignSaveID;
DateTime saveFileTimeOut = DateTime.Now + new TimeSpan(0,0,60);
while (NetIdUtils.IdMoreRecent(campaignSaveID, campaign.LastSaveID))
{
if (DateTime.Now > saveFileTimeOut)
{
GameStarted = true;
DebugConsole.ThrowError("Failed to start campaign round (timed out while waiting for the up-to-date save file).");
GameMain.NetLobbyScreen.Select();
roundInitStatus = RoundInitStatus.Interrupted;
yield return CoroutineStatus.Failure;
}
yield return new WaitForSeconds(0.1f);
}
}
campaign.Map.SelectLocation(selectedLocationIndex);
LevelData levelData = nextLocationIndex > -1 ?
campaign.Map.Locations[nextLocationIndex].LevelData :
campaign.Map.Connections[nextConnectionIndex].LevelData;
debugStartGameCampaignSaveID = campaign.LastSaveID;
if (roundSummary != null)
{
loadTask = campaign.SelectSummaryScreen(roundSummary, levelData, mirrorLevel, null);
@@ -1697,7 +1717,7 @@ namespace Barotrauma.Networking
yield return CoroutineStatus.Success;
}
if (GameMain.GameSession != null) { GameMain.GameSession.EndRound(endMessage, traitorResults, transitionType); }
GameMain.GameSession?.EndRound(endMessage, traitorResults, transitionType);
ServerSettings.ServerDetailsChanged = true;
@@ -2587,31 +2607,24 @@ namespace Barotrauma.Networking
public void WriteCharacterInfo(IWriteMessage msg, string newName = null)
{
msg.WriteBoolean(characterInfo == null);
msg.WritePadBits();
if (characterInfo == null) { return; }
msg.WriteString(newName ?? string.Empty);
var head = characterInfo.Head;
msg.WriteByte((byte)characterInfo.Head.Preset.TagSet.Count);
foreach (Identifier tag in characterInfo.Head.Preset.TagSet)
{
msg.WriteIdentifier(tag);
}
msg.WriteByte((byte)characterInfo.Head.HairIndex);
msg.WriteByte((byte)characterInfo.Head.BeardIndex);
msg.WriteByte((byte)characterInfo.Head.MoustacheIndex);
msg.WriteByte((byte)characterInfo.Head.FaceAttachmentIndex);
msg.WriteColorR8G8B8(characterInfo.Head.SkinColor);
msg.WriteColorR8G8B8(characterInfo.Head.HairColor);
msg.WriteColorR8G8B8(characterInfo.Head.FacialHairColor);
var netInfo = new NetCharacterInfo(
NewName: newName ?? string.Empty,
Tags: head.Preset.TagSet.ToImmutableArray(),
HairIndex: (byte)head.HairIndex,
BeardIndex: (byte)head.BeardIndex,
MoustacheIndex: (byte)head.MoustacheIndex,
FaceAttachmentIndex: (byte)head.FaceAttachmentIndex,
SkinColor: head.SkinColor,
HairColor: head.HairColor,
FacialHairColor: head.FacialHairColor,
JobVariants: GameMain.NetLobbyScreen.JobPreferences.Select(NetJobVariant.FromJobVariant).ToImmutableArray());
var jobPreferences = GameMain.NetLobbyScreen.JobPreferences;
int count = Math.Min(jobPreferences.Count, 3);
msg.WriteByte((byte)count);
for (int i = 0; i < count; i++)
{
msg.WriteIdentifier(jobPreferences[i].Prefab.Identifier);
msg.WriteByte((byte)jobPreferences[i].Variant);
}
msg.WriteNetSerializableStruct(netInfo);
}
public void Vote(VoteType voteType, object data)
@@ -2864,12 +2877,14 @@ namespace Barotrauma.Networking
ClientPeer.Send(msg, DeliveryMethod.Reliable);
}
public bool SpectateClicked(GUIButton button, object userData)
public bool SpectateClicked(GUIButton button, object _)
{
MultiPlayerCampaign campaign =
MultiPlayerCampaign campaign =
GameMain.NetLobbyScreen.SelectedMode == GameMain.GameSession?.GameMode.Preset ?
GameMain.GameSession?.GameMode as MultiPlayerCampaign : null;
if (campaign != null && campaign.LastSaveID < campaign.PendingSaveID)
if (FileReceiver.ActiveTransfers.Any(t => t.FileType == FileTransferType.CampaignSave) ||
(campaign != null && NetIdUtils.IdMoreRecent(campaign.PendingSaveID, campaign.LastSaveID)))
{
new GUIMessageBox("", TextManager.Get("campaignfiletransferinprogress"));
return false;
@@ -92,10 +92,10 @@ namespace Barotrauma.Networking
Name = GameMain.Client.Name,
OwnerKey = ownerKey,
SteamId = SteamManager.GetSteamId().Select(id => (AccountId)id),
SteamAuthTicket = steamAuthTicket switch
SteamAuthTicket = steamAuthTicket?.Data switch
{
null => Option<byte[]>.None(),
var ticket => Option<byte[]>.Some(ticket.Data)
var ticketData => Option<byte[]>.Some(ticketData)
},
GameVersion = GameMain.Version.ToString(),
Language = GameSettings.CurrentConfig.Language.Value
@@ -111,8 +111,25 @@ namespace Barotrauma.Networking
? NetworkConnection.TimeoutThresholdInGame
: NetworkConnection.TimeoutThreshold;
IReadMessage inc = new ReadOnlyMessage(data, false, 0, dataLength, ServerConnection);
try
{
IReadMessage inc = new ReadOnlyMessage(data, false, 0, dataLength, ServerConnection);
ProcessP2PData(inc);
}
catch (Exception e)
{
string errorMsg = $"Client failed to read an incoming P2P message. {{{e}}}\n{e.StackTrace.CleanupStackTrace()}";
GameAnalyticsManager.AddErrorEventOnce($"SteamP2PClientPeer.OnP2PData:ClientReadException{e.TargetSite}", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
#if DEBUG
DebugConsole.ThrowError(errorMsg);
#else
if (GameSettings.CurrentConfig.VerboseLogging) { DebugConsole.ThrowError(errorMsg); }
#endif
}
}
private void ProcessP2PData(IReadMessage inc)
{
var (deliveryMethod, packetHeader, initialization) = INetSerializableStruct.Read<PeerPacketHeaders>(inc);
if (!packetHeader.IsServerMessage()) { return; }
@@ -141,15 +141,31 @@ namespace Barotrauma.Networking
if (remotePeer.DisconnectTime != null) { return; }
var peerPacketHeaders = INetSerializableStruct.Read<PeerPacketHeaders>(inc);
PacketHeader packetHeader = peerPacketHeaders.PacketHeader;
try
{
ProcessP2PData(steamId, remotePeer, inc);
}
catch (Exception e)
{
string errorMsg = $"Server failed to read an incoming P2P message. {{{e}}}\n{e.StackTrace.CleanupStackTrace()}";
GameAnalyticsManager.AddErrorEventOnce($"SteamP2POwnerPeer.OnP2PData:OwnerReadException{e.TargetSite}", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
#if DEBUG
DebugConsole.ThrowError(errorMsg);
#else
if (GameSettings.CurrentConfig.VerboseLogging) { DebugConsole.ThrowError(errorMsg); }
#endif
}
}
if (!remotePeer.Authenticated && !remotePeer.Authenticating && packetHeader.IsConnectionInitializationStep())
private void ProcessP2PData(ulong steamId, RemotePeer remotePeer, IReadMessage inc)
{
var (deliveryMethod, packetHeader, connectionInitialization) = INetSerializableStruct.Read<PeerPacketHeaders>(inc);
if (remotePeer is { Authenticated: false, Authenticating: false } && packetHeader.IsConnectionInitializationStep())
{
remotePeer.DisconnectTime = null;
ConnectionInitialization initialization = peerPacketHeaders.Initialization ?? throw new Exception("Initialization step missing");
ConnectionInitialization initialization = connectionInitialization ?? throw new Exception("Initialization step missing");
if (initialization == ConnectionInitialization.SteamTicketAndVersion)
{
remotePeer.Authenticating = true;
@@ -181,6 +197,7 @@ namespace Barotrauma.Networking
ForwardToServerProcess(outMsg);
}
}
public override void Update(float deltaTime)
@@ -428,7 +428,7 @@ namespace Barotrauma.Networking
if (Enum.TryParse(valueGetter("playstyle"), out PlayStyle playStyle)) { PlayStyle = playStyle; }
Language = valueGetter("language")?.ToLanguageIdentifier() ?? LanguageIdentifier.None;
ContentPackages = ExtractContentPackageInfo(valueGetter).ToImmutableArray();
ContentPackages = ExtractContentPackageInfo(ServerName, valueGetter).ToImmutableArray();
bool getBool(string key)
{
@@ -437,8 +437,34 @@ namespace Barotrauma.Networking
}
}
private static ContentPackageInfo[] ExtractContentPackageInfo(Func<string, string?> valueGetter)
private static ContentPackageInfo[] ExtractContentPackageInfo(string serverName, Func<string, string?> valueGetter)
{
//workaround to ServerRules queries truncating the values to 255 bytes
int individualPackageIndex = 0;
string? individualPackage = valueGetter($"contentpackage{individualPackageIndex}");
if (!individualPackage.IsNullOrEmpty())
{
List<ContentPackageInfo> contentPackages = new List<ContentPackageInfo>();
do
{
string[] splitPackageInfo = individualPackage.Split(',');
if (splitPackageInfo.Length != 3)
{
DebugConsole.Log(
$"Error in a server's content package list: malformed content package info ({individualPackage}).");
return Array.Empty<ContentPackageInfo>();
}
string name = splitPackageInfo[0];
string hash = splitPackageInfo[1];
ulong.TryParse(splitPackageInfo[2], out ulong id);
contentPackages.Add(new ContentPackageInfo(name, hash, Option<ContentPackageId>.Some(new SteamWorkshopId(id))));
individualPackageIndex++;
individualPackage = valueGetter($"contentpackage{individualPackageIndex}");
} while (!individualPackage.IsNullOrEmpty());
return contentPackages.ToArray();
}
string? joinedNames = valueGetter("contentpackage");
string? joinedHashes = valueGetter("contentpackagehash");
string? joinedWorkshopIds = valueGetter("contentpackageid");
@@ -448,9 +474,11 @@ namespace Barotrauma.Networking
#warning TODO: genericize
ulong[] contentPackageIds = joinedWorkshopIds.IsNullOrEmpty() ? new ulong[1] : SteamManager.ParseWorkshopIds(joinedWorkshopIds).ToArray();
if (contentPackageNames.Length != contentPackageHashes.Length
|| contentPackageHashes.Length != contentPackageIds.Length)
if (contentPackageNames.Length != contentPackageHashes.Length || contentPackageHashes.Length != contentPackageIds.Length)
{
DebugConsole.Log(
$"The number of names, hashes and Workshop IDs on server \"{serverName}\"" +
$" doesn't match: {contentPackageNames.Length} names ({string.Join(", ", contentPackageNames)}), {contentPackageHashes.Length} hashes, {contentPackageIds.Length} ids)");
return Array.Empty<ContentPackageInfo>();
}
@@ -35,7 +35,7 @@ namespace Barotrauma
}
private static Option<ServerInfo> InfoFromListEntry(Steamworks.Data.ServerInfo entry) =>
entry.Name.IsNullOrEmpty()
entry.Name.IsNullOrEmpty() || entry.Address is null
? Option<ServerInfo>.None()
: Option<ServerInfo>.Some(new ServerInfo(new LidgrenEndpoint(entry.Address, entry.ConnectionPort))
{
@@ -71,10 +71,10 @@ namespace Barotrauma
foreach (var lobby in lobbies)
{
string lobbyOwnerStr = lobby.GetData("lobbyowner");
string lobbyOwnerStr = lobby.GetData("lobbyowner") ?? "";
lobbyQuery = lobbyQuery.WithoutKeyValue("lobbyowner", lobbyOwnerStr);
string serverName = lobby.GetData("name");
string serverName = lobby.GetData("name") ?? "";
if (string.IsNullOrEmpty(serverName)) { continue; }
var ownerId = SteamId.Parse(lobbyOwnerStr);
@@ -9,6 +9,9 @@ namespace Barotrauma.Networking
{
partial class ServerSettings : ISerializableEntity
{
private static readonly LocalizedString packetAmountTooltip = TextManager.Get("ServerSettingsMaxPacketAmountTooltip");
private static readonly RichString packetAmountTooltipWarning = RichString.Rich($"{packetAmountTooltip}\n\n‖color:gui.red‖{TextManager.Get("PacketLimitWarning")}‖end‖");
partial class NetPropertyData
{
public GUIComponent GUIComponent;
@@ -28,7 +31,15 @@ namespace Barotrauma.Networking
if (GUIComponent == null) return null;
else if (GUIComponent is GUITickBox tickBox) return tickBox.Selected;
else if (GUIComponent is GUITextBox textBox) return textBox.Text;
else if (GUIComponent is GUIScrollBar scrollBar) return scrollBar.BarScrollValue;
else if (GUIComponent is GUIScrollBar scrollBar)
{
if (property.PropertyType == typeof(int))
{
return (int)MathF.Floor(scrollBar.BarScrollValue);
}
return scrollBar.BarScrollValue;
}
else if (GUIComponent is GUIRadioButtonGroup radioButtonGroup) return radioButtonGroup.Selected;
else if (GUIComponent is GUIDropDown dropdown) return dropdown.SelectedData;
else if (GUIComponent is GUINumberInput numInput)
@@ -44,9 +55,9 @@ namespace Barotrauma.Networking
else if (GUIComponent is GUITextBox textBox) textBox.Text = (string)value;
else if (GUIComponent is GUIScrollBar scrollBar)
{
if (value.GetType() == typeof(int))
if (value is int i)
{
scrollBar.BarScrollValue = (int)value;
scrollBar.BarScrollValue = i;
}
else
{
@@ -941,11 +952,58 @@ namespace Barotrauma.Networking
return true;
};
GUILayoutGroup karmaAndDosLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.2f), antigriefingTab.RectTransform), isHorizontal: false);
GUILayoutGroup lowerLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), karmaAndDosLayout.RectTransform), isHorizontal: true);
GUILayoutGroup upperLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), karmaAndDosLayout.RectTransform), isHorizontal: true);
// karma --------------------------------------------------------------------------
var karmaBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), antigriefingTab.RectTransform), TextManager.Get("ServerSettingsUseKarma"));
var karmaBox = new GUITickBox(new RectTransform(new Vector2(0.5f, 1f), upperLayout.RectTransform), TextManager.Get("ServerSettingsUseKarma"));
GetPropertyData(nameof(KarmaEnabled)).AssignGUIComponent(karmaBox);
var enableDosProtection = new GUITickBox(new RectTransform(new Vector2(0.5f, 1f), upperLayout.RectTransform), TextManager.Get("ServerSettingsEnableDoSProtection"))
{
ToolTip = TextManager.Get("ServerSettingsEnableDoSProtectionTooltip")
};
GetPropertyData(nameof(EnableDoSProtection)).AssignGUIComponent(enableDosProtection);
CreateLabeledSlider(lowerLayout, "ServerSettingsMaxPacketAmount", out GUIScrollBar maxPacketSlider, out GUITextBlock maxPacketSliderLabel);
LocalizedString maxPacketCountLabel = maxPacketSliderLabel.Text;
maxPacketSlider.Step = 0.001f;
maxPacketSlider.Range = new Vector2(PacketLimitMin, PacketLimitMax);
maxPacketSlider.ToolTip = packetAmountTooltip;
maxPacketSlider.OnMoved = (scrollBar, _) =>
{
GUITextBlock textBlock = (GUITextBlock)scrollBar.UserData;
int value = (int)MathF.Floor(scrollBar.BarScrollValue);
LocalizedString valueText = value > PacketLimitMin
? value.ToString()
: TextManager.Get("ServerSettingsNoLimit");
switch (value)
{
case <= PacketLimitMin:
textBlock.TextColor = GUIStyle.Green;
scrollBar.ToolTip = packetAmountTooltip;
break;
case < PacketLimitWarning:
textBlock.TextColor = GUIStyle.Red;
scrollBar.ToolTip = packetAmountTooltipWarning;
break;
default:
textBlock.TextColor = GUIStyle.TextColorNormal;
scrollBar.ToolTip = packetAmountTooltip;
break;
}
textBlock.Text = $"{maxPacketCountLabel} {valueText}";
return true;
};
GetPropertyData(nameof(MaxPacketAmount)).AssignGUIComponent(maxPacketSlider);
maxPacketSlider.OnMoved(maxPacketSlider, maxPacketSlider.BarScroll);
karmaPresetDD = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), antigriefingTab.RectTransform));
foreach (string karmaPreset in GameMain.NetworkMember.KarmaManager.Presets.Keys)
{
@@ -276,6 +276,8 @@ namespace Barotrauma.Networking
if (GameMain.Client?.Character != null)
{
var messageType = !ForceLocal && ChatMessage.CanUseRadio(GameMain.Client.Character, out _) ? ChatMessageType.Radio : ChatMessageType.Default;
if (GameMain.Client.Character.IsDead) { messageType = ChatMessageType.Dead; }
GameMain.Client.Character.ShowSpeechBubble(1.25f, ChatMessage.MessageColor[(int)messageType]);
}
//encode audio and enqueue it
@@ -146,7 +146,7 @@ namespace Barotrauma.Networking
if ((client.VoipSound.CurrentAmplitude * client.VoipSound.Gain * GameMain.SoundManager.GetCategoryGainMultiplier("voip")) > 0.1f) //TODO: might need to tweak
{
if (client.Character != null && !client.Character.Removed)
if (client.Character != null && !client.Character.Removed && !client.Character.IsDead)
{
Vector3 clientPos = new Vector3(client.Character.WorldPosition.X, client.Character.WorldPosition.Y, 0.0f);
Vector3 listenerPos = GameMain.SoundManager.ListenerPosition;