protected void handleMessage(KLFCommon.ServerMessageID id, byte[] data) { switch (id) { case KLFCommon.ServerMessageID.HANDSHAKE: Int32 protocol_version = KLFCommon.intFromBytes(data); if (data.Length >= 8) { Int32 server_version_length = KLFCommon.intFromBytes(data, 4); if (data.Length >= 12 + server_version_length) { String server_version = encoder.GetString(data, 8, server_version_length); clientID = KLFCommon.intFromBytes(data, 8 + server_version_length); Console.WriteLine("Handshake received. Server is running version: " + server_version); } } //End the session if the protocol versions don't match if (protocol_version != KLFCommon.NET_PROTOCOL_VERSION) { Console.WriteLine("Server version is incompatible with client version."); endSession = true; intentionalConnectionEnd = true; } else { sendHandshakeMessage(); //Reply to the handshake lock (udpTimestampLock) { lastUDPMessageSendTime = stopwatch.ElapsedMilliseconds; } handshakeCompleted = true; } break; case KLFCommon.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 KLFCommon.ServerMessageID.SERVER_MESSAGE: case KLFCommon.ServerMessageID.TEXT_MESSAGE: if (data != null) { InTextMessage in_message = new InTextMessage(); in_message.fromServer = (id == KLFCommon.ServerMessageID.SERVER_MESSAGE); in_message.message = encoder.GetString(data, 0, data.Length); //Queue the message enqueueTextMessage(in_message); } break; case KLFCommon.ServerMessageID.PLUGIN_UPDATE: if (data != null) sendClientInteropMessage(KLFCommon.ClientInteropMessageID.PLUGIN_UPDATE, data); break; case KLFCommon.ServerMessageID.SERVER_SETTINGS: lock (serverSettingsLock) { if (data != null && data.Length >= KLFCommon.SERVER_SETTINGS_LENGTH && handshakeCompleted) { updateInterval = KLFCommon.intFromBytes(data, 0); screenshotInterval = KLFCommon.intFromBytes(data, 4); lock (clientDataLock) { int new_screenshot_height = KLFCommon.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; } } } } break; case KLFCommon.ServerMessageID.SCREENSHOT_SHARE: if (data != null && data.Length > 0 && data.Length < screenshotSettings.maxNumBytes && watchPlayerName.Length > 0) { //Cache the screenshot Screenshot screenshot = new Screenshot(); screenshot.setFromByteArray(data); cacheScreenshot(screenshot); //Send the screenshot to the client sendClientInteropMessage(KLFCommon.ClientInteropMessageID.SCREENSHOT_RECEIVE, data); } break; case KLFCommon.ServerMessageID.CONNECTION_END: if (data != null) { String message = encoder.GetString(data, 0, data.Length); endSession = true; //If the reason is not a timeout, connection end is intentional intentionalConnectionEnd = message.ToLower() != "timeout"; enqueuePluginChatMessage("Server closed the connection: " + message, true); } break; case KLFCommon.ServerMessageID.UDP_ACKNOWLEDGE: lock (udpTimestampLock) { lastUDPAckReceiveTime = stopwatch.ElapsedMilliseconds; } break; case KLFCommon.ServerMessageID.CRAFT_FILE: if (data != null && data.Length > 4) { //Read craft name length byte craft_type = data[0]; int craft_name_length = KLFCommon.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 { 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 KLFCommon.ServerMessageID.PING_REPLY: if (pingStopwatch.IsRunning) { enqueueTextMessage("Ping Reply: " + pingStopwatch.ElapsedMilliseconds + "ms"); pingStopwatch.Stop(); pingStopwatch.Reset(); } break; } }
public void handleMessage(int client_index, KLFCommon.ClientMessageID id, byte[] data) { if (!clientIsValid(client_index)) return; debugConsoleWriteLine("Message id: " + id.ToString() + " data: " + (data != null ? data.Length.ToString() : "0")); UnicodeEncoding encoder = new UnicodeEncoding(); switch (id) { case KLFCommon.ClientMessageID.HANDSHAKE: if (data != null) { StringBuilder sb = new StringBuilder(); //Read username Int32 username_length = KLFCommon.intFromBytes(data, 0); String username = encoder.GetString(data, 4, username_length); int offset = 4 + username_length; String version = encoder.GetString(data, offset, data.Length - offset); String username_lower = username.ToLower(); bool accepted = true; //Ensure no other players have the same username for (int i = 0; i < clients.Length; i++) { if (i != client_index && clientIsReady(i) && clients[i].username.ToLower() == username_lower) { //Disconnect the player disconnectClient(client_index, "Your username is already in use."); stampedConsoleWriteLine("Rejected client due to duplicate username: "******"Your Client is Outdated Please Update"); stampedConsoleWriteLine("Rejected client due to wrong version : " + version + " New "+ KLFCommon.PROGRAM_VERSION); accepted = false; break; } if (!accepted) break; //Send the active user count to the client if (numClients == 2) { //Get the username of the other user on the server sb.Append("There is currently 1 other user on this server: "); for (int i = 0; i < clients.Length; i++) { if (i != client_index && clientIsReady(i)) { sb.Append(clients[i].username); break; } } } else { sb.Append("There are currently "); sb.Append(numClients - 1); sb.Append(" other users on this server."); if (numClients > 1) { sb.Append(" Enter !list to see them."); } } clients[client_index].username = username; clients[client_index].receivedHandshake = true; sendServerMessage(client_index, sb.ToString()); sendServerSettings(client_index); stampedConsoleWriteLine(username + " ("+getClientIP(client_index).ToString()+") has joined the server using client version " + version); if (!clients[client_index].messagesThrottled) { //Build join message sb.Clear(); sb.Append("User "); sb.Append(username); sb.Append(" has joined the server."); //Send the join message to all other clients sendServerMessageToAll(sb.ToString(), client_index); } messageFloodIncrement(client_index); } break; case KLFCommon.ClientMessageID.PRIMARY_PLUGIN_UPDATE: case KLFCommon.ClientMessageID.SECONDARY_PLUGIN_UPDATE: if (data != null && clientIsReady(client_index)) { #if SEND_UPDATES_TO_SENDER sendPluginUpdateToAll(data, id == KLFCommon.ClientMessageID.SECONDARY_PLUGIN_UPDATE); #else sendPluginUpdateToAll(data, id == KLFCommon.ClientMessageID.SECONDARY_PLUGIN_UPDATE, client_index); #endif } break; case KLFCommon.ClientMessageID.TEXT_MESSAGE: if (data != null && clientIsReady(client_index)) handleClientTextMessage(client_index, encoder.GetString(data, 0, data.Length)); break; case KLFCommon.ClientMessageID.SCREEN_WATCH_PLAYER: if (!clientIsReady(client_index) || data == null || data.Length < 9) break; bool send_screenshot = data[0] != 0; int watch_index = KLFCommon.intFromBytes(data, 1); int current_index = KLFCommon.intFromBytes(data, 5); String watch_name = encoder.GetString(data, 9, data.Length - 9); bool watch_name_changed = false; lock (clients[client_index].watchPlayerNameLock) { if (watch_name != clients[client_index].watchPlayerName || watch_index != clients[client_index].watchPlayerIndex) { //Set the watch player name clients[client_index].watchPlayerIndex = watch_index; clients[client_index].watchPlayerName = watch_name; watch_name_changed = true; } } if (send_screenshot && watch_name_changed && watch_name.Length > 0) { //Try to find the player the client is watching and send that player's current screenshot int watched_index = getClientIndexByName(watch_name); if (clientIsReady(watched_index)) { Screenshot screenshot = null; lock (clients[watched_index].screenshotLock) { screenshot = clients[watched_index].getScreenshot(watch_index); if (screenshot == null && watch_index == -1) screenshot = clients[watched_index].lastScreenshot; } if (screenshot != null && screenshot.index != current_index) { sendScreenshot(client_index, screenshot); } } } break; case KLFCommon.ClientMessageID.SCREENSHOT_SHARE: if (data != null && data.Length <= settings.screenshotSettings.maxNumBytes && clientIsReady(client_index)) { if (!clients[client_index].screenshotsThrottled) { StringBuilder sb = new StringBuilder(); Screenshot screenshot = new Screenshot(); screenshot.setFromByteArray(data); //Set the screenshot for the player lock (clients[client_index].screenshotLock) { clients[client_index].pushScreenshot(screenshot); } sb.Append(clients[client_index].username); sb.Append(" has shared a screenshot."); sendTextMessageToAll(sb.ToString()); stampedConsoleWriteLine(sb.ToString()); //Send the screenshot to every client watching the player sendScreenshotToWatchers(client_index, screenshot); if (settings.saveScreenshots) saveScreenshot(screenshot, clients[client_index].username); SHARED_SCREEN_SHOTS += 1; } bool was_throttled = clients[client_index].screenshotsThrottled; clients[client_index].screenshotFloodIncrement(); if (!was_throttled && clients[client_index].screenshotsThrottled) { long throttle_secs = settings.screenshotFloodThrottleTime / 1000; sendServerMessage(client_index, "You have been restricted from sharing screenshots for " + throttle_secs + " seconds."); stampedConsoleWriteLine(clients[client_index].username + " has been restricted from sharing screenshots for " + throttle_secs + " seconds."); } else if (clients[client_index].throttleState.messageFloodCounter == settings.screenshotFloodLimit - 1) sendServerMessage(client_index, "Warning: You are sharing too many screenshots."); } break; case KLFCommon.ClientMessageID.CONNECTION_END: String message = String.Empty; if (data != null) message = encoder.GetString(data, 0, data.Length); //Decode the message disconnectClient(client_index, message); //Disconnect the client break; case KLFCommon.ClientMessageID.SHARE_CRAFT_FILE: if (clientIsReady(client_index) && data != null && data.Length > 5 && (data.Length - 5) <= KLFCommon.MAX_CRAFT_FILE_BYTES) { if (clients[client_index].messagesThrottled) { messageFloodIncrement(client_index); break; } messageFloodIncrement(client_index); //Read craft name length byte craft_type = data[0]; int craft_name_length = KLFCommon.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); lock (clients[client_index].sharedCraftLock) { clients[client_index].sharedCraftName = craft_name; clients[client_index].sharedCraftFile = craft_bytes; clients[client_index].sharedCraftType = craft_type; } //Send a message to players informing them that a craft has been shared StringBuilder sb = new StringBuilder(); sb.Append(clients[client_index].username); sb.Append(" shared "); sb.Append(craft_name); switch (craft_type) { case KLFCommon.CRAFT_TYPE_VAB: sb.Append(" (VAB)"); break; case KLFCommon.CRAFT_TYPE_SPH: sb.Append(" (SPH)"); break; } stampedConsoleWriteLine(sb.ToString()); sb.Append(" . Enter !getcraft "); sb.Append(clients[client_index].username); sb.Append(" to get it."); sendTextMessageToAll(sb.ToString()); } } break; case KLFCommon.ClientMessageID.ACTIVITY_UPDATE_IN_FLIGHT: clients[client_index].updateActivityLevel(ServerClient.ActivityLevel.IN_FLIGHT); break; case KLFCommon.ClientMessageID.ACTIVITY_UPDATE_IN_GAME: clients[client_index].updateActivityLevel(ServerClient.ActivityLevel.IN_GAME); break; case KLFCommon.ClientMessageID.PING: clients[client_index].queueOutgoingMessage(KLFCommon.ServerMessageID.PING_REPLY, null); break; } debugConsoleWriteLine("Handled message"); }