Developer

9 min readUpdated Today

Overview

Server and client exports plus open event hooks for integrating with ML HealthSystem. The integration surface lives in the open/ folder: open/server/handlers.lua, open/client/handlers.lua, and the radiation_connector.lua files. These are escrow-ignored (plain source) and can be edited without touching the core system.

Live medical state (death state, diseases, injuries, life points) replicates to clients in real time. Persistence uses three database tables: ml_healthsystem (per-identifier JSON health blob), ml_lifepoints (life points), ml_health_tents (placed respawn tents). All three are created automatically on first start.

Event toggles

The death, last stand, and respawn events only fire when enabled in shared/config/open.lua (Config.OpenHandlers). All three default to true.

Server Exports

Disease Management

lua
1exports.ml_healthsystem:AddDisease(source, diseaseName)
  • AddDisease(source, diseaseName): Infects a player with a disease defined in Config.Diseases. Returns true on success, false if the disease key does not exist or is already active.
lua
1exports.ml_healthsystem:CureDiseaseForce(source, diseaseName)
  • CureDiseaseForce(source, diseaseName): Force-cures a specific disease, bypassing maxCurableStage checks. Returns true if cured.
lua
1exports.ml_healthsystem:CureAllDiseases(source)
  • CureAllDiseases(source): Removes all active diseases from a player.
Disease keys

Pass the disease key, not the label. The six shipped defaults are influenza, patogeno_vx_9, radiazioni, infezione, intossicazione, tetano (defined in shared/config/diseases.lua). Keys change if the list is edited.

Revive and Death

lua
1exports.ml_healthsystem:RevivePlayer(source)
  • RevivePlayer(source): Fully revives a player and resets medical stats. Returns true on success.
lua
1exports.ml_healthsystem:SetDeathSystemDisabled(source, isDisabled)
  • SetDeathSystemDisabled(source, isDisabled): Disables or re-enables the death system for one player. Use for cutscenes or safe zones.
lua
1exports.ml_healthsystem:SetDeathReason(source, reason)
  • SetDeathReason(source, reason): Sets a custom death reason string (max 64 chars) consumed on the player's next death. The reason feeds Config.LifePoints.ExternalReasons penalty matching. Calls from outside the resource are gated to an allowlist (ml_radiation, ml_climaticvitals); foreign resources are rejected.

Field Treatment

lua
1exports.ml_healthsystem:ApplyTempBandage(source)
  • ApplyTempBandage(source, duration, previousBleedLevel): Applies a temporary bandage that stops bleeding for duration seconds, then restores the previous bleed level.
lua
1exports.ml_healthsystem:AddBloodRegenBuff(source)
  • AddBloodRegenBuff(source, durationSeconds): Applies a blood regeneration boost.

Life Points

Life points only respond when Config.LifePoints.Enabled = true (server/config_server.lua). When disabled, the getters return -1 and the mutators return false.

lua
1exports.ml_healthsystem:GetLifePoints(source)
  • GetLifePoints(source): Returns the player's current life points (reads/creates the ml_lifepoints row). Returns -1 if the system is disabled.
lua
1exports.ml_healthsystem:GetLifePointsMax(source)
  • GetLifePointsMax(): Returns the maximum (Config.LifePoints.StartingPoints). Returns -1 if disabled.
lua
1exports.ml_healthsystem:IsLifePointsEnabled()
  • IsLifePointsEnabled(): Returns true if the life points system is active.
lua
1exports.ml_healthsystem:SetLifePoints(source, value)
  • SetLifePoints(source, value): Sets a player's life points to an exact value, clamped to [MinPoints, StartingPoints]. Returns true on success.
lua
1exports.ml_healthsystem:AddLifePoints(source, amount)
  • AddLifePoints(source, amount): Adds life points (clamped to max). Returns true on success.
lua
1exports.ml_healthsystem:RemoveLifePoints(source, amount)
  • RemoveLifePoints(source, amount): Removes life points (clamped to min). Returns true on success.
Mutator allowlist

SetLifePoints, AddLifePoints, and RemoveLifePoints are gated by CanMutateLifePoints. Internal calls pass. External resources pass only if listed in Config.LifePoints.ExportAllowlist; if that list is empty, a non-staff player context is blocked. Add the calling resource to the allowlist before relying on these from another script.

Spawn Points and Tents

lua
1exports.ml_healthsystem:GetSpawnPoints()
  • GetSpawnPoints(): Returns the configured spawn table (Config.StartSpawn from shared/config/respawn.lua).
lua
1exports.ml_healthsystem:GetTentCoordsById(tentId)
  • GetTentCoordsById(tentId): Returns x, y, z, heading, owner for a placed tent from ml_health_tents.

Buffs

lua
1exports.ml_healthsystem:GetActiveBuffs(source)
  • GetActiveBuffs(source): Returns the active temporary buffs (regen boosts, temp bandages) for a player.

Client Exports

Disease Management

lua
1exports.ml_healthsystem:HasDisease(diseaseName)
  • HasDisease(diseaseName): Returns true if the local player has the disease (reads the medical:diseases live state).
