BarotraumaServer compiles
Cleanup + fixes coming up next
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class EntitySpawner : Entity, IServerSerializable
|
||||
{
|
||||
public void ClientRead(ServerNetObject type, Lidgren.Network.NetBuffer message, float sendingTime)
|
||||
{
|
||||
if (GameMain.Server != null) return;
|
||||
|
||||
bool remove = message.ReadBoolean();
|
||||
|
||||
if (remove)
|
||||
{
|
||||
ushort entityId = message.ReadUInt16();
|
||||
|
||||
var entity = FindEntityByID(entityId);
|
||||
if (entity != null)
|
||||
{
|
||||
entity.Remove();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (message.ReadByte())
|
||||
{
|
||||
case (byte)SpawnableType.Item:
|
||||
Item.ReadSpawnData(message, true);
|
||||
break;
|
||||
case (byte)SpawnableType.Character:
|
||||
Character.ReadSpawnData(message, true);
|
||||
break;
|
||||
default:
|
||||
DebugConsole.ThrowError("Received invalid entity spawn message (unknown spawnable type)");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,409 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class FileReceiver
|
||||
{
|
||||
public class FileTransferIn : IDisposable
|
||||
{
|
||||
public string FileName
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public string FilePath
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public ulong FileSize
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public ulong Received
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public FileTransferType FileType
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public FileTransferStatus Status
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public float BytesPerSecond
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public float Progress
|
||||
{
|
||||
get { return Received / (float)FileSize; }
|
||||
}
|
||||
|
||||
public FileStream WriteStream
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public int TimeStarted
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public NetConnection Connection
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public int SequenceChannel;
|
||||
|
||||
public FileTransferIn(NetConnection connection, string filePath, FileTransferType fileType)
|
||||
{
|
||||
FilePath = filePath;
|
||||
FileName = Path.GetFileName(FilePath);
|
||||
FileType = fileType;
|
||||
|
||||
Connection = connection;
|
||||
|
||||
WriteStream = new FileStream(FilePath, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
TimeStarted = Environment.TickCount;
|
||||
|
||||
Status = FileTransferStatus.NotStarted;
|
||||
}
|
||||
|
||||
public void ReadBytes(NetIncomingMessage inc)
|
||||
{
|
||||
byte[] all = inc.ReadBytes(inc.LengthBytes - inc.PositionInBytes);
|
||||
Received += (ulong)all.Length;
|
||||
WriteStream.Write(all, 0, all.Length);
|
||||
|
||||
int passed = Environment.TickCount - TimeStarted;
|
||||
float psec = passed / 1000.0f;
|
||||
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
DebugConsole.Log("Received "+all.Length+" bytes of the file "+FileName+" ("+Received+"/"+FileSize+" received)");
|
||||
}
|
||||
|
||||
BytesPerSecond = Received / psec;
|
||||
|
||||
Status = Received >= FileSize ? FileTransferStatus.Finished : FileTransferStatus.Receiving;
|
||||
}
|
||||
|
||||
private bool disposed = false;
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposed) return;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
if (WriteStream != null)
|
||||
{
|
||||
WriteStream.Flush();
|
||||
WriteStream.Close();
|
||||
WriteStream.Dispose();
|
||||
WriteStream = null;
|
||||
}
|
||||
}
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
}
|
||||
|
||||
const int MaxFileSize = 1000000;
|
||||
|
||||
public delegate void OnFinishedDelegate(FileTransferIn fileStreamReceiver);
|
||||
public OnFinishedDelegate OnFinished;
|
||||
|
||||
private List<FileTransferIn> activeTransfers;
|
||||
|
||||
private string downloadFolder;
|
||||
|
||||
public List<FileTransferIn> ActiveTransfers
|
||||
{
|
||||
get { return activeTransfers; }
|
||||
}
|
||||
|
||||
public FileReceiver(string downloadFolder)
|
||||
{
|
||||
if (GameMain.Server != null)
|
||||
{
|
||||
throw new InvalidOperationException("Creating a file receiver is not allowed when a server is running.");
|
||||
}
|
||||
|
||||
activeTransfers = new List<FileTransferIn>();
|
||||
|
||||
this.downloadFolder = downloadFolder;
|
||||
}
|
||||
|
||||
public void ReadMessage(NetIncomingMessage inc)
|
||||
{
|
||||
if (GameMain.Server != null)
|
||||
{
|
||||
throw new InvalidOperationException("Receiving files when a server is running is not allowed");
|
||||
}
|
||||
|
||||
System.Diagnostics.Debug.Assert(!activeTransfers.Any(t =>
|
||||
t.Status == FileTransferStatus.Error ||
|
||||
t.Status == FileTransferStatus.Canceled ||
|
||||
t.Status == FileTransferStatus.Finished), "List of active file transfers contains entires that should have been removed");
|
||||
|
||||
byte transferMessageType = inc.ReadByte();
|
||||
switch (transferMessageType)
|
||||
{
|
||||
case (byte)FileTransferMessageType.Initiate:
|
||||
var existingTransfer = activeTransfers.Find(t => t.SequenceChannel == inc.SequenceChannel);
|
||||
if (existingTransfer != null)
|
||||
{
|
||||
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
|
||||
DebugConsole.ThrowError("File transfer error: file transfer initiated on a sequence channel that's already in use");
|
||||
return;
|
||||
}
|
||||
|
||||
byte fileType = inc.ReadByte();
|
||||
ushort chunkLen = inc.ReadUInt16();
|
||||
ulong fileSize = inc.ReadUInt64();
|
||||
string fileName = inc.ReadString();
|
||||
|
||||
string errorMsg;
|
||||
if (!ValidateInitialData(fileType, fileName, fileSize, out errorMsg))
|
||||
{
|
||||
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
|
||||
DebugConsole.ThrowError("File transfer failed (" + errorMsg + ")");
|
||||
return;
|
||||
}
|
||||
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
DebugConsole.Log("Received file transfer initiation message: ");
|
||||
DebugConsole.Log(" File: "+fileName);
|
||||
DebugConsole.Log(" Size: " + fileSize);
|
||||
DebugConsole.Log(" Sequence channel: " + inc.SequenceChannel);
|
||||
}
|
||||
|
||||
if (!Directory.Exists(downloadFolder))
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(downloadFolder);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Could not start a file transfer: failed to create the folder \""+downloadFolder+"\".", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var newTransfer = new FileTransferIn(inc.SenderConnection, Path.Combine(downloadFolder, fileName), (FileTransferType)fileType);
|
||||
newTransfer.SequenceChannel = inc.SequenceChannel;
|
||||
newTransfer.Status = FileTransferStatus.Receiving;
|
||||
newTransfer.FileSize = fileSize;
|
||||
|
||||
activeTransfers.Add(newTransfer);
|
||||
|
||||
break;
|
||||
case (byte)FileTransferMessageType.Data:
|
||||
var activeTransfer = activeTransfers.Find(t => t.Connection == inc.SenderConnection && t.SequenceChannel == inc.SequenceChannel);
|
||||
if (activeTransfer == null)
|
||||
{
|
||||
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
|
||||
DebugConsole.ThrowError("File transfer error: received data without a transfer initiation message");
|
||||
return;
|
||||
}
|
||||
|
||||
if (activeTransfer.Received + (ulong)(inc.LengthBytes-inc.PositionInBytes) > activeTransfer.FileSize)
|
||||
{
|
||||
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
|
||||
DebugConsole.ThrowError("File transfer error: Received more data than expected");
|
||||
activeTransfer.Status = FileTransferStatus.Error;
|
||||
StopTransfer(activeTransfer);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
activeTransfer.ReadBytes(inc);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
|
||||
DebugConsole.ThrowError("File transfer error: "+e.Message);
|
||||
activeTransfer.Status = FileTransferStatus.Error;
|
||||
StopTransfer(activeTransfer, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (activeTransfer.Status == FileTransferStatus.Finished)
|
||||
{
|
||||
activeTransfer.Dispose();
|
||||
|
||||
string errorMessage = "";
|
||||
if (ValidateReceivedData(activeTransfer, out errorMessage))
|
||||
{
|
||||
OnFinished(activeTransfer);
|
||||
StopTransfer(activeTransfer);
|
||||
}
|
||||
else
|
||||
{
|
||||
new GUIMessageBox("File transfer aborted", errorMessage);
|
||||
|
||||
activeTransfer.Status = FileTransferStatus.Error;
|
||||
StopTransfer(activeTransfer, true);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case (byte)FileTransferMessageType.Cancel:
|
||||
byte sequenceChannel = inc.ReadByte();
|
||||
var matchingTransfer = activeTransfers.Find(t => t.Connection == inc.SenderConnection && t.SequenceChannel == sequenceChannel);
|
||||
if (matchingTransfer != null)
|
||||
{
|
||||
new GUIMessageBox("File transfer cancelled", "The server has cancelled the transfer of the file \"" + matchingTransfer.FileName + "\".");
|
||||
StopTransfer(matchingTransfer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private bool ValidateInitialData(byte type, string fileName, ulong fileSize, out string errorMessage)
|
||||
{
|
||||
errorMessage = "";
|
||||
|
||||
if (fileSize > MaxFileSize)
|
||||
{
|
||||
errorMessage = "File too large (" + MathUtils.GetBytesReadable((long)fileSize) + ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Enum.IsDefined(typeof(FileTransferType), (int)type))
|
||||
{
|
||||
errorMessage = "Unknown file type";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(fileName) ||
|
||||
fileName.IndexOfAny(Path.GetInvalidFileNameChars()) > -1)
|
||||
{
|
||||
errorMessage = "Illegal characters in file name ''" + fileName + "''";
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case (byte)FileTransferType.Submarine:
|
||||
if (Path.GetExtension(fileName) != ".sub")
|
||||
{
|
||||
errorMessage = "Wrong file extension ''" + Path.GetExtension(fileName) + "''! (Expected .sub)";
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ValidateReceivedData(FileTransferIn fileTransfer, out string ErrorMessage)
|
||||
{
|
||||
ErrorMessage = "";
|
||||
switch (fileTransfer.FileType)
|
||||
{
|
||||
case FileTransferType.Submarine:
|
||||
Stream stream = null;
|
||||
|
||||
try
|
||||
{
|
||||
stream = SaveUtil.DecompressFiletoStream(fileTransfer.FilePath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ErrorMessage = "Loading received submarine ''" + fileTransfer.FileName + "'' failed! {" + e.Message + "}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stream == null)
|
||||
{
|
||||
ErrorMessage = "Decompressing received submarine file''" + fileTransfer.FilePath + "'' failed!";
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
stream.Position = 0;
|
||||
|
||||
XmlReaderSettings settings = new XmlReaderSettings();
|
||||
settings.DtdProcessing = DtdProcessing.Prohibit;
|
||||
settings.IgnoreProcessingInstructions = true;
|
||||
|
||||
using (var reader = XmlReader.Create(stream, settings))
|
||||
{
|
||||
while (reader.Read());
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
stream.Close();
|
||||
stream.Dispose();
|
||||
|
||||
ErrorMessage = "Parsing file ''" + fileTransfer.FilePath + "'' failed! The file may not be a valid submarine file.";
|
||||
return false;
|
||||
}
|
||||
|
||||
stream.Close();
|
||||
stream.Dispose();
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void StopTransfer(FileTransferIn transfer, bool deleteFile = false)
|
||||
{
|
||||
if (transfer.Status != FileTransferStatus.Finished &&
|
||||
transfer.Status != FileTransferStatus.Error)
|
||||
{
|
||||
transfer.Status = FileTransferStatus.Canceled;
|
||||
}
|
||||
|
||||
if (activeTransfers.Contains(transfer)) activeTransfers.Remove(transfer);
|
||||
transfer.Dispose();
|
||||
|
||||
if (deleteFile && File.Exists(transfer.FilePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(transfer.FilePath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to delete file \""+transfer.FilePath+"\" ("+e.Message+")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class ClientEntityEventManager : NetEntityEventManager
|
||||
{
|
||||
private List<ClientEntityEvent> events;
|
||||
|
||||
private UInt16 ID;
|
||||
|
||||
private GameClient thisClient;
|
||||
|
||||
//when was a specific entity event last sent to the client
|
||||
// key = event id, value = NetTime.Now when sending
|
||||
public Dictionary<UInt16, float> eventLastSent;
|
||||
|
||||
public UInt16 LastReceivedID
|
||||
{
|
||||
get { return lastReceivedID; }
|
||||
}
|
||||
|
||||
private UInt16 lastReceivedID;
|
||||
|
||||
public ClientEntityEventManager(GameClient client)
|
||||
{
|
||||
events = new List<ClientEntityEvent>();
|
||||
eventLastSent = new Dictionary<UInt16, float>();
|
||||
|
||||
thisClient = client;
|
||||
}
|
||||
|
||||
public void CreateEvent(IClientSerializable entity, object[] extraData = null)
|
||||
{
|
||||
if (GameMain.Client == null || GameMain.Client.Character == null) return;
|
||||
|
||||
if (!(entity is Entity))
|
||||
{
|
||||
DebugConsole.ThrowError("Can't create an entity event for " + entity + "!");
|
||||
return;
|
||||
}
|
||||
|
||||
ID++;
|
||||
var newEvent = new ClientEntityEvent(entity, ID);
|
||||
newEvent.CharacterStateID = GameMain.Client.Character.LastNetworkUpdateID;
|
||||
if (extraData != null) newEvent.SetData(extraData);
|
||||
|
||||
events.Add(newEvent);
|
||||
}
|
||||
|
||||
public void Write(NetOutgoingMessage msg, NetConnection serverConnection)
|
||||
{
|
||||
if (events.Count == 0 || serverConnection == null) return;
|
||||
|
||||
List<NetEntityEvent> eventsToSync = new List<NetEntityEvent>();
|
||||
|
||||
//find the index of the first event the server hasn't received
|
||||
int startIndex = events.Count;
|
||||
while (startIndex > 0 &&
|
||||
NetIdUtils.IdMoreRecent(events[startIndex-1].ID,thisClient.LastSentEntityEventID))
|
||||
{
|
||||
startIndex--;
|
||||
}
|
||||
|
||||
for (int i = startIndex; i < events.Count; i++)
|
||||
{
|
||||
//find the first event that hasn't been sent in 1.5 * roundtriptime or at all
|
||||
float lastSent = 0;
|
||||
eventLastSent.TryGetValue(events[i].ID, out lastSent);
|
||||
|
||||
if (lastSent > NetTime.Now - serverConnection.AverageRoundtripTime * 1.5f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
eventsToSync.AddRange(events.GetRange(i, events.Count - i));
|
||||
break;
|
||||
}
|
||||
if (eventsToSync.Count == 0) return;
|
||||
|
||||
//too many events for one packet
|
||||
if (eventsToSync.Count > MaxEventsPerWrite)
|
||||
{
|
||||
eventsToSync.RemoveRange(MaxEventsPerWrite, eventsToSync.Count - MaxEventsPerWrite);
|
||||
}
|
||||
if (eventsToSync.Count == 0) return;
|
||||
|
||||
foreach (NetEntityEvent entityEvent in eventsToSync)
|
||||
{
|
||||
eventLastSent[entityEvent.ID] = (float)NetTime.Now;
|
||||
}
|
||||
|
||||
msg.Write((byte)ClientNetObject.ENTITY_STATE);
|
||||
Write(msg, eventsToSync);
|
||||
}
|
||||
|
||||
private UInt16? firstNewID;
|
||||
|
||||
/// <summary>
|
||||
/// Read the events from the message, ignoring ones we've already received
|
||||
/// </summary>
|
||||
public void Read(ServerNetObject type, NetIncomingMessage msg, float sendingTime)
|
||||
{
|
||||
UInt16 unreceivedEntityEventCount = 0;
|
||||
|
||||
if (type == ServerNetObject.ENTITY_EVENT_INITIAL)
|
||||
{
|
||||
unreceivedEntityEventCount = msg.ReadUInt16();
|
||||
firstNewID = msg.ReadUInt16();
|
||||
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
DebugConsole.NewMessage(
|
||||
"received midround syncing msg, unreceived: " + unreceivedEntityEventCount +
|
||||
", first new ID: " + firstNewID, Microsoft.Xna.Framework.Color.Yellow);
|
||||
}
|
||||
}
|
||||
else if (firstNewID != null)
|
||||
{
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
DebugConsole.NewMessage("midround syncing complete, switching to ID " + (UInt16) (firstNewID - 1),
|
||||
Microsoft.Xna.Framework.Color.Yellow);
|
||||
}
|
||||
|
||||
lastReceivedID = (UInt16)(firstNewID - 1);
|
||||
firstNewID = null;
|
||||
}
|
||||
|
||||
UInt16 firstEventID = msg.ReadUInt16();
|
||||
int eventCount = msg.ReadByte();
|
||||
|
||||
for (int i = 0; i < eventCount; i++)
|
||||
{
|
||||
UInt16 thisEventID = (UInt16)(firstEventID + (UInt16)i);
|
||||
UInt16 entityID = msg.ReadUInt16();
|
||||
|
||||
if (entityID == 0 && thisEventID == (UInt16)(lastReceivedID + 1))
|
||||
{
|
||||
msg.ReadPadBits();
|
||||
lastReceivedID++;
|
||||
continue;
|
||||
}
|
||||
|
||||
byte msgLength = msg.ReadByte();
|
||||
|
||||
IServerSerializable entity = Entity.FindEntityByID(entityID) as IServerSerializable;
|
||||
|
||||
//skip the event if we've already received it or if the entity isn't found
|
||||
if (thisEventID != (UInt16)(lastReceivedID + 1) || entity == null)
|
||||
{
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
if (thisEventID != (UInt16) (lastReceivedID + 1))
|
||||
{
|
||||
DebugConsole.NewMessage(
|
||||
"received msg " + thisEventID + " (waiting for " + (lastReceivedID + 1) + ")",
|
||||
thisEventID < lastReceivedID + 1
|
||||
? Microsoft.Xna.Framework.Color.Yellow
|
||||
: Microsoft.Xna.Framework.Color.Red);
|
||||
}
|
||||
else if (entity == null)
|
||||
{
|
||||
DebugConsole.NewMessage(
|
||||
"received msg " + thisEventID + ", entity " + entityID + " not found",
|
||||
Microsoft.Xna.Framework.Color.Red);
|
||||
}
|
||||
}
|
||||
msg.Position += msgLength * 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
long msgPosition = msg.Position;
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
DebugConsole.NewMessage("received msg " + thisEventID + " (" + entity.ToString() + ")",
|
||||
Microsoft.Xna.Framework.Color.Green);
|
||||
}
|
||||
lastReceivedID++;
|
||||
try
|
||||
{
|
||||
ReadEvent(msg, entity, sendingTime);
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to read event for entity \"" + entity.ToString() + "!", e);
|
||||
}
|
||||
msg.Position = msgPosition + msgLength * 8;
|
||||
}
|
||||
}
|
||||
msg.ReadPadBits();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void WriteEvent(NetBuffer buffer, NetEntityEvent entityEvent, Client recipient = null)
|
||||
{
|
||||
var clientEvent = entityEvent as ClientEntityEvent;
|
||||
if (clientEvent == null) return;
|
||||
|
||||
clientEvent.Write(buffer);
|
||||
}
|
||||
|
||||
protected void ReadEvent(NetIncomingMessage buffer, IServerSerializable entity, float sendingTime)
|
||||
{
|
||||
entity.ClientRead(ServerNetObject.ENTITY_EVENT, buffer, sendingTime);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
ID = 0;
|
||||
|
||||
lastReceivedID = 0;
|
||||
|
||||
firstNewID = null;
|
||||
|
||||
events.Clear();
|
||||
eventLastSent.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class ClientEntityEvent : NetEntityEvent
|
||||
{
|
||||
private IClientSerializable serializable;
|
||||
|
||||
public UInt16 CharacterStateID;
|
||||
|
||||
public ClientEntityEvent(IClientSerializable entity, UInt16 id)
|
||||
: base(entity, id)
|
||||
{
|
||||
serializable = entity;
|
||||
}
|
||||
|
||||
public void Write(NetBuffer msg)
|
||||
{
|
||||
msg.Write(CharacterStateID);
|
||||
serializable.ClientWrite(msg, Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user