Setup Video by Kamaryn
Installation Instructions
Pay Attention to each step, Don't skip any of them.
1. Find the following events inside qb-multicharacter
and change in server/main.lua event to:
Copy qb-multicharacter > server > main.lua
Copy RegisterNetEvent ( 'qb-multicharacter:server:loadUserData' , function ( cData )
local src = source
if QBCore.Player. Login (src, cData.citizenid) then
repeat
Wait ( 10 )
until hasDonePreloading[src]
print ( '^2[qb-core]^7 ' .. GetPlayerName (src) .. ' (Citizen ID: ' .. cData.citizenid .. ') has succesfully loaded!' )
QBCore.Commands. Refresh (src)
TriggerClientEvent ( 'ps-housing:client:setupSpawnUI' , src, cData)
TriggerEvent("qb-log:server:CreateLog", "joinleave", "Loaded", "green", "**".. GetPlayerName(src) .. "** (<@"..(QBCore.Functions.GetIdentifier(src, 'discord'):gsub("discord:", "") or "unknown").."> | ||" ..(QBCore.Functions.GetIdentifier(src, 'ip') or 'undefined') .. "|| | " ..(QBCore.Functions.GetIdentifier(src, 'license') or 'undefined') .." | " ..cData.citizenid.." | "..src..") loaded..")
end
end )
Copy qb-multicharacter > server > main.lua
Copy RegisterNetEvent ( 'qb-multicharacter:server:createCharacter' , function ( data )
local src = source
local newData = {}
newData.cid = data.cid
newData.charinfo = data
if QBCore.Player. Login (src, false , newData) then
repeat
Wait ( 10 )
until hasDonePreloading[src]
print ( '^2[qb-core]^7 ' .. GetPlayerName (src) .. ' has succesfully loaded!' )
QBCore.Commands. Refresh (src)
TriggerClientEvent ( "qb-multicharacter:client:closeNUI" , src)
newData.citizenid = QBCore.Functions. GetPlayer (src).PlayerData.citizenid
TriggerClientEvent ( 'ps-housing:client:setupSpawnUI' , src, newData)
GiveStarterItems (src)
end
end )
2. Find the following events in qb-spawn
and change in client/client.lua event to:
Copy qb-spawn > client.lua > line 51 > 'qb-spawn:client:setupSpawns' event
Copy RegisterNetEvent ( 'qb-spawn:client:setupSpawns' , function ( cData , new , apps )
if not new then
QBCore.Functions. TriggerCallback ( 'qb-spawn:server:getOwnedHouses' , function ( houses )
local myHouses = {}
if houses ~= nil then
for i = 1 , ( # houses), 1 do
local house = houses[i]
myHouses[ # myHouses + 1 ] = {
house = house,
label = (house.apartment or house.street) .. " " .. house.property_id,
}
end
end
Wait ( 500 )
SendNUIMessage ({
action = "setupLocations" ,
locations = QB.Spawns,
houses = myHouses,
isNew = new
})
end , cData.citizenid)
elseif new then
SendNUIMessage ({
action = "setupAppartements" ,
locations = apps,
isNew = new
})
end
end )
Copy qb-spawn > client.lua > line 134 > 'chooseAppa' NUI Callback
Copy RegisterNUICallback ( 'chooseAppa' , function ( data , cb )
local ped = PlayerPedId ()
local appaYeet = data.appType
SetDisplay ( false )
DoScreenFadeOut ( 500 )
Wait ( 100 )
FreezeEntityPosition (ped, false )
RenderScriptCams ( false , true , 0 , true , true )
SetCamActive (cam, false )
DestroyCam (cam, true )
SetCamActive (cam2, false )
DestroyCam (cam2, true )
SetEntityVisible (ped, true )
Wait ( 500 )
TriggerServerEvent ( 'QBCore:Server:OnPlayerLoaded' )
TriggerEvent ( 'QBCore:Client:OnPlayerLoaded' )
Wait ( 100 )
TriggerServerEvent ( "ps-housing:server:createNewApartment" , appaYeet)
cb ( 'ok' )
end )
Copy qb-spawn > client > client.lua > line 169 'spawnplayer' NUI Callback
Copy RegisterNUICallback ( 'spawnplayer' , function ( data , cb )
local location = tostring (data.spawnloc)
local type = tostring (data.typeLoc)
local ped = PlayerPedId ()
local PlayerData = QBCore.Functions. GetPlayerData ()
local insideMeta = PlayerData.metadata[ "inside" ]
if type == "current" then
PreSpawnPlayer ()
QBCore.Functions. GetPlayerData ( function ( pd )
ped = PlayerPedId ()
SetEntityCoords (ped, pd.position.x, pd.position.y, pd.position.z)
SetEntityHeading (ped, pd.position.a)
FreezeEntityPosition (ped, false )
end )
TriggerServerEvent ( 'QBCore:Server:OnPlayerLoaded' )
TriggerEvent ( 'QBCore:Client:OnPlayerLoaded' )
if insideMeta.property_id ~= nil then
local property_id = insideMeta.property_id
TriggerServerEvent ( 'ps-housing:server:enterProperty' , tostring (property_id))
end
PostSpawnPlayer ()
elseif type == "house" then
PreSpawnPlayer ()
TriggerServerEvent ( 'QBCore:Server:OnPlayerLoaded' )
TriggerEvent ( 'QBCore:Client:OnPlayerLoaded' )
local property_id = data.spawnloc.property_id
TriggerServerEvent ( 'ps-housing:server:enterProperty' , tostring (property_id))
PostSpawnPlayer ()
elseif type == "normal" then
local pos = QB.Spawns[location].coords
PreSpawnPlayer ()
SetEntityCoords (ped, pos.x, pos.y, pos.z)
TriggerServerEvent ( 'QBCore:Server:OnPlayerLoaded' )
TriggerEvent ( 'QBCore:Client:OnPlayerLoaded' )
TriggerServerEvent ( 'ps-housing:server:resetMetaData' )
SetEntityCoords (ped, pos.x, pos.y, pos.z)
SetEntityHeading (ped, pos.w)
PostSpawnPlayer ()
end
cb ( 'ok' )
end )
Copy qb-spawn > server.lua > line 3
Copy QBCore.Functions. CreateCallback ( 'qb-spawn:server:getOwnedHouses' , function ( _ , cb , cid )
if cid ~= nil then
local houses = MySQL.query. await ( 'SELECT * FROM properties WHERE owner_citizenid = ?' , {cid})
if houses[ 1 ] ~= nil then
cb (houses)
else
cb ({})
end
else
cb ({})
end
end )
3. Find the following events in qb-garages
and change:
Copy qb-garages > server > main.lua > around line 120 on event qb-garage:server:checkOwnership
Replace
Copy local hasHouseKey = exports[ 'qb-houses' ]: hasKey (result[ 1 ].license, result[ 1 ].citizenid, house)
With
Copy local hasHouseKey = exports[ 'ps-housing' ]: IsOwner (src, house)
Copy qb-garages > client > main.lua > around line 451 add under event qb-garages:client:addHouseGarage
Copy RegisterNetEvent ( 'qb-garages:client:removeHouseGarage' , function ( house )
Config.HouseGarages[house] = nil
end )
For qb-garages V2:
Replace
Copy if type == 'house' and not exports[ 'qb-houses' ]: hasKey (Player.PlayerData.license, Player.PlayerData.citizenid, Config.HouseGarages[garage].label) then
With
Copy if type == 'house' and not exports[ 'ps-housing' ]: IsOwner (source, garage) then
Copy qb-garages > client > main.lua > around line 392 add under event qb-garages:client:addHouseGarage
Copy RegisterNetEvent ( 'qb-garages:client:removeHouseGarage' , function ( house )
Config.Garages[house] = nil
end
4. Run the properties.sql
file, but be cautious. If a table named properties
already exists in your database, this operation will drop it, resulting in the loss of all its data.
7. Delete qb-apartments/config.lua
references in qb-spawn
, qb-multicharacter
and qb-phone
fxmanifest.lua (and any other scripts that may reference it).
8. Install the dependencies.
Server.cfg Resource Order
Copy ensure ox_lib
ensure ps-housing
ensure ps-realtor
ensure fivem-freecam
Notes
If a player is in their apartment/house and an admin does a "Bring to me" function, they will not see the player nor will the player see anyone else. This is because the player is still in their own unique routing bucket. Workaround : To fix this, the player must go back into their apartment and leave on their own.
Likewise, if an admin tries to "Go to" or "Spectate" a player that is in their apartment/house, the admin will not be able to see the apartment or player because it is in a different routing bucket.
We highly recommend making a folder named [ps-housing] and adding ps-realtor
, fivem-freecam
, ox_lib
, ps-housing
inside the folder.
Logs System Setup
Go to qb-smallresources/server/logs.lua
and add this:
Copy ['pshousing'] = 'yourdiscordwebhookhere',
Create a webhook for the channel you want the logs to show up in.
Replace the placeholder with your webhook link.
This system only supports qb-core for now.
Item Limits System
Choose an item you want to limit under Config.Furniture
in under shared/config.lua
Add ["max"] = 3
or the number of your choice to the item (see example below)
Copy { [ "object" ] = "v_res_r_figcat" , [ "price" ] = 300 , [ "max" ] = 2 , [ "label" ] = "Fig Cat" },
Resolving the "Foreign key constraint is incorrectly formed" Issue
If you come across an error such as Foreign key constraint is incorrectly formed
while importing the properties.sql
into your database, follow these steps to fix it.
Open your database in HeidiSQL.
Right-click on your database name and select "Edit."
Locate the database collation setting and take note of it.
You will need to format the properties.sql
file to match your database collation.
If your database collation is set to utf8mb4_general_ci
, modify the last line of the properties.sql
file using VSCode or in HeidiSQL's query tab to the following:
Copy ) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 COLLATE= utf8mb4_general_ci;
This adjustment ensures that properties.sql
file's character set and collation match that of your database, effectively resolving the issue.