local maf	= require 'maf'
local vec3	= maf.vector
local quat	= maf.rotation


-- Порог для поднятия тангажа, используется для корректировки тангажа
local pitchUpThreshold   = -15 -- значение в градусах, извлечено из MonoBehaviour с fileID: 3737572916587997159

-- Угол для тонкой корректировки рулевого управления,
-- определяет, когда следует выполнять корректировки рысканья или крена
local fineSteeringAngle  = 5   -- значение в градусах, извлечено из MonoBehaviour с fileID: 3737572916587997159

-- Фактор для корректировки рысканья, множитель для настройки управления по рысканию
local yawFactor          = 1   -- множитель, используется для масштабирования корректировки рысканья, извлечено из MonoBehaviour с fileID: 3737572916587997159

-- Фактор для корректировки крена, множитель для настройки управления по крену
local rollFactor         = 0.01 -- множитель, используется для масштабирования корректировки крена, извлечено из MonoBehaviour с fileID: 3737572916587997159

-- Скорость рулевого управления, определяет, насколько быстро следует двигаться к целевому вводу
local steeringSpeed      = 15.0 -- единиц в секунду, скорость перемещения к целевым значениям управления, извлечено из MonoBehaviour с fileID: 3737572916587997159

local dir = {
    forward		= vec3(0, 1, 0),	-- вперед
    backward	= vec3(0, -1, 0),	-- назад
    right		= vec3(1, 0, 0),	-- вправо
    left		= vec3(-1, 0, 0),	-- влево
    up			= vec3(0, 0, 1),	-- вверх
    down		= vec3(0, 0, -1)	-- вниз
}

function signedAngle(from, to, axis)
  -- Step 1: Normalize the both vectors
  local fromNormalized = from:clone():normalize()
  local toNormalized = to:clone():normalize()
  
  -- Step 2: Calculate the unsigned angle
  local dotProduct = fromNormalized:dot(toNormalized)
  local angle = math.acos(math.max(-1, math.min(1, dotProduct))) -- Clamp acos input

  -- Step 3: Determine the sign using the cross product and reference axis
  local crossProduct = fromNormalized:cross(toNormalized)
  local sign = crossProduct:dot(axis) < 0 and -1 or 1

  -- Step 4: Return the signed angle
  return angle * sign
end


function CalculateSteeringForPlane(plane, dt, targetPosition)
    -- Assuming there's a way to check health or other properties similar to your reference

    local planePosition = vec3(getCarCoordinates(plane))
    local planeRotation = quat(getVehicleQuaternion(plane))

    local error = targetPosition - planePosition
    local errorLocal = conjugateQuaternion(planeRotation) * error

    local errorDir = errorLocal:normalize()

    local pitchError = vec3(0, errorLocal.y, errorLocal.z):normalize()
    local rollError = vec3(errorLocal.x, errorLocal.y, 0):normalize()
    local yawError = vec3(errorLocal.x, 0, errorLocal.z):normalize()

    local targetInput = vec3()

    local pitch = signedAngle(dir.forward, pitchError, dir.right)
    if -pitch < pitchUpThreshold then
        pitch = (pitch + 360) % 360
    end
    targetInput.x = pitch

    if calculateAngleBetweenVectors(dir.forward, errorDir) < fineSteeringAngle then
        local yaw = signedAngle(dir.forward, yawError, dir.up)
        targetInput.y = yaw * yawFactor
    else
        local roll = signedAngle(dir.up, rollError, dir.forward)
        targetInput.z = roll * rollFactor
    end

    targetInput.x = math.max(-1, math.min(1, targetInput.x))
    targetInput.y = math.max(-1, math.min(1, targetInput.y))
    targetInput.z = math.max(-1, math.min(1, targetInput.z))

    local input = vec3() -- Assuming there is some last input stored somewhere
    local steeringSpeed = 1 -- Define your steering speed value
    input.x = math.max(-1, math.min(1, input.x + (targetInput.x - input.x) * steeringSpeed * dt))
    input.y = math.max(-1, math.min(1, input.y + (targetInput.y - input.y) * steeringSpeed * dt))
    input.z = math.max(-1, math.min(1, input.z + (targetInput.z - input.z) * steeringSpeed * dt))

    lastInput = input -- Commented out `lastInput = input` assuming `lastInput` is defined elsewhere

    return input
