private static PredictionOutput GetDashingPrediction(this PredictionInput input) { var dashData = input.Unit.GetDashInfo(); var result = new PredictionOutput { Input = input }; if (!dashData.IsBlink) { var endP = dashData.Path.Last(); var dashPred = input.GetPositionOnPath( new List<Vector2> { input.Unit.ServerPosition.ToVector2(), endP }, dashData.Speed); if (dashPred.Hitchance >= HitChance.High && dashPred.UnitPosition.ToVector2().Distance(input.Unit.Position.ToVector2(), endP, true) < 200) { dashPred.CastPosition = dashPred.UnitPosition; dashPred.Hitchance = HitChance.Dashing; return dashPred; } if (dashData.Path.PathLength() > 200) { var timeToPoint = input.Delay / 2 + input.From.ToVector2().Distance(endP) / input.Speed - 0.25f; if (timeToPoint <= input.Unit.Distance(endP) / dashData.Speed + input.RealRadius / input.Unit.MoveSpeed) { return new PredictionOutput { CastPosition = endP.ToVector3(), UnitPosition = endP.ToVector3(), Hitchance = HitChance.Dashing }; } } result.CastPosition = dashData.Path.Last().ToVector3(); result.UnitPosition = result.CastPosition; } return result; }
private static void WayPointAnalysis(this PredictionInput input, PredictionOutput result) { var totalDelay = input.Delay + (Math.Abs(input.Speed - float.MaxValue) < float.Epsilon ? 0 : input.Unit.Distance(input.From) / input.Speed); var lastWaypoint = input.Unit.GetWaypoints().Last().ToVector3(); var totalMoveSpeed = input.Unit.MoveSpeed * totalDelay; var minPath = 400; var moveAngle = 30 + input.Radius / 10; var fixRange = totalMoveSpeed * 0.6; if (Path.PathTracker.GetCurrentPath(input.Unit).Time < 0.1) { minPath = 500; moveAngle += 10; fixRange = totalMoveSpeed * 0.4; } if (input.Type == SkillshotType.SkillshotCircle) { fixRange -= input.Radius / 2; } switch (input.Type) { case SkillshotType.SkillshotLine: if (input.Unit.Path.Count() > 0) { result.Hitchance = input.Unit.Path.Count() > 1 ? HitChance.Medium : (input.From.GetAngle(input.Unit) < moveAngle ? HitChance.VeryHigh : HitChance.High); } break; case SkillshotType.SkillshotCircle: if (totalDelay < 0.7 && AutoAttackDetection.GetLastAutoAttackTime(input.Unit) < 0.1) { result.Hitchance = HitChance.VeryHigh; } if (totalDelay < 1.1 && Path.PathTracker.GetCurrentPath(input.Unit).Time < 0.1) { result.Hitchance = HitChance.VeryHigh; } break; } if (input.Unit.MoveSpeed < 250) { result.Hitchance = HitChance.VeryHigh; } if (input.Unit.Distance(lastWaypoint) > minPath) { result.Hitchance = HitChance.VeryHigh; } if (totalDelay < 0.7 + input.Radius / 500 && AutoAttackDetection.GetLastAutoAttackTime(input.Unit) < 0.1) { result.Hitchance = HitChance.VeryHigh; } if (input.Unit.Path.Count() == 0 && input.Unit.Position == input.Unit.ServerPosition && !input.Unit.IsWindingUp) { result.Hitchance = input.Unit.Distance(input.From) > input.Range - fixRange ? HitChance.High : HitChance.VeryHigh; return; } if (lastWaypoint.Distance(input.From) <= input.Unit.Distance(input.From) && input.Unit.Distance(input.From) > input.Range - fixRange) { result.Hitchance = HitChance.High; } if (input.Unit.Path.Count() > 0 && input.Unit.Distance(lastWaypoint) < totalMoveSpeed && Path.PathTracker.GetCurrentPath(input.Unit).Time > 0.1) { result.Hitchance = HitChance.Medium; } if (totalDelay > 0.7 + input.Radius / 500 && input.Unit.IsWindingUp) { result.Hitchance = HitChance.Medium; } if (input.Unit.Distance(input.From) < 300 || lastWaypoint.Distance(input.From) < 250 || input.Unit.MoveSpeed < 200) { result.Hitchance = HitChance.VeryHigh; } }
private static void WayPointAnalysis(PredictionOutput result, PredictionInput input) { var totalDelay = input.Delay + (Math.Abs(input.Speed - float.MaxValue) < float.Epsilon ? 0 : input.Unit.Distance(input.From) / input.Speed); var fixRange = (input.Unit.MoveSpeed * totalDelay) / 2; var lastWaypiont = input.Unit.GetWaypoints().Last().ToVector3(); if (input.Type == SkillshotType.SkillshotCircle) { fixRange -= input.Radius / 2; } switch (input.Type) { case SkillshotType.SkillshotLine: if (input.Unit.Path.Count() > 0) { result.Hitchance = GetAngle(input.From, input.Unit) < 36 ? HitChance.VeryHigh : HitChance.High; } break; case SkillshotType.SkillshotCircle: if (totalDelay < 1.1 && ((totalDelay < 0.7 && OnProcessSpellDetection.GetLastAutoAttackTime(input.Unit) < 0.1d) || Path.PathTracker.GetCurrentPath(input.Unit).Time < 0.1d)) { result.Hitchance = HitChance.VeryHigh; } break; } if (input.Unit.HasBuffOfType(BuffType.Slow) || input.Unit.Distance(input.From) < 300 || lastWaypiont.Distance(input.From) < 250 || input.Unit.Distance(lastWaypiont) > 800) { result.Hitchance = HitChance.VeryHigh; } if (input.Unit.Path.Count() == 0 && input.Unit.Position == input.Unit.ServerPosition && !input.Unit.IsWindingUp) { result.Hitchance = input.Unit.Distance(input.From) > input.Range - fixRange ? HitChance.High : HitChance.VeryHigh; return; } if (lastWaypiont.Distance(input.From) <= input.Unit.Distance(input.From) && input.Unit.Distance(input.From) > input.Range - fixRange) { result.Hitchance = HitChance.High; } if ((input.Unit.Path.Count() > 0 && input.Unit.Distance(lastWaypiont) < input.Unit.MoveSpeed * totalDelay) || (totalDelay > 0.7 && (input.Unit.IsWindingUp || OnProcessSpellDetection.GetLastAutoAttackTime(input.Unit) < 0.1d)) || (input.Unit.Path.Count() > 1 && input.Type == SkillshotType.SkillshotLine)) { result.Hitchance = HitChance.Medium; } if (input.Unit.Distance(input.From) < 300 || lastWaypiont.Distance(input.From) < 250) { result.Hitchance = HitChance.VeryHigh; } }
/// <summary> /// Returns Dashing Prediction /// </summary> /// <param name="input"> /// <see cref="PredictionInput" /> input /// </param> /// <returns><see cref="PredictionOutput" /> output</returns> internal static PredictionOutput GetDashingPrediction(PredictionInput input) { var dashData = input.Unit.GetDashInfo(); var result = new PredictionOutput { Input = input }; input.Delay += 0.1f; // Normal dashes. if (!dashData.IsBlink) { // Mid air: var dashPred = GetPositionOnPath( input, new List<Vector2> { input.Unit.ServerPosition.ToVector2(), dashData.Path.Last() }, dashData.Speed); if (dashPred.Hitchance >= HitChance.High) { dashPred.CastPosition = dashPred.UnitPosition; dashPred.Hitchance = HitChance.Dashing; return dashPred; } // At the end of the dash: if (dashData.Path.PathLength() > 200) { var endP = dashData.Path.Last(); var timeToPoint = input.Delay + (input.From.ToVector2().Distance(endP) / input.Speed); if (timeToPoint <= (input.Unit.Distance(endP) / dashData.Speed) + (input.RealRadius / input.Unit.MoveSpeed)) { return new PredictionOutput { CastPosition = endP.ToVector3(), UnitPosition = endP.ToVector3(), Hitchance = HitChance.Dashing }; } } result.CastPosition = dashData.Path.Last().ToVector3(); result.UnitPosition = result.CastPosition; // Figure out where the unit is going. } return result; }
/// <summary> /// Returns Calculated Prediction based off given data values. /// </summary> /// <param name="input"> /// <see cref="PredictionInput" /> input /// </param> /// <param name="ft">Add Delay</param> /// <param name="checkCollision">Check Collision</param> /// <returns> /// <see cref="PredictionOutput" /> output /// </returns> internal static PredictionOutput GetPrediction(PredictionInput input, bool ft, bool checkCollision) { PredictionOutput result = null; if (!input.Unit.IsValidTarget(float.MaxValue, false)) { return(new PredictionOutput()); } if (ft) { // Increase the delay due to the latency and server tick: input.Delay += Game.Ping / 2000f + 0.06f; if (input.AoE) { return(Cluster.GetAoEPrediction(input)); } } // Target too far away. if (Math.Abs(input.Range - float.MaxValue) > float.Epsilon && input.Unit.DistanceSquared(input.RangeCheckFrom) > Math.Pow(input.Range * 1.5, 2)) { return(new PredictionOutput { Input = input }); } // Unit is dashing. if (input.Unit.IsDashing()) { result = GetDashingPrediction(input); } else { // Unit is immobile. var remainingImmobileT = UnitIsImmobileUntil(input.Unit); if (remainingImmobileT >= 0d) { result = GetImmobilePrediction(input, remainingImmobileT); } } // Normal prediction if (result == null) { result = GetAdvancedPrediction(input); } // Check if the unit position is in range if (Math.Abs(input.Range - float.MaxValue) > float.Epsilon) { if (result.Hitchance >= HitChance.High && input.RangeCheckFrom.DistanceSquared(input.Unit.Position) > Math.Pow(input.Range + input.RealRadius * 3 / 4, 2)) { result.Hitchance = HitChance.Medium; } if (input.RangeCheckFrom.DistanceSquared(result.UnitPosition) > Math.Pow(input.Range + (input.Type == SkillshotType.SkillshotCircle ? input.RealRadius : 0), 2)) { result.Hitchance = HitChance.OutOfRange; } if (input.RangeCheckFrom.DistanceSquared(result.CastPosition) > Math.Pow(input.Range, 2)) { if (result.Hitchance != HitChance.OutOfRange) { result.CastPosition = input.RangeCheckFrom + input.Range * (result.UnitPosition - input.RangeCheckFrom).Normalized().SetZ(); } else { result.Hitchance = HitChance.OutOfRange; } } } // Check for collision if (checkCollision && input.Collision) { var positions = new List <Vector3> { result.UnitPosition, result.CastPosition, input.Unit.Position }; var originalUnit = input.Unit; result.CollisionObjects = Collision.GetCollision(positions, input); result.CollisionObjects.RemoveAll(x => x.NetworkId == originalUnit.NetworkId); result.Hitchance = result.CollisionObjects.Count > 0 ? HitChance.Collision : result.Hitchance; } return(result); }
private static PredictionOutput WayPointAnalysis(this PredictionInput input, PredictionOutput result) { if (!(input.Unit is Obj_AI_Hero)) { result.Hitchance = HitChance.VeryHigh; return result; } if (UnitTracker.GetLastSpecialSpellTime(input.Unit) > 0) { result.Hitchance = HitChance.VeryHigh; return result; } result.Hitchance = HitChance.High; var lastWaypoint = input.Unit.GetWaypoints().Last().ToVector3(); var distUnitToWaypoint = input.Unit.Distance(lastWaypoint); var distUnitToFrom = input.Unit.Distance(input.From); var distFromToWaypoint = input.From.Distance(lastWaypoint); var totalDelay = input.Delay + (Math.Abs(input.Speed - float.MaxValue) < float.Epsilon ? 0 : distUnitToFrom / input.Speed); var moveArea = input.Unit.MoveSpeed * totalDelay; var fixRange = moveArea * 0.7f; var moveAngle = 30 + input.Radius / 10 - input.Delay * 5; var backToFront = moveArea * 1.5f; var minPath = 700 + backToFront; if (UnitTracker.CanCalcWaypoints(input.Unit)) { result.Hitchance = distUnitToFrom < input.Range - fixRange ? HitChance.VeryHigh : HitChance.High; return result; } if (UnitTracker.GetLastNewPathTime(input.Unit) < 0.1) { fixRange = moveArea * (0.2f + input.Delay); backToFront = moveArea; } if (input.Type == SkillshotType.SkillshotCircle) { fixRange -= input.Radius / 2; } if (distUnitToWaypoint > minPath) { result.Hitchance = HitChance.VeryHigh; } else if (input.Type == SkillshotType.SkillshotLine) { if (input.Unit.Path.Length > 0) { if (input.From.GetAngle(input.Unit) < moveAngle) { result.Hitchance = HitChance.VeryHigh; } else if (UnitTracker.GetLastNewPathTime(input.Unit) > 0.1) { result.Hitchance = HitChance.High; } } } if (input.Unit.Path.Length == 0 && input.Unit.Position == input.Unit.ServerPosition) { if (UnitTracker.GetLastStopMoveTime(input.Unit) < 0.5) { result.Hitchance = HitChance.High; } else { result.Hitchance = distUnitToFrom > input.Range - fixRange ? HitChance.Medium : HitChance.VeryHigh; } } else if (distFromToWaypoint <= input.Unit.Distance(input.From) && distUnitToFrom > input.Range - fixRange) { result.Hitchance = HitChance.Medium; } if (UnitTracker.GetLastAttackTime(input.Unit) < 0.1) { result.Hitchance = (input.Type == SkillshotType.SkillshotLine && totalDelay < 0.8 + input.Radius * 0.001) || (input.Type == SkillshotType.SkillshotCircle && totalDelay < 0.6 + input.Radius * 0.001) ? HitChance.VeryHigh : HitChance.Medium; } if (input.Type == SkillshotType.SkillshotCircle) { if (UnitTracker.GetLastNewPathTime(input.Unit) < 0.1) { result.Hitchance = HitChance.VeryHigh; } else if (distUnitToFrom < input.Range - fixRange) { result.Hitchance = HitChance.VeryHigh; } } if (result.Hitchance != HitChance.Medium) { if (input.Unit.IsWindingUp && UnitTracker.GetLastAttackTime(input.Unit) > 0.1) { result.Hitchance = HitChance.Medium; } else if (input.Unit.Path.Length == 0 && input.Unit.Position != input.Unit.ServerPosition) { result.Hitchance = HitChance.Medium; } else if (input.Unit.Path.Length > 0 && distUnitToWaypoint < backToFront) { result.Hitchance = HitChance.Medium; } else if (input.Unit.Path.Length > 1) { result.Hitchance = HitChance.Medium; } else if (UnitTracker.GetLastVisableTime(input.Unit) < 0.05) { result.Hitchance = HitChance.Medium; } } if (distFromToWaypoint > input.Unit.Distance(input.From) && input.From.GetAngle(input.Unit) > moveAngle) { result.Hitchance = HitChance.VeryHigh; } if (input.Unit.Distance(input.From) < 400 || distFromToWaypoint < 300 || input.Unit.MoveSpeed < 200) { result.Hitchance = HitChance.VeryHigh; } return result; }