kenoZ Posted Saturday at 09:28 Share Posted Saturday at 09:28 Hello everyone, I'm currently working on an engine tuning system for vehicles in MTA and I'm running into an issue with setVehicleHandling that I haven't been able to solve despite many attempts. My goal is for vehicles to get faster with each tuning level (1-3). Problem Description: The function setVehicleHandling(theVehicle, handlingTable) consistently returns false for me, and the vehicle retains its original handling. This means the KM/H values do not change, even though I'm trying to modify maxVelocity, engineAcceleration, and driveForce. What I've Tried So Far: I'm fetching the original handling using getOriginalHandling(modelID). I'm creating a new handling table, carrying over most of the original values. I'm modifying maxVelocity, engineAcceleration, and driveForce based on the tuning level using multipliers > 1.0 (e.g., Level 1 = 1.10x, Level 2 = 1.20x, Level 3 = 1.30x). I'm converting values like driveType and engineType to their (presumably) expected numerical equivalents for the table overload of setVehicleHandling (e.g., "awd" to 2, "petrol" to 0). headLightType and tailLightType are passed as numbers. Vector values like centerOfMass and inertiaTensor are passed as tables {x=..., y=..., z=...}. The final table is filtered to only include properties supported by setVehicleHandling. Relevant Log Output of the finalHandling table (Infernus, Model 411, Engine Level 3 - Target: faster): (Assuming base values: baseMaxVelocity=240, baseEngineAcceleration=12, baseDriveForce=0.3 for Infernus) [HH:MM:SS] INFO: [VehiclesServer DEBUG V1.32] Finales Handling für Modell 411, Level 3: { ABS = false, brakeBias = 0.50999999046326, brakeDeceleration = 11, centerOfMass = { x = 0, y = 0, z = -0.25 }, collisionDamageMultiplier = 0.72000002861023, dragCoeff = 1.5, driveForce = 0.345, -- (0.3 * 1.15) driveType = 2, engineAcceleration = 15.6, -- (12 * 1.30) engineInertia = 10, engineType = 0, handlingFlags = 12599296, headLightType = 0, inertiaTensor = { x = 0.1, y = 0.1, z = 0.1 }, mass = 1400, maxVelocity = 312, -- (240 * 1.30) modelFlags = 1073750020, numberOfGears = 5, percentSubmerged = 70, seatOffsetDistance = 0.37000000476837, steeringLock = 30, suspensionAntiDiveMultiplier = 0.40000000596046, suspensionBiasBetweenFrontAndRear = 0.5, suspensionDampingLevel = 0.18999999761581, suspensionForceLevel = 1.2000000476837, suspensionHighSpeedDamping = 0, suspensionLowerLimit = -0.10000000149012, suspensionUpperLimit = 0.25, tailLightType = 0, tractionBias = 0.5, tractionLoss = 0.80000001192093, tractionMultiplier = 0.69999998807907, turnMass = 2725.3000488281 } [HH:MM:SS] INFO: [applyUpgradesOnSpawn] setVehicleHandling FEHLGESCHLAGEN für Lvl 3, Fahrzeug ID 7 (Modell: 411). [HH:MM:SS] INFO: [applyUpgradesOnSpawn] Aktuelles Handling NACH Fehlversuch: { ... } -- (Das Original-Handling) My getModifiedHandlingForSpawn function (Version 1.32): (It's probably best to provide the full function here, including the helper functions, for complete context in the English forum as well.) -- Helper functions (getNumericValue_vehicles, isVectorTable_vehicles, createCleanVector_vehicles, typeConverters_vehicles) -- These perform standard type conversions and vector cleaning. -- (You can briefly describe them or paste their code here if concise enough) local function getNumericValue_vehicles(val) if type(val) == "number" then return val end if type(val) == "string" then local num = tonumber(val) if num ~= nil then return num end end return nil end local function isVectorTable_vehicles(tbl) if type(tbl) ~= "table" then return false end if getNumericValue_vehicles(tbl.x) ~= nil and getNumericValue_vehicles(tbl.y) ~= nil and getNumericValue_vehicles(tbl.z) ~= nil then return true end if getNumericValue_vehicles(tbl[1]) ~= nil and getNumericValue_vehicles(tbl[2]) ~= nil and getNumericValue_vehicles(tbl[3]) ~= nil then return true end return false end local function createCleanVector_vehicles(originalVector, defaultX, defaultY, defaultZ) local defaultVec = { x = defaultX or 0, y = defaultY or 0, z = defaultZ or 0 } if type(originalVector) ~= "table" then return defaultVec end if isVectorTable_vehicles(originalVector) then local x_val, y_val, z_val if getNumericValue_vehicles(originalVector.x) ~= nil and getNumericValue_vehicles(originalVector.y) ~= nil and getNumericValue_vehicles(originalVector.z) ~= nil then x_val = getNumericValue_vehicles(originalVector.x); y_val = getNumericValue_vehicles(originalVector.y); z_val = getNumericValue_vehicles(originalVector.z) elseif getNumericValue_vehicles(originalVector[1]) ~= nil and getNumericValue_vehicles(originalVector[2]) ~= nil and getNumericValue_vehicles(originalVector[3]) ~= nil then x_val = getNumericValue_vehicles(originalVector[1]); y_val = getNumericValue_vehicles(originalVector[2]); z_val = getNumericValue_vehicles(originalVector[3]) end if x_val ~= nil and y_val ~= nil and z_val ~= nil then return { x = x_val, y = y_val, z = z_val } end end return defaultVec end local typeConverters_vehicles = { engineType = function(val, default) if type(val) == "string" then local s = string.lower(val); if s == "petrol" then return 0 elseif s == "diesel" then return 1 elseif s == "electric" then return 2 end end local num_val = getNumericValue_vehicles(val); if num_val ~= nil and (num_val >= 0 and num_val <= 2) then return num_val end return default end, driveType = function(val, default) if type(val) == "string" then local s = string.lower(val); if s == "fwd" then return 0 elseif s == "rwd" then return 1 elseif s == "awd" or s == "4wd" then return 2 end end local num_val = getNumericValue_vehicles(val); if num_val ~= nil and (num_val >= 0 and num_val <= 2) then return num_val end return default end, headLightType = function(val, default) if type(val) == "string" then local s = string.lower(val); if s == "small" then return 0 elseif s == "long" then return 1 elseif s == "big" then return 2 elseif s == "tall" then return 3 end end local num_val = getNumericValue_vehicles(val); if num_val ~= nil and (num_val >= 0 and num_val <= 3) then return num_val end return default or 0 end, tailLightType = function(val, default) if type(val) == "string" then local s = string.lower(val); if s == "small" then return 0 elseif s == "long" then return 1 elseif s == "big" then return 2 elseif s == "tall" then return 3 end end local num_val = getNumericValue_vehicles(val); if num_val ~= nil and (num_val >= 0 and num_val <= 3) then return num_val end return default or 0 end, ABS = function(val, default) if type(val) == "boolean" then return val end if type(val) == "string" then local s = string.lower(val); if s == "true" then return true elseif s == "false" then return false end end local num_val = getNumericValue_vehicles(val); if num_val ~= nil and (num_val == 0 or num_val == 1) then return num_val == 1 end return default or false end } function getModifiedHandlingForSpawn(theVehicle, engineLevel) if not isElement(theVehicle) or getElementType(theVehicle) ~= "vehicle" then outputDebugString("[VehiclesServer|getModifiedHandlingForSpawn] Error: 'theVehicle' is not a valid vehicle element.") return false end if not engineLevel or type(engineLevel) ~= "number" or engineLevel < 0 or engineLevel > 3 then outputDebugString("[VehiclesServer|getModifiedHandlingForSpawn] Error: Invalid 'engineLevel'.") return false end local vehicleModelID = getElementModel(theVehicle) local success, originalHandling_raw = pcall(getOriginalHandling, vehicleModelID) if not success or type(originalHandling_raw) ~= "table" then outputDebugString(string.format("[VehiclesServer|getModifiedHandlingForSpawn] pcall(getOriginalHandling) for model %d FAILED. Error/Type: %s", vehicleModelID, tostring(originalHandling_raw))) return false end local oh = originalHandling_raw local finalHandling = {} local transData = oh.transmissionData or oh finalHandling.mass = getNumericValue_vehicles(oh.mass) or 1700.0 finalHandling.turnMass = getNumericValue_vehicles(oh.turnMass) or 5000.0 finalHandling.dragCoeff = getNumericValue_vehicles(oh.dragCoeff) or 2.5 finalHandling.centerOfMass = createCleanVector_vehicles(oh.centerOfMass or oh.vecCentreOfMass, 0, 0, -0.1) finalHandling.percentSubmerged = getNumericValue_vehicles(oh.percentSubmerged) or 85 finalHandling.tractionMultiplier = getNumericValue_vehicles(oh.tractionMultiplier) or 0.75 finalHandling.tractionLoss = getNumericValue_vehicles(oh.tractionLoss) or 0.85 finalHandling.tractionBias = getNumericValue_vehicles(oh.tractionBias or oh.driveBias) or 0.5 finalHandling.numberOfGears = getNumericValue_vehicles(transData.maxGear or transData.numberOfGears) or 4 finalHandling.maxVelocity = getNumericValue_vehicles(transData.maxVelocity) or 200.0 finalHandling.engineAcceleration = getNumericValue_vehicles(transData.engineAcceleration) or 10.0 finalHandling.engineInertia = getNumericValue_vehicles(oh.engineInertia or (transData and transData.engineInertia)) or 5.0 finalHandling.driveType = typeConverters_vehicles.driveType(oh.driveType or (transData and transData.driveType), 1) finalHandling.engineType = typeConverters_vehicles.engineType(oh.engineType or (transData and transData.engineType), 0) finalHandling.brakeDeceleration = getNumericValue_vehicles(oh.brakeDeceleration) or 10.0 finalHandling.brakeBias = getNumericValue_vehicles(oh.brakeBias) or 0.5 finalHandling.ABS = typeConverters_vehicles.ABS(oh.ABS, (oh.ABS ~= nil and typeConverters_vehicles.ABS(oh.ABS)) or false) finalHandling.steeringLock = getNumericValue_vehicles(oh.steeringLock) or 35.0 finalHandling.suspensionForceLevel = getNumericValue_vehicles(oh.suspensionForceLevel) or 1.0 finalHandling.suspensionDampingLevel = getNumericValue_vehicles(oh.suspensionDampingLevel or oh.suspensionDamping) or 0.1 finalHandling.suspensionHighSpeedDamping = getNumericValue_vehicles(oh.suspensionHighSpeedDamping) or 0.0 finalHandling.suspensionUpperLimit = getNumericValue_vehicles(oh.suspensionUpperLimit) or 0.35 finalHandling.suspensionLowerLimit = getNumericValue_vehicles(oh.suspensionLowerLimit) or -0.15 finalHandling.suspensionBiasBetweenFrontAndRear = getNumericValue_vehicles(oh.suspensionBiasBetweenFrontAndRear or oh.suspensionFrontRearBias) or 0.5 finalHandling.suspensionAntiDiveMultiplier = getNumericValue_vehicles(oh.suspensionAntiDiveMultiplier) or 0.3 finalHandling.seatOffsetDistance = getNumericValue_vehicles(oh.seatOffsetDistance) or 0.0 finalHandling.collisionDamageMultiplier = getNumericValue_vehicles(oh.collisionDamageMultiplier) or 1.0 finalHandling.modelFlags = (type(oh.modelFlags) == "string" and string.sub(oh.modelFlags, 1, 2) == "0x" and tonumber(oh.modelFlags, 16)) or getNumericValue_vehicles(oh.modelFlags) or 0 finalHandling.handlingFlags = (type(oh.handlingFlags) == "string" and string.sub(oh.handlingFlags, 1, 2) == "0x" and tonumber(oh.handlingFlags, 16)) or getNumericValue_vehicles(oh.handlingFlags) or 0 finalHandling.headLightType = typeConverters_vehicles.headLightType(oh.headLight or oh.headLightType, (oh.headLight and typeConverters_vehicles.headLightType(oh.headLight)) or 0) finalHandling.tailLightType = typeConverters_vehicles.tailLightType(oh.tailLight or oh.tailLightType, (oh.tailLight and typeConverters_vehicles.tailLightType(oh.tailLight)) or 0) finalHandling.inertiaTensor = createCleanVector_vehicles(oh.inertiaTensor or oh.vecInertia, 0.1, 0.1, 0.1) local baseDriveForce = getNumericValue_vehicles(oh.driveForce) if not baseDriveForce or baseDriveForce <= 0.001 then baseDriveForce = (vehicleModelID == 451 and 0.30) or (vehicleModelID == 411 and 0.35) or (vehicleModelID == 560 and 0.25) or 0.20 end finalHandling.driveForce = baseDriveForce -- Modifications for engineLevel (to make vehicle FASTER) if engineLevel > 0 then local velocityMultiplier, accelerationMultiplier, driveForceMultiplier = 1.0, 1.0, 1.0 if engineLevel == 1 then velocityMultiplier = 1.10; accelerationMultiplier = 1.10; driveForceMultiplier = 1.05 elseif engineLevel == 2 then velocityMultiplier = 1.20; accelerationMultiplier = 1.20; driveForceMultiplier = 1.10 elseif engineLevel == 3 then velocityMultiplier = 1.30; accelerationMultiplier = 1.30; driveForceMultiplier = 1.15 end finalHandling.maxVelocity = (getNumericValue_vehicles(transData.maxVelocity) or 200.0) * velocityMultiplier finalHandling.engineAcceleration = (getNumericValue_vehicles(transData.engineAcceleration) or 10.0) * accelerationMultiplier finalHandling.driveForce = baseDriveForce * driveForceMultiplier end outputDebugString("[VehiclesServer DEBUG V1.32] Final handling for model "..vehicleModelID..", Level "..engineLevel..": " .. inspect(finalHandling)) return finalHandling end Question for the Community: Despite ensuring that driveType (e.g., 2 for AWD) and engineType (e.g., 0 for Petrol) are numerical, and headLightType/tailLightType are also numerical in the table passed to setVehicleHandling(theVehicle, handlingTable), the function still returns false. The other values in the table appear plausible and are based on getOriginalHandling. The multipliers for engineAcceleration, maxVelocity, and driveForce are now > 1.0, aiming to make the vehicle faster. Does anyone have an idea why setVehicleHandling might still be failing with the finalHandling table shown in the logs above? Could there be an issue with min/max value violations for other properties, or a missing critical property that setVehicleHandling (table overload) requires? The test vehicle is an Infernus (model 411). I've also tried sending a very minimal table with only the modified values (engineAcceleration, maxVelocity, driveForce) and some core values (mass, numberOfGears, driveType, engineType), which also failed. Any help or insights would be greatly appreciated! Link to comment
Administrators Tut Posted Sunday at 09:07 Administrators Share Posted Sunday at 09:07 Coding is not my cup of tea but just wondering what drivefForce is. There's engineInertia but never in my life seen driveForce Link to comment
kenoZ Posted Sunday at 13:03 Author Share Posted Sunday at 13:03 I fixed the problem, namely setVehicleHandling doesn't accept a table as the second parameter. That's why it didn't work. Link to comment
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now