Developer
Overview
Integration happens through exports and vehicle state bags. Fuel is server-authoritative: clients can read it anywhere, but writes go through the server exports. The open/ folder is not escrowed and is there for your own code.
Vehicle State Bags
Every vehicle carries its fuel state in replicated state bags. Read them from any resource, client or server:
1local state = Entity(vehicle).state
2
3state.fuel -- number, 0-100 percent
4state.fuelType -- 'fuel' | 'diesel' | 'kerosene' | ...
5state.fuelTypeConverted -- true after a conversion kit or SetFuelType
6state.tankSize -- tank capacity in liters (with DynamicTankSize)
7state.tankBonus -- extra liters from installed tank upgrades
8state.engineOn -- mirrored engine state, used by the idle drainfuel is a percentage. Convert with tankSize or the client exports FuelPercentToLiters / FuelLitersToPercent. While driving, the driver client updates the level every tick and replicates it every Config.Consumption.replicationInterval ticks.
1GlobalState['ml_fuel:mode'] -- 'advanced' | 'simple'
2GlobalState['ml_fuel:stations'] -- active scavenge stations: { { idx, coords, charges, maxCharges }, ... }Server Exports
Vehicle Fuel
GetFuel(netId): fuel level 0-100, or nil for an invalid vehicleSetFuel(netId, fuel): set the level (clamped 0-100). Returns booleanGetFuelType(netId): current fuel type stringSetFuelType(netId, fuelType): set the type (must exist inConfig.FuelTypes) and mark the vehicle as converted. Returns booleanGetVehicleFuel(netId)/SetVehicleFuel(netId, fuel)/GetVehicleFuelType(netId)/SetVehicleFuelType(netId, fuelType): aliases of the four aboveGetFuelTypes(): theConfig.FuelTypestable (key -> { label, color, consumptionRate })GetVehicleFuelInfo(netId): fuel level, type and tank data of a spawned vehicle, ornil
Conversions and Upgrades
GetVehicleConversion(plate): converted fuel type for a plate, or nilSetVehicleConversion(plate, fuelType, license?): write a conversion to the databaseDeleteVehicleConversion(plate): remove a conversionGetVehicleTankBonus(plate): total bonus liters installed on a plateGetVehicleUpgrades(plate): { tankBonus, upgrades } for a plateCanInstallUpgrade(plate, upgradeItem): false when the upgrade hit itsmaxStacksGrantTankUpgrade(plate, upgradeItem, playerLicense?): installs an upgrade on a plate from codeRemoveTankUpgrade(plate, upgradeItem): removes itGetTankUpgradeItems(): the configured upgrade itemsGetVehicleFuelSummary(plate):{ fuelType, converted, tankBonus, upgrades }of a plateClearVehicleConversion(plate): removes the conversion of a plate and returnstrueon success
Scavenge Stations
GetActiveStations(): array of { idx, coords, charges, maxCharges }IsStationActiveAtCoords(coords): true when the coordinate falls inside an active station zoneIsStationActive(stationIdx)/GetStationCharges(stationIdx): state of one station by indexGetStationLitres(stationIdx): litres left in the tank of one stationRefreshActiveStations(): force a station rotation nowGetSiphonItemName(): the configured siphon tool item name
Database
WaitForDatabase()/IsDatabaseReady(): block until / check whether the table init finished
Client Exports
Reading Fuel
GetVehicleFuel(vehicle): fuel level 0-100 (entity handle, not netId)GetVehicleFuelType(vehicle): current fuel typeGetFuel(vehicle): alias ofGetVehicleFuelIsFuelCompatible(vehicle, fuelType): true when the vehicle runs the given typeGetVehicleTankSize(vehicle): tank capacity in liters (includes upgrade bonus)FuelPercentToLiters(vehicle, percent)/FuelLitersToPercent(vehicle, liters): unit conversion against the vehicle tankGetVehicleHandlingData(vehicle): cached handling values used by the consumption modelGetVehicleBaseTankSize(vehicle): tank capacity in liters before upgradesIsVehicleFuelConverted(vehicle):truewhen the vehicle runs a converted fuel typeGetVehicleFuelInfo(vehicle): fuel level, type and tank data of a vehicle
There are no SetFuel exports on the client. Modify fuel from the server exports only.
UI and Menus
OpenRefuelMenu(vehicle): open the Transfer UI against a vehicle with the best compatible containerOpenJerryCanMenu(slot, itemName): open the Transfer UI for a specific jerry can slotOpenTransferUI(jerrycanData, vehicleData, mode): low-level open.mode = 'refuel' | 'siphon'OpenTransferUIAdvanced(jerrycanData, vehicleData, options): open with mode switching (options.canRefuel,options.canSiphon)OpenGeneratorTransfer(propId, genData): open the Transfer UI against a generator.genData = { fuel, fuelTank, fuelItem }CloseTransferUI()/IsTransferUIOpen()ShowFuelUI()/HideFuelUI()/UpdateFuelDisplay(data): control the gauge HUDShowFuelGauge()/HideFuelGauge(): show or hide the gauge from another HUD resourceInspectVehicleFuel(vehicle): open the fuel system inspection of a vehicle
Scavenging and State
StartScavenging(pumpCoords, pumpEntity?): start the pump scavenge flowTryScavengeNearbyWreck()/GetNearbyWreck()/SearchNearestWreck(): wreck scavenge helpersIsPumpAtActiveStation(coords)/FindClosestPump(coords, radius)IsInNoLootZone(): true when the player stands inside a no-loot zoneIsFueling()/SetFueling(value)/GetLastVehicle()GetFuelCapPosition(vehicle)/IsNearFuelCap(vehicle, maxDistance?)GetJerryCanItems()/HasRefuelItem(): configured jerry can names and whether the player carries any refuel container
Jerry Can Metadata Contract
Jerry cans are the exchange format between ML Fuel and other resources. A jerry can is a normal inventory item with four metadata keys:
1metadata = {
2 fuelType = 'diesel', -- raw fuel type key, nil when empty
3 fuelTypeLabel = 'Diesel', -- localized label for the tooltip
4 fuelAmount = 18.5, -- current liters, rounded to 2 decimals
5 maxCapacity = 25, -- capacity from Config.JerryCans[item].capacity
6}- The item is refillable. A consumer empties the metadata, it never removes the item
- An empty can has
fuelAmount = 0andfuelType = nil, and can then be filled with any type in itsacceptsFuellist - Fuel types never mix: a can holding diesel refuses gasoline until emptied
- Always re-read the slot server-side before consuming, never trust amounts sent by a client
The read-and-consume pattern for accepting ML Fuel jerry cans in another resource:
1local ACCEPTED = { fuel = true, diesel = true }
2
3function DrawFuelFromJerryCan(src, slot, litersWanted)
4 local item = Bridge.GetSlot(src, slot)
5 if not item then return 0 end
6
7 local meta = item.metadata or {}
8 local amount = meta.fuelAmount or 0
9 local fuelType = meta.fuelType
10
11 if amount <= 0 or not ACCEPTED[fuelType] then return 0 end
12
13 local drawn = math.min(litersWanted, amount)
14 local left = math.floor((amount - drawn) * 100 + 0.5) / 100
15
16 Bridge.SetItemMeta(src, slot, {
17 fuelAmount = left,
18 fuelType = left > 0 and fuelType or nil,
19 fuelTypeLabel = left > 0 and meta.fuelTypeLabel or nil,
20 maxCapacity = meta.maxCapacity,
21 })
22
23 return drawn
24endml_recycler machines consume jerry cans through this contract.
Commands
/mlfuel setfuel|settype|info|resetcooldowns: admin utilities on the current or last vehicle;resetcooldownsforces a station rotation/showpumps: admin. Temporary blips on the active scavenge stations. Name and blip settings inConfig.PumpScavenging.staffCommand/mlwreckreset: admin or server console. Clears all wreck cooldownsml_fuel_interact: key mapping (default E) for pump/wreck interaction in textui modeml_fuel_stop_charge: key mapping (default BACKSPACE) to stop an EV charging session
Examples
1if cache.vehicle then
2 local fuel = exports.ml_fuel:GetVehicleFuel(cache.vehicle)
3 local fuelType = exports.ml_fuel:GetVehicleFuelType(cache.vehicle)
4 local liters = exports.ml_fuel:FuelPercentToLiters(cache.vehicle, fuel)
5 print(('%.1f%% (%.1fL) of %s'):format(fuel, liters, fuelType))
6end1local netId = NetworkGetNetworkIdFromEntity(vehicle)
2exports.ml_fuel:SetFuel(netId, 100.0)
3exports.ml_fuel:SetFuelType(netId, 'diesel')1AddStateBagChangeHandler('fuel', nil, function(bagName, _, value)
2 local entity = GetEntityFromStateBagName(bagName)
3 if entity == 0 or entity ~= cache.vehicle then return end
4 if value and value < 10 then
5 -- low fuel warning
6 end
7end)