Developer API
Read exports, client exports, trusted write exports, events with payloads, and GlobalState.
Updated 2026-07-02
On this page
Everything here works across the escrow boundary - you integrate through
exports, events, and GlobalState, never by editing the resource. Working
starting points for a HUD, phone app, vehicle traction, fishing, interiors,
and a store hook ship in the resource's examples/ folder.
The 60-second version
Three ways to read the sky - pick whichever fits:
-- 1. Ask for everything at once (server)
local snap = exports['dzr-environment']:GetEnvironmentSnapshot()
if snap.surface == 'slick' then --[[ wet roads ]] end
-- 2. React when it changes instead of asking (server or client)
AddEventHandler('dzr-environment:server:weatherChanged', function(data)
-- data.current, data.surface, data.snapshot ...
end)
-- 3. Read the shared state directly - no export call at all (anywhere)
local env = GlobalState.environment -- env.weather, env.hour, env.temperature ...
Conventions:
- Read exports are safe to call from any server resource.
- Write exports are for trusted server scripts. They return
success, reason. Never wire one to a raw client event without your own permission check. - All weather type strings are GTA-native uppercase:
EXTRASUNNY,CLEAR,CLOUDS,OVERCAST,RAIN,THUNDER,CLEARING,FOGGY,SMOG.
Server read exports
local E = exports['dzr-environment']
-- Time
E:GetHour() --> number 0-23
E:GetMinute() --> number 0-59
E:GetTime() --> { hour, minute }
E:IsDay() --> boolean
E:IsNight() --> boolean
-- Weather
E:GetWeather() --> string, e.g. 'RAIN'
E:IsRaining() --> boolean (RAIN or THUNDER)
E:GetWeatherIntensity() --> number 0.3 | 0.6 | 0.9
E:GetWeatherTypes() --> string[] (all valid types)
-- Derived conditions
E:GetTemperature() --> { fahrenheit, celsius }
E:GetHeatLevel() --> 'cool' | 'normal' | 'hot' | 'scorching'
E:GetVisibilityLevel() --> 'clear' | 'reduced' | 'poor'
E:GetSurfaceCondition() --> 'dry' | 'damp' | 'slick'
E:GetWindLevel() --> 'calm' | 'light' | 'moderate' | 'strong' | 'severe'
E:GetRainDuration() --> number (minutes of accumulated rain this session)
-- Full snapshot (one call for everything)
E:GetEnvironmentSnapshot()
-- Forecast / transition
E:GetForecast() --> { weather, eta = 'soon'|'later'|'distant', conditions }
E:GetTransitionInfo() --> { nextWeather, possibleNext, remainingMinutes, ... }
-- Locks / blackout (read)
E:GetTimeLock() --> boolean
E:GetWeatherLock() --> boolean
E:GetBlackout() --> boolean
GetEnvironmentSnapshot() shape:
{
time = { hour = 14, minute = 32 },
weather = 'RAIN',
intensity = 0.6,
temperature = { fahrenheit = 62, celsius = 17 },
heat = 'normal',
visibility = 'reduced',
surface = 'damp',
wind = 'moderate',
}
Client exports
local E = exports['dzr-environment']
-- Sanitized, display-ready, respects Config.TemperatureUnit
E:GetWeatherInfo() --> { time, weather, intensity,
-- temperature = { value, unit, fahrenheit, celsius },
-- heat, visibility, surface, wind }
-- (nil before the first sync)
-- Pause this resource's LOCAL application of time/weather (cinematics,
-- character select). Visual only - it does NOT stop server authority.
-- Resume must match the reason tag.
E:SuppressSync('charselect')
E:ResumeSync('charselect')
Local overrides (client-visual only)
Show THIS player a different sky or clock - interiors, apartments, character select, cutscenes - without changing the world for anyone else. These never trigger a server event or mutate server state. They are reason-tagged and reference-counted (latest active wins per axis); a 120-second timeout auto-clears an orphaned override.
local E = exports['dzr-environment']
E:SetLocalWeather('FOGGY', 'interior:apartment42') --> boolean (false if invalid weather/reason)
E:SetLocalTime(2, 30, 'cutscene:intro') --> boolean (hour 0-23, minute 0-59)
E:ClearLocalOverride('interior:apartment42') -- restores the live server view smoothly
E:HasLocalOverride() --> boolean
-- Example: foggy 1am inside an apartment, restored on exit
AddEventHandler('myapartments:entered', function()
E:SetLocalWeather('FOGGY', 'apt')
E:SetLocalTime(1, 0, 'apt')
end)
AddEventHandler('myapartments:exited', function()
E:ClearLocalOverride('apt')
end)
SetLocalWeather overrides only weather; SetLocalTime overrides only the
clock - mix and match. They are independent of SuppressSync (if both are
active, SuppressSync's full pause wins).
Server write exports (trusted only)
Each returns success: boolean, reason: string|nil.
local ok, reason = exports['dzr-environment']:SetWeather('RAIN')
if not ok then print('failed:', reason) end
E:SetTime(hour) -- 0-23, instant snap
E:SetTime(hour, true) -- cinematic: the clock RUNS to the hour over ~8-30s
E:SetTime(hour, true, true) -- cinematic, rewinding backward instead
E:SetWeather(type) -- a valid weather string
E:SetWeatherIntensity('light') -- 'light' | 'normal' | 'heavy' (or 0.3 / 0.6 / 0.9)
E:RandomizeEnvironment('all') -- 'all' | 'time' | 'weather'
E:SetTimeRatio(ratio) -- 0.1-100 game minutes per real minute
E:SetTimeLock(bool)
E:SetWeatherLock(bool)
E:SetBlackout(bool)
Failure reasons you can get back: control disabled
(Config.ControlTime / ControlWeather is false), invalid input, or
no change. The lock and blackout setters return false, 'no change' when
the state is already what you asked for - the desired end state is still in
effect.
WarningWrite exports are meant for trusted server-side scripts. Never expose one straight to a client event without your own permission check.
Events
Fired when Config.BroadcastEvents is true. Each event has a server-local
variant (dzr-environment:server:*, handle with AddEventHandler) and a
client broadcast variant (dzr-environment:client:*, handle with
RegisterNetEvent). Payloads are self-sufficient - you never need to call
an export in response.
weatherChanged
{
previous = 'CLEAR',
current = 'RAIN',
intensity = 0.6,
temperature = { fahrenheit = 62, celsius = 17 },
visibility = 'reduced',
surface = 'damp',
wind = 'moderate',
snapshot = { ... }, -- full GetEnvironmentSnapshot shape
}
hourChanged
Fires on a natural hour rollover.
{ previousHour = 13, currentHour = 14, minute = 0,
isDay = true, isNight = false, snapshot = { ... } }
blackoutChanged
{ enabled = true, previous = false }
The automation events (overrideStarted,
overrideEnded, presetApplied, notice, audit) are documented on the
automation page.
GlobalState (read-only)
GlobalState.environment is published to every client and readable on both
sides without an export call:
local env = GlobalState.environment
-- env.hour, env.minute, env.weather, env.intensity, env.rainDuration
-- env.baseTimeRatio -- admin-chosen day-length ratio
-- env.realTimeRatio -- live ratio, temporarily higher during smooth transitions
-- env.lockTime, env.lockWeather
-- env.blackout
-- env.temperature = { fahrenheit, celsius }
-- env.wind
-- env.transition = { nextWeather, weatherRemaining }
Contract: authoritative inputs plus stable convenience-derived values. For exact local behavior you may recompute derived values yourself, but the published ones are kept in sync.
Need help with this? Open a ticket on Discord or read the support guide.