Documentation

Exports & Events

Exports and server events for dyno integrations.

General Information

Vehicle arguments are entity handles. Dyno ids are the integers returned by CreateDyno, and the keys of GetDynos. Ids follow the order dynos stand in, so they can change after a restart; history is kept by the dyno's position instead.

Power is in kW, torque in Nm, and speed in metres per second in every export and event, whatever the configured units. Plates are trimmed of spaces.

Run checks and power modifiers belong to the resource that registers them and are removed when it stops. Dynos made through CreateDyno belong to the calling resource and are removed when it stops.

Types / Classes

Types / classes can be found in types/types.lua, shared/formula.lua, and client/live.lua inside zyke_dyno.

#Complete Export Index

ContextExports
ClientGetDynos, GetActiveRun, IsOnDyno, StartRun, GetVehiclePower, GetLiveRun, RegisterPowerModifier, RemovePowerModifier
ServerCreateDyno, RemoveDyno, GetDyno, GetDynos, GetActiveRun, AbortRun, RequestRun, RegisterRunCheck, RemoveRunCheck, GetLastResult, GetResults

#Client Sided Exports

#Get Dynos

Returns every dyno from the zykeDynos global state, keyed by id. Treat the map and its dynos as read-only.

Example:

lua
---@return table<integer, ZykeDyno> dynos
local dynos = exports["zyke_dyno"]:GetDynos()

#Get Active Run

Returns the run on the dyno, or nil while it stands free. Treat it as read-only.

Example:

lua
---@param dynoId integer
---@return ZykeDynoRun? run
local run = exports["zyke_dyno"]:GetActiveRun(dynoId)

#Is On Dyno

Returns whether the player's car stands on a dyno with a run going.

Example:

lua
---@return boolean onDyno
local onDyno = exports["zyke_dyno"]:IsOnDyno()

#Start Run

Starts a run for the car the player drives, as pressing E on the dyno does. Without a dynoId, the dyno under the player's car is used. Returns false and a reason when the run can't start: a locale key, or a check's own text. true means the run was asked for; the server checks it again and notifies the player if it refuses.

Example:

lua
---@param dynoId? integer
---@return boolean requested
---@return string? reason
local requested, reason = exports["zyke_dyno"]:StartRun()

#Get Vehicle Power

Returns the formula's inputs for a car and its power breakdown, without a run. power.engineKw is the engine power in kW. power.base is the power from the handling alone, before the factors, in hp as the formula writes it. See Formula & Calibration.

Example:

lua
---@param vehicle integer
---@return DynoInputs inputs
---@return DynoPowerBreakdown power
local inputs, power = exports["zyke_dyno"]:GetVehiclePower(vehicle)

#Get Live Run

Returns where the pull on a dyno stands as this client sees it, or nil while it stands free. Runs only play for players within streamDistance of the dyno, or connected to it in the laptop app.

  • phase is ready, pull, limiter, or coast.
  • rpm, speed, throttle, and gear are the car's this moment, with throttle from 0 to 1.
  • power and torque are the wheel kW and Nm this moment.
  • points holds the curve drawn so far, each with rpm, kw, and nm.

Example:

lua
---@param dynoId integer
---@return DynoLiveState? live
local live = exports["zyke_dyno"]:GetLiveRun(dynoId)

#Register Power Modifier

Registers a factor on the power the dyno reads, for tunes your resource keeps in its own data. getFactor returns a factor such as 1.15 for 15% more, or 1.0 or nil for none. Every registered factor is multiplied together. Registering again under the same name replaces the earlier modifier.

The driver's client reads the factors as a run starts. They also show in GetVehiclePower and /dynocalibrate. The server refuses a run whose factors multiply to more than 10.

Example:

lua
---@param name string
---@param getFactor fun(vehicle: integer): number?
exports["zyke_dyno"]:RegisterPowerModifier("myTuning", function(vehicle)
    return GetMyStageFactor(vehicle)
end)

#Remove Power Modifier

Removes a power modifier.

Example:

lua
---@param name string
exports["zyke_dyno"]:RemovePowerModifier("myTuning")

#Server Sided Exports

CreateDyno, RemoveDyno, and AbortRun are trusted server operations. They bypass the placing tool's permission check and the driver's own controls. Do not expose them directly through an unrestricted network event.

#Create Dyno

Places a dyno for the calling resource and returns its id, or nil for options without coords. Calling it again within half a metre of a standing dyno returns that dyno's id.

The dyno is removed when the calling resource stops.

Example:

lua
---@param options {coords: vector3, heading?: number, screen?: {offset: vector3, heading: number}, jobs?: string[] | string, label?: string}
---@return integer? dynoId
local dynoId = exports["zyke_dyno"]:CreateDyno({
    coords = vector3(-1352.0, -3020.0, 12.94), -- On the floor, under the middle of the front rollers
    heading = 240.0, -- The way a car's nose points on it
    screen = {offset = vector3(-2.3, 0.6, 0.0), heading = 225.0}, -- Optional, the screen pillar in the dyno's frame
    jobs = {"mechanic"}, -- Optional, who may run it
    label = "Benny's Rolling Road", -- Optional, its name in the laptop app
})

