Merge remote-tracking branch 'upstream/dev' into develop
This commit is contained in:
@@ -152,7 +152,9 @@ namespace Barotrauma.Networking
|
||||
public bool IsBanned(AccountId accountId, out string reason)
|
||||
{
|
||||
RemoveExpired();
|
||||
var bannedPlayer = bannedPlayers.Find(bp => bp.AddressOrAccountId.TryGet(out AccountId id) && accountId.Equals(id));
|
||||
var bannedPlayer =
|
||||
bannedPlayers.Find(bp => bp.AddressOrAccountId.TryGet(out AccountId id) && accountId.Equals(id)) ??
|
||||
bannedPlayers.Find(bp => bp.AddressOrAccountId.TryGet(out Address adr) && adr is SteamP2PAddress steamAdr && steamAdr.SteamId.Equals(accountId));
|
||||
reason = bannedPlayer?.Reason ?? string.Empty;
|
||||
return bannedPlayer != null;
|
||||
}
|
||||
|
||||
@@ -210,9 +210,9 @@ namespace Barotrauma.Networking
|
||||
return length;
|
||||
}
|
||||
|
||||
public virtual void ServerWrite(IWriteMessage msg, Client c)
|
||||
public virtual void ServerWrite(in SegmentTableWriter<ServerNetSegment> segmentTable, IWriteMessage msg, Client c)
|
||||
{
|
||||
msg.WriteByte((byte)ServerNetObject.CHAT_MESSAGE);
|
||||
segmentTable.StartNewSegment(ServerNetSegment.ChatMessage);
|
||||
msg.WriteUInt16(NetStateID);
|
||||
msg.WriteRangedInteger((int)Type, 0, Enum.GetValues(typeof(ChatMessageType)).Length - 1);
|
||||
msg.WriteByte((byte)ChangeType);
|
||||
|
||||
@@ -40,6 +40,8 @@ namespace Barotrauma.Networking
|
||||
public float ChatSpamTimer;
|
||||
public int ChatSpamCount;
|
||||
|
||||
public string RejectedName;
|
||||
|
||||
public int RoundsSincePlayedAsTraitor;
|
||||
|
||||
public float KickAFKTimer;
|
||||
@@ -69,6 +71,9 @@ namespace Barotrauma.Networking
|
||||
|
||||
public DateTime JoinTime;
|
||||
|
||||
public static readonly TimeSpan NameChangeCoolDown = new TimeSpan(hours: 0, minutes: 0, seconds: 30);
|
||||
public DateTime LastNameChangeTime;
|
||||
|
||||
private CharacterInfo characterInfo;
|
||||
public CharacterInfo CharacterInfo
|
||||
{
|
||||
|
||||
@@ -342,9 +342,9 @@ namespace Barotrauma.Networking
|
||||
#endif
|
||||
if (!started) { return; }
|
||||
|
||||
if (OwnerConnection != null && ChildServerRelay.HasShutDown)
|
||||
if (ChildServerRelay.HasShutDown)
|
||||
{
|
||||
Quit();
|
||||
GameMain.Instance.CloseServer();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1041,12 +1041,11 @@ namespace Barotrauma.Networking
|
||||
return;
|
||||
}
|
||||
|
||||
ClientNetObject objHeader;
|
||||
while ((objHeader = (ClientNetObject)inc.ReadByte()) != ClientNetObject.END_OF_MESSAGE)
|
||||
SegmentTableReader<ClientNetSegment>.Read(inc, (segment, inc) =>
|
||||
{
|
||||
switch (objHeader)
|
||||
switch (segment)
|
||||
{
|
||||
case ClientNetObject.SYNC_IDS:
|
||||
case ClientNetSegment.SyncIds:
|
||||
//TODO: might want to use a clever class for this
|
||||
c.LastRecvLobbyUpdate = NetIdUtils.Clamp(inc.ReadUInt16(), c.LastRecvLobbyUpdate, GameMain.NetLobbyScreen.LastUpdateID);
|
||||
if (c.HasPermission(ClientPermissions.ManageSettings) &&
|
||||
@@ -1085,19 +1084,21 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ClientNetObject.CHAT_MESSAGE:
|
||||
case ClientNetSegment.ChatMessage:
|
||||
ChatMessage.ServerRead(inc, c);
|
||||
break;
|
||||
case ClientNetObject.VOTE:
|
||||
case ClientNetSegment.Vote:
|
||||
Voting.ServerRead(inc, c);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
return SegmentTableReader<ClientNetSegment>.BreakSegmentReading.Yes;
|
||||
}
|
||||
|
||||
//don't read further messages if the client has been disconnected (kicked due to spam for example)
|
||||
if (!connectedClients.Contains(c)) break;
|
||||
}
|
||||
return connectedClients.Contains(c)
|
||||
? SegmentTableReader<ClientNetSegment>.BreakSegmentReading.No
|
||||
: SegmentTableReader<ClientNetSegment>.BreakSegmentReading.Yes;
|
||||
});
|
||||
}
|
||||
|
||||
private void ClientReadIngame(IReadMessage inc)
|
||||
@@ -1122,13 +1123,12 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
ClientNetObject objHeader;
|
||||
while ((objHeader = (ClientNetObject)inc.ReadByte()) != ClientNetObject.END_OF_MESSAGE)
|
||||
SegmentTableReader<ClientNetSegment>.Read(inc, (segment, inc) =>
|
||||
{
|
||||
switch (objHeader)
|
||||
switch (segment)
|
||||
{
|
||||
case ClientNetObject.SYNC_IDS:
|
||||
//TODO: might want to use a clever class for this
|
||||
case ClientNetSegment.SyncIds:
|
||||
//TODO: switch this to INetSerializableStruct
|
||||
|
||||
UInt16 lastRecvChatMsgID = inc.ReadUInt16();
|
||||
UInt16 lastRecvEntityEventID = inc.ReadUInt16();
|
||||
@@ -1231,10 +1231,10 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
break;
|
||||
case ClientNetObject.CHAT_MESSAGE:
|
||||
case ClientNetSegment.ChatMessage:
|
||||
ChatMessage.ServerRead(inc, c);
|
||||
break;
|
||||
case ClientNetObject.CHARACTER_INPUT:
|
||||
case ClientNetSegment.CharacterInput:
|
||||
if (c.Character != null)
|
||||
{
|
||||
c.Character.ServerReadInput(inc, c);
|
||||
@@ -1244,22 +1244,24 @@ namespace Barotrauma.Networking
|
||||
DebugConsole.AddWarning($"Received character inputs from a client who's not controlling a character ({c.Name}).");
|
||||
}
|
||||
break;
|
||||
case ClientNetObject.ENTITY_STATE:
|
||||
case ClientNetSegment.EntityState:
|
||||
entityEventManager.Read(inc, c);
|
||||
break;
|
||||
case ClientNetObject.VOTE:
|
||||
case ClientNetSegment.Vote:
|
||||
Voting.ServerRead(inc, c);
|
||||
break;
|
||||
case ClientNetObject.SPECTATING_POS:
|
||||
case ClientNetSegment.SpectatingPos:
|
||||
c.SpectatePos = new Vector2(inc.ReadSingle(), inc.ReadSingle());
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
return SegmentTableReader<ClientNetSegment>.BreakSegmentReading.Yes;
|
||||
}
|
||||
|
||||
//don't read further messages if the client has been disconnected (kicked due to spam for example)
|
||||
if (!connectedClients.Contains(c)) { break; }
|
||||
}
|
||||
return connectedClients.Contains(c)
|
||||
? SegmentTableReader<ClientNetSegment>.BreakSegmentReading.No
|
||||
: SegmentTableReader<ClientNetSegment>.BreakSegmentReading.Yes;
|
||||
});
|
||||
}
|
||||
|
||||
private void ReadCrewMessage(IReadMessage inc, Client sender)
|
||||
@@ -1410,7 +1412,8 @@ namespace Barotrauma.Networking
|
||||
if (mpCampaign != null && Level.IsLoadedFriendlyOutpost && save)
|
||||
{
|
||||
mpCampaign.SavePlayers();
|
||||
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);
|
||||
GameMain.GameSession.SubmarineInfo = new SubmarineInfo(GameMain.GameSession.Submarine);
|
||||
mpCampaign.UpdateStoreStock();
|
||||
SaveUtil.SaveGame(GameMain.GameSession.SavePath);
|
||||
}
|
||||
else
|
||||
@@ -1714,78 +1717,78 @@ namespace Barotrauma.Networking
|
||||
|
||||
IWriteMessage outmsg = new WriteOnlyMessage();
|
||||
outmsg.WriteByte((byte)ServerPacketHeader.UPDATE_INGAME);
|
||||
|
||||
outmsg.WriteSingle((float)NetTime.Now);
|
||||
|
||||
outmsg.WriteByte((byte)ServerNetObject.SYNC_IDS);
|
||||
outmsg.WriteUInt16(c.LastSentChatMsgID); //send this to client so they know which chat messages weren't received by the server
|
||||
outmsg.WriteUInt16(c.LastSentEntityEventID);
|
||||
|
||||
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign && campaign.Preset == GameMain.NetLobbyScreen.SelectedMode)
|
||||
using (var segmentTable = SegmentTableWriter<ServerNetSegment>.StartWriting(outmsg))
|
||||
{
|
||||
outmsg.WriteBoolean(true);
|
||||
outmsg.WritePadBits();
|
||||
campaign.ServerWrite(outmsg, c);
|
||||
}
|
||||
else
|
||||
{
|
||||
outmsg.WriteBoolean(false);
|
||||
outmsg.WritePadBits();
|
||||
}
|
||||
segmentTable.StartNewSegment(ServerNetSegment.SyncIds);
|
||||
outmsg.WriteUInt16(c.LastSentChatMsgID); //send this to client so they know which chat messages weren't received by the server
|
||||
outmsg.WriteUInt16(c.LastSentEntityEventID);
|
||||
|
||||
int clientListBytes = outmsg.LengthBytes;
|
||||
WriteClientList(c, outmsg);
|
||||
clientListBytes = outmsg.LengthBytes - clientListBytes;
|
||||
|
||||
int chatMessageBytes = outmsg.LengthBytes;
|
||||
WriteChatMessages(outmsg, c);
|
||||
chatMessageBytes = outmsg.LengthBytes - chatMessageBytes;
|
||||
|
||||
//write as many position updates as the message can fit (only after midround syncing is done)
|
||||
int positionUpdateBytes = outmsg.LengthBytes;
|
||||
while (!c.NeedsMidRoundSync && c.PendingPositionUpdates.Count > 0)
|
||||
{
|
||||
var entity = c.PendingPositionUpdates.Peek();
|
||||
if (!(entity is IServerPositionSync entityPositionSync) ||
|
||||
entity.Removed ||
|
||||
(entity is Item item && float.IsInfinity(item.PositionUpdateInterval)))
|
||||
if (GameMain.GameSession?.GameMode is MultiPlayerCampaign campaign && campaign.Preset == GameMain.NetLobbyScreen.SelectedMode)
|
||||
{
|
||||
outmsg.WriteBoolean(true);
|
||||
outmsg.WritePadBits();
|
||||
campaign.ServerWrite(outmsg, c);
|
||||
}
|
||||
else
|
||||
{
|
||||
outmsg.WriteBoolean(false);
|
||||
outmsg.WritePadBits();
|
||||
}
|
||||
|
||||
int clientListBytes = outmsg.LengthBytes;
|
||||
WriteClientList(segmentTable, c, outmsg);
|
||||
clientListBytes = outmsg.LengthBytes - clientListBytes;
|
||||
|
||||
int chatMessageBytes = outmsg.LengthBytes;
|
||||
WriteChatMessages(segmentTable, outmsg, c);
|
||||
chatMessageBytes = outmsg.LengthBytes - chatMessageBytes;
|
||||
|
||||
//write as many position updates as the message can fit (only after midround syncing is done)
|
||||
int positionUpdateBytes = outmsg.LengthBytes;
|
||||
while (!c.NeedsMidRoundSync && c.PendingPositionUpdates.Count > 0)
|
||||
{
|
||||
var entity = c.PendingPositionUpdates.Peek();
|
||||
if (!(entity is IServerPositionSync entityPositionSync) ||
|
||||
entity.Removed ||
|
||||
(entity is Item item && float.IsInfinity(item.PositionUpdateInterval)))
|
||||
{
|
||||
c.PendingPositionUpdates.Dequeue();
|
||||
continue;
|
||||
}
|
||||
|
||||
IWriteMessage tempBuffer = new ReadWriteMessage();
|
||||
tempBuffer.WriteBoolean(entity is Item); tempBuffer.WritePadBits();
|
||||
tempBuffer.WriteUInt32(entity is MapEntity me ? me.Prefab.UintIdentifier : (UInt32)0);
|
||||
entityPositionSync.ServerWritePosition(tempBuffer, c);
|
||||
|
||||
//no more room in this packet
|
||||
if (outmsg.LengthBytes + tempBuffer.LengthBytes > MsgConstants.MTU - 100)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
segmentTable.StartNewSegment(ServerNetSegment.EntityPosition);
|
||||
outmsg.WritePadBits(); //padding is required here to make sure any padding bits within tempBuffer are read correctly
|
||||
outmsg.WriteBytes(tempBuffer.Buffer, 0, tempBuffer.LengthBytes);
|
||||
outmsg.WritePadBits();
|
||||
|
||||
c.PositionUpdateLastSent[entity] = (float)NetTime.Now;
|
||||
c.PendingPositionUpdates.Dequeue();
|
||||
continue;
|
||||
}
|
||||
positionUpdateBytes = outmsg.LengthBytes - positionUpdateBytes;
|
||||
|
||||
IWriteMessage tempBuffer = new ReadWriteMessage();
|
||||
tempBuffer.WriteBoolean(entity is Item); tempBuffer.WritePadBits();
|
||||
tempBuffer.WriteUInt32(entity is MapEntity me ? me.Prefab.UintIdentifier : (UInt32)0);
|
||||
entityPositionSync.ServerWritePosition(tempBuffer, c);
|
||||
|
||||
//no more room in this packet
|
||||
if (outmsg.LengthBytes + tempBuffer.LengthBytes > MsgConstants.MTU - 100)
|
||||
if (outmsg.LengthBytes > MsgConstants.MTU)
|
||||
{
|
||||
break;
|
||||
string errorMsg = "Maximum packet size exceeded (" + outmsg.LengthBytes + " > " + MsgConstants.MTU + ")\n";
|
||||
errorMsg +=
|
||||
" Client list size: " + clientListBytes + " bytes\n" +
|
||||
" Chat message size: " + chatMessageBytes + " bytes\n" +
|
||||
" Position update size: " + positionUpdateBytes + " bytes\n\n";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameServer.ClientWriteIngame1:PacketSizeExceeded" + outmsg.LengthBytes, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
}
|
||||
|
||||
outmsg.WriteByte((byte)ServerNetObject.ENTITY_POSITION);
|
||||
outmsg.WritePadBits(); //padding is required here to make sure any padding bits within tempBuffer are read correctly
|
||||
outmsg.WriteBytes(tempBuffer.Buffer, 0, tempBuffer.LengthBytes);
|
||||
outmsg.WritePadBits();
|
||||
|
||||
c.PositionUpdateLastSent[entity] = (float)NetTime.Now;
|
||||
c.PendingPositionUpdates.Dequeue();
|
||||
}
|
||||
positionUpdateBytes = outmsg.LengthBytes - positionUpdateBytes;
|
||||
|
||||
outmsg.WriteByte((byte)ServerNetObject.END_OF_MESSAGE);
|
||||
|
||||
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" +
|
||||
" Position update size: " + positionUpdateBytes + " bytes\n\n";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameServer.ClientWriteIngame1:PacketSizeExceeded" + outmsg.LengthBytes, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
}
|
||||
|
||||
serverPeer.Send(outmsg, c.Connection, DeliveryMethod.Unreliable);
|
||||
@@ -1798,46 +1801,50 @@ namespace Barotrauma.Networking
|
||||
outmsg.WriteByte((byte)ServerPacketHeader.UPDATE_INGAME);
|
||||
outmsg.WriteSingle((float)Lidgren.Network.NetTime.Now);
|
||||
|
||||
int eventManagerBytes = outmsg.LengthBytes;
|
||||
entityEventManager.Write(c, outmsg, out List<NetEntityEvent> sentEvents);
|
||||
eventManagerBytes = outmsg.LengthBytes - eventManagerBytes;
|
||||
|
||||
if (sentEvents.Count == 0)
|
||||
using (var segmentTable = SegmentTableWriter<ServerNetSegment>.StartWriting(outmsg))
|
||||
{
|
||||
break;
|
||||
}
|
||||
int eventManagerBytes = outmsg.LengthBytes;
|
||||
entityEventManager.Write(segmentTable, c, outmsg, out List<NetEntityEvent> sentEvents);
|
||||
eventManagerBytes = outmsg.LengthBytes - eventManagerBytes;
|
||||
|
||||
outmsg.WriteByte((byte)ServerNetObject.END_OF_MESSAGE);
|
||||
|
||||
if (outmsg.LengthBytes > MsgConstants.MTU)
|
||||
{
|
||||
string errorMsg = "Maximum packet size exceeded (" + outmsg.LengthBytes + " > " + MsgConstants.MTU + ")\n";
|
||||
errorMsg +=
|
||||
" Event size: " + eventManagerBytes + " bytes\n";
|
||||
|
||||
if (sentEvents != null && sentEvents.Count > 0)
|
||||
if (sentEvents.Count == 0)
|
||||
{
|
||||
errorMsg += "Sent events: \n";
|
||||
foreach (var entityEvent in sentEvents)
|
||||
{
|
||||
errorMsg += " - " + (entityEvent.Entity?.ToString() ?? "null") + "\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameServer.ClientWriteIngame2:PacketSizeExceeded" + outmsg.LengthBytes, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
if (outmsg.LengthBytes > MsgConstants.MTU)
|
||||
{
|
||||
string errorMsg = "Maximum packet size exceeded (" + outmsg.LengthBytes + " > " +
|
||||
MsgConstants.MTU + ")\n";
|
||||
errorMsg +=
|
||||
" Event size: " + eventManagerBytes + " bytes\n";
|
||||
|
||||
if (sentEvents != null && sentEvents.Count > 0)
|
||||
{
|
||||
errorMsg += "Sent events: \n";
|
||||
foreach (var entityEvent in sentEvents)
|
||||
{
|
||||
errorMsg += " - " + (entityEvent.Entity?.ToString() ?? "null") + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"GameServer.ClientWriteIngame2:PacketSizeExceeded" + outmsg.LengthBytes,
|
||||
GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
serverPeer.Send(outmsg, c.Connection, DeliveryMethod.Unreliable);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteClientList(Client c, IWriteMessage outmsg)
|
||||
private void WriteClientList(in SegmentTableWriter<ServerNetSegment> segmentTable, Client c, IWriteMessage outmsg)
|
||||
{
|
||||
bool hasChanged = NetIdUtils.IdMoreRecent(LastClientListUpdateID, c.LastRecvClientListUpdate);
|
||||
if (!hasChanged) { return; }
|
||||
|
||||
outmsg.WriteByte((byte)ServerNetObject.CLIENT_LIST);
|
||||
segmentTable.StartNewSegment(ServerNetSegment.ClientList);
|
||||
outmsg.WriteUInt16(LastClientListUpdateID);
|
||||
|
||||
GameMain.LuaCs.Hook.Call("writeClientList", c, outmsg);
|
||||
@@ -1883,133 +1890,135 @@ namespace Barotrauma.Networking
|
||||
IWriteMessage outmsg = new WriteOnlyMessage();
|
||||
outmsg.WriteByte((byte)ServerPacketHeader.UPDATE_LOBBY);
|
||||
|
||||
outmsg.WriteByte((byte)ServerNetObject.SYNC_IDS);
|
||||
|
||||
int settingsBytes = outmsg.LengthBytes;
|
||||
int initialUpdateBytes = 0;
|
||||
|
||||
if (ServerSettings.UnsentFlags() != ServerSettings.NetFlags.None)
|
||||
bool messageTooLarge;
|
||||
using (var segmentTable = SegmentTableWriter<ServerNetSegment>.StartWriting(outmsg))
|
||||
{
|
||||
GameMain.NetLobbyScreen.LastUpdateID++;
|
||||
}
|
||||
|
||||
IWriteMessage settingsBuf = null;
|
||||
if (NetIdUtils.IdMoreRecent(GameMain.NetLobbyScreen.LastUpdateID, c.LastRecvLobbyUpdate))
|
||||
{
|
||||
outmsg.WriteBoolean(true);
|
||||
outmsg.WritePadBits();
|
||||
segmentTable.StartNewSegment(ServerNetSegment.SyncIds);
|
||||
|
||||
outmsg.WriteUInt16(GameMain.NetLobbyScreen.LastUpdateID);
|
||||
int settingsBytes = outmsg.LengthBytes;
|
||||
int initialUpdateBytes = 0;
|
||||
|
||||
settingsBuf = new ReadWriteMessage();
|
||||
ServerSettings.ServerWrite(settingsBuf, c);
|
||||
outmsg.WriteUInt16((UInt16)settingsBuf.LengthBytes);
|
||||
outmsg.WriteBytes(settingsBuf.Buffer, 0, settingsBuf.LengthBytes);
|
||||
|
||||
outmsg.WriteBoolean(c.LastRecvLobbyUpdate < 1);
|
||||
if (c.LastRecvLobbyUpdate < 1)
|
||||
if (ServerSettings.UnsentFlags() != ServerSettings.NetFlags.None)
|
||||
{
|
||||
isInitialUpdate = true;
|
||||
initialUpdateBytes = outmsg.LengthBytes;
|
||||
ClientWriteInitial(c, outmsg);
|
||||
initialUpdateBytes = outmsg.LengthBytes - initialUpdateBytes;
|
||||
GameMain.NetLobbyScreen.LastUpdateID++;
|
||||
}
|
||||
outmsg.WriteString(GameMain.NetLobbyScreen.SelectedSub.Name);
|
||||
outmsg.WriteString(GameMain.NetLobbyScreen.SelectedSub.MD5Hash.ToString());
|
||||
outmsg.WriteBoolean(IsUsingRespawnShuttle());
|
||||
var selectedShuttle = GameStarted && RespawnManager != null && RespawnManager.UsingShuttle ?
|
||||
RespawnManager.RespawnShuttle.Info :
|
||||
GameMain.NetLobbyScreen.SelectedShuttle;
|
||||
outmsg.WriteString(selectedShuttle.Name);
|
||||
outmsg.WriteString(selectedShuttle.MD5Hash.ToString());
|
||||
|
||||
outmsg.WriteBoolean(ServerSettings.AllowSubVoting);
|
||||
outmsg.WriteBoolean(ServerSettings.AllowModeVoting);
|
||||
|
||||
outmsg.WriteBoolean(ServerSettings.VoiceChatEnabled);
|
||||
|
||||
outmsg.WriteBoolean(ServerSettings.AllowSpectating);
|
||||
|
||||
outmsg.WriteRangedInteger((int)ServerSettings.TraitorsEnabled, 0, 2);
|
||||
|
||||
outmsg.WriteRangedInteger((int)GameMain.NetLobbyScreen.MissionType, 0, (int)MissionType.All);
|
||||
|
||||
outmsg.WriteByte((byte)GameMain.NetLobbyScreen.SelectedModeIndex);
|
||||
outmsg.WriteString(GameMain.NetLobbyScreen.LevelSeed);
|
||||
outmsg.WriteSingle(ServerSettings.SelectedLevelDifficulty);
|
||||
|
||||
outmsg.WriteByte((byte)ServerSettings.BotCount);
|
||||
outmsg.WriteBoolean(ServerSettings.BotSpawnMode == BotSpawnMode.Fill);
|
||||
|
||||
outmsg.WriteBoolean(ServerSettings.AutoRestart);
|
||||
if (ServerSettings.AutoRestart)
|
||||
IWriteMessage settingsBuf = null;
|
||||
if (NetIdUtils.IdMoreRecent(GameMain.NetLobbyScreen.LastUpdateID, c.LastRecvLobbyUpdate))
|
||||
{
|
||||
outmsg.WriteSingle(autoRestartTimerRunning ? ServerSettings.AutoRestartTimer : 0.0f);
|
||||
outmsg.WriteBoolean(true);
|
||||
outmsg.WritePadBits();
|
||||
|
||||
outmsg.WriteUInt16(GameMain.NetLobbyScreen.LastUpdateID);
|
||||
|
||||
settingsBuf = new ReadWriteMessage();
|
||||
ServerSettings.ServerWrite(settingsBuf, c);
|
||||
outmsg.WriteUInt16((UInt16)settingsBuf.LengthBytes);
|
||||
outmsg.WriteBytes(settingsBuf.Buffer, 0, settingsBuf.LengthBytes);
|
||||
|
||||
outmsg.WriteBoolean(c.LastRecvLobbyUpdate < 1);
|
||||
if (c.LastRecvLobbyUpdate < 1)
|
||||
{
|
||||
isInitialUpdate = true;
|
||||
initialUpdateBytes = outmsg.LengthBytes;
|
||||
ClientWriteInitial(c, outmsg);
|
||||
initialUpdateBytes = outmsg.LengthBytes - initialUpdateBytes;
|
||||
}
|
||||
outmsg.WriteString(GameMain.NetLobbyScreen.SelectedSub.Name);
|
||||
outmsg.WriteString(GameMain.NetLobbyScreen.SelectedSub.MD5Hash.ToString());
|
||||
outmsg.WriteBoolean(IsUsingRespawnShuttle());
|
||||
var selectedShuttle = GameStarted && RespawnManager != null && RespawnManager.UsingShuttle ?
|
||||
RespawnManager.RespawnShuttle.Info :
|
||||
GameMain.NetLobbyScreen.SelectedShuttle;
|
||||
outmsg.WriteString(selectedShuttle.Name);
|
||||
outmsg.WriteString(selectedShuttle.MD5Hash.ToString());
|
||||
|
||||
outmsg.WriteBoolean(ServerSettings.AllowSubVoting);
|
||||
outmsg.WriteBoolean(ServerSettings.AllowModeVoting);
|
||||
|
||||
outmsg.WriteBoolean(ServerSettings.VoiceChatEnabled);
|
||||
|
||||
outmsg.WriteBoolean(ServerSettings.AllowSpectating);
|
||||
|
||||
outmsg.WriteRangedInteger((int)ServerSettings.TraitorsEnabled, 0, 2);
|
||||
|
||||
outmsg.WriteRangedInteger((int)GameMain.NetLobbyScreen.MissionType, 0, (int)MissionType.All);
|
||||
|
||||
outmsg.WriteByte((byte)GameMain.NetLobbyScreen.SelectedModeIndex);
|
||||
outmsg.WriteString(GameMain.NetLobbyScreen.LevelSeed);
|
||||
outmsg.WriteSingle(ServerSettings.SelectedLevelDifficulty);
|
||||
|
||||
outmsg.WriteByte((byte)ServerSettings.BotCount);
|
||||
outmsg.WriteBoolean(ServerSettings.BotSpawnMode == BotSpawnMode.Fill);
|
||||
|
||||
outmsg.WriteBoolean(ServerSettings.AutoRestart);
|
||||
if (ServerSettings.AutoRestart)
|
||||
{
|
||||
outmsg.WriteSingle(autoRestartTimerRunning ? ServerSettings.AutoRestartTimer : 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
outmsg.WriteBoolean(false);
|
||||
outmsg.WritePadBits();
|
||||
}
|
||||
settingsBytes = outmsg.LengthBytes - settingsBytes;
|
||||
|
||||
int campaignBytes = outmsg.LengthBytes;
|
||||
var campaign = GameMain.GameSession?.GameMode as MultiPlayerCampaign;
|
||||
if (outmsg.LengthBytes < MsgConstants.MTU - 500 &&
|
||||
campaign != null && campaign.Preset == GameMain.NetLobbyScreen.SelectedMode)
|
||||
{
|
||||
outmsg.WriteBoolean(true);
|
||||
outmsg.WritePadBits();
|
||||
campaign.ServerWrite(outmsg, c);
|
||||
}
|
||||
else
|
||||
{
|
||||
outmsg.WriteBoolean(false);
|
||||
outmsg.WritePadBits();
|
||||
}
|
||||
campaignBytes = outmsg.LengthBytes - campaignBytes;
|
||||
|
||||
outmsg.WriteUInt16(c.LastSentChatMsgID); //send this to client so they know which chat messages weren't received by the server
|
||||
|
||||
int clientListBytes = outmsg.LengthBytes;
|
||||
if (outmsg.LengthBytes < MsgConstants.MTU - 500)
|
||||
{
|
||||
WriteClientList(c, outmsg);
|
||||
}
|
||||
clientListBytes = outmsg.LengthBytes - clientListBytes;
|
||||
|
||||
int chatMessageBytes = outmsg.LengthBytes;
|
||||
WriteChatMessages(outmsg, c);
|
||||
chatMessageBytes = outmsg.LengthBytes - chatMessageBytes;
|
||||
|
||||
outmsg.WriteByte((byte)ServerNetObject.END_OF_MESSAGE);
|
||||
|
||||
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)
|
||||
else
|
||||
{
|
||||
outmsg.WriteBoolean(false);
|
||||
outmsg.WritePadBits();
|
||||
}
|
||||
settingsBytes = outmsg.LengthBytes - settingsBytes;
|
||||
|
||||
int campaignBytes = outmsg.LengthBytes;
|
||||
var campaign = GameMain.GameSession?.GameMode as MultiPlayerCampaign;
|
||||
if (outmsg.LengthBytes < MsgConstants.MTU - 500 &&
|
||||
campaign != null && campaign.Preset == GameMain.NetLobbyScreen.SelectedMode)
|
||||
{
|
||||
outmsg.WriteBoolean(true);
|
||||
outmsg.WritePadBits();
|
||||
campaign.ServerWrite(outmsg, c);
|
||||
}
|
||||
else
|
||||
{
|
||||
outmsg.WriteBoolean(false);
|
||||
outmsg.WritePadBits();
|
||||
}
|
||||
campaignBytes = outmsg.LengthBytes - campaignBytes;
|
||||
|
||||
outmsg.WriteUInt16(c.LastSentChatMsgID); //send this to client so they know which chat messages weren't received by the server
|
||||
|
||||
int clientListBytes = outmsg.LengthBytes;
|
||||
if (outmsg.LengthBytes < MsgConstants.MTU - 500)
|
||||
{
|
||||
WriteClientList(segmentTable, c, outmsg);
|
||||
}
|
||||
clientListBytes = outmsg.LengthBytes - clientListBytes;
|
||||
|
||||
int chatMessageBytes = outmsg.LengthBytes;
|
||||
WriteChatMessages(segmentTable, outmsg, c);
|
||||
chatMessageBytes = outmsg.LengthBytes - chatMessageBytes;
|
||||
|
||||
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 +=
|
||||
" Initial update size: " + settingsBuf.LengthBytes + " bytes\n";
|
||||
}
|
||||
if (settingsBuf != null)
|
||||
{
|
||||
warningMsg +=
|
||||
" Settings buffer size: " + settingsBuf.LengthBytes + " bytes\n";
|
||||
}
|
||||
" 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: " + initialUpdateBytes + " bytes\n";
|
||||
}
|
||||
if (settingsBuf != null)
|
||||
{
|
||||
warningMsg +=
|
||||
" Settings buffer size: " + settingsBuf.LengthBytes + " bytes\n";
|
||||
}
|
||||
#if DEBUG || UNSTABLE
|
||||
DebugConsole.ThrowError(warningMsg);
|
||||
DebugConsole.ThrowError(warningMsg);
|
||||
#else
|
||||
if (GameSettings.CurrentConfig.VerboseLogging) { DebugConsole.AddWarning(warningMsg); }
|
||||
if (GameSettings.CurrentConfig.VerboseLogging) { DebugConsole.AddWarning(warningMsg); }
|
||||
#endif
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameServer.ClientWriteIngame1:ClientWriteLobby" + outmsg.LengthBytes, GameAnalyticsManager.ErrorSeverity.Warning, warningMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameServer.ClientWriteIngame1:ClientWriteLobby" + outmsg.LengthBytes, GameAnalyticsManager.ErrorSeverity.Warning, warningMsg);
|
||||
}
|
||||
}
|
||||
|
||||
if (isInitialUpdate || messageTooLarge)
|
||||
@@ -2036,7 +2045,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteChatMessages(IWriteMessage outmsg, Client c)
|
||||
private void WriteChatMessages(in SegmentTableWriter<ServerNetSegment> segmentTable, IWriteMessage outmsg, Client c)
|
||||
{
|
||||
c.ChatMsgQueue.RemoveAll(cMsg => !NetIdUtils.IdMoreRecent(cMsg.NetStateID, c.LastRecvChatMsgID));
|
||||
for (int i = 0; i < c.ChatMsgQueue.Count && i < ChatMessage.MaxMessagesPerPacket; i++)
|
||||
@@ -2046,7 +2055,7 @@ namespace Barotrauma.Networking
|
||||
//not enough room in this packet
|
||||
return;
|
||||
}
|
||||
c.ChatMsgQueue[i].ServerWrite(outmsg, c);
|
||||
c.ChatMsgQueue[i].ServerWrite(segmentTable, outmsg, c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2543,6 +2552,7 @@ namespace Barotrauma.Networking
|
||||
msg.WriteInt32(ServerSettings.MaximumMoneyTransferRequest);
|
||||
msg.WriteBoolean(IsUsingRespawnShuttle());
|
||||
msg.WriteByte((byte)ServerSettings.LosMode);
|
||||
msg.WriteByte((byte)ServerSettings.ShowEnemyHealthBars);
|
||||
msg.WriteBoolean(includesFinalize); msg.WritePadBits();
|
||||
|
||||
ServerSettings.WriteMonsterEnabled(msg);
|
||||
@@ -2746,9 +2756,24 @@ namespace Barotrauma.Networking
|
||||
CharacterTeamType newTeam = (CharacterTeamType)inc.ReadByte();
|
||||
|
||||
if (c == null || string.IsNullOrEmpty(newName) || !NetIdUtils.IdMoreRecent(nameId, c.NameId)) { return false; }
|
||||
|
||||
var timeSinceNameChange = DateTime.Now - c.LastNameChangeTime;
|
||||
if (timeSinceNameChange < Client.NameChangeCoolDown)
|
||||
{
|
||||
//only send once per second at most to prevent using this for spamming
|
||||
if (timeSinceNameChange.TotalSeconds > 1)
|
||||
{
|
||||
var coolDownRemaining = Client.NameChangeCoolDown - timeSinceNameChange;
|
||||
SendDirectChatMessage($"ServerMessage.NameChangeFailedCooldownActive~[seconds]={(int)coolDownRemaining.TotalSeconds}", c);
|
||||
}
|
||||
c.NameId = nameId;
|
||||
c.RejectedName = newName;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!newJob.IsEmpty)
|
||||
{
|
||||
if (!JobPrefab.Prefabs.TryGet(newJob, out JobPrefab newJobPrefab) || newJobPrefab.HiddenJob)
|
||||
if (!JobPrefab.Prefabs.TryGet(newJob, out JobPrefab newJobPrefab) || newJobPrefab.HiddenJob)
|
||||
{
|
||||
newJob = Identifier.Empty;
|
||||
}
|
||||
@@ -2773,26 +2798,25 @@ namespace Barotrauma.Networking
|
||||
public bool TryChangeClientName(Client c, string newName)
|
||||
{
|
||||
newName = Client.SanitizeName(newName);
|
||||
//update client list even if the name cannot be changed to the one sent by the client,
|
||||
//so the client will be informed what their actual name is
|
||||
LastClientListUpdateID++;
|
||||
|
||||
if (newName == c.Name || string.IsNullOrEmpty(newName)) { return false; }
|
||||
|
||||
if (IsNameValid(c, newName))
|
||||
if (newName != c.Name && !string.IsNullOrEmpty(newName) && IsNameValid(c, newName))
|
||||
{
|
||||
c.LastNameChangeTime = DateTime.Now;
|
||||
string oldName = c.Name;
|
||||
c.Name = newName;
|
||||
c.RejectedName = string.Empty;
|
||||
SendChatMessage($"ServerMessage.NameChangeSuccessful~[oldname]={oldName}~[newname]={newName}", ChatMessageType.Server);
|
||||
LastClientListUpdateID++;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//update client list even if the name cannot be changed to the one sent by the client,
|
||||
//so the client will be informed what their actual name is
|
||||
LastClientListUpdateID++;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private bool IsNameValid(Client c, string newName)
|
||||
{
|
||||
newName = Client.SanitizeName(newName);
|
||||
@@ -3365,9 +3389,11 @@ namespace Barotrauma.Networking
|
||||
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
msg.WriteByte((byte)ServerPacketHeader.UPDATE_LOBBY);
|
||||
msg.WriteByte((byte)ServerNetObject.VOTE);
|
||||
Voting.ServerWrite(msg);
|
||||
msg.WriteByte((byte)ServerNetObject.END_OF_MESSAGE);
|
||||
using (var segmentTable = SegmentTableWriter<ServerNetSegment>.StartWriting(msg))
|
||||
{
|
||||
segmentTable.StartNewSegment(ServerNetSegment.Vote);
|
||||
Voting.ServerWrite(msg);
|
||||
}
|
||||
|
||||
foreach (var c in recipients)
|
||||
{
|
||||
@@ -3971,6 +3997,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
public void Quit()
|
||||
{
|
||||
|
||||
if (started)
|
||||
{
|
||||
started = false;
|
||||
|
||||
+11
-10
@@ -123,7 +123,7 @@ namespace Barotrauma.Networking
|
||||
//remove old events that have been sent to all clients, they are redundant now
|
||||
// keep at least one event in the list (lastSentToAll == e.ID) so we can use it to keep track of the latest ID
|
||||
// and events less than 15 seconds old to give disconnected clients a bit of time to reconnect without getting desynced
|
||||
if (Timing.TotalTime > GameMain.GameSession.RoundStartTime + NetConfig.RoundStartSyncDuration)
|
||||
if (GameMain.GameSession.RoundDuration > NetConfig.RoundStartSyncDuration)
|
||||
{
|
||||
events.RemoveAll(e =>
|
||||
(NetIdUtils.IdMoreRecent(lastSentToAll, e.ID) || !inGameClientsPresent) &&
|
||||
@@ -168,9 +168,10 @@ namespace Barotrauma.Networking
|
||||
if (!bufferedEvent.Character.IsIncapacitated &&
|
||||
NetIdUtils.IdMoreRecent(bufferedEvent.CharacterStateID, bufferedEvent.Character.LastProcessedID))
|
||||
{
|
||||
DebugConsole.Log($"Delaying reading entity event sent by a client until the character state has been processed. Event's character state: {bufferedEvent.CharacterStateID}, last processed character state: {bufferedEvent.Character.LastProcessedID}");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
ReadEvent(bufferedEvent.Data, bufferedEvent.TargetEntity, bufferedEvent.Sender);
|
||||
@@ -216,7 +217,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (Timing.TotalTime - lastWarningTime > 5.0 &&
|
||||
Timing.TotalTime - lastSentToAnyoneTime > 10.0 &&
|
||||
Timing.TotalTime > GameMain.GameSession.RoundStartTime + NetConfig.RoundStartSyncDuration)
|
||||
GameMain.GameSession.RoundDuration > NetConfig.RoundStartSyncDuration)
|
||||
{
|
||||
lastWarningTime = Timing.TotalTime;
|
||||
GameServer.Log("WARNING: ServerEntityEventManager is lagging behind! Last sent id: " + lastSentToAnyone.ToString() + ", latest create id: " + ID.ToString(), ServerLog.MessageType.ServerMessage);
|
||||
@@ -228,7 +229,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
ServerEntityEvent firstEventToResend = events.Find(e => e.ID == (ushort)(lastSentToAll + 1));
|
||||
if (firstEventToResend != null &&
|
||||
Timing.TotalTime > GameMain.GameSession.RoundStartTime + NetConfig.RoundStartSyncDuration &&
|
||||
GameMain.GameSession.RoundDuration > NetConfig.RoundStartSyncDuration &&
|
||||
((lastSentToAnyoneTime - firstEventToResend.CreateTime) > NetConfig.OldReceivedEventKickTime || (Timing.TotalTime - firstEventToResend.CreateTime) > NetConfig.OldEventKickTime))
|
||||
{
|
||||
// This event is 10 seconds older than the last one we've successfully sent,
|
||||
@@ -294,15 +295,15 @@ namespace Barotrauma.Networking
|
||||
/// <summary>
|
||||
/// Writes all the events that the client hasn't received yet into the outgoing message
|
||||
/// </summary>
|
||||
public void Write(Client client, IWriteMessage msg)
|
||||
public void Write(in SegmentTableWriter<ServerNetSegment> segmentTable, Client client, IWriteMessage msg)
|
||||
{
|
||||
Write(client, msg, out _);
|
||||
Write(segmentTable, client, msg, out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes all the events that the client hasn't received yet into the outgoing message
|
||||
/// </summary>
|
||||
public void Write(Client client, IWriteMessage msg, out List<NetEntityEvent> sentEvents)
|
||||
public void Write(in SegmentTableWriter<ServerNetSegment> segmentTable, Client client, IWriteMessage msg, out List<NetEntityEvent> sentEvents)
|
||||
{
|
||||
List<NetEntityEvent> eventsToSync = GetEventsToSync(client);
|
||||
|
||||
@@ -314,7 +315,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
//too many events for one packet
|
||||
//(normal right after a round has just started, don't show a warning if it's been less than 10 seconds)
|
||||
if (eventsToSync.Count > 200 && GameMain.GameSession != null && Timing.TotalTime > GameMain.GameSession.RoundStartTime + 10.0)
|
||||
if (eventsToSync.Count > 200 && GameMain.GameSession != null && GameMain.GameSession.RoundDuration > 10.0)
|
||||
{
|
||||
if (eventsToSync.Count > 200 && !client.NeedsMidRoundSync && Timing.TotalTime > lastEventCountHighWarning + 2.0)
|
||||
{
|
||||
@@ -344,7 +345,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (client.NeedsMidRoundSync)
|
||||
{
|
||||
msg.WriteByte((byte)ServerNetObject.ENTITY_EVENT_INITIAL);
|
||||
segmentTable.StartNewSegment(ServerNetSegment.EntityEventInitial);
|
||||
msg.WriteUInt16(client.UnreceivedEntityEventCount);
|
||||
msg.WriteUInt16(client.FirstNewEventID);
|
||||
|
||||
@@ -352,7 +353,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else
|
||||
{
|
||||
msg.WriteByte((byte)ServerNetObject.ENTITY_EVENT);
|
||||
segmentTable.StartNewSegment(ServerNetSegment.EntityEvent);
|
||||
Write(msg, eventsToSync, out sentEvents, client);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
using Barotrauma.Steam;
|
||||
using Barotrauma.Steam;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
partial class OrderChatMessage : ChatMessage
|
||||
{
|
||||
public override void ServerWrite(IWriteMessage msg, Client c)
|
||||
public override void ServerWrite(in SegmentTableWriter<ServerNetSegment> segmentTable, IWriteMessage msg, Client c)
|
||||
{
|
||||
msg.WriteByte((byte)ServerNetObject.CHAT_MESSAGE);
|
||||
segmentTable.StartNewSegment(ServerNetSegment.ChatMessage);
|
||||
msg.WriteUInt16(NetStateID);
|
||||
msg.WriteRangedInteger((int)ChatMessageType.Order, 0, Enum.GetValues(typeof(ChatMessageType)).Length - 1);
|
||||
msg.WriteString(SenderName);
|
||||
|
||||
+3
-1
@@ -255,7 +255,9 @@ namespace Barotrauma.Networking
|
||||
structToSend = new ServerPeerContentPackageOrderPacket
|
||||
{
|
||||
ServerName = GameMain.Server.ServerName,
|
||||
ContentPackages = ContentPackageManager.EnabledPackages.All.Where(cp => cp.HasMultiplayerSyncedContent || cp.Files.All(f => f is SubmarineFile))
|
||||
ContentPackages = ContentPackageManager.EnabledPackages.All
|
||||
.Where(cp => cp.Files.Any())
|
||||
.Where(cp => cp.HasMultiplayerSyncedContent || cp.Files.All(f => f is SubmarineFile))
|
||||
.Select(contentPackage => new ServerContentPackage(contentPackage, timeNow))
|
||||
.ToImmutableArray()
|
||||
};
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsRespawnPromptPendingForClient(Client c)
|
||||
private static bool IsRespawnPromptPendingForClient(Client c)
|
||||
{
|
||||
if (!UseRespawnPrompt || !(GameMain.GameSession.GameMode is MultiPlayerCampaign campaign)) { return false; }
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace Barotrauma.Networking
|
||||
return false;
|
||||
}
|
||||
|
||||
private List<CharacterInfo> GetBotsToRespawn()
|
||||
private static List<CharacterInfo> GetBotsToRespawn()
|
||||
{
|
||||
if (GameMain.Server.ServerSettings.BotSpawnMode == BotSpawnMode.Normal)
|
||||
{
|
||||
@@ -113,7 +113,7 @@ namespace Barotrauma.Networking
|
||||
return ShouldStartRespawnCountdown(characterToRespawnCount);
|
||||
}
|
||||
|
||||
private int GetMinCharactersToRespawn()
|
||||
private static int GetMinCharactersToRespawn()
|
||||
{
|
||||
return Math.Max((int)(GameMain.Server.ConnectedClients.Count * GameMain.Server.ServerSettings.MinRespawnRatio), 1);
|
||||
}
|
||||
@@ -485,7 +485,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
if (!(GameMain.GameSession.GameMode is CampaignMode))
|
||||
if (GameMain.GameSession.GameMode is not CampaignMode)
|
||||
{
|
||||
if (scooterPrefab != null)
|
||||
{
|
||||
|
||||
@@ -272,7 +272,6 @@ namespace Barotrauma.Networking
|
||||
XDocument doc = new XDocument(new XElement("serversettings"));
|
||||
|
||||
doc.Root.SetAttributeValue("name", ServerName);
|
||||
doc.Root.SetAttributeValue("public", IsPublic);
|
||||
doc.Root.SetAttributeValue("port", Port);
|
||||
#if USE_STEAM
|
||||
doc.Root.SetAttributeValue("queryport", QueryPort);
|
||||
|
||||
@@ -2,20 +2,18 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using MoonSharp.Interpreter;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class VoipServer
|
||||
{
|
||||
private ServerPeer netServer;
|
||||
private List<VoipQueue> queues;
|
||||
private Dictionary<VoipQueue,DateTime> lastSendTime;
|
||||
private readonly ServerPeer netServer;
|
||||
private readonly List<VoipQueue> queues;
|
||||
private readonly Dictionary<VoipQueue,DateTime> lastSendTime;
|
||||
|
||||
public VoipServer(ServerPeer server)
|
||||
{
|
||||
this.netServer = server;
|
||||
netServer = server;
|
||||
queues = new List<VoipQueue>();
|
||||
lastSendTime = new Dictionary<VoipQueue, DateTime>();
|
||||
}
|
||||
@@ -47,17 +45,19 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
Client sender = clients.Find(c => c.VoipQueue == queue);
|
||||
if (sender == null) { return; }
|
||||
|
||||
foreach (Client recipient in clients)
|
||||
{
|
||||
if (recipient == sender) { continue; }
|
||||
|
||||
if (!CanReceive(sender, recipient)) { continue; }
|
||||
if (!CanReceive(sender, recipient, out float distanceFactor)) { continue; }
|
||||
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
|
||||
msg.WriteByte((byte)ServerPacketHeader.VOICE);
|
||||
msg.WriteByte((byte)queue.QueueID);
|
||||
msg.WriteRangedSingle(distanceFactor, 0.0f, 1.0f, 8);
|
||||
queue.Write(msg);
|
||||
|
||||
netServer.Send(msg, recipient.Connection, DeliveryMethod.Unreliable);
|
||||
@@ -65,9 +65,15 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanReceive(Client sender, Client recipient)
|
||||
private static bool CanReceive(Client sender, Client recipient, out float distanceFactor)
|
||||
{
|
||||
if (Screen.Selected != GameMain.GameScreen) { return true; }
|
||||
if (Screen.Selected != GameMain.GameScreen)
|
||||
{
|
||||
distanceFactor = 0.0f;
|
||||
return true;
|
||||
}
|
||||
|
||||
distanceFactor = 0.0f;
|
||||
|
||||
//no-one can hear muted players
|
||||
if (sender.Muted) { return false; }
|
||||
@@ -75,42 +81,46 @@ namespace Barotrauma.Networking
|
||||
bool recipientSpectating = recipient.Character == null || recipient.Character.IsDead;
|
||||
bool senderSpectating = sender.Character == null || sender.Character.IsDead;
|
||||
|
||||
//TODO: only allow spectators to hear the voice chat if close enough to the speaker?
|
||||
|
||||
//non-spectators cannot hear spectators
|
||||
if (senderSpectating && !recipientSpectating) { return false; }
|
||||
|
||||
//both spectating, no need to do radio/distance checks
|
||||
if (recipientSpectating && senderSpectating) { return true; }
|
||||
|
||||
//spectators can hear non-spectators
|
||||
if (!senderSpectating && recipientSpectating) { return true; }
|
||||
//non-spectators cannot hear spectators, and spectators can always hear spectators
|
||||
if (senderSpectating)
|
||||
{
|
||||
return recipientSpectating;
|
||||
}
|
||||
|
||||
//sender can't speak
|
||||
if (sender.Character != null && sender.Character.SpeechImpediment >= 100.0f) { return false; }
|
||||
|
||||
//check if the message can be sent via radio
|
||||
WifiComponent recipientRadio = null;
|
||||
if (!sender.VoipQueue.ForceLocal &&
|
||||
ChatMessage.CanUseRadio(sender.Character, out WifiComponent senderRadio) &&
|
||||
ChatMessage.CanUseRadio(recipient.Character, out WifiComponent recipientRadio))
|
||||
ChatMessage.CanUseRadio(sender.Character, out WifiComponent senderRadio) &&
|
||||
(recipientSpectating || ChatMessage.CanUseRadio(recipient.Character, out recipientRadio)))
|
||||
{
|
||||
var should = GameMain.LuaCs.Hook.Call<bool?>("canUseVoiceRadio", new object[] { sender, recipient });
|
||||
var canUse = GameMain.LuaCs.Hook.Call<bool?>("canUseVoiceRadio", new object[] { sender, recipient });
|
||||
|
||||
if (should != null)
|
||||
if (canUse != null)
|
||||
{
|
||||
return should.Value;
|
||||
}
|
||||
|
||||
if (recipientRadio.CanReceive(senderRadio)) { return true; }
|
||||
}
|
||||
|
||||
var should2 = GameMain.LuaCs.Hook.Call<float?>("changeLocalVoiceRange", sender, recipient);
|
||||
float range = 1.0f;
|
||||
float range = GameMain.LuaCs.Hook.Call<float?>("changeLocalVoiceRange", sender, recipient) ?? 1.0f;
|
||||
|
||||
if (should2 != null)
|
||||
range = should2.Value;
|
||||
|
||||
|
||||
//otherwise do a distance check
|
||||
return ChatMessage.GetGarbleAmount(recipient.Character, sender.Character, ChatMessage.SpeakRange) < range;
|
||||
if (recipientSpectating)
|
||||
{
|
||||
if (recipient.SpectatePos == null) { return true; }
|
||||
distanceFactor = MathHelper.Clamp(Vector2.Distance(sender.Character.WorldPosition, recipient.SpectatePos.Value) / ChatMessage.SpeakRange, 0.0f, 1.0f);
|
||||
return distanceFactor < 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
//otherwise do a distance check
|
||||
float garbleAmount = ChatMessage.GetGarbleAmount(recipient.Character, sender.Character, ChatMessage.SpeakRange);
|
||||
distanceFactor = garbleAmount;
|
||||
return garbleAmount < range;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user