lua
1exports.ml_healthsystem:GetActiveDiseases()
  • GetActiveDiseases(): Returns the table of active diseases on the local player.
lua
1exports.ml_healthsystem:AddDisease(diseaseName)
  • AddDisease(diseaseName): Requests the server to infect the local player.
Server-side infect and revive

The client AddDisease and Revive exports are staff-only. To infect or revive a player from a server resource, call exports.ml_healthsystem:AddDisease(src, name) and exports.ml_healthsystem:RevivePlayer(src). Curing is handled by the cure item.

Death and Revive

lua
1exports.ml_healthsystem:isDead()
  • isDead(): Returns true if the local player is dead or in last stand.
lua
1exports.ml_healthsystem:Revive()
  • Revive(): Requests a self-revive from the server (staff-gated server-side).
lua
1exports.ml_healthsystem:SetDeathDisabled(disabled)
  • SetDeathDisabled(disabled): Sets the local disableDeathSystem live state.

System State

lua
1exports.ml_healthsystem:isSystemReady()
  • isSystemReady(): Returns true once the medical system has initialized.

Damage and Combat

lua
1exports.ml_healthsystem:GetLastDamageData()
  • GetLastDamageData(): Returns the last damage context: weaponHash, weaponClass, attackerId, bodyPart, attackerModel, timestamp. weaponClass defaults to 'UNKNOWN' and bodyPart to 'chest' when no context exists.
lua
1exports.ml_healthsystem:BuildDeathData()
  • BuildDeathData(): Builds a death object from the last damage event: weaponHash, weaponClass, attackerId, isPlayerKill, bodyPart, cause, timestamp. cause is derived from weaponClass (gunshot, explosion, stabbing, fall, burn, etc.).
lua
1exports.ml_healthsystem:ApplyWound(part, amount, weaponClass)
  • ApplyWound(part?, amount?, weaponClass?): applies a body-part wound to the calling player through the full damage pipeline, so bleeding, severity and the scan panel all react. part is a body zone like 'left_leg', or 'random' to pick one. amount defaults to 15, weaponClass overrides the wound type. Returns true when a wound landed. Call it on the victim's client from an external damage source such as a zombie script.

Life Points (Client)

lua
1exports.ml_healthsystem:GetLifePoints()
  • GetLifePoints(): Returns the local player's life points from the lifepoints live state. Returns -1 if disabled.
lua
1exports.ml_healthsystem:GetLifePointsMax()
  • GetLifePointsMax(): Returns Config.LifePoints.StartingPoints. Returns -1 if disabled.
lua
1exports.ml_healthsystem:IsLifePointsEnabled()
  • IsLifePointsEnabled(): Returns true if the life points system is active.

Tent (Client)

lua
1exports.ml_healthsystem:GetPlayerTentClient()
  • GetPlayerTentClient(): Returns the local player's tracked tent data on the client.

Server Handlers

Located in open/server/handlers.lua. The death and respawn events fire only when the matching Config.OpenHandlers toggle is enabled in shared/config/open.lua.

Death Handler

open/server/handlers.lua
1RegisterNetEvent('ml_healthsystem:server:onPlayerDeath', function(_clientData)
2    if GetInvokingResource() then return end
3    local src = source
4    -- deathData rebuilt server-side, NOT taken from _clientData
5end)
Server-authoritative payload

The original client payload is discarded. deathData is rebuilt from PlayerDeathContext (populated server-side with strict validation) plus the deathState live state. Fields weaponHash, weaponClass, bodyPart, isPlayerKill, attackerId, attackerModel, deathReason, deathZone, cause, and coords are all server-validated and safe for authoritative actions (permadeath, money, database logging). The event is rate-limited and rejects foreign-resource triggers.

Respawn Handler

open/server/handlers.lua
1RegisterNetEvent('ml_healthsystem:server:onPlayerRespawned', function(_clientCoords, _clientSpawnType)
2    if GetInvokingResource() then return end
3    local src = source
4    -- spawnType is whitelisted; coords recalculated from the server ped
5end)

spawnType is validated against hospital, bed, tent, random, last_position (anything else becomes 'unknown'). Coordinates are recomputed server-side from GetEntityCoords(GetPlayerPed(src)), so the client-sent coords cannot teleport-spoof.

Hunger/Thirst Reset

open/server/handlers.lua
1RegisterNetEvent('ml_healthsystem:server:ResetHungerThirst', function()
2    -- Uses Bridge.SetHunger, Bridge.SetThirst, Bridge.RemoveStress
3end)

Fired automatically on revive. Permission is granted one-time per revive cycle (reviveResetAllowed) with a 5-second cooldown, and only applies while deathState == 'alive'. Uses the ml_bridge API for cross-framework compatibility.

Item-to-Disease Wiring

open/server/handlers.lua also listens to ox_inventory:usedItem and rolls the infection chance defined in shared/config/item_diseases.lua (Config.ItemDiseases). Add a "this food makes you sick" entry there; no handler edits needed. Downed and dead players are skipped.

Client Handlers

Located in open/client/handlers.lua.

Death Event

open/client/handlers.lua
1AddEventHandler('ml_healthsystem:onPlayerDeath', function(deathData)
2    -- Fires when the local player dies (if Config.OpenHandlers.EnableDeathEvent)
3end)

