Developer

3 min readUpdated 2 weeks ago

Overview

Other resources read camps through three server exports and the GlobalState snapshot of each camp. Permissions, loot and camp events are changed in open/handlers_server.lua and open/handlers_client.lua, which stay unencrypted.

Server Exports

lua
1local status = exports.ml_camps:GetCampStatus('bandit_grapeseed')
2local cleared = exports.ml_camps:IsCampCleared('bandit_grapeseed')
3local alive = exports.ml_camps:GetCampAliveCount('bandit_grapeseed')
  • GetCampStatus(campId): 'idle', 'active', 'combat', 'cleared', 'cooldown' or 'depleted'. nil for an unknown camp
  • IsCampCleared(campId): true while the camp is 'cleared' or 'cooldown'. A spawn-once camp reports 'depleted', so check it with GetCampStatus
  • GetCampAliveCount(campId): enemies still alive

GlobalState

Each camp publishes a live snapshot under mlcamp_<campId>, readable on server and client:

lua
1local snap = GlobalState['mlcamp_bandit_grapeseed']
  • status: same values as GetCampStatus
  • alive, total: enemies alive and enemies spawned
  • nextRespawn: unix time when the cooldown ends, 0 otherwise
  • wave, waves: current wave and total waves of a horde camp

The HUD settings are published under mlcampcfg as { enabled, position, resetVisibilityDefault }.

Entity State

Camp NPCs carry these keys on their entity state:

  • mlCampPed: true on every camp NPC
  • mlCampId: ID of the camp the NPC belongs to
  • mlCampZombie: set on NPCs of a zombie group
  • mlCampNoRagdoll, mlCampNoCrit: set when the group has ragdoll or headshot kills turned off

Server Handlers

Located in open/handlers_server.lua.

open/handlers_server.lua
1Handlers.HasCreatorPermission = function(source)
2    return checkPermissionTier(source, Config.Permissions.Creator)
3end
4
5Handlers.HasLivePermission = function(source)
6    return checkPermissionTier(source, Config.Permissions.LiveActions)
7end
8
9Handlers.OnCampActivated = function(campId, campData)
10end
11
12Handlers.OnCampWave = function(campId, campData, wave, totalWaves)
13end
14
15Handlers.OnCampCleared = function(campId, campData, raiders)
16end
17
18Handlers.ModifyLoot = function(campId, items, money)
19    return items, money
20end
  • HasCreatorPermission, HasLivePermission: the two staff tiers. The shipped version reads Config.Permissions through ml_bridge. Replace them to use your own permission system
  • OnCampActivated: a camp spawns its NPCs
  • OnCampWave: a new wave of a horde camp spawns
  • OnCampCleared: the last enemy dies. raiders lists the credited player IDs in the order they entered
  • ModifyLoot: runs on each raider's roll for direct delivery, and once on the shared pool for crates. Return the items list as { name, count, metadata? } and money as { account, amount } or nil

Client Handlers

Located in open/handlers_client.lua.

open/handlers_client.lua
1Handlers.CanShowCampBlip = function(campId, campData)
2    return true
3end
4
5Handlers.IsPlayerDead = function()
6    return Bridge.IsPlayerDead() or IsPedDeadOrDying(cache.ped, true)
7end
8
9Handlers.OnCampEntered = function(campId, campData)
10end
11
12Handlers.OnEnemyPedReady = function(ped, weaponHash)
13end
  • CanShowCampBlip: return false to hide a camp blip for the local player
  • IsPlayerDead: camp NPCs stop targeting a player for whom this returns true. Change it if your death script uses its own state
  • OnCampEntered: the local player walks into a camp
  • OnEnemyPedReady: a camp NPC is set up and armed. Apply your own weapon damage rules to camp enemies here

Examples

open/handlers_server.lua
1Handlers.OnCampCleared = function(campId, campData, raiders)
2    for _, src in ipairs(raiders) do
3        Bridge.GiveItem(src, 'water', 1)
4    end
5end
open/handlers_server.lua
1Handlers.ModifyLoot = function(campId, items, money)
2    local camp = Config.Camps[campId]
3    if camp and camp.type == 'military' and money then
4        money.amount = math.floor(money.amount * 1.5)
5    end
6    return items, money
7end
your_script/server.lua
1RegisterNetEvent('myscript:enterBunker', function()
2    local src = source
3    if not exports.ml_camps:IsCampCleared('military_zancudo') then
4        Bridge.NotifyPlayer(src, 'error', 'Clear the outpost first.')
5        return
6    end
7end)
your_script/client.lua
1AddStateBagChangeHandler(nil, 'global', function(_, key, value)
2    if type(key) ~= 'string' or key:sub(1, 7) ~= 'mlcamp_' then return end
3    if value and (value.status == 'cooldown' or value.status == 'depleted') then
4        print(('camp %s cleared'):format(key:sub(8)))
5    end
6end)
your_script/client.lua
1for _, ped in ipairs(GetGamePool('CPed')) do
2    if ped ~= cache.ped and not Entity(ped).state.mlCampPed then
3        print(ped)
4    end
5end
Camps Developer, FiveM Docs | Micio Mods