private MovementHistory.Data GetMovementData(MovementHistory movementHistory, float tick) { var history = movementHistory.movementHistory; var before = history.Where(m => m.tick <= tick).Last(); if (before != null) { movementHistory.ClearBeforeTick(before.tick); } var after = history.Where(m => m.tick >= tick).First(); var delta = after.tick - before.tick; if (delta == 0) { return(before); } var numerator = tick - before.tick; var t = numerator / delta; var data = new MovementHistory.Data(); data.position = Vector3.Lerp(before.position, after.position, t); data.rotation = Quaternion.Lerp(before.rotation, after.rotation, t); data.scale = Vector3.Lerp(before.scale, after.scale, t); data.velocity = Vector3.Lerp(before.velocity, after.velocity, t); data.angularVelocity = Vector3.Lerp(before.angularVelocity, after.angularVelocity, t); return(data); }
private void Update() { foreach (var clientTickEntity in GetEntities <ClientTick>()) { foreach (var entity in GetEntities <ClientMovementHistory>()) { var clientTick = clientTickEntity.Item1.tick; var lastReceivedTick = clientTickEntity.Item1.lastReceivedTick; var movementHistory = entity.Item1; var current = entity.Item1.transform; var data = new MovementHistory.Data(); data.tick = clientTick; data.position = current.position; data.rotation = current.rotation; data.scale = current.localScale; if (current.GetComponent <Rigidbody>()) { data.velocity = current.GetComponent <Rigidbody>().velocity; data.angularVelocity = current.GetComponent <Rigidbody>().angularVelocity; } movementHistory.Add(data); movementHistory.ClearBeforeTick(lastReceivedTick); } } var recompute = false; foreach (var entity in GetEntities <ClientMovementHistory, MovementHistory>()) { var clientMovementHistory = entity.Item1.movementHistory; var server = entity.Item2; var latestReceived = server.movementHistory[server.movementHistory.Count - 1]; server.ClearBeforeTick(latestReceived.tick - 30); var clientMovement = clientMovementHistory.Where(d => d.tick == latestReceived.tick).FirstOrDefault(); if (clientMovement == null) { continue; } var acceptableError = entity.Item1.acceptableError; var error = Vector3.Distance(latestReceived.position, clientMovement.position); if (error > acceptableError) { recompute = true; break; } } if (recompute) { Debug.Log("Recompute!"); foreach (var clientTickEntity in GetEntities <ClientTick, InputBuffer>()) { var clientTick = clientTickEntity.Item1.tick; var inputBuffer = clientTickEntity.Item2.inputs; var latestReceived = clientTickEntity.Item1.lastReceivedTick; foreach (var entity in GetEntities <ClientMovementHistory, MovementHistory>()) { var current = entity.Item1.transform; var clientMovementHistory = entity.Item1.movementHistory; var serverMovementHistory = entity.Item2.movementHistory; clientMovementHistory.Clear(); var corrected = serverMovementHistory.Where(d => d.tick == latestReceived).FirstOrDefault(); if (corrected != null) { clientMovementHistory.Add(corrected); current.position = corrected.position; current.rotation = corrected.rotation; current.localScale = corrected.scale; if (current.GetComponent <Rigidbody>()) { current.GetComponent <Rigidbody>().velocity = corrected.velocity; current.GetComponent <Rigidbody>().angularVelocity = corrected.angularVelocity; } } } for (var tick = latestReceived + 1; tick <= clientTick; tick++) { var input = inputBuffer.Where(i => i.tick == tick).FirstOrDefault(); if (input != null) { foreach (var sessionEntity in GetEntities <Session>()) { foreach (var entity in GetEntities <ClientPrediction, Movement, RigidbodyComponent>()) { var sessionId = sessionEntity.Item1.id; var clientPrediction = entity.Item1; var movement = entity.Item2; var rigidbody = entity.Item3.rigidbody; if (clientPrediction.sessionId != sessionId) { continue; } var forward = Camera.main.transform.forward; var right = Camera.main.transform.right; forward.y = 0f; right.y = 0f; forward.Normalize(); right.Normalize(); var inputForce = forward * input.vertical; inputForce += right * input.horizontal; var jump = input.jumpPressed; rigidbody.AddForce(inputForce * movement.force); if (jump) { rigidbody.AddForce(Vector3.up * movement.force, ForceMode.Impulse); } } } } gameObject.scene.GetPhysicsScene().Simulate(Time.fixedDeltaTime); foreach (var entity in GetEntities <ClientMovementHistory, RigidbodyComponent>()) { var movementHistory = entity.Item1; var current = entity.Item1.transform; var rigidbody = entity.Item2.rigidbody; var data = new MovementHistory.Data(); data.tick = tick; data.position = current.position; data.rotation = current.rotation; data.scale = current.localScale; if (rigidbody) { data.velocity = rigidbody.velocity; data.angularVelocity = rigidbody.angularVelocity; } movementHistory.Add(data); } } } } }
private void Update() { foreach (var entity in GetEntities <OnReceiveEvent, Session>()) { var args = entity.Item1.Args; if (args.Length < 1) { continue; } var command = args[0].ToLower(); if (command == "update") { var session = entity.Item2; var tick = Convert.ToInt32(args[1]); foreach (var clientTick in GetEntities <ClientTick>()) { clientTick.Item1.lastReceivedTick = tick; clientTick.Item1.lastReceivedTime = Time.time; } var remainingEntityIds = GetCurrentEntityIds(); var i = 2; while (i < args.Length) { var entityId = Convert.ToInt32(args[i++]); var prefabName = args[i++]; remainingEntityIds.RemoveAll(e => e.entityId == entityId); var clientEntity = GetEntityById(entityId); if (clientEntity == null) { clientEntity = CreateEntity(entityId, prefabName); } var movementHistory = clientEntity.GetComponent <MovementHistory>(); var movementNetworkSync = clientEntity.GetComponent <MovementNetworkSync>(); if (movementHistory && movementNetworkSync) { var data = new MovementHistory.Data(); data.tick = tick; if (movementNetworkSync.syncPosition) { data.position.x = Convert.ToSingle(args[i++]); data.position.y = Convert.ToSingle(args[i++]); data.position.z = Convert.ToSingle(args[i++]); } if (movementNetworkSync.syncRotation) { data.rotation.x = Convert.ToSingle(args[i++]); data.rotation.y = Convert.ToSingle(args[i++]); data.rotation.z = Convert.ToSingle(args[i++]); data.rotation.w = Convert.ToSingle(args[i++]); } if (movementNetworkSync.syncScale) { data.scale.x = Convert.ToSingle(args[i++]); data.scale.y = Convert.ToSingle(args[i++]); data.scale.z = Convert.ToSingle(args[i++]); } if (movementNetworkSync.syncVelocity) { var velocity = Vector3.zero; data.velocity.x = Convert.ToSingle(args[i++]); data.velocity.y = Convert.ToSingle(args[i++]); data.velocity.z = Convert.ToSingle(args[i++]); } if (movementNetworkSync.syncAngularVelocity) { data.angularVelocity.x = Convert.ToSingle(args[i++]); data.angularVelocity.y = Convert.ToSingle(args[i++]); data.angularVelocity.z = Convert.ToSingle(args[i++]); } movementHistory.Add(data); } } foreach (var remainingEntity in remainingEntityIds) { remainingEntity.gameObject.AddComponent <EntityDestroyed>(); } } } }