private static void queueOutgoingUDPMessage(KMPCommon.ClientMessageID id, byte[] data) { byte[] message_bytes = buildMessageByteArray(id, data, KMPCommon.intToBytes(clientID)); queuedOutUDPMessages.Enqueue (message_bytes); }
private static void sendShareCraftMessage(String craft_name, byte[] data, KMPCommon.CraftType type) { //Encode message byte[] name_bytes = encoder.GetBytes(craft_name); byte[] bytes = new byte[8 + name_bytes.Length + data.Length]; //Check size of data to make sure it's not too large if ((name_bytes.Length + data.Length) <= KMPCommon.MAX_CRAFT_FILE_BYTES) { //Copy data KMPCommon.intToBytes((int)type).CopyTo(bytes, 0); KMPCommon.intToBytes(name_bytes.Length).CopyTo(bytes, 4); name_bytes.CopyTo(bytes, 8); data.CopyTo(bytes, 8 + name_bytes.Length); queueOutgoingMessage(KMPCommon.ClientMessageID.SHARE_CRAFT_FILE, bytes); } else enqueueTextMessage("Craft file is too large to send.", false, true); }
private static void sendMessageUDP(KMPCommon.ClientMessageID id, byte[] data) { if (udpSocket != null) { //Send the packet try { udpSocket.Send(buildMessageByteArray(id, data, KMPCommon.intToBytes(clientID))); } catch { } lock (udpTimestampLock) { lastUDPMessageSendTime = stopwatch.ElapsedMilliseconds; } } }
private static void queueOutgoingMessage(KMPCommon.ClientMessageID id, byte[] data) { //Figure out if this is a high or low priority message byte[] message_bytes = buildMessageByteArray(id, data); switch (id) { case KMPCommon.ClientMessageID.HANDSHAKE: case KMPCommon.ClientMessageID.TEXT_MESSAGE: case KMPCommon.ClientMessageID.KEEPALIVE: case KMPCommon.ClientMessageID.UDP_PROBE: case KMPCommon.ClientMessageID.PING: queuedOutMessagesHighPriority.Enqueue (message_bytes); break; default: queuedOutMessages.Enqueue (message_bytes); break; } }
public void queueOutgoingMessage(KMPCommon.ServerMessageID id, byte[] data) { queueOutgoingMessage(Server.buildMessageArray(id, data)); }
private void enqueuePluginInteropMessage(KMPCommon.PluginInteropMessageID id, byte[] data) { int msg_data_length = 0; if (data != null) msg_data_length = data.Length; byte[] message_bytes = new byte[KMPCommon.INTEROP_MSG_HEADER_LENGTH + msg_data_length]; KMPCommon.intToBytes((int)id).CopyTo(message_bytes, 0); KMPCommon.intToBytes(msg_data_length).CopyTo(message_bytes, 4); if (data != null) data.CopyTo(message_bytes, KMPCommon.INTEROP_MSG_HEADER_LENGTH); interopOutQueue.Enqueue(message_bytes); //Enforce max queue size while (interopOutQueue.Count > INTEROP_MAX_QUEUE_SIZE) interopOutQueue.Dequeue(); }
private static void sendMessageUDP(KMPCommon.ClientMessageID id, byte[] data) { if (udpSocket != null) { //Send the packet try { udpSocket.Send(buildMessageByteArray(id, data, KMPCommon.intToBytes(clientID))); } catch (Exception e) { KMP.Log.Debug("Exception thrown in sendMessageUDP(), catch 1, Exception: {0}", e.ToString()); } lock (udpTimestampLock) { lastUDPMessageSendTime = stopwatch.ElapsedMilliseconds; } } }
static String findCraftFilename(String craft_name, ref KMPCommon.CraftType craft_type) { String vab_filename = getCraftFilename(craft_name, KMPCommon.CraftType.VAB); if (vab_filename != null && System.IO.File.Exists(vab_filename)) { craft_type = KMPCommon.CraftType.VAB; return vab_filename; } String sph_filename = getCraftFilename(craft_name, KMPCommon.CraftType.SPH); if (sph_filename != null && System.IO.File.Exists(sph_filename)) { craft_type = KMPCommon.CraftType.SPH; return sph_filename; } String subassembly_filename = getCraftFilename(craft_name, KMPCommon.CraftType.SUBASSEMBLY); if (subassembly_filename != null && System.IO.File.Exists(subassembly_filename)) { craft_type = KMPCommon.CraftType.SUBASSEMBLY; return subassembly_filename; } return null; }
private void asyncReceive(IAsyncResult ar) { try { // Retrieve the state object and the client socket // from the asynchronous state object. StateObject state = (StateObject)ar.AsyncState; TcpClient client = state.workClient; int bytesRead = client.GetStream().EndRead(ar); // Read data from the remote device directly into the message buffer. updateReceiveTimestamp(); currentBytesToReceive -= bytesRead; //Decrement how many bytes we have read. if (bytesRead > 0) //This is just a shortcut really { if (!currentMessageHeaderRecieved) { //We are receiving just the header if (currentBytesToReceive == 0) { //We have recieved the full message header, lets process it. currentMessageID = (KMPCommon.ClientMessageID)BitConverter.ToInt32(currentMessage, 0); currentBytesToReceive = BitConverter.ToInt32(currentMessage, 4); if (currentBytesToReceive == 0) { //We received the header of a empty message, process it and reset the buffers. messageReceived(currentMessageID, null); currentMessageID = KMPCommon.ClientMessageID.NULL; currentBytesToReceive = KMPCommon.MSG_HEADER_LENGTH; currentMessage = new byte[currentBytesToReceive]; } else { //We received the header of a non-empty message, Let's give it a buffer and read again. currentMessage = new byte[currentBytesToReceive]; currentMessageHeaderRecieved = true; } } } else { if (currentBytesToReceive == 0) { //We have received all the message data, lets decompress and process it byte[] decompressedData = KMPCommon.Decompress(currentMessage); messageReceived(currentMessageID, decompressedData); currentMessageHeaderRecieved = false; currentMessageID = KMPCommon.ClientMessageID.NULL; currentBytesToReceive = KMPCommon.MSG_HEADER_LENGTH; currentMessage = new byte[currentBytesToReceive]; } } } if (currentBytesToReceive < 0) { throw new System.IO.IOException("You somehow managed to read more bytes then we asked for. Good for you. Open this up on the bugtracker now."); } if (client != null) { client.GetStream().BeginRead(currentMessage, currentMessage.Length - currentBytesToReceive, currentBytesToReceive, new AsyncCallback(asyncReceive), state); } } catch (Exception e) { //Basically, If anything goes wrong at all the stream is broken and there is no way to recover from it. Log.Debug("Exception thrown in ReceiveCallback(), catch 1, Exception: {0}", e.ToString()); } }
private static void sendMessageTCP(KMPCommon.ClientMessageID id, byte[] data) { lock (tcpSendLock) { byte[] message_bytes = buildMessageByteArray(id, data); int send_bytes_actually_sent = 0; while (send_bytes_actually_sent < message_bytes.Length) { try { //Send message send_bytes_actually_sent += tcpSocket.Send(message_bytes, send_bytes_actually_sent, message_bytes.Length - send_bytes_actually_sent, SocketFlags.None); // Just do a blocking send // tcpSocket.BeginSend(message_bytes, 0, message_bytes.Length, SocketFlags.None, // new AsyncCallback(SendCallback), tcpSocket); } catch (System.InvalidOperationException e) { KMP.Log.Debug("Exception thrown in sendMessageTCP(), catch 1, Exception: {0}", e.ToString()); } catch (KSP.IO.IOException e) { KMP.Log.Debug("Exception thrown in sendMessageTCP(), catch 2, Exception: {0}", e.ToString()); } } } lastTCPMessageSendTime = stopwatch.ElapsedMilliseconds; }
//Messages private void messageReceived(KMPCommon.ClientMessageID id, byte[] data) { if (id == KMPCommon.ClientMessageID.SPLIT_MESSAGE) { if (splitMessageReceiveIndex == 0) { //New split message int split_message_length = KMPCommon.intFromBytes (data, 4); splitMessageData = new byte[8 + split_message_length]; data.CopyTo (splitMessageData, 0); splitMessageReceiveIndex = data.Length; } else { //Continued split message data.CopyTo (splitMessageData, splitMessageReceiveIndex); splitMessageReceiveIndex = splitMessageReceiveIndex + data.Length; } //Check if we have filled the byte array, if so, handle the message. if (splitMessageReceiveIndex == splitMessageData.Length) { //Parse the message and feed it into the client queue KMPCommon.ClientMessageID joined_message_id = (KMPCommon.ClientMessageID)KMPCommon.intFromBytes (splitMessageData, 0); int joined_message_length = KMPCommon.intFromBytes (splitMessageData, 4); byte[] joined_message_data = new byte[joined_message_length]; Array.Copy (splitMessageData, 8, joined_message_data, 0, joined_message_length); byte[] joined_message_data_decompressed = KMPCommon.Decompress (joined_message_data); parent.queueClientMessage (this, joined_message_id, joined_message_data_decompressed); splitMessageReceiveIndex = 0; } } else { parent.queueClientMessage (this, id, data); } }
private void handleReceive() { while (receiveHandleIndex < receiveIndex) { //Read header bytes if (currentMessageHeaderIndex < KMPCommon.MSG_HEADER_LENGTH) { //Determine how many header bytes can be read int bytes_to_read = Math.Min(receiveIndex - receiveHandleIndex, KMPCommon.MSG_HEADER_LENGTH - currentMessageHeaderIndex); //Read header bytes Array.Copy(receiveBuffer, receiveHandleIndex, currentMessageHeader, currentMessageHeaderIndex, bytes_to_read); //Advance buffer indices currentMessageHeaderIndex += bytes_to_read; receiveHandleIndex += bytes_to_read; //Handle header if (currentMessageHeaderIndex >= KMPCommon.MSG_HEADER_LENGTH) { int id_int = KMPCommon.intFromBytes(currentMessageHeader, 0); //Make sure the message id section of the header is a valid value if (id_int >= 0 && id_int < Enum.GetValues(typeof(KMPCommon.ClientMessageID)).Length) { currentMessageID = (KMPCommon.ClientMessageID)id_int; } else { currentMessageID = KMPCommon.ClientMessageID.NULL; } int data_length = KMPCommon.intFromBytes(currentMessageHeader, 4); if (data_length > 0) { //Init message data buffer currentMessageData = new byte[data_length]; currentMessageDataIndex = 0; } else { currentMessageData = null; //Handle received message messageReceived(currentMessageID, null); //Prepare for the next header read currentMessageHeaderIndex = 0; } } } if (currentMessageData != null) { //Read data bytes if (currentMessageDataIndex < currentMessageData.Length) { //Determine how many data bytes can be read int bytes_to_read = Math.Min(receiveIndex - receiveHandleIndex, currentMessageData.Length - currentMessageDataIndex); //Read data bytes Array.Copy(receiveBuffer, receiveHandleIndex, currentMessageData, currentMessageDataIndex, bytes_to_read); //Advance buffer indices currentMessageDataIndex += bytes_to_read; receiveHandleIndex += bytes_to_read; //Handle data if (currentMessageDataIndex >= currentMessageData.Length) { //Handle received message messageReceived(currentMessageID, currentMessageData); currentMessageData = null; //Prepare for the next header read currentMessageHeaderIndex = 0; } } } } //Once all receive bytes have been handled, reset buffer indices to use the whole buffer again receiveHandleIndex = 0; receiveIndex = 0; }
static void handleMessage(KMPCommon.ServerMessageID id, byte[] data) { //LogAndShare("Message ID: " + id.ToString() + " data: " + (data == null ? "0" : System.Text.Encoding.ASCII.GetString(data))); switch (id) { case KMPCommon.ServerMessageID.HANDSHAKE: Int32 protocol_version = KMPCommon.intFromBytes(data); if (data.Length >= 8) { Int32 server_version_length = KMPCommon.intFromBytes(data, 4); if (data.Length >= 12 + server_version_length) { String server_version = encoder.GetString(data, 8, server_version_length); clientID = KMPCommon.intFromBytes(data, 8 + server_version_length); SetMessage("Handshake received. Server version: " + server_version); } } //End the session if the protocol versions don't match if (protocol_version != KMPCommon.NET_PROTOCOL_VERSION) { endSession = true; intentionalConnectionEnd = true; } else { sendHandshakeMessage(); //Reply to the handshake lock (udpTimestampLock) { lastUDPMessageSendTime = stopwatch.ElapsedMilliseconds; } handshakeCompleted = true; } break; case KMPCommon.ServerMessageID.HANDSHAKE_REFUSAL: String refusal_message = encoder.GetString(data, 0, data.Length); endSession = true; intentionalConnectionEnd = true; enqueuePluginChatMessage("Server refused connection. Reason: " + refusal_message, true); break; case KMPCommon.ServerMessageID.SERVER_MESSAGE: case KMPCommon.ServerMessageID.TEXT_MESSAGE: if (data != null) { InTextMessage in_message = new InTextMessage(); in_message.fromServer = (id == KMPCommon.ServerMessageID.SERVER_MESSAGE); in_message.message = encoder.GetString(data, 0, data.Length); //Queue the message enqueueTextMessage(in_message); } break; case KMPCommon.ServerMessageID.PLUGIN_UPDATE: if (data != null) enqueueClientInteropMessage(KMPCommon.ClientInteropMessageID.PLUGIN_UPDATE, data); break; case KMPCommon.ServerMessageID.SERVER_SETTINGS: lock (serverSettingsLock) { if (data != null && data.Length >= KMPCommon.SERVER_SETTINGS_LENGTH && handshakeCompleted) { updateInterval = KMPCommon.intFromBytes(data, 0); screenshotInterval = KMPCommon.intFromBytes(data, 4); lock (clientDataLock) { int new_screenshot_height = KMPCommon.intFromBytes(data, 8); if (screenshotSettings.maxHeight != new_screenshot_height) { screenshotSettings.maxHeight = new_screenshot_height; lastClientDataChangeTime = stopwatch.ElapsedMilliseconds; enqueueTextMessage("Screenshot Height has been set to " + screenshotSettings.maxHeight); } if (inactiveShipsPerUpdate != data[12]) { inactiveShipsPerUpdate = data[12]; lastClientDataChangeTime = stopwatch.ElapsedMilliseconds; } } receivedSettings = true; /* UnityEngine.Debug.Log("Update interval: " + updateInterval); UnityEngine.Debug.Log("Screenshot interval: " + screenshotInterval); UnityEngine.Debug.Log("Inactive ships per update: " + inactiveShipsPerUpdate); */ } } break; case KMPCommon.ServerMessageID.SCREENSHOT_SHARE: if (data != null && data.Length > 0 && data.Length < screenshotSettings.maxNumBytes && watchPlayerName.Length > 0 && watchPlayerName != username) { enqueueClientInteropMessage(KMPCommon.ClientInteropMessageID.SCREENSHOT_RECEIVE, data); } break; case KMPCommon.ServerMessageID.CONNECTION_END: gameManager.disconnect(); if (data != null) { String message = encoder.GetString(data, 0, data.Length); endSession = true; handshakeCompleted = false; receivedSettings = false; //If the reason is not a timeout, connection end is intentional intentionalConnectionEnd = message.ToLower() != "timeout"; enqueuePluginChatMessage("Server closed the connection: " + message, true); clearConnectionState(); SetMessage("Disconnected from server: " + message); gameManager.disconnect(message); } else { clearConnectionState(); SetMessage("Disconnected from server"); gameManager.disconnect(); } break; case KMPCommon.ServerMessageID.UDP_ACKNOWLEDGE: lock (udpTimestampLock) { lastUDPAckReceiveTime = stopwatch.ElapsedMilliseconds; } break; case KMPCommon.ServerMessageID.CRAFT_FILE: if (data != null && data.Length > 4) { //Read craft name length byte craft_type = data[0]; int craft_name_length = KMPCommon.intFromBytes(data, 1); if (craft_name_length < data.Length - 5) { //Read craft name String craft_name = encoder.GetString(data, 5, craft_name_length); //Read craft bytes byte[] craft_bytes = new byte[data.Length - craft_name_length - 5]; Array.Copy(data, 5 + craft_name_length, craft_bytes, 0, craft_bytes.Length); //Write the craft to a file String filename = getCraftFilename(craft_name, craft_type); if (filename != null) { try { //KSP.IO.File.WriteAllBytes<KMPClientMain>(craft_bytes, filename); System.IO.File.WriteAllBytes(filename,craft_bytes); enqueueTextMessage("Received craft file: " + craft_name); } catch { enqueueTextMessage("Error saving received craft file: " + craft_name); } } else enqueueTextMessage("Unable to save received craft file."); } } break; case KMPCommon.ServerMessageID.PING_REPLY: if (pingStopwatch.IsRunning) { enqueueTextMessage("Ping Reply: " + pingStopwatch.ElapsedMilliseconds + "ms"); lastPing = pingStopwatch.ElapsedMilliseconds; pingStopwatch.Stop(); pingStopwatch.Reset(); } break; case KMPCommon.ServerMessageID.SYNC: if (data != null) gameManager.targetTick = BitConverter.ToDouble(data,0) + Convert.ToDouble(lastPing); break; case KMPCommon.ServerMessageID.SYNC_COMPLETE: gameManager.HandleSyncCompleted(); break; } }
private static byte[] buildMessageByteArray(KMPCommon.ClientMessageID id, byte[] data, byte[] prefix = null) { byte[] compressed_data = null; int prefix_length = 0; if (prefix != null) prefix_length = prefix.Length; int msg_data_length = 0; if (data != null) { compressed_data = KMPCommon.Compress(data); if (compressed_data == null) compressed_data = KMPCommon.Compress(data, true); msg_data_length = compressed_data.Length; } byte[] message_bytes = new byte[KMPCommon.MSG_HEADER_LENGTH + msg_data_length + prefix_length]; int index = 0; if (prefix != null) { prefix.CopyTo(message_bytes, index); index += 4; } KMPCommon.intToBytes((int)id).CopyTo(message_bytes, index); index += 4; KMPCommon.intToBytes(msg_data_length).CopyTo(message_bytes, index); index += 4; if (compressed_data != null) { compressed_data.CopyTo(message_bytes, index); index += compressed_data.Length; } return message_bytes; }
private void enqueuePluginInteropMessage(KMPCommon.PluginInteropMessageID id, byte[] data) { int msg_data_length = 0; if (data != null) msg_data_length = data.Length; byte[] message_bytes = new byte[KMPCommon.INTEROP_MSG_HEADER_LENGTH + msg_data_length]; KMPCommon.intToBytes((int)id).CopyTo(message_bytes, 0); KMPCommon.intToBytes(msg_data_length).CopyTo(message_bytes, 4); if (data != null) data.CopyTo(message_bytes, KMPCommon.INTEROP_MSG_HEADER_LENGTH); KMPClientMain.acceptPluginInterop (message_bytes); }
static void enqueueClientInteropMessage(KMPCommon.ClientInteropMessageID id, byte[] data) { int msg_data_length = 0; if (data != null) msg_data_length = data.Length; byte[] message_bytes = new byte[KMPCommon.INTEROP_MSG_HEADER_LENGTH + msg_data_length]; KMPCommon.intToBytes((int)id).CopyTo(message_bytes, 0); KMPCommon.intToBytes(msg_data_length).CopyTo(message_bytes, 4); if (data != null) data.CopyTo(message_bytes, KMPCommon.INTEROP_MSG_HEADER_LENGTH); lock (interopOutQueueLock) { gameManager.acceptClientInterop (message_bytes); } }
static void handleInteropMessage(KMPCommon.PluginInteropMessageID id, byte[] data) { switch (id) { case KMPCommon.PluginInteropMessageID.CHAT_SEND: if (data != null) { String line = encoder.GetString(data); InTextMessage message = new InTextMessage(); message.fromServer = false; message.isMOTD = false; message.message = "[" + username + "] " + line; enqueueTextMessage(message, false); handleChatInput(line); } break; case KMPCommon.PluginInteropMessageID.PLUGIN_DATA: String new_watch_player_name = String.Empty; if (data != null && data.Length >= 9) { UnicodeEncoding encoder = new UnicodeEncoding(); int index = 0; //Read current activity status bool in_flight = data[index] != 0; index++; //Read current game title int current_game_title_length = KMPCommon.intFromBytes(data, index); index += 4; currentGameTitle = encoder.GetString(data, index, current_game_title_length); index += current_game_title_length; //Read the watch player name int watch_player_name_length = KMPCommon.intFromBytes(data, index); index += 4; new_watch_player_name = encoder.GetString(data, index, watch_player_name_length); index += watch_player_name_length; //Send the activity status to the server if (in_flight) queueOutgoingMessage(KMPCommon.ClientMessageID.ACTIVITY_UPDATE_IN_FLIGHT, null); else queueOutgoingMessage(KMPCommon.ClientMessageID.ACTIVITY_UPDATE_IN_GAME, null); } if (watchPlayerName != new_watch_player_name) { watchPlayerName = new_watch_player_name; if (watchPlayerName == username && lastSharedScreenshot != null) enqueueClientInteropMessage(KMPCommon.ClientInteropMessageID.SCREENSHOT_RECEIVE, lastSharedScreenshot); sendScreenshotWatchPlayerMessage(watchPlayerName); } break; case KMPCommon.PluginInteropMessageID.PRIMARY_PLUGIN_UPDATE: sendPluginUpdate(data, true); break; case KMPCommon.PluginInteropMessageID.SECONDARY_PLUGIN_UPDATE: sendPluginUpdate(data, false); break; case KMPCommon.PluginInteropMessageID.SCENARIO_UPDATE: sendScenarioUpdate(data); break; case KMPCommon.PluginInteropMessageID.SCREENSHOT_SHARE: if (data != null) { lock (screenshotOutLock) { queuedOutScreenshot = data; } } break; case KMPCommon.PluginInteropMessageID.WARPING: queueOutgoingMessage(KMPCommon.ClientMessageID.WARPING, data); break; case KMPCommon.PluginInteropMessageID.SSYNC: queueOutgoingMessage(KMPCommon.ClientMessageID.SSYNC, data); break; } }
static String getCraftFilename(String craft_name, KMPCommon.CraftType craft_type) { //Filter the craft name for illegal characters String filtered_craft_name = KMPCommon.filteredFileName(craft_name.Replace('.', '_')); if (currentGameTitle.Length <= 0 || filtered_craft_name.Length <= 0) return null; switch (craft_type) { case KMPCommon.CraftType.VAB: return "saves/" + currentGameTitle + "/Ships/VAB/" + filtered_craft_name + CRAFT_FILE_EXTENSION; case KMPCommon.CraftType.SPH: return "saves/" + currentGameTitle + "/Ships/SPH/" + filtered_craft_name + CRAFT_FILE_EXTENSION; case KMPCommon.CraftType.SUBASSEMBLY: return "saves/" + currentGameTitle + "/Subassemblies/" + filtered_craft_name + CRAFT_FILE_EXTENSION; } return null; }
static void handleMessage(KMPCommon.ServerMessageID id, byte[] data) { //LogAndShare("Message ID: " + id.ToString() + " data: " + (data == null ? "0" : System.Text.Encoding.ASCII.GetString(data))); switch (id) { case KMPCommon.ServerMessageID.HANDSHAKE: Int32 protocol_version = KMPCommon.intFromBytes(data); if (data.Length >= 8) { Int32 server_version_length = KMPCommon.intFromBytes(data, 4); if (data.Length >= 12 + server_version_length) { String server_version = encoder.GetString(data, 8, server_version_length); clientID = KMPCommon.intFromBytes(data, 8 + server_version_length); gameManager.gameMode = KMPCommon.intFromBytes(data, 12 + server_version_length); int kmpModControl_length = KMPCommon.intFromBytes(data, 16 + server_version_length); kmpModControl_bytes = new byte[kmpModControl_length]; Array.Copy(data, 20 + server_version_length, kmpModControl_bytes, 0, kmpModControl_length); SetMessage("Handshake received. Server version: " + server_version); } } //End the session if the protocol versions don't match if (protocol_version != KMPCommon.NET_PROTOCOL_VERSION) { endSession = true; intentionalConnectionEnd = true; gameManager.disconnect("Your client is incompatible with this server"); } else { if (!modCheck(kmpModControl_bytes)) { endSession = true; intentionalConnectionEnd = true; gameManager.disconnect(modMismatchError); } else { sendHandshakeMessage(); //Reply to the handshake lock (udpTimestampLock) { lastUDPMessageSendTime = stopwatch.ElapsedMilliseconds; } handshakeCompleted = true; } } break; case KMPCommon.ServerMessageID.HANDSHAKE_REFUSAL: String refusal_message = encoder.GetString(data, 0, data.Length); endSession = true; intentionalConnectionEnd = true; enqueuePluginChatMessage("Server refused connection. Reason: " + refusal_message, true); break; case KMPCommon.ServerMessageID.SERVER_MESSAGE: case KMPCommon.ServerMessageID.TEXT_MESSAGE: if (data != null) { InTextMessage in_message = new InTextMessage(); in_message.fromServer = (id == KMPCommon.ServerMessageID.SERVER_MESSAGE); in_message.isMOTD = (id == KMPCommon.ServerMessageID.MOTD_MESSAGE); in_message.message = encoder.GetString(data, 0, data.Length); if (in_message.message.Contains(" has shared a screenshot.")) { int screenshotSharePlayerNameIndex = in_message.message.IndexOf(" has shared a screenshot."); string screenshotSharePlayerName = in_message.message.Substring(0, screenshotSharePlayerNameIndex); if (screenshotSharePlayerName != username) { bool listPlayerNameInScreenshotsWaiting = false; foreach (string listPlayer in screenshotsWaiting) { if (listPlayer == screenshotSharePlayerName) { listPlayerNameInScreenshotsWaiting = true; } } if (listPlayerNameInScreenshotsWaiting == false) { screenshotsWaiting.Add(screenshotSharePlayerName); } } } if (in_message.message.Contains(" has disconnected : ")) { int quitPlayerNameIndex = in_message.message.IndexOf(" has disconnected : "); string quitPlayerName = in_message.message.Substring(0, quitPlayerNameIndex); if (quitPlayerName != username) { bool listPlayerNameInScreenshotsWaiting = false; foreach (string listPlayer in screenshotsWaiting) { if (listPlayer == quitPlayerName) { listPlayerNameInScreenshotsWaiting = true; } } if (listPlayerNameInScreenshotsWaiting) { screenshotsWaiting.Remove(quitPlayerName); } } } //Queue the message enqueueTextMessage(in_message); } break; case KMPCommon.ServerMessageID.MOTD_MESSAGE: if (data != null) { InTextMessage in_message = new InTextMessage(); in_message.fromServer = (id == KMPCommon.ServerMessageID.SERVER_MESSAGE); in_message.isMOTD = (id == KMPCommon.ServerMessageID.MOTD_MESSAGE); in_message.message = encoder.GetString(data, 0, data.Length); enqueueTextMessage(in_message); } break; case KMPCommon.ServerMessageID.PLUGIN_UPDATE: if (data != null) enqueueClientInteropMessage(KMPCommon.ClientInteropMessageID.PLUGIN_UPDATE, data); break; case KMPCommon.ServerMessageID.SCENARIO_UPDATE: if (data != null) enqueueClientInteropMessage(KMPCommon.ClientInteropMessageID.SCENARIO_UPDATE, data); break; case KMPCommon.ServerMessageID.SERVER_SETTINGS: lock (serverSettingsLock) { if (data != null && data.Length >= KMPCommon.SERVER_SETTINGS_LENGTH && handshakeCompleted) { updateInterval = KMPCommon.intFromBytes(data, 0); screenshotInterval = KMPCommon.intFromBytes(data, 4); lock (clientDataLock) { int new_screenshot_height = KMPCommon.intFromBytes(data, 8); if (screenshotSettings.maxHeight != new_screenshot_height) { screenshotSettings.maxHeight = new_screenshot_height; lastClientDataChangeTime = stopwatch.ElapsedMilliseconds; enqueueTextMessage("Screenshot Height has been set to " + screenshotSettings.maxHeight); } gameManager.safetyBubbleRadius = BitConverter.ToDouble(data, 12); if (inactiveShipsPerUpdate != data[20]) { inactiveShipsPerUpdate = data[20]; lastClientDataChangeTime = stopwatch.ElapsedMilliseconds; } gameManager.gameCheatsEnabled = Convert.ToBoolean(data[21]); gameManager.gameArrr = Convert.ToBoolean(data[22]); //partList, requiredModList, shaList, resourceList and resourceControlMode } receivedSettings = true; /* Log.Debug("Update interval: " + updateInterval); Log.Debug("Screenshot interval: " + screenshotInterval); Log.Debug("Inactive ships per update: " + inactiveShipsPerUpdate); */ } } break; case KMPCommon.ServerMessageID.SCREENSHOT_SHARE: if (data != null && data.Length > 0 && data.Length < screenshotSettings.maxNumBytes && watchPlayerName.Length > 0 && watchPlayerName != username) { enqueueClientInteropMessage(KMPCommon.ClientInteropMessageID.SCREENSHOT_RECEIVE, data); } break; case KMPCommon.ServerMessageID.CONNECTION_END: if (data != null) { String message = encoder.GetString(data, 0, data.Length); gameManager.disconnect(message); clearConnectionState(); //If the reason is not a timeout, connection end is intentional intentionalConnectionEnd = message.ToLower() != "timeout"; enqueuePluginChatMessage("Server closed the connection: " + message, true); SetMessage("Disconnected from server: " + message); } else { gameManager.disconnect(); clearConnectionState(); SetMessage("Disconnected from server"); } break; case KMPCommon.ServerMessageID.UDP_ACKNOWLEDGE: lock (udpTimestampLock) { lastUDPAckReceiveTime = stopwatch.ElapsedMilliseconds; } break; case KMPCommon.ServerMessageID.CRAFT_FILE: if (data != null && data.Length > 8) { //Read craft name length KMPCommon.CraftType craft_type = (KMPCommon.CraftType)KMPCommon.intFromBytes(data, 0); int craft_name_length = KMPCommon.intFromBytes(data, 4); if (craft_name_length < data.Length - 8) { //Read craft name String craft_name = encoder.GetString(data, 8, craft_name_length); //Read craft bytes byte[] craft_bytes = new byte[data.Length - craft_name_length - 8]; Array.Copy(data, 8 + craft_name_length, craft_bytes, 0, craft_bytes.Length); //Write the craft to a file String filename = getCraftFilename(craft_name, craft_type); if (filename != null) { try { //KSP.IO.File.WriteAllBytes<KMPClientMain>(craft_bytes, filename); System.IO.File.WriteAllBytes(filename, craft_bytes); enqueueTextMessage("Received craft file: " + craft_name); } catch (Exception e) { Log.Debug("Exception thrown in handleMessage(), catch 1, Exception: {0}", e.ToString()); enqueueTextMessage("Error saving received craft file: " + craft_name); } } else enqueueTextMessage("Unable to save received craft file."); } } break; case KMPCommon.ServerMessageID.PING_REPLY: if (pingStopwatch.IsRunning) { enqueueTextMessage("Ping Reply: " + pingStopwatch.ElapsedMilliseconds + "ms"); lastPing = pingStopwatch.ElapsedMilliseconds; pingStopwatch.Stop(); pingStopwatch.Reset(); } break; case KMPCommon.ServerMessageID.SYNC: if (data != null) gameManager.targetTick = BitConverter.ToDouble(data, 0) + Convert.ToDouble(lastPing); break; case KMPCommon.ServerMessageID.SYNC_COMPLETE: gameManager.HandleSyncCompleted(); break; case KMPCommon.ServerMessageID.SPLIT_MESSAGE: handleSplitMessage(data); break; } }
//Messages private void messageReceived(KMPCommon.ClientMessageID id, byte[] data) { parent.queueClientMessage(this, id, data); }
private static void messageReceived(KMPCommon.ServerMessageID id, byte[] data) { ServerMessage message; message.id = id; message.data = data; if (id != KMPCommon.ServerMessageID.NULL) receivedMessageQueue.Enqueue(message); }
private void handleInteropMessage(KMPCommon.ClientInteropMessageID id, byte[] data) { try { switch (id) { case KMPCommon.ClientInteropMessageID.CHAT_RECEIVE: if (data != null) { KMPChatDisplay.enqueueChatLine(encoder.GetString(data)); KMPChatDX.enqueueChatLine(encoder.GetString(data)); chatMessagesWaiting++; } break; case KMPCommon.ClientInteropMessageID.CLIENT_DATA: if (data != null && data.Length > 9) { //Read inactive vessels per update count inactiveVesselsPerUpdate = data[0]; //Read screenshot height KMPScreenshotDisplay.screenshotSettings.maxHeight = KMPCommon.intFromBytes(data, 1); updateInterval = ((float)KMPCommon.intFromBytes(data, 5))/1000.0f; //Read username playerName = encoder.GetString(data, 9, data.Length - 9); } break; case KMPCommon.ClientInteropMessageID.PLUGIN_UPDATE: if (data != null) { //De-serialize and handle the update handleUpdate(KSP.IO.IOUtils.DeserializeFromBinary(data)); } break; case KMPCommon.ClientInteropMessageID.SCREENSHOT_RECEIVE: if (data != null) { //Read description length int description_length = KMPCommon.intFromBytes(data, 0); //Read description String description = encoder.GetString(data, 4, description_length); //Read data byte[] image_data = new byte[data.Length - 4 - description_length]; Array.Copy(data, 4 + description_length, image_data, 0, image_data.Length); if (image_data.Length <= KMPScreenshotDisplay.screenshotSettings.maxNumBytes) { KMPScreenshotDisplay.description = description; StartCoroutine(applyScreenshotTexture(image_data)); } } break; } } catch (Exception e) { KMPClientMain.DebugLog(e.Message); } }
private static void sendMessageTCP(KMPCommon.ClientMessageID id, byte[] data) { byte[] message_bytes = buildMessageByteArray(id, data); lock (tcpSendLock) { try { //Send message tcpSocket.Send(message_bytes, message_bytes.Length, SocketFlags.None); // Just do a blocking send // tcpSocket.BeginSend(message_bytes, 0, message_bytes.Length, SocketFlags.None, // new AsyncCallback(SendCallback), tcpSocket); } catch (System.InvalidOperationException) { } catch (KSP.IO.IOException) { } } lastTCPMessageSendTime = stopwatch.ElapsedMilliseconds; }