en-weathersync owns the clock, the weather and the ambient temperature for the whole server. Time runs at GTA's pace by default (2 real seconds per in-game minute), but nights pass slower, and both time and weather survive restarts.
Weather follows a weighted cycle: each type lists what it can turn into. A weather lasts 15-35 real minutes with a 45 second blend, and snow is off by default. Each weather has a base temperature, and ambient temperature swings with time of day (warmest at 15:00, coldest at 03:00) and drops with altitude. On every survival tick, survivors outside the comfort band get colder or hotter: shelter (interiors and vehicles) cuts exposure, rain and water chill you, clothing warmth protects against cold but makes heat worse, and nearby heat sources warm you up.
At a glance
| Depends on | /onesync, en-core |
| Used by | en-zombies (night multiplier, weather sight), en-admin (World tab), en-hud (temperature via en-core metadata) |
| Start before | Resources that read its GlobalState keys (they fall back gracefully if the keys are missing) |
| Database tables | None. State is saved to server KVP key state every 60 s and on stop |
| Config files | config/shared.lua |
How it works
Time
The server advances the clock by secondsPerMinute, scaled by nightPace during nightHours, and publishes GlobalState.gameHour and gameMinute. Clients apply the state bags through change handlers.
Weather
When a weather's duration ends, the next type is picked from its next weights. Snow types (SNOWLIGHT, SNOW, BLIZZARD, XMAS) only join the cycle when Config.weather.snow is true. Clients re-assert the current weather every 5 seconds.
Body temperature
Every Config.temperature.interval ms, for each loaded player:
- Ambient temperature is the weather's base temperature, plus the day swing, minus
altitudeLapseper metre of height. - Past the comfort band, body temperature is pulled by
coldRateorheatRateper degree, capped atmaxPullper tick. - Shelter multiplies exposure by
shelter. Being soaked in rain or in water removes extra degrees.nearHeataddsheatSourcedegrees. - Clothing
warmth(0-1, from en-clothing) protects against cold and makes heat worse.
The result is written with en-core's SetTemperature. See Survival system for what body temperature does to a player.
Configuration
config/shared.lua.
Time and weather
| Key | Default | What it does |
|---|---|---|
Config.time.startHour / startMinute | 8 / 0 | Clock on a fresh server |
Config.time.secondsPerMinute | 2.0 | Real seconds per game minute (a 48 minute day) |
Config.time.nightPace | 0.8 | Night speed multiplier (below 1 = longer nights) |
Config.time.nightHours | { from = 20, to = 6 } | What counts as night |
Config.time.persist | true | Resume the clock after a restart |
Config.weather.start | 'CLOUDS' | Weather on a fresh server |
Config.weather.persist | true | Resume the weather after a restart |
Config.weather.duration | { min = 15, max = 35 } | Real minutes per weather |
Config.weather.transition | 45.0 s | Blend time |
Config.weather.snow | false | Allow snow types in the cycle |
Config.weather.types.<NAME> | 14 GTA weather types | { temp (°F), wind, wet?, snow?, next = { TYPE = weight } } |
Example base temperatures: EXTRASUNNY 90°F, CLEAR 82, CLOUDS 72, OVERCAST 64, FOGGY 60, RAIN 56 (wet), THUNDER 52 (wet, wind 8), SNOW 22, BLIZZARD 6.
Temperature
| Key | Default | What it does |
|---|---|---|
Config.temperature.enabled | true | Body temperature exposure on or off |
Config.temperature.interval | 60000 ms | Should match en-core's survival tickInterval |
Config.temperature.daySwing | 12 °F | Afternoon high and pre-dawn low offset |
Config.temperature.altitudeLapse | 0.012 | °F lost per metre of altitude |
Config.temperature.comfort | { low = 58, high = 90 } °F | Ambient band with no effect |
Config.temperature.coldRate / heatRate | 0.03 / 0.025 | Body °F per ambient °F past the comfort band |
Config.temperature.maxPull | 2.0 | Max body °F change per tick |
Config.temperature.shelter | 0.2 | Exposure multiplier indoors or in a vehicle |
Config.temperature.rain / water | 0.35 / 1.2 | Extra body °F lost per tick when soaked or in water |
Config.temperature.heatSource | 1.2 | Body °F gained per tick with nearHeat |
A winter server with long nights and snow in the cycle:
-- config/shared.lua
Config.time.secondsPerMinute = 3.0
Config.time.nightPace = 0.6
Config.weather.start = 'SNOWLIGHT'
Config.weather.snow = true
Config.temperature.comfort = { low = 62, high = 90 }Exports
Server
| Export | Arguments | Returns |
|---|---|---|
SetWeather | name, minutes? | boolean. Holds for minutes, otherwise a random duration |
GetWeather | Weather name | |
SetTime | hour, minute? (0-23, 0-59) | boolean |
GetTime | hour, minute | |
FreezeTime | frozen | Stop or start the clock |
FreezeWeather | frozen | Stop or start the weather cycle |
SetBlackout | on | City lights off or on |
IsBlackout | boolean | |
IsNight | boolean | |
GetAmbientTemperature | coords? | °F at coords.z (sea level if nil) |
Client
| Export | Arguments | Returns |
|---|---|---|
SetSyncEnabled | enabled | Stop or resume following the server (for scenes with their own lighting) |
SetOverride | { weather?, hour?, minute? } | Force weather or time for this client only; the local clock pauses while set |
ClearOverride | ||
GetWeather | GlobalState.weather | |
GetTime | GlobalState.gameHour, GlobalState.gameMinute | |
GetAmbientTemperature | GlobalState.ambientTemperature (sea level, rounded) |
Commands
All restricted to group.admin.
| Command | What it does |
|---|---|
/weather <type> [minutes] | Set the weather, optionally holding it |
/time <hour> [minute] | Set the clock |
/freezetime [on|off] | Freeze the clock; no argument toggles |
/freezeweather [on|off] | Freeze the weather cycle |
/blackout [on|off] | Turn city lights off or on |
The same controls are in the World tab of en-admin.
Events
| Event | Side | Payload |
|---|---|---|
en-weathersync:server:weatherChanged | Server local | newName, previousName |
en-weathersync:server:blackoutChanged | Server local | on |
State bags
Global state published by the server:
| Key | Value |
|---|---|
GlobalState.gameHour / gameMinute | Current game time |
GlobalState.weather | Weather name |
GlobalState.blackout | boolean |
GlobalState.timeFrozen | boolean |
GlobalState.ambientTemperature | Sea-level °F, updated every 30 s |
Player state read by the temperature system:
| Key | Set by | Value |
|---|---|---|
exposure | en-weathersync's own client, every 3 s on change | { sheltered, water } |
warmth | en-clothing | 0-1 |
nearHeat | Other resources, such as a campfire | boolean |
Examples
A campfire that warms whoever stands near it:
-- server
RegisterNetEvent('my-camp:nearFire', function(isNear)
Player(source).state:set('nearHeat', isNear == true, true)
end)A night storm event:
-- server
exports['en-weathersync']:SetWeather('THUNDER', 20)
if exports['en-weathersync']:IsNight() then
exports['en-weathersync']:SetBlackout(true)
end
AddEventHandler('en-weathersync:server:weatherChanged', function(newName, previousName)
if previousName == 'THUNDER' then
exports['en-weathersync']:SetBlackout(false)
end
end)A cutscene at noon in clear weather for one player:
-- client
exports['en-weathersync']:SetOverride({ weather = 'EXTRASUNNY', hour = 12, minute = 0 })
-- ... scene ...
exports['en-weathersync']:ClearOverride()