Unstable 0.17.1.0

This commit is contained in:
Markus Isberg
2022-03-17 01:25:04 +09:00
parent 3974067915
commit 6d410cc1b7
302 changed files with 5878 additions and 3317 deletions
@@ -219,8 +219,12 @@ namespace Barotrauma.Networking
public static string ApplyDistanceEffect(string message, ChatMessageType type, Character sender, Character receiver)
{
if (sender == null) { return ""; }
string spokenMsg = ApplyDistanceEffect(receiver, sender, message, SpeakRange * (1.0f - sender.SpeechImpediment / 100.0f), 3.0f);
float range = SpeakRange;
if (type == ChatMessageType.Default && sender.SpeechImpediment > 0)
{
range *= 1.0f - sender.SpeechImpediment / 100.0f;
}
string spokenMsg = ApplyDistanceEffect(receiver, sender, message, range, 3.0f);
switch (type)
{
@@ -1,6 +1,7 @@
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Barotrauma.Extensions;
@@ -18,6 +19,13 @@ namespace Barotrauma.Networking
private static PipeType writeStream;
private static PipeType readStream;
private enum WriteStatus : byte
{
Success = 0x00,
Heartbeat = 0x01,
Crash = 0xFF
}
private static ManualResetEvent writeManualResetEvent;
private static volatile bool shutDown;
@@ -29,6 +37,8 @@ namespace Barotrauma.Networking
private static int readIncTotal;
private static ConcurrentQueue<byte[]> msgsToWrite;
private static ConcurrentQueue<string> errorsToWrite;
private static ConcurrentQueue<byte[]> msgsToRead;
private static Thread readThread;
@@ -44,6 +54,8 @@ namespace Barotrauma.Networking
readTempBytes = new byte[ReadBufferSize];
msgsToWrite = new ConcurrentQueue<byte[]>();
errorsToWrite = new ConcurrentQueue<string>();
msgsToRead = new ConcurrentQueue<byte[]>();
shutDown = false;
@@ -127,9 +139,11 @@ namespace Barotrauma.Networking
}
}
static partial void HandleCrashString(string str);
private static void UpdateRead()
{
Span<byte> msgLengthSpan = stackalloc byte[2];
Span<byte> msgLengthSpan = stackalloc byte[3];
while (!shutDown)
{
CheckPipeConnected(nameof(readStream), readStream);
@@ -154,13 +168,26 @@ namespace Barotrauma.Networking
if (!readBytes(msgLengthSpan)) { shutDown = true; break; }
int msgLength = msgLengthSpan[0] | (msgLengthSpan[1] << 8);
WriteStatus writeStatus = (WriteStatus)msgLengthSpan[2];
if (msgLength > 0)
{
byte[] msg = new byte[msgLength];
if (!readBytes(msg.AsSpan())) { shutDown = true; break; }
msgsToRead.Enqueue(msg);
switch (writeStatus)
{
case WriteStatus.Success:
msgsToRead.Enqueue(msg);
break;
case WriteStatus.Heartbeat:
//do nothing
break;
case WriteStatus.Crash:
HandleCrashString(Encoding.UTF8.GetString(msg));
shutDown = true;
break;
}
}
Thread.Yield();
@@ -173,9 +200,9 @@ namespace Barotrauma.Networking
{
CheckPipeConnected(nameof(writeStream), writeStream);
bool msgAvailable; byte[] msg;
byte[] msg;
void writeMsg()
void writeMsg(WriteStatus writeStatus)
{
// It's SUPER IMPORTANT that this stack allocation
// remains in this local function and is never inlined,
@@ -183,11 +210,12 @@ namespace Barotrauma.Networking
// 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];
Span<byte> bytesToWrite = stackalloc byte[3 + msg.Length];
bytesToWrite[0] = (byte)(msg.Length & 0xFF);
bytesToWrite[1] = (byte)((msg.Length >> 8) & 0xFF);
Span<byte> msgSlice = bytesToWrite.Slice(2, msg.Length);
bytesToWrite[2] = (byte)writeStatus;
Span<byte> msgSlice = bytesToWrite.Slice(3, msg.Length);
msg.AsSpan().CopyTo(msgSlice);
@@ -209,15 +237,20 @@ namespace Barotrauma.Networking
}
}
msgAvailable = msgsToWrite.TryDequeue(out msg);
while (msgAvailable)
while (errorsToWrite.TryDequeue(out var error))
{
writeMsg();
msg = Encoding.UTF8.GetBytes(error);
writeMsg(WriteStatus.Crash);
shutDown = true;
}
while (msgsToWrite.TryDequeue(out msg))
{
writeMsg(WriteStatus.Success);
if (shutDown) { break; }
msgAvailable = msgsToWrite.TryDequeue(out msg);
}
if (!shutDown)
{
writeManualResetEvent.Reset();
@@ -226,7 +259,7 @@ namespace Barotrauma.Networking
if (shutDown) { return; }
//heartbeat to keep the other end alive
msg = Array.Empty<byte>(); writeMsg();
msg = Array.Empty<byte>(); writeMsg(WriteStatus.Heartbeat);
}
}
}
@@ -5,6 +5,7 @@ using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using Steamworks.ServerList;
namespace Barotrauma
{
@@ -196,51 +197,60 @@ namespace Barotrauma
private readonly Queue<IEntitySpawnInfo> spawnQueue;
private readonly Queue<Entity> removeQueue;
public class SpawnOrRemove
public abstract class SpawnOrRemove : NetEntityEvent.IData
{
public readonly Entity Entity;
public UInt16 ID => Entity.ID;
public readonly UInt16 InventoryID;
public readonly UInt16 OriginalID, OriginalInventoryID;
public readonly int OriginalSlotIndex;
public readonly byte OriginalItemContainerIndex;
public readonly bool Remove = false;
public readonly byte ItemContainerIndex;
public readonly int SlotIndex;
public override string ToString()
{
return
(Remove ? "Remove" : "Spawn") + "(" +
"(" +
((Entity as MapEntity)?.Name ?? "[NULL]") +
$", {OriginalID}, {OriginalInventoryID})";
$", {ID}, {InventoryID}, {SlotIndex})";
}
public SpawnOrRemove(Entity entity, bool remove)
protected SpawnOrRemove(Entity entity)
{
Entity = entity;
OriginalID = entity.ID;
if (entity is Item item && item.ParentInventory?.Owner != null)
if (!(entity is Item { ParentInventory: { Owner: { } } } item)) { return; }
InventoryID = item.ParentInventory.Owner.ID;
SlotIndex = item.ParentInventory.FindIndex(item);
//find the index of the ItemContainer this item is inside to get the item to
//spawn in the correct inventory in multi-inventory items like fabricators
if (item.Container == null) { return; }
foreach (ItemComponent component in item.Container.Components)
{
OriginalInventoryID = item.ParentInventory.Owner.ID;
OriginalSlotIndex = item.ParentInventory.FindIndex(item);
//find the index of the ItemContainer this item is inside to get the item to
//spawn in the correct inventory in multi-inventory items like fabricators
if (item.Container != null)
if (component is ItemContainer container &&
container.Inventory == item.ParentInventory)
{
foreach (ItemComponent component in item.Container.Components)
{
if (component is ItemContainer container &&
container.Inventory == item.ParentInventory)
{
OriginalItemContainerIndex = (byte)item.Container.GetComponentIndex(component);
break;
}
}
ItemContainerIndex = (byte)item.Container.GetComponentIndex(component);
break;
}
}
Remove = remove;
}
}
public sealed class SpawnEntity : SpawnOrRemove
{
public SpawnEntity(Entity entity) : base(entity) { }
public override string ToString()
=> $"Spawn {base.ToString()}";
}
public sealed class RemoveEntity : SpawnOrRemove
{
public RemoveEntity(Entity entity) : base(entity) { }
public override string ToString()
=> $"Remove {base.ToString()}";
}
public EntitySpawner()
: base(null, Entity.EntitySpawnerID)
@@ -397,20 +407,19 @@ namespace Barotrauma
public void Update(bool createNetworkEvents = true)
{
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
if (GameMain.NetworkMember is { IsClient: true }) { return; }
while (spawnQueue.Count > 0)
{
var entitySpawnInfo = spawnQueue.Dequeue();
var spawnedEntity = entitySpawnInfo.Spawn();
if (spawnedEntity != null)
{
if (createNetworkEvents)
{
CreateNetworkEventProjSpecific(spawnedEntity, false);
}
entitySpawnInfo.OnSpawned(spawnedEntity);
if (spawnedEntity == null) { continue; }
if (createNetworkEvents)
{
CreateNetworkEventProjSpecific(new SpawnEntity(spawnedEntity));
}
entitySpawnInfo.OnSpawned(spawnedEntity);
}
while (removeQueue.Count > 0)
@@ -422,13 +431,13 @@ namespace Barotrauma
}
if (createNetworkEvents)
{
CreateNetworkEventProjSpecific(removedEntity, true);
CreateNetworkEventProjSpecific(new RemoveEntity(removedEntity));
}
removedEntity.Remove();
}
}
partial void CreateNetworkEventProjSpecific(Entity entity, bool remove);
partial void CreateNetworkEventProjSpecific(SpawnOrRemove spawnOrRemove);
public void Reset()
{
@@ -3,28 +3,41 @@
interface INetSerializable { }
/// <summary>
/// Interface for entities that the clients can send information of to the server
/// Interface for entities that the clients can send events to the server
/// </summary>
interface IClientSerializable : INetSerializable
{
#if CLIENT
void ClientWrite(IWriteMessage msg, object[] extraData = null);
void ClientEventWrite(IWriteMessage msg, NetEntityEvent.IData extraData = null);
#endif
#if SERVER
void ServerRead(ClientNetObject type, IReadMessage msg, Client c);
void ServerEventRead(IReadMessage msg, Client c);
#endif
}
/// <summary>
/// Interface for entities that the server can send information of to the clients
/// Interface for entities that the server can send events to the clients
/// </summary>
interface IServerSerializable : INetSerializable
{
#if SERVER
void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null);
void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null);
#endif
#if CLIENT
void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime);
void ClientEventRead(IReadMessage msg, float sendingTime);
#endif
}
/// <summary>
/// Interface for entities that handle ServerNetObject.ENTITY_POSITION
/// </summary>
interface IServerPositionSync : IServerSerializable
{
#if SERVER
void ServerWritePosition(IWriteMessage msg, Client c);
#endif
#if CLIENT
void ClientReadPosition(IReadMessage msg, float sendingTime);
#endif
}
}
@@ -5,6 +5,8 @@ using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
@@ -42,6 +44,13 @@ namespace Barotrauma
public int NumberOfBits = 8;
public bool IncludeColorAlpha = false;
public int ArrayMaxSize = ushort.MaxValue;
public readonly int OrderKey;
public NetworkSerialize([CallerLineNumber] int lineNumber = 0)
{
OrderKey = lineNumber;
}
}
/// <summary>
@@ -52,6 +61,7 @@ namespace Barotrauma
public readonly struct ReadWriteBehavior
{
public delegate dynamic? ReadDelegate(IReadMessage inc, Type type, NetworkSerialize attribute);
public delegate void WriteDelegate(dynamic? obj, NetworkSerialize attribute, IWriteMessage msg);
public readonly ReadDelegate ReadAction;
@@ -64,6 +74,58 @@ namespace Barotrauma
}
}
public readonly struct CachedReflectedVariable
{
public delegate object? GetValueDelegate(object? obj);
public delegate void SetValueDelegate(object? obj, object? value);
public readonly Type Type;
public readonly ReadWriteBehavior Behavior;
public readonly NetworkSerialize Attribute;
public readonly SetValueDelegate SetValue;
public readonly GetValueDelegate GetValue;
public readonly bool HasOwnAttribute;
public CachedReflectedVariable(MemberInfo info, ReadWriteBehavior behavior, Type baseClassType)
{
Behavior = behavior;
switch (info)
{
case PropertyInfo pi:
Type = pi.PropertyType;
GetValue = pi.GetValue;
SetValue = pi.SetValue;
break;
case FieldInfo fi:
Type = fi.FieldType;
GetValue = fi.GetValue;
SetValue = fi.SetValue;
break;
default:
throw new ArgumentException($"Expected {nameof(FieldInfo)} or {nameof(PropertyInfo)} but found {info.GetType()}.", nameof(info));
}
if (info.GetCustomAttribute<NetworkSerialize>() is { } ownAttriute)
{
HasOwnAttribute = true;
Attribute = ownAttriute;
}
else if (baseClassType.GetCustomAttribute<NetworkSerialize>() is { } globalAttribute)
{
HasOwnAttribute = false;
Attribute = globalAttribute;
}
else
{
throw new InvalidOperationException($"Unable to serialize \"{Type}\" in \"{baseClassType}\" because it has no {nameof(NetworkSerialize)} attribute.");
}
}
}
private static readonly Dictionary<Type, ImmutableArray<CachedReflectedVariable>> CachedVariables = new Dictionary<Type, ImmutableArray<CachedReflectedVariable>>();
private static readonly ImmutableDictionary<Type, ReadWriteBehavior> TypeBehaviors = new Dictionary<Type, ReadWriteBehavior>
{
{ typeof(Boolean), new ReadWriteBehavior(ReadBoolean, WriteDynamic) },
@@ -82,8 +144,6 @@ namespace Barotrauma
{ typeof(Vector2), new ReadWriteBehavior(ReadVector2, WriteVector2) }
}.ToImmutableDictionary();
private static readonly ReadWriteBehavior InvalidReadWriteBehavior = new ReadWriteBehavior(ReadInvalid, WriteInvalid);
private static readonly ImmutableDictionary<Predicate<Type>, ReadWriteBehavior> TypePredicates = new Dictionary<Predicate<Type>, ReadWriteBehavior>
{
// Arrays
@@ -99,15 +159,18 @@ namespace Barotrauma
{ type => Nullable.GetUnderlyingType(type) != null, new ReadWriteBehavior(ReadNullable, WriteNullable) },
// Option
{ type => type.GetGenericTypeDefinition() == typeof(Option<>), new ReadWriteBehavior(ReadOption, WriteOption) }
{ type => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Option<>), new ReadWriteBehavior(ReadOption, WriteOption) }
}.ToImmutableDictionary();
private static readonly ReadWriteBehavior InvalidReadWriteBehavior = new ReadWriteBehavior(ReadInvalid, WriteInvalid);
private static readonly Dictionary<Type, MethodInfo> cachedSomeCreateMethods = new Dictionary<Type, MethodInfo>();
private static readonly Dictionary<Type, MethodInfo> cachedNoneCreateMethod = new Dictionary<Type, MethodInfo>();
private static void WriteInvalid(dynamic? obj, NetworkSerialize attribute, IWriteMessage msg) => throw new InvalidOperationException($"Type {obj?.GetType()} cannot be serialized. Did you forget to implement INetSerializableStruct?");
private static void WriteInvalid(dynamic? obj, NetworkSerialize attribute, IWriteMessage msg) =>
throw new SerializationException($"Type {obj?.GetType()} cannot be serialized. Did you forget to implement {nameof(INetSerializableStruct)}?");
private static dynamic ReadInvalid(IReadMessage inc, Type type, NetworkSerialize attribute) => throw new InvalidOperationException($"Type {type} cannot be deserialized. Did you forget to implement INetSerializableStruct?");
private static dynamic ReadInvalid(IReadMessage inc, Type type, NetworkSerialize attribute) => throw new SerializationException($"Type {type} cannot be deserialized. Did you forget to implement {nameof(INetSerializableStruct)}?");
private static void WriteOption(dynamic? obj, NetworkSerialize attribute, IWriteMessage msg)
{
@@ -131,7 +194,7 @@ namespace Barotrauma
}
else
{
throw new InvalidOperationException("Option type was neither None<> or Some<>");
throw new ArgumentOutOfRangeException(nameof(obj), "Option type was neither None or Some");
}
}
@@ -147,7 +210,7 @@ namespace Barotrauma
if (TryFindBehavior(underlyingType, out ReadWriteBehavior behavior))
{
dynamic? value = behavior.ReadAction(inc, underlyingType, attribute);
return GetCreateMethod(typeof(Some<>), underlyingType, cachedSomeCreateMethods).Invoke(null, new []{ value });
return GetCreateMethod(typeof(Some<>), underlyingType, cachedSomeCreateMethods).Invoke(null, new[] { value });
}
throw new InvalidOperationException($"Could not find suitable behavior for type {underlyingType} in {nameof(ReadOption)}");
@@ -349,7 +412,7 @@ namespace Barotrauma
private static dynamic ReadDouble(IReadMessage inc, Type type, NetworkSerialize attribute) => inc.ReadDouble();
private static dynamic ReadString(IReadMessage inc, Type type, NetworkSerialize attribute) => inc.ReadString();
private static dynamic ReadIdentifier(IReadMessage inc, Type type, NetworkSerialize attribute) => inc.ReadIdentifier();
private static dynamic ReadColor(IReadMessage inc, Type type, NetworkSerialize attribute) => attribute.IncludeColorAlpha ? inc.ReadColorR8G8B8A8() : inc.ReadColorR8G8B8();
@@ -411,7 +474,7 @@ namespace Barotrauma
return new Range<int>(values.Min(), values.Max());
}
public static bool TryFindBehavior(Type type, out ReadWriteBehavior behavior)
private static bool TryFindBehavior(Type type, out ReadWriteBehavior behavior)
{
if (TypeBehaviors.TryGetValue(type, out behavior)) { return true; }
@@ -427,6 +490,46 @@ namespace Barotrauma
behavior = InvalidReadWriteBehavior;
return false;
}
public static ImmutableArray<CachedReflectedVariable> GetPropertiesAndFields(Type type, Type baseClassType)
{
if (CachedVariables.TryGetValue(type, out var cached)) { return cached; }
List<CachedReflectedVariable> variables = new List<CachedReflectedVariable>();
IEnumerable<PropertyInfo> propertyInfos = type.GetProperties().Where(HasAttribute);
IEnumerable<FieldInfo> fieldInfos = type.GetFields().Where(HasAttribute);
foreach (PropertyInfo info in propertyInfos)
{
if (TryFindBehavior(info.PropertyType, out ReadWriteBehavior behavior))
{
variables.Add(new CachedReflectedVariable(info, behavior, baseClassType));
}
else
{
throw new SerializationException($"Unable to serialize type \"{type}\".");
}
}
foreach (FieldInfo info in fieldInfos)
{
if (TryFindBehavior(info.FieldType, out ReadWriteBehavior behavior))
{
variables.Add(new CachedReflectedVariable(info, behavior, baseClassType));
}
else
{
throw new SerializationException($"Unable to serialize type \"{type}\".");
}
}
ImmutableArray<CachedReflectedVariable> array = variables.All(v => v.HasOwnAttribute) ? variables.OrderBy(v => v.Attribute.OrderKey).ToImmutableArray() : variables.ToImmutableArray();
CachedVariables.Add(type, array);
return array;
bool HasAttribute(MemberInfo info) => (info.GetCustomAttribute<NetworkSerialize>() ?? baseClassType.GetCustomAttribute<NetworkSerialize>()) != null;
}
}
/// <summary>
@@ -512,38 +615,11 @@ namespace Barotrauma
object? newObject = Activator.CreateInstance(type);
if (newObject is null) { return default!; }
PropertyInfo[] properties = type.GetProperties();
foreach (PropertyInfo info in properties)
var properties = NetSerializableProperties.GetPropertiesAndFields(type, type);
foreach (NetSerializableProperties.CachedReflectedVariable property in properties)
{
NetworkSerialize? attribute = GetAttribute(info, newObject);
if (attribute is null) { continue; }
if (NetSerializableProperties.TryFindBehavior(info.PropertyType, out var behavior))
{
object? value = behavior.ReadAction(inc, info.PropertyType, attribute);
info.SetValue(newObject, value);
}
else
{
DebugConsole.ThrowError($"Unsupported property type \"{info.PropertyType}\" in {newObject}!");
}
}
FieldInfo[] fields = type.GetFields();
foreach (FieldInfo info in fields)
{
NetworkSerialize? attribute = GetAttribute(info, newObject);
if (attribute is null) { continue; }
if (NetSerializableProperties.TryFindBehavior(info.FieldType, out var behavior))
{
object? value = behavior.ReadAction(inc, info.FieldType, attribute);
info.SetValue(newObject, value);
}
else
{
DebugConsole.ThrowError($"Unsupported field type \"{info.FieldType}\" in {newObject}!");
}
NetworkSerialize attribute = property.Attribute;
property.SetValue(newObject, property.Behavior.ReadAction(inc, property.Type, attribute));
}
return newObject;
@@ -575,39 +651,34 @@ namespace Barotrauma
/// <param name="msg">Outgoing network message</param>
public void Write(IWriteMessage msg)
{
PropertyInfo[] properties = GetType().GetProperties();
foreach (PropertyInfo info in properties)
Type type = GetType();
var properties = NetSerializableProperties.GetPropertiesAndFields(type, type);
foreach (NetSerializableProperties.CachedReflectedVariable property in properties)
{
NetworkSerialize? attribute = GetAttribute(info, this);
if (attribute is null) { continue; }
if (NetSerializableProperties.TryFindBehavior(info.PropertyType, out var behavior))
{
behavior.WriteAction(info.GetValue(this), attribute, msg);
}
else
{
throw new InvalidOperationException($"Unsupported property type \"{info.PropertyType}\" in {this}");
}
}
FieldInfo[] fields = GetType().GetFields();
foreach (FieldInfo info in fields)
{
NetworkSerialize? attribute = GetAttribute(info, this);
if (attribute is null) { continue; }
if (NetSerializableProperties.TryFindBehavior(info.FieldType, out var behavior))
{
behavior.WriteAction(info.GetValue(this), attribute, msg);
}
else
{
throw new InvalidOperationException($"Unsupported field type \"{info.FieldType}\" in {this}");
}
NetworkSerialize attribute = property.Attribute;
property.Behavior.WriteAction(property.GetValue(this), attribute, msg);
}
}
}
private static NetworkSerialize? GetAttribute(MemberInfo info, object baseClass) => info.GetCustomAttribute<NetworkSerialize>() ?? baseClass.GetType().GetCustomAttribute<NetworkSerialize>();
public static class WriteOnlyMessageExtensions
{
#if CLIENT
public static IWriteMessage WithHeader(this IWriteMessage msg, ClientPacketHeader header)
{
msg.Write((byte)header);
return msg;
}
#elif SERVER
public static IWriteMessage WithHeader(this IWriteMessage msg, ServerPacketHeader header)
{
msg.Write((byte)header);
return msg;
}
#endif
public static void Write(this IWriteMessage msg, INetSerializableStruct serializableStruct)
{
serializableStruct.Write(msg);
}
}
}
@@ -4,47 +4,16 @@ namespace Barotrauma.Networking
{
abstract class NetEntityEvent
{
public enum Type
{
Invalid,
ComponentState,
InventoryState,
Status,
Treatment,
ApplyStatusEffect,
ChangeProperty,
Control,
UpdateSkills,
Combine,
SetAttackTarget,
ExecuteAttack,
Upgrade,
AssignCampaignInteraction,
TeamChange,
ObjectiveManagerState,
AddToCrew,
UpdateExperience,
UpdateTalents,
UpdateMoney,
UpdatePermanentStats,
}
public interface IData { }
public readonly Entity Entity;
public readonly UInt16 ID;
public UInt16 EntityID
{
get;
private set;
}
public UInt16 EntityID => Entity.ID;
//arbitrary extra data that will be passed to the Write method of the serializable entity
//(the index of an itemcomponent for example)
public object[] Data
{
get;
private set;
}
public IData Data { get; private set; }
public bool Sent;
@@ -52,43 +21,18 @@ namespace Barotrauma.Networking
{
this.ID = id;
this.Entity = serializableEntity as Entity;
RefreshEntityID();
}
public void RefreshEntityID()
{
this.EntityID = this.Entity is Entity entity ? entity.ID : Entity.NullEntityID;
}
public void SetData(object[] data)
public void SetData(IData data)
{
this.Data = data;
}
public bool IsDuplicate(NetEntityEvent other)
{
if (other.Entity != this.Entity) return false;
if (other.Entity != this.Entity) { return false; }
if (Data != null && other.Data != null)
{
if (Data.Length != other.Data.Length) return false;
for (int i = 0; i < Data.Length; i++)
{
if (Data[i] == null)
{
if (other.Data[i] != null) return false;
}
else
{
if (other.Data[i] == null) return false;
if (!Data[i].Equals(other.Data[i])) return false;
}
}
return true;
}
return Data == other.Data;
return Equals(Data, other.Data);
}
}
}
@@ -38,7 +38,6 @@ namespace Barotrauma.Networking
//(otherwise the clients might read the next event in the message and think its ID
//is consecutive to the previous one, even though we skipped over this broken event)
tempBuffer.Write(Entity.NullEntityID);
tempBuffer.WritePadBits();
eventCount++;
continue;
}
@@ -53,7 +52,6 @@ namespace Barotrauma.Networking
tempBuffer.Write(e.EntityID);
tempBuffer.WriteVariableUInt32((uint)tempEventBuffer.LengthBytes);
tempBuffer.Write(tempEventBuffer.Buffer, 0, tempEventBuffer.LengthBytes);
tempBuffer.WritePadBits();
sentEvents.Add(e);
eventCount++;
@@ -61,6 +59,7 @@ namespace Barotrauma.Networking
if (eventCount > 0)
{
msg.WritePadBits();
msg.Write(eventsToSync[0].ID);
msg.Write((byte)eventCount);
msg.Write(tempBuffer.Buffer, 0, tempBuffer.LengthBytes);
@@ -6,7 +6,7 @@ using System.Linq;
namespace Barotrauma.Networking
{
enum ClientPacketHeader
public enum ClientPacketHeader
{
UPDATE_LOBBY, //update state in lobby
UPDATE_INGAME, //update state ingame
@@ -31,9 +31,10 @@ namespace Barotrauma.Networking
ERROR, //tell the server that an error occurred
CREW, //hiring UI
MEDICAL, //medical clinic
MONEY, //wallet updates
REWARD_DISTRIBUTION, // wallet reward distribution
READY_CHECK,
READY_TO_SPAWN
}
enum ClientNetObject
{
@@ -52,7 +53,7 @@ namespace Barotrauma.Networking
MISSING_ENTITY //client can't find an entity of a certain ID
}
enum ServerPacketHeader
public enum ServerPacketHeader
{
AUTH_RESPONSE, //tell the player if they require a password to log in
AUTH_FAILURE, //the server won't authorize player yet, however connection is still alive
@@ -82,6 +83,7 @@ namespace Barotrauma.Networking
EVENTACTION,
CREW, //anything related to managing bots in multiplayer
MEDICAL, //medical clinic
MONEY,
READY_CHECK //start, end and update a ready check
}
enum ServerNetObject
@@ -169,7 +171,7 @@ namespace Barotrauma.Networking
get { return false; }
}
public abstract void CreateEntityEvent(INetSerializable entity, object[] extraData = null);
public abstract void CreateEntityEvent(INetSerializable entity, NetEntityEvent.IData extraData = null);
#if DEBUG
public Dictionary<string, long> messageCount = new Dictionary<string, long>();
@@ -654,7 +654,7 @@ namespace Barotrauma.Networking
{
get
{
return lengthBits / 8;
return (LengthBits + 7) / 8;
}
}
@@ -867,7 +867,7 @@ namespace Barotrauma.Networking
{
get
{
return (LengthBits + ((8 - (LengthBits % 8)) % 8)) / 8;
return (LengthBits + 7) / 8;
}
}