/* * SHARED */ //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>FIXED UPDATE private void FixedUpdate() { float speed = 0f; //If this is running at the local player (client with authoritative control or host client) //We run normal FPS controller (prediction) if(isLocalPlayer) { //This must be before move to check if move grounded the character m_PreviouslyGrounded = m_CharacterController.isGrounded; currentStamp = Network.time; //Store crouch input to send to server //We do this before reading input so that we can compare with the current crouch state bool sendCrouch = m_isCrouching; //Input from user or simulated if(inputSimulation) { SimInput(out speed); } else { GetInput(out speed); } //Store jump input to send to server //We need to store this here because player movement will clear m_Jump bool sendJump = m_Jump; // Store transform values //This is also used for the host to know if it moved to send change messages Vector3 prevPosition = transform.position; Quaternion prevRotation = transform.rotation; // Store collision values CollisionFlags lastFlag = m_CollisionFlags; //If we have predicion, we use the input here to move the character if(prediction) { //Move the player object PlayerMovement(speed); } //Client sound and camera ProgressStepCycle(speed); if(!m_PreviouslyGrounded && m_CharacterController.isGrounded) { StartCoroutine(m_JumpBob.DoBobCycle()); PlayLandingSound(); } //OWNER CLIENTS THAT ARE NOT THE HOST //CLIENTS THAT ARE NOT THE SERVER if(!isServer) { bool crouchChange = m_isCrouching != sendCrouch; bool moved = Vector3.Distance(prevPosition, transform.position) > 0 || m_Input[0] || m_Input[1] || m_Input[2] || m_Input[3]; if(moved || sendJump || crouchChange || rotationChanged) { //Store all inputs generated between msgs to send to server Inputs inputs = new Inputs(); inputs.yaw = transform.rotation.eulerAngles.y; inputs.pitch = m_firstPersonCharacter.rotation.eulerAngles.x; inputs.wasd = m_Input; inputs.move = moved; inputs.walk = m_IsWalking; inputs.rotate = rotationChanged; inputs.jump = sendJump; inputs.crouch = m_isCrouching; inputs.timeStamp = currentStamp; inputsList.Enqueue(inputs); debugMovement dePos = new debugMovement(); // DEBUG POSITION dePos.velocity = m_CharacterController.velocity; dePos.position = transform.position; debugClientPos.Enqueue(dePos); //If we moved, then we need to store reconciliation if(moved || sendJump || crouchChange) { // Create reconciliation entry ReconciliationEntry entry = new ReconciliationEntry(); entry.inputs = inputs; entry.lastFlags = lastFlag; entry.position = prevPosition; entry.rotationYaw = transform.rotation.eulerAngles.y; entry.grounded = m_PreviouslyGrounded; entry.prevCrouching = m_PreviouslyCrouching; AddReconciliation(entry); } //Clear the jump to send sendJump = false; //Clear rotation flag rotationChanged = false; } } //HOST CLIENT if (isServer) { if(Vector3.Distance(transform.position, prevPosition) > 0 || rotationChanged) { movementToSend = true; } } //Thread.Sleep(7); } /* * SERVER SIDE */ else { //If we are on the server, we process commands from the client instead, and generate update messages if(isServer) { //Thread.Sleep(7); //Store state Vector3 lastPosition = transform.position; Quaternion lastCharacterRotation = transform.rotation; Quaternion lastCameraRotation = m_firstPersonCharacter.rotation; //Create the struct to read possible input to calculate Inputs inputs; inputs.rotate = false; //If we have inputs, get them and simulate on the server if(inputsList.Count > 0) { while(inputsList.Count > 0) { inputs = inputsList.Dequeue(); m_IsWalking = inputs.walk; m_Input = inputs.wasd; m_isCrouching = inputs.crouch; m_Jump = inputs.jump; currentStamp = inputs.timeStamp; //If need to, apply rotation if(inputs.rotate) { transform.rotation = Quaternion.Euler(transform.rotation.x, inputs.yaw, transform.rotation.z); m_firstPersonCharacter.rotation = Quaternion.Euler(inputs.pitch, m_firstPersonCharacter.rotation.eulerAngles.y, m_firstPersonCharacter.rotation.eulerAngles.z); } //If need to, simulate movement if(inputs.move) { //Server-side method to the speed out of input from clients CalcSpeed(out speed); //Move the player object PlayerMovement(speed); } //Check if something changed and store //This prevents movement skipping if(Vector3.Distance(transform.position, lastPosition) > 0 || inputs.rotate) { movementToSend = true; } } } m_PreviouslyGrounded = m_CharacterController.isGrounded; } } }
/* * SHARED */ //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>FIXED UPDATE private void FixedUpdate() { float speed = 0f; //If this is running at the local player (client with authoritative control or host client) //We run normal FPS controller (prediction) if (isLocalPlayer) { //This must be before move to check if move grounded the character m_PreviouslyGrounded = m_CharacterController.isGrounded; currentStamp = Network.time; //Store crouch input to send to server //We do this before reading input so that we can compare with the current crouch state bool sendCrouch = m_isCrouching; //Input from user or simulated if (inputSimulation) { SimInput(out speed); } else { GetInput(out speed); } //Store jump input to send to server //We need to store this here because player movement will clear m_Jump bool sendJump = m_Jump; // Store transform values //This is also used for the host to know if it moved to send change messages Vector3 prevPosition = transform.position; Quaternion prevRotation = transform.rotation; // Store collision values CollisionFlags lastFlag = m_CollisionFlags; //If we have predicion, we use the input here to move the character if (prediction) { //Move the player object PlayerMovement(speed); } //Client sound and camera ProgressStepCycle(speed); if (!m_PreviouslyGrounded && m_CharacterController.isGrounded) { StartCoroutine(m_JumpBob.DoBobCycle()); PlayLandingSound(); } //OWNER CLIENTS THAT ARE NOT THE HOST //CLIENTS THAT ARE NOT THE SERVER if (!isServer) { bool crouchChange = m_isCrouching != sendCrouch; bool moved = Vector3.Distance(prevPosition, transform.position) > 0 || m_Input[0] || m_Input[1] || m_Input[2] || m_Input[3]; if (moved || sendJump || crouchChange || rotationChanged) { //Store all inputs generated between msgs to send to server Inputs inputs = new Inputs(); inputs.yaw = transform.rotation.eulerAngles.y; inputs.pitch = m_firstPersonCharacter.rotation.eulerAngles.x; inputs.wasd = m_Input; inputs.move = moved; inputs.walk = m_IsWalking; inputs.rotate = rotationChanged; inputs.jump = sendJump; inputs.crouch = m_isCrouching; inputs.timeStamp = currentStamp; inputsList.Enqueue(inputs); debugMovement dePos = new debugMovement(); // DEBUG POSITION dePos.velocity = m_CharacterController.velocity; dePos.position = transform.position; debugClientPos.Enqueue(dePos); //If we moved, then we need to store reconciliation if (moved || sendJump || crouchChange) { // Create reconciliation entry ReconciliationEntry entry = new ReconciliationEntry(); entry.inputs = inputs; entry.lastFlags = lastFlag; entry.position = prevPosition; entry.rotationYaw = transform.rotation.eulerAngles.y; entry.grounded = m_PreviouslyGrounded; entry.prevCrouching = m_PreviouslyCrouching; AddReconciliation(entry); } //Clear the jump to send sendJump = false; //Clear rotation flag rotationChanged = false; } } //HOST CLIENT if (isServer) { if (Vector3.Distance(transform.position, prevPosition) > 0 || rotationChanged) { movementToSend = true; } } //Thread.Sleep(7); } /* * SERVER SIDE */ else //If we are on the server, we process commands from the client instead, and generate update messages { if (isServer) { //Thread.Sleep(7); //Store state Vector3 lastPosition = transform.position; Quaternion lastCharacterRotation = transform.rotation; Quaternion lastCameraRotation = m_firstPersonCharacter.rotation; //Create the struct to read possible input to calculate Inputs inputs; inputs.rotate = false; //If we have inputs, get them and simulate on the server if (inputsList.Count > 0) { while (inputsList.Count > 0) { inputs = inputsList.Dequeue(); m_IsWalking = inputs.walk; m_Input = inputs.wasd; m_isCrouching = inputs.crouch; m_Jump = inputs.jump; currentStamp = inputs.timeStamp; //If need to, apply rotation if (inputs.rotate) { transform.rotation = Quaternion.Euler(transform.rotation.x, inputs.yaw, transform.rotation.z); m_firstPersonCharacter.rotation = Quaternion.Euler(inputs.pitch, m_firstPersonCharacter.rotation.eulerAngles.y, m_firstPersonCharacter.rotation.eulerAngles.z); } //If need to, simulate movement if (inputs.move) { //Server-side method to the speed out of input from clients CalcSpeed(out speed); //Move the player object PlayerMovement(speed); } //Check if something changed and store //This prevents movement skipping if (Vector3.Distance(transform.position, lastPosition) > 0 || inputs.rotate) { movementToSend = true; } } } m_PreviouslyGrounded = m_CharacterController.isGrounded; } } }