//This method looks through the data structure and scans for timedout connections public static void CheckForClientTimeout(float timeout) { BaseControllerType temp; bool foundDeadConnection = false; if (WiFiInputController.controllerDataDictionary != null) { for (int keyIndex = 0; keyIndex < WiFiInputController.controllerDataDictionaryKeys.Count; ++keyIndex) { string key = WiFiInputController.controllerDataDictionaryKeys[keyIndex]; temp = WiFiInputController.controllerDataDictionary[key]; if (!temp.controllerType.Contains(WiFiInputConstants.BACKCHANNEL_FILTER) && temp.logicalPlayerNumber != WiFiInputConstants.PLAYERNUMBER_DISCONNECTED && (DateTime.UtcNow - temp.lastReceivedPacketTime).TotalSeconds > timeout && (DateTime.UtcNow - temp.lastReceivedPacketTime).TotalSeconds < 150d) { temp.previousConnectionPlayerNumber = temp.logicalPlayerNumber; temp.logicalPlayerNumber = WiFiInputConstants.PLAYERNUMBER_DISCONNECTED; foundDeadConnection = true; WiFiInputController.lastConnectedPlayerNumber = temp.previousConnectionPlayerNumber; } } } //if we found a dead connection let the callback know if (foundDeadConnection) { WiFiInputController.isConnect = false; WiFiInputController.forceConnectionRefresh(); } }
public static void createAndSendHeartbeatMessages(int packetNumber) { BaseControllerType temp; //loop through each client foreach (string client in serverSendKeys) { bool send = true; string message = WiFiInputConstants.MESSAGETYPE_HEARTBEAT + WiFiInputConstants.SPLITMESSAGE_COLON + packetNumber.ToString(); for (int keyIndex = 0; keyIndex < controllerDataDictionaryKeys.Count; ++keyIndex) { string key = controllerDataDictionaryKeys[keyIndex]; temp = controllerDataDictionary[key]; if (temp.clientIP.Equals(client) && temp.logicalPlayerNumber == WiFiInputConstants.PLAYERNUMBER_DISCONNECTED) { //we've found that this is actually disconnected send = false; break; } } //we don't want to send heartbeat to those marked as disconnected if (send) { WiFiInputController.sendHeartbeat(message, client); } } }
// INTERNALS private void SendServerHeartbeat() { WiFiInputController.createAndSendHeartbeatMessages(heartbeatPacketNumber); //increment the packet number if (heartbeatPacketNumber < WiFiInputConstants.ROLLOVER_PACKET_NUMBER) { heartbeatPacketNumber++; } else { heartbeatPacketNumber = 0; } }
// LOGIC public void Initialize() { Screen.sleepTimeout = SleepTimeout.NeverSleep; WiFiInputController.initialize(applicationName, serverSocketPort, clientSocketPort, logVerbose, clientConnectAutomatically); if (serverSendHeartbeatRate > 0f) { InvokeRepeating("SendServerHeartbeat", serverSendHeartbeatRate, serverSendHeartbeatRate); } if (clientTimeout > 0f) { InvokeRepeating("CheckForClientTimeout", clientTimeout, clientTimeout); } }
//for our network traffic on both ends we are essentially having strings (converted in/out for byte[] on the send/recieve //these methods essentially will be one line in the string (remember a client will have more than one controller type) //this method is called when a packet is received on a connection that is marked as disconnected due to a timeout //this can occur in game usecases when the player suspends the app and restarts and expects the controller to still work //because the app wasn't executing having the server sending a message stating hey you timed out is useless //instead because our design is player based simply check to see if another controller has been assigned this player number //if not then just change the player number back and proceed as normal //if another controller has then get the next available player number and then notify the callback of a changed connection public void reuseOrGetAnotherConnection(int previousPlayerNumber) { if (WiFiInputUtilities.isPlayerNumberOccupied(previousPlayerNumber, clientKey)) { logicalPlayerNumber = WiFiInputController.getNewPlayerNumber(clientKey); } else { logicalPlayerNumber = previousConnectionPlayerNumber; } lastReceivedPacketTime = DateTime.UtcNow; justReconnected = true; //take this time to reactivate all of the controls from this IP address so callback only get fired once BaseControllerType temp; string[] splitter = { clientKey }; String[] clientIP = serverKey.Split(splitter, StringSplitOptions.RemoveEmptyEntries); if (WiFiInputController.controllerDataDictionary != null) { foreach (string key in WiFiInputController.controllerDataDictionary.Keys) { temp = WiFiInputController.controllerDataDictionary[key]; if (temp.serverKey.Contains(clientIP[0])) { temp.justReconnected = true; temp.lastReceivedPacketTime = DateTime.UtcNow; temp.logicalPlayerNumber = logicalPlayerNumber; } } } //send the callback for a connection WiFiInputController.isConnect = true; WiFiInputController.lastConnectedPlayerNumber = logicalPlayerNumber; WiFiInputController.forceConnectionRefresh(); }
// MonoBehaviour's interface void OnApplicationQuit() { WiFiInputController.endUDPClientAndThread(); }