mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-16 07:12:27 +02:00
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
129 lines
4.3 KiB
C#
129 lines
4.3 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.IO.Compression;
|
|
using Lidgren.Network;
|
|
using Robust.Shared.GameStates;
|
|
using Robust.Shared.IoC;
|
|
using Robust.Shared.Log;
|
|
using Robust.Shared.Serialization;
|
|
using Robust.Shared.Utility;
|
|
|
|
#nullable disable
|
|
|
|
namespace Robust.Shared.Network.Messages
|
|
{
|
|
public sealed class MsgState : NetMessage
|
|
{
|
|
// If a state is large enough we send it ReliableUnordered instead.
|
|
// This is to avoid states being so large that they consistently fail to reach the other end
|
|
// (due to being in many parts).
|
|
public const int ReliableThreshold = 1300;
|
|
|
|
// If a state is larger than this, compress it with deflate.
|
|
public const int CompressionThreshold = 256;
|
|
|
|
public override MsgGroups MsgGroup => MsgGroups.Entity;
|
|
|
|
public GameState State;
|
|
|
|
private bool _hasWritten;
|
|
|
|
public override void ReadFromBuffer(NetIncomingMessage buffer)
|
|
{
|
|
MsgSize = buffer.LengthBytes;
|
|
var uncompressedLength = buffer.ReadVariableInt32();
|
|
var compressedLength = buffer.ReadVariableInt32();
|
|
MemoryStream finalStream;
|
|
|
|
// State is compressed.
|
|
if (compressedLength > 0)
|
|
{
|
|
var stream = buffer.ReadAlignedMemory(compressedLength);
|
|
using var decompressStream = new DeflateStream(stream, CompressionMode.Decompress);
|
|
var decompressedStream = new MemoryStream(uncompressedLength);
|
|
decompressStream.CopyTo(decompressedStream, uncompressedLength);
|
|
decompressedStream.Position = 0;
|
|
finalStream = decompressedStream;
|
|
}
|
|
// State is uncompressed.
|
|
else
|
|
{
|
|
var stream = buffer.ReadAlignedMemory(uncompressedLength);
|
|
finalStream = stream;
|
|
}
|
|
|
|
var serializer = IoCManager.Resolve<IRobustSerializer>();
|
|
serializer.DeserializeDirect(finalStream, out State);
|
|
finalStream.Dispose();
|
|
|
|
State.PayloadSize = uncompressedLength;
|
|
}
|
|
|
|
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
|
{
|
|
var serializer = IoCManager.Resolve<IRobustSerializer>();
|
|
MemoryStream finalStream;
|
|
var stateStream = new MemoryStream();
|
|
serializer.SerializeDirect(stateStream, State);
|
|
buffer.WriteVariableInt32((int) stateStream.Length);
|
|
|
|
// We compress the state.
|
|
if (stateStream.Length > CompressionThreshold)
|
|
{
|
|
stateStream.Position = 0;
|
|
var compressedStream = new MemoryStream();
|
|
using (var deflateStream = new DeflateStream(compressedStream, CompressionMode.Compress, true))
|
|
{
|
|
stateStream.CopyTo(deflateStream);
|
|
}
|
|
|
|
buffer.WriteVariableInt32((int) compressedStream.Length);
|
|
finalStream = compressedStream;
|
|
}
|
|
// The state is sent as is.
|
|
else
|
|
{
|
|
// 0 means that the state isn't compressed.
|
|
buffer.WriteVariableInt32(0);
|
|
finalStream = stateStream;
|
|
}
|
|
|
|
finalStream.TryGetBuffer(out var segment);
|
|
buffer.Write(segment);
|
|
finalStream.Dispose();
|
|
|
|
_hasWritten = false;
|
|
MsgSize = buffer.LengthBytes;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Whether this state message is large enough to warrant being sent reliably.
|
|
/// This is only valid after
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public bool ShouldSendReliably()
|
|
{
|
|
// This check will be true in integration tests.
|
|
// TODO: Maybe handle this better so that packet loss integration testing can be done?
|
|
if (!_hasWritten)
|
|
{
|
|
return true;
|
|
}
|
|
return MsgSize > ReliableThreshold;
|
|
}
|
|
|
|
public override NetDeliveryMethod DeliveryMethod
|
|
{
|
|
get
|
|
{
|
|
if (ShouldSendReliably())
|
|
{
|
|
return NetDeliveryMethod.ReliableUnordered;
|
|
}
|
|
|
|
return base.DeliveryMethod;
|
|
}
|
|
}
|
|
}
|
|
}
|