Housing
Configurables
All config & open sourced files included within this script.
Config Files
--[[
BY RX Scripts © rxscripts.xyz
--]]
Config = {}
Config.Locale = 'en'
Config.SaveInterval = 10 -- In Minutes
Config.DefaultRoutingBucket = 0
Config.UseMoney = 'bank' -- Money account used for payments
Config.PostMessageCooldown = 300 -- In Seconds, cooldown on sending post messages to a house
Config.MaxHouses = 5 -- Amount of houses a player can own
Config.SellReturn = 0.5 -- Percentage of the house price you get back when selling (0 - 1)
Config.LaptopProp = 'prop_laptop_01a' -- Prop used for the laptop
Config.UseStashUpgrade = true -- Set to false if you want to disable the stash upgrades (for if ur using an inventory that doesnt offer this feature)
Config.LockUnsoldPropertyDoors = true -- Lock the doors of unsold properties
Config.Ringing = {
refreshCooldown = 3000, -- In MS
canOpenStash = true, -- Can the player open the stash whilst being let in by ringing the doorbell?
canOpenWardrobe = true, -- Can the player open the wardrobe whilst being let in by ringing the doorbell?
}
Config.Keyholders = {
maxKeyholders = 5, -- false to make unlimited
canOpenStash = true, -- Can the player open the stash as a keyholder?
canOpenWardrobe = true, -- Can the player open the wardrobe as a keyholder?
}
Config.BreakIn = {
enabled = true,
canOpenStash = true,
canOpenWardrobe = true,
minimumCops = 0,
copsJob = 'police',
requiredItem = 'lockpick',
}
Config.Raid = {
enabled = true,
canOpenStash = true,
canOpenWardrobe = true,
requiredItem = 'phone',
allowedJobs = { -- Minimum grade required
{ job = "police", grade = 0 },
}
}
Config.Blips = {
ownedPropertyOwner = { -- When you have the key to the property
enabled = true,
color = 26,
sprite = 40,
scale = 0.8,
display = 4,
},
ownedPropertyStranger = { -- When you don't own the property
enabled = true,
color = 62,
sprite = 40,
scale = 0.8,
display = 4,
},
unownedProperty = { -- When the property is unowned
enabled = true,
color = 0,
sprite = 40,
scale = 0.8,
display = 4,
},
}
Config.StashGrades = {
{ -- DEFAULT GRADE
price = 0,
weight = 150000,
slots = 10,
},
{
price = 25000,
weight = 300000,
slots = 20,
},
{
price = 50000,
weight = 500000,
slots = 30,
}
}
Config.ShellsZ = -50 -- Z axis for shells
Config.MLODoorAutoClose = {
enabled = true, -- Enable automatic door closing for MLO properties
closeTime = 5000 -- Time in milliseconds before door auto-closes (5 seconds)
}
Config.Commands = {
enterfix = 'housing:enterfix', -- Used to tp back into the property if fallen through the map
admin = 'housing:admin', -- Opens the admin panel
}
--[[
IMPORTANT: Changing these keybinds only affects NEW players!
Once a player joins the server, these keybinds are saved to their FiveM settings.
Existing players must either:
- Clear their FiveM cache, or
- Manually change the keybinds in their FiveM Settings > Key Bindings > FiveM
--]]
Config.PlacementKeys = {
moveMode = '1', -- Switch to position adjustment
turnMode = '2', -- Switch to rotation adjustment
coordinateMode = '3', -- Switch between global/local axis
groundAlign = 'LMENU', -- Align object with ground (Alt key)
confirm = 'RETURN', -- Finish and save position (Enter)
cancel = 'BACK', -- Discard changes (Backspace)
}
-- Placement Camera Settings
Config.PlacementCamera = {
enabled = true, -- Enable orbital camera during placement
hidePlayer = true, -- Hide player during placement for better visibility
}
--[[
YOU CAN USE ACE PERMISSIONS TO ALLOW CERTAIN PLAYERS/GROUPS TO ACCESS THE ADMIN HOUSING PANEL
EXAMPLE:
add_ace group.admin housing allow
add_ace identifier.fivem:1432744 housing allow #Rejox
OR YOU CAN USE THE STAFF GROUPS/JOBS BELOW
--]]
Config.AllowedToCreate = {
jobs = {
-- 'real_estate_agent',
},
groups = {
'admin',
'superadmin',
}
}
Config.GlobalPropertyNPC = {
enabled = true, -- Enable/disable the global property NPC
withImages = true, -- Set to false if you don't want to use images for the properties
maxPrice = 1000000, -- Maximum price for the price slider filter
ped = {
model = 'a_m_y_business_03', -- NPC model
coords = vector4(-268.54, -957.31, 31.22, 205.89), -- NPC location (x, y, z, heading)
scenario = 'WORLD_HUMAN_CLIPBOARD', -- Animation scenario
},
blip = {
enabled = true,
sprite = 375,
color = 2,
scale = 0.8,
label = 'Real Estate Agent',
},
}
Config.UI = {
color = {
primary = { -- Different shades of primary color
[50] = "#FEDDE9",
[100] = "#FCBAD3",
[200] = "#FA76A6",
[300] = "#F7317A",
[400] = "#D80955",
[500] = "#95063B",
[600] = "#76052E",
[700] = "#580423",
[800] = "#3B0217",
[900] = "#1D010C",
[950] = "#0F0106"
},
}
}
--[[
ONLY CHANGE THIS PART IF YOU HAVE RENAMED SCRIPTS SUCH AS FRAMEWORK, TARGET, INVENTORY ETC
RENAME THE SCRIPT NAME TO THE NEW NAME
--]]
---@type table Only change these if you have changed the name of a resource
Resources = {
FM = { name = 'fmLib', export = 'new' },
SCREENBASIC = { name = 'screenshot-basic', export = 'all' },
OXTarget = { name = 'ox_target', export = 'all' },
QBTarget = { name = 'qb-target', export = 'all' },
}
IgnoreScriptFoundLogs = false
ShowDebugPrints = false
--[[
DON'T TOUCH ANYTHING BELOW HERE
ADDING IPLS OR SHELLS SHOULD BE DONE IN config/ipls/ or config/shells/
--]]
Config.Shells = {}
Config.IPLs = {}
Opensource Files
All script-related open source code is contained within these files. Third-party components, including frameworks, inventory systems, and other external code, are separately maintained & open sourced in our fmLib repository.
--[[
BY RX Scripts © rxscripts.xyz
--]]
FM.callback.register('rxhousing:takeScreenshot', function(presignedUrl)
local p = promise.new()
if SCREENBASIC then
SCREENBASIC:requestScreenshotUpload(presignedUrl, 'file', function(data)
local resp = json.decode(data)
if resp then
p:resolve(resp)
else
p:resolve(false)
end
end)
else
p:resolve(false)
end
return Citizen.Await(p)
end)
function IsDoorModel(model)
-- Common door model hashes
local doorModels = {
[`prop_com_ls_door_01`] = true,
[`prop_com_ld_door_01`] = true,
[`v_ilev_ra_door4l`] = true,
[`v_ilev_ra_door4r`] = true,
[`prop_ld_garaged_01`] = true,
[`prop_cs6_03_door_l`] = true,
[`prop_cs6_03_door_r`] = true,
[`prop_magenta_door`] = true,
[`v_ilev_roc_door4`] = true,
[`v_ilev_epsstoredoor`] = true,
[`prop_ss1_14_garage_door`] = true,
[`prop_fnclink_03gate1`] = true,
[`prop_facgate_08`] = true,
[`v_ilev_mm_doorm_l`] = true,
[`v_ilev_mm_doorm_r`] = true,
[`prop_bh1_48_gate_1`] = true,
[`prop_gate_prison_01`] = true,
[`p_cut_door_01`] = true,
[`prop_com_gar_door_01`] = true,
[`prop_sec_gate_01c`] = true,
[`prop_sec_gate_01d`] = true,
}
-- Check if model name contains 'door' or 'gate'
local modelName = tostring(model):lower()
if modelName:find('door') or modelName:find('gate') then
return true
end
return doorModels[model] == true
end
function StartGizmoPlacing(obj, propertyId)
-- Use our new placement system
return PlaceFurniture(obj, propertyId)
end
function ShowMarker(type, coords)
if type == 'laptop' or type == 'door' or type == 'stash' or type == 'clothing' then
DrawMarker(2, coords, 0, 0, 0, 0, 180.0, 0, 0.3, 0.3, 0.3, 204, 0, 102, 100, false, false, 2, true, false, false, false)
elseif type == 'entranceForSale' then
DrawMarker(29, coords, 0, 0, 0, 0, 180.0, 0, 0.5, 0.5, 0.5, 255, 204, 0, 100, false, false, 2, true, false, false, false)
elseif type == 'entranceHasKey' or type == 'entranceNoKey' then
local rgb = type == 'entranceHasKey' and { 4, 107, 200 } or { 217, 217, 217 }
DrawMarker(1, coords, 0, 0, 0, 0, 0, 0, 2.0, 2.0, 0.5, rgb[1], rgb[2], rgb[3], 100, false, false, 2, false, false, false, false)
elseif type == 'storeVehicle' then
DrawMarker(1, coords, 0, 0, 0, 0, 0, 0, 3.0, 3.0, 0.5, 4, 107, 200, 100, false, false, 2, false, false, false, false)
elseif type == 'takeVehicle' then
DrawMarker(36, coords, 0, 0, 0, 0, 0, 0, 1.0, 1.0, 1.0, 4, 107, 200, 100, false, false, 2, true, false, false, false)
end
end
function BreakInMinigame()
TaskStartScenarioInPlace(PlayerPedId(), "WORLD_HUMAN_STAND_MOBILE", 0, true)
local result = lib.skillCheck({'easy', 'easy', 'easy'}, {'w', 'a', 's', 'd'})
ClearPedTasks(PlayerPedId())
return result
end
function RaidMinigame()
TaskStartScenarioInPlace(PlayerPedId(), "WORLD_HUMAN_STAND_MOBILE", 0, true)
local result = lib.skillCheck({'easy', 'easy', 'easy'}, {'w', 'a', 's', 'd'})
ClearPedTasks(PlayerPedId())
return result
end
function ShowHelpNotification(msg, thisFrame, beep, duration)
AddTextEntry('helpNotification', msg)
if thisFrame then
DisplayHelpTextThisFrame('helpNotification', false)
else
if beep == nil then
beep = true
end
BeginTextCommandDisplayHelp('helpNotification')
EndTextCommandDisplayHelp(0, false, beep, duration or -1)
end
end
function AddFurnitureTarget(object, furnitureId, propertyId, furnitureData)
if not object or not DoesEntityExist(object) then return end
local property = Houses[propertyId]
if not property then return end
local identifier = FM.player.getIdentifier()
local isOwner = property.owner == identifier
local status = GetPlayerPropertyStatus(propertyId)
if OXTarget then
local options = {}
if furnitureData then
if furnitureData.isStash and CanOpenStash(property, status.isBreakIn, status.rung, status.isRaid) then
table.insert(options, {
label = 'Open Stash',
name = 'open_stash_' .. furnitureId,
icon = 'fas fa-box',
distance = 2.5,
onSelect = function(data)
FM.callback.async('rxhousing:getFurnitureStashId', function(stashData)
if stashData then
FM.inventory.openStash(stashData.stashId, property.owner, stashData.weight, stashData.slots)
end
end, furnitureId, propertyId)
end,
})
end
if furnitureData.isWardrobe and CanOpenWardrobe(property, status.isBreakIn, status.rung, status.isRaid) then
table.insert(options, {
label = 'Open Wardrobe',
name = 'open_wardrobe_' .. furnitureId,
icon = 'fas fa-tshirt',
distance = 2.5,
onSelect = function(data)
FM.player.openWardrobe(propertyId)
end,
})
end
if furnitureData.isComputer and isOwner then
table.insert(options, {
label = 'Manage Property',
name = 'open_computer_' .. furnitureId,
icon = 'fas fa-desktop',
distance = 2.5,
onSelect = function(data)
OpenPropertyMenu(property, true, true, nil)
end,
})
end
end
if isOwner then
table.insert(options, {
label = 'Reposition',
name = 'reposition_furniture_' .. furnitureId,
icon = 'fas fa-arrows-alt',
distance = 2.5,
onSelect = function(data)
FM.callback.async('rxhousing:getFurnitureById', function(furniture)
if furniture then
TriggerEvent('rxhousing:startFurnitureReposition', {
propertyId = propertyId,
furnitureId = furnitureId,
model = furniture.model
})
end
end, furnitureId)
end,
})
table.insert(options, {
label = 'Pick Up',
name = 'pickup_furniture_' .. furnitureId,
icon = 'fas fa-box',
distance = 2.5,
onSelect = function(data)
FM.callback.async('rxhousing:pickupFurniture', function(success, err)
if success then
FM.utils.notify(_L("furniture_picked_up"), "success")
RemoveFurnitureTarget(furnitureId)
else
FM.utils.notify(err or _L("unknown_error"), "error")
end
end, {
propertyId = propertyId,
furnitureId = furnitureId
})
end,
})
end
if #options > 0 then
OXTarget:addLocalEntity(object, options)
end
elseif QBTarget then
local options = {}
if furnitureData then
if furnitureData.isStash and CanOpenStash(property, status.isBreakIn, status.rung, status.isRaid) then
table.insert(options, {
label = 'Open Stash',
icon = 'fas fa-box',
targeticon = 'fas fa-box',
action = function(entity)
FM.callback.async('rxhousing:getFurnitureStashId', function(stashData)
if stashData then
FM.inventory.openStash(stashData.stashId, property.owner, stashData.weight, stashData.slots)
end
end, furnitureId, propertyId)
end,
})
end
if furnitureData.isWardrobe and CanOpenWardrobe(property, status.isBreakIn, status.rung, status.isRaid) then
table.insert(options, {
label = 'Open Wardrobe',
icon = 'fas fa-tshirt',
targeticon = 'fas fa-tshirt',
action = function(entity)
FM.player.openWardrobe(propertyId)
end,
})
end
if furnitureData.isComputer and isOwner then
table.insert(options, {
label = 'Manage Property',
icon = 'fas fa-desktop',
targeticon = 'fas fa-desktop',
action = function(entity)
OpenPropertyMenu(property, true, true, nil)
end,
})
end
end
if isOwner then
table.insert(options, {
label = 'Reposition',
icon = 'fas fa-arrows-alt',
targeticon = 'fas fa-arrows-alt',
action = function(entity)
FM.callback.async('rxhousing:getFurnitureById', function(furniture)
if furniture then
TriggerEvent('rxhousing:startFurnitureReposition', {
propertyId = propertyId,
furnitureId = furnitureId,
model = furniture.model
})
end
end, furnitureId)
end,
})
table.insert(options, {
label = 'Pick Up',
icon = 'fas fa-box',
targeticon = 'fas fa-box',
action = function(entity)
FM.callback.async('rxhousing:pickupFurniture', function(success, err)
if success then
FM.utils.notify(_L("furniture_picked_up"), "success")
RemoveFurnitureTarget(furnitureId)
else
FM.utils.notify(err or _L("unknown_error"), "error")
end
end, {
propertyId = propertyId,
furnitureId = furnitureId
})
end,
})
end
if #options > 0 then
QBTarget:AddTargetEntity(object, {
options = options,
distance = 2.5,
})
end
end
end
function RemoveFurnitureTarget(furnitureId)
local object = SpawnedFurniture[furnitureId]
if not object or not DoesEntityExist(object) then return end
if OXTarget then
OXTarget:removeLocalEntity(object, {
'reposition_furniture_' .. furnitureId,
'pickup_furniture_' .. furnitureId,
'open_stash_' .. furnitureId,
'open_wardrobe_' .. furnitureId,
'open_computer_' .. furnitureId
})
elseif QBTarget then
QBTarget:RemoveTargetEntity(object)
end
end
local MLODoorTargets = {}
local MLODoorEntityTargets = {} -- Track targets on actual door entities
-- Add target to a specific door entity (handles double doors)
function AddMLODoorTarget(doorEntity, propertyId, doorIndex, forceRefresh)
if not OXTarget and not QBTarget then return end
local property = Houses[propertyId]
if not property then return end
-- Handle double doors (array of entities)
if type(doorEntity) == "table" then
for _, entity in ipairs(doorEntity) do
if entity and DoesEntityExist(entity) then
local entityId = tostring(entity)
-- Remove existing target first if refresh is forced or it already exists
if forceRefresh or MLODoorEntityTargets[entityId] then
if OXTarget then
OXTarget:removeLocalEntity(entity)
elseif QBTarget then
QBTarget:RemoveTargetEntity(entity)
end
MLODoorEntityTargets[entityId] = nil
end
if not MLODoorEntityTargets[entityId] then
if OXTarget then
OXTarget:addLocalEntity(entity, {
{
label = "Open " .. property.label,
name = 'open_mlo_door_' .. propertyId .. '_' .. doorIndex,
icon = 'fas fa-door-open',
distance = 2.0,
onSelect = function()
-- Re-fetch property data to ensure it's current
local currentProperty = Houses[propertyId]
if currentProperty then
OpenPropertyMenu(currentProperty, false, false, doorIndex)
end
end
}
})
MLODoorEntityTargets[entityId] = true
elseif QBTarget then
QBTarget:AddTargetEntity(entity, {
options = {
{
label = "Open " .. property.label,
icon = 'fas fa-door-open',
action = function()
-- Re-fetch property data to ensure it's current
local currentProperty = Houses[propertyId]
if currentProperty then
OpenPropertyMenu(currentProperty, false, false, doorIndex)
end
end
}
},
distance = 2.0
})
MLODoorEntityTargets[entityId] = true
end
end
end
end
else
-- Single door
if not doorEntity or not DoesEntityExist(doorEntity) then return end
local entityId = tostring(doorEntity)
-- Remove existing target first if refresh is forced or it already exists
if forceRefresh or MLODoorEntityTargets[entityId] then
if OXTarget then
OXTarget:removeLocalEntity(doorEntity)
elseif QBTarget then
QBTarget:RemoveTargetEntity(doorEntity)
end
MLODoorEntityTargets[entityId] = nil
end
if not MLODoorEntityTargets[entityId] then
if OXTarget then
OXTarget:addLocalEntity(doorEntity, {
{
label = "Open " .. property.label,
name = 'open_mlo_door_' .. propertyId .. '_' .. doorIndex,
icon = 'fas fa-door-open',
distance = 2.0,
onSelect = function()
-- Re-fetch property data to ensure it's current
local currentProperty = Houses[propertyId]
if currentProperty then
OpenPropertyMenu(currentProperty, false, false, doorIndex)
end
end
}
})
MLODoorEntityTargets[entityId] = true
elseif QBTarget then
QBTarget:AddTargetEntity(doorEntity, {
options = {
{
label = "Open " .. property.label,
icon = 'fas fa-door-open',
action = function()
-- Re-fetch property data to ensure it's current
local currentProperty = Houses[propertyId]
if currentProperty then
OpenPropertyMenu(currentProperty, false, false, doorIndex)
end
end
}
},
distance = 2.0
})
MLODoorEntityTargets[entityId] = true
end
end
end
end
-- Property NPC Target Functions
function AddPropertyNPCTarget(npcEntity)
if not OXTarget and not QBTarget then return end
if not npcEntity or not DoesEntityExist(npcEntity) then return end
if OXTarget then
OXTarget:addLocalEntity(npcEntity, {
{
label = 'Browse Properties',
name = 'property_npc_browse',
icon = 'fas fa-home',
distance = 2.5,
onSelect = function()
OpenPropertyNPCMenu()
end
}
})
elseif QBTarget then
QBTarget:AddTargetEntity(npcEntity, {
options = {
{
action = function()
OpenPropertyNPCMenu()
end,
icon = "fas fa-home",
label = 'Browse Properties',
}
},
distance = 2.5
})
end
end
function RemovePropertyNPCTarget(npcEntity)
if not OXTarget and not QBTarget then return end
if not npcEntity or not DoesEntityExist(npcEntity) then return end
if OXTarget then
OXTarget:removeLocalEntity(npcEntity, 'property_npc_browse')
elseif QBTarget then
QBTarget:RemoveTargetEntity(npcEntity)
end
end
-- Remove target from a specific door entity (handles double doors)
function RemoveMLODoorTarget(doorEntity)
if not doorEntity then return end
-- Handle double doors (array of entities)
if type(doorEntity) == "table" then
for _, entity in ipairs(doorEntity) do
if entity then
local entityId = tostring(entity)
if MLODoorEntityTargets[entityId] then
if OXTarget then
OXTarget:removeLocalEntity(entity)
elseif QBTarget then
QBTarget:RemoveTargetEntity(entity)
end
MLODoorEntityTargets[entityId] = nil
end
end
end
else
-- Single door
local entityId = tostring(doorEntity)
if not MLODoorEntityTargets[entityId] then return end
if OXTarget then
OXTarget:removeLocalEntity(doorEntity)
elseif QBTarget then
QBTarget:RemoveTargetEntity(doorEntity)
end
MLODoorEntityTargets[entityId] = nil
end
end
function RemoveMLODoorTargets()
if OXTarget then
for zoneName, zoneId in pairs(MLODoorTargets) do
OXTarget:removeZone(zoneId)
end
elseif QBTarget then
for _, zoneName in ipairs(MLODoorTargets) do
QBTarget:RemoveZone(zoneName)
end
end
MLODoorTargets = {}
end
-- Refresh MLO door targets for a specific property
function RefreshMLODoorTargets(propertyId)
if not propertyId then return end
local property = Houses[propertyId]
if not property or property.propertyType ~= 'mlo' then return end
-- Find all tracked door entities for this property
if TrackedDoorEntities and TrackedDoorEntities[propertyId] then
for doorIndex, doorEntity in pairs(TrackedDoorEntities[propertyId]) do
-- Force refresh the target with updated property data
AddMLODoorTarget(doorEntity, propertyId, doorIndex, true)
end
end
end
--[[
BY RX Scripts © rxscripts.xyz
--]]
Config.DiscordWebhook = ''
--[[
API KEY (https://fivemanage.com/)
DO NOT SHARE THIS WITH ANYONE, EVER!
REQUIRES: screenshot-basic (https://github.com/citizenfx/screenshot-basic)
--]]
Config.FIVEMANAGE_API_KEY = ''
function IsPhotoServiceAvailable()
-- Check if API key is configured
if not Config.FIVEMANAGE_API_KEY or Config.FIVEMANAGE_API_KEY == '' then
return false, 'FiveManage API key not configured'
end
-- Check if screenshot-basic is running
if GetResourceState('screenshot-basic') ~= 'started' then
return false, 'screenshot-basic resource not started'
end
return true, nil
end
function TakeScreenshot(src)
local success, err = IsPhotoServiceAvailable()
if not success then
Error(err)
return false
end
local url = promise.new()
if Config.FIVEMANAGE_API_KEY then
local headers = {
['User-Agent'] = 'rxhousing',
['Authorization'] = Config.FIVEMANAGE_API_KEY
}
PerformHttpRequest('https://api.fivemanage.com/api/presigned-url?fileType=image',
function(statusCode, resultData, resultHeaders, errorData)
if statusCode ~= 200 then
Error('Failed to get presigned URL from Fivemanage')
return url:resolve(false)
end
resultData = json.decode(resultData)
if not resultData or not resultData.presignedUrl then
Error('Failed to get presigned URL from Fivemanage')
return url:resolve(false)
end
local res = FM.callback.sync('rxhousing:takeScreenshot', src, resultData.presignedUrl)
if res then
url:resolve(res)
else
url:resolve(false)
end
end, 'GET', nil, headers)
end
return Citizen.Await(url)
end
function DeleteImageFromCloud(imageId)
local success, err = IsPhotoServiceAvailable()
if not success then
Error(err)
return false
end
local deleted = promise.new()
if Config.FIVEMANAGE_API_KEY then
local headers = {
['Authorization'] = Config.FIVEMANAGE_API_KEY,
}
PerformHttpRequest('https://fmapi.net/api/image/delete/' .. imageId,
function(statusCode, resultData, resultHeaders, errorData)
if statusCode == 200 then
deleted:resolve(true)
else
Error('Failed to delete image from FiveManage. Status: ' .. statusCode)
if errorData then
Error('Error: ' .. tostring(errorData))
end
deleted:resolve(false)
end
end,
'DELETE',
'',
headers
)
end
return Citizen.Await(deleted)
end
function RemoveMoneyFromBankSQL(identifier, amount)
local table = GetResourceState('es_extended') == 'started' and 'users' or 'players'
local accountsColumn = GetResourceState('es_extended') == 'started' and 'accounts' or 'money'
local identifierColumn = GetResourceState('es_extended') == 'started' and 'identifier' or 'citizenid'
return MySQL.update.await(
string.format('UPDATE %s SET %s = JSON_SET(%s, "$.bank", JSON_EXTRACT(%s, "$.bank") - @amount) WHERE %s = @identifier',
table, accountsColumn, accountsColumn, accountsColumn, identifierColumn),
{
['@amount'] = amount,
['@identifier'] = identifier,
}
)
end
function GetMoneyFromBankSQL(identifier)
local table = GetResourceState('es_extended') == 'started' and 'users' or 'players'
local accountsColumn = GetResourceState('es_extended') == 'started' and 'accounts' or 'money'
local identifierColumn = GetResourceState('es_extended') == 'started' and 'identifier' or 'citizenid'
return MySQL.query.await(
string.format('SELECT JSON_UNQUOTE(JSON_EXTRACT(%s, "$.bank")) AS bank FROM %s WHERE %s = @identifier',
accountsColumn, table, identifierColumn),
{
['@identifier'] = identifier,
}
)[1].bank
end
function CanBuyProperty(src, property, price)
return true
end
--[[
EVENTS
--]]
RegisterNetEvent('rxhousing:onHouseEntered', function(src, property, isBreakIn, isRaid)
-- You can utilize this event for any custom needs
end)
RegisterNetEvent('rxhousing:onHouseExited', function(src, propertyId)
-- You can utilize this event for any custom needs
end)
RegisterNetEvent('rxhousing:onHouseBought', function(playerId, property)
-- This event will be called whenever a player bought a house
end)
RegisterNetEvent('rxhousing:onHouseRented', function(playerId, property)
-- This event will be called whenever a player rents a house
end)
RegisterNetEvent('rxhousing:onPropertyCreated', function(property)
-- This event will be called whenever a new property is created
end)
RegisterNetEvent('rxhousing:onKeyholderAdded', function(propertyId, identifier, addedBy)
-- This event will be called whenever a keyholder is added
end)
RegisterNetEvent('rxhousing:onKeyholderRemoved', function(propertyId, identifier, removedBy)
-- This event will be called whenever a keyholder is removed
end)
RegisterNetEvent('rxhousing:onFurniturePlaced', function(propertyId, furnitureData, playerId)
-- This event will be called whenever furniture is placed
end)
RegisterNetEvent('rxhousing:onFurnitureRemoved', function(propertyId, furnitureId, playerId)
-- This event will be called whenever furniture is removed
end)
RegisterNetEvent('rxhousing:onPropertyTransferred', function(propertyId, oldOwner, newOwner)
-- This event will be called whenever property ownership is transferred
end)
