Unstable v0.15.17.0 (Hex is out of town edition)

This commit is contained in:
Juan Pablo Arce
2021-12-03 13:31:10 -03:00
parent cd5c8f3e13
commit 617d9ede88
245 changed files with 8088 additions and 5842 deletions
@@ -269,7 +269,7 @@ namespace Barotrauma
{
string errorMsg = "Failed to write input to command line (window width: " + Console.WindowWidth + ", window height: " + Console.WindowHeight + ")\n"
+ e.Message + "\n" + e.StackTrace.CleanupStackTrace();
GameAnalyticsManager.AddErrorEventOnce("DebugConsole.RewriteInputToCommandLine", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("DebugConsole.RewriteInputToCommandLine", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
}
}
@@ -1588,10 +1588,6 @@ namespace Barotrauma
if (tpCharacter != null)
{
tpCharacter.TeleportTo(cursorWorldPos);
if (tpCharacter.AIController?.SteeringManager is IndoorsSteeringManager pathSteering)
{
pathSteering.ResetPath();
}
}
}
);
@@ -1,7 +1,6 @@
using Barotrauma.Networking;
using Barotrauma.Steam;
using FarseerPhysics.Dynamics;
using GameAnalyticsSDK.Net;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
@@ -98,8 +97,9 @@ namespace Barotrauma
Console.WriteLine("Initializing SteamManager");
SteamManager.Initialize();
Console.WriteLine("Initializing GameAnalytics");
if (GameSettings.SendUserStatistics) GameAnalyticsManager.Init();
//TODO: figure out how consent is supposed to work for servers
//Console.WriteLine("Initializing GameAnalytics");
//GameAnalyticsManager.InitIfConsented();
Console.WriteLine("Initializing GameScreen");
GameScreen = new GameScreen();
@@ -418,7 +418,7 @@ namespace Barotrauma
SaveUtil.CleanUnnecessarySaveFiles();
if (GameSettings.SaveDebugConsoleLogs || GameSettings.VerboseLogging) { DebugConsole.SaveLogs(); }
if (GameSettings.SendUserStatistics) { GameAnalytics.OnQuit(); }
if (GameAnalyticsManager.SendUserStatistics) { GameAnalyticsManager.ShutDown(); }
MainThread = null;
}
@@ -13,7 +13,7 @@ namespace Barotrauma
get { return itemData != null; }
}
public CharacterCampaignData(Client client, bool giveRespawnPenaltyAffliction = false)
public CharacterCampaignData(Client client)
{
Name = client.Name;
ClientEndPoint = client.Connection.EndPointString;
@@ -22,13 +22,6 @@ namespace Barotrauma
healthData = new XElement("health");
client.Character?.CharacterHealth?.Save(healthData);
if (giveRespawnPenaltyAffliction)
{
var respawnPenaltyAffliction = RespawnManager.GetRespawnPenaltyAffliction();
healthData.Add(new XElement("Affliction",
new XAttribute("identifier", respawnPenaltyAffliction.Identifier),
new XAttribute("strength", respawnPenaltyAffliction.Strength.ToString("G", CultureInfo.InvariantCulture))));
}
if (client.Character?.Inventory != null)
{
itemData = new XElement("inventory");
@@ -211,18 +211,6 @@ namespace Barotrauma
{
c.Character = null;
}
if (c.HasSpawned && c.CharacterInfo != null && c.CharacterInfo.CauseOfDeath != null && c.CharacterInfo.CauseOfDeath.Type != CauseOfDeathType.Disconnected)
{
//the client has opted to spawn this round with Reaper's Tax
if (c.WaitForNextRoundRespawn.HasValue && !c.WaitForNextRoundRespawn.Value)
{
c.CharacterInfo.StartItemsGiven = false;
characterData.RemoveAll(cd => cd.MatchesClient(c));
characterData.Add(new CharacterCampaignData(c, giveRespawnPenaltyAffliction: true));
continue;
}
}
//use the info of the character the client is currently controlling
// or the previously saved info if not (e.g. if the client has been spectating or died)
var characterInfo = c.Character?.Info ?? characterData.Find(d => d.MatchesClient(c))?.CharacterInfo;
@@ -231,6 +219,7 @@ namespace Barotrauma
if (characterInfo.CauseOfDeath != null && characterInfo.CauseOfDeath.Type != CauseOfDeathType.Disconnected)
{
RespawnManager.ReduceCharacterSkills(characterInfo);
characterInfo.RemoveSavedStatValuesOnDeath();
}
c.CharacterInfo = characterInfo;
characterData.RemoveAll(cd => cd.MatchesClient(c));
@@ -358,6 +347,7 @@ namespace Barotrauma
}
}
}
UpdateCampaignSubs();
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
PendingSubmarineSwitch = null;
@@ -400,20 +390,50 @@ namespace Barotrauma
partial void InitProjSpecific()
{
if (GameMain.Server != null)
{
CargoManager.OnItemsInBuyCrateChanged += () => { LastUpdateID++; };
CargoManager.OnPurchasedItemsChanged += () => { LastUpdateID++; };
CargoManager.OnSoldItemsChanged += () => { LastUpdateID++; };
UpgradeManager.OnUpgradesChanged += () => { LastUpdateID++; };
Map.OnLocationSelected += (loc, connection) => { LastUpdateID++; };
Map.OnMissionsSelected += (loc, mission) => { LastUpdateID++; };
Reputation.OnAnyReputationValueChanged += () => { LastUpdateID++; };
}
CargoManager.OnItemsInBuyCrateChanged += () => { LastUpdateID++; };
CargoManager.OnPurchasedItemsChanged += () => { LastUpdateID++; };
CargoManager.OnSoldItemsChanged += () => { LastUpdateID++; };
UpgradeManager.OnUpgradesChanged += () => { LastUpdateID++; };
Map.OnLocationSelected += (loc, connection) => { LastUpdateID++; };
Map.OnMissionsSelected += (loc, mission) => { LastUpdateID++; };
Reputation.OnAnyReputationValueChanged += () => { LastUpdateID++; };
UpdateCampaignSubs();
//increment save ID so clients know they're lacking the most up-to-date save file
LastSaveID++;
}
private void UpdateCampaignSubs()
{
bool isSubmarineVisible(SubmarineInfo s)
=> !GameMain.Server.ServerSettings.HiddenSubs.Any(h
=> s.Name.Equals(h, StringComparison.OrdinalIgnoreCase));
List<SubmarineInfo> availableSubs =
SubmarineInfo.SavedSubmarines
.Where(s =>
s.IsCampaignCompatible
&& isSubmarineVisible(s))
.ToList();
if (!availableSubs.Any())
{
//None of the available subs were marked as campaign-compatible, just include all visible subs
availableSubs.AddRange(
SubmarineInfo.SavedSubmarines
.Where(isSubmarineVisible));
}
if (!availableSubs.Any())
{
//No subs are visible at all! Just make the selected one available
availableSubs.Add(GameMain.NetLobbyScreen.SelectedSub);
}
GameMain.NetLobbyScreen.CampaignSubmarines = availableSubs;
}
public void DiscardClientCharacterData(Client client)
{
characterData.RemoveAll(cd => cd.MatchesClient(client));
@@ -1030,14 +1050,6 @@ namespace Barotrauma
new XAttribute("points", savedExperiencePoint.ExperiencePoints)));
}
// save available submarines
XElement availableSubsElement = new XElement("AvailableSubs");
for (int i = 0; i < GameMain.NetLobbyScreen.CampaignSubmarines.Count; i++)
{
availableSubsElement.Add(new XElement("Sub", new XAttribute("name", GameMain.NetLobbyScreen.CampaignSubmarines[i].Name)));
}
modeElement.Add(availableSubsElement);
element.Add(modeElement);
//save character data to a separate file
@@ -14,6 +14,7 @@ namespace Barotrauma.Items.Components
{
if (c.Character == null) { return; }
var requestedFixAction = (FixActions)msg.ReadRangedInteger(0, 2);
var QTESuccess = msg.ReadBoolean();
if (requestedFixAction != FixActions.None)
{
if (!c.Character.IsTraitor && requestedFixAction == FixActions.Sabotage)
@@ -31,6 +32,11 @@ namespace Barotrauma.Items.Components
item.CreateServerEvent(this);
}
}
else
{
RepairBoost(QTESuccess);
item.CreateServerEvent(this);
}
}
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
@@ -42,6 +48,7 @@ namespace Barotrauma.Items.Components
msg.Write(tinkeringStrength);
msg.Write(CurrentFixer == null ? (ushort)0 : CurrentFixer.ID);
msg.WriteRangedInteger((int)currentFixerAction, 0, 2);
msg.Write(repairBoost);
}
}
}
@@ -41,7 +41,7 @@ namespace Barotrauma
}
msg.WriteRangedInteger((int)NetEntityEvent.Type.Invalid, 0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1);
DebugConsole.Log(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("Item.ServerWrite:InvalidData" + Name, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("Item.ServerWrite:InvalidData" + Name, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
return;
}
@@ -186,7 +186,7 @@ namespace Barotrauma
msg.LengthBits = initialWritePos;
msg.WriteRangedInteger((int)NetEntityEvent.Type.Invalid, 0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1);
DebugConsole.Log(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("Item.ServerWrite:" + errorMsg, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("Item.ServerWrite:" + errorMsg, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
}
}
@@ -402,7 +402,7 @@ namespace Barotrauma
{
string errorMsg = "Attempted to create a network event for an item (" + Name + ") that hasn't been fully initialized yet.\n" + Environment.StackTrace.CleanupStackTrace();
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("Item.CreateServerEvent:EventForUninitializedItem" + Name + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("Item.CreateServerEvent:EventForUninitializedItem" + Name + ID, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
return;
}
@@ -423,7 +423,7 @@ namespace Barotrauma
{
string errorMsg = "Attempted to create a network event for an item (" + Name + ") that hasn't been fully initialized yet.\n" + Environment.StackTrace.CleanupStackTrace();
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("Item.CreateServerEvent:EventForUninitializedItem" + Name + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("Item.CreateServerEvent:EventForUninitializedItem" + Name + ID, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
return;
}
@@ -274,6 +274,8 @@ namespace Barotrauma.Networking
public void Save()
{
GameServer.Log("Saving banlist", ServerLog.MessageType.ServerMessage);
GameMain.Server?.ServerSettings?.UpdateFlag(ServerSettings.NetFlags.Properties);
bannedPlayers.RemoveAll(bp => bp.ExpirationTime.HasValue && DateTime.Now > bp.ExpirationTime.Value);
@@ -344,7 +346,7 @@ namespace Barotrauma.Networking
catch (Exception e)
{
string errorMsg = "Error while writing banlist. {" + e + "}\n" + e.StackTrace.CleanupStackTrace();
GameAnalyticsManager.AddErrorEventOnce("Banlist.ServerAdminWrite", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("Banlist.ServerAdminWrite", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
throw;
}
}
@@ -278,7 +278,7 @@ namespace Barotrauma.Networking
DebugConsole.ThrowError("FileSender threw an exception when trying to send data", e);
GameAnalyticsManager.AddErrorEventOnce(
"FileSender.Update:Exception",
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
GameAnalyticsManager.ErrorSeverity.Error,
"FileSender threw an exception when trying to send data:\n" + e.Message + "\n" + e.StackTrace.CleanupStackTrace());
transfer.Status = FileTransferStatus.Error;
return;
@@ -600,16 +600,19 @@ namespace Barotrauma.Networking
//constantly increase AFK timer if the client is controlling a character (gets reset to zero every time an input is received)
if (gameStarted && c.Character != null && !c.Character.IsDead && !c.Character.IsIncapacitated)
{
if (c.Connection != OwnerConnection) c.KickAFKTimer += deltaTime;
if (c.Connection != OwnerConnection && c.Permissions != ClientPermissions.All) { c.KickAFKTimer += deltaTime; }
}
}
IEnumerable<Client> kickAFK = connectedClients.FindAll(c =>
c.KickAFKTimer >= serverSettings.KickAFKTime &&
(OwnerConnection == null || c.Connection != OwnerConnection));
foreach (Client c in kickAFK)
if (connectedClients.Any(c => c.KickAFKTimer >= serverSettings.KickAFKTime))
{
KickClient(c, "DisconnectMessage.AFK");
IEnumerable<Client> kickAFK = connectedClients.FindAll(c =>
c.KickAFKTimer >= serverSettings.KickAFKTime &&
(OwnerConnection == null || c.Connection != OwnerConnection));
foreach (Client c in kickAFK)
{
KickClient(c, "DisconnectMessage.AFK");
}
}
serverPeer.Update(deltaTime);
@@ -632,7 +635,7 @@ namespace Barotrauma.Networking
{
DebugConsole.ThrowError("Failed to write a network message for the client \"" + c.Name + "\"!", e);
string errorMsg = "Failed to write a network message for the client \"" + c.Name + "\"! (MidRoundSyncing: " + c.NeedsMidRoundSync + ")\n"
string errorMsg = "Failed to write a network message for a client! (MidRoundSyncing: " + c.NeedsMidRoundSync + ")\n"
+ e.Message + "\n" + e.StackTrace.CleanupStackTrace();
if (e.InnerException != null)
{
@@ -641,7 +644,7 @@ namespace Barotrauma.Networking
GameAnalyticsManager.AddErrorEventOnce(
"GameServer.Update:ClientWriteFailed" + e.StackTrace.CleanupStackTrace(),
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
GameAnalyticsManager.ErrorSeverity.Error,
errorMsg);
}
}
@@ -791,6 +794,8 @@ namespace Barotrauma.Networking
string localSavePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Multiplayer, saveName);
if (connectedClient.HasPermission(ClientPermissions.SelectMode) || connectedClient.HasPermission(ClientPermissions.ManageCampaign))
{
ServerSettings.RadiationEnabled = settings.RadiationEnabled;
ServerSettings.MaxMissionCount = settings.MaxMissionCount;
MultiPlayerCampaign.StartNewCampaign(localSavePath, matchingSub.FilePath, seed, settings);
}
}
@@ -854,6 +859,7 @@ namespace Barotrauma.Networking
private void HandleClientError(IReadMessage inc, Client c)
{
string errorStr = "Unhandled error report";
string errorStrNoName = errorStr;
ClientNetError error = (ClientNetError)inc.ReadByte();
switch (error)
@@ -861,7 +867,7 @@ namespace Barotrauma.Networking
case ClientNetError.MISSING_EVENT:
UInt16 expectedID = inc.ReadUInt16();
UInt16 receivedID = inc.ReadUInt16();
errorStr = "Expecting event id " + expectedID.ToString() + ", received " + receivedID.ToString();
errorStr = errorStrNoName = "Expecting event id " + expectedID.ToString() + ", received " + receivedID.ToString();
break;
case ClientNetError.MISSING_ENTITY:
UInt16 eventID = inc.ReadUInt16();
@@ -869,25 +875,26 @@ namespace Barotrauma.Networking
Entity entity = Entity.FindEntityByID(entityID);
if (entity == null)
{
errorStr = "Received an update for an entity that doesn't exist (event id " + eventID.ToString() + ", entity id " + entityID.ToString() + ").";
errorStr = errorStrNoName = "Received an update for an entity that doesn't exist (event id " + eventID.ToString() + ", entity id " + entityID.ToString() + ").";
}
else if (entity is Character character)
{
errorStr = "Missing character " + character.Name + " (event id " + eventID.ToString() + ", entity id " + entityID.ToString() + ").";
errorStrNoName = "Missing character " + character.SpeciesName + "(event id " + eventID.ToString() + ", entity id " + entityID.ToString() + ").";
}
else if (entity is Item item)
{
errorStr = "Missing item " + item.Name + " (event id " + eventID.ToString() + ", entity id " + entityID.ToString() + ").";
errorStr = errorStrNoName = "Missing item " + item.Name + " (event id " + eventID.ToString() + ", entity id " + entityID.ToString() + ").";
}
else
{
errorStr = "Missing entity " + entity.ToString() + " (event id " + eventID.ToString() + ", entity id " + entityID.ToString() + ").";
errorStr = errorStrNoName = "Missing entity " + entity.ToString() + " (event id " + eventID.ToString() + ", entity id " + entityID.ToString() + ").";
}
break;
}
Log(GameServer.ClientLogName(c) + " has reported an error: " + errorStr, ServerLog.MessageType.Error);
GameAnalyticsManager.AddErrorEventOnce("GameServer.HandleClientError:" + errorStr, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorStr);
Log(ClientLogName(c) + " has reported an error: " + errorStr, ServerLog.MessageType.Error);
GameAnalyticsManager.AddErrorEventOnce("GameServer.HandleClientError:" + errorStrNoName, GameAnalyticsManager.ErrorSeverity.Error, errorStr);
try
{
@@ -1392,49 +1399,23 @@ namespace Barotrauma.Networking
}
break;
case ClientPermissions.SelectSub:
bool isCampaign = inc.ReadBoolean();
if (!isCampaign)
bool isShuttle = inc.ReadBoolean();
inc.ReadPadBits();
UInt16 subIndex = inc.ReadUInt16();
var subList = GameMain.NetLobbyScreen.GetSubList();
if (subIndex >= subList.Count)
{
bool isShuttle = inc.ReadBoolean();
inc.ReadPadBits();
UInt16 subIndex = inc.ReadUInt16();
var subList = GameMain.NetLobbyScreen.GetSubList();
if (subIndex >= subList.Count)
{
DebugConsole.NewMessage("Client \"" + GameServer.ClientLogName(sender) + "\" attempted to select a sub, index out of bounds (" + subIndex + ")", Color.Red);
}
else
{
if (isShuttle)
{
GameMain.NetLobbyScreen.SelectedShuttle = subList[subIndex];
}
else
{
GameMain.NetLobbyScreen.SelectedSub = subList[subIndex];
}
}
DebugConsole.NewMessage($"Client \"{ClientLogName(sender)}\" attempted to select a sub, index out of bounds ({subIndex})", Color.Red);
}
else
{
int subEqualityCheckVal = inc.ReadInt32();
bool add = inc.ReadBoolean();
SubmarineInfo sub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.EqualityCheckVal == subEqualityCheckVal);
if (sub == null)
if (isShuttle)
{
DebugConsole.NewMessage("Client \"" + GameServer.ClientLogName(sender) + "\" attempted to select a sub that does not exist on the server!", Color.Red);
GameMain.NetLobbyScreen.SelectedShuttle = subList[subIndex];
}
else
{
if (add)
{
GameMain.NetLobbyScreen.AddCampaignSubmarine(sub);
}
else
{
GameMain.NetLobbyScreen.RemoveCampaignSubmarine(sub);
}
GameMain.NetLobbyScreen.SelectedSub = subList[subIndex];
}
}
break;
@@ -1751,7 +1732,7 @@ namespace Barotrauma.Networking
" Chat message size: " + chatMessageBytes + " bytes\n" +
" Position update size: " + positionUpdateBytes + " bytes\n\n";
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameServer.ClientWriteIngame1:PacketSizeExceeded" + outmsg.LengthBytes, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameServer.ClientWriteIngame1:PacketSizeExceeded" + outmsg.LengthBytes, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
}
serverPeer.Send(outmsg, c.Connection, DeliveryMethod.Unreliable);
@@ -1791,7 +1772,7 @@ namespace Barotrauma.Networking
}
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameServer.ClientWriteIngame2:PacketSizeExceeded" + outmsg.LengthBytes, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameServer.ClientWriteIngame2:PacketSizeExceeded" + outmsg.LengthBytes, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
}
serverPeer.Send(outmsg, c.Connection, DeliveryMethod.Unreliable);
@@ -1878,7 +1859,7 @@ namespace Barotrauma.Networking
List<int> campaignSubIndices = new List<int>();
if (GameMain.NetLobbyScreen.SelectedMode == GameModePreset.MultiPlayerCampaign)
{
List<SubmarineInfo> subList = GameMain.NetLobbyScreen.GetSubList();
IReadOnlyList<SubmarineInfo> subList = GameMain.NetLobbyScreen.GetSubList();
for (int i = 0; i < subList.Count; i++)
{
if (GameMain.NetLobbyScreen.CampaignSubmarines.Contains(subList[i]))
@@ -1916,9 +1897,6 @@ namespace Barotrauma.Networking
{
outmsg.Write(autoRestartTimerRunning ? serverSettings.AutoRestartTimer : 0.0f);
}
outmsg.Write(serverSettings.RadiationEnabled);
outmsg.Write((byte)serverSettings.MaxMissionCount);
}
else
{
@@ -1958,8 +1936,31 @@ namespace Barotrauma.Networking
chatMessageBytes = outmsg.LengthBytes - outmsg.LengthBytes;
outmsg.Write((byte)ServerNetObject.END_OF_MESSAGE);
if (isInitialUpdate)
bool messageTooLarge = outmsg.LengthBytes > MsgConstants.MTU;
if (messageTooLarge && !isInitialUpdate)
{
string warningMsg = "Maximum packet size exceeded, will send using reliable mode (" + outmsg.LengthBytes + " > " + MsgConstants.MTU + ")\n";
warningMsg +=
" Client list size: " + clientListBytes + " bytes\n" +
" Chat message size: " + chatMessageBytes + " bytes\n" +
" Campaign size: " + campaignBytes + " bytes\n" +
" Settings size: " + settingsBytes + " bytes\n";
if (initialUpdateBytes > 0)
{
warningMsg +=
" Initial update size: " + settingsBuf.LengthBytes + " bytes\n";
}
if (settingsBuf != null)
{
warningMsg +=
" Settings buffer size: " + settingsBuf.LengthBytes + " bytes\n";
}
if (GameSettings.VerboseLogging) { DebugConsole.AddWarning(warningMsg); }
GameAnalyticsManager.AddErrorEventOnce("GameServer.ClientWriteIngame1:ClientWriteLobby" + outmsg.LengthBytes, GameAnalyticsManager.ErrorSeverity.Warning, warningMsg);
}
if (isInitialUpdate || messageTooLarge)
{
//the initial update may be very large if the host has a large number
//of submarine files, so the message may have to be fragmented
@@ -1975,28 +1976,6 @@ namespace Barotrauma.Networking
}
else
{
if (outmsg.LengthBytes > MsgConstants.MTU)
{
string errorMsg = "Maximum packet size exceeded (" + outmsg.LengthBytes + " > " + MsgConstants.MTU + ")\n";
errorMsg +=
" Client list size: " + clientListBytes + " bytes\n" +
" Chat message size: " + chatMessageBytes + " bytes\n" +
" Campaign size: " + campaignBytes + " bytes\n" +
" Settings size: " + settingsBytes + " bytes\n";
if (initialUpdateBytes > 0)
{
errorMsg +=
" Initial update size: " + settingsBuf.LengthBytes + " bytes\n";
}
if (settingsBuf != null)
{
errorMsg +=
" Settings buffer size: " + settingsBuf.LengthBytes + " bytes\n";
}
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameServer.ClientWriteIngame1:ClientWriteLobby" + outmsg.LengthBytes, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
}
serverPeer.Send(outmsg, c.Connection, DeliveryMethod.Unreliable);
}
}
@@ -2121,7 +2100,7 @@ namespace Barotrauma.Networking
startGameCoroutine = null;
string errorMsg = "Starting the round failed. Campaign was still active, but the map has been disposed. Try selecting another game mode.";
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameServer.StartGame:InvalidCampaignState", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameServer.StartGame:InvalidCampaignState", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
if (OwnerConnection != null)
{
SendDirectChatMessage(errorMsg, connectedClients.Find(c => c.Connection == OwnerConnection), ChatMessageType.Error);
@@ -2163,7 +2142,7 @@ namespace Barotrauma.Networking
{
string errorMsg = "Failed to start a campaign round (next level not set).";
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameServer.StartGame:InvalidCampaignState", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameServer.StartGame:InvalidCampaignState", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
if (OwnerConnection != null)
{
SendDirectChatMessage(errorMsg, connectedClients.Find(c => c.Connection == OwnerConnection), ChatMessageType.Error);
@@ -2392,6 +2371,9 @@ namespace Barotrauma.Networking
spawnedCharacter.TeamID = teamID;
spawnedCharacter.GiveJobItems(mainSubWaypoints[i]);
spawnedCharacter.GiveIdCardTags(mainSubWaypoints[i]);
spawnedCharacter.Info.InventoryData = new XElement("inventory");
spawnedCharacter.Info.StartItemsGiven = true;
spawnedCharacter.SaveInventory();
// talents are only avilable for players in online sessions, but modders or someone else might want to have them loaded anyway
spawnedCharacter.LoadTalents();
}
@@ -2953,7 +2935,7 @@ namespace Barotrauma.Networking
{
string errorMsg = "Attempted to send a chat message to a null client.\n" + Environment.StackTrace.CleanupStackTrace();
DebugConsole.ThrowError(errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameServer.SendDirectChatMessage:ClientNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("GameServer.SendDirectChatMessage:ClientNull", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
return;
}
@@ -3255,7 +3237,7 @@ namespace Barotrauma.Networking
BanClient(c, "ServerMessage.KickedByVoteAutoBan", duration: TimeSpan.FromSeconds(serverSettings.AutoBanTime));
}
GameMain.NetLobbyScreen.LastUpdateID++;
//GameMain.NetLobbyScreen.LastUpdateID++;
SendVoteStatus(connectedClients);
@@ -186,7 +186,7 @@ namespace Barotrauma.Networking
DebugConsole.ThrowError(errorMsg, e);
}
GameAnalyticsManager.AddErrorEventOnce("ServerEntityEventManager.Read:ReadFailed" + entityName,
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
GameAnalyticsManager.ErrorSeverity.Error,
"Failed to read server event for entity \"" + entityName + "\"!\n" + e.StackTrace.CleanupStackTrace());
}
@@ -125,7 +125,7 @@ namespace Barotrauma.Networking
catch (Exception e)
{
string errorMsg = "Server failed to read an incoming message. {" + e + "}\n" + e.StackTrace.CleanupStackTrace();
GameAnalyticsManager.AddErrorEventOnce("LidgrenServerPeer.Update:ClientReadException" + e.TargetSite.ToString(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("LidgrenServerPeer.Update:ClientReadException" + e.TargetSite.ToString(), GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
#if DEBUG
DebugConsole.ThrowError(errorMsg);
#else
@@ -208,15 +208,13 @@ namespace Barotrauma.Networking
PendingClient pendingClient = pendingClients.Find(c => (c.Connection is LidgrenConnection l) && l.NetConnection == inc.SenderConnection);
byte incByte = inc.ReadByte();
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
PacketHeader packetHeader = (PacketHeader)inc.ReadByte();
if (isConnectionInitializationStep && pendingClient != null)
if (packetHeader.IsConnectionInitializationStep() && pendingClient != null)
{
ReadConnectionInitializationStep(pendingClient, new ReadWriteMessage(inc.Data, (int)inc.Position, inc.LengthBits, false));
}
else if (!isConnectionInitializationStep)
else if (!packetHeader.IsConnectionInitializationStep())
{
LidgrenConnection conn = connectedClients.Find(c => (c is LidgrenConnection l) && l.NetConnection == inc.SenderConnection) as LidgrenConnection;
if (conn == null)
@@ -242,7 +240,7 @@ namespace Barotrauma.Networking
//DebugConsole.NewMessage(isCompressed + " " + isConnectionInitializationStep + " " + (int)incByte + " " + length);
IReadMessage msg = new ReadOnlyMessage(inc.Data, isCompressed, inc.PositionInBytes, length, conn);
IReadMessage msg = new ReadOnlyMessage(inc.Data, packetHeader.IsCompressed(), inc.PositionInBytes, length, conn);
OnMessageReceived?.Invoke(conn, msg);
}
}
@@ -102,7 +102,7 @@ namespace Barotrauma.Networking
catch (Exception e)
{
string errorMsg = "Server failed to read an incoming message. {" + e + "}\n" + e.StackTrace.CleanupStackTrace();
GameAnalyticsManager.AddErrorEventOnce("SteamP2PServerPeer.Update:ClientReadException" + e.TargetSite.ToString(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
GameAnalyticsManager.AddErrorEventOnce("SteamP2PServerPeer.Update:ClientReadException" + e.TargetSite.ToString(), GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
#if DEBUG
DebugConsole.ThrowError(errorMsg);
#else
@@ -125,14 +125,9 @@ namespace Barotrauma.Networking
UInt64 senderSteamId = inc.ReadUInt64();
UInt64 ownerSteamId = inc.ReadUInt64();
byte incByte = inc.ReadByte();
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
bool isDisconnectMessage = (incByte & (byte)PacketHeader.IsDisconnectMessage) != 0;
bool isServerMessage = (incByte & (byte)PacketHeader.IsServerMessage) != 0;
bool isHeartbeatMessage = (incByte & (byte)PacketHeader.IsHeartbeatMessage) != 0;
PacketHeader packetHeader = (PacketHeader)inc.ReadByte();
if (isServerMessage)
if (packetHeader.IsServerMessage())
{
DebugConsole.ThrowError("Got server message from" + senderSteamId.ToString());
return;
@@ -160,7 +155,7 @@ namespace Barotrauma.Networking
}
return;
}
else if (isDisconnectMessage)
else if (packetHeader.IsDisconnectMessage())
{
if (pendingClient != null)
{
@@ -174,12 +169,12 @@ namespace Barotrauma.Networking
}
return;
}
else if (isHeartbeatMessage)
else if (packetHeader.IsHeartbeatMessage())
{
//message exists solely as a heartbeat, ignore its contents
return;
}
else if (isConnectionInitializationStep)
else if (packetHeader.IsConnectionInitializationStep())
{
if (pendingClient != null)
@@ -203,7 +198,7 @@ namespace Barotrauma.Networking
{
UInt16 length = inc.ReadUInt16();
IReadMessage msg = new ReadOnlyMessage(inc.Buffer, isCompressed, inc.BytePosition, length, connectedClient);
IReadMessage msg = new ReadOnlyMessage(inc.Buffer, packetHeader.IsCompressed(), inc.BytePosition, length, connectedClient);
OnMessageReceived?.Invoke(connectedClient, msg);
}
}
@@ -211,17 +206,17 @@ namespace Barotrauma.Networking
{
if (OwnerConnection != null) { (OwnerConnection as SteamP2PConnection).Heartbeat(); }
if (isDisconnectMessage)
if (packetHeader.IsDisconnectMessage())
{
DebugConsole.ThrowError("Received disconnect message from owner");
return;
}
if (isServerMessage)
if (packetHeader.IsServerMessage())
{
DebugConsole.ThrowError("Received server message from owner");
return;
}
if (isConnectionInitializationStep)
if (packetHeader.IsConnectionInitializationStep())
{
if (OwnerConnection == null)
{
@@ -236,7 +231,7 @@ namespace Barotrauma.Networking
}
return;
}
if (isHeartbeatMessage)
if (packetHeader.IsHeartbeatMessage())
{
return;
}
@@ -244,7 +239,7 @@ namespace Barotrauma.Networking
{
UInt16 length = inc.ReadUInt16();
IReadMessage msg = new ReadOnlyMessage(inc.Buffer, isCompressed, inc.BytePosition, length, OwnerConnection);
IReadMessage msg = new ReadOnlyMessage(inc.Buffer, packetHeader.IsCompressed(), inc.BytePosition, length, OwnerConnection);
OnMessageReceived?.Invoke(OwnerConnection, msg);
}
}
@@ -267,7 +262,7 @@ namespace Barotrauma.Networking
}
IWriteMessage msgToSend = new WriteOnlyMessage();
byte[] msgData = new byte[msg.LengthBytes];
byte[] msgData = new byte[16];
msg.PrepareForSending(ref msgData, out bool isCompressed, out int length);
msgToSend.Write(conn.SteamID);
msgToSend.Write((byte)deliveryMethod);
@@ -398,6 +398,7 @@ namespace Barotrauma.Networking
else
{
ReduceCharacterSkills(characterInfos[i]);
characterInfos[i].RemoveSavedStatValuesOnDeath();
}
}
}
@@ -14,6 +14,17 @@ namespace Barotrauma.Networking
public static readonly string ClientPermissionsFile = "Data" + Path.DirectorySeparatorChar + "clientpermissions.xml";
public static readonly char SubmarineSeparatorChar = '|';
public readonly Dictionary<NetFlags, UInt16> LastUpdateIdForFlag = new Dictionary<NetFlags, UInt16>();
public void UpdateFlag(NetFlags flag)
=> LastUpdateIdForFlag[flag] = (UInt16)(GameMain.NetLobbyScreen.LastUpdateID + 1);
public NetFlags GetRequiredFlags(Client c)
=> LastUpdateIdForFlag.Keys
.Where(k => LastUpdateIdForFlag[k] > c.LastRecvLobbyUpdate)
.Concat(NetFlags.None.ToEnumerable()) //prevents InvalidOperationException in Aggregate
.Aggregate((f1, f2) => f1 | f2);
partial void InitProjSpecific()
{
LoadSettings();
@@ -37,6 +48,9 @@ namespace Barotrauma.Networking
//outMsg.WritePadBits();
//outMsg.Write((UInt16)QueryPort);
NetFlags requiredFlags = GetRequiredFlags(c);
if (!requiredFlags.HasFlag(NetFlags.Properties)) { return; }
WriteNetProperties(outMsg);
WriteMonsterEnabled(outMsg);
BanList.ServerAdminWrite(outMsg, c);
@@ -45,8 +59,18 @@ namespace Barotrauma.Networking
public void ServerWrite(IWriteMessage outMsg, Client c)
{
outMsg.Write(ServerName);
outMsg.Write(ServerMessageText);
NetFlags requiredFlags = GetRequiredFlags(c);
outMsg.Write((byte)requiredFlags);
if (requiredFlags.HasFlag(NetFlags.Name))
{
outMsg.Write(ServerName);
}
if (requiredFlags.HasFlag(NetFlags.Message))
{
outMsg.Write(ServerMessageText);
}
outMsg.Write((byte)PlayStyle);
outMsg.Write((byte)MaxPlayers);
outMsg.Write(HasPassword);
outMsg.Write(IsPublic);
@@ -54,12 +78,13 @@ namespace Barotrauma.Networking
outMsg.WritePadBits();
outMsg.WriteRangedInteger(TickRate, 1, 60);
WriteExtraCargo(outMsg);
if (requiredFlags.HasFlag(NetFlags.Properties))
{
WriteExtraCargo(outMsg);
}
WriteHiddenSubs(outMsg);
Voting.ServerWrite(outMsg);
if (c.HasPermission(Networking.ClientPermissions.ManageSettings))
{
outMsg.Write(true);
@@ -85,20 +110,20 @@ namespace Barotrauma.Networking
if (flags.HasFlag(NetFlags.Name))
{
string serverName = incMsg.ReadString();
if (ServerName != serverName) changed = true;
if (ServerName != serverName) { changed = true; }
ServerName = serverName;
}
if (flags.HasFlag(NetFlags.Message))
{
string serverMessageText = incMsg.ReadString();
if (ServerMessageText != serverMessageText) changed = true;
if (ServerMessageText != serverMessageText) { changed = true; }
ServerMessageText = serverMessageText;
}
if (flags.HasFlag(NetFlags.Properties))
{
changed |= ReadExtraCargo(incMsg);
bool propertiesChanged = ReadExtraCargo(incMsg);
UInt32 count = incMsg.ReadUInt32();
@@ -114,7 +139,7 @@ namespace Barotrauma.Networking
{
GameServer.Log(GameServer.ClientLogName(c) + " changed " + netProperties[key].Name + " to " + netProperties[key].Value.ToString(), ServerLog.MessageType.ServerMessage);
}
changed = true;
propertiesChanged = true;
}
else
{
@@ -124,10 +149,13 @@ namespace Barotrauma.Networking
}
bool changedMonsterSettings = incMsg.ReadBoolean(); incMsg.ReadPadBits();
changed |= changedMonsterSettings;
if (changedMonsterSettings) ReadMonsterEnabled(incMsg);
changed |= BanList.ServerAdminRead(incMsg, c);
changed |= Whitelist.ServerAdminRead(incMsg, c);
propertiesChanged |= changedMonsterSettings;
if (changedMonsterSettings) { ReadMonsterEnabled(incMsg); }
propertiesChanged |= BanList.ServerAdminRead(incMsg, c);
propertiesChanged |= Whitelist.ServerAdminRead(incMsg, c);
if (propertiesChanged) { UpdateFlag(NetFlags.Properties); }
changed |= propertiesChanged;
}
if (flags.HasFlag(NetFlags.HiddenSubs))
@@ -175,12 +203,14 @@ namespace Barotrauma.Networking
MaxMissionCount = MathHelper.Clamp(maxMissionCount, CampaignSettings.MinMissionCountLimit, CampaignSettings.MaxMissionCountLimit);
changed |= true;
UpdateFlag(NetFlags.Misc);
}
if (flags.HasFlag(NetFlags.LevelSeed))
{
GameMain.NetLobbyScreen.LevelSeed = incMsg.ReadString();
changed |= true;
UpdateFlag(NetFlags.LevelSeed);
}
if (changed)
@@ -271,6 +301,8 @@ namespace Barotrauma.Networking
HiddenSubs.UnionWith(doc.Root.GetAttributeStringArray("HiddenSubs", Array.Empty<string>()));
SelectedSubmarine = SelectNonHiddenSubmarine(SelectedSubmarine);
string[] defaultAllowedClientNameChars =
new string[] {
"32-33",
@@ -345,7 +377,6 @@ namespace Barotrauma.Networking
GameMain.NetLobbyScreen.SetBotSpawnMode(BotSpawnMode);
GameMain.NetLobbyScreen.SetBotCount(BotCount);
GameMain.NetLobbyScreen.SetMaxMissionCount(MaxMissionCount);
List<string> monsterNames = CharacterPrefab.Prefabs.Select(p => p.Identifier).ToList();
MonsterEnabled = new Dictionary<string, bool>();
@@ -355,16 +386,25 @@ namespace Barotrauma.Networking
}
}
public void SelectNonHiddenSubmarine()
public string SelectNonHiddenSubmarine(string current = null)
{
if (HiddenSubs.Contains(GameMain.NetLobbyScreen.SelectedSub.Name))
current ??= GameMain.NetLobbyScreen.SelectedSub.Name;
if (HiddenSubs.Contains(current))
{
var candidates = GameMain.NetLobbyScreen.GetSubList().Where(s => !HiddenSubs.Contains(s.Name)).ToArray();
var candidates
= GameMain.NetLobbyScreen.GetSubList().Where(s => !HiddenSubs.Contains(s.Name)).ToArray();
if (candidates.Any())
{
GameMain.NetLobbyScreen.SelectedSub = candidates.GetRandom(Rand.RandSync.Unsynced);
return GameMain.NetLobbyScreen.SelectedSub.Name;
}
else
{
HiddenSubs.Remove(current);
return current;
}
}
return current;
}
public void LoadClientPermissions()
@@ -69,6 +69,8 @@ namespace Barotrauma.Networking
{
GameServer.Log("Saving whitelist", ServerLog.MessageType.ServerMessage);
GameMain.Server?.ServerSettings?.UpdateFlag(ServerSettings.NetFlags.Properties);
List<string> lines = new List<string>();
if (Enabled)
@@ -1,13 +1,13 @@
#region Using Statements
using Barotrauma.Steam;
using GameAnalyticsSDK.Net;
using System;
using Barotrauma.IO;
using System.Linq;
using System.Text;
using System.Threading;
#if LINUX
using System.Runtime.InteropServices;
#endif
#endregion
@@ -56,7 +56,7 @@ namespace Barotrauma
Game = new GameMain(args);
Game.Run();
if (GameSettings.SendUserStatistics) { GameAnalytics.OnQuit(); }
if (GameAnalyticsManager.SendUserStatistics) { GameAnalyticsManager.ShutDown(); }
SteamManager.ShutDown();
}
@@ -152,6 +152,13 @@ namespace Barotrauma
}
}
if (GameAnalyticsManager.SendUserStatistics)
{
//send crash report before appending debug console messages (which may contain non-anonymous information)
GameAnalyticsManager.AddErrorEvent(GameAnalyticsManager.ErrorSeverity.Critical, sb.ToString());
GameAnalyticsManager.ShutDown();
}
sb.AppendLine("Last debug messages:");
DebugConsole.Clear();
for (int i = DebugConsole.Messages.Count - 1; i > 0 && i > DebugConsole.Messages.Count - 15; i--)
@@ -171,10 +178,8 @@ namespace Barotrauma
if (GameSettings.SaveDebugConsoleLogs || GameSettings.VerboseLogging) { DebugConsole.SaveLogs(); }
if (GameSettings.SendUserStatistics)
if (GameAnalyticsManager.SendUserStatistics)
{
GameAnalytics.AddErrorEvent(EGAErrorSeverity.Critical, crashReport);
GameAnalytics.OnQuit();
Console.Write("A crash report (\"servercrashreport.log\") was saved in the root folder of the game and sent to the developers.");
}
else
@@ -51,42 +51,6 @@ namespace Barotrauma
private List<SubmarineInfo> campaignSubmarines;
public void AddCampaignSubmarine(SubmarineInfo sub)
{
if (!campaignSubmarines.Contains(sub))
{
campaignSubmarines.Add(sub);
}
else
{
return;
}
lastUpdateID++;
if (GameMain.NetworkMember?.ServerSettings != null)
{
GameMain.NetworkMember.ServerSettings.ServerDetailsChanged = true;
}
}
public void RemoveCampaignSubmarine(SubmarineInfo sub)
{
if (campaignSubmarines.Contains(sub))
{
campaignSubmarines.Remove(sub);
}
else
{
return;
}
lastUpdateID++;
if (GameMain.NetworkMember?.ServerSettings != null)
{
GameMain.NetworkMember.ServerSettings.ServerDetailsChanged = true;
}
}
public GameModePreset[] GameModes { get; }
private int selectedModeIndex;
@@ -212,10 +176,7 @@ namespace Barotrauma
}
private List<SubmarineInfo> subs;
public List<SubmarineInfo> GetSubList()
{
return subs;
}
public IReadOnlyList<SubmarineInfo> GetSubList() => subs;
public string LevelSeed
{