void StoreCurrentTransform() { PlayerTransform snapshot = new PlayerTransform(Transform.Position, camera.Yaw, camera.Pitch); playerTransforms.Add(snapshot); if (playerTransforms.Count > MAX_STORED_TRANSFORMS) { playerTransforms.RemoveAt(0); } }
public PlayerTransform RollbackTransform(int timeFrame, bool suppressLog = false) { PlayerTransform pt1 = null, pt2 = null; for (int i = 0; i < playerTransforms.Count; i++) { PlayerTransform pt = playerTransforms[i]; int tickOff = Math.Abs(pt.Ticks - timeFrame); // Don't process anything more than a second off if (tickOff > 1000) { continue; } if (pt1 == null || tickOff < Math.Abs(pt1.Ticks - timeFrame)) { pt1 = pt; } } for (int i = 0; i < playerTransforms.Count; i++) { PlayerTransform pt = playerTransforms[i]; if (pt == pt1) { continue; } int tickOff = Math.Abs(pt.Ticks - timeFrame); // Don't process anything more than a second off if (tickOff > 1000) { continue; } if (pt2 == null || tickOff < Math.Abs(pt2.Ticks - timeFrame)) { pt2 = pt; } } if (pt1 != null && pt2 != null) { if (pt2.Ticks > pt1.Ticks) { PlayerTransform temp = pt2; pt2 = pt1; pt1 = temp; } // Interpolate float timeI = pt1.Ticks == pt2.Ticks ? 0f : (float)(timeFrame - pt2.Ticks) / (pt1.Ticks - pt2.Ticks); //timeI = MathHelper.Clamp(timeI, 0f, 1f); if (DashCMD.GetCVar <bool>("sv_hitboxes") && !suppressLog) { DashCMD.WriteImportant("[RB] Rolling back transform by {0}%. [timeFrame: {3}, pt2: {1}, pt1: {2}]", timeI * 100, pt2.Ticks, pt1.Ticks, timeFrame); } Vector3 position = Interpolation.Lerp(pt2.Position, pt1.Position, timeI); float camPitch = Interpolation.LerpDegrees(pt2.CameraPitch, pt1.CameraPitch, timeI); float camYaw = Interpolation.LerpDegrees(pt2.CameraYaw, pt1.CameraYaw, timeI); return(new PlayerTransform(position, camYaw, camPitch, timeFrame)); } else if (pt1 != null && pt2 == null) { // Take pt1 return(pt1); } else { // Take current return(new PlayerTransform(Transform.Position, camera.Yaw, camera.Pitch, Environment.TickCount)); } }
public override PlayerRaycastResult RaycastPlayers(Ray ray, float maxDist = float.MaxValue, params Player[] ignore) { bool sv_impacts = DashCMD.GetCVar <bool>("sv_impacts"); bool sv_hitboxes = DashCMD.GetCVar <bool>("sv_hitboxes"); ServerMPPlayer hitPlayer = null; float? hitPlayerAt = null; foreach (ServerMPPlayer otherPlayer in players.Values) { // Make sure we aren't ignoring this player if (ignore.Length == 0 || !Array.Exists(ignore, (x => x == otherPlayer))) { Vector3 otherPlayerPosition; float otherPlayerCamYaw; if (rollbackTime.HasValue) { // We are applying rollback, so find the players old transform int otherPlayerPing = DashCMD.GetCVar <bool>("rp_usetargetping") ? otherPlayer.StateInfo.Owner.Stats.Ping : 0; int rollbackFrame = MathHelper.Clamp(otherPlayerPing + rollbackTime.Value, 0, 1000); if (sv_hitboxes) { DashCMD.WriteLine("[RB] Rolling back bullet-player transform by {0}ms [target ping: {1}ms]", ConsoleColor.Green, rollbackTime, otherPlayerPing); } PlayerTransform otherPlayerTransform = otherPlayer.RollbackTransform(Environment.TickCount - rollbackFrame); otherPlayerPosition = otherPlayerTransform.Position; otherPlayerCamYaw = otherPlayerTransform.CameraYaw; } else { // No rollback currently, use current transform otherPlayerPosition = otherPlayer.Transform.Position; otherPlayerCamYaw = otherPlayer.GetCamera().Yaw; } if (sv_hitboxes) { channel.FireEventForAllConnections("Client_RolledBackServerPlayer", otherPlayerPosition.X, otherPlayerPosition.Y, otherPlayerPosition.Z, (byte)otherPlayer.Team); } Ray newRay = new Ray(ray.Origin - otherPlayerPosition, ray.Direction); float?dist; // Check for intersection if (newRay.Intersects(otherPlayer.GetOrientatedBoundingBox(otherPlayerCamYaw), out dist)) { // If the distance is out of bounds, ignore if (dist.Value > maxDist) { continue; } // Only update the intersected player if it was closer than the last if (!hitPlayerAt.HasValue || dist.Value < hitPlayerAt.Value) { hitPlayer = otherPlayer; hitPlayerAt = dist.Value; } } } } if (hitPlayer != null) { return(new PlayerRaycastResult(ray, true, ray.Origin + ray.Direction * hitPlayerAt.Value, hitPlayerAt, hitPlayer)); } else { return(new PlayerRaycastResult(ray)); } }