public static string GetClientAlertSubject(ClientMessageType alertType, Job job) { string subject = String.Empty; switch (alertType) { case ClientMessageType.Estimate: subject = "Estimate for Work Request - No. " + job.JobId.ToString(); break; case ClientMessageType.JobCanceled: subject = "Notice of Job Cancellation - Job No. " + job.JobId.ToString(); break; case ClientMessageType.JobCompleted: subject = "Notice of Job Completion - Job No. " + job.JobId.ToString(); break; case ClientMessageType.JobDeclined: subject = "Unable to Accept Work Request - No. " + job.JobId.ToString(); break; case ClientMessageType.General: subject = "Notice Regarding Job No. " + job.JobId.ToString(); break; } return(subject); }
/// <summary> /// Called when replying to messages recieved from the client /// </summary> private void SendReplyMessage(NetConnection netConnection, ClientMessageType messageType, int feedback, string jsonBody = null) { //Determine how to send the data DetermineMethodandChannel(messageType, out NetDeliveryMethod deliverymethod, out int?sequenceChannel); //Send the message lidgrenServer.SendMessage(false, (byte)messageType, netConnection, deliverymethod, feedback, sequenceChannel, jsonBody); }
/// <summary> /// Sends data over the connection asynchronously. /// </summary> /// <param name="buffer">The buffer to be sent over the connection.</param> /// <param name="messageType">TIndicates whether the application is sending a binary or text message.</param> /// <param name="endOfMessage">Indicates whether the data in "buffer" is the last part of a message.</param> /// <param name="cancellationToken">The token that propagates the notification that operations should be canceled.</param> /// <returns>Task.</returns> public Task SendAsync(ArraySegment <byte> buffer, ClientMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) { return(_webSocket.SendAsync( buffer, messageType.ToWebSocketMessageType(), endOfMessage, cancellationToken)); }
/// <summary> /// Called when creating a new message from the server /// </summary> private void SendNewMessage(ClientMessageType messageType, string jsonBody = null) { //Determine how to send the data DetermineMethodandChannel(messageType, out NetDeliveryMethod deliverymethod, out int?sequenceChannel); //Send the message lidgrenClient.SendMessage(true, (byte)messageType, deliverymethod, null, sequenceChannel, jsonBody); }
public TestClientSettings(string host, int concurrentClients, int totalClients, int requestsPerClient, ClientMessageType messageType) { Host = host; ConcurrentClients = concurrentClients; TotalClients = totalClients; RequestsPerClient = requestsPerClient; MessageType = messageType; }
public void SendBytes(ClientMessageType type, byte[] msg) { byte[] buffer = new byte[msg.Length + 1]; buffer[0] = (byte)type; msg.CopyTo(buffer, 1); stream.Write(buffer, 0, buffer.Length); }
public static Offset <ClientMessage> CreateClientMessage(FlatBufferBuilder builder, ushort clientId = 0, ClientMessageType msg_type = ClientMessageType.NONE, int msgOffset = 0) { builder.StartObject(3); ClientMessage.AddMsg(builder, msgOffset); ClientMessage.AddClientId(builder, clientId); ClientMessage.AddMsgType(builder, msg_type); return(ClientMessage.EndClientMessage(builder)); }
/// <summary> /// Messages from client to server. /// </summary> /// <param name="message"></param> private void OnClientDispatch(object sender, NetworkMessageEventArgs e) { ClientMessageType clientMessageType = (ClientMessageType)e.Message.Type; switch (clientMessageType) { case ClientMessageType.GameAction: DispatchGameAction(e.Message); break; } }
/// <summary> /// Sends data over the connection asynchronously. /// </summary> /// <param name="buffer">The buffer to be sent over the connection.</param> /// <param name="messageType">TIndicates whether the application is sending a binary or text message.</param> /// <param name="endOfMessage">Indicates whether the data in "buffer" is the last part of a message.</param> /// <param name="cancellationToken">The token that propagates the notification that operations should be canceled.</param> /// <returns>Task.</returns> public Task SendAsync(ArraySegment <byte> buffer, ClientMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) { var message = new MockClientMessage(buffer.ToArray(), messageType, endOfMessage); lock (_outgoingMessageQueue) { _outgoingMessageQueue.Enqueue(message); } return(Task.CompletedTask); }
/// <summary> /// Initializes a new instance of the <see cref="MockClientMessage" /> class. /// </summary> /// <param name="data">The data.</param> /// <param name="messageType">Type of the message.</param> /// <param name="isEndOfMessage">The is end of message.</param> /// <param name="closeStatus">The close status.</param> /// <param name="closeDescription">The close description.</param> public MockClientMessage( byte[] data, ClientMessageType messageType, bool isEndOfMessage = false, ClientConnectionCloseStatus?closeStatus = null, string closeDescription = null) { this.Data = data; this.MessageType = messageType; this.CloseStatus = closeStatus; this.CloseStatusDescription = closeDescription; }
/// <summary> /// Initializes a new instance of the <see cref="MockClientMessageResult" /> class. /// </summary> /// <param name="byteCount">The byte count.</param> /// <param name="messageType">Type of the message.</param> /// <param name="isEndOfMessage">The is end of message.</param> /// <param name="closeStatus">The close status.</param> /// <param name="closeDescription">The close description.</param> public MockClientMessageResult( int byteCount, ClientMessageType messageType, bool isEndOfMessage = false, ClientConnectionCloseStatus?closeStatus = null, string closeDescription = null) { this.Count = byteCount; this.MessageType = messageType; this.CloseStatus = closeStatus; this.CloseStatusDescription = closeDescription; this.EndOfMessage = isEndOfMessage; }
public void RecordSend(byte[] data, ClientMessageType messageType) { if (!active) { return; } using (MessageWriter mw = new MessageWriter()) { mw.Write <int>((int)messageType); mw.Write <int>(data.Length); byte[] headerData = mw.GetMessageBytes(); recording.Write(headerData, 0, headerData.Length); } recording.Write(data, 0, data.Length); }
public ClientMessage(ClientMessageType Type) { MessageType = Type; if (MyAPIGateway.Multiplayer != null && !MyAPIGateway.Multiplayer.IsServer) { if (MyAPIGateway.Session.LocalHumanPlayer == null) { return; } IdentityID = MySession.Static?.LocalHumanPlayer?.Identity?.IdentityId ?? 0; SteamID = MySession.Static?.LocalHumanPlayer?.Id.SteamId ?? 0; PluginVersion = SeamlessClient.Version; } }
/// <summary> /// Sends data to the <see cref="INetworkSender"/>. This method is thread-safe. /// </summary> /// <param name="sender">The <see cref="INetworkSender"/> to use to send the data.</param> /// <param name="data">BitStream containing the data to send to the User.</param> /// <param name="messageType">The <see cref="ClientMessageType"/> to use for sending the <paramref name="data"/>.</param> public static void Send(this INetworkSender sender, BitStream data, ClientMessageType messageType) { if (!sender.IsConnected) { const string errmsg = "Send to `{0}` failed - not connected."; if (log.IsErrorEnabled) log.ErrorFormat(errmsg, sender); Debug.Fail(string.Format(errmsg, sender)); return; } NetDeliveryMethod method; int seqChannel; messageType.GetDeliveryMethod(out method, out seqChannel); sender.Send(data, method, seqChannel); }
public byte[] ConstructClientGoodbye(ClientMessageType type, ushort clientId) { fbBuilder.Clear(); ClientGoodbye.StartClientGoodbye(fbBuilder); Offset <ClientGoodbye> clientGoodbyeOffset = ClientGoodbye.EndClientGoodbye(fbBuilder); ClientMessage.StartClientMessage(fbBuilder); //var clientIdOffset = clientId; ClientMessage.AddClientId(fbBuilder, clientId); ClientMessage.AddMsgType(fbBuilder, type); ClientMessage.AddMsg(fbBuilder, clientGoodbyeOffset.Value); Offset <ClientMessage> clientMessageOffset = ClientMessage.EndClientMessage(fbBuilder); ClientMessage.FinishClientMessageBuffer(fbBuilder, clientMessageOffset); return(fbBuilder.SizedByteArray()); }
public void RecordSend(ByteArray data, ClientMessageType messageType, Guid vesselID) { if (!active) { return; } if (HighLogic.LoadedSceneIsFlight && FlightGlobals.fetch != null && FlightGlobals.fetch.activeVessel != null && FlightGlobals.fetch.activeVessel.id == vesselID) { using (MessageWriter mw = new MessageWriter()) { mw.Write <int>((int)messageType); mw.Write <int>(data.Length); byte[] headerData = mw.GetMessageBytes(); recording.Write(headerData, 0, headerData.Length); } recording.Write(data.data, 0, data.Length); } }
public byte[] ConstructTickAck(ClientMessageType type, ushort clientId, uint tick) { fbBuilder.Clear(); TickAck.StartTickAck(fbBuilder); TickAck.AddTick(fbBuilder, tick); Offset <TickAck> tickAckOffset = TickAck.EndTickAck(fbBuilder); ClientMessage.StartClientMessage(fbBuilder); //var clientIdOffset = clientId; ClientMessage.AddClientId(fbBuilder, clientId); ClientMessage.AddMsgType(fbBuilder, type); ClientMessage.AddMsg(fbBuilder, tickAckOffset.Value); Offset <ClientMessage> clientMessageOffset = ClientMessage.EndClientMessage(fbBuilder); ClientMessage.FinishClientMessageBuffer(fbBuilder, clientMessageOffset); return(fbBuilder.SizedByteArray()); }
/* Documentation on Delivery Methods * Unreliable This is just UDP. Messages can be lost or received more than once. * Messages may not be received in the same order as they were sent. * * UnreliableSequenced Using this delivery method messages can still be lost; but you're protected against duplicated messages. * If a message arrives late; that is, if a message sent after this one has already been received - it will be dropped. * This means you will never receive "older" data than what you already have received. * * ReliableUnordered This delivery method ensures that every message sent will be eventually received. * It does not however guarantee what order they will be received in; late messages may be delivered before newer ones. * * ReliableSequenced This delivery method is similar to UnreliableSequenced; except that it guarantees that SOME messages will be received * - if you only send one message - it will be received. * If you sent two messages quickly, and they get reordered in transit, only the newest message will be received * - but at least ONE of them will be received. * * ReliableOrdered This delivery method guarantees that messages will always be received in the exact order they were sent. */ public static void DetermineMethodandChannel(ClientMessageType messageType, out NetDeliveryMethod deliverymethod, out int?sequenceChannel) { //Determine the delivery type and if needed, the sequence channel sequenceChannel = null; switch (messageType) { case ClientMessageType.Beat: throw new Exception("Shouldn't be sending beats this way (Specific beat function that recycles message)"); case ClientMessageType.SendName: deliverymethod = NetDeliveryMethod.ReliableOrdered; sequenceChannel = 0; break; default: throw new Exception("Could not determine datatype"); } }
void ILidgrenClientEvents.HandleReplyMessage(ClientMessageType messageType, int feedback, string jsonBody) { try { //Switch on the message type and have it handled by specific methods so as to not clutter this area switch (messageType) { case ClientMessageType.SendName: SendNameReply?.Invoke(feedback, jsonBody); break; default: throw new Exception($"Unhandled message type {messageType}"); } } catch (Exception ex) { LogMessage($"Error handling reply message type {messageType} with feedback {feedback}, error: {ex.Message}"); } }
/// <summary> /// Sends data to the <see cref="INetworkSender"/>. This method is thread-safe. /// </summary> /// <param name="sender">The <see cref="INetworkSender"/> to use to send the data.</param> /// <param name="data">BitStream containing the data to send to the User.</param> /// <param name="messageType">The <see cref="ClientMessageType"/> to use for sending the <paramref name="data"/>.</param> public static void Send(this INetworkSender sender, BitStream data, ClientMessageType messageType) { if (!sender.IsConnected) { const string errmsg = "Send to `{0}` failed - not connected."; if (log.IsErrorEnabled) { log.ErrorFormat(errmsg, sender); } Debug.Fail(string.Format(errmsg, sender)); return; } NetDeliveryMethod method; int seqChannel; messageType.GetDeliveryMethod(out method, out seqChannel); sender.Send(data, method, seqChannel); }
public byte[] ConstructClientHello(ClientMessageType type, ushort clientId, string playerName) { fbBuilder.Clear(); StringOffset playerNameOffset = fbBuilder.CreateString(playerName); ClientHello.StartClientHello(fbBuilder); ClientHello.AddPlayerName(fbBuilder, playerNameOffset); Offset <ClientHello> clientHelloOffset = ClientHello.EndClientHello(fbBuilder); ClientMessage.StartClientMessage(fbBuilder); //var clientIdOffset = clientId; ClientMessage.AddClientId(fbBuilder, clientId); ClientMessage.AddMsgType(fbBuilder, type); ClientMessage.AddMsg(fbBuilder, clientHelloOffset.Value); Offset <ClientMessage> clientMessageOffset = ClientMessage.EndClientMessage(fbBuilder); ClientMessage.FinishClientMessageBuffer(fbBuilder, clientMessageOffset); return(fbBuilder.SizedByteArray()); }
public override bool Handle(ClientMessageType messageType, uint clientId, byte[] buffer, int count) { if (!_messageTypeMapping.TryGetValue(messageType, out var clientMessageType)) { return(false); } if (!_handlerMethods.TryGetValue(messageType, out var handlerMethod)) { return(false); } var buff = new ArraySegment <byte>(buffer, 1, count).ToArray(); var gcHandle = GCHandle.Alloc(buff, GCHandleType.Pinned); var clientMessage = (IClientMessage)Marshal.PtrToStructure(gcHandle.AddrOfPinnedObject(), clientMessageType); gcHandle.Free(); handlerMethod.Invoke(clientId, clientMessage); return(true); }
public byte[] ConstructClientInputState(ClientMessageType type, ushort clientId, uint tick, Vector3 desiredMove, bool isTurbo) { fbBuilder.Clear(); ClientInputState.StartClientInputState(fbBuilder); ClientInputState.AddTick(fbBuilder, tick); ClientInputState.AddDesiredMove(fbBuilder, Vec2.CreateVec2(fbBuilder, desiredMove.x, desiredMove.y)); ClientInputState.AddIsTurbo(fbBuilder, isTurbo); Offset <ClientInputState> clientInputStateOffset = ClientInputState.EndClientInputState(fbBuilder); ClientMessage.StartClientMessage(fbBuilder); //var clientIdOffset = clientId; ClientMessage.AddClientId(fbBuilder, clientId); ClientMessage.AddMsgType(fbBuilder, type); ClientMessage.AddMsg(fbBuilder, clientInputStateOffset.Value); Offset <ClientMessage> clientMessageOffset = ClientMessage.EndClientMessage(fbBuilder); ClientMessage.FinishClientMessageBuffer(fbBuilder, clientMessageOffset); return(fbBuilder.SizedByteArray()); }
public void ToClientMessageType(WebSocketMessageType messageType, ClientMessageType expectedType) { Assert.AreEqual(expectedType, messageType.ToClientMessageType()); }
public ClientMessage(ClientMessageType type, params string[] messages) : this() { MessageType = type; Messages.AddRange(messages.Where(x => !x.IsNullOrEmpty())); }
public ClientMessageTypeAttribute(ClientMessageType clientMessageType) { ClientMessageType = clientMessageType; }
/// <summary> /// Handles data messages (reads the message and outputs to interface) /// </summary> /// <param name="incomingMessage"></param> private void HandleMessageData(NetIncomingMessage incomingMessage) { //Determine if it is a new message from the client network object (true) or a reply to a message from the server (false) bool newMessage = incomingMessage.ReadBoolean(); //Determine if there is a body to read bool bodyToRead = incomingMessage.ReadBoolean(); //Consume the pad bits incomingMessage.ReadPadBits(); //Determine the message type int messageType = incomingMessage.ReadByte(); //If a beat then do nothing if (messageType == 0) { //Log the message lidgrenConsoleOutputGUI.WriteConsole($"Received beat", LogLevel.Everything); //Abort further processing return; } int?feedback = null; //If it is a reply message if (!newMessage) { //Read the feedback feedback = incomingMessage.ReadByte(); } string jsonBody = null; //If there is a body if (bodyToRead) { int bodylength = incomingMessage.ReadInt32(); //Read the body byte[] bodyBytes = incomingMessage.ReadBytes(bodylength); //Decode the body jsonBody = Encoding.UTF8.GetString(bodyBytes); } //Handle the message type accordingly if (newMessage) { //Cast to the enum ServerMessageType serverMessageType = (ServerMessageType)messageType; //Log the message if (jsonBody == null) { lidgrenConsoleOutputGUI.WriteConsole($"Received new message with type {serverMessageType} and no body", LogLevel.High); } else { lidgrenConsoleOutputGUI.WriteConsole($"Received new message with type {serverMessageType} and body {jsonBody}", LogLevel.High); } //Activate the event lidgrenClientEvents.HandleNewMessage(serverMessageType, jsonBody); } else { //Cast to the enum ClientMessageType clientMessageType = (ClientMessageType)messageType; //Log the message if (jsonBody == null) { lidgrenConsoleOutputGUI.WriteConsole($"Received reply message with type {clientMessageType} and feedback {feedback} and no body", LogLevel.High); } else { lidgrenConsoleOutputGUI.WriteConsole($"Received reply message with type {clientMessageType} and feedback {feedback} and body {jsonBody}", LogLevel.High); } if (feedback == null) { //Log the message lidgrenConsoleOutputGUI.WriteConsole($"Aborting processing of message type {clientMessageType} as feedback is null", LogLevel.Medium); //Don't handle any further return; } //Activate the event lidgrenClientEvents.HandleReplyMessage(clientMessageType, (int)feedback, jsonBody); } }
/// <summary> /// Sends a message using the lidgren connection /// </summary> /// <param name="newMessageFromClient">Set to true when it is a new message from the client and not a reply</param> /// <param name="messageType">Based on the enum in the owner class (Note: limited to 256 types)</param> /// <param name="deliverymethod">The delivery method to use</param> /// <param name="feedback">This is required if it is a reply type message</param> /// <param name="sequenceChannel"></param> /// <param name="body"></param> void ILidgrenClient.SendMessage(bool newMessageFromClient, byte messageType, NetDeliveryMethod deliverymethod, int?feedback, int?sequenceChannel, string jsonBody) { //Log the message if (newMessageFromClient) { //Cast to the enum ClientMessageType clientMessageType = (ClientMessageType)messageType; //Log the message if (jsonBody == null) { lidgrenConsoleOutputGUI.WriteConsole($"Sending new message with type {clientMessageType} and no body", LogLevel.High); } else { lidgrenConsoleOutputGUI.WriteConsole($"Sending new message with type {clientMessageType} and body {jsonBody}", LogLevel.High); } } else { //Cast to the enum ServerMessageType serverMessageType = (ServerMessageType)messageType; lidgrenConsoleOutputGUI.WriteConsole($"Sending reply message with type {serverMessageType} and feedback {feedback} and body {jsonBody}", LogLevel.High); } //If there is a jsonBody then convert it to a byte array body, otherwise set to null byte[] body = jsonBody == null ? null : Encoding.UTF8.GetBytes(jsonBody); //Create a new message NetOutgoingMessage outgoingMessage = netClient.CreateMessage(); //Write whether it is a new message from the client (true) or a reply to a message from the server (false) outgoingMessage.Write(newMessageFromClient); //Write true if a body exists to read outgoingMessage.Write(body != null); //Pad so that future reading is easily done outgoingMessage.WritePadBits(); //Write the message type (note it's been squished to 8 bits therefore max 256 message types) outgoingMessage.Write(messageType); //If it is a reply message if (!newMessageFromClient) { if (feedback != null) { //Write the feedback (note again 8 bit so max 256 types) outgoingMessage.Write((byte)feedback); } else { throw new Exception("Feedback not provided but is necessary for reply type message!"); } } //If a body exists if (body != null) { //Write the body length outgoingMessage.Write(body.Length); //Write the body outgoingMessage.Write(body); } /* * There is an override for SendMessage() which takes an integer called 'sequenceChannel' * - this can be used for certain delivery methods, namely UnreliableSequenced, ReliableSequenced and ReliableOrdered. * * The sequence channel is a number between 0 and (NetConstants.NetChannelsPerDeliveryMethod - 1) - currently 31. * The reason for this limitation is to reduce the amount of overhead per message.Note that there are this amount of channels per delivery method, not in total. * * Messages sent in a certain sequence channel will be dropped/withheld independently of messages sent in a different sequence channel. */ switch (deliverymethod) { case NetDeliveryMethod.UnreliableSequenced: case NetDeliveryMethod.ReliableSequenced: case NetDeliveryMethod.ReliableOrdered: if (sequenceChannel != null) { netClient.SendMessage(outgoingMessage, deliverymethod, (int)sequenceChannel); } else { throw new Exception("Trying to send a message without specifying the required sequence channel"); } break; default: netClient.SendMessage(outgoingMessage, deliverymethod); break; } }
protected ClientMessage(ClientMessageType type) { this.MessageType = type; }
public void StartPlayback() { int messagesLoaded = 0; bool firstMessage = true; ByteArray headerBytes = ByteRecycler.GetObject(8); using (FileStream fs = new FileStream(recordPath, FileMode.Open)) { while (fs.Position < fs.Length) { messagesLoaded++; fs.Read(headerBytes.data, 0, 8); using (MessageReader mr = new MessageReader(headerBytes.data)) { ClientMessageType messageType = (ClientMessageType)mr.Read <int>(); int length = mr.Read <int>(); ByteArray dataBytes = ByteRecycler.GetObject(length); fs.Read(dataBytes.data, 0, length); using (MessageReader timeReader = new MessageReader(dataBytes.data)) { //Planet time is the first part of the message for the three types we care about here double planetTime = timeReader.Read <double>(); lastTime = planetTime; if (firstMessage) { firstTime = planetTime; firstMessage = false; Planetarium.SetUniversalTime(planetTime - 5d); warpWorker.SendNewSubspace(); } } using (MessageReader mrignore = new MessageReader(dataBytes.data)) { //Planet time, don't care here mrignore.Read <double>(); string vesselID = mrignore.Read <string>(); vesselWorker.IgnoreVessel(new Guid(vesselID)); } switch (messageType) { case ClientMessageType.VESSEL_PROTO: HandleProtoUpdate(dataBytes); break; case ClientMessageType.VESSEL_UPDATE: HandleVesselUpdate(dataBytes, false); break; case ClientMessageType.VESSEL_REMOVE: HandleVesselRemove(dataBytes); break; default: break; } ByteRecycler.ReleaseObject(dataBytes); } } ByteRecycler.ReleaseObject(headerBytes); } playbackQueue = new Queue <VesselUpdate>(); using (FileStream fs = new FileStream(recordVectorPath, FileMode.Open)) { while (fs.Position < fs.Length) { fs.Read(headerBytesInt, 0, 4); if (BitConverter.IsLittleEndian) { Array.Reverse(headerBytesInt); } int updateLength = BitConverter.ToInt32(headerBytesInt, 0); ByteArray updateBytes = ByteRecycler.GetObject(updateLength); fs.Read(updateBytes.data, 0, updateLength); VesselUpdate vu = networkWorker.VeselUpdateFromBytes(updateBytes.data, false); playbackQueue.Enqueue(vu); ByteRecycler.ReleaseObject(updateBytes); } } ScreenMessages.PostScreenMessage("Loaded " + messagesLoaded + " saved updates.", 5f, ScreenMessageStyle.UPPER_CENTER); screenMessage = ScreenMessages.PostScreenMessage("Playback 0 / " + (int)(lastTime - firstTime) + " seconds.", float.MaxValue, ScreenMessageStyle.UPPER_CENTER); playback = true; }
private void SplitAndRewriteMessage(ref ClientMessage message) { if (message == null) { return; } if (message.data == null) { return; } if (message.data.Length > Common.SPLIT_MESSAGE_LENGTH) { lastSplitMessageType = message.type; ClientMessage newSplitMessage = new ClientMessage(); newSplitMessage.type = ClientMessageType.SPLIT_MESSAGE; int splitBytesLeft = message.data.Length; using (MessageWriter mw = new MessageWriter()) { mw.Write<int>((int)message.type); mw.Write<int>(message.data.Length); byte[] firstSplit = new byte[Common.SPLIT_MESSAGE_LENGTH]; Array.Copy(message.data, 0, firstSplit, 0, Common.SPLIT_MESSAGE_LENGTH); mw.Write<byte[]>(firstSplit); splitBytesLeft -= Common.SPLIT_MESSAGE_LENGTH; newSplitMessage.data = mw.GetMessageBytes(); sendMessageQueueSplit.Enqueue(newSplitMessage); } while (splitBytesLeft > 0) { ClientMessage currentSplitMessage = new ClientMessage(); currentSplitMessage.type = ClientMessageType.SPLIT_MESSAGE; currentSplitMessage.data = new byte[Math.Min(splitBytesLeft, Common.SPLIT_MESSAGE_LENGTH)]; Array.Copy(message.data, message.data.Length - splitBytesLeft, currentSplitMessage.data, 0, currentSplitMessage.data.Length); splitBytesLeft -= currentSplitMessage.data.Length; sendMessageQueueSplit.Enqueue(currentSplitMessage); } message = sendMessageQueueSplit.Dequeue(); } }
protected PromptMessageBase(ClientMessageType messageType) : base(messageType) { this.Id = Interlocked.Increment(ref PromptMessageBase.id); }
/// <summary> /// Gets the <see cref="NetDeliveryMethod"/> and sequence channel to use for a given <see cref="ClientMessageType"/>. /// </summary> /// <param name="msgType">The <see cref="ClientMessageType"/>.</param> /// <param name="method">The <see cref="NetDeliveryMethod"/> to use for the <paramref name="msgType"/>.</param> /// <param name="seqChannel">The sequence channel to use for the <paramref name="msgType"/>.</param> public static void GetDeliveryMethod(this ClientMessageType msgType, out NetDeliveryMethod method, out int seqChannel) { /* Some important things to keep in mind: * * - Sequence numbers are unique per NetDeliveryMethod. That is, seqChannel=1 for ReliableOrder is not * the same as seqChannel=1 for UnreliableSequenced. * * - Sequence numbers are not used on Unreliable and ReliableUnordered. For these channels, always use seqChannel=0. * * - The max sequence number is defined by NetConstants.NetChannelsPerDeliveryMethod. * * - All sequences are created equally. They just provide a way to, when using ordering/sequencing, not have to * stall on messages that are irrelevant. For example, say Chat and MapEffect were on the same channel. Then * you send a huge chat message, then a MapEffect message shortly after. For some reason, the chat message gets * lost in the network and has to be retransmitted while the MapEffect arrived very quickly. Even though they are * logically irrelevant, since they use the same channel, the MapEffect will not be handled until that chat message * was received. Putting them on a different sequence channel resolves this issue. * * - Unreliable messages are just raw UDP. Not only can they be lost forever, they can arrive out-of-order and duplicate * copies can arrive. * * - It is perfectly fine, and even recommended, to use the same method and channel for multiple message types. Even if there * is no important distinction on the network layer, it keeps them logically separated in the upper layer. This makes it * very easy to change them on the network layer if needed. * * - Never create or use a message type based on the underlying delivery method and/or sequence channel. How it arrives should * be irrelevant on the upper layer. * * - A delivery method and (when applicable) sequence number should be specified for every message type. Never just rely * on the default behavior. * * If you update this comment block, please also update it in the server under: * ServerMessageTypeExtensions.GetDeliveryMethod(). */ #if true // NOTE: For now, we use a very simple and straight-forward approach. In the future, we will use more complex deliveries. method = NetDeliveryMethod.ReliableOrdered; seqChannel = 0; #else // Listing of the used sequence numbers, grouped by delivery method const int chRO_General = 0; const int chRO_Chat = 1; // FUTURE: Can start dividing stuff up for the client into different channels in the future. For now, it shouldn't be important. switch (msgType) { case ClientMessageType.CharacterMove: case ClientMessageType.CharacterInteract: case ClientMessageType.General: case ClientMessageType.GUI: case ClientMessageType.GUIItems: case ClientMessageType.System: method = NetDeliveryMethod.ReliableOrdered; seqChannel = chRO_General; break; case ClientMessageType.Chat: method = NetDeliveryMethod.ReliableOrdered; seqChannel = chRO_Chat; break; default: const string errmsg = "ClientMessageType `{0}` does not explicitly define a delivery method and sequence channel." + " All message types should define this explicitly. Falling back to ClientMessageType.General."; if (log.IsErrorEnabled) { log.ErrorFormat(errmsg, msgType); } GetDeliveryMethod(ClientMessageType.General, out method, out seqChannel); break; } #endif }