# Developer > Developer API reference for ML Fuel Category: FUEL · Source: https://miciomods.it/docs/ml-fuel-developer · Last updated: 2026-07-28 ## 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 reserved for customer code; it ships with the HRS Base Building mapping in `open/shared.lua`. ## Vehicle State Bags Every vehicle carries its fuel state in replicated state bags. Read them from any resource, client or server: ```lua local state = Entity(vehicle).state state.fuel -- number, 0-100 percent state.fuelType -- 'fuel' | 'diesel' | 'kerosene' | ... state.fuelTypeConverted -- true after a conversion kit or SetFuelType state.tankSize -- tank capacity in liters (with DynamicTankSize) state.tankBonus -- extra liters from installed tank upgrades state.engineOn -- mirrored engine state, used by the idle drain ``` `fuel` 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. ```lua GlobalState['ml_fuel:mode'] -- 'advanced' | 'simple' GlobalState['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 vehicle - `SetFuel(netId, fuel)`: set the level (clamped 0-100). Returns boolean - `GetFuelType(netId)`: current fuel type string - `SetFuelType(netId, fuelType)`: set the type (must exist in `Config.FuelTypes`) and mark the vehicle as converted. Returns boolean - `GetVehicleFuel(netId)` / `SetVehicleFuel(netId, fuel)` / `GetVehicleFuelType(netId)` / `SetVehicleFuelType(netId, fuelType)`: aliases of the four above - `GetFuelTypes()`: the `Config.FuelTypes` table (key -> { label, color, consumptionRate }) ### Conversions and Upgrades - `GetVehicleConversion(plate)`: converted fuel type for a plate, or nil - `SetVehicleConversion(plate, fuelType, license?)`: write a conversion to the database - `DeleteVehicleConversion(plate)`: remove a conversion - `GetVehicleTankBonus(plate)`: total bonus liters installed on a plate - `GetVehicleUpgrades(plate)`: { tankBonus, upgrades } for a plate - `CanInstallUpgrade(plate, upgradeItem)`: false when the upgrade hit its `maxStacks` ### Scavenge Stations - `GetActiveStations()`: array of { idx, coords, charges, maxCharges } - `IsStationActiveAtCoords(coords)`: true when the coordinate falls inside an active station zone - `IsStationActive(stationIdx)` / `GetStationCharges(stationIdx)`: state of one station by index - `RefreshActiveStations()`: force a station rotation now - `GetSiphonItemName()`: 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 type - `GetFuel(vehicle)`: alias of `GetVehicleFuel` - `IsFuelCompatible(vehicle, fuelType)`: true when the vehicle runs the given type - `GetVehicleTankSize(vehicle)`: tank capacity in liters (includes upgrade bonus) - `FuelPercentToLiters(vehicle, percent)` / `FuelLitersToPercent(vehicle, liters)`: unit conversion against the vehicle tank - `GetVehicleHandlingData(vehicle)`: cached handling values used by the consumption model > **INFO:** No client-side writes > > 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 container - `OpenJerryCanMenu(slot, itemName)`: open the Transfer UI for a specific jerry can slot - `OpenTransferUI(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 an HRS generator. `genData = { fuel, fuelTank, fuelItem }` - `CloseTransferUI()` / `IsTransferUIOpen()` - `ShowFuelUI()` / `HideFuelUI()` / `UpdateFuelDisplay(data)`: control the gauge HUD ### Scavenging and State - `StartScavenging(pumpCoords, pumpEntity?)`: start the pump scavenge flow - `TryScavengeNearbyWreck()` / `GetNearbyWreck()` / `SearchNearestWreck()`: wreck scavenge helpers - `IsPumpAtActiveStation(coords)` / `FindClosestPump(coords, radius)` - `IsInNoLootZone()`: true when the player stands inside a no-loot zone - `IsFueling()` / `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: ```lua metadata = { fuelType = 'diesel', -- raw fuel type key, nil when empty fuelTypeLabel = 'Diesel', -- localized label for the tooltip fuelAmount = 18.5, -- current liters, rounded to 2 decimals maxCapacity = 25, -- capacity from Config.JerryCans[item].capacity } ``` - The item is refillable. A consumer empties the metadata, it never removes the item - An empty can has `fuelAmount = 0` and `fuelType = nil`, and can then be filled with any type in its `acceptsFuel` list - 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: **your_script/server.lua** ```lua local ACCEPTED = { fuel = true, diesel = true } function DrawFuelFromJerryCan(src, slot, litersWanted) local item = Bridge.GetSlot(src, slot) if not item then return 0 end local meta = item.metadata or {} local amount = meta.fuelAmount or 0 local fuelType = meta.fuelType if amount <= 0 or not ACCEPTED[fuelType] then return 0 end local drawn = math.min(litersWanted, amount) local left = math.floor((amount - drawn) * 100 + 0.5) / 100 Bridge.SetItemMeta(src, slot, { fuelAmount = left, fuelType = left > 0 and fuelType or nil, fuelTypeLabel = left > 0 and meta.fuelTypeLabel or nil, maxCapacity = meta.maxCapacity, }) return drawn end ``` ml_recycler (machine fuel) and hrs_base_building generators consume jerry cans through this exact contract. ## HRS Base Building The generator integration is built in. When a player opens "Manage Fuel" on an HRS generator, ML Fuel opens its Transfer UI instead of the default one, finds a jerry can holding the matching fuel type, and pours with hold-to-pour. The `fuelItem` value set on the generator is mapped to an ML Fuel type through `Config.HRS.fuelTypeMapping` in `open/shared.lua`. Two open-file edits are required on the HRS side: a pair of exports in `server/main_unlocked.lua` and a UI intercept in `client/main_unlocked.lua`. Copy them from `open/HRS_INTEGRATION.md`, which ships with the resource. ## Commands - `/mlfuel setfuel|settype|info|resetcooldowns`: admin utilities on the current or last vehicle; `resetcooldowns` forces a station rotation - `/showpumps`: admin. Temporary blips on the active scavenge stations. Name and blip settings in `Config.PumpScavenging.staffCommand` - `/mlwreckreset`: admin or server console. Clears all wreck cooldowns - `/mlfueldebug`: unified debug menu. Only registered when `Config.Debug = true` - `ml_fuel_interact`: key mapping (default E) for pump/wreck interaction in textui mode - `ml_fuel_stop_charge`: key mapping (default BACKSPACE) to stop an EV charging session ## Examples **Read the fuel of the current vehicle (client)** **your_script/client.lua** ```lua if cache.vehicle then local fuel = exports.ml_fuel:GetVehicleFuel(cache.vehicle) local fuelType = exports.ml_fuel:GetVehicleFuelType(cache.vehicle) local liters = exports.ml_fuel:FuelPercentToLiters(cache.vehicle, fuel) print(('%.1f%% (%.1fL) of %s'):format(fuel, liters, fuelType)) end ``` **Refill a vehicle from the server** **your_script/server.lua** ```lua local netId = NetworkGetNetworkIdFromEntity(vehicle) exports.ml_fuel:SetFuel(netId, 100.0) exports.ml_fuel:SetFuelType(netId, 'diesel') ``` **React to fuel changes with a state bag handler** **your_script/client.lua** ```lua AddStateBagChangeHandler('fuel', nil, function(bagName, _, value) local entity = GetEntityFromStateBagName(bagName) if entity == 0 or entity ~= cache.vehicle then return end if value and value < 10 then -- low fuel warning end end) ```