Zones (PolyZones Alternative)

The Zones module provides comprehensive zone management for FiveM resources with support for multiple zone types, advanced collision detection, event handling, and performance optimization.

createPolygon

Creates a polygon zone with complex shape support and 2D collision detection.

B2Lib.Zones.createPolygon(options)

Parameters:

  • options (table): Zone configuration options

    • points (table): Array of vector3 points defining polygon vertices

    • minZ (number, optional): Minimum Z coordinate for zone bounds

    • maxZ (number, optional): Maximum Z coordinate for zone bounds

    • name (string, optional): Custom zone identifier

    • onEnter (function, optional): Callback when player enters zone

    • onExit (function, optional): Callback when player exits zone

    • onInside (function, optional): Callback while player is inside zone

    • data (table, optional): Custom data attached to zone

    • active (boolean, optional): Whether zone is active (default: true)

    • debug (boolean, optional): Enable debug rendering

    • priority (number, optional): Zone priority for processing order

    • tags (table, optional): Array of tags for zone categorization

Returns: string - Unique zone identifier

Example:

local zoneId = B2Lib.Zones.createPolygon({
    points = {
        vector3(100.0, 200.0, 30.0),
        vector3(150.0, 200.0, 30.0),
        vector3(150.0, 250.0, 30.0),
        vector3(100.0, 250.0, 30.0)
    },
    minZ = 25.0,
    maxZ = 35.0,
    name = "parking_lot",
    onEnter = function(playerId, zone)
        print("Player entered parking lot")
    end,
    data = {type = "parking", capacity = 20}
})

createCircle

Creates a circle zone with 2D collision detection and configurable radius.

B2Lib.Zones.createCircle(options)

Parameters:

  • options (table): Zone configuration options

    • center (vector3): Center coordinates of the circle

    • radius (number): Circle radius in units

    • minZ (number, optional): Minimum Z coordinate (default: center.z - 100)

    • maxZ (number, optional): Maximum Z coordinate (default: center.z + 100)

    • name (string, optional): Custom zone identifier

    • onEnter (function, optional): Callback when player enters zone

    • onExit (function, optional): Callback when player exits zone

    • onInside (function, optional): Callback while player is inside zone

    • data (table, optional): Custom data attached to zone

    • active (boolean, optional): Whether zone is active (default: true)

    • debug (boolean, optional): Enable debug rendering

    • priority (number, optional): Zone priority for processing order

    • tags (table, optional): Array of tags for zone categorization

Returns: string - Unique zone identifier

Example:

local zoneId = B2Lib.Zones.createCircle({
    center = vector3(0.0, 0.0, 30.0),
    radius = 50.0,
    name = "spawn_area",
    onEnter = function(playerId, zone)
        TriggerEvent('player:enteredSpawn', playerId)
    end,
    data = {safe = true, pvp = false}
})

createSphere

Creates a sphere zone with 3D collision detection for full spatial coverage.

B2Lib.Zones.createSphere(options)

Parameters:

  • options (table): Zone configuration options

    • center (vector3): Center coordinates of the sphere

    • radius (number): Sphere radius in units

    • name (string, optional): Custom zone identifier

    • onEnter (function, optional): Callback when player enters zone

    • onExit (function, optional): Callback when player exits zone

    • onInside (function, optional): Callback while player is inside zone

    • data (table, optional): Custom data attached to zone

    • active (boolean, optional): Whether zone is active (default: true)

    • debug (boolean, optional): Enable debug rendering

    • priority (number, optional): Zone priority for processing order

    • tags (table, optional): Array of tags for zone categorization

Returns: string - Unique zone identifier

Example:

local zoneId = B2Lib.Zones.createSphere({
    center = vector3(100.0, 200.0, 50.0),
    radius = 25.0,
    name = "interaction_sphere",
    onEnter = function(playerId, zone)
        TriggerClientEvent('ui:showInteraction', playerId, "Press E to interact")
    end
})

createBox

Creates a box zone with optional rotation support and 3D collision detection.

B2Lib.Zones.createBox(options)

