void StartServer() { started = true; OperationNetwork.isServer = true; myServer = new ServerAcceptor(); myServer.StartServer(); // This is to get the server player to connect: OperationNetwork.initialConnected = 0; // The server player doesn't necessarily have to connect first. // Demo maker: ServerPerson sP = new ServerPerson(myServer); sP.setDemo(); // Revert addID: ServerPerson.addID--; RunGame.myServerThreads.Add(sP); // PlayerListHandler does not consider demo client. // Instantly connect the demo client: sP.connected = true; }
static int runMovementCommandData(ServerPerson theClient, short packetID, byte[] data, bool runPlayerInput, short index) { byte numFrames = data [0]; int endPoint = 1; for (int i = 0; i < numFrames; i++) { byte length = data [endPoint++]; byte[] dataForPlayerInput = new byte[length]; Buffer.BlockCopy(data, endPoint, dataForPlayerInput, 0, length); endPoint += length; if (index != -1 && runPlayerInput) { operationObjects [index].GetComponent <PlayerMove> ().movementData(packetID, dataForPlayerInput); } } return(endPoint); }
void sendGameStatesToPlayer(GameState serverState, ServerPerson theClient) { if (theClient.connected) { // This is easy enough, we send both game states every time, so both game states are expected in the 1, 2 order each time. bool changedData = theClient.lastSentGameState[theClient.lastSentGameState.Length - 1] != null; // Obviously server overrides this // First, we strip serverState of its playerData when getting its data: byte[] data1 = serverState.getDataWithoutPlayerData(changedData, theClient.id, theClient.shouldNextSendOutBeFullSendOut); theClient.shouldNextSendOutBeFullSendOut = false; // Now, we create the player gamestate, and send that: Interp.shiftBuffer(theClient.lastSentGameState); theClient.lastSentGameState[0] = new GameState(theClient.lastSentGameState, ServerState.tickNumber, theClient.id); // lastSentGameState is used to determine if changedData here byte[] data2 = theClient.lastSentGameState[0].getChangedData(); byte[] data = new byte[data1.Length + data2.Length]; Buffer.BlockCopy(data1, 0, data, 0, data1.Length); Buffer.BlockCopy(data2, 0, data, data1.Length, data2.Length); theClient.SendData(data, false); } }
public static void serverReceivedInput(byte[] data, int fromWho, short packetID) { // We need to go out and find the index for this object: short index = -1; if (GameManager.GetPlayer((short)fromWho).playerObject != null) { index = GameManager.GetPlayer((short)fromWho).playerObject.GetComponent <SyncGameState> ().objectID; } // In the model where commands are sent more than once to avoid excessive lag due to packet loss, // We must check that the packetID is not the same. ServerPerson thisClient = getClient((short)fromWho); bool runPlayerInput = true; if ((short)(thisClient.lastPlayerInputGroupID + 1) == packetID) { // Good to go thisClient.lastPlayerInputGroupID++; // By definition, this should never happen: if (thisClient.inputCommands.ContainsKey(packetID)) { Debug.LogError("Packet existed but wasn't run! OperationNetwork -> serverReceivedInput"); thisClient.inputCommands.Remove(packetID); } // I would assume its limited to 30ish (20) for (int i = 1; i < 30; i++) { if (thisClient.inputCommands.ContainsKey((short)(packetID + i))) { thisClient.lastPlayerInputGroupID = (short)(packetID + i); runMovementCommandData(thisClient, packetID, thisClient.inputCommands [(short)(packetID + i)], true, index); thisClient.inputCommands.Remove((short)(packetID + i)); } else { break; } } // This allows for a maximum of (8) buffered input commands, which is WAY more than we should ever have.. probably.. -but now out of order needs to be considered } else { bool found = false; // OLD packets: (This includes the same packet, of course). for (int i = 0; i < 160; i++) { if ((short)(thisClient.lastPlayerInputGroupID - i) == packetID) { found = true; runPlayerInput = false; break; } } // We assume that these are simply packets that are slightly out of order.. if (!found) { // FUTURE packets. Note that 30 means that in the current system, after not receiving a certain packet in 400ms, you will rubber band for that entire second. TODO make it so it runs what it can when rubber banding occurs for (int i = 2; i < 20; i++) { if ((short)(thisClient.lastPlayerInputGroupID + i) == packetID) { found = true; runPlayerInput = false; if (!thisClient.inputCommands.ContainsKey(packetID)) { thisClient.inputCommands.Add(packetID, data); } break; } } // First, we are going to check if the command was from before. These simply need to be skipped // Otherwise, we assume the command is too late and we run all buffered input commands including this one to "catch up" if (!found) { Debug.LogError("Rubber Banding!!! " + thisClient.lastPlayerInputGroupID + " / " + packetID); thisClient.inputCommands.Clear(); // And start off input from hereon out: runPlayerInput = true; thisClient.lastPlayerInputGroupID = packetID; } } // Note that packets more out of order than the above limit will cause all previous packets to be skipped. // Running an out of order packet will cause all packets available to run, regardless if +1 order is maintained. } // The code after this will run to iterate through the data, but with a bool to see if the code should actually be simulated. int endPoint = runMovementCommandData(thisClient, packetID, data, runPlayerInput, index); if (endPoint < data.Length) { // And then the next input command is read: (We technically don't have to run this if the player doesn't exist) byte[] nextData = new byte[data.Length - endPoint]; Buffer.BlockCopy(data, endPoint, nextData, 0, data.Length - endPoint); serverReceivedInput(nextData, fromWho, (short)(packetID + 1)); } }
public void ReadMessages() { for (int i = 0; i < 5000; i++) { try { int recHostId; int recConnectionId; int recChannelId; byte[] recBuffer = new byte[2048]; int bufferSize = 2048; int dataSize; byte error; NetworkEventType networkEvent = NetworkTransport.Receive(out recHostId, out recConnectionId, out recChannelId, recBuffer, bufferSize, out dataSize, out error); NetworkError networkError = (NetworkError)error; if (networkError != NetworkError.Ok) { Debug.LogError(string.Format("Error recieving event: {0} with recHostId: {1}, recConnectionId: {2}, recChannelId: {3}", networkError, recHostId, recConnectionId, recChannelId)); } switch (networkEvent) { case NetworkEventType.Nothing: return; case NetworkEventType.ConnectEvent: Debug.LogError(string.Format("incoming connection event received with connectionId: {0}, recHostId: {1}, recChannelId: {2}", recConnectionId, recHostId, recChannelId)); if (!serverClients.ContainsKey(recConnectionId)) { // Add server client: ServerPerson sP = new ServerPerson(this); RunGame.myServerThreads.Add(sP); // hmm... player.players.Add(sP.id, new OtherPlayerInfo()); // Stick to default settings until a RPC is received. sP.recConnectionId = recConnectionId; serverClients.Add(recConnectionId, sP); } break; case NetworkEventType.DataEvent: // Player Input! // Delegate this to the "ServerClientData" first: if (serverClients.ContainsKey(recConnectionId)) { short id = serverClients [recConnectionId].id; if (dataSize > 500) { Debug.LogError("Nearing Data limit on server: " + dataSize + ": " + recChannelId + "(" + reliableSequencedChannelId + " / " + unreliableChannelId + ")"); } // todo: When removing RPCs, we're going to make this into a proper ref index sorta thing: byte[] rpcData = new byte[dataSize]; Buffer.BlockCopy(recBuffer, 0, rpcData, 0, dataSize); if (recChannelId == reliableSequencedChannelId) { OperationNetwork.serverReceivedData(rpcData, id); } else { short packetID = BitConverter.ToInt16(rpcData, 0); byte[] sData = new byte[rpcData.Length - 2]; // This might be one of the most inefficient things on the server, TODO!! The copy of byte data!! Buffer.BlockCopy(rpcData, 2, sData, 0, sData.Length); OperationNetwork.serverReceivedInput(sData, id, packetID); } } else { Debug.LogError("Client not connected: " + recConnectionId); } break; case NetworkEventType.DisconnectEvent: Debug.LogError("remote client " + recConnectionId + " disconnected"); if (serverClients.ContainsKey(recConnectionId)) { RunGame.myServerThreads.Remove(serverClients [recConnectionId]); serverClients [recConnectionId].disconnect(); serverClients.Remove(recConnectionId); } break; } } catch (Exception e) { Debug.LogError("Error on client data receive: " + e.Message); } } Debug.LogError("Missing Messages on Server!"); }