Clock on at the yard, take the truck with the riding mower on the bed and work the contracts on the board: mow stripes into lawns, trim hedges and topiaries, clear leaves, prune trees from a ladder, plant flower beds and clean pools — alone or as a crew of four.
A gardener job where every task is done by hand, and the work stays visible on the property for everyone.
What is in the resource
A custom garden shop MLO in Del Perro as the crew's base, with a garage for the truck.
A streamed flatbed truck with a ramp, a riding mower you strap on and off, four opening toolboxes with every tool, and a ladder on the rack.
Seven tasks: mowing with real stripes, hedge trimming, topiary sculpting, leaf cleanup with a blower and bags, pruning dead branches from a ladder, planting flower beds and cleaning swimming pools.
About 1,560 properties (1,503 gardens, parks and green areas plus 57 private pools) scanned from the GTA map, so contracts work all over the map without placing anything.
Close-up work with the mouse for hedges, topiaries, branches, beds and pools.
Synced for everyone nearby: the mowing stripes, the trimmed hedges, the planted flowers, the clean pool water, the tools in hand, the ladder and the blower's leaves.
Ratings from one to five stars, pay per unit of work, levels that unlock tasks, urgent and weather bonuses.
Crews of up to four, paid by each member's share of the work.
A job app for phones and tablets (lb-phone, lb-tablet, Quasar, yPhone, okokPhone, GKS) and a full Meteo Job Tablet integration.
An in-game admin panel for the yard, truck spots, pay, levels, contracts and sound, and Discord logging.
English, German and Bosnian included.
Almost nothing is configured in a file. Apart from the handful of options in
config.lua, the whole job is set up in game through /gardenadmin,
and changes save on the server and apply live.
Requirements
OneSync and a framework. Everything else is optional.
ServerOneSync.
FrameworkQbox, QBCore, ESX or standalone. Anything else can use the custom bridge.
StorageNo SQL. Settings and profiles are saved in the resource's storage/ folder, which is created on start.
Optionalox_target or qb-target, ox_lib notifications, a vehicle keys script, a fuel script, a weather sync script (for rain and heat), a phone or tablet.
Installation
Start it after your framework and phone, then check the yard in game.
Put 9labs_landmower in your resources folder and keep that exact name.
Add it to server.cfg, after your framework, target, keys, fuel, weather and phone resources.
Give your admins the ACE below (or keep using command, which txAdmin admins already have).
Set the basics in config.lua.
Restart the server.
As an admin, run /gardenadmin and check the yard, truck spots and pay for your server.
ensure 9labs_landmower
add_ace group.admin gardener.admin allow
Players must reconnect after you update the resource. It streams a vehicle, props,
textures and an animation, and those only reload when a client connects. Invisible grass or
wrong textures on the pool tools almost always mean someone did not reconnect.
config.lua
Only the basics live here. Pay, yard, contracts, levels, sound and Discord logs are set in game.
Language of the UI, notifications and logs. Add your own file in locales/ and list it in fxmanifest.lua
framework
auto, qbx, qb, esx, standalone, custom
auto picks the first running one: qbx_core, qb-core, es_extended, otherwise standalone
keys
auto, qbx, qb, none, custom
Keys for the company truck and mower; crew members get keys too. qb uses the server exports of qb-vehiclekeys 1.6 and newer, older versions get the old client event. ESX has no common keys script: use custom
fuel
auto or a resource name
auto fills the vehicles through ox_fuel, LegacyFuel, cdn-fuel or the native level
interaction
9labs_ui, ox_target, qb-target, custom
How players talk to the yard foreman. Everything else (truck, tools, work spots) always uses the on-screen keys
notify
9labs_ui, ox_lib, native, custom
Notification style
truck
plate, colours
Plate format and the primary/secondary GTA colour ids of the company truck
Blocks the inventory and its hotbar keys while a tool is in hand. true works with ox_inventory, qb-inventory and every inventory that respects inv_busy
adminAces
list of ACEs
Who can open /gardenadmin and use the admin test commands. Any one of them is enough
Standalone only: pay goes to a built-in wallet per FiveM license. Standalone takes no shift deposit
debug
true / false
Extra server and F8 output
devTools
true / false
Map checking commands for admins (/gardensurvey pool, /gardenpoolfx, /gardenwhere). Leave off on live servers
First setup
/gardenadmin opens the admin panel. Changes save on the server in storage/settings.json and apply live.
Section
What you set
General
Required job and grade, shift deposit, the yard (foreman position), foreman ped, foreman on or off, truck spots, the radius for returning the truck, the map blip
Pay
Account (cash or bank), contract fee, pay per task unit (100 m² mowed, a hedge, a topiary, a leaf bag, a branch, a flower, 10 m² of pool), level, on-time, urgent, weather and crew bonuses
Levels
XP per contract, XP per rating star, XP per level, the maximum level
Contracts
Offer distance, offers on the board, board refresh, pause between contracts, drop cooldown, urgent share, how long finished properties keep their fresh look, clean mowing speed, and every task on or off with its weight and the level that unlocks it
Sound
Volume and range of the tool sounds
Discord logs
Webhook and what to log
The default yard is the Los Santos Golf Club parking lot. Stand where the foreman should be and
use My position, then add truck spots the same way. Points can also be typed in
or pasted as vector4(...).
Your own NPC instead of the foreman
Turn the foreman off in General. Your script then starts and ends shifts through
StartShift and EndShift; with an options table the yard distance is
not checked and the truck spawns where you say.
-- server side, e.g. when your own NPC hands out the trucklocal r = exports['9labs_landmower']:StartShift(source, { spawn = vector4(-1340.2, 46.1, 54.2, 90.0) })if not r.ok then print(r.error) end
Garden shop MLO
A home for the crew: 9labs_gardenshop, a garden shop interior in Del Perro.
A sales counter with a register, a job board with a desk and computer, a staff room with lockers and a garage for the company truck.
Map files only, no scripts: nothing runs on the client or the server.
Every prop inside is an original GTA V object.
Put 9labs_gardenshop in your resources and add ensure 9labs_gardenshop to server.cfg. It needs sv_enforceGameBuild 2060 or newer.
Fully restart the FiveM client once; a new MLO does not load from a resource restart alone.
Stand behind the counter, open /gardenadmin → General and use My position for the foreman, then add a truck spot in front of the garage. The shop's README lists ready coordinates for the counter, job board, lockers and garage.
Map conflicts. The shop replaces the building sm_11_bld1 and its collision.
Do not run another map that changes the same building.
Properties and pools
Nothing has to be placed. Every property comes from the GTA map.
1,503 garden properties (private gardens, parks and green areas) were scanned from the map: lawns from the ground collision, reachable from a road, with the hedges and broadleaf trees around them. Flower beds and topiaries are placed on the lawn.
90 swimming pools were scanned the same way and checked in game: you can swim in them and the floor and edge match. 33 belong to a garden property, 57 are offered on their own as a private pool.
Objects standing on a lawn (graves, benches, poles) are detected in game and taken out of the mowing, so no grass grows inside a gravestone.
A property that was worked on keeps its fresh look (mowing stripes, flowers, the topiary) for everyone for the time set in /gardenadmin, and is not offered again during that time.
Custom maps. A map that replaces a garden or a pool can leave overgrowth floating or a
pool without water. Those properties simply drop that task. To check every pool on your own
map, turn on devTools and run /gardensurvey pool.
Discord logs
Shifts, payouts, admin changes and security events, each one switchable.
In /gardenadmin → Discord logs paste a webhook URL, save, then press
Send test. Only Discord webhook addresses are accepted, and the webhook never
leaves the server: the panel shows it masked.
How the job works
Shift, board, property, report.
Start a shift at the yard foreman. A deposit is taken and the truck comes with the riding mower strapped on the bed.
Open the contract board (F6 or the phone app) and pick an offer: a private garden, a park, a green area or a private pool, each with one to three tasks, the distance, the estimated time and the pay. Urgent contracts pay extra when finished before the deadline.
Drive there and do every task. The HUD lists what is left and what you still have to pack.
Pack up: mower strapped, ladder on the rack, ramp raised, and stand next to the truck.
The contract report shows the rating per task, the time, every crew member's share and the pay.
Bring the truck back to the yard to end the shift and get the deposit back.
The tasks
Seven kinds of work, each done by hand.
Task
Tools
What you do
Mowing
Riding mower
Lower the ramp (E at the tailgate), release the mower (G) and drive over the overgrown lawn. Rows leave real stripes. Mowing faster than the clean speed leaves a ragged cut that lowers the rating; rain lowers the clean speed
Hedge trimming
Hedge trimmer
Walk up to a marked hedge and press E. In the close-up hold the left mouse button over the overgrowth. Cutting into the hedge where nothing sticks out counts as a gouge and lowers the rating
Topiary
Hedge trimmer
A new figure is planted on the lawn, completely overgrown. Carve it out the same way; the finished figure stays on the property
Leaf cleanup
Leaf blower
Blow the leaf piles onto the tarp (hold the left mouse button, aim with the camera), bag them at the tarp (E), carry the bags to the truck and throw them on the bed (E)
Pruning
Pruning saw, ladder
Take the ladder from the rack (H), carry it to the tree and lean it against the trunk (H), climb it with the saw and press E at a dead branch. Saw with the left mouse button while moving the mouse left and right, then carry the fallen branches to the truck
Flower bed
Trowel, seedling tray, watering can
E at the bed opens the close-up. Dig six holes with the trowel, plant the seedlings, water every plant (twice in a heat wave)
You can only hold one thing at a time: a tool, a leaf bag, a branch or the ladder. Bags cannot
be picked up with a tool in hand.
Pool cleaning
Skim, brush, vacuum, then get the water chemistry right.
Take a pool tool from the truck and press E at the pool edge. The close-up camera opens over the water.
Hold the left mouse button on a target. A marker shows what you aim at; a grey marker means it is out of reach, walk around the pool.
Skimmer: lift the floating leaves and the scum. The net holds 8; empty it into the bag at the pool with E.
Brush: scrub the algae on the floor and the walls.
Vacuum: clear the dirt on the floor.
Test kit: when the pool is clean, compare the sample colour with the chart and press the number (1 to 4) of the dose written next to the matching colour. A wrong dose means a new test and a lower rating.
Carry the leaf bags to the truck. The task is done when the water is balanced and every bag is on the bed.
Truck, mower and tools
Everything the crew needs rides on the flatbed.
Ramp: E at the tailgate lowers and raises it. It cannot be raised while the mower stands on it.
Mower: G straps it to the bed or releases it. Releasing only works with the ramp lowered.
Toolboxes: E opens, G closes. Leaf blower, skimmer and pool brush front left; hedge trimmer and pool vacuum front right; trowel, watering can and test kit rear left; saw and seedling tray rear right. Scroll to choose when a box holds more than one tool, and put a tool back in the same box.
Ladder: H takes it from the rack, leans it against a wall or a tree trunk (a green outline shows where it will stand) and puts it back on the rack.
Prompts follow where you look: when two actions share a key (strapping the mower and closing a
toolbox), the one you face is the one that runs. Only your own crew gets the prompts of your
truck.
Rating, pay and levels
Do it well and on time, earn more.
Pay = contract fee + pay per unit of work for every task (all in /gardenadmin → Pay).
Rating: every task is rated (ragged mowing, gouged hedges, missed spots, wrong pool doses). The contract gets one to five stars, which scale the pay and give extra XP.
Bonuses: level, finishing within the estimated time, urgent contracts before the deadline, working in the rain, and the crew bonus.
Levels unlock tasks. Defaults: mowing and leaves 1, hedges 3, pool cleaning 4, flower beds 5, pruning 8, topiary 12.
Crew work
Up to four gardeners on one truck, paid by the work each one did.
On shift, open the foreman's tablet and invite colleagues standing next to you; they accept with
Y or decline with N. Crew members use your truck and mower, see the same contract and get keys,
without a deposit.
The crew earns 25% more for every extra member, split by each member's share of the work, and the crew bonus is added on top.
Members who did less than 10% of the work get nothing. The report shows everyone's share.
When the leader ends the shift the crew is disbanded; when a member leaves, only that member goes off duty.
Player controls
On-screen keys, all set in config.lua.
Key
Action
F6
Contract board (rebind in Settings → Key Bindings → FiveM)
E
Ramp, toolboxes, start work, pick up a bag or a branch, throw it on the truck
G
Strap or release the mower, close a toolbox, put down what you carry
controls = { use = { control = 38, label = 'E' }, -- ramp, toolboxes, start work on the hedge/bed/branch in front of you secure = { control = 47, label = 'G' }, -- strap / release the mower, put a tool back ladder = { control = 74, label = 'H' }, -- take, lean and stow the ladder depot = { control = 38, label = 'E' }, -- talk to the depot foreman accept = { control = 246, label = 'Y' }, -- accept a crew invite decline = { control = 306, label = 'N' }, -- decline a crew invite},
Testing: a pool contract at the pool you stand next to (starts a shift if needed) with everything but the water test done
/gardenboard
Player
Opens the contract board
/gardencancel
Player
Drops the current contract (crew: leader only)
gardenprof (F8)
Anyone
Measures this resource's client cost for 5 seconds
Phone and tablet apps
The job app installs itself on every supported phone and tablet that is running.
The app shows the shift, the current contract with GPS, the contract board button, your level
and the best gardeners on the server. Turn single phones off in apps.
Registered as a full job: Clock In and Out (at the yard, or anywhere when the foreman is turned
off), accept, reject and cancel contracts, the dispatch panel, levels, rankings, achievements and
tournaments.
Custom bridges
Your own framework, money, keys, weather, prompts or target.
Set framework = 'custom' (and/or keys = 'custom') and fill in the
Custom block at the top of server/bridge.lua. Weather is read
automatically from Renewed-Weathersync, qb-weathersync and cd_easytime; any other weather script
goes through Custom.weather.
function Custom.identity(src) return GetPlayerIdentifierByType(src, 'license') end -- stable character idfunction Custom.name(src) return GetPlayerName(src) end -- name in the job appfunction Custom.addMoney(src, account, amount, reason) return false end -- return true on successfunction Custom.removeMoney(src, account, amount, reason) return false endfunction Custom.getMoney(src, account) return 0 endfunction Custom.hasJob(src, job, grade) return true end -- only used when a job is setfunction Custom.giveKeys(src, vehicle, plate) end -- vehicle = server entity handlefunction Custom.removeKeys(src, vehicle, plate) endfunction Custom.weather() return nil end -- 'CLEAR', 'RAIN', 'EXTRASUNNY' ... or nil
Set interaction = 'custom' and/or notify = 'custom' and fill in the
Custom block at the top of client/bridge.lua.
function Custom.showContext(items) end -- items = { { key = 'E', text = '...', disabled = nil|true }, ... }function Custom.hideContext() endfunction Custom.notify(text, kind) end -- kind: 'info', 'success', 'error'function Custom.addTarget(id, coords, radius, options) return nil end -- options: { { label, icon, onSelect } }, return a handlefunction Custom.removeTarget(handle) endfunction Custom.setFuel(vehicle, level) endfunction Custom.lockInventory(locked) end -- used when lockInventory = 'custom'
config.lua, locales/, both bridge files, both integration files and
data/ stay open under Asset Escrow.
Exports
Everything another script needs to read or drive a shift.
Server
-- true when the player is on a gardener shift (leader or crew member)local onDuty = exports['9labs_landmower']:IsOnDuty(source)-- level and statistics of the player's character, or nillocal p = exports['9labs_landmower']:GetProfile(source)-- p.level, p.xp, p.levelXp, p.nextXp, p.maxLevel, p.jobs, p.earned, p.best, p.rating, p.name-- the shift and the current contract, or false when off shiftlocal shift = exports['9labs_landmower']:GetShiftState(source)-- shift.truck, shift.mower (net ids), shift.deposit, shift.earned, shift.jobs, shift.leader (bool)-- shift.next (seconds until new offers) or nil, shift.crew (see GetCrew) or nil-- shift.task = { id, kind ('garden' | 'park' | 'green' | 'villa'), x, y, z (road), cx, cy, cz (property centre),-- tasks = { { kind, done, units } }, ready, urgent, deadline, accepted, par, weather, pay } or nil-- the full contract view with every task and its progress, or nillocal contract = exports['9labs_landmower']:GetContract(source)-- the crew, or nil when the player works alonelocal crew = exports['9labs_landmower']:GetCrew(source)-- crew.leader, crew.members = { { id, name, leader } }-- start or end a shift from your own scriptexports['9labs_landmower']:StartShift(source) -- same rules as the foreman: only at the yardexports['9labs_landmower']:StartShift(source, { spawn = vector4(x, y, z, h) }) -- anywhere, truck at spawn (or a free truck spot)-- returns { ok, truck } or { ok = false, error }exports['9labs_landmower']:EndShift(source) -- { ok, summary } or { ok = false, confirm = true, error }exports['9labs_landmower']:EndShift(source, { force = true }) -- end even when the truck is not back in the yardexports['9labs_landmower']:EndShift(source, { refund = true }) -- your script decides about the deposit-- drop the current contract (crew: acts for the leader)exports['9labs_landmower']:AbandonJob(source)
Client
local shift = exports['9labs_landmower']:GetShiftState() -- same shape as the server exportexports['9labs_landmower']:SetJobWaypoint() -- GPS to the propertyexports['9labs_landmower']:SetJobWaypoint('depot') -- GPS to the yardAddEventHandler('9labs_landmower:client:stateChanged', function(shift) -- shift is false when the player went off dutyend)
Server events
Local server events, safe to listen to from any resource.