Parameters:

  • options (table): Zone configuration options

    • center (vector3): Center coordinates of the box

    • size (vector3): Box dimensions (x, y, z)

    • heading (number, optional): Box rotation in degrees (default: 0)

    • name (string, optional): Custom zone identifier

    • onEnter (function, optional): Callback when player enters zone

    • onExit (function, optional): Callback when player exits zone

    • onInside (function, optional): Callback while player is inside zone

    • data (table, optional): Custom data attached to zone

    • active (boolean, optional): Whether zone is active (default: true)

    • debug (boolean, optional): Enable debug rendering

    • priority (number, optional): Zone priority for processing order

    • tags (table, optional): Array of tags for zone categorization

Returns: string - Unique zone identifier

Example:

local zoneId = B2Lib.Zones.createBox({
    center = vector3(0.0, 0.0, 30.0),
    size = vector3(10.0, 20.0, 5.0),
    heading = 45.0,
    name = "building_entrance",
    onEnter = function(playerId, zone)
        TriggerEvent('building:playerEntered', playerId, zone.data.buildingId)
    end,
    data = {buildingId = 123, restricted = false}
})

isPointInside

Checks if a point is inside a specific zone with optimized collision detection.

B2Lib.Zones.isPointInside(zoneId, point)

Parameters:

  • zoneId (string): Zone identifier to check

  • point (vector3): Point coordinates to test

Returns: boolean - True if point is inside the zone

Example:

local playerPos = GetEntityCoords(PlayerPedId())
local isInside = B2Lib.Zones.isPointInside("spawn_area", playerPos)
if isInside then
    print("Player is in spawn area")
end

getZone

Retrieves zone information by ID with complete zone data.

B2Lib.Zones.getZone(zoneId)

Parameters:

  • zoneId (string): Zone identifier

Returns: table|nil - Zone object or nil if not found

  • id (string): Zone identifier

  • type (string): Zone type (polygon, circle, sphere, box)

  • active (boolean): Whether zone is active

  • data (table): Custom zone data

  • enterCount (number): Number of times zone was entered

  • exitCount (number): Number of times zone was exited

  • lastEnter (number): Timestamp of last entry

  • lastExit (number): Timestamp of last exit

  • createdAt (number): Zone creation timestamp

getAllZones

Retrieves all zones with optional filtering capabilities.

B2Lib.Zones.getAllZones(filterOptions)

Parameters:

  • filterOptions (table, optional): Filtering criteria

    • active (boolean): Filter by active state

    • type (string): Filter by zone type

    • tags (table): Filter by tags

    • hasData (string): Filter zones with specific data key

Returns: table - Array of zone objects

Example:

local activeZones = B2Lib.Zones.getAllZones({active = true})
local parkingZones = B2Lib.Zones.getAllZones({tags = {"parking"}})

remove

Removes a zone from the system with proper cleanup.

B2Lib.Zones.remove(zoneId)

Parameters:

  • zoneId (string): Zone identifier to remove

Returns: boolean - True if zone was successfully removed

Example:

local success = B2Lib.Zones.remove("temporary_zone")
if success then
    print("Zone removed successfully")
end

setActive

Enables or disables a zone without removing it.

B2Lib.Zones.setActive(zoneId, active)

Parameters:

  • zoneId (string): Zone identifier

  • active (boolean): New active state

Returns: boolean - True if zone state was successfully changed

Example:

B2Lib.Zones.setActive("event_zone", false)  -- Disable zone
B2Lib.Zones.setActive("event_zone", true)   -- Re-enable zone

updateData

Updates zone data properties with merge functionality.

B2Lib.Zones.updateData(zoneId, data)

Parameters:

  • zoneId (string): Zone identifier

  • data (table): New data to merge with existing data

Returns: boolean - True if data was successfully updated

Example:

B2Lib.Zones.updateData("shop_zone", {
    discount = 0.15,
    specialOffer = "Black Friday Sale"
})

modifyZone

Modifies zone geometry including position, size, and rotation.

B2Lib.Zones.modifyZone(zoneId, modifications)

Parameters:

  • zoneId (string): Zone identifier

  • modifications (table): Geometry modifications

    • center (vector3): New center position

    • radius (number): New radius (for circles/spheres)

    • size (vector3): New size (for boxes)

    • heading (number): New rotation (for boxes)

    • points (table): New points (for polygons)

    • minZ (number): New minimum Z coordinate

    • maxZ (number): New maximum Z coordinate

Returns: boolean - True if zone was successfully modified

Example:

