This commit is contained in:
Evil Factory
2022-06-15 13:26:49 -03:00
410 changed files with 11140 additions and 5815 deletions
@@ -3,6 +3,7 @@ using Barotrauma.Steam;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using Barotrauma.IO;
using System.IO.Compression;
using System.Linq;
@@ -11,6 +12,7 @@ using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using Barotrauma.Extensions;
using Microsoft.Xna.Framework.Input;
namespace Barotrauma.Networking
{
@@ -182,6 +184,20 @@ namespace Barotrauma.Networking
get { return ownerKey > 0 || steamP2POwner; }
}
internal readonly struct PermissionChangedEvent
{
public readonly ClientPermissions NewPermissions;
public readonly ImmutableArray<string> NewPermittedConsoleCommands;
public PermissionChangedEvent(ClientPermissions newPermissions, IReadOnlyList<string> newPermittedConsoleCommands)
{
NewPermissions = newPermissions;
NewPermittedConsoleCommands = newPermittedConsoleCommands.ToImmutableArray();
}
}
public readonly NamedEvent<PermissionChangedEvent> OnPermissionChanged = new NamedEvent<PermissionChangedEvent>();
public GameClient(string newName, string ip, UInt64 steamId, string serverName = null, int ownerKey = 0, bool steamP2POwner = false)
{
//TODO: gui stuff should probably not be here?
@@ -570,7 +586,12 @@ namespace Barotrauma.Networking
public override void Update(float deltaTime)
{
#if DEBUG
if (PlayerInput.GetKeyboardState.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.P)) return;
if (PlayerInput.GetKeyboardState.IsKeyDown(Keys.P)) return;
if (PlayerInput.KeyHit(Keys.Home))
{
OnPermissionChanged.Invoke(new PermissionChangedEvent(permissions, permittedConsoleCommands));
}
#endif
foreach (Client c in ConnectedClients)
@@ -668,7 +689,7 @@ namespace Barotrauma.Networking
if (ChildServerRelay.Process?.HasExited ?? true)
{
Disconnect();
if (!GUIMessageBox.MessageBoxes.Any(mb => (mb as GUIMessageBox)?.Text.Text == ChildServerRelay.CrashMessage))
if (!GUIMessageBox.MessageBoxes.Any(mb => (mb as GUIMessageBox)?.Text?.Text == ChildServerRelay.CrashMessage))
{
var msgBox = new GUIMessageBox(TextManager.Get("ConnectionLost"), ChildServerRelay.CrashMessage);
msgBox.Buttons[0].OnClicked += ReturnToPreviousMenu;
@@ -805,7 +826,11 @@ namespace Barotrauma.Networking
byte campaignID = inc.ReadByte();
UInt16 campaignSaveID = inc.ReadUInt16();
UInt16 campaignUpdateID = inc.ReadUInt16();
Dictionary<MultiPlayerCampaign.NetFlags, UInt16> campaignUpdateIDs = new Dictionary<MultiPlayerCampaign.NetFlags, ushort>();
foreach (MultiPlayerCampaign.NetFlags flag in Enum.GetValues(typeof(MultiPlayerCampaign.NetFlags)))
{
campaignUpdateIDs[flag] = inc.ReadUInt16();
}
IWriteMessage readyToStartMsg = new WriteOnlyMessage();
readyToStartMsg.Write((byte)ClientPacketHeader.RESPONSE_STARTGAME);
@@ -824,7 +849,7 @@ namespace Barotrauma.Networking
campaign != null &&
campaign.CampaignID == campaignID &&
campaign.LastSaveID == campaignSaveID &&
campaign.LastUpdateID == campaignUpdateID;
campaignUpdateIDs.All(kvp => campaign.GetLastUpdateIdForFlag(kvp.Key) == kvp.Value);
}
readyToStartMsg.Write(readyToStart);
@@ -1021,40 +1046,25 @@ namespace Barotrauma.Networking
GameMain.GameSession.EnforceMissionOrder(serverMissionIdentifiers);
}
byte equalityCheckValueCount = inc.ReadByte();
List<int> levelEqualityCheckValues = new List<int>();
for (int i = 0; i < equalityCheckValueCount; i++)
var levelEqualityCheckValues = new Dictionary<Level.LevelGenStage, int>();
foreach (Level.LevelGenStage stage in Enum.GetValues(typeof(Level.LevelGenStage)).OfType<Level.LevelGenStage>().OrderBy(s => s))
{
levelEqualityCheckValues.Add(inc.ReadInt32());
levelEqualityCheckValues.Add(stage, inc.ReadInt32());
}
if (Level.Loaded.EqualityCheckValues.Count != levelEqualityCheckValues.Count)
foreach (var stage in levelEqualityCheckValues.Keys)
{
string errorMsg = "Level equality check failed. The level generated at your end doesn't match the level generated by the server" +
" (client value count: " + Level.Loaded.EqualityCheckValues.Count +
", level value count: " + levelEqualityCheckValues.Count +
", seed: " + Level.Loaded.Seed +
", sub: " + Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash.ShortRepresentation + ")" +
", mirrored: " + Level.Loaded.Mirrored + ").";
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
throw new Exception(errorMsg);
}
else
{
for (int i = 0; i < equalityCheckValueCount; i++)
if (Level.Loaded.EqualityCheckValues[stage] != levelEqualityCheckValues[stage])
{
if (Level.Loaded.EqualityCheckValues[i] != levelEqualityCheckValues[i])
{
string errorMsg = "Level equality check failed. The level generated at your end doesn't match the level generated by the server" +
" (client value #" + i + ": " + Level.Loaded.EqualityCheckValues[i] +
", server value #" + i + ": " + levelEqualityCheckValues[i].ToString("X") +
", level value count: " + levelEqualityCheckValues.Count +
", seed: " + Level.Loaded.Seed +
", sub: " + Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash.ShortRepresentation + ")" +
", mirrored: " + Level.Loaded.Mirrored + ").";
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
throw new Exception(errorMsg);
}
string errorMsg = "Level equality check failed. The level generated at your end doesn't match the level generated by the server" +
" (client value " + stage + ": " + Level.Loaded.EqualityCheckValues[stage].ToString("X") +
", server value " + stage + ": " + levelEqualityCheckValues[stage].ToString("X") +
", level value count: " + levelEqualityCheckValues.Count +
", seed: " + Level.Loaded.Seed +
", sub: " + Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash.ShortRepresentation + ")" +
", mirrored: " + Level.Loaded.Mirrored + ").";
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
throw new Exception(errorMsg);
}
}
@@ -1078,6 +1088,7 @@ namespace Barotrauma.Networking
reconnectBox?.Close();
reconnectBox = null;
GameMain.ModDownloadScreen.Reset();
ContentPackageManager.EnabledPackages.Restore();
GUI.ClearCursorWait();
@@ -1191,7 +1202,14 @@ namespace Barotrauma.Networking
new LocalizedString[] { TextManager.Get("Cancel") });
reconnectBox.Buttons[0].OnClicked += (btn, userdata) => { CancelConnect(); return true; };
connected = false;
var prevContentPackages = clientPeer.ServerContentPackages;
ConnectToServer(serverEndpoint, serverName);
if (clientPeer != null)
{
//restore the previous list of content packages so we can reconnect immediately without having to recheck that the packages match
clientPeer.ServerContentPackages = prevContentPackages;
}
}
else
{
@@ -1382,18 +1400,13 @@ namespace Barotrauma.Networking
private void SetMyPermissions(ClientPermissions newPermissions, IEnumerable<string> permittedConsoleCommands)
{
if (!(this.permittedConsoleCommands.Any(c => !permittedConsoleCommands.Contains(c)) ||
permittedConsoleCommands.Any(c => !this.permittedConsoleCommands.Contains(c))))
permittedConsoleCommands.Any(c => !this.permittedConsoleCommands.Contains(c))))
{
if (newPermissions == permissions) return;
}
bool refreshCampaignUI = false;
if (permissions.HasFlag(ClientPermissions.ManageCampaign) != newPermissions.HasFlag(ClientPermissions.ManageCampaign) ||
permissions.HasFlag(ClientPermissions.ManageRound) != newPermissions.HasFlag(ClientPermissions.ManageRound))
{
refreshCampaignUI = true;
}
bool refreshCampaignUI = permissions.HasFlag(ClientPermissions.ManageCampaign) != newPermissions.HasFlag(ClientPermissions.ManageCampaign) ||
permissions.HasFlag(ClientPermissions.ManageRound) != newPermissions.HasFlag(ClientPermissions.ManageRound);
permissions = newPermissions;
this.permittedConsoleCommands = new List<string>(permittedConsoleCommands);
@@ -1432,7 +1445,7 @@ namespace Barotrauma.Networking
if (newPermissions.HasFlag(ClientPermissions.ConsoleCommands))
{
var commandsLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), rightColumn.RectTransform),
TextManager.Get("PermittedConsoleCommands"), wrap: true, font: GUIStyle.SubHeadingFont);
TextManager.Get("PermittedConsoleCommands"), wrap: true, font: GUIStyle.SubHeadingFont);
var commandList = new GUIListBox(new RectTransform(new Vector2(1.0f, 1.0f), rightColumn.RectTransform));
foreach (string permittedCommand in permittedConsoleCommands)
{
@@ -1471,6 +1484,7 @@ namespace Barotrauma.Networking
}
GameMain.NetLobbyScreen.RefreshEnabledElements();
OnPermissionChanged.Invoke(new PermissionChangedEvent(permissions, this.permittedConsoleCommands));
}
private IEnumerable<CoroutineStatus> StartGame(IReadMessage inc)
@@ -1518,6 +1532,7 @@ namespace Barotrauma.Networking
serverSettings.LockAllDefaultWires = inc.ReadBoolean();
serverSettings.AllowRagdollButton = inc.ReadBoolean();
serverSettings.AllowLinkingWifiToChat = inc.ReadBoolean();
serverSettings.MaximumMoneyTransferRequest = inc.ReadInt32();
bool usingShuttle = GameMain.NetLobbyScreen.UsingShuttle = inc.ReadBoolean();
GameMain.LightManager.LosMode = (LosMode)inc.ReadByte();
bool includesFinalize = inc.ReadBoolean(); inc.ReadPadBits();
@@ -1683,6 +1698,13 @@ namespace Barotrauma.Networking
}
}
if (clientPeer == null)
{
DebugConsole.ThrowError("There was an error initializing the round (disconnected during the StartGame coroutine.)");
roundInitStatus = RoundInitStatus.Error;
yield return CoroutineStatus.Failure;
}
roundInitStatus = RoundInitStatus.WaitingForStartGameFinalize;
DateTime? timeOut = null;
@@ -1825,7 +1847,8 @@ namespace Barotrauma.Networking
GameMain.GameScreen.Select();
AddChatMessage($"ServerMessage.HowToCommunicate~[chatbutton]={GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Chat)}~[radiobutton]={GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.RadioChat)}", ChatMessageType.Server);
// TODO: Re-enable the server message once it's been edited and translated
//AddChatMessage($"ServerMessage.HowToCommunicate~[chatbutton]={GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.Chat)}~[radiobutton]={GameSettings.CurrentConfig.KeyMap.KeyBindText(InputType.RadioChat)}", ChatMessageType.Server);
yield return CoroutineStatus.Success;
}
@@ -2399,7 +2422,10 @@ namespace Barotrauma.Networking
{
outmsg.Write(campaign.LastSaveID);
outmsg.Write(campaign.CampaignID);
outmsg.Write(campaign.LastUpdateID);
foreach (MultiPlayerCampaign.NetFlags netFlag in Enum.GetValues(typeof(MultiPlayerCampaign.NetFlags)))
{
outmsg.Write(campaign.GetLastUpdateIdForFlag(netFlag));
}
outmsg.Write(GameMain.NetLobbyScreen.CampaignCharacterDiscarded);
}
@@ -2444,7 +2470,10 @@ namespace Barotrauma.Networking
{
outmsg.Write(campaign.LastSaveID);
outmsg.Write(campaign.CampaignID);
outmsg.Write(campaign.LastUpdateID);
foreach (MultiPlayerCampaign.NetFlags flag in Enum.GetValues(typeof(MultiPlayerCampaign.NetFlags)))
{
outmsg.Write(campaign.GetLastUpdateIdForFlag(flag));
}
outmsg.Write(GameMain.NetLobbyScreen.CampaignCharacterDiscarded);
}
@@ -2491,6 +2520,7 @@ namespace Barotrauma.Networking
message,
type,
gameStarted && myCharacter != null ? myCharacter : null);
chatMessage.ChatMode = GameMain.ActiveChatMode;
lastQueueChatMsgID++;
chatMessage.NetStateID = lastQueueChatMsgID;
@@ -2642,7 +2672,7 @@ namespace Barotrauma.Networking
if (!(GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign) || campaign.CampaignID != campaignID)
{
string savePath = transfer.FilePath;
GameMain.GameSession = new GameSession(null, savePath, GameModePreset.MultiPlayerCampaign, CampaignSettings.Unsure);
GameMain.GameSession = new GameSession(null, savePath, GameModePreset.MultiPlayerCampaign, CampaignSettings.Empty);
campaign = (MultiPlayerCampaign)GameMain.GameSession.GameMode;
campaign.CampaignID = campaignID;
GameMain.NetLobbyScreen.ToggleCampaignMode(true);
@@ -2672,9 +2702,12 @@ namespace Barotrauma.Networking
}
DebugConsole.Log("Campaign save received (" + GameMain.GameSession.SavePath + "), save ID " + campaign.LastSaveID);
//decrement campaign update ID so the server will send us the latest data
//decrement campaign update IDs so the server will send us the latest data
//(as there may have been campaign updates after the save file was created)
campaign.LastUpdateID--;
foreach (MultiPlayerCampaign.NetFlags flag in Enum.GetValues(typeof(MultiPlayerCampaign.NetFlags)))
{
campaign.SetLastUpdateIdForFlag(flag, (ushort)(campaign.GetLastUpdateIdForFlag(flag) - 1));
}
break;
case FileTransferType.Mod:
if (!(Screen.Selected is ModDownloadScreen)) { return; }
@@ -2775,10 +2808,21 @@ namespace Barotrauma.Networking
GameMain.GameSession = null;
}
public void WriteCharacterInfo(IWriteMessage msg)
public void SendCharacterInfo(string newName = null)
{
IWriteMessage msg = new WriteOnlyMessage();
msg.Write((byte)ClientPacketHeader.UPDATE_CHARACTERINFO);
WriteCharacterInfo(msg, newName);
msg.Write((byte)ServerNetObject.END_OF_MESSAGE);
clientPeer?.Send(msg, DeliveryMethod.Reliable);
}
public void WriteCharacterInfo(IWriteMessage msg, string newName = null)
{
msg.Write(characterInfo == null);
if (characterInfo == null) return;
if (characterInfo == null) { return; }
msg.Write(newName ?? string.Empty);
msg.Write((byte)characterInfo.Head.Preset.TagSet.Count);
foreach (Identifier tag in characterInfo.Head.Preset.TagSet)
@@ -2824,18 +2868,18 @@ namespace Barotrauma.Networking
}
#region Submarine Change Voting
public void InitiateSubmarineChange(SubmarineInfo sub, VoteType voteType)
public void InitiateSubmarineChange(SubmarineInfo sub, bool transferItems, VoteType voteType)
{
if (sub == null) { return; }
Vote(voteType, sub);
Vote(voteType, (sub, transferItems));
}
public void ShowSubmarineChangeVoteInterface(Client starter, SubmarineInfo info, VoteType type, float timeOut)
public void ShowSubmarineChangeVoteInterface(Client starter, SubmarineInfo info, VoteType type, bool transferItems, float timeOut)
{
if (info == null) { return; }
if (votingInterface != null && votingInterface.VoteRunning) { return; }
votingInterface?.Remove();
votingInterface = VotingInterface.CreateSubmarineVotingInterface(starter, info, type, timeOut);
votingInterface = VotingInterface.CreateSubmarineVotingInterface(starter, info, type, transferItems, timeOut);
}
#endregion
@@ -3017,7 +3061,7 @@ namespace Barotrauma.Networking
msg.Write(mapSeed);
msg.Write(sub.Name);
msg.Write(sub.MD5Hash.StringRepresentation);
settings.Serialize(msg);
msg.Write(settings);
clientPeer.Send(msg, DeliveryMethod.Reliable);
}
@@ -3265,10 +3309,8 @@ namespace Barotrauma.Networking
{
if (GUI.KeyboardDispatcher.Subscriber == null)
{
bool chatKeyHit = PlayerInput.KeyHit(InputType.Chat);
bool radioKeyHit = PlayerInput.KeyHit(InputType.RadioChat) && (Character.Controlled == null || Character.Controlled.SpeechImpediment < 100);
if (chatKeyHit || radioKeyHit)
var chatKeyStates = ChatBox.ChatKeyStates.GetChatKeyStates();
if (chatKeyStates.AnyHit)
{
if (msgBox.Selected)
{
@@ -3279,34 +3321,8 @@ namespace Barotrauma.Networking
{
if (Screen.Selected == GameMain.GameScreen)
{
if (chatKeyHit)
{
msgBox.AddToGUIUpdateList();
ChatBox.GUIFrame.Flash(Color.DarkGreen, 0.5f);
if (!chatBox.ToggleOpen)
{
ChatBox.CloseAfterMessageSent = !ChatBox.ToggleOpen;
ChatBox.ToggleOpen = true;
}
}
if (radioKeyHit)
{
msgBox.AddToGUIUpdateList();
ChatBox.GUIFrame.Flash(Color.YellowGreen, 0.5f);
if (!chatBox.ToggleOpen)
{
ChatBox.CloseAfterMessageSent = !ChatBox.ToggleOpen;
ChatBox.ToggleOpen = true;
}
if (!msgBox.Text.StartsWith(ChatBox.RadioChatString))
{
msgBox.Text = ChatBox.RadioChatString;
}
}
ChatBox.ApplySelectionInputs(msgBox, false, chatKeyStates);
}
msgBox.Select(msgBox.Text.Length);
}
}
@@ -3574,13 +3590,13 @@ namespace Barotrauma.Networking
return true;
};
durationInputDays = new GUINumberInput(new RectTransform(new Vector2(0.2f, 1.0f), durationContainer.RectTransform), GUINumberInput.NumberType.Int)
durationInputDays = new GUINumberInput(new RectTransform(new Vector2(0.2f, 1.0f), durationContainer.RectTransform), NumberType.Int)
{
MinValueInt = 0,
MaxValueFloat = 1000
};
new GUITextBlock(new RectTransform(new Vector2(0.2f, 1.0f), durationContainer.RectTransform), TextManager.Get("Days"));
durationInputHours = new GUINumberInput(new RectTransform(new Vector2(0.2f, 1.0f), durationContainer.RectTransform), GUINumberInput.NumberType.Int)
durationInputHours = new GUINumberInput(new RectTransform(new Vector2(0.2f, 1.0f), durationContainer.RectTransform), NumberType.Int)
{
MinValueInt = 0,
MaxValueFloat = 24
@@ -3687,7 +3703,9 @@ namespace Barotrauma.Networking
}
if (Level.Loaded != null)
{
errorLines.Add("Level: " + Level.Loaded.Seed + ", " + string.Join(", ", Level.Loaded.EqualityCheckValues.Select(cv => cv.ToString("X"))));
errorLines.Add("Level: " + Level.Loaded.Seed + ", "
+ string.Join("; ", Level.Loaded.EqualityCheckValues.Select(cv
=> cv.Key + "=" + cv.Value.ToString("X"))));
errorLines.Add("Entity count before generating level: " + Level.Loaded.EntityCountBeforeGenerate);
errorLines.Add("Entities:");
foreach (Entity e in Level.Loaded.EntitiesBeforeGenerate.OrderBy(e => e.CreationIndex))