ZerØ Network

Technical Developer Documentation — ZerØ Rent

Version: 1.0.1 | Author: ZerØ Network | Frameworks: QBCore, Qbox, ESX Legacy, Standalone
CPU Resmon: 0.00 ms | Storage Engine: Dual-JSON WAL (Zero SQL Dependencies)


1. Design Philosophy & Architecture

ZerØ Rent was engineered upon three core technical pillars:

  1. Total Independence (100% Standalone): Completely free from proprietary dependencies (no zero_os, no mandatory MySQL/MariaDB database). Works directly on any OneSync-enabled FiveM server.
  2. Adaptive efficiency: NPC streaming uses the configurable SleepFarMs interval (1500 ms by default). Per-frame input checks only run next to a rental point or while the 3D editor is active. The measurable idle target is 0.00 ms.
  3. Transactional Persistence (Write-Ahead Logging - WAL): Data is saved in atomic JSON file pairs (catalog.json and rentals.json alongside their .backup.json twins). Any financial transaction registers in the WAL journal first; only once disk persistence is confirmed is the vehicle spawned, preventing money duplicates or ghost vehicles upon unexpected server crashes.

2. Project Directory Structure

zero_rent/
├── fxmanifest.lua               # FiveM Manifest (Cerulean, OneSync, Lua 5.4)
├── shared/
│   ├── config.lua               # Global configuration file
│   ├── config_locales.lua       # Bilingual server language strings (ES / EN)
│   └── schema.lua               # JSON schema validators and type guards
├── bridge/
│   ├── client.lua               # Client bridge: textUI, targets, notifications & garage locks
│   └── server.lua               # Server bridge: frameworks (QBCore, Qbox, ESX), keys & banking
├── server/
│   ├── store.lua                # Transactional JSON storage engine (WAL)
│   ├── rentals.lua              # Rental state logic, sequential spawn clearance & ticks
│   ├── version.lua              # Protected ZerØ Network version checker and console banner
│   └── server.lua               # RPC events, vehicle lifecycle & statebags
├── client/
│   ├── editor.lua               # 3D Ghost Editor: free cam, raycasting, rotation & previews
│   └── client.lua               # Client logic: NUI menus, 0.00ms streaming, HUD & safe spawning
├── html/
│   ├── index.html               # NUI user interface and admin studio
│   ├── style.css                # Responsive Glassmorphic stylesheets & keyframe animations
│   ├── app.js                   # Client-side UI application controller
│   ├── locales.js               # Interactive bilingual dictionary (ES / EN)
│   └── assets/                  # Local Lucide icon assets and brand logo
├── readme/
│   ├── Documentacion_ES.md      # Technical documentation in Spanish
│   ├── Documentation_EN.md      # Technical documentation in English
│   ├── Instrucciones_ES.md      # User and installation manual in Spanish
│   └── Instructions_EN.md      # User and installation manual in English
└── data/                        # Persistent storage folder (automatically created)
    ├── catalog.json             # Rental points, vehicles, coordinates, and blips
    ├── catalog.backup.json      # Automatic backup of the catalog
    ├── rentals.json             # Active contracts, transactions, and debt ledgers
    └── rentals.backup.json      # Automatic backup of the financial ledger

3. Complete Configuration Reference (shared/config.lua)

Every configuration block in shared/config.lua is categorized:

3.1. Language and Framework

Config.Locale = 'EN' -- Default language: 'EN' (English) or 'ES' (Spanish)
Config.Framework = 'auto' -- 'auto', 'qbcore', 'qbox', or 'esx'
Config.FrameworkResources = {
    qbcore = 'qb-core',
    qbox = 'qbx_core',
    esx = 'es_extended'
}

3.2. Interaction and TextUI

Config.Interaction = {
    Mode = 'E',             -- 'E' (Proximity), 'qb-target', or 'ox_target'
    Distance = 2.0,         -- Interaction distance in meters to NPC
    StreamDistance = 90.0,  -- Stream distance to spawn local shopkeeper ped
    TextUI = 'auto',        -- 'auto', 'zero_notify', 'ox_lib', 'qb-core', 'esx', or 'native'
    TargetIcon = 'fas fa-car',
    OxIcon = 'fa-solid fa-car'
}

3.3. Modular Vehicle Key System

Controls which vehicle keys system handles locking, ignition, and key grants:

Config.Keys = {
    System = 'auto', -- Options available:
                     -- 'auto'             (Automatically detects started resource)
                     -- 'qbx_vehiclekeys'  (Qbox)
                     -- 'qb-vehiclekeys'   (QBCore)
                     -- 'qs-vehiclekeys'   (Quasar)
                     -- 'wasabi_carlock'   (Wasabi)
                     -- 'cd_garage'        (Codesign)
                     -- 'custom'           (Calls open hooks in bridge/server.lua)
                     -- 'none'             (Native GTA engine/doors control)
}

