Esempio n. 1
0
        IEnumerator SendResultsC(Results res)
        {
            yield return(new WaitForSeconds(UnityEngine.Random.Range(0.21f, 0.38f)));
#endif

            if (isLocalPlayer)
            {
                Debug_UI.UpdateUI(res.position, res.position, res.position, currentTick, res.timestamp);
                serverResults = res;
                worldUpdated  = true;
            }
            else
            {
                currentTick++;
                updateCount++;

                lastResults = res;
                GameManager.PlayerTick(this, lastResults);
                if (tickUpdate != null)
                {
                    tickUpdate(res, false);
                }

                histResults[updateCount % 3] = lastResults;

                if (currentTick > 2 && currentTick % GameManager.singleton.networkSettings.maxDeltaTicks != 0)
                {
                    //if (Time.fixedTime - 2f > startTime)
                    startTime = Mathf.Min(Time.time, Time.fixedTime);
                    //else
                    //	startTime = Time.fixedTime - ((Time.fixedTime - startTime) / (Time.fixedDeltaTime * _sendUpdates) - 1) * (Time.fixedDeltaTime * _sendUpdates);
                }
                else
                {
                    startTime = Mathf.Min(Time.time, Time.fixedTime);
                }
            }
        }
Esempio n. 2
0
 void Awake()
 {
     singleton = this;
 }
Esempio n. 3
0
        IEnumerator SendResultsC(Results res)
        {
            yield return(new WaitForSeconds(UnityEngine.Random.Range(0.21f, 0.38f)));
                        #endif

            if (isLocalPlayer)
            {
                foreach (Results t in clientResults)
                {
                    if (t.timestamp == res.timestamp)
                    {
                        Debug_UI.UpdateUI(posEnd, res.position, t.position, currentTick, res.timestamp);
                    }
                }

                if (serverResultList.Count > data.serverResultsBuffer)
                {
                    serverResultList.RemoveAt(0);
                }

                if (!ServerResultsContainTimestamp(res.timestamp))
                {
                    serverResultList.Add(res);
                }

                serverResults = SortServerResultsAndReturnFirst();

                if (serverResultList.Count >= data.serverResultsBuffer)
                {
                    reconciliate = true;
                }
            }
            else
            {
                currentTick++;

                if (!isServer)
                {
                    serverResults = res;
                    if (tickUpdate != null)
                    {
                        tickUpdate(res);
                    }
                }

                if (currentTick > 2)
                {
                    serverResults = res;
                    posStart      = posEnd;
                    rotStart      = rotEnd;
                    headStartRot  = headEndRot;
                    headEndRot    = res.camX;
                    //if (Time.fixedTime - 2f > startTime)
                    startTime = Time.fixedTime;
                    //else
                    //	startTime = Time.fixedTime - ((Time.fixedTime - startTime) / (Time.fixedDeltaTime * _sendUpdates) - 1) * (Time.fixedDeltaTime * _sendUpdates);
                    posEnd          = posEndO;
                    rotEnd          = rotEndO;
                    groundPointTime = serverResults.groundPointTime;
                    posEndG         = serverResults.groundPoint;
                    posEndO         = serverResults.position;
                    rotEndO         = serverResults.rotation;
                }
                else
                {
                    startTime       = Time.fixedTime;
                    serverResults   = res;
                    posStart        = serverResults.position;
                    rotStart        = serverResults.rotation;
                    headStartRot    = headEndRot;
                    headEndRot      = res.camX;
                    posEnd          = posStart;
                    rotEnd          = rotStart;
                    groundPointTime = serverResults.groundPointTime;
                    posEndG         = posEndO.y;
                    posEndO         = posStart;
                    rotEndO         = rotStart;
                }
            }
        }
