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;
        }
    }