38f1ddb...178a853: v0.8.9.1, removed content folder
This commit is contained in:
@@ -9,6 +9,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
public string Name;
|
||||
public string IP;
|
||||
public ulong SteamID;
|
||||
public string Reason;
|
||||
public DateTime? ExpirationTime;
|
||||
|
||||
@@ -33,6 +34,14 @@ namespace Barotrauma.Networking
|
||||
this.Reason = reason;
|
||||
this.ExpirationTime = expirationTime;
|
||||
}
|
||||
|
||||
public BannedPlayer(string name, ulong steamID, string reason, DateTime? expirationTime)
|
||||
{
|
||||
this.Name = name;
|
||||
this.SteamID = steamID;
|
||||
this.Reason = reason;
|
||||
this.ExpirationTime = expirationTime;
|
||||
}
|
||||
}
|
||||
|
||||
partial class BanList
|
||||
@@ -74,13 +83,12 @@ namespace Barotrauma.Networking
|
||||
if (separatedLine.Length < 2) continue;
|
||||
|
||||
string name = separatedLine[0];
|
||||
string ip = separatedLine[1];
|
||||
string identifier = separatedLine[1];
|
||||
|
||||
DateTime? expirationTime = null;
|
||||
if (separatedLine.Length > 2 && !string.IsNullOrEmpty(separatedLine[2]))
|
||||
{
|
||||
DateTime parsedTime;
|
||||
if (DateTime.TryParse(separatedLine[2], out parsedTime))
|
||||
if (DateTime.TryParse(separatedLine[2], out DateTime parsedTime))
|
||||
{
|
||||
expirationTime = parsedTime;
|
||||
}
|
||||
@@ -89,14 +97,49 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (expirationTime.HasValue && DateTime.Now > expirationTime.Value) continue;
|
||||
|
||||
bannedPlayers.Add(new BannedPlayer(name, ip, reason, expirationTime));
|
||||
if (identifier.Contains("."))
|
||||
{
|
||||
//identifier is an ip
|
||||
bannedPlayers.Add(new BannedPlayer(name, identifier, reason, expirationTime));
|
||||
}
|
||||
else
|
||||
{
|
||||
//identifier should be a steam id
|
||||
if (ulong.TryParse(identifier, out ulong steamID))
|
||||
{
|
||||
bannedPlayers.Add(new BannedPlayer(name, steamID, reason, expirationTime));
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Error in banlist: \"" + identifier + "\" is not a valid IP or a Steam ID");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void BanPlayer(string name, string ip, string reason, TimeSpan? duration)
|
||||
{
|
||||
if (bannedPlayers.Any(bp => bp.IP == ip)) return;
|
||||
BanPlayer(name, ip, 0, reason, duration);
|
||||
}
|
||||
|
||||
public void BanPlayer(string name, ulong steamID, string reason, TimeSpan? duration)
|
||||
{
|
||||
BanPlayer(name, "", steamID, reason, duration);
|
||||
}
|
||||
|
||||
private void BanPlayer(string name, string ip, ulong steamID, string reason, TimeSpan? duration)
|
||||
{
|
||||
var existingBan = bannedPlayers.Find(bp => bp.IP == ip && bp.SteamID == steamID);
|
||||
if (existingBan != null)
|
||||
{
|
||||
if (!duration.HasValue) return;
|
||||
|
||||
DebugConsole.Log("Set \"" + name + "\"'s ban duration to " + duration.Value);
|
||||
existingBan.ExpirationTime = DateTime.Now + duration.Value;
|
||||
Save();
|
||||
return;
|
||||
}
|
||||
|
||||
System.Diagnostics.Debug.Assert(!name.Contains(','));
|
||||
|
||||
@@ -121,7 +164,7 @@ namespace Barotrauma.Networking
|
||||
var player = bannedPlayers.Find(bp => bp.Name == name);
|
||||
if (player == null)
|
||||
{
|
||||
DebugConsole.Log("Could not unban player \""+name+"\". Matching player not found.");
|
||||
DebugConsole.Log("Could not unban player \"" + name + "\". Matching player not found.");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -146,10 +189,10 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsBanned(string IP)
|
||||
public bool IsBanned(string IP, ulong steamID)
|
||||
{
|
||||
bannedPlayers.RemoveAll(bp => bp.ExpirationTime.HasValue && DateTime.Now > bp.ExpirationTime.Value);
|
||||
return bannedPlayers.Any(bp => bp.CompareTo(IP));
|
||||
return bannedPlayers.Any(bp => bp.CompareTo(IP) || (steamID != 0 && bp.SteamID == steamID));
|
||||
}
|
||||
|
||||
private void RemoveBan(BannedPlayer banned)
|
||||
@@ -200,10 +243,11 @@ namespace Barotrauma.Networking
|
||||
List<string> lines = new List<string>();
|
||||
foreach (BannedPlayer banned in bannedPlayers)
|
||||
{
|
||||
string line = banned.Name + "," + banned.IP;
|
||||
string line = banned.Name;
|
||||
line += "," + ((banned.SteamID > 0) ? banned.SteamID.ToString() : banned.IP);
|
||||
line += "," + (banned.ExpirationTime.HasValue ? banned.ExpirationTime.Value.ToString() : "");
|
||||
if (!string.IsNullOrWhiteSpace(banned.Reason)) line += "," + banned.Reason;
|
||||
|
||||
|
||||
lines.Add(line);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
using Lidgren.Network;
|
||||
using Barotrauma.Items.Components;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
enum ChatMessageType
|
||||
{
|
||||
Default, Error, Dead, Server, Radio, Private, Console, MessageBox, ServerLog
|
||||
Default, Error, Dead, Server, Radio, Private, Console, MessageBox, Order, ServerLog
|
||||
}
|
||||
|
||||
partial class ChatMessage
|
||||
@@ -20,13 +22,15 @@ namespace Barotrauma.Networking
|
||||
|
||||
public static Color[] MessageColor =
|
||||
{
|
||||
new Color(125, 140, 153), //default
|
||||
new Color(190, 198, 205), //default
|
||||
new Color(204, 74, 78), //error
|
||||
new Color(63, 72, 204), //dead
|
||||
new Color(136, 177, 255), //dead
|
||||
new Color(157, 225, 160), //server
|
||||
new Color(238, 208, 0), //radio
|
||||
new Color(64, 240, 89), //private
|
||||
new Color(255, 255, 255) //console
|
||||
new Color(255, 255, 255), //console
|
||||
new Color(255, 255, 255), //messagebox
|
||||
new Color(255, 128, 0) //order
|
||||
};
|
||||
|
||||
public readonly string Text;
|
||||
@@ -56,7 +60,7 @@ namespace Barotrauma.Networking
|
||||
set;
|
||||
}
|
||||
|
||||
private ChatMessage(string senderName, string text, ChatMessageType type, Character sender)
|
||||
protected ChatMessage(string senderName, string text, ChatMessageType type, Character sender)
|
||||
{
|
||||
Text = text;
|
||||
Type = type;
|
||||
@@ -115,26 +119,104 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (Submarine.CheckVisibility(listener.SimPosition, Sender.SimPosition) != null) dist = (dist + 100f) * obstructionmult;
|
||||
if (dist > range) return "";
|
||||
|
||||
return ApplyDistanceEffect(text, dist / range);
|
||||
}
|
||||
|
||||
float garbleAmount = dist / range;
|
||||
public static string ApplyDistanceEffect(string text, float garbleAmount)
|
||||
{
|
||||
if (garbleAmount < 0.3f) return text;
|
||||
if (garbleAmount > 1.0f) return "";
|
||||
|
||||
int startIndex = Math.Max(text.IndexOf(':') + 1, 1);
|
||||
|
||||
StringBuilder sb = new StringBuilder(text.Length);
|
||||
for (int i = 0; i < text.Length; i++)
|
||||
{
|
||||
sb.Append((i>startIndex && Rand.Range(0.0f, 1.0f) < garbleAmount) ? '-' : text[i]);
|
||||
sb.Append((i > startIndex && Rand.Range(0.0f, 1.0f) < garbleAmount) ? '-' : text[i]);
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string ApplyDistanceEffect(string message, ChatMessageType type, Character sender, Character receiver)
|
||||
{
|
||||
if (sender == null) return "";
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ChatMessageType.Default:
|
||||
if (receiver != null && !receiver.IsDead)
|
||||
{
|
||||
return ApplyDistanceEffect(receiver, sender, message, SpeakRange * (1.0f - sender.SpeechImpediment / 100.0f), 3.0f);
|
||||
}
|
||||
break;
|
||||
case ChatMessageType.Radio:
|
||||
case ChatMessageType.Order:
|
||||
if (receiver != null && !receiver.IsDead)
|
||||
{
|
||||
var receiverItem = receiver.Inventory?.Items.FirstOrDefault(i => i?.GetComponent<WifiComponent>() != null);
|
||||
//character doesn't have a radio -> don't send
|
||||
if (receiverItem == null || !receiver.HasEquippedItem(receiverItem)) return "";
|
||||
|
||||
var senderItem = sender.Inventory?.Items.FirstOrDefault(i => i?.GetComponent<WifiComponent>() != null);
|
||||
if (senderItem == null || !sender.HasEquippedItem(senderItem)) return "";
|
||||
|
||||
var receiverRadio = receiverItem.GetComponent<WifiComponent>();
|
||||
var senderRadio = senderItem.GetComponent<WifiComponent>();
|
||||
|
||||
if (!receiverRadio.CanReceive(senderRadio)) return "";
|
||||
|
||||
string msg = ApplyDistanceEffect(receiverItem, senderItem, message, senderRadio.Range);
|
||||
if (sender.SpeechImpediment > 0.0f)
|
||||
{
|
||||
//speech impediment doesn't reduce the range when using a radio, but adds extra garbling
|
||||
msg = ApplyDistanceEffect(msg, sender.SpeechImpediment / 100.0f);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
public static void ServerRead(NetIncomingMessage msg, Client c)
|
||||
{
|
||||
c.KickAFKTimer = 0.0f;
|
||||
|
||||
UInt16 ID = msg.ReadUInt16();
|
||||
string txt = msg.ReadString();
|
||||
if (txt == null) txt = "";
|
||||
ChatMessageType type = (ChatMessageType)msg.ReadByte();
|
||||
string txt = "";
|
||||
|
||||
int orderIndex = -1;
|
||||
Character orderTargetCharacter = null;
|
||||
Entity orderTargetEntity = null;
|
||||
int orderOptionIndex = -1;
|
||||
OrderChatMessage orderMsg = null;
|
||||
if (type == ChatMessageType.Order)
|
||||
{
|
||||
orderIndex = msg.ReadByte();
|
||||
orderTargetCharacter = Entity.FindEntityByID(msg.ReadUInt16()) as Character;
|
||||
orderTargetEntity = Entity.FindEntityByID(msg.ReadUInt16()) as Entity;
|
||||
orderOptionIndex = msg.ReadByte();
|
||||
|
||||
if (orderIndex < 0 || orderIndex >= Order.PrefabList.Count)
|
||||
{
|
||||
DebugConsole.ThrowError("Invalid order message from client \"" + c.Name + "\" - order index out of bounds.");
|
||||
return;
|
||||
}
|
||||
|
||||
Order order = Order.PrefabList[orderIndex];
|
||||
string orderOption = orderOptionIndex < 0 || orderOptionIndex >= order.Options.Length ? "" : order.Options[orderOptionIndex];
|
||||
orderMsg = new OrderChatMessage(order, orderOption, orderTargetEntity, orderTargetCharacter, c.Character);
|
||||
txt = orderMsg.Text;
|
||||
}
|
||||
else
|
||||
{
|
||||
txt = msg.ReadString() ?? "";
|
||||
}
|
||||
|
||||
if (!NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID)) return;
|
||||
|
||||
@@ -148,15 +230,22 @@ namespace Barotrauma.Networking
|
||||
c.LastSentChatMessages.Add(txt);
|
||||
if (c.LastSentChatMessages.Count > 10)
|
||||
{
|
||||
c.LastSentChatMessages.RemoveRange(0, c.LastSentChatMessages.Count-10);
|
||||
c.LastSentChatMessages.RemoveRange(0, c.LastSentChatMessages.Count - 10);
|
||||
}
|
||||
|
||||
|
||||
float similarity = 0.0f;
|
||||
for (int i = 0; i < c.LastSentChatMessages.Count; i++)
|
||||
{
|
||||
float closeFactor = 1.0f / (c.LastSentChatMessages.Count - i);
|
||||
int levenshteinDist = ToolBox.LevenshteinDistance(txt, c.LastSentChatMessages[i]);
|
||||
similarity += Math.Max((txt.Length - levenshteinDist) / (float)txt.Length * closeFactor, 0.0f);
|
||||
if (string.IsNullOrEmpty(txt))
|
||||
{
|
||||
similarity += closeFactor;
|
||||
}
|
||||
else
|
||||
{
|
||||
int levenshteinDist = ToolBox.LevenshteinDistance(txt, c.LastSentChatMessages[i]);
|
||||
similarity += Math.Max((txt.Length - levenshteinDist) / (float)txt.Length * closeFactor, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
if (similarity + c.ChatSpamSpeed > 5.0f)
|
||||
@@ -172,7 +261,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null);
|
||||
c.ChatSpamTimer = 10.0f;
|
||||
GameMain.Server.SendChatMessage(denyMsg, c);
|
||||
GameMain.Server.SendDirectChatMessage(denyMsg, c);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -183,14 +272,42 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null);
|
||||
c.ChatSpamTimer = 10.0f;
|
||||
GameMain.Server.SendChatMessage(denyMsg, c);
|
||||
GameMain.Server.SendDirectChatMessage(denyMsg, c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == ChatMessageType.Order)
|
||||
{
|
||||
if (c.Character.SpeechImpediment >= 100.0f || c.Character.IsDead) return;
|
||||
|
||||
//dead characters are allowed to send chat messages,
|
||||
//we'll just switch the message type to dead chat in SendChatMessage
|
||||
if (c.Character != null && (!c.Character.CanSpeak && !c.Character.IsDead)) return;
|
||||
GameMain.Server.SendChatMessage(txt, null, c);
|
||||
ChatMessageType messageType = CanUseRadio(orderMsg.Sender) ? ChatMessageType.Radio : ChatMessageType.Default;
|
||||
if (orderMsg.Order.TargetAllCharacters)
|
||||
{
|
||||
#if CLIENT
|
||||
//add the order to the crewmanager only if the host is not controlling a character
|
||||
//OR the character is close enough to hear it
|
||||
if (Character.Controlled == null ||
|
||||
!string.IsNullOrEmpty(ApplyDistanceEffect(orderMsg.Text, messageType, orderMsg.Sender, Character.Controlled)))
|
||||
{
|
||||
GameMain.GameSession?.CrewManager?.AddOrder(
|
||||
new Order(orderMsg.Order.Prefab, orderTargetEntity, (orderTargetEntity as Item)?.GetComponent<ItemComponent>()),
|
||||
orderMsg.Order.Prefab.FadeOutTime);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (orderTargetCharacter != null)
|
||||
{
|
||||
orderTargetCharacter.SetOrder(
|
||||
new Order(orderMsg.Order.Prefab, orderTargetEntity, (orderTargetEntity as Item)?.GetComponent<ItemComponent>()),
|
||||
orderMsg.OrderOption, orderMsg.Sender);
|
||||
}
|
||||
|
||||
GameMain.Server.SendOrderChatMessage(orderMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.Server.SendChatMessage(txt, null, c);
|
||||
}
|
||||
}
|
||||
|
||||
public int EstimateLengthBytesClient()
|
||||
@@ -221,7 +338,14 @@ namespace Barotrauma.Networking
|
||||
return length;
|
||||
}
|
||||
|
||||
public void ServerWrite(NetOutgoingMessage msg, Client c)
|
||||
public static bool CanUseRadio(Character sender)
|
||||
{
|
||||
if (sender == null) return false;
|
||||
var senderItem = sender.Inventory.Items.FirstOrDefault(i => i?.GetComponent<WifiComponent>() != null);
|
||||
return senderItem != null && sender.HasEquippedItem(senderItem) && senderItem.GetComponent<WifiComponent>().CanTransmit();
|
||||
}
|
||||
|
||||
public virtual void ServerWrite(NetOutgoingMessage msg, Client c)
|
||||
{
|
||||
msg.Write((byte)ServerNetObject.CHAT_MESSAGE);
|
||||
msg.Write(NetStateID);
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
public string Name;
|
||||
public byte ID;
|
||||
public ulong SteamID;
|
||||
|
||||
private float karma = 1.0f;
|
||||
public float Karma
|
||||
@@ -63,6 +64,8 @@ namespace Barotrauma.Networking
|
||||
public float ChatSpamSpeed;
|
||||
public float ChatSpamTimer;
|
||||
public int ChatSpamCount;
|
||||
|
||||
public float KickAFKTimer;
|
||||
|
||||
public double MidRoundSyncTimeOut;
|
||||
|
||||
@@ -86,6 +89,8 @@ namespace Barotrauma.Networking
|
||||
|
||||
public float DeleteDisconnectedTimer;
|
||||
|
||||
public HashSet<string> GivenAchievements = new HashSet<string>();
|
||||
|
||||
public ClientPermissions Permissions = ClientPermissions.None;
|
||||
public List<DebugConsole.Command> PermittedConsoleCommands
|
||||
{
|
||||
@@ -136,8 +141,8 @@ namespace Barotrauma.Networking
|
||||
|
||||
public static bool IsValidName(string name, GameServer server)
|
||||
{
|
||||
if (name.Contains("\n") || name.Contains("\r")) return false;
|
||||
if (name.Any(c => c == ';' || c == ',' || c == '<' || c == '/')) return false;
|
||||
char[] disallowedChars = new char[] { ';', ',', '<', '>', '/', '\\', '[', ']', '"', '?' };
|
||||
if (name.Any(c => disallowedChars.Contains(c))) return false;
|
||||
|
||||
foreach (char character in name)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Xml.Linq;
|
||||
|
||||
@@ -10,23 +9,14 @@ namespace Barotrauma.Networking
|
||||
enum ClientPermissions
|
||||
{
|
||||
None = 0,
|
||||
[Description("End round")]
|
||||
EndRound = 1,
|
||||
[Description("Kick")]
|
||||
Kick = 2,
|
||||
[Description("Ban")]
|
||||
Ban = 4,
|
||||
[Description("Revoke Ban")]
|
||||
Unban = 8,
|
||||
[Description("Select submarine")]
|
||||
SelectSub = 16,
|
||||
[Description("Select game mode")]
|
||||
SelectMode = 32,
|
||||
[Description("Manage campaign")]
|
||||
ManageCampaign = 64,
|
||||
[Description("Console commands")]
|
||||
ConsoleCommands = 128,
|
||||
[Description("Access server log")]
|
||||
ServerLog = 256
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
public FileSender(NetworkMember networkMember)
|
||||
{
|
||||
peer = networkMember.netPeer;
|
||||
peer = networkMember.NetPeer;
|
||||
chunkLen = peer.Configuration.MaximumTransmissionUnit - 100;
|
||||
|
||||
activeTransfers = new List<FileTransferOut>();
|
||||
@@ -205,6 +205,7 @@ namespace Barotrauma.Networking
|
||||
message.Write((ushort)chunkLen);
|
||||
message.Write((ulong)transfer.Data.Length);
|
||||
message.Write(transfer.FileName);
|
||||
GameMain.Server.CompressOutgoingMessage(message);
|
||||
transfer.Connection.SendMessage(message, NetDeliveryMethod.ReliableOrdered, transfer.SequenceChannel);
|
||||
|
||||
transfer.Status = FileTransferStatus.Sending;
|
||||
@@ -227,6 +228,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
message.Write(sendBytes);
|
||||
|
||||
GameMain.Server.CompressOutgoingMessage(message);
|
||||
transfer.Connection.SendMessage(message, NetDeliveryMethod.ReliableOrdered, transfer.SequenceChannel);
|
||||
transfer.SentOffset += sendByteCount;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,27 +2,29 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class UnauthenticatedClient
|
||||
{
|
||||
public NetConnection Connection;
|
||||
public int Nonce;
|
||||
|
||||
public int failedAttempts;
|
||||
public readonly NetConnection Connection;
|
||||
public readonly ulong SteamID;
|
||||
public Facepunch.Steamworks.ServerAuth.Status? SteamAuthStatus = null;
|
||||
public readonly int Nonce;
|
||||
|
||||
public int FailedAttempts;
|
||||
|
||||
public float AuthTimer;
|
||||
|
||||
public UnauthenticatedClient(NetConnection connection, int nonce)
|
||||
|
||||
public UnauthenticatedClient(NetConnection connection, int nonce, ulong steamID = 0)
|
||||
{
|
||||
Connection = connection;
|
||||
SteamID = steamID;
|
||||
Nonce = nonce;
|
||||
|
||||
AuthTimer = 10.0f;
|
||||
|
||||
failedAttempts = 0;
|
||||
FailedAttempts = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,28 +32,158 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
List<UnauthenticatedClient> unauthenticatedClients = new List<UnauthenticatedClient>();
|
||||
|
||||
private void ClientAuthRequest(NetConnection conn)
|
||||
private void ReadClientSteamAuthRequest(NetIncomingMessage inc, out ulong clientSteamID)
|
||||
{
|
||||
clientSteamID = 0;
|
||||
if (!Steam.SteamManager.USE_STEAM)
|
||||
{
|
||||
//not using steam, handle auth normally
|
||||
HandleClientAuthRequest(inc.SenderConnection, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
clientSteamID = inc.ReadUInt64();
|
||||
int authTicketLength = inc.ReadInt32();
|
||||
inc.ReadBytes(authTicketLength, out byte[] authTicketData);
|
||||
|
||||
DebugConsole.Log("Received a Steam auth request");
|
||||
DebugConsole.Log(" Steam ID: "+ clientSteamID);
|
||||
DebugConsole.Log(" Auth ticket length: " + authTicketLength);
|
||||
DebugConsole.Log(" Auth ticket data: " +
|
||||
((authTicketData == null) ? "null" : ToolBox.LimitString(string.Concat(authTicketData.Select(b => b.ToString("X2"))), 16)));
|
||||
|
||||
if (banList.IsBanned("", clientSteamID))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ulong steamID = clientSteamID;
|
||||
if (unauthenticatedClients.Any(uc => uc.Connection == inc.SenderConnection))
|
||||
{
|
||||
var steamAuthedClient = unauthenticatedClients.Find(uc =>
|
||||
uc.Connection == inc.SenderConnection &&
|
||||
uc.SteamID == steamID &&
|
||||
uc.SteamAuthStatus == Facepunch.Steamworks.ServerAuth.Status.OK);
|
||||
if (steamAuthedClient != null)
|
||||
{
|
||||
DebugConsole.Log("Client already authenticated, sending AUTH_RESPONSE again...");
|
||||
HandleClientAuthRequest(inc.SenderConnection, steamID);
|
||||
}
|
||||
DebugConsole.Log("Steam authentication already pending...");
|
||||
return;
|
||||
}
|
||||
|
||||
if (authTicketData == null)
|
||||
{
|
||||
DebugConsole.Log("Invalid request");
|
||||
return;
|
||||
}
|
||||
|
||||
unauthenticatedClients.RemoveAll(uc => uc.Connection == inc.SenderConnection);
|
||||
var unauthClient = new UnauthenticatedClient(inc.SenderConnection, 0, clientSteamID)
|
||||
{
|
||||
AuthTimer = 20
|
||||
};
|
||||
unauthenticatedClients.Add(unauthClient);
|
||||
|
||||
if (!Steam.SteamManager.StartAuthSession(authTicketData, clientSteamID))
|
||||
{
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
if (GameMain.Config.RequireSteamAuthentication)
|
||||
{
|
||||
unauthClient.Connection.Disconnect(DisconnectReason.SteamAuthenticationFailed.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.Log("Steam authentication failed, skipping to basic auth...");
|
||||
HandleClientAuthRequest(inc.SenderConnection);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public void OnAuthChange(ulong steamID, ulong ownerID, Facepunch.Steamworks.ServerAuth.Status status)
|
||||
{
|
||||
DebugConsole.Log("************ OnAuthChange");
|
||||
DebugConsole.Log(" Steam ID: " + steamID);
|
||||
DebugConsole.Log(" Owner ID: " + ownerID);
|
||||
DebugConsole.Log(" Status: " + status);
|
||||
|
||||
UnauthenticatedClient unauthClient = unauthenticatedClients.Find(uc => uc.SteamID == ownerID);
|
||||
if (unauthClient != null)
|
||||
{
|
||||
unauthClient.SteamAuthStatus = status;
|
||||
switch (status)
|
||||
{
|
||||
case Facepunch.Steamworks.ServerAuth.Status.OK:
|
||||
////steam authentication done, check password next
|
||||
HandleClientAuthRequest(unauthClient.Connection, unauthClient.SteamID);
|
||||
break;
|
||||
default:
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
if (GameMain.Config.RequireSteamAuthentication)
|
||||
{
|
||||
unauthClient.Connection.Disconnect(DisconnectReason.SteamAuthenticationFailed.ToString() + "; (" + status.ToString() + ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.Log("Steam authentication failed (" + status.ToString() + "), skipping to basic auth...");
|
||||
HandleClientAuthRequest(unauthClient.Connection);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.Log(" No unauthenticated clients found with the Steam ID " + steamID);
|
||||
}
|
||||
|
||||
//kick connected client if status becomes invalid (e.g. VAC banned, not connected to steam)
|
||||
if (status != Facepunch.Steamworks.ServerAuth.Status.OK && GameMain.Config.RequireSteamAuthentication)
|
||||
{
|
||||
var connectedClient = connectedClients.Find(c => c.SteamID == ownerID);
|
||||
if (connectedClient != null)
|
||||
{
|
||||
KickClient(connectedClient, TextManager.Get("DisconnectMessage.SteamAuthNoLongerValid").Replace("[status]", status.ToString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleClientAuthRequest(NetConnection connection, ulong steamID = 0)
|
||||
{
|
||||
DebugConsole.Log("HandleClientAuthRequest (steamID " + steamID + ")");
|
||||
|
||||
if (GameMain.Config.RequireSteamAuthentication && steamID == 0)
|
||||
{
|
||||
connection.Disconnect(DisconnectReason.SteamAuthenticationRequired.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
//client wants to know if server requires password
|
||||
if (ConnectedClients.Find(c => c.Connection == conn) != null)
|
||||
if (ConnectedClients.Find(c => c.Connection == connection) != null)
|
||||
{
|
||||
//this client has already been authenticated
|
||||
return;
|
||||
}
|
||||
|
||||
UnauthenticatedClient unauthClient = unauthenticatedClients.Find(uc => uc.Connection == conn);
|
||||
UnauthenticatedClient unauthClient = unauthenticatedClients.Find(uc => uc.Connection == connection);
|
||||
if (unauthClient == null)
|
||||
{
|
||||
DebugConsole.Log("Unauthed client, generating a nonce...");
|
||||
//new client, generate nonce and add to unauth queue
|
||||
if (ConnectedClients.Count >= maxPlayers)
|
||||
{
|
||||
//server is full, can't allow new connection
|
||||
conn.Disconnect("Server full");
|
||||
connection.Disconnect(DisconnectReason.ServerFull.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
int nonce = CryptoRandom.Instance.Next();
|
||||
unauthClient = new UnauthenticatedClient(conn, nonce);
|
||||
unauthClient = new UnauthenticatedClient(connection, nonce, steamID);
|
||||
unauthenticatedClients.Add(unauthClient);
|
||||
}
|
||||
unauthClient.AuthTimer = 10.0f;
|
||||
@@ -67,15 +199,19 @@ namespace Barotrauma.Networking
|
||||
nonceMsg.Write(true); //true = password
|
||||
nonceMsg.Write((Int32)unauthClient.Nonce); //here's nonce, encrypt with this
|
||||
}
|
||||
server.SendMessage(nonceMsg, conn, NetDeliveryMethod.Unreliable);
|
||||
CompressOutgoingMessage(nonceMsg);
|
||||
DebugConsole.Log("Sending auth response...");
|
||||
server.SendMessage(nonceMsg, connection, NetDeliveryMethod.Unreliable);
|
||||
}
|
||||
|
||||
private void ClientInitRequest(NetIncomingMessage inc)
|
||||
{
|
||||
DebugConsole.Log("Received client init request");
|
||||
if (ConnectedClients.Find(c => c.Connection == inc.SenderConnection) != null)
|
||||
{
|
||||
//this client was already authenticated
|
||||
//another init request means they didn't get any update packets yet
|
||||
DebugConsole.Log("Client already connected, ignoring...");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -83,7 +219,7 @@ namespace Barotrauma.Networking
|
||||
if (unauthClient == null)
|
||||
{
|
||||
//client did not ask for nonce first, can't authorize
|
||||
inc.SenderConnection.Disconnect("Client did not properly request authentication.");
|
||||
inc.SenderConnection.Disconnect(DisconnectReason.AuthenticationRequired.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -96,12 +232,12 @@ namespace Barotrauma.Networking
|
||||
string clPw = inc.ReadString();
|
||||
if (clPw != saltedPw)
|
||||
{
|
||||
unauthClient.failedAttempts++;
|
||||
if (unauthClient.failedAttempts > 3)
|
||||
unauthClient.FailedAttempts++;
|
||||
if (unauthClient.FailedAttempts > 3)
|
||||
{
|
||||
//disconnect and ban after too many failed attempts
|
||||
banList.BanPlayer("Unnamed", unauthClient.Connection.RemoteEndPoint.Address.ToString(), "Too many failed login attempts.", null);
|
||||
DisconnectUnauthClient(inc, unauthClient, "Too many failed login attempts. You have been automatically banned from the server.");
|
||||
banList.BanPlayer("Unnamed", unauthClient.Connection.RemoteEndPoint.Address.ToString(), TextManager.Get("DisconnectMessage.TooManyFailedLogins"), duration: null);
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.TooManyFailedLogins, "");
|
||||
|
||||
Log(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " has been banned from the server (too many wrong passwords)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " has been banned from the server (too many wrong passwords)", Color.Red);
|
||||
@@ -112,9 +248,10 @@ namespace Barotrauma.Networking
|
||||
//not disconnecting the player here, because they'll still use the same connection and nonce if they try logging in again
|
||||
NetOutgoingMessage reject = server.CreateMessage();
|
||||
reject.Write((byte)ServerPacketHeader.AUTH_FAILURE);
|
||||
reject.Write("Wrong password! You have "+Convert.ToString(4-unauthClient.failedAttempts)+" more attempts before you're banned from the server.");
|
||||
reject.Write("Wrong password! You have " + Convert.ToString(4 - unauthClient.FailedAttempts) + " more attempts before you're banned from the server.");
|
||||
Log(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " failed to join the server (incorrect password)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " failed to join the server (incorrect password)", Color.Red);
|
||||
CompressOutgoingMessage(reject);
|
||||
server.SendMessage(reject, unauthClient.Connection, NetDeliveryMethod.Unreliable);
|
||||
unauthClient.AuthTimer = 10.0f;
|
||||
return;
|
||||
@@ -122,13 +259,32 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
string clVersion = inc.ReadString();
|
||||
string clPackageName = inc.ReadString();
|
||||
string clPackageHash = inc.ReadString();
|
||||
|
||||
UInt16 contentPackageCount = inc.ReadUInt16();
|
||||
List<string> contentPackageNames = new List<string>();
|
||||
List<string> contentPackageHashes = new List<string>();
|
||||
for (int i = 0; i < contentPackageCount; i++)
|
||||
{
|
||||
string packageName = inc.ReadString();
|
||||
string packageHash = inc.ReadString();
|
||||
contentPackageNames.Add(packageName);
|
||||
contentPackageHashes.Add(packageHash);
|
||||
if (contentPackageCount == 0)
|
||||
{
|
||||
DebugConsole.Log("Client is using content package " +
|
||||
(packageName ?? "null") + " (" + (packageHash ?? "null" + ")"));
|
||||
}
|
||||
}
|
||||
|
||||
if (contentPackageCount == 0)
|
||||
{
|
||||
DebugConsole.Log("Client did not list any content packages.");
|
||||
}
|
||||
|
||||
string clName = Client.SanitizeName(inc.ReadString());
|
||||
if (string.IsNullOrWhiteSpace(clName))
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, "You need a name.");
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.NoName, "");
|
||||
|
||||
Log(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " couldn't join the server (no name given)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " couldn't join the server (no name given)", Color.Red);
|
||||
@@ -137,44 +293,100 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (clVersion != GameMain.Version.ToString())
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, "Version " + GameMain.Version + " required to connect to the server (Your version: " + clVersion + ")");
|
||||
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.InvalidVersion,
|
||||
TextManager.Get("DisconnectMessage.InvalidVersion").Replace("[version]", GameMain.Version.ToString()).Replace("[clientversion]", clVersion));
|
||||
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong game version)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong game version)", Color.Red);
|
||||
return;
|
||||
}
|
||||
if (clPackageName != GameMain.SelectedPackage.Name)
|
||||
|
||||
//check if the client is missing any of the content packages the server requires
|
||||
List<ContentPackage> missingPackages = new List<ContentPackage>();
|
||||
foreach (ContentPackage contentPackage in GameMain.SelectedPackages)
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, "Your content package (" + clPackageName + ") doesn't match the server's version (" + GameMain.SelectedPackage.Name + ")");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong content package name)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong content package name)", Color.Red);
|
||||
if (!contentPackage.HasMultiplayerIncompatibleContent) continue;
|
||||
bool packageFound = false;
|
||||
for (int i = 0; i < contentPackageCount; i++)
|
||||
{
|
||||
if (contentPackageNames[i] == contentPackage.Name && contentPackageHashes[i] == contentPackage.MD5hash.Hash)
|
||||
{
|
||||
packageFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!packageFound) missingPackages.Add(contentPackage);
|
||||
}
|
||||
|
||||
if (missingPackages.Count == 1)
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.MissingContentPackage, TextManager.Get("DisconnectMessage.MissingContentPackage").Replace("[missingcontentpackage]", GetPackageStr(missingPackages[0])));
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (missing content package " + GetPackageStr(missingPackages[0]) + ")", ServerLog.MessageType.Error);
|
||||
return;
|
||||
}
|
||||
if (clPackageHash != GameMain.SelectedPackage.MD5hash.Hash)
|
||||
else if (missingPackages.Count > 1)
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, "Your content package (MD5: " + clPackageHash + ") doesn't match the server's version (MD5: " + GameMain.SelectedPackage.MD5hash.Hash + ")");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong content package hash)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong content package hash)", Color.Red);
|
||||
List<string> packageStrs = new List<string>();
|
||||
missingPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.MissingContentPackage, TextManager.Get("DisconnectMessage.MissingContentPackages").Replace("[missingcontentpackages]", string.Join(", ", packageStrs)));
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (missing content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
string GetPackageStr(ContentPackage contentPackage)
|
||||
{
|
||||
return "\"" + contentPackage.Name + "\" (hash " + contentPackage.MD5hash.ShortHash + ")";
|
||||
}
|
||||
|
||||
//check if the client is using any contentpackages that are not compatible with the server
|
||||
List<Pair<string, string>> incompatiblePackages = new List<Pair<string, string>>();
|
||||
for (int i = 0; i < contentPackageNames.Count; i++)
|
||||
{
|
||||
if (!GameMain.Config.SelectedContentPackages.Any(cp => cp.Name == contentPackageNames[i] && cp.MD5hash.Hash == contentPackageHashes[i]))
|
||||
{
|
||||
incompatiblePackages.Add(new Pair<string, string>(contentPackageNames[i], contentPackageHashes[i]));
|
||||
}
|
||||
}
|
||||
|
||||
if (incompatiblePackages.Count == 1)
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.IncompatibleContentPackage,
|
||||
TextManager.Get("DisconnectMessage.IncompatibleContentPackage").Replace("[incompatiblecontentpackage]", GetPackageStr2(incompatiblePackages[0])));
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible content package " + GetPackageStr2(incompatiblePackages[0]) + ")", ServerLog.MessageType.Error);
|
||||
return;
|
||||
}
|
||||
else if (incompatiblePackages.Count > 1)
|
||||
{
|
||||
List<string> packageStrs = new List<string>();
|
||||
incompatiblePackages.ForEach(cp => packageStrs.Add(GetPackageStr2(cp)));
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.IncompatibleContentPackage,
|
||||
TextManager.Get("DisconnectMessage.IncompatibleContentPackages").Replace("[incompatiblecontentpackages]", string.Join(", ", packageStrs)));
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
string GetPackageStr2(Pair<string, string> nameAndHash)
|
||||
{
|
||||
return "\"" + nameAndHash.First + "\" (hash " + Md5Hash.GetShortHash(nameAndHash.Second) + ")";
|
||||
}
|
||||
|
||||
if (!whitelist.IsWhiteListed(clName, inc.SenderConnection.RemoteEndPoint.Address.ToString()))
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, "You're not in this server's whitelist.");
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.NotOnWhitelist, "");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (not in whitelist)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (not in whitelist)", Color.Red);
|
||||
return;
|
||||
}
|
||||
if (!Client.IsValidName(clName, this))
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, "Your name contains illegal symbols.");
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.InvalidName, "");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (invalid name)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (invalid name)", Color.Red);
|
||||
return;
|
||||
}
|
||||
if (Homoglyphs.Compare(clName.ToLower(),Name.ToLower()))
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, "That name is taken.");
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.NameTaken, "");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name taken by the server)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name taken by the server)", Color.Red);
|
||||
return;
|
||||
@@ -185,7 +397,7 @@ namespace Barotrauma.Networking
|
||||
if (nameTaken.Connection.RemoteEndPoint.Address.ToString() == inc.SenderEndPoint.Address.ToString())
|
||||
{
|
||||
//both name and IP address match, replace this player's connection
|
||||
nameTaken.Connection.Disconnect("Your session was taken by a new connection on the same IP address.");
|
||||
nameTaken.Connection.Disconnect(DisconnectReason.SessionTaken.ToString());
|
||||
nameTaken.Connection = unauthClient.Connection;
|
||||
nameTaken.InitClientSync(); //reinitialize sync ids because this is a new connection
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
@@ -195,7 +407,7 @@ namespace Barotrauma.Networking
|
||||
else
|
||||
{
|
||||
//can't authorize this client
|
||||
DisconnectUnauthClient(inc, unauthClient, "That name is taken.");
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.NameTaken, "");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name already taken)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name already taken)", Color.Red);
|
||||
return;
|
||||
@@ -206,6 +418,7 @@ namespace Barotrauma.Networking
|
||||
Client newClient = new Client(clName, GetNewClientID());
|
||||
newClient.InitClientSync();
|
||||
newClient.Connection = unauthClient.Connection;
|
||||
newClient.SteamID = unauthClient.SteamID;
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
unauthClient = null;
|
||||
ConnectedClients.Add(newClient);
|
||||
@@ -215,7 +428,11 @@ namespace Barotrauma.Networking
|
||||
#endif
|
||||
GameMain.Server.SendChatMessage(clName + " has joined the server.", ChatMessageType.Server, null);
|
||||
|
||||
var savedPermissions = clientPermissions.Find(cp => cp.IP == newClient.Connection.RemoteEndPoint.Address.ToString());
|
||||
var savedPermissions = clientPermissions.Find(cp =>
|
||||
cp.SteamID > 0 ?
|
||||
cp.SteamID == newClient.SteamID :
|
||||
cp.IP == newClient.Connection.RemoteEndPoint.Address.ToString());
|
||||
|
||||
if (savedPermissions != null)
|
||||
{
|
||||
newClient.SetPermissions(savedPermissions.Permissions, savedPermissions.PermittedCommands);
|
||||
@@ -226,9 +443,9 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
private void DisconnectUnauthClient(NetIncomingMessage inc, UnauthenticatedClient unauthClient, string reason)
|
||||
private void DisconnectUnauthClient(NetIncomingMessage inc, UnauthenticatedClient unauthClient, DisconnectReason reason, string message)
|
||||
{
|
||||
inc.SenderConnection.Disconnect(reason);
|
||||
inc.SenderConnection.Disconnect(reason.ToString() + "; " + message);
|
||||
|
||||
if (unauthClient != null)
|
||||
{
|
||||
|
||||
@@ -19,11 +19,17 @@ namespace Barotrauma.Networking
|
||||
No = 0, Maybe = 1, Yes = 2
|
||||
}
|
||||
|
||||
enum BotSpawnMode
|
||||
{
|
||||
Normal, Fill
|
||||
}
|
||||
|
||||
partial class GameServer : NetworkMember, ISerializableEntity
|
||||
{
|
||||
private class SavedClientPermission
|
||||
{
|
||||
public readonly string IP;
|
||||
public readonly ulong SteamID;
|
||||
public readonly string Name;
|
||||
public List<DebugConsole.Command> PermittedCommands;
|
||||
|
||||
@@ -34,6 +40,14 @@ namespace Barotrauma.Networking
|
||||
this.Name = name;
|
||||
this.IP = ip;
|
||||
|
||||
this.Permissions = permissions;
|
||||
this.PermittedCommands = permittedCommands;
|
||||
}
|
||||
public SavedClientPermission(string name, ulong steamID, ClientPermissions permissions, List<DebugConsole.Command> permittedCommands)
|
||||
{
|
||||
this.Name = name;
|
||||
this.SteamID = steamID;
|
||||
|
||||
this.Permissions = permissions;
|
||||
this.PermittedCommands = permittedCommands;
|
||||
}
|
||||
@@ -58,6 +72,8 @@ namespace Barotrauma.Networking
|
||||
|
||||
private SelectionMode subSelectionMode, modeSelectionMode;
|
||||
|
||||
private float selectedLevelDifficulty;
|
||||
|
||||
private bool registeredToMaster;
|
||||
|
||||
private WhiteList whitelist;
|
||||
@@ -102,8 +118,7 @@ namespace Barotrauma.Networking
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Serialize(60.0f, true)]
|
||||
public float AutoRestartInterval
|
||||
{
|
||||
@@ -111,6 +126,20 @@ namespace Barotrauma.Networking
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, true)]
|
||||
public bool StartWhenClientsReady
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize(0.8f, true)]
|
||||
public float StartWhenClientsReadyRatio
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize(true, true)]
|
||||
public bool AllowSpectating
|
||||
{
|
||||
@@ -176,6 +205,32 @@ namespace Barotrauma.Networking
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(0, true)]
|
||||
public int BotCount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(16, true)]
|
||||
public int MaxBotCount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public BotSpawnMode BotSpawnMode
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public float SelectedLevelDifficulty
|
||||
{
|
||||
get { return selectedLevelDifficulty; }
|
||||
set { selectedLevelDifficulty = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
||||
}
|
||||
|
||||
[Serialize(true, true)]
|
||||
public bool AllowDisguises
|
||||
@@ -233,6 +288,13 @@ namespace Barotrauma.Networking
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize(120.0f, true)]
|
||||
public float KickAFKTime
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize(true, true)]
|
||||
public bool TraitorUseRatio
|
||||
{
|
||||
@@ -254,8 +316,8 @@ namespace Barotrauma.Networking
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize("Sandbox", true)]
|
||||
public string GameMode
|
||||
[Serialize("sandbox", true)]
|
||||
public string GameModeIdentifier
|
||||
{
|
||||
get;
|
||||
set;
|
||||
@@ -267,8 +329,13 @@ namespace Barotrauma.Networking
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public int MaxPlayers
|
||||
{
|
||||
get { return maxPlayers; }
|
||||
}
|
||||
|
||||
public List<string> AllowedRandomMissionTypes
|
||||
public List<MissionType> AllowedRandomMissionTypes
|
||||
{
|
||||
get;
|
||||
set;
|
||||
@@ -305,17 +372,22 @@ namespace Barotrauma.Networking
|
||||
|
||||
doc.Root.SetAttributeValue("name", name);
|
||||
doc.Root.SetAttributeValue("public", isPublic);
|
||||
doc.Root.SetAttributeValue("port", config.Port);
|
||||
doc.Root.SetAttributeValue("port", NetPeerConfiguration.Port);
|
||||
if (Steam.SteamManager.USE_STEAM) doc.Root.SetAttributeValue("queryport", QueryPort);
|
||||
doc.Root.SetAttributeValue("maxplayers", maxPlayers);
|
||||
doc.Root.SetAttributeValue("enableupnp", config.EnableUPnP);
|
||||
doc.Root.SetAttributeValue("enableupnp", NetPeerConfiguration.EnableUPnP);
|
||||
|
||||
doc.Root.SetAttributeValue("autorestart", autoRestart);
|
||||
|
||||
doc.Root.SetAttributeValue("SubSelection", subSelectionMode.ToString());
|
||||
doc.Root.SetAttributeValue("ModeSelection", modeSelectionMode.ToString());
|
||||
|
||||
doc.Root.SetAttributeValue("LevelDifficulty", ((int)selectedLevelDifficulty).ToString());
|
||||
doc.Root.SetAttributeValue("TraitorsEnabled", TraitorsEnabled.ToString());
|
||||
|
||||
/*doc.Root.SetAttributeValue("BotCount", BotCount);
|
||||
doc.Root.SetAttributeValue("MaxBotCount", MaxBotCount);*/
|
||||
doc.Root.SetAttributeValue("BotSpawnMode", BotSpawnMode.ToString());
|
||||
|
||||
doc.Root.SetAttributeValue("AllowedRandomMissionTypes", string.Join(",", AllowedRandomMissionTypes));
|
||||
|
||||
doc.Root.SetAttributeValue("AllowedClientNameChars", string.Join(",", AllowedClientNameChars.Select(c => c.First + "-" + c.Second)));
|
||||
@@ -374,10 +446,17 @@ namespace Barotrauma.Networking
|
||||
Enum.TryParse(doc.Root.GetAttributeString("ModeSelection", "Manual"), out modeSelectionMode);
|
||||
Voting.AllowModeVoting = modeSelectionMode == SelectionMode.Vote;
|
||||
|
||||
selectedLevelDifficulty = doc.Root.GetAttributeFloat("LevelDifficulty", 20.0f);
|
||||
GameMain.NetLobbyScreen.SetLevelDifficulty(selectedLevelDifficulty);
|
||||
|
||||
var traitorsEnabled = TraitorsEnabled;
|
||||
Enum.TryParse(doc.Root.GetAttributeString("TraitorsEnabled", "No"), out traitorsEnabled);
|
||||
TraitorsEnabled = traitorsEnabled;
|
||||
GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled);
|
||||
|
||||
var botSpawnMode = BotSpawnMode.Fill;
|
||||
Enum.TryParse(doc.Root.GetAttributeString("BotSpawnMode", "Fill"), out botSpawnMode);
|
||||
BotSpawnMode = botSpawnMode;
|
||||
|
||||
//"65-90", "97-122", "48-59" = upper and lower case english alphabet and numbers
|
||||
string[] allowedClientNameCharsStr = doc.Root.GetAttributeStringArray("AllowedClientNameChars", new string[] { "32-33", "65-90", "97-122", "48-59" });
|
||||
@@ -406,12 +485,20 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
if (min > -1 && max > -1) AllowedClientNameChars.Add(Pair<int, int>.Create(min, max));
|
||||
if (min > -1 && max > -1) AllowedClientNameChars.Add(new Pair<int, int>(min, max));
|
||||
}
|
||||
|
||||
AllowedRandomMissionTypes = doc.Root.GetAttributeStringArray(
|
||||
"AllowedRandomMissionTypes",
|
||||
MissionPrefab.MissionTypes.ToArray()).ToList();
|
||||
AllowedRandomMissionTypes = new List<MissionType>();
|
||||
string[] allowedMissionTypeNames = doc.Root.GetAttributeStringArray(
|
||||
"AllowedRandomMissionTypes", Enum.GetValues(typeof(MissionType)).Cast<MissionType>().Select(m => m.ToString()).ToArray());
|
||||
foreach (string missionTypeName in allowedMissionTypeNames)
|
||||
{
|
||||
if (Enum.TryParse(missionTypeName, out MissionType missionType))
|
||||
{
|
||||
if (missionType == Barotrauma.MissionType.None) continue;
|
||||
AllowedRandomMissionTypes.Add(missionType);
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.NetLobbyScreen != null
|
||||
#if CLIENT
|
||||
@@ -421,17 +508,20 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
#if SERVER
|
||||
GameMain.NetLobbyScreen.ServerName = doc.Root.GetAttributeString("name", "");
|
||||
GameMain.NetLobbyScreen.SelectedModeName = GameMode;
|
||||
GameMain.NetLobbyScreen.SelectedModeIdentifier = GameModeIdentifier;
|
||||
GameMain.NetLobbyScreen.MissionTypeName = MissionType;
|
||||
#endif
|
||||
GameMain.NetLobbyScreen.ServerMessageText = doc.Root.GetAttributeString("ServerMessage", "");
|
||||
}
|
||||
|
||||
GameMain.NetLobbyScreen.SetBotSpawnMode(BotSpawnMode);
|
||||
GameMain.NetLobbyScreen.SetBotCount(BotCount);
|
||||
|
||||
#if CLIENT
|
||||
showLogButton.Visible = SaveServerLogs;
|
||||
#endif
|
||||
|
||||
List<string> monsterNames = GameMain.Config.SelectedContentPackage.GetFilesOfType(ContentType.Character);
|
||||
List<string> monsterNames = GameMain.Instance.GetFilesOfType(ContentType.Character).ToList();
|
||||
for (int i = 0; i < monsterNames.Count; i++)
|
||||
{
|
||||
monsterNames[i] = Path.GetFileName(Path.GetDirectoryName(monsterNames[i]));
|
||||
@@ -465,15 +555,29 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
string clientName = clientElement.GetAttributeString("name", "");
|
||||
string clientIP = clientElement.GetAttributeString("ip", "");
|
||||
if (string.IsNullOrWhiteSpace(clientName) || string.IsNullOrWhiteSpace(clientIP))
|
||||
string steamIdStr = clientElement.GetAttributeString("steamid", "");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(clientName))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - all clients must have a name and an IP address.");
|
||||
continue;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(clientIP) && string.IsNullOrWhiteSpace(steamIdStr))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - all clients must have an IP address or a Steam ID.");
|
||||
continue;
|
||||
}
|
||||
|
||||
string permissionsStr = clientElement.GetAttributeString("permissions", "");
|
||||
ClientPermissions permissions;
|
||||
if (!Enum.TryParse(permissionsStr, out permissions))
|
||||
ClientPermissions permissions = ClientPermissions.None;
|
||||
if (permissionsStr.ToLowerInvariant() == "all")
|
||||
{
|
||||
foreach (ClientPermissions permission in Enum.GetValues(typeof(ClientPermissions)))
|
||||
{
|
||||
permissions |= permission;
|
||||
}
|
||||
}
|
||||
else if (!Enum.TryParse(permissionsStr, out permissions))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - \"" + permissionsStr + "\" is not a valid client permission.");
|
||||
continue;
|
||||
@@ -498,7 +602,22 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
clientPermissions.Add(new SavedClientPermission(clientName, clientIP, permissions, permittedCommands));
|
||||
if (!string.IsNullOrEmpty(steamIdStr))
|
||||
{
|
||||
if (ulong.TryParse(steamIdStr, out ulong steamID))
|
||||
{
|
||||
clientPermissions.Add(new SavedClientPermission(clientName, steamID, permissions, permittedCommands));
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - \"" + steamIdStr + "\" is not a valid Steam ID.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
clientPermissions.Add(new SavedClientPermission(clientName, clientIP, permissions, permittedCommands));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,9 +673,17 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
XElement clientElement = new XElement("Client",
|
||||
new XAttribute("name", clientPermission.Name),
|
||||
new XAttribute("ip", clientPermission.IP),
|
||||
new XAttribute("permissions", clientPermission.Permissions.ToString()));
|
||||
|
||||
if (clientPermission.SteamID > 0)
|
||||
{
|
||||
clientElement.Add(new XAttribute("steamid", clientPermission.SteamID));
|
||||
}
|
||||
else
|
||||
{
|
||||
clientElement.Add(new XAttribute("ip", clientPermission.IP));
|
||||
}
|
||||
|
||||
if (clientPermission.Permissions.HasFlag(ClientPermissions.ConsoleCommands))
|
||||
{
|
||||
foreach (DebugConsole.Command command in clientPermission.PermittedCommands)
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
{
|
||||
static class NetConfig
|
||||
{
|
||||
public const int DefaultPort = 14242;
|
||||
|
||||
public const int DefaultPort = 27015;
|
||||
public const int DefaultQueryPort = 27016;
|
||||
|
||||
public const int MaxPlayers = 16;
|
||||
|
||||
public static string MasterServerUrl = GameMain.Config.MasterServerUrl;
|
||||
|
||||
@@ -11,10 +11,11 @@ namespace Barotrauma.Networking
|
||||
ComponentState,
|
||||
InventoryState,
|
||||
Status,
|
||||
Repair,
|
||||
Treatment,
|
||||
ApplyStatusEffect,
|
||||
ChangeProperty,
|
||||
Control
|
||||
Control,
|
||||
UpdateSkills
|
||||
}
|
||||
|
||||
public readonly Entity Entity;
|
||||
|
||||
+4
-7
@@ -37,7 +37,7 @@ namespace Barotrauma.Networking
|
||||
//write an empty event to avoid messing up IDs
|
||||
//(otherwise the clients might read the next event in the message and think its ID
|
||||
//is consecutive to the previous one, even though we skipped over this broken event)
|
||||
tempBuffer.Write((UInt16)0);
|
||||
tempBuffer.Write(Entity.NullEntityID);
|
||||
tempBuffer.WritePadBits();
|
||||
eventCount++;
|
||||
continue;
|
||||
@@ -67,7 +67,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
//technically the clients don't have any use for these, but removing events and shifting the IDs of all
|
||||
//consecutive ones is so error-prone that I think this is a safer option
|
||||
tempBuffer.Write((UInt16)0);
|
||||
tempBuffer.Write(Entity.NullEntityID);
|
||||
tempBuffer.WritePadBits();
|
||||
}*/
|
||||
else
|
||||
@@ -88,10 +88,7 @@ namespace Barotrauma.Networking
|
||||
msg.Write(tempBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void WriteEvent(NetBuffer buffer, NetEntityEvent entityEvent, Client recipient = null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected abstract void WriteEvent(NetBuffer buffer, NetEntityEvent entityEvent, Client recipient = null);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -75,7 +75,7 @@ namespace Barotrauma.Networking
|
||||
return;
|
||||
}
|
||||
|
||||
if (((Entity)entity).Removed)
|
||||
if (((Entity)entity).Removed && !(entity is Level))
|
||||
{
|
||||
DebugConsole.ThrowError("Can't create an entity event for " + entity + " - the entity has been removed.\n"+Environment.StackTrace);
|
||||
return;
|
||||
@@ -338,7 +338,7 @@ namespace Barotrauma.Networking
|
||||
UInt16 thisEventID = (UInt16)(firstEventID + (UInt16)i);
|
||||
UInt16 entityID = msg.ReadUInt16();
|
||||
|
||||
if (entityID == 0)
|
||||
if (entityID == Entity.NullEntityID)
|
||||
{
|
||||
msg.ReadPadBits();
|
||||
if (thisEventID == (UInt16)(sender.LastSentEntityEventID + 1)) sender.LastSentEntityEventID++;
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace Barotrauma.Networking
|
||||
enum ClientPacketHeader
|
||||
{
|
||||
REQUEST_AUTH, //ask the server if a password is needed, if so we'll get nonce for encryption
|
||||
REQUEST_STEAMAUTH, //the same as REQUEST_AUTH, but in addition we want to authenticate the player's Steam ID
|
||||
REQUEST_INIT, //ask the server to give you initialization
|
||||
UPDATE_LOBBY, //update state in lobby
|
||||
UPDATE_INGAME, //update state ingame
|
||||
@@ -45,6 +46,7 @@ namespace Barotrauma.Networking
|
||||
UPDATE_INGAME, //update state ingame (character input and chat messages)
|
||||
|
||||
PERMISSIONS, //tell the client which special permissions they have (if any)
|
||||
ACHIEVEMENT, //give the client a steam achievement
|
||||
|
||||
FILE_TRANSFER,
|
||||
|
||||
@@ -60,7 +62,7 @@ namespace Barotrauma.Networking
|
||||
VOTE,
|
||||
ENTITY_POSITION,
|
||||
ENTITY_EVENT,
|
||||
ENTITY_EVENT_INITIAL
|
||||
ENTITY_EVENT_INITIAL,
|
||||
}
|
||||
|
||||
enum VoteType
|
||||
@@ -69,7 +71,29 @@ namespace Barotrauma.Networking
|
||||
Sub,
|
||||
Mode,
|
||||
EndRound,
|
||||
Kick
|
||||
Kick,
|
||||
StartRound
|
||||
}
|
||||
|
||||
enum DisconnectReason
|
||||
{
|
||||
Unknown,
|
||||
Banned,
|
||||
Kicked,
|
||||
ServerShutdown,
|
||||
ServerFull,
|
||||
AuthenticationRequired,
|
||||
SteamAuthenticationRequired,
|
||||
SteamAuthenticationFailed,
|
||||
SessionTaken,
|
||||
TooManyFailedLogins,
|
||||
NoName,
|
||||
InvalidName,
|
||||
NameTaken,
|
||||
InvalidVersion,
|
||||
MissingContentPackage,
|
||||
IncompatibleContentPackage,
|
||||
NotOnWhitelist,
|
||||
}
|
||||
|
||||
abstract partial class NetworkMember
|
||||
@@ -78,7 +102,7 @@ namespace Barotrauma.Networking
|
||||
public Dictionary<string, long> messageCount = new Dictionary<string, long>();
|
||||
#endif
|
||||
|
||||
public NetPeer netPeer
|
||||
public NetPeer NetPeer
|
||||
{
|
||||
get;
|
||||
protected set;
|
||||
@@ -136,6 +160,12 @@ namespace Barotrauma.Networking
|
||||
protected set;
|
||||
}
|
||||
|
||||
public NetPeerConfiguration NetPeerConfiguration
|
||||
{
|
||||
get;
|
||||
protected set;
|
||||
}
|
||||
|
||||
public NetworkMember()
|
||||
{
|
||||
InitProjSpecific();
|
||||
@@ -155,17 +185,15 @@ namespace Barotrauma.Networking
|
||||
return radioComponent.HasRequiredContainedItems(false);
|
||||
}
|
||||
|
||||
public void AddChatMessage(string message, ChatMessageType type, string senderName="", Character senderCharacter = null)
|
||||
public void AddChatMessage(string message, ChatMessageType type, string senderName = "", Character senderCharacter = null)
|
||||
{
|
||||
AddChatMessage(ChatMessage.Create(senderName, message, type, senderCharacter));
|
||||
}
|
||||
|
||||
|
||||
public void AddChatMessage(ChatMessage message)
|
||||
{
|
||||
GameServer.Log(message.TextWithSender, ServerLog.MessageType.Chat);
|
||||
|
||||
string displayedText = message.Text;
|
||||
|
||||
|
||||
if (message.Sender != null && !message.Sender.IsDead)
|
||||
{
|
||||
message.Sender.ShowSpeechBubble(2.0f, ChatMessage.MessageColor[(int)message.Type]);
|
||||
@@ -173,42 +201,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
#if CLIENT
|
||||
GameMain.NetLobbyScreen.NewChatMessage(message);
|
||||
|
||||
while (chatBox.CountChildren > 20)
|
||||
{
|
||||
chatBox.RemoveChild(chatBox.children[0]);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(message.SenderName))
|
||||
{
|
||||
displayedText = (message.Type == ChatMessageType.Private ? "[PM] " : "" ) + message.SenderName + ": " + displayedText;
|
||||
}
|
||||
|
||||
GUITextBlock msg = new GUITextBlock(new Rectangle(0, 0, chatBox.Rect.Width - 40, 0), displayedText,
|
||||
((chatBox.CountChildren % 2) == 0) ? Color.Transparent : Color.Black * 0.1f, message.Color,
|
||||
Alignment.Left, Alignment.TopLeft, "", null, true, GUI.SmallFont);
|
||||
msg.UserData = message.SenderName;
|
||||
|
||||
msg.Padding = new Vector4(20.0f, 0, 0, 0);
|
||||
|
||||
float prevSize = chatBox.BarSize;
|
||||
|
||||
msg.Padding = new Vector4(20, 0, 0, 0);
|
||||
chatBox.AddChild(msg);
|
||||
|
||||
if ((prevSize == 1.0f && chatBox.BarScroll == 0.0f) || (prevSize < 1.0f && chatBox.BarScroll == 1.0f)) chatBox.BarScroll = 1.0f;
|
||||
|
||||
GUISoundType soundType = GUISoundType.Message;
|
||||
if (message.Type == ChatMessageType.Radio)
|
||||
{
|
||||
soundType = GUISoundType.RadioMessage;
|
||||
}
|
||||
else if (message.Type == ChatMessageType.Dead)
|
||||
{
|
||||
soundType = GUISoundType.DeadMessage;
|
||||
}
|
||||
|
||||
GUI.PlayUISound(soundType);
|
||||
chatBox.AddMessage(message);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -221,44 +214,7 @@ namespace Barotrauma.Networking
|
||||
public virtual void Update(float deltaTime)
|
||||
{
|
||||
#if CLIENT
|
||||
GUITextBox msgBox = (Screen.Selected == GameMain.GameScreen ? chatMsgBox : GameMain.NetLobbyScreen.TextBox);
|
||||
if (gameStarted && Screen.Selected == GameMain.GameScreen)
|
||||
{
|
||||
msgBox.Visible = Character.Controlled == null || Character.Controlled.CanSpeak;
|
||||
|
||||
if (!GUI.DisableHUD)
|
||||
{
|
||||
inGameHUD.Update(deltaTime);
|
||||
GameMain.GameSession.CrewManager.Update(deltaTime);
|
||||
}
|
||||
|
||||
if (Character.Controlled == null || Character.Controlled.IsDead)
|
||||
{
|
||||
GameMain.GameScreen.Cam.TargetPos = Vector2.Zero;
|
||||
GameMain.LightManager.LosEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
//tab doesn't autoselect the chatbox when debug console is open,
|
||||
//because tab is used for autocompleting console commands
|
||||
if ((PlayerInput.KeyHit(InputType.Chat) || PlayerInput.KeyHit(InputType.RadioChat)) &&
|
||||
!DebugConsole.IsOpen && (Screen.Selected != GameMain.GameScreen || msgBox.Visible))
|
||||
{
|
||||
if (msgBox.Selected)
|
||||
{
|
||||
msgBox.Text = "";
|
||||
msgBox.Deselect();
|
||||
}
|
||||
else
|
||||
{
|
||||
msgBox.Select();
|
||||
if (Screen.Selected == GameMain.GameScreen && PlayerInput.KeyHit(InputType.RadioChat))
|
||||
{
|
||||
msgBox.Text = "r; ";
|
||||
msgBox.OnTextChanged?.Invoke(msgBox, msgBox.Text);
|
||||
}
|
||||
}
|
||||
}
|
||||
UpdateHUD(deltaTime);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
partial class OrderChatMessage : ChatMessage
|
||||
{
|
||||
public readonly Order Order;
|
||||
|
||||
//who was this order given to
|
||||
public readonly Character TargetCharacter;
|
||||
|
||||
//which entity is this order referring to (hull, reactor, railgun controller, etc)
|
||||
public readonly Entity TargetEntity;
|
||||
|
||||
//additional instructions (power up, fire at will, etc)
|
||||
public readonly string OrderOption;
|
||||
|
||||
public OrderChatMessage(Order order, string orderOption, Entity targetEntity, Character targetCharacter, Character sender)
|
||||
: this(order, orderOption,
|
||||
order.GetChatMessage(targetCharacter?.Name, sender?.CurrentHull?.RoomName, orderOption),
|
||||
targetEntity, targetCharacter, sender)
|
||||
{
|
||||
}
|
||||
|
||||
public OrderChatMessage(Order order, string orderOption, string text, Entity targetEntity, Character targetCharacter, Character sender)
|
||||
: base(sender?.Name, text, ChatMessageType.Order, sender)
|
||||
{
|
||||
Order = order;
|
||||
OrderOption = orderOption;
|
||||
TargetCharacter = targetCharacter;
|
||||
TargetEntity = targetEntity;
|
||||
}
|
||||
|
||||
public override void ServerWrite(NetOutgoingMessage msg, Client c)
|
||||
{
|
||||
msg.Write((byte)ServerNetObject.CHAT_MESSAGE);
|
||||
msg.Write(NetStateID);
|
||||
msg.Write((byte)ChatMessageType.Order);
|
||||
|
||||
msg.Write(SenderName);
|
||||
msg.Write(Sender != null && c.InGame);
|
||||
if (Sender != null && c.InGame)
|
||||
{
|
||||
msg.Write(Sender.ID);
|
||||
}
|
||||
|
||||
msg.Write((byte)Order.PrefabList.IndexOf(Order.Prefab));
|
||||
msg.Write(TargetCharacter == null ? (UInt16)0 : TargetCharacter.ID);
|
||||
msg.Write(TargetEntity == null ? (UInt16)0 : TargetEntity.ID);
|
||||
msg.Write((byte)Array.IndexOf(Order.Prefab.Options, OrderOption));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,7 +103,10 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
foreach (Connection connection in connectionPanel.Connections)
|
||||
{
|
||||
Array.ForEach(connection.Wires, w => { if (w != null) w.Locked = true; });
|
||||
foreach (Wire wire in connection.Wires)
|
||||
{
|
||||
if (wire != null) wire.Locked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,6 +131,45 @@ namespace Barotrauma.Networking
|
||||
(c.Character == null || c.Character.IsDead));
|
||||
}
|
||||
|
||||
private List<CharacterInfo> GetBotsToRespawn()
|
||||
{
|
||||
GameServer server = networkMember as GameServer;
|
||||
|
||||
if (server.BotSpawnMode == BotSpawnMode.Normal)
|
||||
{
|
||||
return Character.CharacterList
|
||||
.FindAll(c => c.TeamID == 1 && c.AIController != null && c.Info != null && c.IsDead)
|
||||
.Select(c => c.Info)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
int currPlayerCount = server.ConnectedClients.Count(c => c.InGame && (!c.SpectateOnly || !server.AllowSpectating));
|
||||
if (server.CharacterInfo != null) currPlayerCount++;
|
||||
|
||||
var existingBots = Character.CharacterList
|
||||
.FindAll(c => c.TeamID == 1 && c.AIController != null && c.Info != null);
|
||||
|
||||
int requiredBots = server.BotCount - currPlayerCount;
|
||||
requiredBots -= existingBots.Count(b => !b.IsDead);
|
||||
|
||||
List<CharacterInfo> botsToRespawn = new List<CharacterInfo>();
|
||||
for (int i = 0; i < requiredBots; i++)
|
||||
{
|
||||
CharacterInfo botToRespawn = existingBots.Find(b => b.IsDead)?.Info;
|
||||
if (botToRespawn == null)
|
||||
{
|
||||
botToRespawn = new CharacterInfo(Character.HumanConfigFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
existingBots.Remove(botToRespawn.Character);
|
||||
}
|
||||
botsToRespawn.Add(botToRespawn);
|
||||
}
|
||||
return botsToRespawn;
|
||||
}
|
||||
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
if (respawnShuttle == null)
|
||||
@@ -425,22 +467,21 @@ namespace Barotrauma.Networking
|
||||
|
||||
foreach (Character c in Character.CharacterList)
|
||||
{
|
||||
if (c.Submarine == respawnShuttle)
|
||||
{
|
||||
if (Character.Controlled == c) Character.Controlled = null;
|
||||
c.Enabled = false;
|
||||
|
||||
if (c.Inventory != null)
|
||||
{
|
||||
foreach (Item item in c.Inventory.Items)
|
||||
{
|
||||
if (item == null) continue;
|
||||
Spawner.AddToRemoveQueue(item);
|
||||
}
|
||||
}
|
||||
if (c.Submarine != respawnShuttle) continue;
|
||||
|
||||
if (Character.Controlled == c) Character.Controlled = null;
|
||||
c.Kill(CauseOfDeathType.Unknown, null, true);
|
||||
c.Enabled = false;
|
||||
|
||||
c.Kill(CauseOfDeath.Damage, true);
|
||||
}
|
||||
Spawner.AddToRemoveQueue(c);
|
||||
if (c.Inventory != null)
|
||||
{
|
||||
foreach (Item item in c.Inventory.Items)
|
||||
{
|
||||
if (item == null) continue;
|
||||
Spawner.AddToRemoveQueue(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
respawnShuttle.SetPosition(new Vector2(Level.Loaded.StartPosition.X, Level.Loaded.Size.Y + respawnShuttle.Borders.Height));
|
||||
@@ -466,8 +507,11 @@ namespace Barotrauma.Networking
|
||||
c.TeamID = 1;
|
||||
if (c.CharacterInfo == null) c.CharacterInfo = new CharacterInfo(Character.HumanConfigFile, c.Name);
|
||||
}
|
||||
|
||||
List<CharacterInfo> characterInfos = clients.Select(c => c.CharacterInfo).ToList();
|
||||
|
||||
var botsToSpawn = GetBotsToRespawn();
|
||||
characterInfos.AddRange(botsToSpawn);
|
||||
|
||||
if (server.Character != null && server.Character.IsDead)
|
||||
{
|
||||
characterInfos.Add(server.CharacterInfo);
|
||||
@@ -485,10 +529,10 @@ namespace Barotrauma.Networking
|
||||
//(in order to give them appropriate ID card tags)
|
||||
var mainSubSpawnPoints = WayPoint.SelectCrewSpawnPoints(characterInfos, Submarine.MainSub);
|
||||
|
||||
ItemPrefab divingSuitPrefab = MapEntityPrefab.Find("Diving Suit") as ItemPrefab;
|
||||
ItemPrefab oxyPrefab = MapEntityPrefab.Find("Oxygen Tank") as ItemPrefab;
|
||||
ItemPrefab scooterPrefab = MapEntityPrefab.Find("Underwater Scooter") as ItemPrefab;
|
||||
ItemPrefab batteryPrefab = MapEntityPrefab.Find("Battery Cell") as ItemPrefab;
|
||||
ItemPrefab divingSuitPrefab = MapEntityPrefab.Find(null, "divingsuit") as ItemPrefab;
|
||||
ItemPrefab oxyPrefab = MapEntityPrefab.Find(null, "oxygentank") as ItemPrefab;
|
||||
ItemPrefab scooterPrefab = MapEntityPrefab.Find(null, "underwaterscooter") as ItemPrefab;
|
||||
ItemPrefab batteryPrefab = MapEntityPrefab.Find(null, "batterycell") as ItemPrefab;
|
||||
|
||||
var cargoSp = WayPoint.WayPointList.Find(wp => wp.Submarine == respawnSub && wp.SpawnType == SpawnType.Cargo);
|
||||
|
||||
@@ -496,14 +540,16 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
bool myCharacter = false;
|
||||
#if CLIENT
|
||||
myCharacter = i >= clients.Count;
|
||||
myCharacter = i >= clients.Count + botsToSpawn.Count;
|
||||
#endif
|
||||
bool bot = i >= clients.Count && !myCharacter;
|
||||
|
||||
var character = Character.Create(characterInfos[i], shuttleSpawnPoints[i].WorldPosition, !myCharacter, false);
|
||||
|
||||
var character = Character.Create(characterInfos[i], shuttleSpawnPoints[i].WorldPosition, characterInfos[i].Name, !myCharacter && !bot, bot);
|
||||
character.TeamID = 1;
|
||||
|
||||
#if CLIENT
|
||||
GameMain.GameSession.CrewManager.AddCharacter(character);
|
||||
|
||||
if (myCharacter)
|
||||
{
|
||||
server.Character = character;
|
||||
@@ -512,19 +558,23 @@ namespace Barotrauma.Networking
|
||||
GameMain.LightManager.LosEnabled = true;
|
||||
GameServer.Log(string.Format("Respawning {0} (host) as {1}", character.Name, characterInfos[i].Job.Name), ServerLog.MessageType.Spawning);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (!myCharacter)
|
||||
{
|
||||
#endif
|
||||
clients[i].Character = character;
|
||||
character.OwnerClientIP = clients[i].Connection.RemoteEndPoint.Address.ToString();
|
||||
character.OwnerClientName = clients[i].Name;
|
||||
GameServer.Log(string.Format("Respawning {0} ({1}) as {2}", clients[i].Name, clients[i].Connection?.RemoteEndPoint?.Address, characterInfos[i].Job.Name), ServerLog.MessageType.Spawning);
|
||||
|
||||
#if CLIENT
|
||||
if (bot)
|
||||
{
|
||||
GameServer.Log(string.Format("Respawning bot {0} as {1}", character.Info.Name, characterInfos[i].Job.Name), ServerLog.MessageType.Spawning);
|
||||
}
|
||||
else
|
||||
{
|
||||
clients[i].Character = character;
|
||||
character.OwnerClientIP = clients[i].Connection.RemoteEndPoint.Address.ToString();
|
||||
character.OwnerClientName = clients[i].Name;
|
||||
GameServer.Log(string.Format("Respawning {0} ({1}) as {2}", clients[i].Name, clients[i].Connection?.RemoteEndPoint?.Address, characterInfos[i].Job.Name), ServerLog.MessageType.Spawning);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (respawnShuttle != null)
|
||||
|
||||
if (divingSuitPrefab != null && oxyPrefab != null && respawnShuttle != null)
|
||||
{
|
||||
Vector2 pos = cargoSp == null ? character.Position : cargoSp.Position;
|
||||
if (divingSuitPrefab != null && oxyPrefab != null)
|
||||
@@ -567,9 +617,6 @@ namespace Barotrauma.Networking
|
||||
if (!string.IsNullOrWhiteSpace(shuttleSpawnPoints[i].IdCardDesc))
|
||||
item.Description = shuttleSpawnPoints[i].IdCardDesc;
|
||||
}
|
||||
#if CLIENT
|
||||
GameMain.GameSession.CrewManager.AddCharacter(character);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
partial class ServerInfo
|
||||
{
|
||||
public string IP;
|
||||
public string Port;
|
||||
public string ServerName;
|
||||
public string ServerMessage;
|
||||
public bool GameStarted;
|
||||
public int PlayerCount;
|
||||
public int MaxPlayers;
|
||||
public bool HasPassword;
|
||||
|
||||
public bool PingChecked;
|
||||
public int Ping = -1;
|
||||
|
||||
//null value means that the value isn't known (the server may be using
|
||||
//an old version of the game that didn't report these values or the FetchRules query to Steam may not have finished yet)
|
||||
public bool? UsingWhiteList;
|
||||
public SelectionMode? ModeSelectionMode;
|
||||
public SelectionMode? SubSelectionMode;
|
||||
public bool? AllowSpectating;
|
||||
public bool? AllowRespawn;
|
||||
public YesNoMaybe? TraitorsEnabled;
|
||||
public string GameMode;
|
||||
|
||||
public bool? RespondedToSteamQuery = null;
|
||||
|
||||
public string GameVersion;
|
||||
public List<string> ContentPackageNames
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new List<string>();
|
||||
public List<string> ContentPackageHashes
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new List<string>();
|
||||
public List<string> ContentPackageWorkshopUrls
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
} = new List<string>();
|
||||
|
||||
public bool ContentPackagesMatch(IEnumerable<ContentPackage> myContentPackages)
|
||||
{
|
||||
return ContentPackagesMatch(myContentPackages.Select(cp => cp.MD5hash.Hash));
|
||||
}
|
||||
|
||||
public bool ContentPackagesMatch(IEnumerable<string> myContentPackageHashes)
|
||||
{
|
||||
HashSet<string> contentPackageHashes = new HashSet<string>(ContentPackageHashes);
|
||||
return contentPackageHashes.SetEquals(myContentPackageHashes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,9 +116,9 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
while (listBox != null && listBox.children.Count > LinesPerFile)
|
||||
while (listBox != null && listBox.Content.CountChildren > LinesPerFile)
|
||||
{
|
||||
listBox.RemoveChild(listBox.children[0]);
|
||||
listBox.RemoveChild(listBox.Content.Children.First());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -26,7 +26,7 @@ namespace Barotrauma
|
||||
var existingVotable = voteList.Find(v => v.First == vote || v.First.Equals(vote));
|
||||
if (existingVotable == null)
|
||||
{
|
||||
voteList.Add(Pair<object, int>.Create(vote, 1));
|
||||
voteList.Add(new Pair<object, int>(vote, 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -101,8 +101,8 @@ namespace Barotrauma
|
||||
break;
|
||||
|
||||
case VoteType.Mode:
|
||||
string modeName = inc.ReadString();
|
||||
GameModePreset mode = GameModePreset.list.Find(gm => gm.Name == modeName);
|
||||
string modeIdentifier = inc.ReadString();
|
||||
GameModePreset mode = GameModePreset.List.Find(gm => gm.Identifier == modeIdentifier);
|
||||
if (!mode.Votable) break;
|
||||
|
||||
sender.SetVote(voteType, mode);
|
||||
@@ -130,6 +130,18 @@ namespace Barotrauma
|
||||
GameMain.Server.SendChatMessage(sender.Name + " has voted to kick " + kicked.Name, ChatMessageType.Server, null);
|
||||
}
|
||||
|
||||
break;
|
||||
case VoteType.StartRound:
|
||||
bool ready = inc.ReadBoolean();
|
||||
if (ready != sender.GetVote<bool>(VoteType.StartRound))
|
||||
{
|
||||
sender.SetVote(VoteType.StartRound, ready);
|
||||
GameServer.Log(sender.Name + (ready ? " is ready to start the game." : " is not ready to start the game."), ServerLog.MessageType.ServerMessage);
|
||||
#if CLIENT
|
||||
UpdateVoteTexts(GameMain.Server.ConnectedClients, voteType);
|
||||
#endif
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -161,7 +173,7 @@ namespace Barotrauma
|
||||
foreach (Pair<object, int> vote in voteList)
|
||||
{
|
||||
msg.Write((byte)vote.Second);
|
||||
msg.Write(((GameModePreset)vote.First).Name);
|
||||
msg.Write(((GameModePreset)vote.First).Identifier);
|
||||
}
|
||||
}
|
||||
msg.Write(AllowEndVoting);
|
||||
@@ -173,6 +185,13 @@ namespace Barotrauma
|
||||
|
||||
msg.Write(AllowVoteKick);
|
||||
|
||||
var readyClients = GameMain.Server.ConnectedClients.FindAll(c => c.GetVote<bool>(VoteType.StartRound));
|
||||
msg.Write((byte)readyClients.Count);
|
||||
foreach (Client c in readyClients)
|
||||
{
|
||||
msg.Write(c.ID);
|
||||
}
|
||||
|
||||
msg.WritePadBits();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user