end


-- This function calculates the angle between two vectors in degrees.
-- The 'maf' implementation erroneously uses 'v:dot(u) / (v:length() + u:length())',
-- adding vector lengths instead of multiplying them. Correctly, the formula should be:
-- cos(θ) = (v . u) / (|v| * |u|),
-- where |v| and |u| are vector magnitudes. This error can produce invalid angles,
-- as the result might exceed the valid range for arccos, [-1, 1].
function calculateAngleBetweenVectors(v1, v2)
    -- Normalize the vectors to focus only on their direction
    local norm_v1 = v1:normalize()
    local norm_v2 = v2:normalize()

    -- Compute the dot product of the normalized vectors
    local dot_product = norm_v1:dot(norm_v2)

    -- Clamp the dot product value in the range [-1, 1]
    -- to avoid numerical errors during arccos calculation
    dot_product = math.max(-1, math.min(1, dot_product))

    -- Calculate the angle in radians and convert it to degrees
    local angle_radians = math.acos(dot_product)
    return math.deg(angle_radians)
end


local n = 1

-- Функция для получения кватерниона сопряжения
function conjugateQuaternion(q)
    return quat(-q.x, -q.y, -q.z, q.w)
end

local socket = require("socket")

local samem = require 'SAMemory'




function main()
    local lastTime = socket.gettime()  -- Initialize the starting time

    while true do
        wait(1)  -- This can be reduced or adjusted as needed

        -- Calculate the delta time (dt) in seconds
        local currentTime = socket.gettime()
        local dt = currentTime - lastTime
        lastTime = currentTime  -- Update the lastTime for the next loop

        -- Print received dt for debugging
        --print("Delta time (dt):", dt)

        -- Retrieve the plane the player is in
        local plane = storeCarCharIsInNoSave(playerPed)

        -- Get the plane's position and rotation
        local planePosition = vec3(getCarCoordinates(plane))
        local planeRotation = quat(getVehicleQuaternion(plane))

        -- Retrieve the active camera's coordinates
        local camPosition = vec3(getActiveCameraCoordinates())
        local camPointAt = vec3(getActiveCameraPointAt())

        -- Calculate the camera's forward direction vector (normalized)
        local camDirection = (camPointAt - camPosition):normalize()

        -- Calculate target position by adding the camera vector to the plane's position
        local targetPosition = planePosition + camDirection

        -- Calculate steering for the plane using the target position
        --print(CalculateSteeringForPlane(plane, dt, targetPosition))
		pitchInput, yawInput, rollInput = CalculateSteeringForPlane(plane, dt*500, targetPosition):unpack()
		print(pitchInput, yawInput, rollInput)
		
		if doesVehicleExist(plane) then
			local carPointer = getCarPointer(plane)
			local vehicle = samem.cast("CVehicle *", carPointer)
		
			-- Проверка на тип транспортного средства
			if vehicle ~= samem.nullptr and vehicle.nVehicleClass == 0 then -- VEHICLE_TYPE_AUTOMOBILE = 0
				local plane = samem.cast('CPlane *', vehicle)
				plane.field_988 = yawInput  	* 2^30
				plane.field_98C = pitchInput	* 2^30
				plane.field_990 = rollInput 	* 2^30
				plane.field_9C4 = 1				* 2^30
				
		
				--print(yawInput, pitchInput, rollInput)
			end
		end
		
    end
end

отрефактори весь этот код. порядок функций, имена функций, имена переменных, комментарии итд

главное НИКАК не меняй логику, принципов рабоыт