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:
qb-multicharacter > server > main.lua
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)
qb-multicharacter > server > main.lua
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:
qb-spawn > client.lua > line 51 > 'qb-spawn:client:setupSpawns' event
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)
qb-spawn > client.lua > line 134 > 'chooseAppa' NUI Callback
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)
qb-spawn > server.lua > line 3
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:
qb-garages > server > main.lua > around line 120 on event qb-garage:server:checkOwnership
Replace
local hasHouseKey = exports['qb-houses']:hasKey(result[1].license, result[1].citizenid, house)
With
local hasHouseKey = exports['ps-housing']:IsOwner(src, house)
qb-garages > client > main.lua > around line 451 add under event qb-garages:client:addHouseGarage
if type == 'house' and not exports['qb-houses']:hasKey(Player.PlayerData.license, Player.PlayerData.citizenid, Config.HouseGarages[garage].label) then
With
if type == 'house' and not exports['ps-housing']:IsOwner(source, garage) then
qb-garages > client > main.lua > around line 392 add under event qb-garages:client:addHouseGarage
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).
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:
['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)
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: