Build 0.18.4.0

This commit is contained in:
Markus Isberg
2022-05-31 23:13:05 +09:00
parent 077917fa5d
commit 64db1a6a44
175 changed files with 4916 additions and 2393 deletions
@@ -21,7 +21,7 @@ namespace Barotrauma.Networking
public UInt16 LastSentEntityEventID = 0;
public UInt16 LastRecvEntityEventID = 0;
public UInt16 LastRecvCampaignUpdate = 0;
public readonly Dictionary<MultiPlayerCampaign.NetFlags, UInt16> LastRecvCampaignUpdate = new Dictionary<MultiPlayerCampaign.NetFlags, ushort>();
public UInt16 LastRecvCampaignSave = 0;
public (UInt16 saveId, float time) LastCampaignSaveSendTime;
@@ -1,5 +1,5 @@
using System;
using System.IO;
using Barotrauma.IO;
using System.Linq;
using System.Threading.Tasks;
@@ -155,7 +155,7 @@ namespace Barotrauma.Networking
else
{
Log("Using SteamP2P networking.", ServerLog.MessageType.ServerMessage);
serverPeer = new SteamP2PServerPeer(ownerSteamId.Value, serverSettings);
serverPeer = new SteamP2PServerPeer(ownerSteamId.Value, ownerKey.Value, serverSettings);
}
serverPeer.OnInitializationComplete = OnInitializationComplete;
@@ -746,7 +746,7 @@ namespace Barotrauma.Networking
string seed = inc.ReadString();
string subName = inc.ReadString();
string subHash = inc.ReadString();
CampaignSettings settings = new CampaignSettings(inc);
CampaignSettings settings = INetSerializableStruct.Read<CampaignSettings>(inc);
var matchingSub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == subName && s.MD5Hash.StringRepresentation == subHash);
@@ -767,8 +767,7 @@ 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;
ServerSettings.CampaignSettings = settings;
ServerSettings.SaveSettings();
MultiPlayerCampaign.StartNewCampaign(localSavePath, matchingSub.FilePath, seed, settings);
}
@@ -833,6 +832,9 @@ namespace Barotrauma.Networking
case ClientPacketHeader.EVENTMANAGER_RESPONSE:
GameMain.GameSession?.EventManager.ServerRead(inc, connectedClient);
break;
case ClientPacketHeader.UPDATE_CHARACTERINFO:
UpdateCharacterInfo(inc, connectedClient);
break;
case ClientPacketHeader.ERROR:
HandleClientError(inc, connectedClient);
break;
@@ -1050,9 +1052,11 @@ namespace Barotrauma.Networking
if (c.LastRecvCampaignSave > 0)
{
byte campaignID = inc.ReadByte();
c.LastRecvCampaignUpdate = inc.ReadUInt16();
foreach (MultiPlayerCampaign.NetFlags netFlag in Enum.GetValues(typeof(MultiPlayerCampaign.NetFlags)))
{
c.LastRecvCampaignUpdate[netFlag] = inc.ReadUInt16();
}
bool characterDiscarded = inc.ReadBoolean();
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign)
{
if (characterDiscarded) { campaign.DiscardClientCharacterData(c); }
@@ -1061,7 +1065,11 @@ namespace Barotrauma.Networking
if (campaign.CampaignID != campaignID)
{
c.LastRecvCampaignSave = (ushort)(campaign.LastSaveID - 1);
c.LastRecvCampaignUpdate = (ushort)(campaign.LastUpdateID - 1);
foreach (MultiPlayerCampaign.NetFlags netFlag in Enum.GetValues(typeof(MultiPlayerCampaign.NetFlags)))
{
c.LastRecvCampaignUpdate[netFlag] =
(UInt16)(campaign.GetLastUpdateIdForFlag(netFlag) - 1);
}
}
}
}
@@ -1122,9 +1130,11 @@ namespace Barotrauma.Networking
if (c.LastRecvCampaignSave > 0)
{
byte campaignID = inc.ReadByte();
c.LastRecvCampaignUpdate = inc.ReadUInt16();
foreach (MultiPlayerCampaign.NetFlags netFlag in Enum.GetValues(typeof(MultiPlayerCampaign.NetFlags)))
{
c.LastRecvCampaignUpdate[netFlag] = inc.ReadUInt16();
}
bool characterDiscarded = inc.ReadBoolean();
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign)
{
if (characterDiscarded) { campaign.DiscardClientCharacterData(c); }
@@ -1133,7 +1143,11 @@ namespace Barotrauma.Networking
if (campaign.CampaignID != campaignID)
{
c.LastRecvCampaignSave = (ushort)(campaign.LastSaveID - 1);
c.LastRecvCampaignUpdate = (ushort)(campaign.LastUpdateID - 1);
foreach (MultiPlayerCampaign.NetFlags netFlag in Enum.GetValues(typeof(MultiPlayerCampaign.NetFlags)))
{
c.LastRecvCampaignUpdate[netFlag] =
(UInt16)(campaign.GetLastUpdateIdForFlag(netFlag) - 1);
}
}
}
}
@@ -1370,7 +1384,7 @@ namespace Barotrauma.Networking
if (gameStarted)
{
Log("Client \"" + GameServer.ClientLogName(sender) + "\" ended the round.", ServerLog.MessageType.ServerMessage);
if (mpCampaign != null && Level.IsLoadedOutpost && save)
if (mpCampaign != null && Level.IsLoadedFriendlyOutpost && save)
{
mpCampaign.SavePlayers();
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);
@@ -1672,8 +1686,7 @@ namespace Barotrauma.Networking
outmsg.Write(c.LastSentChatMsgID); //send this to client so they know which chat messages weren't received by the server
outmsg.Write(c.LastSentEntityEventID);
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign && campaign.Preset == GameMain.NetLobbyScreen.SelectedMode &&
NetIdUtils.IdMoreRecent(campaign.LastUpdateID, c.LastRecvCampaignUpdate))
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign && campaign.Preset == GameMain.NetLobbyScreen.SelectedMode)
{
outmsg.Write(true);
outmsg.WritePadBits();
@@ -1899,8 +1912,7 @@ namespace Barotrauma.Networking
int campaignBytes = outmsg.LengthBytes;
var campaign = GameMain.GameSession?.GameMode as MultiPlayerCampaign;
if (outmsg.LengthBytes < MsgConstants.MTU - 500 &&
campaign != null && campaign.Preset == GameMain.NetLobbyScreen.SelectedMode &&
NetIdUtils.IdMoreRecent(campaign.LastUpdateID, c.LastRecvCampaignUpdate))
campaign != null && campaign.Preset == GameMain.NetLobbyScreen.SelectedMode)
{
outmsg.Write(true);
outmsg.WritePadBits();
@@ -2049,7 +2061,10 @@ namespace Barotrauma.Networking
var campaign = GameMain.GameSession?.GameMode as MultiPlayerCampaign;
msg.Write(campaign == null ? (byte)0 : campaign.CampaignID);
msg.Write(campaign == null ? (UInt16)0 : campaign.LastSaveID);
msg.Write(campaign == null ? (UInt16)0 : campaign.LastUpdateID);
foreach (MultiPlayerCampaign.NetFlags flag in Enum.GetValues(typeof(MultiPlayerCampaign.NetFlags)))
{
msg.Write(campaign == null ? (UInt16)0 : campaign.GetLastUpdateIdForFlag(flag));
}
connectedClients.ForEach(c => c.ReadyToStart = false);
@@ -2077,7 +2092,7 @@ namespace Barotrauma.Networking
}
}
startGameCoroutine = GameMain.Instance.ShowLoading(StartGame(selectedSub, selectedShuttle, selectedMode, CampaignSettings.Unsure), false);
startGameCoroutine = GameMain.Instance.ShowLoading(StartGame(selectedSub, selectedShuttle, selectedMode, CampaignSettings.Empty), false);
yield return CoroutineStatus.Success;
}
@@ -2195,7 +2210,7 @@ namespace Barotrauma.Networking
Level.Loaded?.SpawnNPCs();
Level.Loaded?.SpawnCorpses();
Level.Loaded?.PrepareBeaconStation();
AutoItemPlacer.SpawnItems();
AutoItemPlacer.SpawnItems(campaign?.Settings.StartItemSet);
CrewManager crewManager = campaign?.CrewManager;
@@ -3203,18 +3218,27 @@ namespace Barotrauma.Networking
if (checkActiveVote && Voting.ActiveVote != null)
{
int yes = GameMain.Server.ConnectedClients.Count(c => c.InGame && c.GetVote<int>(Voting.ActiveVote.VoteType) == 2);
int no = GameMain.Server.ConnectedClients.Count(c => c.InGame && c.GetVote<int>(Voting.ActiveVote.VoteType) == 1);
int max = GameMain.Server.ConnectedClients.Count(c => c.InGame);
// Required ratio cannot be met
if (no / (float)max > 1f - serverSettings.VoteRequiredRatio)
{
Voting.ActiveVote.Finish(Voting, passed: false);
}
else if (yes / (float)max >= serverSettings.VoteRequiredRatio)
var inGameClients = GameMain.Server.ConnectedClients.Where(c => c.InGame);
if (inGameClients.Count() == 1)
{
Voting.ActiveVote.Finish(Voting, passed: true);
}
}
else
{
var eligibleClients = inGameClients.Where(c => c != Voting.ActiveVote.VoteStarter);
int yes = eligibleClients.Count(c => c.GetVote<int>(Voting.ActiveVote.VoteType) == 2);
int no = eligibleClients.Count(c => c.GetVote<int>(Voting.ActiveVote.VoteType) == 1);
int max = eligibleClients.Count();
// Required ratio cannot be met
if (no / (float)max > 1f - serverSettings.VoteRequiredRatio)
{
Voting.ActiveVote.Finish(Voting, passed: false);
}
else if (yes / (float)max >= serverSettings.VoteRequiredRatio)
{
Voting.ActiveVote.Finish(Voting, passed: true);
}
}
}
Client.UpdateKickVotes(connectedClients);
@@ -3295,7 +3319,7 @@ namespace Barotrauma.Networking
if (voteType != VoteType.PurchaseSub)
{
GameMain.GameSession.SwitchSubmarine(targetSubmarine, deliveryFee, starter);
GameMain.GameSession.SwitchSubmarine(targetSubmarine, subVote.TransferItems, deliveryFee, starter);
}
Voting.StopSubmarineVote(true);
@@ -16,14 +16,21 @@ namespace Barotrauma.Networking
private set;
}
public SteamP2PServerPeer(UInt64 steamId, ServerSettings settings)
private UInt64 ownerKey64 => unchecked((UInt64)ownerKey.Value);
private UInt64 ReadSteamId(IReadMessage inc)
=> inc.ReadUInt64() ^ ownerKey64;
private void WriteSteamId(IWriteMessage msg, UInt64 val)
=> msg.Write(val ^ ownerKey64);
public SteamP2PServerPeer(UInt64 steamId, int ownerKey, ServerSettings settings)
{
serverSettings = settings;
connectedClients = new List<NetworkConnection>();
pendingClients = new List<PendingClient>();
ownerKey = null;
this.ownerKey = ownerKey;
OwnerSteamID = steamId;
@@ -33,7 +40,7 @@ namespace Barotrauma.Networking
public override void Start()
{
IWriteMessage outMsg = new WriteOnlyMessage();
outMsg.Write(OwnerSteamID);
WriteSteamId(outMsg, OwnerSteamID);
outMsg.Write((byte)DeliveryMethod.Reliable);
outMsg.Write((byte)(PacketHeader.IsConnectionInitializationStep | PacketHeader.IsServerMessage));
@@ -122,8 +129,8 @@ namespace Barotrauma.Networking
{
if (!started) { return; }
UInt64 senderSteamId = inc.ReadUInt64();
UInt64 ownerSteamId = inc.ReadUInt64();
UInt64 senderSteamId = ReadSteamId(inc);
UInt64 ownerSteamId = ReadSteamId(inc);
PacketHeader packetHeader = (PacketHeader)inc.ReadByte();
@@ -264,7 +271,7 @@ namespace Barotrauma.Networking
IWriteMessage msgToSend = new WriteOnlyMessage();
byte[] msgData = new byte[16];
msg.PrepareForSending(ref msgData, compressPastThreshold, out bool isCompressed, out int length);
msgToSend.Write(conn.SteamID);
WriteSteamId(msgToSend, conn.SteamID);
msgToSend.Write((byte)deliveryMethod);
msgToSend.Write((byte)((isCompressed ? PacketHeader.IsCompressed : PacketHeader.None) | PacketHeader.IsServerMessage));
msgToSend.Write((UInt16)length);
@@ -281,7 +288,7 @@ namespace Barotrauma.Networking
if (string.IsNullOrWhiteSpace(msg)) { return; }
IWriteMessage msgToSend = new WriteOnlyMessage();
msgToSend.Write(steamId);
WriteSteamId(msgToSend, steamId);
msgToSend.Write((byte)DeliveryMethod.Reliable);
msgToSend.Write((byte)(PacketHeader.IsDisconnectMessage | PacketHeader.IsServerMessage));
msgToSend.Write(msg);
@@ -318,7 +325,7 @@ namespace Barotrauma.Networking
protected override void SendMsgInternal(NetworkConnection conn, DeliveryMethod deliveryMethod, IWriteMessage msg)
{
IWriteMessage msgToSend = new WriteOnlyMessage();
msgToSend.Write(conn.SteamID);
WriteSteamId(msgToSend, conn.SteamID);
msgToSend.Write((byte)deliveryMethod);
msgToSend.Write(msg.Buffer, 0, msg.LengthBytes);
byte[] bufToSend = (byte[])msgToSend.Buffer.Clone();
@@ -1,11 +1,9 @@
using Barotrauma.IO;
using Microsoft.Xna.Framework;
using Barotrauma.Extensions;
using Barotrauma.IO;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Extensions;
namespace Barotrauma.Networking
{
@@ -36,7 +34,7 @@ namespace Barotrauma.Networking
=> LastUpdateIdForFlag[flag] = (UInt16)(GameMain.NetLobbyScreen.LastUpdateID + 1);
private bool IsFlagRequired(Client c, NetFlags flag)
=> LastUpdateIdForFlag[flag] > c.LastRecvLobbyUpdate;
=> NetIdUtils.IdMoreRecent(LastUpdateIdForFlag[flag], c.LastRecvLobbyUpdate);
public NetFlags GetRequiredFlags(Client c)
=> LastUpdateIdForFlag.Keys
@@ -56,7 +54,7 @@ namespace Barotrauma.Networking
{
var property = netProperties[key];
property.SyncValue();
if (property.LastUpdateID > c.LastRecvLobbyUpdate)
if (NetIdUtils.IdMoreRecent(property.LastUpdateID, c.LastRecvLobbyUpdate))
{
outMsg.Write(key);
netProperties[key].Write(outMsg);
@@ -257,7 +255,7 @@ namespace Barotrauma.Networking
doc.Root.SetAttributeValue("queryport", QueryPort);
#endif
doc.Root.SetAttributeValue("password", password ?? "");
doc.Root.SetAttributeValue("enableupnp", EnableUPnP);
doc.Root.SetAttributeValue("autorestart", autoRestart);
@@ -266,11 +264,12 @@ namespace Barotrauma.Networking
doc.Root.SetAttributeValue("ServerMessage", ServerMessageText);
doc.Root.SetAttributeValue("HiddenSubs", string.Join(",", HiddenSubs));
doc.Root.SetAttributeValue("AllowedRandomMissionTypes", string.Join(",", AllowedRandomMissionTypes));
doc.Root.SetAttributeValue("AllowedClientNameChars", string.Join(",", AllowedClientNameChars.Select(c => $"{c.Start}-{c.End}")));
SerializableProperty.SerializeProperties(this, doc.Root, true);
doc.Root.Add(CampaignSettings.Save());
System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings
{
@@ -399,7 +398,7 @@ namespace Barotrauma.Networking
ServerName = doc.Root.GetAttributeString("name", "");
if (ServerName.Length > NetConfig.ServerNameMaxLength) { ServerName = ServerName.Substring(0, NetConfig.ServerNameMaxLength); }
ServerMessageText = doc.Root.GetAttributeString("ServerMessage", "");
GameMain.NetLobbyScreen.SelectedModeIdentifier = GameModeIdentifier;
//handle Random as the mission type, which is no longer a valid setting
//MissionType.All offers equivalent functionality
@@ -410,6 +409,14 @@ namespace Barotrauma.Networking
GameMain.NetLobbyScreen.SetBotCount(BotCount);
MonsterEnabled ??= CharacterPrefab.Prefabs.Select(p => (p.Identifier, true)).ToDictionary();
foreach (XElement element in doc.Root.Elements())
{
if (element.Name.ToIdentifier() == nameof(Barotrauma.CampaignSettings))
{
CampaignSettings = new CampaignSettings(element);
}
}
}
public string SelectNonHiddenSubmarine(string current = null)
@@ -27,11 +27,13 @@ namespace Barotrauma
public VoteState State { get; set; }
public SubmarineInfo Sub;
public bool TransferItems;
public int DeliveryFee;
public SubmarineVote(Client starter, SubmarineInfo subInfo, int deliveryFee, VoteType voteType)
public SubmarineVote(Client starter, SubmarineInfo subInfo, bool transferItems, int deliveryFee, VoteType voteType)
{
Sub = subInfo;
TransferItems = transferItems;
DeliveryFee = deliveryFee;
VoteType = voteType;
State = VoteState.Started;
@@ -101,15 +103,12 @@ namespace Barotrauma
private readonly Dictionary<Client, (VoteType voteType, DateTime time)> rejectedVoteTimes = new Dictionary<Client, (VoteType voteType, DateTime time)>();
private void StartSubmarineVote(SubmarineInfo subInfo, VoteType voteType, Client sender)
private void StartSubmarineVote(SubmarineInfo subInfo, bool transferItems, VoteType voteType, Client sender)
{
if (ActiveVote == null)
{
sender.SetVote(voteType, 2);
}
var subVote = new SubmarineVote(
sender,
subInfo,
transferItems,
voteType == VoteType.SwitchSub ? GameMain.GameSession.Map.DistanceToClosestLocationWithOutpost(GameMain.GameSession.Map.CurrentLocation, out Location endLocation) : 0,
voteType);
StartOrEnqueueVote(subVote);
@@ -152,10 +151,6 @@ namespace Barotrauma
{
return;
}
if (ActiveVote == null)
{
starter.SetVote(VoteType.TransferMoney, 2);
}
StartOrEnqueueVote(new TransferVote(starter, from, transferAmount, to));
GameMain.Server.UpdateVoteStatus(checkActiveVote: false);
}
@@ -205,11 +200,19 @@ namespace Barotrauma
if (ActiveVote.Timer >= GameMain.NetworkMember.ServerSettings.VoteTimeout)
{
var inGameClients = GameMain.Server.ConnectedClients.Where(c => c.InGame);
var eligibleClients = inGameClients.Where(c => c != ActiveVote.VoteStarter);
// Do not take unanswered into account for total
int yes = GameMain.Server.ConnectedClients.Count(c => c.InGame && c.GetVote<int>(ActiveVote.VoteType) == 2);
int no = GameMain.Server.ConnectedClients.Count(c => c.InGame && c.GetVote<int>(ActiveVote.VoteType) == 1);
int yes = eligibleClients.Count(c => c.GetVote<int>(ActiveVote.VoteType) == 2);
int no = eligibleClients.Count(c => c.GetVote<int>(ActiveVote.VoteType) == 1);
int total = Math.Max(yes + no, 1);
ActiveVote.Finish(this, passed: yes / (float)(total) >= GameMain.NetworkMember.ServerSettings.VoteRequiredRatio);
bool passed =
yes / (float)total >= GameMain.NetworkMember.ServerSettings.VoteRequiredRatio ||
inGameClients.Count() == 1;
ActiveVote.Finish(this, passed);
}
}
@@ -293,12 +296,13 @@ namespace Barotrauma
{
string subName = inc.ReadString();
SubmarineInfo subInfo = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == subName);
bool transferItems = inc.ReadBoolean();
if (!ShouldRejectVote(sender, voteType))
{
if (GameMain.GameSession?.Campaign is MultiPlayerCampaign campaign &&
(campaign.CanPurchaseSub(subInfo, sender) || GameMain.GameSession.IsSubmarineOwned(subInfo)))
{
StartSubmarineVote(subInfo, voteType, sender);
StartSubmarineVote(subInfo, transferItems, voteType, sender);
}
}
}
@@ -355,22 +359,24 @@ namespace Barotrauma
{
msg.Write((byte)ActiveVote.VoteType);
if (ActiveVote.State != VoteState.None && ActiveVote.VoteType != VoteType.Unknown)
{
var yesClients = GameMain.Server.ConnectedClients.FindAll(c => c.InGame && c.GetVote<int>(ActiveVote.VoteType) == 2);
msg.Write((byte)yesClients.Count);
{
var eligibleClients = GameMain.Server.ConnectedClients.Where(c => c.InGame && c != ActiveVote.VoteStarter);
var yesClients = eligibleClients.Where(c => c.GetVote<int>(ActiveVote.VoteType) == 2);
msg.Write((byte)yesClients.Count());
foreach (Client c in yesClients)
{
msg.Write(c.ID);
}
var noClients = GameMain.Server.ConnectedClients.FindAll(c => c.InGame && c.GetVote<int>(ActiveVote.VoteType) == 1);
msg.Write((byte)noClients.Count);
var noClients = eligibleClients.Where(c => c.GetVote<int>(ActiveVote.VoteType) == 1);
msg.Write((byte)noClients.Count());
foreach (Client c in noClients)
{
msg.Write(c.ID);
}
msg.Write((byte)GameMain.Server.ConnectedClients.Count(c => c.InGame));
msg.Write((byte)eligibleClients.Count());
switch (ActiveVote.State)
{
@@ -384,6 +390,7 @@ namespace Barotrauma
case VoteType.PurchaseAndSwitchSub:
case VoteType.SwitchSub:
msg.Write((ActiveVote as SubmarineVote).Sub.Name);
msg.Write((ActiveVote as SubmarineVote).TransferItems);
break;
case VoteType.TransferMoney:
var transferVote = (ActiveVote as TransferVote);
@@ -405,8 +412,10 @@ namespace Barotrauma
case VoteType.PurchaseSub:
case VoteType.PurchaseAndSwitchSub:
case VoteType.SwitchSub:
msg.Write((ActiveVote as SubmarineVote).Sub.Name);
msg.Write((short)(ActiveVote as SubmarineVote).DeliveryFee);
var subVote = ActiveVote as SubmarineVote;
msg.Write(subVote.Sub.Name);
msg.Write(subVote.TransferItems);
msg.Write((short)subVote.DeliveryFee);
break;
}
break;