private void PredictOwner() { ServerState serverState; svbuffer = m_serverStateBuffer.Count; if (m_serverStateBuffer.Count > 0) { serverState = m_serverStateBuffer[m_serverStateBuffer.Count - 1]; serverId = serverState.messageId; //debug if ((m_pendingStates.Count > 0)) { //remove all old input states but the newest two - they are required for interpolation while ((m_pendingStates.Count > 2) && (serverState.messageId >= m_pendingStates[0].keyState.messageId)) { /*if ( * (serverState.messageId == m_pendingStates[0].keyState.messageId) && * serverState.inhibitReconciliation * ) * { * Debug.Log("inhibited"); * }*/ //update position with server data if ( (serverState.messageId == m_pendingStates[0].keyState.messageId) && !serverState.inhibitReconciliation && (serverState.properties != m_pendingStates[0].properties) ) { //Debug.Log ("update pos " + serverState.messageId + " " + m_pendingStates[0].keyState.messageId); m_movement.SetProperties(serverState.properties); m_pendingStates.RemoveAt(0); //re-apply all remaining states if (m_pendingStates.Count > 0) { for (int i = 0; i < m_pendingStates.Count; i++) { ClientState clientState = m_pendingStates[i]; NetKeyState keyState = clientState.keyState; m_input.Process(keyState.inputData); m_movement.ProcessInputs(m_input.GetInputData(), Time.fixedDeltaTime); clientState.properties = m_movement.GetProperties(); m_pendingStates[i] = clientState; } } } else { m_pendingStates.RemoveAt(0); } } } m_serverStateBuffer.Clear(); } }
public int postponed = 0; //debug public void UpdateClientMotion(int id, int inputData) { NetKeyState keyState = new NetKeyState(id, inputData); postponed = m_postponedInputs.Count; if (id == m_nextId) { //correct order, add to queue m_pendingInputs.Enqueue(keyState); m_nextId++; } else if (id > m_nextId) { //wrong order, put newer snapshots aside //Debug.Log("postpone " + id); m_postponedInputs.Add(id, keyState); } else { //snapshot was delayed too long and is of no use anymore Debug.LogWarning("delayed snapshot dropped " + id); } //grab any postponed followup keystates while (m_postponedInputs.ContainsKey(m_nextId)) { m_pendingInputs.Enqueue(m_postponedInputs[m_nextId]); //Debug.Log("enqueue "+nextId); m_postponedInputs.Remove(m_nextId); m_nextId++; } //skip keystate id if too many snapshots are postponed already if (m_postponedInputs.Count >= c_postponedLength) { //rebuild latest keystate and add to queue with lost id //otherwise client and server would run out of sync with their message ids int input = m_sendBuffer[m_sendBuffer.Count - 1].inputData; keyState = new NetKeyState(m_nextId, input); m_pendingInputs.Enqueue(keyState); Debug.LogWarning("snapshot skipped " + m_nextId); m_nextId++; } }
public ClientState(NetKeyState keyState, PlayerProperties properties) { this.keyState = keyState; this.properties = properties; }
void FixedUpdate() { if (isLocalPlayer) { //store interpolated player state PlayerProperties properties = m_movement.GetProperties(); //update from server - includes reconciliation PredictOwner(); m_input.Process(); m_messageId++; int data = m_input.Data(); NetKeyState keyState = new NetKeyState(m_messageId, data); //client prediction //rewind to last non interpolated state if (m_pendingStates.Count > 0) { ClientState cs = m_pendingStates[m_pendingStates.Count - 1]; m_movement.SetProperties(cs.properties); } // m_movement.ProcessInputs(m_input.GetInputData(), Time.fixedDeltaTime); m_movement.ProcessActions(m_input.GetInputData(), Time.fixedDeltaTime); //local prediction of actions if (/*!isServer ||*/ (isServer && isClient)) { //m_movement.ProcessActions(m_input.GetInputData()); //local prediction of actions m_movement.ProcessEvents(); } m_movement.ProcessInputs(m_input.GetInputData(), Time.fixedDeltaTime); //send key state to server if (connectionToServer.isReady && m_streamer != null) { //DEBUG START /*serverid = m_messageId; * if (m_input.shoot == true) * { * string ids = ""; * //Debug.Log (PlayerManager.m_players.Count); * foreach(PlayerIdentity identity in PlayerManager.Players) * { * if (identity.gameObject == gameObject) * { * continue; * } * NetClPlayerManager clm = identity.gameObject.GetComponent<NetClPlayerManager>(); * if (clm.m_serverStateBuffer.Count > 0) * ids += identity.name+": "+clm.m_serverStateBuffer[0].messageId+" "; * } * Debug.Log (name+": "+m_messageId +" ("+ids+")"); * }*/ //DEBUG END m_streamer.CmdUpdateMotion(m_messageId, data); } //client reconciliation: add key state to pending input list //log curent player state for cl<->sv deviation check if (m_pendingStates.Count == 100) { m_pendingStates.RemoveAt(0); } ClientState clientState = new ClientState(keyState, m_movement.GetProperties()); m_pendingStates.Add(clientState); //prepare for interpolation - rewind to interpolated state m_movement.SetProperties(properties); m_stateTime = Time.time; } }