F.A.Q

5 min readUpdated 2 weeks ago

Setup

No. The ml_turrets table is created automatically at first start through CREATE TABLE IF NOT EXISTS. Subsequent restarts are a no-op.

oxmysql cannot reach your database. Check the connection string in your server config. The script refuses to start until the DB is reachable, no silent fallback.

The item is not registered in your inventory, or the item field on the turret type does not match the inventory item name. Verify both sides. The item name on the type must be the exact key used by your inventory definition.

Placement

Your Bazq stream resource is not loaded or starts after ml_turret. Move it above in server.cfg. The ghost reads the same props the live turret uses, so if streaming fails only the base is created.

Use Config.NoPlaceZones. The ghost turns red inside these zones and cannot be confirmed. Three shape types supported: sphere, box, poly.

shared/config.lua
1Config.NoPlaceZones = {
2    { type = 'sphere', coords = vec3(298.6, -584.8, 43.3), radius = 80.0 },
3}

Yes, via Config.PlacementProgress.anim. Any valid animation dict + clip works. The config comment lists four useful presets (hammering, rummaging, inspecting, repairing).

Ownership and Invites

Check the permissions.canBeUsedByAll flag on the turret type. If true, anyone in range can use the turret. If false, the option only appears to the owner and group members. The ox_target canInteract callback evaluates this on every aim, so changes take effect immediately.

Set Config.Ownership.playerNameFormat = 'rp_full'. License2 alone does not distinguish characters on the same account, ml_turret falls back to citizenid on QBCore/Qbox for ownership checks. On ESX/standalone, license is used.

30 seconds by default. Configurable via Config.Ownership.inviteTimeoutSeconds.

No. Only the owner can invite or revoke members. Group members can open the panel, reload, repair and refuel but cannot transfer ownership or dismantle.

Combat and Damage

The weapon must be in the turret's weaponDamage table. It is a strict whitelist: unknown weapons are blocked as potential forge attempts. Add the weapon hash with an absolute HP value:

shared/config.lua
1weaponDamage = {
2    [`WEAPON_YOUR_WEAPON`] = 25,
3}

Set infiniteHealth = true on the turret type (applies to every instance) or on a specific Config.FixedTurrets entry (per-instance). The damage pipeline short-circuits server-side.

Increase rotation.aimDeadZone (metres). When the target is inside this horizontal distance the turret freezes yaw instead of flipping. Default is 1.2m for bazq_heavy, 0.8m for cctv_sentry.

Increase targeting.switchCooldown (ms) on the type, or Config.AI.defaultSwitchCooldown for a global override. Default is 800ms, the turret will not adopt a new target until that much time has passed since the last swap.

Destruction and Repair

Open the panel via target → Repair tab → select a repair item. Each repair item has an addHealth value configured in the turret type:

shared/config.lua
1repairItems = {
2    ['repair_kit']    = { addHealth = 300.0 },
3    ['welding_torch'] = { addHealth = 150.0 },
4}

Target the rubble prop → Repair Rubble → consumes one Config.Destruction.destructionRepairItem (default turret_rebuild_kit) and brings the turret back at 50% HP.

Yes, two options.

Per type, set canBeRepairedAfterDestruction = false: rubble still spawns but the Repair option is hidden (dismantle-only for salvage).

Per type, set permanentDestruction = true: death is final: no rubble, no repair, DB row deleted instantly, player quota freed up immediately.

Set stayDestroyed = true on the instance in Config.FixedTurrets. When destroyed, the DB row keeps is_destroyed = 1 across restarts. To bring it back, run /turret_revive <fixed_config_id> as an admin, then restart the resource.

Change destroyedProp on the type. Valid GTA props include prop_rub_scrap_02, prop_rub_scrap_04, prop_rub_generator, prop_rub_boxpile_05, prop_dumpster_02a. Set nil to skip the rubble entirely (explosion only).

AI Behaviour

Set Config.AI.enabled = false. Every turret becomes manual-only.

Set targeting.targetPlayers = false, targetHumans = false, targetZombies = true on the turret type. For Config.HRS, either patch hrs_zombies to set the hrsIsZombie state bag, or add your zombie models to the zombieModels whitelist.

The owner and group members by default. For fixed turrets, configure ai.toggleableBy with a policy table:

shared/config.lua
1ai = {
2    enabled      = true,
3    toggleableBy = { jobs = { 'police' }, aces = { 'command.turret' } },
4}

Networking and Performance

The turret's gunner and barrel are client-side-only props, each client spawns and animates its own local copies attached to the networked base. Every player sees 60fps rotation regardless of network ownership or distance.

One networked entity (the base) and a batch DB save every 60 seconds if the turret's state has changed. Fire events, muzzle flashes and damage reports are scope-limited to clients within 150m. AI logic runs entirely on clients.

Updates

  1. Download latest from CFX Portal
  2. Backup your shared/config.lua, server/config_server.lua, locales/*.lua and any edits in open/*.lua
  3. Replace all other files
  4. Restart the resource

No DB migration is required. New columns are added via CREATE TABLE IF NOT EXISTS safely, existing rows keep their data.