public void HandleMessage(int clientIndex, KLFCommon.ClientMessageID id, byte[] data) { if (!ValidClient(clientIndex)) 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 usernameLength = KLFCommon.BytesToInt(data, 0); String username = encoder.GetString(data, 4, usernameLength); int offset = 4 + usernameLength; String version = encoder.GetString(data, offset, data.Length - offset); String usernameLower = username.ToLower(); bool accepted = true; //Ensure no other players have the same username for (int i = 0; i < Clients.Length; i++) { if (i != clientIndex && ClientIsReady(i) && Clients[i].Username.ToLower() == usernameLower) { //Disconnect the player DisconnectClient(clientIndex, "Your username is already in use."); StampedConsoleWriteLine("Rejected client due to duplicate username: "******"There is currently 1 other user on this server: "); for (int i = 0; i < Clients.Length; i++) { if (i != clientIndex && 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[clientIndex].Username = username; Clients[clientIndex].ReceivedHandshake = true; SendServerMessage(clientIndex, sb.ToString()); SendServerSettings(clientIndex); StampedConsoleWriteLine(username + " ("+GetClientIP(clientIndex).ToString()+") has joined the server using client version " + version); if (!Clients[clientIndex].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(), clientIndex); } MessageFloodIncrement(clientIndex); } break; case KLFCommon.ClientMessageID.PrimaryPluginUpdate: case KLFCommon.ClientMessageID.SecondaryPluginUpdate: if (data != null && ClientIsReady(clientIndex)) { #if SEND_UPDATES_TO_SENDER SendPluginUpdateToAll(data, id == KLFCommon.ClientMessageID.SecondaryPluginUpdate); #else SendPluginUpdateToAll(data, id == KLFCommon.ClientMessageID.SecondaryPluginUpdate, clientIndex); #endif } break; case KLFCommon.ClientMessageID.TextMessage: if (data != null && ClientIsReady(clientIndex)) HandleClientTextMessage(clientIndex, encoder.GetString(data, 0, data.Length)); break; case KLFCommon.ClientMessageID.ScreenWatchPlayer: if(!ClientIsReady(clientIndex) || data == null || data.Length < 9) break; bool sendScreenshot = data[0] != 0; int watchIndex = KLFCommon.BytesToInt(data, 1); int currentIndex = KLFCommon.BytesToInt(data, 5); String watchName = encoder.GetString(data, 9, data.Length - 9); bool watchNameChanged = false; lock (Clients[clientIndex].WatchPlayerNameLock) { if(watchName != Clients[clientIndex].WatchPlayerName || watchIndex != Clients[clientIndex].WatchPlayerIndex) {//Set the watch player name Clients[clientIndex].WatchPlayerIndex = watchIndex; Clients[clientIndex].WatchPlayerName = watchName; watchNameChanged = true; } } if (sendScreenshot && watchNameChanged && watchName.Length > 0) {//Try to find the player the client is watching and send that player's current screenshot int watchedIndex = GetClientIndexByName(watchName); if (ClientIsReady(watchedIndex)) { Screenshot screenshot = null; lock (Clients[watchedIndex].ScreenshotLock) { screenshot = Clients[watchedIndex].GetScreenshot(watchIndex); if (screenshot == null && watchIndex == -1) screenshot = Clients[watchedIndex].LastScreenshot; } if(screenshot != null && screenshot.Index != currentIndex) SendScreenshot(clientIndex, screenshot); } } break; case KLFCommon.ClientMessageID.ScreenshotShare: if (data != null && data.Length <= Configuration.ScreenshotSettings.MaxNumBytes && ClientIsReady(clientIndex)) { if (!Clients[clientIndex].ScreenshotsThrottled) { StringBuilder sb = new StringBuilder(); Screenshot screenshot = new Screenshot(); screenshot.SetFromByteArray(data); //Set the screenshot for the player lock (Clients[clientIndex].ScreenshotLock) { Clients[clientIndex].PushScreenshot(screenshot); } sb.Append(Clients[clientIndex].Username); sb.Append(" has shared a screenshot."); SendTextMessageToAll(sb.ToString()); StampedConsoleWriteLine(sb.ToString()); //Send the screenshot to every client watching the player SendScreenshotToWatchers(clientIndex, screenshot); if (Configuration.SaveScreenshots) saveScreenshot(screenshot, Clients[clientIndex].Username); } bool throttled = Clients[clientIndex].ScreenshotsThrottled; Clients[clientIndex].ScreenshotFloodIncrement(); if (!throttled && Clients[clientIndex].ScreenshotsThrottled) { long throttleSeconds = Configuration.ScreenshotFloodThrottleTime / 1000; SendServerMessage(clientIndex, "You have been restricted from sharing screenshots for " + throttleSeconds + " seconds."); StampedConsoleWriteLine(Clients[clientIndex].Username + " has been restricted from sharing screenshots for " + throttleSeconds + " seconds."); } else if (Clients[clientIndex].CurrentThrottle.MessageFloodCounter == Configuration.ScreenshotFloodLimit - 1) SendServerMessage(clientIndex, "Warning: You are sharing too many screenshots."); } break; case KLFCommon.ClientMessageID.ConnectionEnd: String message = String.Empty; if (data != null) message = encoder.GetString(data, 0, data.Length); //Decode the message DisconnectClient(clientIndex, message); //Disconnect the client break; case KLFCommon.ClientMessageID.ShareCraftFile: if(ClientIsReady(clientIndex) && data != null && data.Length > 5 && (data.Length - 5) <= KLFCommon.MaxCraftFileBytes) { if (Clients[clientIndex].MessagesThrottled) { MessageFloodIncrement(clientIndex); break; } MessageFloodIncrement(clientIndex); //Read craft name length byte craftType = data[0]; int craftNameLength = KLFCommon.BytesToInt(data, 1); if (craftNameLength < data.Length - 5) { //Read craft name String craftName = encoder.GetString(data, 5, craftNameLength); //Read craft bytes byte[] craftBytes = new byte[data.Length - craftNameLength - 5]; Array.Copy(data, 5 + craftNameLength, craftBytes, 0, craftBytes.Length); lock (Clients[clientIndex].SharedCraftLock) { Clients[clientIndex].SharedCraftName = craftName; Clients[clientIndex].SharedCraftFile = craftBytes; Clients[clientIndex].SharedCraftType = craftType; } //Send a message to players informing them that a craft has been shared StringBuilder sb = new StringBuilder(); sb.Append(Clients[clientIndex].Username); sb.Append(" shared "); sb.Append(craftName); switch (craftType) { case KLFCommon.CraftTypeVab: sb.Append(" (VAB)"); break; case KLFCommon.CraftTypeSph: sb.Append(" (SPH)"); break; } StampedConsoleWriteLine(sb.ToString()); sb.Append(" . Enter " + KLFCommon.GetCraftCommand); sb.Append(Clients[clientIndex].Username); sb.Append(" to get it."); SendTextMessageToAll(sb.ToString()); } } break; case KLFCommon.ClientMessageID.ActivityUpdateInFlight: Clients[clientIndex].UpdateActivity(ServerClient.Activity.InFlight); break; case KLFCommon.ClientMessageID.ActivityUpdateInGame: Clients[clientIndex].UpdateActivity(ServerClient.Activity.InGame); break; case KLFCommon.ClientMessageID.Ping: Clients[clientIndex].QueueOutgoingMessage(KLFCommon.ServerMessageID.PingReply, null); break; } DebugConsoleWriteLine("Handled message"); }
protected void HandleMessage(KLFCommon.ServerMessageID id, byte[] data) { switch (id) { case KLFCommon.ServerMessageID.Handshake: Int32 protocolVersion = KLFCommon.BytesToInt(data); if (data.Length >= 8) { Int32 server_version_length = KLFCommon.BytesToInt(data, 4); if (data.Length >= 12 + server_version_length) { String server_version = Encoder.GetString(data, 8, server_version_length); ClientID = KLFCommon.BytesToInt(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 (protocolVersion != KLFCommon.NetProtocolVersion) { Console.WriteLine("Server version is incompatible with client version."); EndSession = true; IntentionalConnectionEnd = true; } else { SendHandshakeMessage(); //Reply to the handshake lock (UdpTimestampLock) { LastUdpMessageSendTime = ClientStopwatch.ElapsedMilliseconds; } HandshakeComplete = true; } break; case KLFCommon.ServerMessageID.HandshakeRefusal: 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.ServerMessage: case KLFCommon.ServerMessageID.TextMessage: if (data != null) { InTextMessage inMessage = new InTextMessage(); inMessage.FromServer = (id == KLFCommon.ServerMessageID.ServerMessage); inMessage.message = Encoder.GetString(data, 0, data.Length); //Queue the message EnqueueTextMessage(inMessage); } break; case KLFCommon.ServerMessageID.PluginUpdate: if (data != null) SendClientInteropMessage(KLFCommon.ClientInteropMessageID.PluginUpdate, data); break; case KLFCommon.ServerMessageID.ServerSettings: lock (ServerSettingsLock) { if (data != null && data.Length >= KLFCommon.ServerSettingsLength && HandshakeComplete) { UpdateInterval = KLFCommon.BytesToInt(data, 0); ScreenshotInterval = KLFCommon.BytesToInt(data, 4); lock (ClientDataLock) { int new_screenshot_height = KLFCommon.BytesToInt(data, 8); if (ScreenshotConfiguration.MaxHeight != new_screenshot_height) { ScreenshotConfiguration.MaxHeight = new_screenshot_height; LastClientDataChangeTime = ClientStopwatch.ElapsedMilliseconds; EnqueueTextMessage("Screenshot Height has been set to " + ScreenshotConfiguration.MaxHeight); } if (InactiveShipsPerUpdate != data[12]) { InactiveShipsPerUpdate = data[12]; LastClientDataChangeTime = ClientStopwatch.ElapsedMilliseconds; } } } } break; case KLFCommon.ServerMessageID.ScreenshotShare: if (data != null && data.Length > 0 && data.Length < ScreenshotConfiguration.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.ScreenshotReceive, data); } break; case KLFCommon.ServerMessageID.ConnectionEnd: 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.UdpAcknowledge: lock (UdpTimestampLock) { LastUdpAckReceiveTime = ClientStopwatch.ElapsedMilliseconds; } break; case KLFCommon.ServerMessageID.CraftFile: if (data != null && data.Length > 4) { //Read craft name length byte craftType = data[0]; int craftName_length = KLFCommon.BytesToInt(data, 1); if (craftName_length < data.Length - 5) { //Read craft name String craftName = Encoder.GetString(data, 5, craftName_length); //Read craft bytes byte[] craft_bytes = new byte[data.Length - craftName_length - 5]; Array.Copy(data, 5 + craftName_length, craft_bytes, 0, craft_bytes.Length); //Write the craft to a file String filename = GetCraftFilename(craftName, craftType); if (filename != null) { try { File.WriteAllBytes(filename, craft_bytes); EnqueueTextMessage("Received craft file: " + craftName); } catch { EnqueueTextMessage("Error saving received craft file: " + craftName); } } else EnqueueTextMessage("Unable to save received craft file."); } } break; case KLFCommon.ServerMessageID.PingReply: if (PingStopwatch.IsRunning) { EnqueueTextMessage("Ping Reply: " + PingStopwatch.ElapsedMilliseconds + "ms"); PingStopwatch.Stop(); PingStopwatch.Reset(); } break; } }