Merge branch 'master' of https://github.com/Regalis11/Barotrauma.git into Regalis11-master
This commit is contained in:
@@ -1,39 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Barotrauma.IO;
|
||||
using System.IO.Pipes;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Barotrauma.Extensions;
|
||||
|
||||
#if SERVER
|
||||
using PipeType = System.IO.Pipes.AnonymousPipeClientStream;
|
||||
#else
|
||||
using PipeType = System.IO.Pipes.AnonymousPipeServerStream;
|
||||
#endif
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
static partial class ChildServerRelay
|
||||
{
|
||||
private static System.IO.Stream writeStream;
|
||||
private static System.IO.Stream readStream;
|
||||
private static volatile bool shutDown;
|
||||
public static bool HasShutDown
|
||||
{
|
||||
get { return shutDown; }
|
||||
}
|
||||
private static PipeType writeStream;
|
||||
private static PipeType readStream;
|
||||
|
||||
private static ManualResetEvent writeManualResetEvent;
|
||||
|
||||
private static byte[] tempBytes;
|
||||
private enum ReadState
|
||||
{
|
||||
WaitingForPacketStart,
|
||||
WaitingForPacketEnd
|
||||
};
|
||||
private static ReadState readState;
|
||||
private static byte[] readIncBuf;
|
||||
private static volatile bool shutDown;
|
||||
public static bool HasShutDown => shutDown;
|
||||
|
||||
private const int ReadBufferSize = MsgConstants.MTU * 2;
|
||||
private static byte[] readTempBytes;
|
||||
private static int readIncOffset;
|
||||
private static int readIncTotal;
|
||||
|
||||
private static Queue<byte[]> msgsToWrite;
|
||||
private static Queue<byte[]> msgsToRead;
|
||||
private static ConcurrentQueue<byte[]> msgsToWrite;
|
||||
private static ConcurrentQueue<byte[]> msgsToRead;
|
||||
|
||||
private static Thread readThread;
|
||||
private static Thread writeThread;
|
||||
@@ -42,14 +38,13 @@ namespace Barotrauma.Networking
|
||||
|
||||
private static void PrivateStart()
|
||||
{
|
||||
readState = ReadState.WaitingForPacketStart;
|
||||
readIncOffset = 0;
|
||||
readIncTotal = 0;
|
||||
|
||||
tempBytes = new byte[MsgConstants.MTU * 2];
|
||||
readTempBytes = new byte[ReadBufferSize];
|
||||
|
||||
msgsToWrite = new Queue<byte[]>();
|
||||
msgsToRead = new Queue<byte[]>();
|
||||
msgsToWrite = new ConcurrentQueue<byte[]>();
|
||||
msgsToRead = new ConcurrentQueue<byte[]>();
|
||||
|
||||
shutDown = false;
|
||||
|
||||
@@ -88,113 +83,86 @@ namespace Barotrauma.Networking
|
||||
|
||||
private static int ReadIncomingMsgs()
|
||||
{
|
||||
Task<int> readTask = readStream?.ReadAsync(tempBytes, 0, tempBytes.Length, readCancellationToken.Token);
|
||||
Task<int> readTask = readStream?.ReadAsync(readTempBytes, 0, readTempBytes.Length, readCancellationToken.Token);
|
||||
if (readTask is null) { return -1; }
|
||||
|
||||
TimeSpan timeOut = TimeSpan.FromMilliseconds(100);
|
||||
for (int i = 0; i < 150; i++)
|
||||
{
|
||||
if (shutDown)
|
||||
{
|
||||
readCancellationToken?.Cancel();
|
||||
shutDown = true;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((readTask?.IsCompleted ?? true) || (readTask?.Wait(timeOut) ?? true))
|
||||
if (readTask.IsCompleted || readTask.Wait(timeOut))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (readTask == null || !readTask.IsCompleted)
|
||||
{
|
||||
readCancellationToken?.Cancel();
|
||||
shutDown = true;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (readTask.Status != TaskStatus.RanToCompletion)
|
||||
{
|
||||
shutDown = true;
|
||||
return -1;
|
||||
bool swallowException = shutDown
|
||||
&& ((readTask.Exception?.InnerException is ObjectDisposedException)
|
||||
|| (readTask.Exception?.InnerException is System.IO.IOException));
|
||||
if (swallowException)
|
||||
{
|
||||
readCancellationToken?.Cancel();
|
||||
return -1;
|
||||
}
|
||||
throw new Exception(
|
||||
$"ChildServerRelay readTask did not run to completion: status was {readTask.Status}.",
|
||||
readTask.Exception);
|
||||
}
|
||||
|
||||
return readTask.Result;
|
||||
}
|
||||
|
||||
private static void CheckPipeConnected(string name, PipeType pipe)
|
||||
{
|
||||
if (!(pipe is { IsConnected: true }))
|
||||
{
|
||||
throw new Exception($"{name} was disconnected unexpectedly");
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateRead()
|
||||
{
|
||||
Span<byte> msgLengthSpan = stackalloc byte[2];
|
||||
while (!shutDown)
|
||||
{
|
||||
#if SERVER
|
||||
if (!((readStream as AnonymousPipeClientStream)?.IsConnected ?? false))
|
||||
CheckPipeConnected(nameof(readStream), readStream);
|
||||
|
||||
bool readBytes(Span<byte> readTo)
|
||||
{
|
||||
shutDown = true;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (!((readStream as AnonymousPipeServerStream)?.IsConnected ?? false))
|
||||
{
|
||||
shutDown = true;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int readLen = ReadIncomingMsgs();
|
||||
|
||||
if (readLen < 0) { shutDown = true; return; }
|
||||
|
||||
int procIndex = 0;
|
||||
|
||||
while (procIndex < readLen)
|
||||
{
|
||||
if (readState == ReadState.WaitingForPacketStart)
|
||||
for (int i = 0; i < readTo.Length; i++)
|
||||
{
|
||||
readIncTotal = tempBytes[procIndex];
|
||||
procIndex++;
|
||||
|
||||
if (procIndex >= readLen)
|
||||
if (readIncOffset >= readIncTotal)
|
||||
{
|
||||
readLen = ReadIncomingMsgs();
|
||||
|
||||
if (readLen < 0) { shutDown = true; return; }
|
||||
|
||||
procIndex = 0;
|
||||
readIncTotal = ReadIncomingMsgs();
|
||||
readIncOffset = 0;
|
||||
if (readIncTotal == 0) { Thread.Yield(); continue; }
|
||||
if (readIncTotal < 0) { return false; }
|
||||
}
|
||||
|
||||
readIncTotal |= (tempBytes[procIndex] << 8);
|
||||
procIndex++;
|
||||
|
||||
if (readIncTotal <= 0) { continue; }
|
||||
|
||||
readIncOffset = 0;
|
||||
readIncBuf = new byte[readIncTotal];
|
||||
readState = ReadState.WaitingForPacketEnd;
|
||||
readTo[i] = readTempBytes[readIncOffset];
|
||||
readIncOffset++;
|
||||
}
|
||||
else if (readState == ReadState.WaitingForPacketEnd)
|
||||
{
|
||||
if ((readIncTotal - readIncOffset) > (readLen - procIndex))
|
||||
{
|
||||
Array.Copy(tempBytes, procIndex, readIncBuf, readIncOffset, readLen - procIndex);
|
||||
readIncOffset += (readLen - procIndex);
|
||||
procIndex = readLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Copy(tempBytes, procIndex, readIncBuf, readIncOffset, readIncTotal - readIncOffset);
|
||||
procIndex += (readIncTotal - readIncOffset);
|
||||
readIncOffset = readIncTotal;
|
||||
lock (msgsToRead)
|
||||
{
|
||||
msgsToRead.Enqueue(readIncBuf);
|
||||
}
|
||||
readIncBuf = null;
|
||||
readState = ReadState.WaitingForPacketStart;
|
||||
}
|
||||
}
|
||||
|
||||
if (shutDown) { break; }
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!readBytes(msgLengthSpan)) { shutDown = true; break; }
|
||||
|
||||
int msgLength = msgLengthSpan[0] | (msgLengthSpan[1] << 8);
|
||||
|
||||
if (msgLength > 0)
|
||||
{
|
||||
byte[] msg = new byte[msgLength];
|
||||
if (!readBytes(msg.AsSpan())) { shutDown = true; break; }
|
||||
|
||||
msgsToRead.Enqueue(msg);
|
||||
}
|
||||
|
||||
Thread.Yield();
|
||||
}
|
||||
}
|
||||
@@ -203,81 +171,62 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
while (!shutDown)
|
||||
{
|
||||
#if SERVER
|
||||
if (!((writeStream as AnonymousPipeClientStream)?.IsConnected ?? false))
|
||||
{
|
||||
shutDown = true;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (!((writeStream as AnonymousPipeServerStream)?.IsConnected ?? false))
|
||||
{
|
||||
shutDown = true;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
bool msgAvailable; byte[] msg;
|
||||
lock (msgsToWrite)
|
||||
{
|
||||
msgAvailable = msgsToWrite.TryDequeue(out msg);
|
||||
}
|
||||
while (msgAvailable)
|
||||
{
|
||||
byte[] lengthBytes = new byte[2];
|
||||
lengthBytes[0] = (byte)(msg.Length & 0xFF);
|
||||
lengthBytes[1] = (byte)((msg.Length >> 8) & 0xFF);
|
||||
CheckPipeConnected(nameof(writeStream), writeStream);
|
||||
|
||||
msg = lengthBytes.Concat(msg).ToArray();
|
||||
bool msgAvailable; byte[] msg;
|
||||
|
||||
void writeMsg()
|
||||
{
|
||||
// It's SUPER IMPORTANT that this stack allocation
|
||||
// remains in this local function and is never inlined,
|
||||
// because C# is stupid and only calls for deallocation
|
||||
// when the function returns; placing it in the loop
|
||||
// this method is based around would lead to a stack
|
||||
// overflow real quick!
|
||||
Span<byte> bytesToWrite = stackalloc byte[2 + msg.Length];
|
||||
|
||||
bytesToWrite[0] = (byte)(msg.Length & 0xFF);
|
||||
bytesToWrite[1] = (byte)((msg.Length >> 8) & 0xFF);
|
||||
Span<byte> msgSlice = bytesToWrite.Slice(2, msg.Length);
|
||||
|
||||
msg.AsSpan().CopyTo(msgSlice);
|
||||
|
||||
try
|
||||
{
|
||||
writeStream?.Write(msg, 0, msg.Length);
|
||||
writeStream?.Write(bytesToWrite);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
catch (Exception exception)
|
||||
{
|
||||
shutDown = true;
|
||||
break;
|
||||
}
|
||||
catch (System.IO.IOException)
|
||||
{
|
||||
shutDown = true;
|
||||
break;
|
||||
switch (exception)
|
||||
{
|
||||
case ObjectDisposedException _:
|
||||
case System.IO.IOException _:
|
||||
if (!shutDown) { throw; }
|
||||
break;
|
||||
default:
|
||||
throw;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
msgAvailable = msgsToWrite.TryDequeue(out msg);
|
||||
while (msgAvailable)
|
||||
{
|
||||
writeMsg();
|
||||
|
||||
if (shutDown) { break; }
|
||||
|
||||
lock (msgsToWrite)
|
||||
{
|
||||
msgAvailable = msgsToWrite.TryDequeue(out msg);
|
||||
}
|
||||
msgAvailable = msgsToWrite.TryDequeue(out msg);
|
||||
}
|
||||
if (!shutDown)
|
||||
{
|
||||
writeManualResetEvent.Reset();
|
||||
if (!writeManualResetEvent.WaitOne(1000))
|
||||
{
|
||||
if (shutDown)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
//heartbeat to keep the other end alive
|
||||
byte[] lengthBytes = new byte[2];
|
||||
lengthBytes[0] = (byte)0;
|
||||
lengthBytes[1] = (byte)0;
|
||||
writeStream?.Write(lengthBytes, 0, 2);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
shutDown = true;
|
||||
break;
|
||||
}
|
||||
catch (System.IO.IOException)
|
||||
{
|
||||
shutDown = true;
|
||||
break;
|
||||
}
|
||||
if (shutDown) { return; }
|
||||
|
||||
//heartbeat to keep the other end alive
|
||||
msg = Array.Empty<byte>(); writeMsg();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -287,21 +236,15 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (shutDown) { return; }
|
||||
|
||||
lock (msgsToWrite)
|
||||
{
|
||||
msgsToWrite.Enqueue(msg);
|
||||
writeManualResetEvent.Set();
|
||||
}
|
||||
msgsToWrite.Enqueue(msg);
|
||||
writeManualResetEvent.Set();
|
||||
}
|
||||
|
||||
public static bool Read(out byte[] msg)
|
||||
{
|
||||
if (shutDown) { msg = null; return false; }
|
||||
|
||||
lock (msgsToRead)
|
||||
{
|
||||
return msgsToRead.TryDequeue(out msg);
|
||||
}
|
||||
return msgsToRead.TryDequeue(out msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,7 +257,7 @@ namespace Barotrauma
|
||||
{
|
||||
string errorMsg = "Attempted to add a null item to entity spawn queue.\n" + Environment.StackTrace.CleanupStackTrace();
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("EntitySpawner.AddToSpawnQueue1:ItemPrefabNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("EntitySpawner.AddToSpawnQueue1:ItemPrefabNull", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
}
|
||||
spawnQueue.Enqueue(new ItemSpawnInfo(itemPrefab, worldPosition, onSpawned, condition, quality));
|
||||
@@ -270,7 +270,7 @@ namespace Barotrauma
|
||||
{
|
||||
string errorMsg = "Attempted to add a null item to entity spawn queue.\n" + Environment.StackTrace.CleanupStackTrace();
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("EntitySpawner.AddToSpawnQueue2:ItemPrefabNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("EntitySpawner.AddToSpawnQueue2:ItemPrefabNull", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
}
|
||||
spawnQueue.Enqueue(new ItemSpawnInfo(itemPrefab, position, sub, onSpawned, condition, quality));
|
||||
@@ -283,7 +283,7 @@ namespace Barotrauma
|
||||
{
|
||||
string errorMsg = "Attempted to add a null item to entity spawn queue.\n" + Environment.StackTrace.CleanupStackTrace();
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("EntitySpawner.AddToSpawnQueue3:ItemPrefabNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("EntitySpawner.AddToSpawnQueue3:ItemPrefabNull", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
}
|
||||
spawnQueue.Enqueue(new ItemSpawnInfo(itemPrefab, inventory, onSpawned, condition, quality)
|
||||
@@ -301,7 +301,7 @@ namespace Barotrauma
|
||||
{
|
||||
string errorMsg = "Attempted to add an empty/null species name to entity spawn queue.\n" + Environment.StackTrace.CleanupStackTrace();
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("EntitySpawner.AddToSpawnQueue4:SpeciesNameNullOrEmpty", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("EntitySpawner.AddToSpawnQueue4:SpeciesNameNullOrEmpty", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
}
|
||||
spawnQueue.Enqueue(new CharacterSpawnInfo(speciesName, worldPosition, onSpawn));
|
||||
@@ -314,7 +314,7 @@ namespace Barotrauma
|
||||
{
|
||||
string errorMsg = "Attempted to add an empty/null species name to entity spawn queue.\n" + Environment.StackTrace.CleanupStackTrace();
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("EntitySpawner.AddToSpawnQueue5:SpeciesNameNullOrEmpty", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("EntitySpawner.AddToSpawnQueue5:SpeciesNameNullOrEmpty", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
}
|
||||
spawnQueue.Enqueue(new CharacterSpawnInfo(speciesName, position, sub, onSpawn));
|
||||
@@ -327,7 +327,7 @@ namespace Barotrauma
|
||||
{
|
||||
string errorMsg = "Attempted to add an empty/null species name to entity spawn queue.\n" + Environment.StackTrace.CleanupStackTrace();
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("EntitySpawner.AddToSpawnQueue4:SpeciesNameNullOrEmpty", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("EntitySpawner.AddToSpawnQueue4:SpeciesNameNullOrEmpty", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
}
|
||||
spawnQueue.Enqueue(new CharacterSpawnInfo(speciesName, worldPosition, characterInfo, onSpawn));
|
||||
|
||||
@@ -105,6 +105,15 @@ namespace Barotrauma
|
||||
[Serialize(120.0f, true)]
|
||||
public float AllowedRetaliationTime { get; set; }
|
||||
|
||||
[Serialize(5.0f, true)]
|
||||
public float DangerousItemContainKarmaDecrease { get; set; }
|
||||
|
||||
[Serialize(defaultValue: true, true)]
|
||||
public bool IsDangerousItemContainKarmaDecreaseIncremental { get; set; }
|
||||
|
||||
[Serialize(30.0f, true)]
|
||||
public float MaxDangerousItemContainKarmaDecrease { get; set; }
|
||||
|
||||
private readonly AfflictionPrefab herpesAffliction;
|
||||
|
||||
public Dictionary<string, XElement> Presets = new Dictionary<string, XElement>();
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace Barotrauma.Networking
|
||||
public const int MaxPlayers = 256;
|
||||
|
||||
public const int ServerNameMaxLength = 60;
|
||||
public const int ServerMessageMaxLength = 2000;
|
||||
|
||||
public static string MasterServerUrl = GameMain.Config.MasterServerUrl;
|
||||
|
||||
|
||||
+28
-3
@@ -27,12 +27,11 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
WriteEvent(tempEventBuffer, e, recipient);
|
||||
}
|
||||
|
||||
catch (Exception exception)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to write an event for the entity \"" + e.Entity + "\"", exception);
|
||||
GameAnalyticsManager.AddErrorEventOnce("NetEntityEventManager.Write:WriteFailed" + e.Entity.ToString(),
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
GameAnalyticsManager.ErrorSeverity.Error,
|
||||
"Failed to write an event for the entity \"" + e.Entity + "\"\n" + exception.StackTrace.CleanupStackTrace());
|
||||
|
||||
//write an empty event to avoid messing up IDs
|
||||
@@ -55,7 +54,7 @@ namespace Barotrauma.Networking
|
||||
tempBuffer.WriteVariableUInt32((uint)tempEventBuffer.LengthBytes);
|
||||
tempBuffer.Write(tempEventBuffer.Buffer, 0, tempEventBuffer.LengthBytes);
|
||||
tempBuffer.WritePadBits();
|
||||
sentEvents.Add(e);
|
||||
sentEvents.Add(e);
|
||||
|
||||
eventCount++;
|
||||
}
|
||||
@@ -68,6 +67,32 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
protected static bool ValidateEntity(INetSerializable entity)
|
||||
{
|
||||
void error(string reason)
|
||||
=> DebugConsole.ThrowError($"Can't create an entity event for {entity} - {reason}.\n{Environment.StackTrace.CleanupStackTrace()}");
|
||||
|
||||
if (entity is Entity { Removed: var removed, IdFreed: var idFreed })
|
||||
{
|
||||
if (removed)
|
||||
{
|
||||
error("the entity has been removed");
|
||||
return false;
|
||||
}
|
||||
if (idFreed)
|
||||
{
|
||||
error("the ID of the entity has been freed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error($"input is not of type {nameof(Entity)}");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract void WriteEvent(IWriteMessage buffer, NetEntityEvent entityEvent, Client recipient = null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Barotrauma.Networking
|
||||
static class NetIdUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Is newID more recent than oldID
|
||||
/// Is newID more recent than oldID, i.e. newId > oldId accounting for ushort rollover
|
||||
/// </summary>
|
||||
public static bool IdMoreRecent(ushort newID, ushort oldID)
|
||||
{
|
||||
@@ -22,6 +22,12 @@ namespace Barotrauma.Networking
|
||||
(id2 > id1) && (id2 - id1 > ushort.MaxValue / 2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// newId >= oldId accounting for ushort rollover (newer or equals)
|
||||
/// </summary>
|
||||
public static bool IdMoreRecentOrMatches(ushort newId, ushort oldId)
|
||||
=> !IdMoreRecent(oldId, newId);
|
||||
|
||||
public static ushort Difference(ushort id1, ushort id2)
|
||||
{
|
||||
int diff = id2 > id1 ? id2 - id1 : id1 - id2;
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
public enum DeliveryMethod : byte
|
||||
public enum DeliveryMethod : int
|
||||
{
|
||||
Unreliable = 0x0,
|
||||
Reliable = 0x1,
|
||||
ReliableOrdered = 0x2
|
||||
}
|
||||
|
||||
public enum ConnectionInitialization : byte
|
||||
public enum ConnectionInitialization : int
|
||||
{
|
||||
//used by all peer implementations
|
||||
SteamTicketAndVersion = 0x1,
|
||||
@@ -22,7 +22,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum PacketHeader : byte
|
||||
public enum PacketHeader : int
|
||||
{
|
||||
//used by all peer implementations
|
||||
None = 0x0,
|
||||
@@ -34,5 +34,23 @@ namespace Barotrauma.Networking
|
||||
IsServerMessage = 0x8,
|
||||
IsHeartbeatMessage = 0x10
|
||||
}
|
||||
|
||||
public static class NetworkEnumExtensions
|
||||
{
|
||||
public static bool IsCompressed(this PacketHeader h)
|
||||
=> h.IsBitSet(PacketHeader.IsCompressed);
|
||||
|
||||
public static bool IsConnectionInitializationStep(this PacketHeader h)
|
||||
=> h.IsBitSet(PacketHeader.IsConnectionInitializationStep);
|
||||
|
||||
public static bool IsDisconnectMessage(this PacketHeader h)
|
||||
=> h.IsBitSet(PacketHeader.IsDisconnectMessage);
|
||||
|
||||
public static bool IsServerMessage(this PacketHeader h)
|
||||
=> h.IsBitSet(PacketHeader.IsServerMessage);
|
||||
|
||||
public static bool IsHeartbeatMessage(this PacketHeader h)
|
||||
=> h.IsBitSet(PacketHeader.IsHeartbeatMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -219,7 +219,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
internal static void EnsureBufferSize(ref byte[] buf, int numberOfBits)
|
||||
{
|
||||
int byteLen = ((numberOfBits + 7) >> 3);
|
||||
int byteLen = (numberOfBits + 7) / 8;
|
||||
if (buf == null)
|
||||
{
|
||||
buf = new byte[byteLen + MsgConstants.BufferOverAllocateAmount];
|
||||
@@ -461,7 +461,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
get
|
||||
{
|
||||
return (LengthBits + ((8 - (LengthBits % 8)) % 8)) / 8;
|
||||
return (LengthBits + 7) / 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
partial void UpdateReturningProjSpecific(float deltaTime);
|
||||
|
||||
private IEnumerable<object> ForceShuttleToPos(Vector2 position, float speed)
|
||||
private IEnumerable<CoroutineStatus> ForceShuttleToPos(Vector2 position, float speed)
|
||||
{
|
||||
|
||||
#if SERVER
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace Barotrauma.Networking
|
||||
ServerMessage,
|
||||
ConsoleUsage,
|
||||
Karma,
|
||||
Talent,
|
||||
Error,
|
||||
}
|
||||
|
||||
@@ -56,6 +57,7 @@ namespace Barotrauma.Networking
|
||||
{ MessageType.ServerMessage, new Color(157, 225, 160) },
|
||||
{ MessageType.ConsoleUsage, new Color(0, 162, 232) },
|
||||
{ MessageType.Karma, new Color(75, 88, 255) },
|
||||
{ MessageType.Talent, new Color(125, 125, 255) },
|
||||
{ MessageType.Error, Color.Red },
|
||||
};
|
||||
|
||||
@@ -70,6 +72,7 @@ namespace Barotrauma.Networking
|
||||
{ MessageType.ServerMessage, "ServerMessage" },
|
||||
{ MessageType.ConsoleUsage, "ConsoleUsage" },
|
||||
{ MessageType.Karma, "Karma" },
|
||||
{ MessageType.Talent, "Talent" },
|
||||
{ MessageType.Error, "Error" }
|
||||
};
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
@@ -44,11 +45,13 @@ namespace Barotrauma.Networking
|
||||
[Flags]
|
||||
public enum NetFlags : byte
|
||||
{
|
||||
None = 0x0,
|
||||
Name = 0x1,
|
||||
Message = 0x2,
|
||||
Properties = 0x4,
|
||||
Misc = 0x8,
|
||||
LevelSeed = 0x10
|
||||
LevelSeed = 0x10,
|
||||
HiddenSubs = 0x20
|
||||
}
|
||||
|
||||
public static readonly string PermissionPresetFile = "Data" + Path.DirectorySeparatorChar + "permissionpresets.xml";
|
||||
@@ -284,6 +287,8 @@ namespace Barotrauma.Networking
|
||||
|
||||
ExtraCargo = new Dictionary<ItemPrefab, int>();
|
||||
|
||||
HiddenSubs = new HashSet<string>();
|
||||
|
||||
PermissionPreset.LoadAll(PermissionPresetFile);
|
||||
InitProjSpecific();
|
||||
|
||||
@@ -339,8 +344,14 @@ namespace Barotrauma.Networking
|
||||
get { return serverName; }
|
||||
set
|
||||
{
|
||||
serverName = value;
|
||||
if (serverName.Length > NetConfig.ServerNameMaxLength) { ServerName = ServerName.Substring(0, NetConfig.ServerNameMaxLength); }
|
||||
string val = value;
|
||||
if (val.Length > NetConfig.ServerNameMaxLength) { val = val.Substring(0, NetConfig.ServerNameMaxLength); }
|
||||
if (serverName == val) { return; }
|
||||
serverName = val;
|
||||
ServerDetailsChanged = true;
|
||||
#if SERVER
|
||||
UpdateFlag(NetFlags.Name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,9 +361,14 @@ namespace Barotrauma.Networking
|
||||
get { return serverMessageText; }
|
||||
set
|
||||
{
|
||||
if (serverMessageText == value) { return; }
|
||||
serverMessageText = value;
|
||||
string val = value;
|
||||
if (val.Length > NetConfig.ServerMessageMaxLength) { val = val.Substring(0, NetConfig.ServerMessageMaxLength); }
|
||||
if (serverMessageText == val) { return; }
|
||||
serverMessageText = val;
|
||||
ServerDetailsChanged = true;
|
||||
#if SERVER
|
||||
UpdateFlag(NetFlags.Message);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,8 +386,12 @@ namespace Barotrauma.Networking
|
||||
|
||||
public Dictionary<string, bool> MonsterEnabled { get; private set; }
|
||||
|
||||
public const int MaxExtraCargoItemsOfType = 10;
|
||||
public const int MaxExtraCargoItemTypes = 20;
|
||||
public Dictionary<ItemPrefab, int> ExtraCargo { get; private set; }
|
||||
|
||||
public HashSet<string> HiddenSubs { get; private set; }
|
||||
|
||||
private float selectedLevelDifficulty;
|
||||
private string password;
|
||||
|
||||
@@ -509,6 +529,13 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
[Serialize(Barotrauma.LosMode.Opaque, true)]
|
||||
public LosMode LosMode
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(800, true)]
|
||||
public int LinesPerLogFile
|
||||
{
|
||||
@@ -993,16 +1020,17 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
bool changed = false;
|
||||
UInt32 count = msg.ReadUInt32();
|
||||
if (ExtraCargo == null || count != ExtraCargo.Count) changed = true;
|
||||
if (ExtraCargo == null || count != ExtraCargo.Count) { changed = true; }
|
||||
Dictionary<ItemPrefab, int> extraCargo = new Dictionary<ItemPrefab, int>();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
string prefabIdentifier = msg.ReadString();
|
||||
byte amount = msg.ReadByte();
|
||||
|
||||
var itemPrefab = MapEntityPrefab.Find(null, prefabIdentifier, showErrorMessages: false) as ItemPrefab;
|
||||
if (itemPrefab != null && amount > 0)
|
||||
if (MapEntityPrefab.Find(null, prefabIdentifier, showErrorMessages: false) is ItemPrefab itemPrefab && amount > 0)
|
||||
{
|
||||
if (ExtraCargo.Keys.Count() >= MaxExtraCargoItemTypes) { continue; }
|
||||
if (ExtraCargo.ContainsKey(itemPrefab) && ExtraCargo[itemPrefab] >= MaxExtraCargoItemsOfType) { continue; }
|
||||
if (changed || !ExtraCargo.ContainsKey(itemPrefab) || ExtraCargo[itemPrefab] != amount) { changed = true; }
|
||||
extraCargo.Add(itemPrefab, amount);
|
||||
}
|
||||
@@ -1026,5 +1054,36 @@ namespace Barotrauma.Networking
|
||||
msg.Write((byte)kvp.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public void ReadHiddenSubs(IReadMessage msg)
|
||||
{
|
||||
var subList = GameMain.NetLobbyScreen.GetSubList();
|
||||
|
||||
HiddenSubs.Clear();
|
||||
uint count = msg.ReadVariableUInt32();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
int index = msg.ReadUInt16();
|
||||
if (index < 0 || index >= subList.Count) { continue; }
|
||||
string submarineName = subList[index].Name;
|
||||
HiddenSubs.Add(submarineName);
|
||||
}
|
||||
|
||||
#if SERVER
|
||||
MultiPlayerCampaign.UpdateCampaignSubs();
|
||||
SelectNonHiddenSubmarine();
|
||||
#endif
|
||||
}
|
||||
|
||||
public void WriteHiddenSubs(IWriteMessage msg)
|
||||
{
|
||||
var subList = GameMain.NetLobbyScreen.GetSubList();
|
||||
|
||||
msg.WriteVariableUInt32((uint)HiddenSubs.Count);
|
||||
foreach (string submarineName in HiddenSubs)
|
||||
{
|
||||
msg.Write((UInt16)subList.FindIndex(s => s.Name.Equals(submarineName, StringComparison.OrdinalIgnoreCase)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,19 @@ namespace Barotrauma.Steam
|
||||
return Steamworks.SteamClient.Name;
|
||||
}
|
||||
|
||||
private static Steamworks.AuthTicket currentTicket = null;
|
||||
public static Steamworks.AuthTicket GetAuthSessionTicket()
|
||||
{
|
||||
if (!isInitialized)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
currentTicket?.Cancel();
|
||||
currentTicket = Steamworks.SteamUser.GetAuthSessionTicket();
|
||||
return currentTicket;
|
||||
}
|
||||
|
||||
public static bool OverlayCustomURL(string url)
|
||||
{
|
||||
if (!isInitialized || !Steamworks.SteamClient.IsValid)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Barotrauma.Networking;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -15,23 +16,22 @@ namespace Barotrauma
|
||||
|
||||
public enum VoteState { None = 0, Started = 1, Running = 2, Passed = 3, Failed = 4 };
|
||||
|
||||
private List<Pair<object, int>> GetVoteList(VoteType voteType, List<Client> voters)
|
||||
private IReadOnlyDictionary<T, int> GetVoteCounts<T>(VoteType voteType, List<Client> voters)
|
||||
{
|
||||
List<Pair<object, int>> voteList = new List<Pair<object, int>>();
|
||||
Dictionary<T, int> voteList = new Dictionary<T, int>();
|
||||
|
||||
foreach (Client voter in voters)
|
||||
{
|
||||
object vote = voter.GetVote<object>(voteType);
|
||||
T vote = voter.GetVote<T>(voteType);
|
||||
if (vote == null) continue;
|
||||
|
||||
var existingVotable = voteList.Find(v => v.First == vote || v.First.Equals(vote));
|
||||
if (existingVotable == null)
|
||||
if (!voteList.ContainsKey(vote))
|
||||
{
|
||||
voteList.Add(new Pair<object, int>(vote, 1));
|
||||
voteList.Add(vote, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
existingVotable.Second++;
|
||||
voteList[vote]++;
|
||||
}
|
||||
}
|
||||
return voteList;
|
||||
@@ -42,16 +42,23 @@ namespace Barotrauma
|
||||
if (voteType == VoteType.Sub && !AllowSubVoting) return default(T);
|
||||
if (voteType == VoteType.Mode && !AllowModeVoting) return default(T);
|
||||
|
||||
List<Pair<object, int>> voteList = GetVoteList(voteType, voters);
|
||||
IReadOnlyDictionary<T, int> voteList = GetVoteCounts<T>(voteType, voters);
|
||||
|
||||
T selected = default(T);
|
||||
int highestVotes = 0;
|
||||
foreach (Pair<object, int> votable in voteList)
|
||||
foreach (KeyValuePair<T, int> votable in voteList)
|
||||
{
|
||||
if (selected == null || votable.Second > highestVotes)
|
||||
if (voteType == VoteType.Sub
|
||||
&& votable.Key is SubmarineInfo subInfo
|
||||
&& GameMain.NetworkMember.ServerSettings.HiddenSubs.Contains(subInfo.Name))
|
||||
{
|
||||
highestVotes = votable.Second;
|
||||
selected = (T)votable.First;
|
||||
//This sub is hidden so it can't be voted for, skip
|
||||
continue;
|
||||
}
|
||||
if (selected == null || votable.Value > highestVotes)
|
||||
{
|
||||
highestVotes = votable.Value;
|
||||
selected = votable.Key;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user