Esempio n. 4
0
		void CmdSendInputs (Inputs inp, Results res) {
		#else
		void CmdSendInputs (Inputs inp) {
		#endif
			#if (SIMULATE)
			#if (CLIENT_TRUST)
			StartCoroutine (SendInputs (inp, res));
			#else
			StartCoroutine (SendInputs (inp));
			#endif
		}
		#if (CLIENT_TRUST)
		IEnumerator SendInputs (Inputs inp, Results res) {
		#else
		IEnumerator SendInputs (Inputs inp) {
		#endif
			yield return new WaitForSeconds (UnityEngine.Random.Range (0.21f, 0.28f));
			#endif

			if (!isLocalPlayer) {

				if (clientInputs.Count > data.clientInputsBuffer)
					clientInputs.RemoveAt (0);

				if (!ClientInputsContainTimestamp (inp.timestamp))
					clientInputs.Add (inp);

				#if (CLIENT_TRUST)
				tempResults = res;
				#endif

				currentTFixedUpdates += sendUpdates;

				if (data.debug && lastTick + 1 != inp.timestamp && lastTick != -1) {
					Debug.Log ("Missing tick " + lastTick + 1);
				}
				lastTick = inp.timestamp;
			}
		}

		[ClientRpc]
		void RpcSendResults (Results res) {

			if (isServer)
				return;
			#if (SIMULATE)
			StartCoroutine (SendResults (res));
		}

		IEnumerator SendResults (Results res) {
			yield return new WaitForSeconds (UnityEngine.Random.Range (0.21f, 0.38f));
			#endif

			if (isLocalPlayer) {

				foreach (Results t in clientResults) {
					if (t.timestamp == res.timestamp)
						Debug_UI.UpdateUI (posEnd, res.position, t.position, currentTick, res.timestamp);
				}

				if (serverResultList.Count > data.serverResultsBuffer)
					serverResultList.RemoveAt (0);

				if (!ServerResultsContainTimestamp (res.timestamp))
					serverResultList.Add (res);

				serverResults = SortServerResultsAndReturnFirst ();

				if (serverResultList.Count >= data.serverResultsBuffer)
					reconciliate = true;

			} else {
				currentTick++;

				if (!isServer) {
					serverResults = res;
					onTickUpdate.Invoke (res);
				}

				if (currentTick > 2) {
					serverResults = res;
					posStart = posEnd;
					rotStart = rotEnd;
					headStartRot = headEndRot;
					headEndRot = res.camX;
					//if (Time.fixedTime - 2f > startTime)
						startTime = Time.fixedTime;
					//else
					//	startTime = Time.fixedTime - ((Time.fixedTime - startTime) / (Time.fixedDeltaTime * _sendUpdates) - 1) * (Time.fixedDeltaTime * _sendUpdates);
					posEnd = posEndO;
					rotEnd = rotEndO;
					groundPointTime = serverResults.groundPointTime;
					posEndG = serverResults.groundPoint;
					posEndO = serverResults.position;
					rotEndO = serverResults.rotation;
				} else {
					startTime = Time.fixedTime;
					serverResults = res;
					posStart = serverResults.position;
					rotStart = serverResults.rotation;
					headStartRot = headEndRot;
					headEndRot = res.camX;
					posEnd = posStart;
					rotEnd = rotStart;
					groundPointTime = serverResults.groundPointTime;
					posEndG = posEndO.y;
					posEndO = posStart;
					rotEndO = rotStart;

				}
			}
		}

		Results SortServerResultsAndReturnFirst () {

			Results tempRes;

			for (int x = 0; x < serverResultList.Count; x++) {
				for (int y = 0; y < serverResultList.Count - 1; y++) {
					if (serverResultList [y].timestamp > serverResultList [y + 1].timestamp) {
						tempRes = serverResultList [y + 1];
						serverResultList [y + 1] = serverResultList [y];
						serverResultList [y] = tempRes;
					}
				}
			}

			if (serverResultList.Count > data.serverResultsBuffer)
				serverResultList.RemoveAt (0);


			return serverResultList [0];
		}

		bool ServerResultsContainTimestamp (int timeStamp) {
			for (int i = 0; i < serverResultList.Count; i++) {
				if (serverResultList [i].timestamp == timeStamp)
					return true;
			}

			return false;
		}

		Inputs SortClientInputsAndReturnFirst () {

			Inputs tempInp;

			for (int x = 0; x < clientInputs.Count; x++) {
				for (int y = 0; y < clientInputs.Count - 1; y++) {
					if (clientInputs [y].timestamp > clientInputs [y + 1].timestamp) {
						tempInp = clientInputs [y + 1];
						clientInputs [y + 1] = clientInputs [y];
						clientInputs [y] = tempInp;
					}
				}
			}

			if (clientInputs.Count > data.clientInputsBuffer)
				clientInputs.RemoveAt (0);


			return clientInputs [0];
		}

		bool ClientInputsContainTimestamp (int timeStamp) {
			for (int i = 0; i < clientInputs.Count; i++) {
				if (clientInputs [i].timestamp == timeStamp)
					return true;
			}

			return false;
		}

		//Function which replays the old inputs if prediction errors occur
		void Reconciliate () {

			for (int i = 0; i < clientResults.Count; i++) {
				if (clientResults [i].timestamp == serverResults.timestamp) {
					clientResults.RemoveRange (0, i);
					for (int o = 0; o < clientInputs.Count; o++) {
						if (clientInputs [o].timestamp == serverResults.timestamp) {
							clientInputs.RemoveRange (0, o);
							break;
						}
					}
					break;
				}
			}

			tempResults = serverResults;

			controller.enabled = true;

			for (int i = 1; i < clientInputs.Count - 1; i++) {
				tempResults = MoveCharacter (tempResults, clientInputs [i], Time.fixedDeltaTime * sendUpdates, data.maxSpeedNormal);
			}

			groundPointTime = tempResults.groundPointTime;
			posEnd = tempResults.position;
			rotEnd = tempResults.rotation;
			posEndG = tempResults.groundPoint;

		}

		//Input gathering
		void Update () {
			if (isLocalPlayer) {
				if (inputsInterface == null)
					throw (new UnityException ("inputsInterface is not set!"));
				
				curInput.inputs.x = inputsInterface.GetMoveX ();
				curInput.inputs.y = inputsInterface.GetMoveY ();

				curInput.x = inputsInterface.GetMouseX ();
				curInput.y = inputsInterface.GetMouseY ();

				curInput.jump = inputsInterface.GetJump ();
				curInput.sprint = inputsInterface.GetSprint ();

				curInput.crouch = inputsInterface.GetCrouch ();
			
			}
		}

		//This is where the ticks happen
		void FixedUpdate () {

			if (data.strafeToSpeedCurveScale != _strafeToSpeedCurveScale) {
				_strafeToSpeedCurveScale = data.strafeToSpeedCurveScale;
				strafeToSpeedCurveScaleMul = 1f / data.strafeToSpeedCurveScale;
			}

			if (isLocalPlayer || isServer) {
				currentFixedUpdates++;
			}

			if (isLocalPlayer && currentFixedUpdates >= sendUpdates) {
				currentTick++;

				if (!isServer) {
					onTickUpdate.Invoke (lastResults);
					clientResults.Add (lastResults);
				}

				if (clientInputs.Count >= data.inputsToStore)
					clientInputs.RemoveAt (0);

				clientInputs.Add (curInput);
				curInput.timestamp = currentTick;

				posStart = myTransform.position;
				rotStart = myTransform.rotation;
				startTime = Time.fixedTime;

				if (reconciliate) {
					Reconciliate ();
					lastResults = tempResults;
					reconciliate = false;
				}
					
				controller.enabled = true;
				lastResults = MoveCharacter (lastResults, clientInputs [clientInputs.Count - 1], Time.fixedDeltaTime * _sendUpdates, data.maxSpeedNormal);

				#if (CLIENT_TRUST)
				CmdSendInputs (clientInputs [clientInputs.Count - 1], lastResults);
				#else
				CmdSendInputs (clientInputs [clientInputs.Count - 1]);
				#endif
				if (data.debug)
					onTickUpdateDebug.Invoke(clientInputs [clientInputs.Count - 1], lastResults);

				controller.enabled = false;
				posEnd = lastResults.position;
				groundPointTime = lastResults.groundPointTime;
				posEndG = lastResults.groundPoint;
				rotEnd = lastResults.rotation;
			}

			if (isServer && currentFixedUpdates >= sendUpdates && (currentTFixedUpdates >= sendUpdates || isLocalPlayer)) {

				if (isLocalPlayer) {
					onTickUpdate.Invoke (lastResults);
					RpcSendResults (lastResults);
				}

				if (!isLocalPlayer && clientInputs.Count > 0) {
					currentFixedUpdates -= sendUpdates;
					currentTFixedUpdates -= sendUpdates;
					//if (clientInputs.Count == 0)
					//	clientInputs.Add (curInputServer);
					//clientInputs[clientInputs.Count - 1] = curInputServer;
					curInput = SortClientInputsAndReturnFirst ();

					posStart = myTransform.position;
					rotStart = myTransform.rotation;
					startTime = Time.fixedTime;
					controller.enabled = true;
					serverResults = MoveCharacter (serverResults, curInput, Time.fixedDeltaTime * _sendUpdates, data.maxSpeedNormal);
					#if (CLIENT_TRUST)
					if (serverResults.timestamp == tempResults.timestamp && Vector3.SqrMagnitude(serverResults.position-tempResults.position) <= data.clientPositionToleration * data.clientPositionToleration && Vector3.SqrMagnitude(serverResults.speed-tempResults.speed) <= data.clientSpeedToleration * data.clientSpeedToleration && ((serverResults.isGrounded == tempResults.isGrounded) || !data.clientGroundedMatch) && ((serverResults.crouch == tempResults.crouch) || !data.clientCrouchMatch))
						serverResults = tempResults;
					#endif
					groundPointTime = serverResults.groundPointTime;
					posEnd = serverResults.position;
					rotEnd = serverResults.rotation;
					posEndG = serverResults.groundPoint;
					controller.enabled = false;

					onTickUpdate.Invoke (serverResults);
					if (data.debug)
						onTickUpdateDebug.Invoke(curInput, serverResults);
					RpcSendResults (serverResults);
				}

			}

			if (isLocalPlayer && currentFixedUpdates >= sendUpdates)
				currentFixedUpdates = 0;
		}

		//This is where all the interpolation happens
		void LateUpdate () {
			if (data.movementType == MoveType.UpdateOnceAndLerp) {
				if (isLocalPlayer || isServer || (Time.time - startTime) / (Time.fixedDeltaTime * _sendUpdates) <= 1f) {
					interpPos = Vector3.Lerp (posStart, posEnd, (Time.time - startTime) / (Time.fixedDeltaTime * _sendUpdates));
					//if ((Time.time - startTime) / (Time.fixedDeltaTime * _sendUpdates) <= groundPointTime)
					//	interpPos.y = Mathf.Lerp (posStart.y, posEndG, (Time.time - startTime) / (Time.fixedDeltaTime * _sendUpdates * groundPointTime));
					//else
					//	interpPos.y = Mathf.Lerp (posStart.y, posEndG, (Time.time - startTime + (groundPointTime * Time.fixedDeltaTime * _sendUpdates)) / (Time.fixedDeltaTime * _sendUpdates * (1f - groundPointTime)));

					myTransform.rotation = Quaternion.Lerp (rotStart, rotEnd, (Time.time - startTime) / (Time.fixedDeltaTime * _sendUpdates));
					if (isLocalPlayer)
						myTransform.rotation = Quaternion.Euler (myTransform.rotation.eulerAngles.x, curInput.x, myTransform.rotation.eulerAngles.z);
					myTransform.position = interpPos;
				} else {
					myTransform.position = Vector3.Lerp (posEnd, posEndO, (Time.time - startTime) / (Time.fixedDeltaTime * _sendUpdates) - 1f);
					myTransform.rotation = Quaternion.Lerp (rotEnd, rotEndO, (Time.time - startTime) / (Time.fixedDeltaTime * _sendUpdates) - 1f);
				}
			} else {
				myTransform.position = posEnd;
				myTransform.rotation = rotEnd;
			}
		}

		//Data not to be messed with. Needs to be outside the function due to OnControllerColliderHit
		Vector3 hitNormal;

		//Actual movement code. Mostly isolated, except transform
		Results MoveCharacter (Results inpRes, Inputs inp, float deltaMultiplier, Vector3 maxSpeed) {

			inp.y = Mathf.Clamp (curInput.y, dataInp.camMinY, dataInp.camMaxY);

			if (inp.x > 360f)
				inp.x -= 360f;
			else if (inp.x < 0f)
				inp.x += 360f;

			Vector3 pos = myTransform.position;
			Quaternion rot = myTransform.rotation;

			myTransform.position = inpRes.position;
			myTransform.rotation = inpRes.rotation;

			Vector3 tempSpeed = myTransform.InverseTransformDirection (inpRes.speed);

			myTransform.rotation = Quaternion.Euler (new Vector3 (0, inp.x, 0));

			//Character sliding of surfaces
			if (!inpRes.isGrounded) {
				inpRes.speed.x += (1f - inpRes.groundNormal.y) * inpRes.groundNormal.x * (inpRes.speed.y > 0 ? 0 : -inpRes.speed.y) * (1f - data.slideFriction);
				inpRes.speed.x += (1f - inpRes.groundNormal.y) * inpRes.groundNormal.x * (inpRes.speed.y < 0 ? 0 : inpRes.speed.y) * (1f - data.slideFriction);
				inpRes.speed.z += (1f - inpRes.groundNormal.y) * inpRes.groundNormal.z * (inpRes.speed.y > 0 ? 0 : -inpRes.speed.y) * (1f - data.slideFriction);
				inpRes.speed.z += (1f - inpRes.groundNormal.y) * inpRes.groundNormal.z * (inpRes.speed.y < 0 ? 0 : -inpRes.speed.y) * (1f - data.slideFriction);
			}

			Vector3 localSpeed = myTransform.InverseTransformDirection (inpRes.speed);
			Vector3 localSpeed2 = Vector3.Lerp (myTransform.InverseTransformDirection (inpRes.speed), tempSpeed, data.velocityTransferCurve.Evaluate (Mathf.Abs (inpRes.rotation.eulerAngles.y - inp.x) / (deltaMultiplier * data.velocityTransferDivisor)));

			if (!inpRes.isGrounded && data.strafing)
				AirStrafe (ref inpRes, ref inp, ref deltaMultiplier, ref maxSpeed, ref localSpeed, ref localSpeed2);
			else
				localSpeed = localSpeed2;

			BaseMovement (ref inpRes, ref inp, ref deltaMultiplier, ref maxSpeed, ref localSpeed);

			float tY = myTransform.position.y;

			inpRes.speed = transform.TransformDirection (localSpeed);
			hitNormal = new Vector3 (0, 0, 0);

			inpRes.speed.x = data.finalSpeedCurve.Evaluate (inpRes.speed.x);
			inpRes.speed.y = data.finalSpeedCurve.Evaluate (inpRes.speed.y);
			inpRes.speed.z = data.finalSpeedCurve.Evaluate (inpRes.speed.z);

			controller.Move (inpRes.speed * deltaMultiplier);
			//This code continues after OnControllerColliderHit gets called (if it does)

			if (Vector3.Angle (Vector3.up, hitNormal) <= data.slopeLimit)
				inpRes.isGrounded = true;
			else
				inpRes.isGrounded = false;

			//float speed = inpRes.speed.y;
			inpRes.speed = (transform.position - inpRes.position) / deltaMultiplier;
			//inpRes.speed.y = speed;

			float gpt = 1f;
			float gp = myTransform.position.y;

			//WIP, broken, Handles hitting ground while spacebar is pressed. It determines how much time was left to move based on at which height the player hit the ground. Some math involved.
			if (data.handleMidTickJump && !inpRes.isGrounded && tY - gp >= 0 && inp.jump && (controller.isGrounded || Physics.Raycast (myTransform.position + controller.center, Vector3.down, (controller.height / 2) + (controller.skinWidth * 1.5f)))) {
				float oSpeed = inpRes.speed.y;
				gpt = (tY - gp) / (-oSpeed);
				inpRes.speed.y = data.speedJump + ((Physics.gravity.y / 2) * Mathf.Abs((1f - gpt) * deltaMultiplier));
				Debug.Log (inpRes.speed.y + " " + gpt);
				controller.Move (myTransform.TransformDirection (0, inpRes.speed.y * deltaMultiplier, 0));
				inpRes.isGrounded = true;
				Debug.DrawLine (new Vector3( myTransform.position.x, gp, myTransform.position.z), myTransform.position, Color.blue, deltaMultiplier);
				inpRes.jumped = true;
			}

			if (data.snapSize > 0f)
				myTransform.position = new Vector3 (Mathf.Round (myTransform.position.x * snapInvert) * data.snapSize, Mathf.Round (myTransform.position.y * snapInvert) * data.snapSize, Mathf.Round (myTransform.position.z * snapInvert) * data.snapSize);


			if (inpRes.isGrounded)
				localSpeed.y = Physics.gravity.y * Mathf.Clamp(deltaMultiplier, 1f, 1f);

			inpRes = new Results (myTransform.position, myTransform.rotation, hitNormal, inp.y, inpRes.speed, inpRes.isGrounded, inpRes.jumped, inpRes.crouch, gp, gpt, inp.timestamp);

			myTransform.position = pos;
			myTransform.rotation = rot;

			return inpRes;
		}

		//The part which determines if the controller was hit or not
		void OnControllerColliderHit (ControllerColliderHit hit) {
			hitNormal = hit.normal;
		}