B2Lib.Zones.modifyZone("dynamic_zone", {
    center = vector3(100.0, 200.0, 30.0),
    radius = 75.0
})

getCurrentZones

Gets zones that the player is currently inside.

B2Lib.Zones.getCurrentZones()

Returns: table - Array of zone IDs the player is currently in

Example:

local currentZones = B2Lib.Zones.getCurrentZones()
for _, zoneId in ipairs(currentZones) do
    print("Player is in zone:", zoneId)
end

getZoneHistory

Gets zone entry/exit history for analysis and debugging.

B2Lib.Zones.getZoneHistory(zoneId, limit)

Parameters:

  • zoneId (string): Zone identifier

  • limit (number, optional): Maximum number of history entries to return

Returns: table - Array of history entries

  • type (string): Event type ("enter" or "exit")

  • timestamp (number): Event timestamp

  • coordinates (vector3): Player coordinates at event time

  • reason (string, optional): Reason for event (e.g., "zone_removed")

Example:

local history = B2Lib.Zones.getZoneHistory("important_zone", 10)
for _, event in ipairs(history) do
    print(string.format("%s at %d: %s", event.type, event.timestamp, event.reason or "normal"))
end

getStats

Gets comprehensive zone system statistics and performance metrics.

B2Lib.Zones.getStats()

Returns: table - Zone system statistics

  • totalZones (number): Total number of zones

  • activeZones (number): Number of active zones

  • currentPlayerZones (number): Zones player is currently in

  • totalEnters (number): Total zone entries

  • totalExits (number): Total zone exits

  • systemStats (table): Performance statistics

    • totalChecks (number): Total zone checks performed

    • averageCheckTime (number): Average check time in milliseconds

    • lastCheckTime (number): Last check time in milliseconds

  • config (table): Current system configuration

startChecking

Starts the zone checking system for automatic zone monitoring.

B2Lib.Zones.startChecking()

Example:

B2Lib.Zones.startChecking()
print("Zone monitoring started")

stopChecking

Stops the zone checking system to pause monitoring.

B2Lib.Zones.stopChecking()

Example:

B2Lib.Zones.stopChecking()
print("Zone monitoring stopped")

setCheckInterval

Sets the zone check interval for performance optimization.

B2Lib.Zones.setCheckInterval(interval)

Parameters:

  • interval (number): Interval in milliseconds (minimum 50ms)

Example:

B2Lib.Zones.setCheckInterval(100)  -- Check every 100ms for better performance

getCheckInterval

Gets the current zone check interval.

B2Lib.Zones.getCheckInterval()

Returns: number - Current interval in milliseconds

setDebug

Enables or disables debug rendering for a specific zone.

B2Lib.Zones.setDebug(zoneId, enabled)

Parameters:

  • zoneId (string): Zone identifier

  • enabled (boolean): Debug rendering state

Example:

B2Lib.Zones.setDebug("test_zone", true)   -- Enable debug rendering
B2Lib.Zones.setDebug("test_zone", false)  -- Disable debug rendering

updateConfig

Updates zone system configuration with new settings.

B2Lib.Zones.updateConfig(newConfig)

Parameters:

  • newConfig (table): Configuration options to update

Example:

B2Lib.Zones.updateConfig({
    checkInterval = 100,
    enableDebug = true,
    maxZones = 1000
})

Configuration

Configure the zones system in config.lua:

Config.Zones = {
    checkInterval = 250,            -- Milliseconds between zone checks
    maxZones = 500,                -- Maximum number of zones
    enableDebug = false,           -- Debug logging
    enableVisualization = false,   -- Debug rendering
    optimizeChecks = true,         -- Use spatial optimization
    trackHistory = true,           -- Track zone entry/exit history
    maxHistoryEntries = 100        -- Maximum history entries per zone
}

Advanced Examples

Multi-Zone Event System

-- Create interconnected zones for a complex event
local eventZones = {}

-- Main event area
eventZones.main = B2Lib.Zones.createCircle({
    center = vector3(0.0, 0.0, 30.0),
    radius = 100.0,
    name = "event_main",
    onEnter = function(playerId, zone)
        TriggerClientEvent('event:welcome', playerId)
        B2Lib.UI.notify(playerId, "Welcome to the event!", "success")
    end,
    data = {eventId = 1, type = "main"}
})

