esx_property
esx_property lets ESX Legacy players buy, furnish and share houses with keys, garages, CCTV, raids and a real estate job. Setup, config, commands and exports.
esx_property is the official housing resource for ESX Legacy. Players buy properties from a list of 95 premade houses and apartments, enter them in their own routing bucket, give keys to friends, place furniture, store vehicles in a garage and watch a CCTV camera. Admins and an optional real estate job can create, edit and sell properties in-game.
Overview
| Resource | esx_property (version 2.0) |
| Side | Client + server |
| Dependencies | esx_lib, es_extended, oxmysql |
| Optional | ox_inventory (stash), esx_datastore + skinchanger (wardrobe), esx_society + esx_addonaccount (real estate job), esx_context, esx_notify, esx_progressbar (raids), IPL or shell resources |
| SQL file | None. Tables are created at startup |
| Storage | esx_properties, esx_property_migrations |
Features in short:
- Buying and selling. Buying takes the price from the bank. Selling back pays 60 % of the price.
- Keys. The owner can give and remove keys. Players with keys can enter and use the property.
- Locking. Locked doors keep visitors out.
Config.CanAlwaysExitandConfig.OwnerCanAlwaysEntercontrol edge cases. Visitors can knock. - Furniture. Furniture stores sell props by category, paid from the bank, placed and moved with keyboard controls.
- Garage. Store owned vehicles inside a property and take them out again.
- CCTV. A camera above the door with zoom and night vision. Optional Discord webhook for screenshots.
- Raids. On-duty
police(and optionally admins) can break in, optionally consuming an item. - Interiors. IPL interiors are on by default. Shell interiors need
Config.Shells = trueand a shell pack.
Installation
Ensure the resource
ensure oxmysql
ensure esx_lib
ensure es_extended
ensure esx_datastore
ensure esx_society
ensure ox_inventory
ensure esx_propertyOnly oxmysql, esx_lib and es_extended are required. Start optional resources before esx_property.
First start: JSON to SQL migration
On startup the resource creates esx_properties and esx_property_migrations (both must be InnoDB). If the migration properties_json_to_sql_v1 has not run yet, it reads properties.json, imports every property into SQL in one transaction and keeps the JSON file unchanged.
The import refuses to run if esx_properties already has rows without a migration marker, or if properties.json is missing or empty. While storage is not ready, all property actions are rejected.
Optional setup done automatically
The resource inserts a shared property datastore if the datastore table exists. With Config.PlayerManagement.Enabled it also creates the real estate job, its grades and the society account, and registers the society with esx_society.
Configuration
General
| Key | Default | Description |
|---|---|---|
Config.ForSaleBlips | false | Blips for properties for sale (can clutter the map). |
Config.OwnedBlips | true | Blips for owned properties. |
Config.Locale | GetConvar('esx:locale', 'en') | Locale. |
Config.Shells | false | Enable shell interiors. |
Config.SaveInterval | 5 | Fallback save interval in minutes. Changes are also saved after a short debounce. |
Config.MaxFurniturePerProperty | 500 | Limit for new furniture purchases. |
Config.MaxVehiclesPerProperty | 100 | Limit for new garage deposits. |
Config.CanAlwaysExit | true | false allows players to be locked in. |
Config.OwnerCanAlwaysEnter | true | false means the owner needs the door unlocked. |
Config.MaxNameLength | 20 | Max length of property names. |
Config.CanCustomiseInventoryAndWardrobePositions | true | Owners can move storage and wardrobe points. |
Config.WipeCustomNameOnSell | true | Reset the custom name on sale. |
Config.WipeFurnitureOnSell | true | Remove furniture on sale. |
Config.AllowedGroups | { "admin" } | ESX groups with admin access. |
Config.OxInventory | ESX.GetConfig().OxInventory | Uses ox_inventory stashes. |
Prices, raids, garage, logs
| Key | Default | Description |
|---|---|---|
Config.ZonePriceOptions.Enabled | true | Suggest prices by zone in the creator. |
Config.ZonePriceOptions.Default | 250000 | Base price for suggestions. |
Config.ZonePrices | [0] = 10 ... [5] = 1 | Multiplier per zone class (posh to scum). |
Config.Raiding.Enabled | true | Allow raids. |
Config.Raiding.CanAdminsRaid | true | Admins may raid too. |
Config.Raiding.ItemRequired | { RemoveItem = true, name = "bread", label = "Bread", ItemCount = 1 } | Item needed to raid. Remove the table to disable. Change bread to a real tool. |
Config.Raiding.Animation | { type = "Scenario", Scenario = "WORLD_HUMAN_HAMMERING" } | Raid animation. |
Config.Garage.Enabled | true | Property garages. |
Config.Garage.OwnedVehiclesOnly | true | Only owned vehicles can be stored. |
Config.Garage.MySQLquery | "UPDATE `owned_vehicles` SET `stored` = ? WHERE `plate` = ?" | Query run when storing or retrieving. Adapt it to your garage schema. |
Config.Logs.Webhook | "" | Discord webhook for logs (server only). |
Config.Logs.LogLevel | 1 | 0 none, 1 major, 2 major + minor, 3 all. |
Furniture and CCTV
| Key | Default | Description |
|---|---|---|
Config.Furniture.Enabled | true | Furniture system. |
Config.Furniture.RotationSpeed / MovementSpeed / MovementZspeed | 0.4 / 0.01 / 0.05 | Placement speeds. |
Config.Furniture.Controls | control IDs | Arrow keys move, Alt/Shift rotate, Enter confirms, Backspace exits. |
Config.FurnitureStores | Ikea, Electronics Store | Stores and the categories they sell. |
Config.FurnitureCatagories | list | Props per category with prices. |
Config.CCTV.Enabled | true | CCTV system. |
Config.CCTV.PictureWebook | "" (server) | Discord webhook for CCTV screenshots. Leave the client string unchanged. |
Config.CCTV.HeightAboveDoor / FOV | 2.5 / 80.0 | Camera placement. |
Config.CCTV.MaxLeftRotation / MaxRightRotation / MaxUpRotation / MaxDownRotation | 80 / -50 / 10 / -45 | Rotation limits. |
Config.CCTV.MaxZoom / MinZoom / RotateSpeed | 30 / 100 / 0.3 | Zoom and speed. |
Real estate job (Config.PlayerManagement)
| Key | Default | Description |
|---|---|---|
Enabled | false | Enable the real estate job. |
job / joblabel | "realestateagent" / "Estate Agent" | Job name and label. |
society | "society_realestateagent" | Society account. |
SalePercentage | 0.25 | Share of the price paid to the selling agent's bank. The rest goes to the society. |
jobRanks | trainee (0), agent (1), boss (2) | Grades created automatically. |
Permissions | e.g. CreateProperty = 0, DeleteProperty = 2 | Minimum grade per action. |
Locations | office entrance, exit, management menu | Real estate office points. |
Config.Interiors lists the IPL and shell interiors with their spawn, wardrobe and storage positions. Config.WardrobeInteraction is a client function you can replace to use your own clothing script.
Commands
| Command | Who | Description |
|---|---|---|
/property:create | Admins, or real estate agents with the CreateProperty grade | Opens the property creator. |
/property:admin | Config.AllowedGroups | Admin menu: manage, teleport to or delete any property. |
/property:save | Config.AllowedGroups | Saves all properties now. |
/property:refresh | Config.AllowedGroups | Resends property data to all players. |
/getoffset | Client command | Prints your offset inside a property to F8 (for wardrobe and storage positions). |
Command names come from the locale file and can differ if you change it.
Exports
Server
| Export | Returns |
|---|---|
GetProperties() | The full properties table, indexed by property ID. |
GetOwnedProperties() | Array of owned properties. |
GetNonOwnedProperties() | Array of properties for sale. |
GetPlayerProperties(identifier) | Array of properties owned by that identifier. |
GetPropertyKeys(propertyId) | Table of key holders, { [identifier] = true }. |
DoesPlayerHaveKeys(propertyId, identifier) | true / false (see note below). |
ForceSaveProperties() | Saves immediately and logs the calling resource. |
ESX.RegisterCommand('myhouses', 'user', function(xPlayer)
local owned = exports.esx_property:GetPlayerProperties(xPlayer.getIdentifier())
for _, property in ipairs(owned) do
xPlayer.showNotification(property.setName ~= '' and property.setName or property.Name)
end
end, false, { help = 'List your properties' })A property table contains among others Name, setName, Price, Interior, Entrance, Owner, Owned, Locked, Keys, garage, cctv, furniture and positions. Treat it as read-only. Changes from other resources are not saved.
Edge cases
GetPropertyKeys and DoesPlayerHaveKeys index Properties[propertyId] without a nil check, so an invalid ID throws an error. Validate the ID first.
Client
exports.esx_property:GetProperties() returns the property data the server synced to this player. For properties without access, the server strips owner, keys, furniture and garage data.
Events and callbacks
All interaction (buy, sell, lock, keys, furniture, garage, CCTV, raids, admin edits) goes through server callbacks named esx_property:<action>, for example esx_property:buyProperty, esx_property:toggleLock, esx_property:GiveKey and esx_property:StoreVehicle. Every callback is wrapped by a rate limiter, refuses to run while storage is not ready, validates property IDs and checks ownership, keys, admin groups or real estate grade on the server.
The client-triggerable net events are esx_property:enter, esx_property:leave, esx_property:SetVehicleOut and esx_property:server:createProperty. They are rate limited too. enter checks access and distance to the entrance, and createProperty requires admin or the CreateProperty grade and validates every field.
Client events sent by the server include esx_property:syncProperties, esx_property:syncProperty, esx_property:receivePropertyOffer, esx_property:giveKeyAccess, esx_property:RemoveKey and the furniture events (syncFurniture, loadFurniture, placeFurniture, removeFurniture, editFurniture).
Common issues
- "properties.json is missing or empty; SQL migration was not completed". The first start needs the shipped
properties.json. Restore it, or insert at least one row and the migration marker manually if you start from scratch. - "SQL property IDs must be contiguous". IDs in
esx_propertiesmust be 1..n without gaps. Do not delete rows by hand. Use the admin menu. - Storage marker does nothing. Storage needs ox_inventory.
- Wardrobe is empty. Install esx_datastore and save outfits through esx_clotheshop.
- Vehicles stay "out" in your garage script. Adjust
Config.Garage.MySQLqueryto your schema. - Shell interiors are black or missing. Enable
Config.Shellsand install the shell pack the interiors refer to.
Related
Frequently asked questions
Independent documentation
Last updated on
esx_policejob
Set up esx_policejob for ESX Legacy. Covers SQL, config keys, armory, job vehicles, handcuffs, fines, server events, callbacks and common issues.
esx_rpchat
esx_rpchat adds roleplay chat to ESX Legacy - /me and /do proximity messages, global OOC, /twt, /anontwt and private /msg with per-command rate limits.