Developer

4 min readUpdated 2 weeks ago

Overview

ml_climaticvitals has client exports for reading temperature data and toggling the system, plus open/ folder with empty OpenClient/OpenServer tables reserved for your own code. Vehicle climate state syncs via entity StateBags. Server-side: temperature calculation, weather sync, DB persistence, item confirmation (zero-trust, server computes all damage/stat values, never trusts client).

Client Exports

Temperature Data

  • GetPerceivedTemperature(): Returns the current perceived temperature (number, Celsius). Includes all modifiers
  • GetCurrentTemperature(): Returns the current ambient/server temperature (number, Celsius). Raw weather-based value
  • GetState(): Returns a table with the full system state:
lua
1{
2    perceived = 22.0,      -- Perceived temperature (Celsius)
3    current = 20.0,        -- Ambient temperature (Celsius)
4    weather = 'CLEAR',     -- Current weather type string
5    nearHeat = false,      -- Near a heat/cold source object
6    inVehicle = false,     -- In a vehicle with insulation
7    inInterior = false,    -- Inside an MLO/interior
8    wetness = 0.0,         -- Wetness level (0.0 to 1.0)
9    itemBuff = 0.0,        -- Active item buff modifier
10}

UI Control

  • hideweatherhud(hide): Hide or show the temperature HUD widget. true = hide, false = show. Blocked when Config.ForceShowWidget = true
  • HideUi(shouldHide): Alias for hideweatherhud
  • OpenClimateMenu(): Opens the vehicle climate control UI. Only works in a valid vehicle with the engine running

System Control

  • SetClimaticState(state): Enable or disable the entire system. true = active, false = paused. When paused: HUD hides, visual effects clear, damage stops, temperature updates stop

Buffs

  • ApplyBuff(buffAmount, durationMinutes): Apply a local temperature buff. buffAmount is degrees (positive = warm, negative = cool), durationMinutes is duration in minutes. Client-side only, does not sync to server

StateBags

Vehicle Climate State

Climate control state is stored on the vehicle entity:

lua
1Entity(vehicle).state.climateState = {
2    on = true,          -- Climate system on/off
3    temp = 21.0,        -- Target temperature
4    fan = 1,            -- Fan speed level (0-3)
5    mode = 'auto'       -- 'auto', 'heat', or 'ac'
6}

All vehicle occupants read this StateBag. The driver sends updates to the server via ml_climaticvitals:server:updateClimateState. The server validates: entity existence, player proximity (10 units), data types, and clamps temp/fan/mode to valid ranges before writing the StateBag.

Server Events

  • ml_climaticvitals:getInitialTemperature: Client requests current temperature on join
  • ml_climaticvitals:server:setWeather: Weather reporter client sends the current weather name. Accepted only from the assigned reporter
  • ml_climaticvitals:server:updateClimateState: Client sends vehicle climate changes. Server validates before writing StateBag
  • ml_climaticvitals:server:ApplyStatusDamage: Client sends condition string ('hot'/'cold'). Server computes actual hunger/thirst values from config and applies them via Bridge.SetHunger/Bridge.SetThirst. Rate-limited to 10 seconds per player
  • ml_climaticvitals:server:confirmItemUse: Client confirms item consumption after progress bar completes. Server verifies inventory, removes 1 item, applies buff via client event. Protected with GetInvokingResource() check

Client Events

  • ml_climaticvitals:updateTemperature: Server broadcasts ambient temperature and weather type
  • ml_climaticvitals:client:setAsWeatherReporter: Server assigns a client as weather reporter
  • ml_climaticvitals:client:useItem: Server triggers item consumption flow. Client shows progress bar, then confirms back to server
  • ml_climaticvitals:client:applyBuff: Server applies a buff after item confirmation. Receives buffAmount and durationMs
  • ml_climaticvitals:client:notifyItemBuff: Server sends item notification after confirmation
  • ml_climaticvitals:client:playerReady: Internal event fired when the player is fully loaded

All RegisterNetEvent handlers include GetInvokingResource() checks to prevent server-side event spoofing.

Temperature Calculation

The perceived temperature formula:

lua
1basePerceived = ambient
2    + zoneModifier
3    + clothesThermalBonus
4    + temperatureObjectBonus
5    + vehicleClimateModifier
6    + vehicleInsulationBonus
7    + nightTimeMalus (-4 between 21:00-06:00)
8    + wetnessMalus (wetness * Config.Wetness.TemperatureMalus)
9    + waterMalus (Config.PlayerOnWater.TempMalus when swimming)
10    + itemBuff
11
12interiorMod = (Config.InteriorBonus.targetTemp - basePerceived) * Config.InteriorBonus.strength
13
14perceived = basePerceived + interiorMod

The interior mod pulls perceived temp towards targetTemp: warms you if it's cold, cools you if it's hot.

Weather Reporter System

One client is designated as the weather reporter and polls GetPrevWeatherTypeHashName() every 5 seconds. When the reporter disconnects, the server reassigns after 1 second. Only the assigned reporter's weather updates are accepted.

Item Use Flow

  1. Server registers all Config.ItemBuffs items as usable via Bridge.BindUsableItem
  2. Player uses item → server checks Bridge.HasItem → triggers ml_climaticvitals:client:useItem
  3. Client shows lib.progressBar with animation/prop
  4. On progress bar completion → client triggers ml_climaticvitals:server:confirmItemUse
  5. Server re-checks Bridge.HasItem, removes 1 item, triggers buff on client

Item is removed server-side only after client confirms progress bar completion. Cancelling the progress bar does not remove the item.

Examples

lua
1-- Client-side
2local state = exports.ml_climaticvitals:GetState()
3print(('Perceived: %.1f, Weather: %s, Wetness: %.0f%%'):format(
4    state.perceived, state.weather, state.wetness * 100
5))
lua
1-- Client-side
2exports.ml_climaticvitals:hideweatherhud(true)  -- hide
3exports.ml_climaticvitals:hideweatherhud(false) -- show
lua
1-- Client-side
2exports.ml_climaticvitals:SetClimaticState(false) -- pause
3-- ...minigame logic...
4exports.ml_climaticvitals:SetClimaticState(true)  -- resume
lua
1-- Client-side: cool the local player by 10 degrees for 5 minutes
2exports.ml_climaticvitals:ApplyBuff(-10.0, 5)