config.server.lua
Preview File Updated: v1.4.1 - 05/05/2026
SV = {}
-- ██╗ ██╗███████╗██████╗ ██╗ ██╗ ██████╗ ██████╗ ██╗ ██╗███████╗
-- ██║ ██║██╔════╝██╔══██╗██║ ██║██╔═══██╗██╔═══██╗██║ ██╔╝██╔════╝
-- ██║ █╗ ██║█████╗ ██████╔╝███████║██║ ██║██║ ██║█████╔╝ ███████╗
-- ██║███╗██║██╔══╝ ██╔══██╗██╔══██║██║ ██║██║ ██║██╔═██╗ ╚════██║
-- ╚███╔███╔╝███████╗██████╔╝██║ ██║╚██████╔╝╚██████╔╝██║ ██╗███████║
-- ╚══╝╚══╝ ╚══════╝╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝
SV.Webhook = function(data)
if Config.Logs == 'fivemanage' then
exports.fmsdk:LogMessage(
"info",
'[VMS Housing] ' .. data.title,
data.metadata
)
else
local token = Webhooks[data.id]
if not token or token == "" then
return
end
local embeds = {{
["title"] = data.title,
["type"] = "rich",
["description"] = data.description,
["color"] = 0,
["footer"] = {
["text"] = data.footer .. ' - ' .. os.date(),
},
}}
PerformHttpRequest(token, function(err, text, headers) end, 'POST', json.encode({embeds = embeds}), {['Content-Type'] = 'application/json'})
end
end
-- ███████╗██████╗ █████╗ ███╗ ███╗███████╗██╗ ██╗ ██████╗ ██████╗ ██╗ ██╗
-- ██╔════╝██╔══██╗██╔══██╗████╗ ████║██╔════╝██║ ██║██╔═══██╗██╔══██╗██║ ██╔╝
-- █████╗ ██████╔╝███████║██╔████╔██║█████╗ ██║ █╗ ██║██║ ██║██████╔╝█████╔╝
-- ██╔══╝ ██╔══██╗██╔══██║██║╚██╔╝██║██╔══╝ ██║███╗██║██║ ██║██╔══██╗██╔═██╗
-- ██║ ██║ ██║██║ ██║██║ ╚═╝ ██║███████╗╚███╔███╔╝╚██████╔╝██║ ██║██║ ██╗
-- ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ ╚══╝╚══╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝
SV.GetPlayer = function(src)
if Config.Core == "ESX" then
return Core.GetPlayerFromId(src)
elseif Config.Core == "QB-Core" then
return Core.Functions.GetPlayer(src)
end
end
SV.GetSource = function(xPlayer)
if Config.Core == "ESX" then
return xPlayer.source
elseif Config.Core == "QB-Core" then
return xPlayer.PlayerData.source
end
end
SV.GetIdentifier = function(xPlayer)
if Config.Core == "ESX" then
return xPlayer.identifier
elseif Config.Core == "QB-Core" then
return xPlayer.PlayerData.citizenid
end
end
SV.GetPlayerByIdentifier = function(identifier)
if Config.Core == "ESX" then
return Core.GetPlayerFromIdentifier(identifier)
elseif Config.Core == "QB-Core" then
return Core.Functions.GetPlayerByCitizenId(identifier)
end
end
SV.GetCharacterName = function(xPlayer, offline)
if Config.Core == "ESX" then
if offline then
local response = MySQL.query.await('SELECT `firstname`, `lastname` FROM `users` WHERE `identifier` = ?', {
xPlayer.identifier
})
if response then
local data = response[1]
return data.firstname .. ' ' .. data.lastname
end
else
return xPlayer.getName()
end
elseif Config.Core == "QB-Core" then
if offline then
local response = MySQL.query.await('SELECT `charinfo` FROM `players` WHERE `citizenid` = ?', {
xPlayer.identifier
})
if response then
local data = response[1]
local charinfo = json.decode(data.charinfo)
return charinfo.firstname .. ' ' .. charinfo.lastname
end
else
return xPlayer.PlayerData.charinfo.firstname .. ' ' .. xPlayer.PlayerData.charinfo.lastname
end
end
end
SV.GetPlayerGroup = function(xPlayer)
if Config.Core == "ESX" then
return xPlayer.group
elseif Config.Core == "QB-Core" then
if GetResourceState('qbx_core') == 'started' then
-- Sort your permissions from highest to lowest so that when it detects the highest role, the function returns the highest one!
if IsPlayerAceAllowed(xPlayer.PlayerData.source, 'god') then
return 'god'
elseif IsPlayerAceAllowed(xPlayer.PlayerData.source, 'admin') then
return 'admin'
elseif IsPlayerAceAllowed(xPlayer.PlayerData.source, 'mod') then
return 'mod'
elseif IsPlayerAceAllowed(xPlayer.PlayerData.source, 'support') then
return 'support'
end
else
local permissions = Core.Functions.GetPermission(xPlayer.PlayerData.source)
-- Sort your permissions from highest to lowest so that when it detects the highest role, the function returns the highest one!
if permissions['god'] then
return 'god'
elseif permissions['admin'] then
return 'admin'
elseif permissions['mod'] then
return 'mod'
end
end
return nil
end
end
SV.GetPlayerJob = function(xPlayer, type)
if Config.Core == "ESX" and xPlayer.job then
if type == "table" then
return xPlayer.job
end
if type == "name" then
return xPlayer.job.name
end
if type == "label" then
return xPlayer.job.label
end
if type == "grade" then
return xPlayer.job.grade
end
if type == "grade_name" then
return xPlayer.job.grade_name
end
elseif Config.Core == "QB-Core" and xPlayer.PlayerData.job then
if type == "table" then
return xPlayer.PlayerData.job
end
if type == "name" then
return xPlayer.PlayerData.job.name
end
if type == "label" then
return xPlayer.PlayerData.job.label
end
if type == "grade" then
return xPlayer.PlayerData.job.grade.level
end
if type == "grade_name" then
return xPlayer.PlayerData.job.grade.name
end
end
return nil
end
SV.GetJobsOnline = function(jobName)
if Config.Core == "ESX" then
return #Core.GetExtendedPlayers('job', jobName)
elseif Config.Core == "QB-Core" then
local players, count = Core.Functions.GetPlayersOnDuty(jobName)
return count
end
end
SV.RegisterCommand = function(command, groups, cb, help, suggestions)
if Config.Core == "ESX" then
local arguments = {}
if suggestions then
for k, v in pairs(suggestions) do
table.insert(arguments, {
name = v.name,
help = v.label,
type = 'any'
})
end
end
Core.RegisterCommand(command, groups, function(xPlayer, args, showError)
local src = SV.GetSource(xPlayer)
cb(src, args)
end, false, {
help = help,
arguments = arguments
})
elseif Config.Core == "QB-Core" then
local arguments = {}
if suggestions then
for k, v in pairs(suggestions) do
table.insert(arguments, {
name = v.name,
help = v.label
})
end
end
Core.Commands.Add(command, help, arguments, false, function(source, args)
cb(source, args)
end, groups)
end
end
-- ███╗ ███╗ ██████╗ ███╗ ██╗███████╗██╗ ██╗
-- ████╗ ████║██╔═══██╗████╗ ██║██╔════╝╚██╗ ██╔╝
-- ██╔████╔██║██║ ██║██╔██╗ ██║█████╗ ╚████╔╝
-- ██║╚██╔╝██║██║ ██║██║╚██╗██║██╔══╝ ╚██╔╝
-- ██║ ╚═╝ ██║╚██████╔╝██║ ╚████║███████╗ ██║
-- ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝ ╚═╝
SV.GetMoney = function(xPlayer, moneyType)
if Config.Core == "ESX" then
local moneyType = moneyType == 'cash' and 'money' or moneyType
return xPlayer.getAccount(moneyType).money
elseif Config.Core == "QB-Core" then
return xPlayer.Functions.GetMoney(moneyType)
end
end
---@class AddMoney
---@param reason string
---| 'automaticSale'
---| 'sellFurniture'
---| 'rentalBillPayment'
---| 'rentalContract'
---| 'salesContract'
---| 'salesMarketplace'
---| 'rentalMarketplace'
---| 'deliveredFurniture'
SV.AddMoney = function(xPlayer, moneyType, count, reason)
if Config.Core == "ESX" then
local moneyType = moneyType == 'cash' and 'money' or moneyType == 'dirty' and 'black_money' or moneyType
xPlayer.addAccountMoney(moneyType, count)
elseif Config.Core == "QB-Core" then
xPlayer.Functions.AddMoney(moneyType, count)
end
end
---@class RemoveMoney
---@param reason string
---| 'furniturePurchase'
---| 'purchaseProperty'
---| 'rentalProperty'
---| 'purchaseKey'
---| 'lockReplacement'
---| 'upgradeProperty'
---| 'serviceBillPayment'
---| 'rentalBillPayment'
---| 'rentalContract'
---| 'salesContract'
---| 'salesMarketplace'
---| 'rentalMarketplace'
SV.RemoveMoney = function(xPlayer, moneyType, count, reason)
if Config.Core == "ESX" then
local moneyType = moneyType == 'cash' and 'money' or moneyType
xPlayer.removeAccountMoney(moneyType, count)
elseif Config.Core == "QB-Core" then
xPlayer.Functions.RemoveMoney(moneyType, count)
end
end
---@class AddMoneyOffline
---@param reason string
---| 'rentalBillPayment'
---| 'salesMarketplace'
---| 'rentalMarketplace'
SV.AddMoneyOffline = function(identifier, moneyType, count, reason)
if Config.Core == "ESX" then
local moneyType = moneyType == 'cash' and 'money' or moneyType == 'dirty' and 'black_money' or moneyType
local data = MySQL.query.await("SELECT accounts FROM `users` WHERE `identifier` = @identifier", {
['@identifier'] = identifier
})
if not data or not data[1] then return end
local accounts = json.decode(data[1].accounts)
if not accounts or not accounts[moneyType] then return end
accounts[moneyType] = tonumber(accounts[moneyType]) + tonumber(count)
local updatedAccountsJson = json.encode(accounts)
MySQL.Async.execute('UPDATE `users` SET accounts = @accounts WHERE `identifier` = @identifier', {
['@accounts'] = updatedAccountsJson,
['@identifier'] = identifier
})
elseif Config.Core == "QB-Core" then
local data = MySQL.query.await("SELECT money FROM `players` WHERE `citizenid` = @citizenid", {
['@citizenid'] = identifier
})
if not data or not data[1] then return end
local accounts = json.decode(data[1].money)
if not accounts or not accounts[moneyType] then return end
accounts[moneyType] = tonumber(accounts[moneyType]) + tonumber(count)
local updatedAccountsJson = json.encode(accounts)
MySQL.Async.execute('UPDATE `players` SET money = @money WHERE `citizenid` = @citizenid', {
['@money'] = updatedAccountsJson,
['@citizenid'] = identifier
})
end
end
-- ██╗████████╗███████╗███╗ ███╗███████╗
-- ██║╚══██╔══╝██╔════╝████╗ ████║██╔════╝
-- ██║ ██║ █████╗ ██╔████╔██║███████╗
-- ██║ ██║ ██╔══╝ ██║╚██╔╝██║╚════██║
-- ██║ ██║ ███████╗██║ ╚═╝ ██║███████║
-- ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚══════╝
SV.RegisterUsableItem = function(name, cb)
if RegisterUsableItem then -- The script looks for functions in ./integration/[inventory]/*
RegisterUsableItem(name, cb)
else
if Config.Core == "ESX" then
Core.RegisterUsableItem(name, function(src, itemName, itemData)
cb(src, itemName, {metadata = itemData.metadata})
end)
elseif Config.Core == "QB-Core" then
Core.Functions.CreateUseableItem(name, function(src, item)
cb(src, item.name, {metadata = item.info})
end)
end
end
end
SV.GetItem = function(src, xPlayer, name, data, search)
if search == 'key' then
if GetItem then -- The script looks for functions in ./integration/[inventory]/*
return GetItem(src, xPlayer, 'house_key', data, search)
end
end
end
SV.GetItemCount = function(xPlayer, name)
if Config.Core == "ESX" then
return xPlayer.getInventoryItem(name).count
elseif Config.Core == "QB-Core" then
return xPlayer.Functions.GetItemByName(name) and xPlayer.Functions.GetItemByName(name).amount or 0
end
end
SV.AddItem = function(src, xPlayer, name, count, metadata)
if AddItem then -- The script looks for functions in ./integration/[inventory]/*
AddItem(src, xPlayer, name, count, metadata)
else
if Config.Core == "ESX" then
xPlayer.addInventoryItem(name, count)
elseif Config.Core == "QB-Core" then
xPlayer.Functions.AddItem(name, count)
end
end
end
SV.RemoveItem = function(src, xPlayer, name, count)
if RemoveItem then -- The script looks for functions in ./integration/[inventory]/*
RemoveItem(src, xPlayer, name, count)
else
if Config.Core == "ESX" then
xPlayer.removeInventoryItem(name, count)
elseif Config.Core == "QB-Core" then
xPlayer.Functions.RemoveItem(name, count)
end
end
end
-- ██████╗██╗████████╗██╗ ██╗██╗ ██╗ █████╗ ██╗ ██╗
-- ██╔════╝██║╚══██╔══╝╚██╗ ██╔╝██║ ██║██╔══██╗██║ ██║
-- ██║ ██║ ██║ ╚████╔╝ ███████║███████║██║ ██║
-- ██║ ██║ ██║ ╚██╔╝ ██╔══██║██╔══██║██║ ██║
-- ╚██████╗██║ ██║ ██║ ██║ ██║██║ ██║███████╗███████╗
-- ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚══════╝
SV.AddTax = function(identifier, characterName, propertyName, propertyAddress, type, fromAmount)
local isCityHall = GetResourceState('vms_cityhall') == 'started'
if not isCityHall then return false end
if not Config.CityHallTaxes then return false end
local amount = 0
local percentage = 0
if type == 'property_purchase_tax' then
if Config.CityHallTaxes.PropertyPurchase.Type == 'percentage' then
amount = fromAmount
percentage = Config.CityHallTaxes.PropertyPurchase.Value
else
amount = Config.CityHallTaxes.PropertyPurchase.Value
percentage = 100
end
if amount >= 1 and percentage >= 1 then
exports['vms_cityhall']:addPlayerCustomTaxToPay({
identifier = identifier,
characterName = characterName,
}, amount, percentage, (Config.CityHallTaxes.PropertyPurchase.Title):format(propertyName, propertyAddress))
end
elseif type == 'property_resale_tax' then
if Config.CityHallTaxes.PropertyResale.Type == 'percentage' then
amount = fromAmount
percentage = Config.CityHallTaxes.PropertyResale.Value
else
amount = Config.CityHallTaxes.PropertyResale.Value
percentage = 100
end
if amount >= 1 and percentage >= 1 then
exports['vms_cityhall']:addPlayerCustomTaxToPay({
identifier = identifier,
characterName = characterName,
}, amount, percentage, (Config.CityHallTaxes.PropertyResale.Title):format(propertyName, propertyAddress))
end
elseif type == 'rental_income_tax' then
if Config.CityHallTaxes.RentalIncome.Type == 'percentage' then
amount = fromAmount
percentage = Config.CityHallTaxes.RentalIncome.Value
else
amount = Config.CityHallTaxes.RentalIncome.Value
percentage = 100
end
if amount >= 1 and percentage >= 1 then
exports['vms_cityhall']:addPlayerCustomTaxToPay({
identifier = identifier,
characterName = characterName,
}, amount, percentage, (Config.CityHallTaxes.RentalIncome.Title):format(propertyName, propertyAddress))
end
elseif type == 'property_cadastral_tax' then
if Config.CityHallTaxes.PropertyCadastralTax.Type == 'percentage' then
amount = fromAmount
percentage = Config.CityHallTaxes.PropertyCadastralTax.Value
else
amount = Config.CityHallTaxes.PropertyCadastralTax.Value
percentage = 100
end
if amount >= 1 and percentage >= 1 then
exports['vms_cityhall']:addPlayerCustomTaxToPay({
identifier = identifier,
characterName = characterName,
}, amount, percentage, (Config.CityHallTaxes.PropertyCadastralTax.Title):format(propertyName, propertyAddress))
end
elseif type == 'agency_rental_income_tax' then
if Config.CityHallTaxes.AgencyRentalIncome.Type == 'percentage' then
amount = fromAmount
percentage = Config.CityHallTaxes.AgencyRentalIncome.Value
else
amount = Config.CityHallTaxes.AgencyRentalIncome.Value
percentage = 0
end
if percentage == 0 then
exports['vms_cityhall']:addCompanyFlatTaxAmount(identifier, amount)
else
exports['vms_cityhall']:addCompanyCustomTaxAmount(identifier, amount, percentage)
end
elseif type == 'agency_purchase_tax' then
if Config.CityHallTaxes.AgencyPropertyPurchase.Type == 'percentage' then
amount = fromAmount
percentage = Config.CityHallTaxes.AgencyPropertyPurchase.Value
else
amount = Config.CityHallTaxes.AgencyPropertyPurchase.Value
percentage = 0
end
if percentage == 0 then
exports['vms_cityhall']:addCompanyFlatTaxAmount(identifier, amount)
else
exports['vms_cityhall']:addCompanyCustomTaxAmount(identifier, amount, percentage)
end
elseif type == 'agency_resale_tax' then
if Config.CityHallTaxes.AgencyPropertyResale.Type == 'percentage' then
amount = fromAmount
percentage = Config.CityHallTaxes.AgencyPropertyResale.Value
else
amount = Config.CityHallTaxes.AgencyPropertyResale.Value
percentage = 0
end
if percentage == 0 then
exports['vms_cityhall']:addCompanyFlatTaxAmount(identifier, amount)
else
exports['vms_cityhall']:addCompanyCustomTaxAmount(identifier, amount, percentage)
end
elseif type == 'project_sale_tax' then
if Config.CityHallTaxes.AuthorProjectSale.Type == 'percentage' then
amount = fromAmount
percentage = Config.CityHallTaxes.AuthorProjectSale.Value
else
amount = Config.CityHallTaxes.AuthorProjectSale.Value
percentage = 100
end
if amount >= 1 and percentage >= 1 then
exports['vms_cityhall']:addPlayerCustomTaxToPay({
identifier = identifier,
characterName = characterName,
}, amount, percentage, (Config.CityHallTaxes.AuthorProjectSale.Title):format(propertyName))
end
elseif type == 'studio_project_sale_tax' then
if Config.CityHallTaxes.StudioProjectSale.Type == 'percentage' then
amount = fromAmount
percentage = Config.CityHallTaxes.StudioProjectSale.Value
else
amount = Config.CityHallTaxes.StudioProjectSale.Value
percentage = 100
end
if percentage == 0 then
exports['vms_cityhall']:addCompanyFlatTaxAmount(identifier, amount)
else
exports['vms_cityhall']:addCompanyCustomTaxAmount(identifier, amount, percentage)
end
end
return true -- DO NOT REMOVE!
end
-- ██╗ ██╗ █████╗ ██████╗ ██╗ █████╗ ██████╗ ██╗ ███████╗███████╗
-- ██║ ██║██╔══██╗██╔══██╗██║██╔══██╗██╔══██╗██║ ██╔════╝██╔════╝
-- ██║ ██║███████║██████╔╝██║███████║██████╔╝██║ █████╗ ███████╗
-- ╚██╗ ██╔╝██╔══██║██╔══██╗██║██╔══██║██╔══██╗██║ ██╔══╝ ╚════██║
-- ╚████╔╝ ██║ ██║██║ ██║██║██║ ██║██████╔╝███████╗███████╗███████║
-- ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚══════╝╚══════╝
SV.CanEnterHouse = function(src, xPlayer)
-- This function is triggered when a player tries to enter the property.
-- You can return false to block access, for example if they are handcuffed or anything else
return true
end
SV.CanExitHouse = function(src, xPlayer)
-- This function is triggered when a player tries to exit the property.
-- You can return false to block access, for example if they are handcuffed or anything else
return true
endLast updated