Dyno forgets other resources' dynos, run checks, and power modifiers when it restarts. Register them when it starts as well:

Example:

lua
local function placeDynos()
    exports["zyke_dyno"]:CreateDyno({coords = vector3(-1352.0, -3020.0, 12.94), heading = 240.0})
end

AddEventHandler("onResourceStart", function(resource)
    if (resource == "zyke_dyno") then placeDynos() end
end)

if (GetResourceState("zyke_dyno") == "started") then placeDynos() end

#Remove Dyno

Removes a dyno. Only the resource that made the dyno can remove it. A run on it is stopped.

Example:

lua
---@param dynoId integer
---@return boolean removed
local removed = exports["zyke_dyno"]:RemoveDyno(dynoId)

#Get Dyno

Returns one dyno, or nil. Treat it as read-only.

Example:

lua
---@param dynoId integer
---@return ZykeDyno? dyno
local dyno = exports["zyke_dyno"]:GetDyno(dynoId)

#Get Dynos

Returns every dyno, keyed by id. Treat the map and its dynos as read-only.

Example:

lua
---@return table<integer, ZykeDyno> dynos
local dynos = exports["zyke_dyno"]:GetDynos()

#Get Active Run

Returns the run on the dyno, or nil while it stands free. driver is the player who drives it.

Example:

lua
---@param dynoId integer
---@return ZykeDynoRun? run
local run = exports["zyke_dyno"]:GetActiveRun(dynoId)

#Abort Run

Stops the run on the dyno and returns whether there was one. The driver is told the run was stopped, and the car is let down once its rollers have run down.

Example:

lua
---@param dynoId integer
---@return boolean aborted
local aborted = exports["zyke_dyno"]:AbortRun(dynoId)

#Request Run

Starts a run for a player who sits in a car on a dyno, as if they pressed E. Without a dynoId, the dyno under their car is used. Every check still applies, and the player is notified when the run can't start.

Example:

lua
---@param plyId PlayerId
---@param dynoId? integer
exports["zyke_dyno"]:RequestRun(plyId)

#Register Run Check

Registers a check that runs before every run starts. Return false and a reason to refuse: a zyke_dyno locale key, or your own text with a space in it, which is shown as it is. Registering again under the same name replaces the earlier check.

data holds plyId, dynoId, vehicle, plate, and inputs, the formula's inputs read from the car. Checks run after the built-in checks and CanRunDyno in server/can_checks.lua.

Example:

lua
---@param name string
---@param canRun fun(data: DynoRunCheckData): boolean, string?
exports["zyke_dyno"]:RegisterRunCheck("myJob", function(data)
    if (not IsMechanicOnDuty(data.dynoId)) then return false, "A mechanic has to be on duty to run the dyno." end

    return true
end)

#Remove Run Check

Removes a run check.

Example:

lua
---@param name string
exports["zyke_dyno"]:RemoveRunCheck("myJob")

#Get Last Result

Returns the car's last saved sheet, or nil for a car without runs. Reads the database, so call it from a thread that can wait.

Example:

lua
---@param plate string
---@return DynoSheet? sheet
local sheet = exports["zyke_dyno"]:GetLastResult(plate)

#Get Results

Returns the car's saved sheets, newest first. limit defaults to 10. Reads the database, so call it from a thread that can wait.

Example:

lua
---@param plate string
---@param limit? integer
---@return DynoSheet[] sheets
local sheets = exports["zyke_dyno"]:GetResults(plate, 5)

#Server Local Events

These events are local server integration notifications. They are not network event entry points and cannot block a run; use RegisterRunCheck for that. Listen with AddEventHandler on the server.

#On Run Started

Fires when a run starts. plyId is the driver, and netId the car's network id.

Example:

lua
AddEventHandler("zyke_dyno:OnRunStarted", function(data)
    print(data.dynoId, data.runId, data.plate, data.plyId, data.netId)
end)

#On Run Finished

Fires when a run is finished and saved, with its sheet: runId, dynoId, plate, label, model, drive, date, engineKw, wheelKw, wheelNm, powerRpm, torqueRpm, loss, redlineSpeed, gear, curve, compare, and gain over the car's last run. The sheet leaves out the driver; match runId with OnRunStarted, or use OnDynoRunFinished in server/hooks.lua, which gets sheet.driver.

Example:

lua
---@param sheet DynoSheet
AddEventHandler("zyke_dyno:OnRunFinished", function(sheet)
    print(sheet.plate, sheet.wheelKw, sheet.wheelNm, sheet.gain and sheet.gain.wheelKw)
end)

#On Run Aborted

Fires when a run is stopped early. reason is a locale key, such as reason:driverLeft, reason:engineStopped, reason:tooDamaged, reason:vehicleGone, reason:pullTimeout, or reason:stopped.

Example:

lua
AddEventHandler("zyke_dyno:OnRunAborted", function(data)
    print(data.dynoId, data.runId, data.plate, data.plyId, data.reason)
end)

#State Bags

The zykeDynos global state holds every dyno and the run on it. It is read-only; use the exports above.

For custom rules within Dyno itself, use Can-Check Hooks.