3.4. Universal Garage Blocker

Prevents players from stashing rental vehicles into persistent personal garages:

Config.Garages = {
    System = 'auto', -- 'auto' or 'custom'
    BlockSave = true -- Client and server-side preventative blocker
}

3.5. Modular Notification System

Config.Notify = {
    System = 'auto', -- 'auto', 'zero_notify', 'ox_lib', 'okokNotify', 'mythic_notify',
                     -- 'wasabi_notify', 'qbox', 'qbcore', 'esx', 'custom'
    Duration = 7000  -- Notification duration in milliseconds
}

3.6. Modular Fuel System (Config.Fuel)

Ensures every rented vehicle spawns with a full tank (100%) and offers seamless compatibility with modern FiveM fuel resources without overlapping:

Config.Fuel = {
    System = 'auto', -- 'auto', 'ox_fuel', 'LegacyFuel', 'cdn-fuel', 'ps-fuel',
                     -- 'rcore_fuel', 'ti_fuel', 'okokGasStation', 'myFuel', 'native', 'custom'
    Level = 100.0,   -- Guaranteed fuel level upon spawn (100% full tank)
    StateBag = true  -- Synchronize network StateBag (.state.fuel) for modern HUDs and Qbox
}

Hooks Bridge.SetFuel(vehicle, amount) and Bridge.CustomSetFuel(vehicle, amount) are available in bridge/client.lua and bridge/server.lua for custom or private fuel systems.

3.7. Rental Policies and Durations

Config.Rental = {
    Minutes = { 15, 30, 60, 120 },     -- Allowed lease durations
    MaxPerCharacter = 3,               -- Maximum simultaneous rentals per character
    RefundPercent = 20,                -- Early return refund percentage (20%)
    DestroyedPenaltyPercent = 30,      -- Penalty percentage if vehicle is destroyed (30%)
    PostExpiryDeleteMinutes = 5,       -- Grace minutes after expiry before entity cleanup
    DisconnectGraceMinutes = 20,       -- Grace minutes to reconnect if player leaves server
    PlatePrefix = 'ZR',                -- License plate prefix (e.g., ZR000042)
    AutoRepairOnRenew = true,          -- Automatically repair and clean vehicle on renewal
    MaxPayment = 5000000,              -- Sanity maximum payment limit
}

3.7. Color Palette (Config.Colors)

Predefined colors with RGB values, hex codes, and GTA V engine color indices:

Config.Colors = {
    white  = { label = 'White',   r = 255, g = 255, b = 255, primary = 111, secondary = 111, hex = '#FFFFFF' },
    black  = { label = 'Black',   r = 15,  g = 15,  b = 15,  primary = 0,   secondary = 0,   hex = '#0F0F0F' },
    red    = { label = 'Red',     r = 200, g = 20,  b = 20,  primary = 27,  secondary = 27,  hex = '#C81414' },
    blue   = { label = 'Blue',    r = 20,  g = 80,  b = 200, primary = 64,  secondary = 64,  hex = '#1450C8' },
    purple = { label = 'Purple',  r = 120, g = 30,  b = 180, primary = 145, secondary = 145, hex = '#781EB4' },
    -- ...
}

4. Open Bridge Architecture (bridge/)

To allow developers to easily integrate custom scripts without touching internal code, zero_rent exposes open hooks in bridge/:

4.1. Connecting a Custom Vehicle Keys System

  1. In shared/config.lua, set:
    Config.Keys.System = 'custom'
    
  2. Open bridge/server.lua and add your calls:
    function Bridge.CustomGiveKeys(source, entity, contract)
        -- EXAMPLE: Give keys in your custom keys resource
        exports['my_keys_script']:GiveKey(source, contract.plate)
        -- Or via client event:
        -- TriggerClientEvent('my_keys_script:give', source, contract.plate)
    end
    
    function Bridge.CustomRemoveKeys(source, entity, contract)
        -- EXAMPLE: Remove keys in your custom keys resource
        exports['my_keys_script']:RemoveKey(source, contract.plate)
    end
    

4.2. Connecting a Custom Garage System

If your server uses a custom garage that does not inspect StateBags automatically:

  1. In your garage resource, add a check against the public export:
    -- Inside your garage deposit/store function:
    if exports['zero_rent']:IsRentalVehicle(vehicle) then
        TriggerEvent('chat:addMessage', { args = { '^1ERROR', 'Rental vehicles cannot be stored in personal garages.' } })
        return false
    end
    
  2. Or set Config.Garages.System = 'custom' and adjust the hook in bridge/client.lua:
    function B.CustomCanStoreVehicle(vehicle)
        local s = Entity(vehicle).state
        if s and (s.zeroRent ~= nil or s.isRental == true) then
            return false
        end
        return true
    end
    