Last Stand Event

open/client/handlers.lua
1AddEventHandler('ml_healthsystem:onPlayerLastStand', function(damageData)
2    -- Fires when the local player enters last stand (if EnableLastStandEvent)
3end)

The radiation bridge lives in open/client/radiation_connector.lua and open/server/radiation_connector.lua; both early-return unless Config.RadiationIntegration.Enabled and ml_radiation are present. The client connector is passive (debug logging only); all infect/cure logic is server-side.

Configuration

The configuration is split by domain across shared/config/*.lua plus server/config_server.lua. The shared/config.lua file is only the index header; the real values live in the per-domain files below.

  • core.lua: Config.Debug, Config.Locale, Config.Theme, Config.DisableHealthRegen
  • vitals.lua: blood, bandages, armor, wound levels, blood trails, cast duration
  • bodyparts.lua: the nine body parts (armor, fracture, cast)
  • diseases.lua: diseases and stages (customer-editable)
  • items.lua: Config.MedicalItems (customer-editable) and Config.XpCooldownSeconds
  • anim_presets.lua: animation presets reused by items
  • masks.lua: protective masks (customer-editable)
  • fractures.lua: fracture model wiring
  • weapons.lua: weapon-class wound profiles, weapon→class map, body-part health thresholds
  • respawn.lua: Config.RespawnSettings, Config.StartSpawn, Config.HrsBase, Config.RespawnTent
  • lifecycle.lua: last stand and death tuning
  • effects.lua: visual effects, voice, Config.Flare, vehicle crash, NPC interaction
  • ui.lua: scan UI, medical jobs, commands
  • integrations.lua: radiation integration, contact infection, and Config.LifePoints.Zones
  • item_diseases.lua: Config.ItemDiseases (food/item → disease wiring)
  • security.lua: Config.AntiBunnyHop
  • open.lua: Config.OpenHandlers event toggles
  • server/config_server.lua: server-only settings: Discord logging, Config.LifePoints (enabled, penalties, allowlist), inventory wipe, revive/hospital reset

Diseases, items, and masks are shipped as defaults and are fully customer-editable: add, remove, or modify entries in their config file freely. The escrowed internal/balance/*.lua files (performance throttles, damage control, blood-group probabilities, weapon penalties, anti-bunny-hop sensitivity presets, body-part balance) are encrypted and cannot be edited; the customer-facing anti-bunny-hop knob is in security.lua:

shared/config/security.lua
1Config.AntiBunnyHop = {
2    Enabled     = true,
3    Sensitivity = 'medium', -- 'low' | 'medium' | 'high' | 'extreme'
4    Notify      = true,
5    Message     = "Slow down! Don't jump so often.",
6}
  • Enabled: master switch for the anti-bunny-hop ragdoll.
  • Sensitivity: selects an escrowed preset: low (extreme hops only), medium (recommended), high (aggressive), extreme (ragdoll almost always).
  • Notify: show a notification when a hop is blocked.
  • Message: notification text.

Examples

open/server/handlers.lua
1RegisterNetEvent('ml_healthsystem:server:onPlayerRespawned', function(_clientCoords, spawnType)
2    if GetInvokingResource() then return end
3    local src = source
4    if spawnType == 'hospital' then
5        Bridge.RemoveMoney(src, 'bank', 500)
6    end
7end)
open/server/handlers.lua
1RegisterNetEvent('ml_healthsystem:server:onPlayerDeath', function()
2    if GetInvokingResource() then return end
3    local src = source
4    -- deathData is rebuilt server-side; read it from PlayerDeathContext or
5    -- log straight from the validated fields the handler already computes.
6    MySQL.insert('INSERT INTO death_logs (identifier, cause, killer) VALUES (?, ?, ?)', {
7        Bridge.GetLicense(src),
8        PlayerDeathContext[src] and PlayerDeathContext[src].deathReason or 'unknown',
9        PlayerDeathContext[src] and PlayerDeathContext[src].attackerServerId or 'environment'
10    })
11end)
lua
1-- Server side (authoritative): block safe-zone entry while infected
2if exports.ml_healthsystem:HasDisease and exports.ml_healthsystem:GetActiveDiseases then
3    -- prefer the server disease state; HasDisease here reads the player's diseases
4end
5
6-- Client side: show a cough notification for the local player
7if exports.ml_healthsystem:HasDisease('influenza') then
8    -- ...
9end
open/server/handlers.lua
1RegisterNetEvent('ml_healthsystem:server:onPlayerDeath', function()
2    if GetInvokingResource() then return end
3    local src = source
4    local ctx = PlayerDeathContext[src]
5    if ctx and ctx.killedByPlayer then
6        -- Add this resource to Config.LifePoints.ExportAllowlist first.
7        exports.ml_healthsystem:RemoveLifePoints(src, 15)
8    end
9end)

The respawn flow already applies a life-point penalty internally via CalculatePenalty (highest-matching zone / external reason / NPC+weapon / player-kill / weapon penalty wins, no stacking). Use the export above only for extra, custom deductions.