Merge branch 'dev' of https://github.com/Regalis11/Barotrauma.git into unstable-tests
This commit is contained in:
@@ -38,7 +38,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
public bool CompareTo(string endpointCompare)
|
||||
{
|
||||
if (string.IsNullOrEmpty(EndPoint) || string.IsNullOrEmpty(EndPoint)) { return false; }
|
||||
if (string.IsNullOrEmpty(EndPoint) || string.IsNullOrEmpty(endpointCompare)) { return false; }
|
||||
if (!IsRangeBan)
|
||||
{
|
||||
return endpointCompare == EndPoint;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System;
|
||||
using System.Text;
|
||||
using MoonSharp.Interpreter;
|
||||
|
||||
@@ -18,31 +17,48 @@ namespace Barotrauma.Networking
|
||||
Character orderTargetCharacter = null;
|
||||
Entity orderTargetEntity = null;
|
||||
OrderChatMessage orderMsg = null;
|
||||
OrderTarget orderTargetPosition = null;
|
||||
Order.OrderTargetType orderTargetType = Order.OrderTargetType.Entity;
|
||||
int? wallSectionIndex = null;
|
||||
Order order = null;
|
||||
bool isNewOrder = false;
|
||||
if (type == ChatMessageType.Order)
|
||||
{
|
||||
var orderMessageInfo = OrderChatMessage.ReadOrder(msg);
|
||||
if (orderMessageInfo.OrderIndex < 0 || orderMessageInfo.OrderIndex >= Order.PrefabList.Count)
|
||||
if (orderMessageInfo.OrderIdentifier == Identifier.Empty)
|
||||
{
|
||||
DebugConsole.ThrowError($"Invalid order message from client \"{c.Name}\" - order index out of bounds ({orderMessageInfo.OrderIndex}).");
|
||||
DebugConsole.ThrowError($"Invalid order message from client \"{c.Name}\" - order identifier is empty.");
|
||||
if (NetIdUtils.IdMoreRecent(ID, c.LastSentChatMsgID)) { c.LastSentChatMsgID = ID; }
|
||||
return;
|
||||
}
|
||||
isNewOrder = orderMessageInfo.IsNewOrder;
|
||||
orderTargetCharacter = orderMessageInfo.TargetCharacter;
|
||||
orderTargetEntity = orderMessageInfo.TargetEntity;
|
||||
orderTargetPosition = orderMessageInfo.TargetPosition;
|
||||
OrderTarget orderTargetPosition = orderMessageInfo.TargetPosition;
|
||||
orderTargetType = orderMessageInfo.TargetType;
|
||||
wallSectionIndex = orderMessageInfo.WallSectionIndex;
|
||||
var orderPrefab = orderMessageInfo.OrderPrefab ?? Order.PrefabList[orderMessageInfo.OrderIndex];
|
||||
string orderOption = orderMessageInfo.OrderOption ??
|
||||
(orderMessageInfo.OrderOptionIndex == null || orderMessageInfo.OrderOptionIndex < 0 || orderMessageInfo.OrderOptionIndex >= orderPrefab.Options.Length ?
|
||||
"" : orderPrefab.Options[orderMessageInfo.OrderOptionIndex.Value]);
|
||||
orderMsg = new OrderChatMessage(orderPrefab, orderOption, orderMessageInfo.Priority, orderTargetPosition ?? orderTargetEntity as ISpatialEntity, orderTargetCharacter, c.Character, isNewOrder: orderMessageInfo.IsNewOrder)
|
||||
var orderPrefab = orderMessageInfo.OrderPrefab ?? OrderPrefab.Prefabs[orderMessageInfo.OrderIdentifier];
|
||||
Identifier orderOption = orderMessageInfo.OrderOption;
|
||||
if (orderOption.IsEmpty)
|
||||
{
|
||||
WallSectionIndex = wallSectionIndex
|
||||
};
|
||||
orderOption = orderMessageInfo.OrderOptionIndex == null || orderMessageInfo.OrderOptionIndex < 0 || orderMessageInfo.OrderOptionIndex >= orderPrefab.Options.Length ?
|
||||
Identifier.Empty : orderPrefab.Options[orderMessageInfo.OrderOptionIndex.Value];
|
||||
}
|
||||
if (orderTargetType == Order.OrderTargetType.Position)
|
||||
{
|
||||
order = new Order(orderPrefab, orderOption, orderTargetPosition, orderGiver: c.Character)
|
||||
.WithManualPriority(orderMessageInfo.Priority);
|
||||
}
|
||||
else if (orderTargetType == Order.OrderTargetType.WallSection)
|
||||
{
|
||||
order = new Order(orderPrefab, orderOption, orderTargetEntity as Structure, wallSectionIndex, orderGiver: c.Character)
|
||||
.WithManualPriority(orderMessageInfo.Priority);
|
||||
}
|
||||
else
|
||||
{
|
||||
order = new Order(orderPrefab, orderOption, orderTargetEntity, orderPrefab.GetTargetItemComponent(orderTargetEntity as Item), orderGiver: c.Character)
|
||||
.WithManualPriority(orderMessageInfo.Priority);
|
||||
}
|
||||
orderMsg = new OrderChatMessage(order, orderTargetCharacter, c.Character);
|
||||
txt = orderMsg.Text;
|
||||
}
|
||||
else
|
||||
@@ -96,11 +112,11 @@ namespace Barotrauma.Networking
|
||||
if (c.ChatSpamCount > 3)
|
||||
{
|
||||
//kick for spamming too much
|
||||
GameMain.Server.KickClient(c, TextManager.Get("SpamFilterKicked"));
|
||||
GameMain.Server.KickClient(c, TextManager.Get("SpamFilterKicked").Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null);
|
||||
ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked").Value, ChatMessageType.Server, null);
|
||||
c.ChatSpamTimer = 10.0f;
|
||||
GameMain.Server.SendDirectChatMessage(denyMsg, c);
|
||||
}
|
||||
@@ -111,7 +127,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (c.ChatSpamTimer > 0.0f && !isOwner && !GameMain.Lua.game.disableSpamFilter)
|
||||
{
|
||||
ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked"), ChatMessageType.Server, null);
|
||||
ChatMessage denyMsg = Create("", TextManager.Get("SpamFilterBlocked").Value, ChatMessageType.Server, null);
|
||||
c.ChatSpamTimer = 10.0f;
|
||||
GameMain.Server.SendDirectChatMessage(denyMsg, c);
|
||||
return;
|
||||
@@ -132,16 +148,6 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
HumanAIController.ReportProblem(orderMsg.Sender, orderMsg.Order);
|
||||
}
|
||||
Order order = orderTargetType switch
|
||||
{
|
||||
Order.OrderTargetType.Entity =>
|
||||
new Order(orderMsg.Order, orderTargetEntity, orderMsg.Order?.GetTargetItemComponent(orderTargetEntity as Item), orderGiver: orderMsg.Sender),
|
||||
Order.OrderTargetType.Position =>
|
||||
new Order(orderMsg.Order, orderTargetPosition, orderGiver: orderMsg.Sender),
|
||||
Order.OrderTargetType.WallSection when orderTargetEntity is Structure s && wallSectionIndex.HasValue =>
|
||||
new Order(orderMsg.Order, s, wallSectionIndex, orderGiver: orderMsg.Sender),
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
if (order != null)
|
||||
{
|
||||
if (order.TargetAllCharacters)
|
||||
@@ -168,7 +174,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else if (orderTargetCharacter != null)
|
||||
{
|
||||
orderTargetCharacter.SetOrder(order, orderMsg.OrderOption, orderMsg.OrderPriority, orderMsg.Sender);
|
||||
orderTargetCharacter.SetOrder(order, isNewOrder);
|
||||
}
|
||||
}
|
||||
GameMain.Server.SendOrderChatMessage(orderMsg);
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using System.IO.Pipes;
|
||||
using System;
|
||||
using System.IO.Pipes;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
@@ -14,6 +17,12 @@ namespace Barotrauma.Networking
|
||||
PrivateStart();
|
||||
}
|
||||
|
||||
public static void NotifyCrash(string msg)
|
||||
{
|
||||
errorsToWrite.Enqueue(msg);
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
public static void ShutDown()
|
||||
{
|
||||
PrivateShutDown();
|
||||
|
||||
@@ -57,8 +57,8 @@ namespace Barotrauma.Networking
|
||||
|
||||
public bool ReadyToStart;
|
||||
|
||||
public List<Pair<JobPrefab, int>> JobPreferences;
|
||||
public Pair<JobPrefab, int> AssignedJob;
|
||||
public List<JobVariant> JobPreferences;
|
||||
public JobVariant AssignedJob;
|
||||
|
||||
public float DeleteDisconnectedTimer;
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
partial void InitProjSpecific()
|
||||
{
|
||||
JobPreferences = new List<Pair<JobPrefab, int>>();
|
||||
JobPreferences = new List<JobVariant>();
|
||||
|
||||
VoipQueue = new VoipQueue(ID, true, true);
|
||||
GameMain.Server.VoipServer.RegisterQueue(VoipQueue);
|
||||
@@ -149,7 +149,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
foreach (char character in name)
|
||||
{
|
||||
if (!serverSettings.AllowedClientNameChars.Any(charRange => (int)character >= charRange.First && (int)character <= charRange.Second)) { return false; }
|
||||
if (!serverSettings.AllowedClientNameChars.Any(charRange => (int)character >= charRange.Start && (int)character <= charRange.End)) { return false; }
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -1,47 +1,55 @@
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class EntitySpawner : Entity, IServerSerializable
|
||||
{
|
||||
public void CreateNetworkEvent(Entity entity, bool remove)
|
||||
public void CreateNetworkEvent(SpawnOrRemove spawnOrRemove)
|
||||
{
|
||||
CreateNetworkEventProjSpecific(entity, remove);
|
||||
CreateNetworkEventProjSpecific(spawnOrRemove);
|
||||
}
|
||||
|
||||
partial void CreateNetworkEventProjSpecific(Entity entity, bool remove)
|
||||
partial void CreateNetworkEventProjSpecific(SpawnOrRemove spawnOrRemove)
|
||||
{
|
||||
if (GameMain.Server != null && entity != null)
|
||||
if (GameMain.Server == null || spawnOrRemove?.Entity == null) { return; }
|
||||
|
||||
GameMain.Server.CreateEntityEvent(this, spawnOrRemove);
|
||||
if (spawnOrRemove.Entity is Character { Info: { } } character)
|
||||
{
|
||||
GameMain.Server.CreateEntityEvent(this, new object[] { new SpawnOrRemove(entity, remove) });
|
||||
foreach (var statKey in character.Info.SavedStatValues.Keys)
|
||||
{
|
||||
GameMain.NetworkMember.CreateEntityEvent(character, new Character.UpdatePermanentStatsEventData(statKey));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage message, Client client, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage message, Client client, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
if (GameMain.Server == null) return;
|
||||
if (GameMain.Server is null) { return; }
|
||||
if (!(extraData is SpawnOrRemove entities)) { throw new Exception($"Malformed {nameof(EntitySpawner)} event: expected {nameof(SpawnOrRemove)}"); }
|
||||
|
||||
SpawnOrRemove entities = (SpawnOrRemove)extraData[0];
|
||||
|
||||
message.Write(entities.Remove);
|
||||
if (entities.Remove)
|
||||
message.Write(entities is RemoveEntity);
|
||||
if (entities is RemoveEntity)
|
||||
{
|
||||
message.Write(entities.OriginalID);
|
||||
message.Write(entities.ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (entities.Entity is Item)
|
||||
switch (entities.Entity)
|
||||
{
|
||||
message.Write((byte)SpawnableType.Item);
|
||||
DebugConsole.Log("Writing item spawn data " + entities.Entity.ToString() + " (original ID: " + entities.OriginalID + ", current ID: " + entities.Entity.ID + ")");
|
||||
((Item)entities.Entity).WriteSpawnData(message, entities.OriginalID, entities.OriginalInventoryID, entities.OriginalItemContainerIndex);
|
||||
}
|
||||
else if (entities.Entity is Character)
|
||||
{
|
||||
message.Write((byte)SpawnableType.Character);
|
||||
DebugConsole.Log("Writing character spawn data: " + entities.Entity.ToString() + " (original ID: " + entities.OriginalID + ", current ID: " + entities.Entity.ID + ")");
|
||||
((Character)entities.Entity).WriteSpawnData(message, entities.OriginalID, restrictMessageSize: true);
|
||||
case Item item:
|
||||
message.Write((byte)SpawnableType.Item);
|
||||
DebugConsole.Log(
|
||||
$"Writing item spawn data {item} (ID: {entities.ID})");
|
||||
item.WriteSpawnData(message, entities.ID, entities.InventoryID, entities.ItemContainerIndex, entities.SlotIndex);
|
||||
break;
|
||||
case Character character:
|
||||
message.Write((byte)SpawnableType.Character);
|
||||
DebugConsole.Log(
|
||||
$"Writing character spawn data: {character} (ID: {entities.ID})");
|
||||
character.WriteSpawnData(message, entities.ID, restrictMessageSize: true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,12 +36,25 @@ namespace Barotrauma.Networking
|
||||
get { return KnownReceivedOffset / (float)Data.Length; }
|
||||
}
|
||||
|
||||
private float waitTimer;
|
||||
public float WaitTimer
|
||||
{
|
||||
get;
|
||||
set;
|
||||
get => waitTimer;
|
||||
set
|
||||
{
|
||||
if (value > 0.0f)
|
||||
{
|
||||
//setting a wait timer means that network conditions
|
||||
//aren't ideal, slow down the packet rate
|
||||
PacketsPerUpdate = Math.Max(PacketsPerUpdate / 4.0f, 1.0f);
|
||||
}
|
||||
waitTimer = value;
|
||||
}
|
||||
}
|
||||
|
||||
public const int MaxPacketsPerUpdate = 4;
|
||||
public float PacketsPerUpdate { get; set; } = 1.0f;
|
||||
|
||||
public byte[] Data { get; }
|
||||
|
||||
public bool Acknowledged;
|
||||
@@ -112,15 +125,12 @@ namespace Barotrauma.Networking
|
||||
public float StallPacketsTime { get; set; }
|
||||
#endif
|
||||
|
||||
public List<FileTransferOut> ActiveTransfers
|
||||
{
|
||||
get { return activeTransfers; }
|
||||
}
|
||||
public IReadOnlyList<FileTransferOut> ActiveTransfers => activeTransfers;
|
||||
|
||||
public FileSender(ServerPeer serverPeer, int mtu)
|
||||
{
|
||||
peer = serverPeer;
|
||||
chunkLen = mtu - 100;
|
||||
chunkLen = mtu - 200;
|
||||
|
||||
activeTransfers = new List<FileTransferOut>();
|
||||
}
|
||||
@@ -163,13 +173,14 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
OnStarted(transfer);
|
||||
GameMain.Server.LastClientListUpdateID++;
|
||||
|
||||
return transfer;
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
activeTransfers.RemoveAll(t => t.Connection.Status != NetworkConnectionStatus.Connected);
|
||||
int numRemoved = activeTransfers.RemoveAll(t => t.Connection.Status != NetworkConnectionStatus.Connected);
|
||||
|
||||
var endedTransfers = activeTransfers.FindAll(t =>
|
||||
t.Connection.Status != NetworkConnectionStatus.Connected ||
|
||||
@@ -186,20 +197,19 @@ namespace Barotrauma.Networking
|
||||
foreach (FileTransferOut transfer in activeTransfers)
|
||||
{
|
||||
transfer.WaitTimer -= deltaTime;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
if (transfer.WaitTimer > 0.0f) { break; }
|
||||
Send(transfer);
|
||||
}
|
||||
if (transfer.WaitTimer > 0.0f) { continue; }
|
||||
Send(transfer);
|
||||
}
|
||||
|
||||
if (numRemoved > 0 || endedTransfers.Count > 0)
|
||||
{
|
||||
GameMain.Server.LastClientListUpdateID++;
|
||||
}
|
||||
}
|
||||
|
||||
private void Send(FileTransferOut transfer)
|
||||
{
|
||||
// send another part of the file
|
||||
long remaining = transfer.Data.Length - transfer.SentOffset;
|
||||
int sendByteCount = (remaining > chunkLen ? chunkLen : (int)remaining);
|
||||
|
||||
IWriteMessage message;
|
||||
|
||||
try
|
||||
@@ -234,7 +244,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
transfer.Status = FileTransferStatus.Sending;
|
||||
|
||||
if (GameSettings.VerboseLogging)
|
||||
if (GameSettings.CurrentConfig.VerboseLogging)
|
||||
{
|
||||
DebugConsole.Log("Sending file transfer initiation message: ");
|
||||
DebugConsole.Log(" File: " + transfer.FileName);
|
||||
@@ -246,28 +256,44 @@ namespace Barotrauma.Networking
|
||||
return;
|
||||
}
|
||||
|
||||
message = new WriteOnlyMessage();
|
||||
message.Write((byte)ServerPacketHeader.FILE_TRANSFER);
|
||||
message.Write((byte)FileTransferMessageType.Data);
|
||||
|
||||
message.Write((byte)transfer.ID);
|
||||
message.Write(transfer.SentOffset);
|
||||
|
||||
byte[] sendBytes = new byte[sendByteCount];
|
||||
Array.Copy(transfer.Data, transfer.SentOffset, sendBytes, 0, sendByteCount);
|
||||
|
||||
message.Write((ushort)sendByteCount);
|
||||
message.Write(sendBytes, 0, sendByteCount);
|
||||
|
||||
transfer.SentOffset += sendByteCount;
|
||||
if (transfer.SentOffset > transfer.KnownReceivedOffset + chunkLen * 10 ||
|
||||
transfer.SentOffset >= transfer.Data.Length)
|
||||
for (int i = 0; i < Math.Floor(transfer.PacketsPerUpdate); i++)
|
||||
{
|
||||
transfer.SentOffset = transfer.KnownReceivedOffset;
|
||||
transfer.WaitTimer = 0.5f;
|
||||
}
|
||||
long remaining = transfer.Data.Length - transfer.SentOffset;
|
||||
int sendByteCount = (remaining > chunkLen ? chunkLen : (int)remaining);
|
||||
|
||||
message = new WriteOnlyMessage();
|
||||
message.Write((byte)ServerPacketHeader.FILE_TRANSFER);
|
||||
message.Write((byte)FileTransferMessageType.Data);
|
||||
|
||||
peer.Send(message, transfer.Connection, DeliveryMethod.Unreliable);
|
||||
message.Write((byte)transfer.ID);
|
||||
message.Write(transfer.SentOffset);
|
||||
|
||||
message.Write((ushort)sendByteCount);
|
||||
int chunkDestPos = message.BytePosition;
|
||||
message.BitPosition += sendByteCount * 8;
|
||||
message.LengthBits = Math.Max(message.LengthBits, message.BitPosition);
|
||||
Array.Copy(transfer.Data, transfer.SentOffset, message.Buffer, chunkDestPos, sendByteCount);
|
||||
|
||||
transfer.SentOffset += sendByteCount;
|
||||
if (transfer.SentOffset >= transfer.Data.Length)
|
||||
{
|
||||
transfer.SentOffset = transfer.KnownReceivedOffset;
|
||||
transfer.WaitTimer = 1.0f;
|
||||
}
|
||||
|
||||
peer.Send(message, transfer.Connection, DeliveryMethod.Unreliable, compressPastThreshold: false);
|
||||
|
||||
if (GameSettings.CurrentConfig.VerboseLogging)
|
||||
{
|
||||
DebugConsole.Log($"Sending {sendByteCount} bytes of the file {transfer.FileName} ({transfer.SentOffset / 1000}/{transfer.Data.Length / 1000} kB sent)");
|
||||
}
|
||||
|
||||
//try to increase the packet rate so large files get sent faster,
|
||||
//this gets reset when packet loss or disorder sets in
|
||||
transfer.PacketsPerUpdate = Math.Min(FileTransferOut.MaxPacketsPerUpdate,
|
||||
transfer.PacketsPerUpdate + 0.05f);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
transfer.WaitTimer = Math.Max(transfer.WaitTimer, StallPacketsTime);
|
||||
#endif
|
||||
@@ -283,11 +309,6 @@ namespace Barotrauma.Networking
|
||||
transfer.Status = FileTransferStatus.Error;
|
||||
return;
|
||||
}
|
||||
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
DebugConsole.Log($"Sending {sendByteCount} bytes of the file {transfer.FileName} ({transfer.SentOffset / 1000}/{transfer.Data.Length / 1000} kB sent)");
|
||||
}
|
||||
}
|
||||
|
||||
public void CancelTransfer(FileTransferOut transfer)
|
||||
@@ -302,9 +323,9 @@ namespace Barotrauma.Networking
|
||||
|
||||
public void ReadFileRequest(IReadMessage inc, Client client)
|
||||
{
|
||||
byte messageType = inc.ReadByte();
|
||||
FileTransferMessageType messageType = (FileTransferMessageType)inc.ReadByte();
|
||||
|
||||
if (messageType == (byte)FileTransferMessageType.Cancel)
|
||||
if (messageType == FileTransferMessageType.Cancel)
|
||||
{
|
||||
byte transferId = inc.ReadByte();
|
||||
var matchingTransfer = activeTransfers.Find(t => t.Connection == inc.Sender && t.ID == transferId);
|
||||
@@ -312,42 +333,51 @@ namespace Barotrauma.Networking
|
||||
|
||||
return;
|
||||
}
|
||||
else if (messageType == (byte)FileTransferMessageType.Data)
|
||||
else if (messageType == FileTransferMessageType.Data)
|
||||
{
|
||||
byte transferId = inc.ReadByte();
|
||||
var matchingTransfer = activeTransfers.Find(t => t.Connection == inc.Sender && t.ID == transferId);
|
||||
if (matchingTransfer != null)
|
||||
{
|
||||
matchingTransfer.Acknowledged = true;
|
||||
int offset = inc.ReadInt32();
|
||||
matchingTransfer.KnownReceivedOffset = offset > matchingTransfer.KnownReceivedOffset ? offset : matchingTransfer.KnownReceivedOffset;
|
||||
int expecting = inc.ReadInt32(); //the offset the client is waiting for
|
||||
int lastSeen = Math.Min(matchingTransfer.SentOffset, inc.ReadInt32()); //the last offset the client got from us
|
||||
matchingTransfer.KnownReceivedOffset = Math.Max(expecting, matchingTransfer.KnownReceivedOffset);
|
||||
if (matchingTransfer.SentOffset < matchingTransfer.KnownReceivedOffset)
|
||||
{
|
||||
matchingTransfer.WaitTimer = 0.0f;
|
||||
matchingTransfer.SentOffset = matchingTransfer.KnownReceivedOffset;
|
||||
}
|
||||
|
||||
if (lastSeen - matchingTransfer.KnownReceivedOffset >= chunkLen * 10 ||
|
||||
matchingTransfer.SentOffset >= matchingTransfer.Data.Length)
|
||||
{
|
||||
matchingTransfer.SentOffset = matchingTransfer.KnownReceivedOffset;
|
||||
matchingTransfer.WaitTimer = 1.0f;
|
||||
}
|
||||
|
||||
if (matchingTransfer.KnownReceivedOffset >= matchingTransfer.Data.Length)
|
||||
{
|
||||
matchingTransfer.Status = FileTransferStatus.Finished;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
byte fileType = inc.ReadByte();
|
||||
FileTransferType fileType = (FileTransferType)inc.ReadByte();
|
||||
switch (fileType)
|
||||
{
|
||||
case (byte)FileTransferType.Submarine:
|
||||
case FileTransferType.Submarine:
|
||||
string fileName = inc.ReadString();
|
||||
string fileHash = inc.ReadString();
|
||||
var requestedSubmarine = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == fileName && s.MD5Hash.Hash == fileHash);
|
||||
var requestedSubmarine = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == fileName && s.MD5Hash.StringRepresentation == fileHash);
|
||||
|
||||
if (requestedSubmarine != null)
|
||||
{
|
||||
StartTransfer(inc.Sender, FileTransferType.Submarine, requestedSubmarine.FilePath);
|
||||
}
|
||||
break;
|
||||
case (byte)FileTransferType.CampaignSave:
|
||||
case FileTransferType.CampaignSave:
|
||||
if (GameMain.GameSession != null &&
|
||||
!ActiveTransfers.Any(t => t.Connection == inc.Sender && t.FileType == FileTransferType.CampaignSave))
|
||||
{
|
||||
@@ -357,6 +387,23 @@ namespace Barotrauma.Networking
|
||||
client.LastCampaignSaveSendTime = new Pair<ushort, float>(campaign.LastSaveID, (float)Lidgren.Network.NetTime.Now);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FileTransferType.Mod:
|
||||
string modName = inc.ReadString();
|
||||
Md5Hash modHash = Md5Hash.StringAsHash(inc.ReadString());
|
||||
|
||||
if (!GameMain.Server.ServerSettings.AllowModDownloads) { return; }
|
||||
if (!(GameMain.Server.ModSender is { Ready: true })) { return; }
|
||||
|
||||
ContentPackage mod = ContentPackageManager.AllPackages.FirstOrDefault(p => p.Hash.Equals(modHash));
|
||||
|
||||
if (mod is null) { return; }
|
||||
|
||||
string modCompressedPath = ModSender.GetCompressedModPath(mod);
|
||||
if (!File.Exists(modCompressedPath)) { return; }
|
||||
|
||||
StartTransfer(inc.Sender, FileTransferType.Mod, modCompressedPath);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class ModSender : IDisposable
|
||||
{
|
||||
public const string UploadFolder = "TempMods_Upload";
|
||||
public const string Extension = ".barodir.gz";
|
||||
|
||||
public bool Ready { get; private set; } = false;
|
||||
|
||||
public ModSender()
|
||||
{
|
||||
DeleteDir();
|
||||
Directory.CreateDirectory(UploadFolder);
|
||||
TaskPool.Add(
|
||||
"ModSender",
|
||||
Task.WhenAll(
|
||||
ContentPackageManager.EnabledPackages.All
|
||||
.Where(p => p != ContentPackageManager.VanillaCorePackage && p.HasMultiplayerSyncedContent)
|
||||
.Select(CompressMod)),
|
||||
(t) => Ready = true);
|
||||
}
|
||||
|
||||
public static string GetCompressedModPath(ContentPackage mod)
|
||||
{
|
||||
string dir = mod.Dir;
|
||||
string resultFileName
|
||||
= dir.StartsWith(ContentPackage.LocalModsDir)
|
||||
? $"Local_{mod.Name}"
|
||||
: $"Workshop_{mod.Name}_{mod.SteamWorkshopId}";
|
||||
resultFileName = ToolBox.RemoveInvalidFileNameChars(resultFileName.Replace('\\', '_').Replace('/', '_'));
|
||||
resultFileName = $"{resultFileName}{Extension}";
|
||||
return Path.Combine(UploadFolder, resultFileName);
|
||||
}
|
||||
|
||||
public async Task CompressMod(ContentPackage mod)
|
||||
{
|
||||
await Task.Yield();
|
||||
string dir = mod.Dir;
|
||||
SaveUtil.CompressDirectory(dir, GetCompressedModPath(mod), fileName => { });
|
||||
}
|
||||
|
||||
private void DeleteDir()
|
||||
{
|
||||
if (Directory.Exists(UploadFolder)) { Directory.Delete(UploadFolder, recursive: true); }
|
||||
}
|
||||
|
||||
public bool IsDisposed { get; private set; } = false;
|
||||
public void Dispose()
|
||||
{
|
||||
IsDisposed = true;
|
||||
DeleteDir();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -128,7 +128,7 @@ namespace Barotrauma
|
||||
clientMemory.PreviousNotifiedKarma >= KickBanThreshold + KarmaNotificationInterval &&
|
||||
client.Karma < KickBanThreshold + KarmaNotificationInterval)
|
||||
{
|
||||
GameMain.Server.SendDirectChatMessage(TextManager.Get("KarmaBanWarning"), client);
|
||||
GameMain.Server.SendDirectChatMessage(TextManager.Get("KarmaBanWarning").Value, client);
|
||||
GameServer.Log(GameServer.ClientLogName(client) + " has been warned for having dangerously low karma.", ServerLog.MessageType.Karma);
|
||||
clientMemory.PreviousNotifiedKarma = client.Karma;
|
||||
clientMemory.PreviousKarmaNotificationTime = Timing.TotalTime;
|
||||
@@ -170,7 +170,7 @@ namespace Barotrauma
|
||||
existingAffliction.Strength = herpesStrength;
|
||||
if (herpesStrength <= 0.0f)
|
||||
{
|
||||
client.Character.CharacterHealth.ReduceAffliction(null, "invertcontrols", 100.0f);
|
||||
client.Character.CharacterHealth.ReduceAfflictionOnAllLimbs("invertcontrols".ToIdentifier(), 100.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,7 +283,7 @@ namespace Barotrauma
|
||||
|
||||
if (foundItem == null) { return; }
|
||||
|
||||
bool isIdCard = foundItem.prefab.Identifier == "idcard";
|
||||
bool isIdCard = ((MapEntity)foundItem).Prefab.Identifier == "idcard";
|
||||
bool isWeapon = foundItem.GetComponent<RangedWeapon>() != null || foundItem.GetComponent<MeleeWeapon>() != null;
|
||||
|
||||
if (isIdCard)
|
||||
@@ -394,8 +394,8 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
//attacking/healing clowns has a smaller effect on karma
|
||||
if (target.HasEquippedItem("clownmask") &&
|
||||
target.HasEquippedItem("clowncostume"))
|
||||
if (target.HasEquippedItem("clownmask".ToIdentifier()) &&
|
||||
target.HasEquippedItem("clowncostume".ToIdentifier()))
|
||||
{
|
||||
damage *= 0.5f;
|
||||
stun *= 0.5f;
|
||||
@@ -604,8 +604,8 @@ namespace Barotrauma
|
||||
if (client == null) { return; }
|
||||
|
||||
//all penalties/rewards are halved when wearing a clown costume
|
||||
if (target.HasEquippedItem("clownmask") &&
|
||||
target.HasEquippedItem("clowncostume"))
|
||||
if (target.HasEquippedItem("clownmask".ToIdentifier()) &&
|
||||
target.HasEquippedItem("clowncostume".ToIdentifier()))
|
||||
{
|
||||
amount *= 0.5f;
|
||||
}
|
||||
|
||||
+11
-26
@@ -38,7 +38,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
public void Write(IWriteMessage msg, Client recipient)
|
||||
{
|
||||
serializable.ServerWrite(msg, recipient, Data);
|
||||
serializable.ServerEventWrite(msg, recipient, Data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace Barotrauma.Networking
|
||||
lastWarningTime = -10.0;
|
||||
}
|
||||
|
||||
public void CreateEvent(IServerSerializable entity, object[] extraData = null)
|
||||
public void CreateEvent(IServerSerializable entity, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
if (!ValidateEntity(entity)) { return; }
|
||||
|
||||
@@ -179,7 +179,7 @@ namespace Barotrauma.Networking
|
||||
catch (Exception e)
|
||||
{
|
||||
string entityName = bufferedEvent.TargetEntity == null ? "null" : bufferedEvent.TargetEntity.ToString();
|
||||
if (GameSettings.VerboseLogging)
|
||||
if (GameSettings.CurrentConfig.VerboseLogging)
|
||||
{
|
||||
string errorMsg = "Failed to read server event for entity \"" + entityName + "\"!";
|
||||
GameServer.Log(errorMsg + "\n" + e.StackTrace.CleanupStackTrace(), ServerLog.MessageType.Error);
|
||||
@@ -291,12 +291,6 @@ namespace Barotrauma.Networking
|
||||
bufferedEvents.Add(bufferedEvent);
|
||||
}
|
||||
|
||||
public void RefreshEntityIDs()
|
||||
{
|
||||
events.ForEach(e => e.RefreshEntityID());
|
||||
uniqueEvents.ForEach(e => e.RefreshEntityID());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes all the events that the client hasn't received yet into the outgoing message
|
||||
/// </summary>
|
||||
@@ -310,15 +304,7 @@ namespace Barotrauma.Networking
|
||||
/// </summary>
|
||||
public void Write(Client client, IWriteMessage msg, out List<NetEntityEvent> sentEvents)
|
||||
{
|
||||
List<NetEntityEvent> eventsToSync = null;
|
||||
if (client.NeedsMidRoundSync)
|
||||
{
|
||||
eventsToSync = GetEventsToSync(client);
|
||||
}
|
||||
else
|
||||
{
|
||||
eventsToSync = GetEventsToSync(client);
|
||||
}
|
||||
List<NetEntityEvent> eventsToSync = GetEventsToSync(client);
|
||||
|
||||
if (eventsToSync.Count == 0)
|
||||
{
|
||||
@@ -347,7 +333,7 @@ namespace Barotrauma.Networking
|
||||
count++;
|
||||
if (count > 3) { break; }
|
||||
}
|
||||
if (GameSettings.VerboseLogging)
|
||||
if (GameSettings.CurrentConfig.VerboseLogging)
|
||||
{
|
||||
GameServer.Log(warningMsg, ServerLog.MessageType.Error);
|
||||
}
|
||||
@@ -460,6 +446,7 @@ namespace Barotrauma.Networking
|
||||
/// </summary>
|
||||
public void Read(IReadMessage msg, Client sender = null)
|
||||
{
|
||||
msg.ReadPadBits();
|
||||
UInt16 firstEventID = msg.ReadUInt16();
|
||||
int eventCount = msg.ReadByte();
|
||||
|
||||
@@ -470,7 +457,6 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (entityID == Entity.NullEntityID)
|
||||
{
|
||||
msg.ReadPadBits();
|
||||
if (thisEventID == (UInt16)(sender.LastSentEntityEventID + 1)) sender.LastSentEntityEventID++;
|
||||
continue;
|
||||
}
|
||||
@@ -482,7 +468,7 @@ namespace Barotrauma.Networking
|
||||
//skip the event if we've already received it
|
||||
if (thisEventID != (UInt16)(sender.LastSentEntityEventID + 1))
|
||||
{
|
||||
if (GameSettings.VerboseLogging)
|
||||
if (GameSettings.CurrentConfig.VerboseLogging)
|
||||
{
|
||||
DebugConsole.NewMessage("Received msg " + thisEventID + ", expecting " + sender.LastSentEntityEventID, Color.Red);
|
||||
}
|
||||
@@ -490,10 +476,10 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else if (entity == null)
|
||||
{
|
||||
//entity not found -> consider the even read and skip over it
|
||||
//entity not found -> consider the event read and skip over it
|
||||
//(can happen, for example, when a client uses a medical item repeatedly
|
||||
//and creates an event for it before receiving the event about it being removed)
|
||||
if (GameSettings.VerboseLogging)
|
||||
if (GameSettings.CurrentConfig.VerboseLogging)
|
||||
{
|
||||
DebugConsole.NewMessage(
|
||||
"Received msg " + thisEventID + ", entity " + entityID + " not found",
|
||||
@@ -504,7 +490,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GameSettings.VerboseLogging)
|
||||
if (GameSettings.CurrentConfig.VerboseLogging)
|
||||
{
|
||||
DebugConsole.NewMessage("Received msg " + thisEventID, Microsoft.Xna.Framework.Color.Green);
|
||||
}
|
||||
@@ -519,7 +505,6 @@ namespace Barotrauma.Networking
|
||||
|
||||
sender.LastSentEntityEventID++;
|
||||
}
|
||||
msg.ReadPadBits();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,7 +521,7 @@ namespace Barotrauma.Networking
|
||||
var clientEntity = entity as IClientSerializable;
|
||||
if (clientEntity == null) return;
|
||||
|
||||
clientEntity.ServerRead(ClientNetObject.ENTITY_STATE, buffer, sender);
|
||||
clientEntity.ServerEventRead(buffer, sender);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
|
||||
+4
-4
@@ -133,7 +133,7 @@ namespace Barotrauma.Networking
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
#else
|
||||
if (GameSettings.VerboseLogging) { DebugConsole.ThrowError(errorMsg); }
|
||||
if (GameSettings.CurrentConfig.VerboseLogging) { DebugConsole.ThrowError(errorMsg); }
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -339,7 +339,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public override void Send(IWriteMessage msg, NetworkConnection conn, DeliveryMethod deliveryMethod)
|
||||
public override void Send(IWriteMessage msg, NetworkConnection conn, DeliveryMethod deliveryMethod, bool compressPastThreshold = true)
|
||||
{
|
||||
if (netServer == null) { return; }
|
||||
|
||||
@@ -366,7 +366,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
NetOutgoingMessage lidgrenMsg = netServer.CreateMessage();
|
||||
byte[] msgData = new byte[msg.LengthBytes];
|
||||
msg.PrepareForSending(ref msgData, out bool isCompressed, out int length);
|
||||
msg.PrepareForSending(ref msgData, compressPastThreshold, out bool isCompressed, out int length);
|
||||
lidgrenMsg.Write((byte)(isCompressed ? PacketHeader.IsCompressed : PacketHeader.None));
|
||||
lidgrenMsg.Write((UInt16)length);
|
||||
lidgrenMsg.Write(msgData, 0, length);
|
||||
@@ -435,7 +435,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (pendingClient.SteamID == null)
|
||||
{
|
||||
bool requireSteamAuth = GameMain.Config.RequireSteamAuthentication;
|
||||
bool requireSteamAuth = GameSettings.CurrentConfig.RequireSteamAuthentication;
|
||||
#if DEBUG
|
||||
requireSteamAuth = false;
|
||||
#endif
|
||||
|
||||
+6
-4
@@ -123,7 +123,7 @@ namespace Barotrauma.Networking
|
||||
return;
|
||||
}
|
||||
|
||||
string language = inc.ReadString();
|
||||
LanguageIdentifier language = inc.ReadIdentifier().ToLanguageIdentifier();
|
||||
pendingClient.Connection.Language = language;
|
||||
|
||||
Client nameTaken = GameMain.Server.ConnectedClients.Find(c => Homoglyphs.Compare(c.Name.ToLower(), name.ToLower()));
|
||||
@@ -253,12 +253,14 @@ namespace Barotrauma.Networking
|
||||
case ConnectionInitialization.ContentPackageOrder:
|
||||
outMsg.Write(GameMain.Server.ServerName);
|
||||
|
||||
var mpContentPackages = GameMain.Config.AllEnabledPackages.Where(cp => cp.HasMultiplayerIncompatibleContent).ToList();
|
||||
var mpContentPackages = ContentPackageManager.EnabledPackages.All.Where(cp => cp.HasMultiplayerSyncedContent).ToList();
|
||||
outMsg.WriteVariableUInt32((UInt32)mpContentPackages.Count);
|
||||
for (int i = 0; i < mpContentPackages.Count; i++)
|
||||
{
|
||||
outMsg.Write(mpContentPackages[i].Name);
|
||||
outMsg.Write(mpContentPackages[i].MD5hash.Hash);
|
||||
byte[] hashBytes = mpContentPackages[i].Hash.ByteRepresentation;
|
||||
outMsg.WriteVariableUInt32((UInt32)hashBytes.Length);
|
||||
outMsg.Write(hashBytes, 0, hashBytes.Length);
|
||||
outMsg.Write(mpContentPackages[i].SteamWorkshopId);
|
||||
UInt32 installTimeDiffSeconds = (UInt32)((mpContentPackages[i].InstallTime ?? DateTime.UtcNow) - DateTime.UtcNow).TotalSeconds;
|
||||
outMsg.Write(installTimeDiffSeconds);
|
||||
@@ -301,7 +303,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void Send(IWriteMessage msg, NetworkConnection conn, DeliveryMethod deliveryMethod);
|
||||
public abstract void Send(IWriteMessage msg, NetworkConnection conn, DeliveryMethod deliveryMethod, bool compressPastThreshold = true);
|
||||
public abstract void Disconnect(NetworkConnection conn, string msg = null);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -106,7 +106,7 @@ namespace Barotrauma.Networking
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
#else
|
||||
if (GameSettings.VerboseLogging) { DebugConsole.ThrowError(errorMsg); }
|
||||
if (GameSettings.CurrentConfig.VerboseLogging) { DebugConsole.ThrowError(errorMsg); }
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -223,7 +223,7 @@ namespace Barotrauma.Networking
|
||||
string ownerName = inc.ReadString();
|
||||
OwnerConnection = new SteamP2PConnection(ownerName, OwnerSteamID)
|
||||
{
|
||||
Language = GameMain.Config.Language
|
||||
Language = GameSettings.CurrentConfig.Language
|
||||
};
|
||||
OwnerConnection.SetOwnerSteamIDIfUnknown(OwnerSteamID);
|
||||
|
||||
@@ -250,7 +250,7 @@ namespace Barotrauma.Networking
|
||||
throw new InvalidOperationException("Called InitializeSteamServerCallbacks on SteamP2PServerPeer!");
|
||||
}
|
||||
|
||||
public override void Send(IWriteMessage msg, NetworkConnection conn, DeliveryMethod deliveryMethod)
|
||||
public override void Send(IWriteMessage msg, NetworkConnection conn, DeliveryMethod deliveryMethod, bool compressPastThreshold = true)
|
||||
{
|
||||
if (!started) { return; }
|
||||
|
||||
@@ -263,7 +263,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
IWriteMessage msgToSend = new WriteOnlyMessage();
|
||||
byte[] msgData = new byte[16];
|
||||
msg.PrepareForSending(ref msgData, out bool isCompressed, out int length);
|
||||
msg.PrepareForSending(ref msgData, compressPastThreshold, out bool isCompressed, out int length);
|
||||
msgToSend.Write(conn.SteamID);
|
||||
msgToSend.Write((byte)deliveryMethod);
|
||||
msgToSend.Write((byte)((isCompressed ? PacketHeader.IsCompressed : PacketHeader.None) | PacketHeader.IsServerMessage));
|
||||
|
||||
@@ -248,7 +248,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
var shuttleGaps = Gap.GapList.FindAll(g => g.Submarine == RespawnShuttle && g.ConnectedWall != null);
|
||||
shuttleGaps.ForEach(g => Spawner.AddToRemoveQueue(g));
|
||||
shuttleGaps.ForEach(g => Spawner.AddEntityToRemoveQueue(g));
|
||||
|
||||
var dockingPorts = Item.ItemList.FindAll(i => i.Submarine == RespawnShuttle && i.GetComponent<DockingPort>() != null);
|
||||
dockingPorts.ForEach(d => d.GetComponent<DockingPort>().Undock());
|
||||
@@ -376,7 +376,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (campaign?.GetClientCharacterData(c) == null || c.CharacterInfo.Job == null)
|
||||
{
|
||||
c.CharacterInfo.Job = new Job(c.AssignedJob.First, Rand.RandSync.Unsynced, c.AssignedJob.Second);
|
||||
c.CharacterInfo.Job = new Job(c.AssignedJob.Prefab, Rand.RandSync.Unsynced, c.AssignedJob.Variant);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,17 +390,17 @@ namespace Barotrauma.Networking
|
||||
if ((shuttlePos != null && Level.Loaded.GetRealWorldDepth(shuttlePos.Value.Y) > Level.DefaultRealWorldCrushDepth) ||
|
||||
Level.Loaded.GetRealWorldDepth(Submarine.MainSub.WorldPosition.Y) > Level.DefaultRealWorldCrushDepth)
|
||||
{
|
||||
divingSuitPrefab = ItemPrefab.Prefabs.FirstOrDefault(it => it.Tags.Any(t => t.Equals("respawnsuitdeep", StringComparison.OrdinalIgnoreCase)));
|
||||
divingSuitPrefab = ItemPrefab.Prefabs.FirstOrDefault(it => it.Tags.Any(t => t == "respawnsuitdeep"));
|
||||
}
|
||||
if (divingSuitPrefab == null)
|
||||
{
|
||||
divingSuitPrefab =
|
||||
ItemPrefab.Prefabs.FirstOrDefault(it => it.Tags.Any(t => t.Equals("respawnsuit", StringComparison.OrdinalIgnoreCase))) ??
|
||||
ItemPrefab.Find(null, "divingsuit");
|
||||
ItemPrefab.Prefabs.FirstOrDefault(it => it.Tags.Any(t => t == "respawnsuit")) ??
|
||||
ItemPrefab.Find(null, "divingsuit".ToIdentifier());
|
||||
}
|
||||
ItemPrefab oxyPrefab = ItemPrefab.Find(null, "oxygentank");
|
||||
ItemPrefab scooterPrefab = ItemPrefab.Find(null, "underwaterscooter");
|
||||
ItemPrefab batteryPrefab = ItemPrefab.Find(null, "batterycell");
|
||||
ItemPrefab oxyPrefab = ItemPrefab.Find(null, "oxygentank".ToIdentifier());
|
||||
ItemPrefab scooterPrefab = ItemPrefab.Find(null, "underwaterscooter".ToIdentifier());
|
||||
ItemPrefab batteryPrefab = ItemPrefab.Find(null, "batterycell".ToIdentifier());
|
||||
|
||||
var cargoSp = WayPoint.WayPointList.Find(wp => wp.Submarine == respawnSub && wp.SpawnType == SpawnType.Cargo);
|
||||
|
||||
@@ -468,11 +468,11 @@ namespace Barotrauma.Networking
|
||||
if (divingSuitPrefab != null && oxyPrefab != null)
|
||||
{
|
||||
var divingSuit = new Item(divingSuitPrefab, pos, respawnSub);
|
||||
Spawner.CreateNetworkEvent(divingSuit, false);
|
||||
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(divingSuit));
|
||||
respawnItems.Add(divingSuit);
|
||||
|
||||
var oxyTank = new Item(oxyPrefab, pos, respawnSub);
|
||||
Spawner.CreateNetworkEvent(oxyTank, false);
|
||||
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(oxyTank));
|
||||
divingSuit.Combine(oxyTank, user: null);
|
||||
respawnItems.Add(oxyTank);
|
||||
}
|
||||
@@ -480,10 +480,10 @@ namespace Barotrauma.Networking
|
||||
if (scooterPrefab != null && batteryPrefab != null)
|
||||
{
|
||||
var scooter = new Item(scooterPrefab, pos, respawnSub);
|
||||
Spawner.CreateNetworkEvent(scooter, false);
|
||||
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(scooter));
|
||||
|
||||
var battery = new Item(batteryPrefab, pos, respawnSub);
|
||||
Spawner.CreateNetworkEvent(battery, false);
|
||||
Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(battery));
|
||||
|
||||
scooter.Combine(battery, user: null);
|
||||
respawnItems.Add(scooter);
|
||||
@@ -543,13 +543,13 @@ namespace Barotrauma.Networking
|
||||
if (characterInfo?.Job == null) { return; }
|
||||
foreach (Skill skill in characterInfo.Job.Skills)
|
||||
{
|
||||
var skillPrefab = characterInfo.Job.Prefab.Skills.Find(s => skill.Identifier.Equals(s.Identifier, StringComparison.OrdinalIgnoreCase));
|
||||
var skillPrefab = characterInfo.Job.Prefab.Skills.Find(s => skill.Identifier == s.Identifier);
|
||||
if (skillPrefab == null) { continue; }
|
||||
skill.Level = MathHelper.Lerp(skill.Level, skillPrefab.LevelRange.Start, SkillReductionOnCampaignMidroundRespawn);
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
|
||||
{
|
||||
msg.WriteRangedInteger((int)CurrentState, 0, Enum.GetNames(typeof(State)).Length);
|
||||
|
||||
|
||||
@@ -268,7 +268,7 @@ namespace Barotrauma.Networking
|
||||
doc.Root.SetAttributeValue("HiddenSubs", string.Join(",", HiddenSubs));
|
||||
|
||||
doc.Root.SetAttributeValue("AllowedRandomMissionTypes", string.Join(",", AllowedRandomMissionTypes));
|
||||
doc.Root.SetAttributeValue("AllowedClientNameChars", string.Join(",", AllowedClientNameChars.Select(c => c.First + "-" + c.Second)));
|
||||
doc.Root.SetAttributeValue("AllowedClientNameChars", string.Join(",", AllowedClientNameChars.Select(c => $"{c.Start}-{c.End}")));
|
||||
|
||||
SerializableProperty.SerializeProperties(this, doc.Root, true);
|
||||
|
||||
@@ -307,13 +307,13 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (string.IsNullOrEmpty(doc.Root.GetAttributeString("losmode", "")))
|
||||
{
|
||||
LosMode = GameMain.Config.LosMode;
|
||||
LosMode = GameSettings.CurrentConfig.Graphics.LosMode;
|
||||
}
|
||||
|
||||
AutoRestart = doc.Root.GetAttributeBool("autorestart", false);
|
||||
|
||||
Voting.AllowSubVoting = SubSelectionMode == SelectionMode.Vote;
|
||||
Voting.AllowModeVoting = ModeSelectionMode == SelectionMode.Vote;
|
||||
AllowSubVoting = SubSelectionMode == SelectionMode.Vote;
|
||||
AllowModeVoting = ModeSelectionMode == SelectionMode.Vote;
|
||||
|
||||
selectedLevelDifficulty = doc.Root.GetAttributeFloat("LevelDifficulty", 20.0f);
|
||||
GameMain.NetLobbyScreen.SetLevelDifficulty(selectedLevelDifficulty);
|
||||
@@ -321,11 +321,16 @@ namespace Barotrauma.Networking
|
||||
GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled);
|
||||
|
||||
HiddenSubs.UnionWith(doc.Root.GetAttributeStringArray("HiddenSubs", Array.Empty<string>()));
|
||||
if (HiddenSubs.Any())
|
||||
{
|
||||
UpdateFlag(NetFlags.HiddenSubs);
|
||||
}
|
||||
|
||||
SelectedSubmarine = SelectNonHiddenSubmarine(SelectedSubmarine);
|
||||
|
||||
string[] defaultAllowedClientNameChars =
|
||||
new string[] {
|
||||
new string[]
|
||||
{
|
||||
"32-33",
|
||||
"38-46",
|
||||
"48-57",
|
||||
@@ -370,7 +375,12 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
if (min > -1 && max > -1) { AllowedClientNameChars.Add(new Pair<int, int>(min, max)); }
|
||||
if (min > max)
|
||||
{
|
||||
//swap min and max
|
||||
(min, max) = (max, min);
|
||||
}
|
||||
if (min > -1 && max > -1) { AllowedClientNameChars.Add(new Range<int>(min, max)); }
|
||||
}
|
||||
|
||||
AllowedRandomMissionTypes = new List<MissionType>();
|
||||
@@ -399,12 +409,7 @@ namespace Barotrauma.Networking
|
||||
GameMain.NetLobbyScreen.SetBotSpawnMode(BotSpawnMode);
|
||||
GameMain.NetLobbyScreen.SetBotCount(BotCount);
|
||||
|
||||
List<string> monsterNames = CharacterPrefab.Prefabs.Select(p => p.Identifier).ToList();
|
||||
MonsterEnabled = new Dictionary<string, bool>();
|
||||
foreach (string s in monsterNames)
|
||||
{
|
||||
if (!MonsterEnabled.ContainsKey(s)) MonsterEnabled.Add(s, true);
|
||||
}
|
||||
MonsterEnabled ??= CharacterPrefab.Prefabs.Select(p => (p.Identifier, true)).ToDictionary();
|
||||
}
|
||||
|
||||
public string SelectNonHiddenSubmarine(string current = null)
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma.Steam
|
||||
{
|
||||
partial class SteamManager
|
||||
{
|
||||
#region Server
|
||||
|
||||
private static void InitializeProjectSpecific() { isInitialized = true; }
|
||||
|
||||
public static bool CreateServer(Networking.GameServer server, bool isPublic)
|
||||
{
|
||||
isInitialized = true;
|
||||
|
||||
Steamworks.SteamServerInit options = new Steamworks.SteamServerInit("Barotrauma", "Barotrauma")
|
||||
{
|
||||
GamePort = (ushort)server.Port,
|
||||
QueryPort = isPublic ? (ushort)server.QueryPort : (ushort)0,
|
||||
Mode = isPublic ? Steamworks.InitServerMode.Authentication : Steamworks.InitServerMode.NoAuthentication,
|
||||
IpAddress = server.ServerSettings.ListenIPAddress
|
||||
};
|
||||
//options.QueryShareGamePort();
|
||||
|
||||
Steamworks.SteamServer.Init(AppID, options, false);
|
||||
if (!Steamworks.SteamServer.IsValid)
|
||||
{
|
||||
Steamworks.SteamServer.Shutdown();
|
||||
DebugConsole.ThrowError("Initializing Steam server failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
RefreshServerDetails(server);
|
||||
|
||||
server.ServerPeer.InitializeSteamServerCallbacks();
|
||||
|
||||
Steamworks.SteamServer.LogOnAnonymous();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool RefreshServerDetails(Networking.GameServer server)
|
||||
{
|
||||
if (!isInitialized || !Steamworks.SteamServer.IsValid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var contentPackages = GameMain.Config.AllEnabledPackages.Where(cp => cp.HasMultiplayerIncompatibleContent);
|
||||
|
||||
// These server state variables may be changed at any time. Note that there is no longer a mechanism
|
||||
// to send the player count. The player count is maintained by steam and you should use the player
|
||||
// creation/authentication functions to maintain your player count.
|
||||
Steamworks.SteamServer.ServerName = server.ServerName;
|
||||
Steamworks.SteamServer.MaxPlayers = server.ServerSettings.MaxPlayers;
|
||||
Steamworks.SteamServer.Passworded = server.ServerSettings.HasPassword;
|
||||
Steamworks.SteamServer.MapName = GameMain.NetLobbyScreen?.SelectedSub?.DisplayName ?? "";
|
||||
Steamworks.SteamServer.SetKey("haspassword", server.ServerSettings.HasPassword.ToString());
|
||||
Steamworks.SteamServer.SetKey("message", GameMain.Server.ServerSettings.ServerMessageText);
|
||||
Steamworks.SteamServer.SetKey("version", GameMain.Version.ToString());
|
||||
Steamworks.SteamServer.SetKey("playercount", GameMain.Server.ConnectedClients.Count.ToString());
|
||||
Steamworks.SteamServer.SetKey("contentpackage", string.Join(",", contentPackages.Select(cp => cp.Name)));
|
||||
Steamworks.SteamServer.SetKey("contentpackagehash", string.Join(",", contentPackages.Select(cp => cp.MD5hash.Hash)));
|
||||
Steamworks.SteamServer.SetKey("contentpackageid", string.Join(",", contentPackages.Select(cp => cp.SteamWorkshopId)));
|
||||
Steamworks.SteamServer.SetKey("usingwhitelist", (server.ServerSettings.Whitelist != null && server.ServerSettings.Whitelist.Enabled).ToString());
|
||||
Steamworks.SteamServer.SetKey("modeselectionmode", server.ServerSettings.ModeSelectionMode.ToString());
|
||||
Steamworks.SteamServer.SetKey("subselectionmode", server.ServerSettings.SubSelectionMode.ToString());
|
||||
Steamworks.SteamServer.SetKey("voicechatenabled", server.ServerSettings.VoiceChatEnabled.ToString());
|
||||
Steamworks.SteamServer.SetKey("allowspectating", server.ServerSettings.AllowSpectating.ToString());
|
||||
Steamworks.SteamServer.SetKey("allowrespawn", server.ServerSettings.AllowRespawn.ToString());
|
||||
Steamworks.SteamServer.SetKey("traitors", server.ServerSettings.TraitorsEnabled.ToString());
|
||||
Steamworks.SteamServer.SetKey("gamestarted", server.GameStarted.ToString());
|
||||
Steamworks.SteamServer.SetKey("gamemode", server.ServerSettings.GameModeIdentifier);
|
||||
Steamworks.SteamServer.SetKey("playstyle", server.ServerSettings.PlayStyle.ToString());
|
||||
|
||||
Steamworks.SteamServer.DedicatedServer = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Steamworks.BeginAuthResult StartAuthSession(byte[] authTicketData, ulong clientSteamID)
|
||||
{
|
||||
if (!isInitialized || !Steamworks.SteamServer.IsValid) return Steamworks.BeginAuthResult.ServerNotConnectedToSteam;
|
||||
|
||||
DebugConsole.Log("SteamManager authenticating Steam client " + clientSteamID);
|
||||
Steamworks.BeginAuthResult startResult = Steamworks.SteamServer.BeginAuthSession(authTicketData, clientSteamID);
|
||||
if (startResult != Steamworks.BeginAuthResult.OK)
|
||||
{
|
||||
DebugConsole.Log("Authentication failed: failed to start auth session (" + startResult.ToString() + ")");
|
||||
}
|
||||
|
||||
return startResult;
|
||||
}
|
||||
|
||||
public static void StopAuthSession(ulong clientSteamID)
|
||||
{
|
||||
if (!isInitialized || !Steamworks.SteamServer.IsValid) return;
|
||||
|
||||
DebugConsole.Log("SteamManager ending auth session with Steam client " + clientSteamID);
|
||||
Steamworks.SteamServer.EndSession(clientSteamID);
|
||||
}
|
||||
|
||||
public static bool CloseServer()
|
||||
{
|
||||
if (!isInitialized || !Steamworks.SteamServer.IsValid) return false;
|
||||
|
||||
Steamworks.SteamServer.Shutdown();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -7,59 +7,168 @@ namespace Barotrauma
|
||||
{
|
||||
partial class Voting
|
||||
{
|
||||
public bool AllowSubVoting
|
||||
public interface IVote
|
||||
{
|
||||
get { return allowSubVoting; }
|
||||
set { allowSubVoting = value; }
|
||||
}
|
||||
public bool AllowModeVoting
|
||||
{
|
||||
get { return allowModeVoting; }
|
||||
set { allowModeVoting = value; }
|
||||
}
|
||||
public Client VoteStarter { get; }
|
||||
public VoteType VoteType { get; }
|
||||
public float Timer { get; set; }
|
||||
|
||||
public struct SubmarineVote
|
||||
public VoteState State { get; set; }
|
||||
|
||||
public void Finish(Voting voting, bool passed);
|
||||
}
|
||||
|
||||
public class SubmarineVote : IVote
|
||||
{
|
||||
public Client VoteStarter;
|
||||
public Client VoteStarter { get; }
|
||||
public VoteType VoteType { get; }
|
||||
public float Timer { get; set; }
|
||||
|
||||
public VoteState State { get; set; }
|
||||
|
||||
public SubmarineInfo Sub;
|
||||
public VoteType VoteType;
|
||||
public float Timer;
|
||||
public int DeliveryFee;
|
||||
public VoteState State;
|
||||
|
||||
public SubmarineVote(Client starter, SubmarineInfo subInfo, int deliveryFee, VoteType voteType)
|
||||
{
|
||||
Sub = subInfo;
|
||||
DeliveryFee = deliveryFee;
|
||||
VoteType = voteType;
|
||||
State = VoteState.Started;
|
||||
VoteStarter = starter;
|
||||
}
|
||||
|
||||
public void Finish(Voting voting, bool passed)
|
||||
{
|
||||
if (passed)
|
||||
{
|
||||
GameMain.Server?.SwitchSubmarine();
|
||||
}
|
||||
voting.StopSubmarineVote(passed);
|
||||
}
|
||||
}
|
||||
|
||||
public static SubmarineVote SubVote;
|
||||
public static IVote ActiveVote;
|
||||
|
||||
public class TransferVote : IVote
|
||||
{
|
||||
public Client VoteStarter { get; }
|
||||
public VoteType VoteType { get; }
|
||||
public float Timer { get; set; }
|
||||
|
||||
public VoteState State { get; set; }
|
||||
|
||||
//null = bank
|
||||
public readonly Client From, To;
|
||||
public readonly int TransferAmount;
|
||||
|
||||
public TransferVote(Client starter, Client from, int transferAmount, Client to)
|
||||
{
|
||||
VoteStarter = starter;
|
||||
From = from;
|
||||
To = to;
|
||||
TransferAmount = transferAmount;
|
||||
State = VoteState.Started;
|
||||
VoteType = VoteType.TransferMoney;
|
||||
}
|
||||
|
||||
public void Finish(Voting voting, bool passed)
|
||||
{
|
||||
if (passed)
|
||||
{
|
||||
Wallet fromWallet = From == null ? (GameMain.GameSession.GameMode as MultiPlayerCampaign)?.Bank : From.Character?.Wallet;
|
||||
if (fromWallet.TryDeduct(TransferAmount))
|
||||
{
|
||||
Wallet toWallet = To == null ? (GameMain.GameSession.GameMode as MultiPlayerCampaign)?.Bank : To.Character?.Wallet;
|
||||
toWallet.Give(TransferAmount);
|
||||
}
|
||||
}
|
||||
voting.StopMoneyTransferVote(passed);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Queue<IVote> pendingVotes = new Queue<IVote>();
|
||||
|
||||
private void StartSubmarineVote(SubmarineInfo subInfo, VoteType voteType, Client sender)
|
||||
{
|
||||
SubVote.Sub = subInfo;
|
||||
SubVote.DeliveryFee = voteType == VoteType.SwitchSub ? GameMain.GameSession.Map.DistanceToClosestLocationWithOutpost(GameMain.GameSession.Map.CurrentLocation, out Location endLocation) : 0;
|
||||
SubVote.VoteType = voteType;
|
||||
SubVote.State = VoteState.Started;
|
||||
SubVote.VoteStarter = sender;
|
||||
VoteRunning = true;
|
||||
sender.SetVote(voteType, 2);
|
||||
if (ActiveVote == null)
|
||||
{
|
||||
sender.SetVote(voteType, 2);
|
||||
}
|
||||
var subVote = new SubmarineVote(
|
||||
sender,
|
||||
subInfo,
|
||||
voteType == VoteType.SwitchSub ? GameMain.GameSession.Map.DistanceToClosestLocationWithOutpost(GameMain.GameSession.Map.CurrentLocation, out Location endLocation) : 0,
|
||||
voteType);
|
||||
StartOrEnqueueVote(subVote);
|
||||
GameMain.Server.UpdateVoteStatus(checkActiveVote: false);
|
||||
}
|
||||
|
||||
public void StopSubmarineVote(bool passed)
|
||||
{
|
||||
VoteRunning = false;
|
||||
SubVote.State = passed ? VoteState.Passed : VoteState.Failed;
|
||||
if (!(ActiveVote is SubmarineVote)) { return; }
|
||||
StopActiveVote(passed);
|
||||
}
|
||||
|
||||
GameMain.Server.UpdateVoteStatus();
|
||||
public void StopMoneyTransferVote(bool passed)
|
||||
{
|
||||
if (!(ActiveVote is TransferVote)) { return; }
|
||||
StopActiveVote(passed);
|
||||
}
|
||||
|
||||
public void StopActiveVote(bool passed)
|
||||
{
|
||||
ActiveVote.State = passed ? VoteState.Passed : VoteState.Failed;
|
||||
GameMain.Server.UpdateVoteStatus(checkActiveVote: false);
|
||||
|
||||
GameMain.NetworkMember.SubmarineVoteYesCount = GameMain.NetworkMember.SubmarineVoteNoCount = GameMain.NetworkMember.SubmarineVoteMax = 0;
|
||||
for (int i = 0; i < GameMain.NetworkMember.ConnectedClients.Count; i++)
|
||||
{
|
||||
GameMain.NetworkMember.ConnectedClients[i].SetVote(SubVote.VoteType, 0);
|
||||
GameMain.NetworkMember.ConnectedClients[i].SetVote(ActiveVote.VoteType, 0);
|
||||
}
|
||||
|
||||
SubVote.Sub = null;
|
||||
SubVote.DeliveryFee = 0;
|
||||
SubVote.VoteType = VoteType.Unknown;
|
||||
SubVote.Timer = 0.0f;
|
||||
SubVote.State = VoteState.None;
|
||||
SubVote.VoteStarter = null;
|
||||
ActiveVote = null;
|
||||
if (pendingVotes.Any())
|
||||
{
|
||||
ActiveVote = pendingVotes.Dequeue();
|
||||
ActiveVote.VoteStarter?.SetVote(ActiveVote.VoteType, 2);
|
||||
}
|
||||
}
|
||||
|
||||
public void StartTransferVote(Client starter, Client from, int transferAmount, Client to)
|
||||
{
|
||||
if (ActiveVote == null)
|
||||
{
|
||||
starter.SetVote(VoteType.TransferMoney, 2);
|
||||
}
|
||||
StartOrEnqueueVote(new TransferVote(starter, from, transferAmount, to));
|
||||
GameMain.Server.UpdateVoteStatus(checkActiveVote: false);
|
||||
}
|
||||
|
||||
private void StartOrEnqueueVote(IVote vote)
|
||||
{
|
||||
if (ActiveVote == null)
|
||||
{
|
||||
ActiveVote = vote;
|
||||
}
|
||||
else
|
||||
{
|
||||
pendingVotes.Enqueue(vote);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
if (ActiveVote == null) { return; }
|
||||
|
||||
ActiveVote.Timer += deltaTime;
|
||||
|
||||
if (ActiveVote.Timer >= GameMain.NetworkMember.ServerSettings.VoteTimeout)
|
||||
{
|
||||
// Do not take unanswered into account for total
|
||||
int yes = GameMain.Server.ConnectedClients.Count(c => c.InGame && c.GetVote<int>(ActiveVote.VoteType) == 2);
|
||||
int no = GameMain.Server.ConnectedClients.Count(c => c.InGame && c.GetVote<int>(ActiveVote.VoteType) == 1);
|
||||
ActiveVote.Finish(this, passed: yes / (float)(yes + no) >= GameMain.NetworkMember.ServerSettings.VoteRequiredRatio);
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerRead(IReadMessage inc, Client sender)
|
||||
@@ -85,7 +194,7 @@ namespace Barotrauma
|
||||
string hash = equalityCheckVal > 0 ? string.Empty : inc.ReadString();
|
||||
SubmarineInfo sub = equalityCheckVal > 0 ?
|
||||
SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Type == SubmarineType.Player && s.EqualityCheckVal == equalityCheckVal) :
|
||||
SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Type == SubmarineType.Player && s.MD5Hash.Hash == hash);
|
||||
SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Type == SubmarineType.Player && s.MD5Hash.StringRepresentation == hash);
|
||||
sender.SetVote(voteType, sub);
|
||||
break;
|
||||
case VoteType.Mode:
|
||||
@@ -97,10 +206,6 @@ namespace Barotrauma
|
||||
case VoteType.EndRound:
|
||||
if (!sender.HasSpawned) { return; }
|
||||
sender.SetVote(voteType, inc.ReadBoolean());
|
||||
|
||||
GameMain.NetworkMember.EndVoteCount = GameMain.Server.ConnectedClients.Count(c => c.HasSpawned && c.GetVote<bool>(VoteType.EndRound));
|
||||
GameMain.NetworkMember.EndVoteMax = GameMain.Server.ConnectedClients.Count(c => c.HasSpawned);
|
||||
|
||||
break;
|
||||
case VoteType.Kick:
|
||||
byte kickedClientID = inc.ReadByte();
|
||||
@@ -126,24 +231,34 @@ namespace Barotrauma
|
||||
case VoteType.PurchaseAndSwitchSub:
|
||||
case VoteType.PurchaseSub:
|
||||
case VoteType.SwitchSub:
|
||||
case VoteType.TransferMoney:
|
||||
bool startVote = inc.ReadBoolean();
|
||||
if (startVote)
|
||||
{
|
||||
string subName = inc.ReadString();
|
||||
SubmarineInfo subInfo = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == subName);
|
||||
if (GameMain.GameSession?.Campaign is MultiPlayerCampaign campaign && (campaign.CanPurchaseSub(subInfo) || GameMain.GameSession.IsSubmarineOwned(subInfo)))
|
||||
if (voteType == VoteType.TransferMoney)
|
||||
{
|
||||
StartSubmarineVote(subInfo, voteType, sender);
|
||||
int amount = inc.ReadInt32();
|
||||
int fromClientId = inc.ReadByte();
|
||||
int toClientId = inc.ReadByte();
|
||||
pendingVotes.Enqueue(new TransferVote(sender,
|
||||
GameMain.Server.ConnectedClients.Find(c => c.ID == fromClientId),
|
||||
amount,
|
||||
GameMain.Server.ConnectedClients.Find(c => c.ID == toClientId)));
|
||||
}
|
||||
else
|
||||
{
|
||||
string subName = inc.ReadString();
|
||||
SubmarineInfo subInfo = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == subName);
|
||||
if (GameMain.GameSession?.Campaign is MultiPlayerCampaign campaign && (campaign.CanPurchaseSub(subInfo, sender) || GameMain.GameSession.IsSubmarineOwned(subInfo)))
|
||||
{
|
||||
StartSubmarineVote(subInfo, voteType, sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sender.SetVote(voteType, (int)inc.ReadByte());
|
||||
}
|
||||
|
||||
GameMain.Server.SubmarineVoteYesCount = GameMain.Server.ConnectedClients.Count(c => c.GetVote<int>(SubVote.VoteType) == 2);
|
||||
GameMain.Server.SubmarineVoteNoCount = GameMain.Server.ConnectedClients.Count(c => c.GetVote<int>(SubVote.VoteType) == 1);
|
||||
GameMain.Server.SubmarineVoteMax = GameMain.Server.ConnectedClients.Count(c => c.InGame);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -154,10 +269,10 @@ namespace Barotrauma
|
||||
|
||||
public void ServerWrite(IWriteMessage msg)
|
||||
{
|
||||
if (GameMain.Server == null) return;
|
||||
if (GameMain.Server == null) { return; }
|
||||
|
||||
msg.Write(allowSubVoting);
|
||||
if (allowSubVoting)
|
||||
msg.Write(GameMain.Server.ServerSettings.AllowSubVoting);
|
||||
if (GameMain.Server.ServerSettings.AllowSubVoting)
|
||||
{
|
||||
IReadOnlyDictionary<SubmarineInfo, int> voteList = GetVoteCounts<SubmarineInfo>(VoteType.Sub, GameMain.Server.ConnectedClients);
|
||||
msg.Write((byte)voteList.Count);
|
||||
@@ -167,8 +282,8 @@ namespace Barotrauma
|
||||
msg.Write(vote.Key.Name);
|
||||
}
|
||||
}
|
||||
msg.Write(AllowModeVoting);
|
||||
if (allowModeVoting)
|
||||
msg.Write(GameMain.Server.ServerSettings.AllowModeVoting);
|
||||
if (GameMain.Server.ServerSettings.AllowModeVoting)
|
||||
{
|
||||
IReadOnlyDictionary<GameModePreset, int> voteList = GetVoteCounts<GameModePreset>(VoteType.Mode, GameMain.Server.ConnectedClients);
|
||||
msg.Write((byte)voteList.Count);
|
||||
@@ -178,60 +293,78 @@ namespace Barotrauma
|
||||
msg.Write(vote.Key.Identifier);
|
||||
}
|
||||
}
|
||||
msg.Write(AllowEndVoting);
|
||||
if (AllowEndVoting)
|
||||
msg.Write(GameMain.Server.ServerSettings.AllowEndVoting);
|
||||
if (GameMain.Server.ServerSettings.AllowEndVoting)
|
||||
{
|
||||
msg.Write((byte)GameMain.Server.ConnectedClients.Count(c => c.HasSpawned && c.GetVote<bool>(VoteType.EndRound)));
|
||||
msg.Write((byte)GameMain.Server.ConnectedClients.Count(c => c.HasSpawned));
|
||||
}
|
||||
|
||||
msg.Write(AllowVoteKick);
|
||||
msg.Write(GameMain.Server.ServerSettings.AllowVoteKick);
|
||||
|
||||
msg.Write((byte)SubVote.State);
|
||||
if (SubVote.State != VoteState.None)
|
||||
msg.Write((byte)(ActiveVote?.State ?? VoteState.None));
|
||||
if (ActiveVote != null)
|
||||
{
|
||||
msg.Write((byte)SubVote.VoteType);
|
||||
|
||||
if (SubVote.VoteType != VoteType.Unknown)
|
||||
{
|
||||
var yesClients = GameMain.Server.ConnectedClients.FindAll(c => c.GetVote<int>(SubVote.VoteType) == 2);
|
||||
msg.Write((byte)ActiveVote.VoteType);
|
||||
if (ActiveVote.State != VoteState.None && ActiveVote.VoteType != VoteType.Unknown)
|
||||
{
|
||||
var yesClients = GameMain.Server.ConnectedClients.FindAll(c => c.InGame && c.GetVote<int>(ActiveVote.VoteType) == 2);
|
||||
msg.Write((byte)yesClients.Count);
|
||||
foreach (Client c in yesClients)
|
||||
{
|
||||
msg.Write(c.ID);
|
||||
}
|
||||
|
||||
var noClients = GameMain.Server.ConnectedClients.FindAll(c => c.GetVote<int>(SubVote.VoteType) == 1);
|
||||
var noClients = GameMain.Server.ConnectedClients.FindAll(c => c.InGame && c.GetVote<int>(ActiveVote.VoteType) == 1);
|
||||
msg.Write((byte)noClients.Count);
|
||||
foreach (Client c in noClients)
|
||||
{
|
||||
msg.Write(c.ID);
|
||||
}
|
||||
|
||||
msg.Write((byte)GameMain.Server.SubmarineVoteMax);
|
||||
msg.Write((byte)GameMain.Server.ConnectedClients.Count(c => c.InGame));
|
||||
|
||||
switch (SubVote.State)
|
||||
switch (ActiveVote.State)
|
||||
{
|
||||
case VoteState.Started:
|
||||
msg.Write(SubVote.Sub.Name);
|
||||
msg.Write(SubVote.VoteStarter.ID);
|
||||
msg.Write((byte)GameMain.Server.ServerSettings.SubmarineVoteTimeout);
|
||||
msg.Write(ActiveVote.VoteStarter.ID);
|
||||
msg.Write((byte)GameMain.Server.ServerSettings.VoteTimeout);
|
||||
|
||||
switch (ActiveVote.VoteType)
|
||||
{
|
||||
case VoteType.PurchaseSub:
|
||||
case VoteType.PurchaseAndSwitchSub:
|
||||
case VoteType.SwitchSub:
|
||||
msg.Write((ActiveVote as SubmarineVote).Sub.Name);
|
||||
break;
|
||||
case VoteType.TransferMoney:
|
||||
var transferVote = (ActiveVote as TransferVote);
|
||||
msg.Write(transferVote.From?.ID ?? 0);
|
||||
msg.Write(transferVote.To?.ID ?? 0);
|
||||
msg.Write(transferVote.TransferAmount);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case VoteState.Running:
|
||||
// Nothing specific
|
||||
break;
|
||||
case VoteState.Passed:
|
||||
case VoteState.Failed:
|
||||
msg.Write(SubVote.State == VoteState.Passed);
|
||||
msg.Write(SubVote.Sub.Name);
|
||||
if (SubVote.State == VoteState.Passed)
|
||||
msg.Write(ActiveVote.State == VoteState.Passed);
|
||||
switch (ActiveVote.VoteType)
|
||||
{
|
||||
msg.Write((short)SubVote.DeliveryFee);
|
||||
case VoteType.PurchaseSub:
|
||||
case VoteType.PurchaseAndSwitchSub:
|
||||
case VoteType.SwitchSub:
|
||||
msg.Write((ActiveVote as SubmarineVote).Sub.Name);
|
||||
msg.Write((short)(ActiveVote as SubmarineVote).DeliveryFee);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var readyClients = GameMain.Server.ConnectedClients.FindAll(c => c.GetVote<bool>(VoteType.StartRound));
|
||||
msg.Write((byte)readyClients.Count);
|
||||
|
||||
Reference in New Issue
Block a user