Installation

Guide for installing ps-housing

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:

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('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)
qb-spawn > client > client.lua > line 169 'spawnplayer' 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
RegisterNetEvent('qb-garages:client:removeHouseGarage', function(house)
    Config.HouseGarages[house] = nil
end)

For qb-garages V2:

Replace

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.

5. Delete default qb-apartments

6. Delete default qb-houses

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

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

  1. Go to qb-smallresources/server/logs.lua and add this:

    ['pshousing'] = 'yourdiscordwebhookhere',
  1. Create a webhook for the channel you want the logs to show up in.

  2. Replace the placeholder with your webhook link.

This system only supports qb-core for now.

Item Limits System

  1. Choose an item you want to limit under Config.Furniture in under shared/config.lua

  2. Add ["max"] = 3 or the number of your choice to the item (see example below)

{ ["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.

  1. Open your database in HeidiSQL.

  2. Right-click on your database name and select "Edit."

  3. Locate the database collation setting and take note of it.

  4. 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:

) 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.

Last updated