Skip to content

Commit

Permalink
Improve turn rate calculations
Browse files Browse the repository at this point in the history
  • Loading branch information
moofMonkey committed Dec 10, 2024
1 parent 1d17b6e commit a2c02d1
Show file tree
Hide file tree
Showing 5 changed files with 274 additions and 0 deletions.
181 changes: 181 additions & 0 deletions wrapper/Data/TurnData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
interface ITurnData {
MaxTurnSpeed: number
TurnAcceleration: number
TurnDeceleration: number
ImmediateMovementAngle: number
FullTurnMovementAngle: number
CastAngles: number[]
}

const castAngles = [11, 45, 90, 135, 180]
const turnDataEntries: {
TurnRate: number
TurnData: ITurnData
}[] = [
{
TurnRate: 0.1,
TurnData: {
MaxTurnSpeed: 147.6,
TurnAcceleration: 5000,
TurnDeceleration: 1800,
ImmediateMovementAngle: 86.4,
FullTurnMovementAngle: 126,
CastAngles: [13.2, 24, 39.6, 54, 69.6]
}
},
{
TurnRate: 0.4,
TurnData: {
MaxTurnSpeed: 494.4,
TurnAcceleration: 13333,
TurnDeceleration: 4800,
ImmediateMovementAngle: 108,
FullTurnMovementAngle: 138,
CastAngles: [13.2, 28.8, 50.4, 72, 93.6]
}
},
{
TurnRate: 0.5,
TurnData: {
MaxTurnSpeed: 576,
TurnAcceleration: 13333,
TurnDeceleration: 6000,
ImmediateMovementAngle: 115.2,
FullTurnMovementAngle: 138,
CastAngles: [13.2, 31.2, 54, 78, 102]
}
},
{
TurnRate: 0.6,
TurnData: {
MaxTurnSpeed: 648,
TurnAcceleration: 13333,
TurnDeceleration: 7200,
ImmediateMovementAngle: 122.4,
FullTurnMovementAngle: 138,
CastAngles: [13.2, 32.4, 58.8, 84, 110.4]
}
},
{
TurnRate: 1,
TurnData: {
MaxTurnSpeed: 756,
TurnAcceleration: 13333,
TurnDeceleration: 12000,
ImmediateMovementAngle: 150,
FullTurnMovementAngle: 156,
CastAngles: [13.2, 38.4, 73.2, 108, 141.6]
}
}
]

export function GetTurnData(turnRate: number): ITurnData {
if (turnRate <= turnDataEntries[0].TurnRate) {
return turnDataEntries[0].TurnData
}

let nextMatch = 1
for (; nextMatch < turnDataEntries.length; nextMatch++) {
if (turnDataEntries[nextMatch].TurnRate >= turnRate) {
break
}
}
if (nextMatch === turnDataEntries.length) {
return turnDataEntries[turnDataEntries.length - 1].TurnData
}
if (turnDataEntries[nextMatch].TurnRate === turnRate) {
return turnDataEntries[nextMatch].TurnData
}

const prevData = turnDataEntries[nextMatch - 1]
const nextData = turnDataEntries[nextMatch]
const mul = (turnRate - prevData.TurnRate) / (nextData.TurnRate - prevData.TurnRate)
return {
MaxTurnSpeed:
nextData.TurnData.MaxTurnSpeed * mul +
prevData.TurnData.MaxTurnSpeed * (1 - mul),
TurnAcceleration:
nextData.TurnData.TurnAcceleration * mul +
prevData.TurnData.TurnAcceleration * (1 - mul),
TurnDeceleration:
nextData.TurnData.TurnDeceleration * mul +
prevData.TurnData.TurnDeceleration * (1 - mul),
ImmediateMovementAngle:
nextData.TurnData.ImmediateMovementAngle * mul +
prevData.TurnData.ImmediateMovementAngle * (1 - mul),
FullTurnMovementAngle:
nextData.TurnData.FullTurnMovementAngle * mul +
prevData.TurnData.FullTurnMovementAngle * (1 - mul),
CastAngles: prevData.TurnData.CastAngles.map(
(prevAng, i) => nextData.TurnData.CastAngles[i] * mul + prevAng * (1 - mul)
)
}
}

export function GetCastAngle(turnData: ITurnData, ang: number, distSqr: number): number {
if (distSqr < 0.1 || ang <= 11.5) {
return 180
}
let nextMatch = 1
for (; nextMatch < castAngles.length; nextMatch++) {
if (castAngles[nextMatch] >= ang) {
break
}
}
if (nextMatch === castAngles.length) {
return 180
}
const mul =
(ang - castAngles[nextMatch - 1]) /
(castAngles[nextMatch] - castAngles[nextMatch - 1])
const prevCastAngle = turnData.CastAngles[nextMatch - 1]
const nextCastAngle = turnData.CastAngles[nextMatch]
return prevCastAngle + (nextCastAngle - prevCastAngle) * mul
}

export function UpdateFacing(
turnData: ITurnData,
yawVelocity: number,
angDiff: number,
curInterval: number
): [number, number] {
if (yawVelocity * angDiff < 0) {
yawVelocity = 0
}
const decel = yawVelocity ** 2 / (angDiff * 2)
if (
yawVelocity === 0 ||
angDiff === 0 ||
Math.abs(decel) < turnData.TurnDeceleration
) {
yawVelocity += turnData.TurnAcceleration * curInterval * (angDiff >= 0 ? 1 : -1)
if (Math.abs(yawVelocity) > turnData.MaxTurnSpeed) {
yawVelocity = (yawVelocity >= 0 ? 1 : -1) * turnData.MaxTurnSpeed
}
} else {
yawVelocity -= curInterval * decel
if (yawVelocity * (decel >= 0 ? 1 : -1) < 0) {
yawVelocity = 0
}
}
const change = yawVelocity * curInterval
if ((angDiff - change) * angDiff <= 0) {
return [angDiff, 0]
}
return [change, yawVelocity]
}

export function GetAngleToFacePath(turnData: ITurnData, angDiffAbs: number): number {
if (angDiffAbs <= turnData.ImmediateMovementAngle) {
return angDiffAbs
}
if (turnData.FullTurnMovementAngle >= 180) {
return turnData.FullTurnMovementAngle
}
return (
turnData.ImmediateMovementAngle +
(turnData.FullTurnMovementAngle - turnData.ImmediateMovementAngle) *
((angDiffAbs - turnData.ImmediateMovementAngle) /
(180 - turnData.ImmediateMovementAngle))
)
}
42 changes: 42 additions & 0 deletions wrapper/Managers/Monitors/UnitChanged.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { GetTurnData, UpdateFacing } from "../../Data/TurnData"
import { EAbilitySlot } from "../../Enums/EAbilitySlot"
import { EventPriority } from "../../Enums/EventPriority"
import { GameActivity } from "../../Enums/GameActivity"
Expand All @@ -8,6 +9,7 @@ import { NeutralSpawner, NeutralSpawners } from "../../Objects/Base/NeutralSpawn
import { Unit, Units } from "../../Objects/Base/Unit"
import { Wearable } from "../../Objects/Base/Wearable"
import { GameState } from "../../Utils/GameState"
import { AngleDiff } from "../../Utils/Math"
import { EventsSDK } from "../EventsSDK"
import { Prediction } from "../Prediction/Prediction"

Expand Down Expand Up @@ -102,6 +104,46 @@ const Monitor = new (class CPreUnitChanged {
}
}
}
let prevPos = unit.PositionHistoryIndex - 1
if (prevPos < 0) {
prevPos += unit.PreviousNetworkedAngles_.length
}
if (
prevPos === -1 ||
unit.PreviousNetworkedAngles_[prevPos] !== unit.NetworkedAngles_.y ||
unit.PreviousRotationDifference !== unit.RotationDifference
) {
const turnData = GetTurnData(unit.TurnRate())
let rotDiff = unit.RotationDifference
if (prevPos !== -1) {
rotDiff += AngleDiff(
unit.NetworkedAngles_.y,
unit.PreviousNetworkedAngles_[prevPos]
)
if (rotDiff <= -180) {
rotDiff += 360
} else if (rotDiff >= 180) {
rotDiff -= 360
}
}
unit.YawVelocity = UpdateFacing(
turnData,
unit.YawVelocity,
rotDiff,
dt
)[1]

unit.PreviousRotationDifference = unit.RotationDifference
} else if (unit.RotationDifference === 0) {
unit.YawVelocity = 0
}
if (unit.PreviousNetworkedAngles_.length === 120) {
unit.PreviousNetworkedAngles_[unit.PositionHistoryIndex] =
unit.NetworkedAngles_.y
} else {
unit.PreviousNetworkedAngles_.push(unit.NetworkedAngles_.y)
}
unit.PositionHistoryIndex = (unit.PositionHistoryIndex + 1) % 120
// TODO: interpolate DeltaZ from OnModifierUpdated?
}
}
Expand Down
3 changes: 3 additions & 0 deletions wrapper/Objects/Base/Entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ export class Entity {
public ModelScale: number = 1
public BecameDormantTime: number = 0
public RotationDifference: number = 0
public PreviousRotationDifference: number = 0
public HierarchyAttachName: number = 0
public Attachments: string[] = []
public ModelData: Nullable<ModelData>
Expand All @@ -159,6 +160,8 @@ export class Entity {
public readonly VisualAngles = new QAngle()
public readonly NetworkedAngles = new QAngle()
public readonly NetworkedAngles_ = new QAngle()
public readonly PreviousNetworkedAngles_: number[] = []
public PositionHistoryIndex: number = 0
public readonly BoundingBox = new AABB(this.VisualPosition)
public readonly SpawnPosition = new Vector3()

Expand Down
36 changes: 36 additions & 0 deletions wrapper/Objects/Base/Unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ import { Vector2 } from "../../Base/Vector2"
import { Vector3 } from "../../Base/Vector3"
import { ArmorPerAgility, AttackSpeedData, MoveSpeedData } from "../../Data/GameData"
import { GetUnitTexture } from "../../Data/ImageData"
import {
GetAngleToFacePath,
GetCastAngle,
GetTurnData,
UpdateFacing
} from "../../Data/TurnData"
import { NetworkedBasicField, WrapperClass } from "../../Decorators"
import { ArmorType } from "../../Enums/ArmorType"
import { AttackDamageType } from "../../Enums/AttackDamageType"
Expand Down Expand Up @@ -200,6 +206,8 @@ export class Unit extends Entity {
public LastPredictedPositionUpdate: number = 0
public LastRealPredictedPositionUpdate: number = 0

public YawVelocity = 0

/**
* @description added for compatibility (icore)
* @deprecated
Expand Down Expand Up @@ -1241,6 +1249,34 @@ export class Unit extends Entity {
public TurnTime(angle: number, currentTurnRate = true): number {
return Math.max(angle / (30 * this.TurnRate(currentTurnRate)), 0)
}
public TurnTimeNew(
target: Vector3,
movement: boolean,
directionalMovement = false,
currentTurnRate = true
): number {
const turnData = GetTurnData(this.TurnRate(currentTurnRate))
let angDiff = Math.radianToDegrees(this.GetAngle(target, false))
const targetAng = directionalMovement
? 0
: movement
? GetAngleToFacePath(turnData, angDiff)
: GetCastAngle(turnData, angDiff, this.Position.DistanceSqr2D(target))
let time = 0,
yawVelocity = this.YawVelocity
while (angDiff > targetAng) {
const [change, yawVelocityNew] = UpdateFacing(
turnData,
yawVelocity,
angDiff,
GameState.TickInterval
)
angDiff -= change
yawVelocity = yawVelocityNew
time += GameState.TickInterval
}
return time
}
public IsInside(vec: Vector3, radius: number): boolean {
const position = this.Position
const direction = this.Forward
Expand Down
12 changes: 12 additions & 0 deletions wrapper/Utils/Math.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,3 +278,15 @@ export function SmoothStep(amount: number): number {
export function Clamp(value: number, min: number, max: number): number {
return Math.min(Math.max(value, min), max)
}

export function AngleDiff(destAngle: number, srcAngle: number): number {
const result = (destAngle - srcAngle) % 360
if (destAngle <= srcAngle) {
if (result <= -180) {
return result + 360
}
} else if (result >= 180) {
return result - 360
}
return result
}

0 comments on commit a2c02d1

Please sign in to comment.