4.3. Connecting Custom Notifications

  1. In shared/config.lua, set:
    Config.Notify.System = 'custom'
    
  2. In bridge/client.lua:
    function B.CustomNotify(text, kind, duration)
        -- EXAMPLE:
        exports['my_notify']:SendAlert({
            type = kind, -- 'info', 'success', 'error', 'warning'
            message = text,
            time = duration
        })
    end
    

5. Sequential Spawn Clearance Engine (server/rentals.lua)

The function E.FreeSpace(point, category, bucket, rentingSource) delivers precise, mathematically isolated parking bay clearance:

5.1. Effective Horizontal Clearance Radii

Standard GTA V parking bays range between 2.2m and 2.5m in width. Older spherical 3D checks of 4.0m caused false-positive blockages across 2-3 adjacent bays. The clearance engine calculates strictly in the horizontal 2D (XY) plane with vertical Z limits:

  • Cars (car): Effective radius 1.40 m (Vertical Z tolerance: 3.0 m).
  • Motorcycles & Bicycles (motorcycle, bicycle): Effective radius 1.00 m.
  • Boats (boat): Effective radius 3.50 m (or custom configured spawn radius).
  • Aircraft (aircraft): Effective radius 7.50 m (or custom configured spawn radius).

5.2. Intelligent Entity Exclusions

  • Shopkeeper NPC: Automatically excluded so the desk ped never blocks adjacent parking bays.
  • Renting Customer: The client player's ped is explicitly excluded so proximity to the counter does not register as an obstacle.
  • Pedestrians: Only block a bay if standing directly in the center of the parking space ($< 0.85\text{ m}$).

5.3. Strict Sequential Order (1 through N)

Parking bays are evaluated sequentially according to their index in the point:

  • If bays 1, 2, and 3 are occupied, the system allocates bay 4.
  • As soon as bay 1 is cleared, the system reprioritizes bay 1 for the next customer.

6. Safe Spawning Engine & Anti-Catapult Protection

In older versions of GTA V and OneSync, executing SetVehicleOnGroundProperly on two-wheeled vehicles (bicycles, motorcycles) or aircraft triggered a physics division-by-zero, launching entities 27 kilometers into the ocean (to coordinates Y: -27647).

6.1. Implemented Safeguards

  • Removal of SetVehicleOnGroundProperly: Server creation via CreateVehicleServerSetter already positions vehicles precisely on the terrain mesh with calibrated Z offsets:
    • Bicycles & Motorcycles: +0.05 m
    • Cars & Boats: +0.10 m
    • Helicopters: +0.40 m
    • Airplanes: +0.60 m
  • Strict FiveM Network Classes:
    CreateVehicleServerSetter(hash, spawnType, x, y, z, h) maps strictly to one of the 5 valid FiveM network classes: 'automobile', 'bike', 'boat', 'heli', or 'plane'.
  • Warp Safety Bounds Check:
    Before executing TaskWarpPedIntoVehicle, the client validates that the vehicle's coordinates fall within GTA V world boundaries (|x| < 8000, |y| < 10000, z > -50) and within 30 meters of the bay. If any physics anomaly occurs, the vehicle is snapped back to the spawn coordinates before the player is placed inside.

7. Public Exports and Entity StateBags

7.1. Client Exports

-- Checks if an entity is an active rental vehicle
local isRental = exports['zero_rent']:IsRentalVehicle(vehicle)

-- Checks if vehicle can be stored in a garage (returns false for rentals)
local canStore = exports['zero_rent']:CanStoreVehicle(vehicle)

7.2. Server Exports

-- Checks entity handle or license plate string
local isRental = exports['zero_rent']:IsRentalVehicle(entityOrPlate)

-- Specifically checks if a plate matches an active rental contract
local isRentalPlate = exports['zero_rent']:IsRentalPlate("ZR000042")

7.3. Vehicle StateBags

When a rental vehicle spawns, the server assigns the following network StateBags:

Entity(vehicle).state.zeroRent = recordId        -- Contract ID (e.g. 'rent_1792089697_150')
Entity(vehicle).state.isRental = true           -- Universal boolean indicator
Entity(vehicle).state.cannotBeStored = true     -- Standard blocker for modern garages
Entity(vehicle).state.isRented = true           -- Backwards compatibility

8. Version Manifest System (server/version.lua)

Following the ZerØ Network standard, version checking logic is strictly server-side and lives in a single protected script server/version.lua (outside config.lua to prevent end-user tampering, link spoofing, or bypasses):

  • Asynchronous periodic checking: Upon startup and every 60 minutes, the server performs a non-blocking GET request to GitHub (https://raw.githubusercontent.com/Zer0-Network/zero_rent/main/versions). If a new version is detected, a colored ZerØ Network alert banner is output to the server console displaying the release notes and repository link without interrupting gameplay.
  • Remote manifest format (GitHub):
    {
      "schema": 1,
      "resource": "zero_rent",
      "version": "1.0.1",
      "download": "https://github.com/Zer0-Network/zero_rent/releases/latest"
    }