-- VIP area within main event
eventZones.vip = B2Lib.Zones.createBox({
    center = vector3(0.0, 0.0, 30.0),
    size = vector3(20.0, 20.0, 10.0),
    name = "event_vip",
    onEnter = function(playerId, zone)
        if hasVipAccess(playerId) then
            TriggerClientEvent('event:vipAccess', playerId)
        else
            TriggerClientEvent('event:accessDenied', playerId)
        end
    end,
    data = {eventId = 1, type = "vip", restricted = true}
})

-- Stage area
eventZones.stage = B2Lib.Zones.createPolygon({
    points = {
        vector3(-10.0, 40.0, 30.0),
        vector3(10.0, 40.0, 30.0),
        vector3(10.0, 50.0, 30.0),
        vector3(-10.0, 50.0, 30.0)
    },
    name = "event_stage",
    onEnter = function(playerId, zone)
        if isPerformer(playerId) then
            TriggerClientEvent('event:stageAccess', playerId)
        end
    end,
    data = {eventId = 1, type = "stage", performersOnly = true}
})

Dynamic Zone Management

-- Create zones that change based on game state
local function createDynamicZones()
    local timeOfDay = GetClockHours()
    
    if timeOfDay >= 22 or timeOfDay <= 6 then
        -- Night time - create restricted zones
        B2Lib.Zones.createCircle({
            center = vector3(100.0, 200.0, 30.0),
            radius = 50.0,
            name = "night_restricted",
            onEnter = function(playerId, zone)
                if not hasNightPermission(playerId) then
                    TriggerClientEvent('police:trespassing', playerId)
                end
            end,
            data = {timeRestricted = true, activeHours = "22:00-06:00"}
        })
    else
        -- Day time - remove night restrictions
        B2Lib.Zones.remove("night_restricted")
    end
end

-- Update zones every hour
CreateThread(function()
    while true do
        createDynamicZones()
        Wait(3600000) -- 1 hour
    end
end)

Zone-Based Gameplay Systems

-- Territory control system
local territories = {}

local function createTerritory(name, center, radius, faction)
    local zoneId = B2Lib.Zones.createCircle({
        center = center,
        radius = radius,
        name = name,
        onEnter = function(playerId, zone)
            local playerFaction = getPlayerFaction(playerId)
            if playerFaction == zone.data.controlledBy then
                TriggerClientEvent('territory:friendly', playerId, zone.data)
            else
                TriggerClientEvent('territory:hostile', playerId, zone.data)
            end
        end,
        onInside = function(playerId, zone)
            -- Award territory points while inside
            if getPlayerFaction(playerId) == zone.data.controlledBy then
                awardTerritoryPoints(playerId, 1)
            end
        end,
        data = {
            controlledBy = faction,
            contestable = true,
            points = 0
        }
    })
    
    territories[name] = zoneId
    return zoneId
end

-- Create multiple territories
createTerritory("north_district", vector3(100.0, 500.0, 30.0), 75.0, "gang_a")
createTerritory("south_district", vector3(100.0, -500.0, 30.0), 75.0, "gang_b")
createTerritory("central_plaza", vector3(0.0, 0.0, 30.0), 50.0, "neutral")

Troubleshooting

Zones Not Triggering

  1. Check that zone checking system is started with startChecking()

  2. Verify zone is active with getZone() and check active property

  3. Ensure callback functions don't throw errors

  4. Check zone coordinates and player position are valid

Performance Issues

  1. Reduce check interval with setCheckInterval() for better performance

  2. Limit number of active zones (use setActive() to disable unused zones)

  3. Use appropriate zone types (circles are faster than polygons)

  4. Enable spatial optimization in configuration

Zone Overlap Problems

  1. Use zone priorities to control processing order

  2. Check getCurrentZones() to see all active zones

  3. Design zones to minimize unnecessary overlaps

  4. Use zone tags for better organization

Memory Leaks

  1. Always remove zones when no longer needed

  2. Limit zone history with maxHistoryEntries configuration

  3. Monitor statistics with getStats() for memory usage

  4. Clean up event handlers in zone callbacks

Debug and Visualization

  1. Enable debug mode in configuration for detailed logging

  2. Use setDebug() for individual zone visualization

  3. Check zone history with getZoneHistory() for event tracking

  4. Monitor performance with statistics from getStats()

Last updated