structura foldere

mutat kq- folders in un singur folder [kq]
This commit is contained in:
2026-03-30 01:55:03 +03:00
parent af1286d583
commit c291b81f26
2319 changed files with 0 additions and 14 deletions

View File

@@ -0,0 +1,23 @@
if Config.Billing ~= 'RxBilling' then return end
---@param src number
---@return Invoice[]
function GetInvoices(src)
local identifier = GetIdentifier(src)
local invoices = exports.RxBilling:GetPlayerInvoices(identifier, 'incoming')
local data = {}
for k, v in pairs(invoices) do
if v.status ~= 'pending' then goto continue end
table.insert(data, {
id = v.id,
price = v.amount,
label = v.reason or 'No reason',
})
::continue::
end
return data
end

View File

@@ -0,0 +1,26 @@
if Config.Billing ~= 'codemv2' then return end
---@param source number
---@return Invoice[]
function GetInvoices(source)
local src = source
local bills = exports['codem-billingv2']:GetPlayerUnpaidBillings(src)
local data = {}
if bills then
for _, v in pairs(bills) do
table.insert(data, {
id = v.invoiceid,
price = v.amount,
label = v.reason,
})
end
end
return data
end
RegisterNetEvent('codemBilling:PayInvoice', function(invoiceId)
local src = source
exports['codem-billingv2']:PayBilling(src, invoiceId)
end)

View File

@@ -0,0 +1,19 @@
if Config.Billing ~= 'esx_billing' then return end
---@param source number
---@return Invoice[]
function GetInvoices(source)
local xPlayer = ESX.GetPlayerFromId(source)
local invoices = MySQL.query.await('SELECT amount, id, label FROM billing WHERE identifier = ?', { xPlayer.identifier })
local data = {}
for k, v in pairs(invoices) do
table.insert(data, {
id = v.id,
price = v.amount,
label = v.label or 'No reason',
})
end
return data
end

View File

@@ -0,0 +1,21 @@
if Config.Billing ~= 'okok' then return end
---@param source number
---@return Invoice[]
function GetInvoices(source)
local src = source
local identifier = GetIdentifier(src)
local invoices = MySQL.Sync.fetchAll('SELECT * FROM okokbilling WHERE receiver_identifier = ? ORDER BY CASE WHEN status = "unpaid" THEN 1 WHEN status = "autopaid" THEN 2 WHEN status = "paid" THEN 3 WHEN status = "cancelled" THEN 4 END ASC, id DESC', { identifier })
local data = {}
for k, v in pairs(invoices) do
if v.status == 'paid' then goto continue end
table.insert(data, {
id = v.id,
price = v.invoice_value,
label = v.notes or 'No reason',
})
::continue::
end
return data
end

View File

@@ -0,0 +1,22 @@
if Config.Billing ~= 'qs' then return end
---@param source number
---@return Invoice[]
function GetInvoices(source)
local src = source
local identifier = GetIdentifier(src)
-- Consulta ajustada a la tabla qs_billing
local invoices = MySQL.Sync.fetchAll('SELECT * FROM qs_billing WHERE receiver_identifier = ? ORDER BY CASE WHEN status = "unpaid" THEN 1 WHEN status = "autopaid" THEN 2 WHEN status = "paid" THEN 3 WHEN status = "cancelled" THEN 4 END ASC, id DESC', { identifier })
local data = {}
for k, v in pairs(invoices) do
-- Ignora facturas no pagadas
if v.status == 'unpaid' then goto continue end
table.insert(data, {
id = v.id,
price = v.invoice_value, -- Mapeo directo de invoice_value
label = v.notes or 'No reason', -- Mapeo directo de notes
})
::continue::
end
return data
end

View File

@@ -0,0 +1,43 @@
if Config.Billing ~= 'standalone' then return end
---@param source number
---@return Invoice[]
function GetInvoices(source)
local src = source
local identifier = GetIdentifier(src)
local invoices = MySQL.Sync.fetchAll('SELECT * FROM phone_bills WHERE `identifier` = ?', { identifier })
return invoices
end
RegisterCommand('sendbill', function(source, args)
local job = GetJobName(source)
local existJob = table.find(Config.BillJobs, function(v)
return v == job
end)
if not existJob then
return TriggerClientEvent('phone:client:sendTextMessage', source, Lang('PHONE_NOTIFICATION_BANK_BILL_WHITELIST'), 'error')
end
local target = tonumber(args[1])
local price = tonumber(args[2])
local reason = table.concat(args, ' ', 3)
reason = reason == '' and Lang('PHONE_NOTIFICATION_BANK_INVOICE_NO_REASON') or reason
if not target or not price then
return TriggerClientEvent('phone:client:sendTextMessage', source, Lang('PHONE_NOTIFICATION_BANK_NO_PLAYER'), 'error')
end
local identifier = GetIdentifier(target)
if not identifier then
return TriggerClientEvent('phone:client:sendTextMessage', source, Lang('PHONE_NOTIFICATION_BANK_NO_PLAYER'), 'error')
end
MySQL.Sync.execute('INSERT INTO `phone_bills` (`identifier`, `sender`, `price`, `label`) VALUES (?, ?, ?, ?)', {
identifier,
GetIdentifier(source),
price,
reason
})
TriggerClientEvent('phone:client:sendTextMessage', source, Lang('PHONE_NOTIFICATION_BANK_BILL_SENT') .. ' ' .. GetPlayerName(target), 'success')
TriggerClientEvent('phone:sendNotificationOld', target, {
app = 'bank',
title = Lang('PHONE_NOTIFICATION_BANK_TITLE'),
text = Lang('PHONE_NOTIFICATION_BANK_BILL_RECEIVED') .. ' ' .. GetPlayerName(source)
})
end, false)

View File

@@ -0,0 +1,91 @@
-- These are examples of how to use the custom functions in the server.
-- Example of how to use the sendNewMail export.
RegisterCommand('mailTest', function(source)
exports['qs-smartphone-pro']:sendNewMail(source, {
sender = 'Quasar',
subject = 'Es tu culpa',
message = 'Es tu culpa que no haya un ejemplo de como usar esto...'
})
end, false)
-- You can get phone name by using this export. It returns all phone names.
RegisterCommand('phoneNames', function(source)
local phoneNames = exports['qs-smartphone-pro']:getPhoneNames()
print(json.encode(phoneNames, { indent = true }))
end, false)
-- This export returns player's phone number. If the user has used the phone. It prioritizes that phone. If the user has never used a phone, it returns the phone number of any phone from its inventory.
RegisterCommand('getPhone', function(source, args)
local identifier = GetIdentifier(source) -- This is a player identifier. Like ESX.GetPlayerFromId(source).identifier
local mustBePhoneOwner = true -- If its true, checks phone owner is the identifier. So you can handle to a stolen phone.
local number = exports['qs-smartphone-pro']:GetPhoneNumberFromIdentifier(identifier, mustBePhoneOwner)
print(number) -- phone number or false
end, false)
-- This export returns player's currently using or last used phone meta
RegisterCommand('getMeta', function(source, args)
local meta = exports['qs-smartphone-pro']:getMetaFromSource(source)
print(json.encode(meta, { indent = true })) -- phone meta or false
end, false)
-- This export sends a new message to a phone number.
RegisterCommand('sendNewMessage', function(source, args)
local identifier = GetIdentifier(source)
local sender = exports['qs-smartphone-pro']:GetPhoneNumberFromIdentifier(identifier, false) -- Sender phone number
local target = '293823' -- Target phone number
local message = 'Hello world!'
local type = 'message' -- message or location
exports['qs-smartphone-pro']:sendNewMessage(sender, target, message, type)
end, false)
-- This export sends a SOS message to a phone number.
RegisterCommand('sendSOSMessage', function(source, args)
local src = source
local identifier = GetIdentifier(src)
local phoneNumber = exports['qs-smartphone-pro']:GetPhoneNumberFromIdentifier(identifier, false) -- Sender phone number
local job = 'ambulance'
local coords = GetEntityCoords(GetPlayerPed(src))
exports['qs-smartphone-pro']:sendSOSMessage(phoneNumber, job, json.encode(coords), 'location')
end, false)
-- This export sends a new message from a app. You can use this to send a message from a app.
RegisterCommand('sendNewMessageFromApp', function(source, args)
local src = source
local identifier = GetIdentifier(src)
local phone = exports['qs-smartphone-pro']:GetPhoneNumberFromIdentifier(identifier, false) -- Sender phone number
local message = 'Quasar: Hello from twitter!'
local appName = 'twitter'
exports['qs-smartphone-pro']:sendNewMessageFromApp(src, phone, message, appName)
end, false)
-- This export sends a new notification to a phone number.
RegisterCommand('sendNewNotification', function(source, args)
local phone = exports['qs-smartphone-pro']:GetPhoneNumberFromIdentifier(GetIdentifier(source), false)
local disableTempNotification = false -- Disables the temporary notification. (Pop up notification)
exports['qs-smartphone-pro']:sendNotification(phone, {
app = 'twitter',
msg = 'Hello world!',
head = 'Quasar'
}, disableTempNotification)
end, false)
-- Same as sendNewNotification
RegisterCommand('sendNewNotification', function(source, args)
local phone = exports['qs-smartphone-pro']:GetPhoneNumberFromIdentifier(GetIdentifier(source), false)
local disableTempNotification = false -- Disables the temporary notification. (Pop up notification)
exports['qs-smartphone-pro']:sendNotificationOld(phone, {
app = 'twitter',
msg = 'Hello world!',
head = 'Quasar'
}, disableTempNotification)
end, false)
RegisterCommand('sendNewMessage', function(source, args)
local phone = '323'
local targetPhone = '123'
local message = 'Hello'
local type = 'message' -- message, location
local success = exports['qs-smartphone-pro']:sendNewMessage(phone, targetPhone, message, type)
print('Success: ', success)
end, false)

View File

@@ -0,0 +1,197 @@
--[[
Hi dear customer or developer, here you can fully configure your server's
framework or you could even duplicate this file to create your own framework.
If you do not have much experience, we recommend you download the base version
of the framework that you use in its latest version and it will work perfectly.
]]
if Config.Framework ~= 'esx' then
return
end
ESX = nil
local legacyEsx = pcall(function()
ESX = exports['es_extended']:getSharedObject()
end)
if not legacyEsx then
TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end)
end
identifierTable = 'identifier'
userColumn = 'users'
garageTable = 'owned_vehicles'
garageIdentifierColumn = 'owner'
RegisterNetEvent('esx:playerLoaded', function(id, data)
Wait(2000)
Debug('Loaded player:', id)
CreateQuests(id)
end)
CreateThread(function()
for k, v in pairs(ESX.Players) do
if v and v.source then
Debug('Loaded player:', v.source)
CreateQuests(v.source)
end
end
end)
function RegisterServerCallback(name, cb)
ESX.RegisterServerCallback(name, cb)
end
exports('RegisterServerCallback', RegisterServerCallback)
function RegisterUsableItem(name, cb)
ESX.RegisterUsableItem(name, cb)
end
function GetPlayerFromId(source)
return ESX.GetPlayerFromId(source)
end
function GetPlayerFromIdentifier(identifier)
if not identifier then return nil end
identifier = string.gsub(identifier, ' ', '')
return ESX.GetPlayerFromIdentifier(identifier)
end
function GetItem(player, item)
return player.getInventoryItem(item)
end
function GetCrypto(identifier)
local str = ([[
SELECT cryptocurrency FROM %s WHERE %s = ? LIMIT 1
]]):format(userColumn, identifierTable)
local result = MySQL.Sync.fetchAll(str, { identifier })
if not result[1] or not result[1].cryptocurrency then
return 0
end
return result[1].cryptocurrency
end
function AddItem(source, item, count, slot, metadata)
local player = GetPlayerFromId(source)
player.addInventoryItem(item, count, metadata, slot)
end
function AddWeapon(source, weapon, ammo)
local player = GetPlayerFromId(source)
player.addWeapon(weapon, ammo)
end
function RemoveItem(source, item, count, slot)
local player = GetPlayerFromId(source)
player.removeInventoryItem(item, count, nil, slot)
end
function GetBankMoney(source)
local player = GetPlayerFromId(source)
return player.getAccount('bank').money
end
function SetJob(source, job, grade)
local player = GetPlayerFromId(source)
player.setJob(job, grade)
end
function AddBankMoney(source, amount)
local player = GetPlayerFromId(source)
player.addAccountMoney('bank', amount)
end
function RemoveBankMoney(source, amount)
local player = GetPlayerFromId(source)
player.removeAccountMoney('bank', amount)
end
function GetJobName(source)
local player = GetPlayerFromId(source)
if not player then return 'unemployed' end
return player.getJob().name
end
function IsAdmin(source)
local player = GetPlayerFromId(source)
return player.getGroup() == 'admin'
end
function GetIdentifier(source)
local player = GetPlayerFromId(source)
if not player then
print('ESX player not found. Source: ', source)
return false
end
return player.identifier
end
function GetItems(player)
if not player then return end
if Config.Inventory == 'codem-inventory' then
local inventory = player.getInventory()
for k, v in pairs(inventory) do
if tonumber(v.amount) <= 0 then
inventory[k] = nil
elseif not Config.UniquePhone and not v.info then
inventory[k].info = {}
inventory[k].metadata = {}
end
end
return inventory
elseif Config.Inventory == 'tgiann-inventory' then
local inventory = exports['tgiann-inventory']:GetPlayerItems(player.source)
for k, v in pairs(inventory) do
if tonumber(v.amount) <= 0 then
inventory[k] = nil
elseif not Config.UniquePhone and not v.info then
inventory[k].info = {}
inventory[k].metadata = {}
end
end
return inventory
else
local inventory = player.getInventory()
for k, v in pairs(inventory) do
local count = v.count or v.amount or 0
if count <= 0 then
inventory[k] = nil
elseif not Config.UniquePhone and not v.info then
inventory[k].info = {}
inventory[k].metadata = {}
end
end
return inventory
end
end
function GetPlayerSource(player)
return player.source
end
function GetDataForWithOutMetaData(source)
local player = GetPlayerFromId(source)
local identifier = GetIdentifier(source)
local result = MySQL.Sync.fetchAll('SELECT * FROM phone_metadata WHERE owneridentifier = ?', {
identifier
})
result = result[1]
if result then return json.decode(result.metadata) end
local info
local firstname, lastname, phone = GetUserData(identifier)
info = CreatePhoneMetaData({
firstname = firstname,
lastname = lastname,
identifier = identifier,
phone = phone
})
MySQL.Async.execute('INSERT INTO phone_metadata (owneridentifier, metadata, phoneNumber) VALUES (?, ?, ?)', {
identifier,
json.encode(info),
info.phoneNumber
})
return info
end

View File

@@ -0,0 +1,173 @@
--[[
Hi dear customer or developer, here you can fully configure your server's
framework or you could even duplicate this file to create your own framework.
If you do not have much experience, we recommend you download the base version
of the framework that you use in its latest version and it will work perfectly.
]]
if Config.Framework ~= 'qb' then
return
end
ESX = exports['qb-core']:GetCoreObject()
identifierTable = 'citizenid'
userColumn = 'players'
garageTable = 'player_vehicles'
garageIdentifierColumn = 'citizenid'
function RegisterServerCallback(name, cb)
ESX.Functions.CreateCallback(name, cb)
end
exports('RegisterServerCallback', RegisterServerCallback)
function RegisterUsableItem(name, cb)
ESX.Functions.CreateUseableItem(name, cb)
end
RegisterNetEvent('QBCore:Server:OnPlayerLoaded', function()
local src = source
if CheckWalletId then
CheckWalletId(src)
end
CreateQuests(src)
end)
CreateThread(function()
for k, v in pairs(ESX.Functions.GetPlayers()) do
Debug('Loaded player:', v)
if v then
CreateQuests(v)
end
end
end)
function GetPlayerFromId(source)
source = tonumber(source)
return ESX.Functions.GetPlayer(source)
end
function GetPlayerFromIdentifier(identifier)
identifier = string.gsub(identifier, ' ', '')
return ESX.Functions.GetPlayerByCitizenId(identifier)
end
function GetItem(player, item)
local data = player.Functions.GetItemByName(item)
data.count = data.amount
return data
end
function AddItem(source, item, count, slot, metadata)
local player = GetPlayerFromId(source)
player.Functions.AddItem(item, count, slot, metadata)
end
function GetCrypto(identifier)
local str = ([[
SELECT cryptocurrency FROM %s WHERE %s = ? LIMIT 1
]]):format(userColumn, identifierTable)
local result = MySQL.Sync.fetchAll(str, { identifier })
if not result[1] or not result[1].cryptocurrency then
return 0
end
return result[1].cryptocurrency
end
function RemoveItem(source, item, count, slot)
local player = GetPlayerFromId(source, true)
player.Functions.RemoveItem(item, count, slot)
end
function GetBankMoney(source)
local player = GetPlayerFromId(source)
return player.PlayerData.money.bank
end
function SetJob(source, job, grade)
local player = GetPlayerFromId(source)
player.Functions.SetJob(job, grade)
end
function AddBankMoney(source, amount)
local player = GetPlayerFromId(source)
player.Functions.AddMoney('bank', amount)
end
function RemoveBankMoney(source, amount)
local player = GetPlayerFromId(source)
player.Functions.RemoveMoney('bank', amount)
end
function GetJobName(source)
local player = GetPlayerFromId(source)
return player.PlayerData.job.name
end
function IsAdmin(source)
if source == 0 then
return true
end
return ESX.Functions.HasPermission(source, 'god') or IsPlayerAceAllowed(source, 'command') or ESX.Functions.HasPermission(source, 'admin')
end
function GetIdentifier(source)
local player = GetPlayerFromId(source)
if not player then
print('ESX player not found. Source: ', source)
return false
end
return player.PlayerData.citizenid
end
function GetItems(player)
if not player then return false end
if Config.Inventory == 'origen_inventory' then
local userData = OrigenInventory:getInventory(player.PlayerData.source)
if not userData then return end
return userData.inventory
end
return player.PlayerData.items
end
function GetPlayerSource(player)
return player.PlayerData.source
end
function GetDataForWithOutMetaData(source)
local player = GetPlayerFromId(source)
local identifier = GetIdentifier(source)
local result = MySQL.Sync.fetchAll('SELECT * FROM phone_metadata WHERE owneridentifier = ?', {
identifier
})
result = result[1]
if result then return json.decode(result.metadata) end
local info
info = CreatePhoneMetaData({
firstname = player.PlayerData.charinfo.firstname,
lastname = player.PlayerData.charinfo.lastname,
identifier = identifier,
phone = player.PlayerData.charinfo.phone
})
MySQL.Async.execute('INSERT INTO phone_metadata (owneridentifier, metadata, phoneNumber) VALUES (?, ?, ?)', {
identifier,
json.encode(info),
info.phoneNumber
})
return info
end
RegisterServerCallback('phone:market:getPlayerData', function(_, cb, player)
local identifier = GetIdentifier(player)
local firstName, lastName, phoneNumber = GetUserData(identifier)
cb({
name = firstName .. ' ' .. lastName,
id = identifier,
})
end)
RegisterServerCallback('phone:market:getAccountBalance', function(source, cb, account)
cb(exports['qb-banking']:GetAccountBalance(account))
end)

View File

@@ -0,0 +1,161 @@
--[[
Hi dear customer or developer, here you can fully configure your server's
framework or you could even duplicate this file to create your own framework.
If you do not have much experience, we recommend you download the base version
of the framework that you use in its latest version and it will work perfectly.
]]
if Config.Framework ~= 'qbx' then
return
end
ESX = nil
ESX = exports['qb-core']:GetCoreObject()
identifierTable = 'citizenid'
userColumn = 'players'
function RegisterServerCallback(name, cb)
ESX.Functions.CreateCallback(name, cb)
end
exports('RegisterServerCallback', RegisterServerCallback)
function RegisterUsableItem(name, cb)
exports.qbx_core:CreateUseableItem(name, cb)
end
RegisterNetEvent('QBCore:Server:OnPlayerLoaded', function()
local src = source
if CheckWalletId then
CheckWalletId(src)
end
CreateQuests(src)
end)
CreateThread(function()
for k, v in pairs(QBCore.Functions.GetPlayers()) do
if v and v.source then
Debug('Loaded player:', v.source)
CreateQuests(v.source)
end
end
end)
function GetPlayerFromId(source)
source = tonumber(source)
return exports.qbx_core:GetPlayer(source)
end
function GetPlayerFromIdentifier(identifier)
identifier = string.gsub(identifier, ' ', '')
return exports.qbx_core:GetPlayerByCitizenId(identifier)
end
function GetItem(player, item)
local data = exports.ox_inventory:GetItem(player.PlayerData.source, item, nil, false)
return data
end
function AddItem(source, item, count, slot, metadata)
exports.ox_inventory:AddItem(source, item, count, metadata, slot)
end
function GetCrypto(identifier)
local str = ([[
SELECT cryptocurrency FROM %s WHERE %s = ? LIMIT 1
]]):format(userColumn, identifierTable)
local result = MySQL.Sync.fetchAll(str, { identifier })
if not result[1] or not result[1].cryptocurrency then
return 0
end
return result[1].cryptocurrency
end
function RemoveItem(source, item, count, slot)
exports.ox_inventory:RemoveItem(source, item, count, metadata, slot)
end
function GetBankMoney(source)
local player = GetPlayerFromId(source)
return player.PlayerData.money.bank
end
function SetJob(source, job, grade)
local player = GetPlayerFromId(source)
player.Functions.SetJob(job, grade)
end
function AddBankMoney(source, amount)
local player = GetPlayerFromId(source)
player.Functions.AddMoney('bank', amount)
end
function RemoveBankMoney(source, amount)
local player = GetPlayerFromId(source)
player.Functions.RemoveMoney('bank', amount)
end
function GetJobName(source)
local player = GetPlayerFromId(source)
return player.PlayerData.job.name
end
function IsAdmin(source)
if source == 0 then
return true
end
return exports.qbx_core:HasPermission(source, 'god') or IsPlayerAceAllowed(source, 'command') or exports.qbx_core:HasPermission(source, 'admin')
end
function GetIdentifier(source)
local player = GetPlayerFromId(source)
if not player then
print('ESX player not found. Source: ', source)
return false
end
return player.PlayerData.citizenid
end
function GetItems(player)
if not player then return false end
return exports.ox_inventory:GetInventoryItems(player.PlayerData.source)
end
function GetPlayerSource(player)
return player.PlayerData.source
end
function GetDataForWithOutMetaData(source)
local player = GetPlayerFromId(source)
local identifier = GetIdentifier(source)
local result = MySQL.Sync.fetchAll('SELECT * FROM phone_metadata WHERE owneridentifier = ?', {
identifier
})
result = result[1]
if result then return json.decode(result.metadata) end
local info
info = CreatePhoneMetaData({
firstname = player.PlayerData.charinfo.firstname,
lastname = player.PlayerData.charinfo.lastname,
identifier = identifier,
phone = player.PlayerData.charinfo.phone
})
MySQL.Async.execute('INSERT INTO phone_metadata (owneridentifier, metadata, phoneNumber) VALUES (?, ?, ?)', {
identifier,
json.encode(info),
info.phoneNumber
})
return info
end
RegisterServerCallback('phone:market:getPlayerData', function(_, cb, player)
local identifier = GetIdentifier(player)
local firstName, lastName, phoneNumber = GetUserData(identifier)
cb({
name = firstName .. ' ' .. lastName,
id = identifier,
})
end)

View File

@@ -0,0 +1,202 @@
--[[
Hi dear customer or developer, here you can fully configure your server's
framework or you could even duplicate this file to create your own framework.
If you do not have much experience, we recommend you download the base version
of the framework that you use in its latest version and it will work perfectly.
]]
if Config.Framework ~= 'standalone' then
return
end
-- ESX Callbacks
local serverCallbacks = {}
local clientRequests = {}
local RequestId = 0
---@param eventName string
---@param callback function
RegisterServerCallback = function(eventName, callback)
serverCallbacks[eventName] = callback
end
exports('RegisterServerCallback', RegisterServerCallback)
RegisterNetEvent('qs-smartphone-pro:triggerServerCallback', function(eventName, requestId, invoker, ...)
if not serverCallbacks[eventName] then
return print(('[^1ERROR^7] Server Callback not registered, name: ^5%s^7, invoker resource: ^5%s^7'):format(eventName, invoker))
end
local source = source
serverCallbacks[eventName](source, function(...)
TriggerClientEvent('qs-smartphone-pro:serverCallback', source, requestId, invoker, ...)
end, ...)
end)
---@param player number playerId
---@param eventName string
---@param callback function
---@param ... any
TriggerClientCallback = function(player, eventName, callback, ...)
clientRequests[RequestId] = callback
TriggerClientEvent('qs-smartphone-pro:triggerClientCallback', player, eventName, RequestId, GetInvokingResource() or 'unknown', ...)
RequestId = RequestId + 1
end
RegisterNetEvent('qs-smartphone-pro:clientCallback', function(requestId, invoker, ...)
if not clientRequests[requestId] then
return print(('[^1ERROR^7] Client Callback with requestId ^5%s^7 Was Called by ^5%s^7 but does not exist.'):format(requestId, invoker))
end
clientRequests[requestId](...)
clientRequests[requestId] = nil
end)
function GetCrypto(identifier)
Debug('GetCrypto used with standalone')
return 0
end
RegisterServerCallback('qs-smartphone-pro:GetIdentifier', function(source, cb)
local identifier = GetIdentifier(source)
cb(identifier)
end)
function RegisterUsableItem(name, cb)
Debug('RegisterUsableItem is not supported with standalone')
return false
end
function GetPlayerFromId(source)
return {
source = source,
identifier = GetIdentifier(source)
}
end
function GetPlayerFromIdentifier(identifier)
if not identifier then
return nil
end
identifier = string.gsub(identifier, ' ', '')
local players = GetPlayers()
for k, v in pairs(players) do
if GetIdentifier(v) == identifier then
return {
source = v,
identifier = identifier
}
end
end
return nil
end
function GetItem(player, item)
Debug('GetItem used with standalone')
return {
name = item,
count = 99,
}
end
function AddItem(source, item, count, slot, metadata)
Debug('AddItem used with standalone')
return true
end
function AddWeapon(source, weapon, ammo)
Debug('AddWeapon used with standalone')
return true
end
function RemoveItem(source, item, count, slot)
Debug('RemoveItem used with standalone')
return true
end
function GetBankMoney(source)
Debug('GetBankMoney used with standalone')
return 0
end
function SetJob(source, job, grade)
Debug('SetJob used with standalone')
return true
end
function AddBankMoney(source, amount)
Debug('AddBankMoney used with standalone')
return false
end
function RemoveBankMoney(source, amount)
Debug('RemoveBankMoney used with standalone')
return false
end
function GetJobName(source)
Debug('GetJobName used with standalone')
return 'unemployed'
end
function IsAdmin(source)
return IsPlayerAceAllowed(source, 'command.qsphone_admin') == 1
end
function GetIdentifier(source)
for k, v in pairs(GetPlayerIdentifiers(source)) do
if string.sub(v, 1, string.len('license:')) == 'license:' then
return v:gsub('license:', '')
end
end
return nil
end
function GetStandaloneUserData(identifier)
local firstname = 'unknown'
local lastname = 'unknown'
local phone = Config.Prefix .. math.random(StartDigit, FinishDigit)
return firstname, lastname, phone
end
function GetItems(player)
Debug('Get Items used with standalone')
return {
{
name = 'phone'
}
}
end
function GetPlayerSource(player)
return player.source
end
function GetDataForWithOutMetaData(source)
local player = GetPlayerFromId(source)
local identifier = GetIdentifier(source)
local result = MySQL.Sync.fetchAll('SELECT * FROM phone_metadata WHERE owneridentifier = ?', {
identifier
})
result = result[1]
if result then return json.decode(result.metadata) end
local info
local firstname, lastname, phone = GetUserData(identifier)
info = CreatePhoneMetaData({
firstname = firstname,
lastname = lastname,
identifier = identifier,
phone = phone
})
MySQL.Async.execute('INSERT INTO phone_metadata (owneridentifier, metadata, phoneNumber) VALUES (?, ?, ?)', {
identifier,
json.encode(info),
info.phoneNumber
})
return info
end

View File

@@ -0,0 +1,89 @@
if Config.Garage ~= 'RxGarages' then
return
end
local function getTableName()
return Config.Framework == 'qb' and 'player_vehicles' or 'owned_vehicles'
end
local function getOwnerField()
return Config.Framework == 'qb' and 'citizenid' or 'owner'
end
local function determineGarageName(vehicleData)
local garageName = vehicleData.location or vehicleData.in_shared
if not garageName then
if vehicleData.parked_at == 'garage' then
garageName = 'Garage'
elseif vehicleData.parked_at == 'outside' then
garageName = 'Outside'
elseif vehicleData.parked_at == 'impound' then
garageName = 'Impound'
elseif vehicleData.parked_at == 'shared' then
garageName = 'Shared Garage'
else
garageName = vehicleData.parked_at
end
end
return garageName
end
RegisterNetEvent('phone:setVehicleToOutSide', function(plate)
local str = ([[
UPDATE %s
SET parked_at = 'outside'
WHERE plate = ?
]]):format(getTableName())
MySQL.Sync.execute(str, { plate })
end)
function getGarageData(identifier, plate)
local tableName = getTableName()
local ownerField = getOwnerField()
local str = ([[
SELECT * FROM %s WHERE %s = ? AND (type = 'vehicle' OR type = 'car')
]]):format(tableName, ownerField)
if plate then
str = str .. ([[
AND plate = "%s"
]]):format(plate)
end
local result = MySQL.Sync.fetchAll(str, { identifier })
if not result[1] then return false end
local data = {}
for k, v in pairs(result) do
if Config.Framework ~= 'qb' then
local vehicle = json.decode(v.vehicle)
if not vehicle then return end
table.insert(data, {
name = vehicle.model,
plate = v.plate,
inGarage = v.parked_at == 'garage' or v.parked_at == 'shared',
fuel = vehicle.fuel or 1000,
engine = vehicle.engine or 1000,
body = vehicle.body or 1000,
vehicle = vehicle,
garage = determineGarageName(v),
})
else
table.insert(data, {
name = v.vehicle,
plate = v.plate,
inGarage = v.parked_at == 'garage' or v.parked_at == 'shared',
fuel = v.fuel or 1000,
engine = v.engine or 1000,
body = v.body or 1000,
vehicle = json.decode(v.mods),
garage = determineGarageName(v),
})
end
end
return data
end

View File

@@ -0,0 +1,95 @@
if Config.Garage ~= 'cd_garage' then
return
end
RegisterNetEvent('phone:setVehicleToOutSide', function(plate)
local str = [[
UPDATE owned_vehicles
SET in_garage = 0
WHERE plate = ?
]]
if Config.Framework == 'qb' then
str = [[
UPDATE player_vehicles
SET state = 0
WHERE plate = ?
]]
end
MySQL.Sync.execute(str, { plate })
end)
function getGarageData(identifier, plate)
local str = [[
SELECT * FROM owned_vehicles WHERE owner = ? AND (type = 'vehicle' OR type = 'car')
]]
if Config.Framework == 'qb' then
str = [[
SELECT * FROM player_vehicles WHERE citizenid = ?
]]
end
if plate then
str = str .. ([[
AND plate = "%s"
]]):format(plate)
end
local result = MySQL.Sync.fetchAll(str, { identifier })
if not result[1] then return false end
local data = {}
if Config.Framework == 'qb' then
for k, v in pairs(result) do
local inGarage = v.in_garage
local garageId = v.garage_id
local impound = v.impound
if not inGarage and impound == 0 then
garageId = 'OUT'
end
if impound == 1 then
garageId = 'IMPOUND'
inGarage = false
end
table.insert(data, {
name = v.vehicle,
plate = v.plate,
inGarage = inGarage,
fuel = v.fuel or 1000,
engine = v.engine or 1000,
body = v.body or 1000,
vehicle = json.decode(v.mods),
garage = garageId,
})
end
else
for k, v in pairs(result) do
local vehicle = json.decode(v.vehicle)
if not vehicle then return end
local inGarage = v.in_garage
local garageId = v.garage_id
local impound = v.impound
if not inGarage and impound == 0 then
garageId = 'OUT'
end
if impound == 1 then
garageId = 'IMPOUND'
inGarage = false
end
table.insert(data, {
name = vehicle.model,
plate = v.plate,
inGarage = inGarage,
fuel = vehicle.fuel or 1000,
engine = vehicle.engine or 1000,
body = vehicle.body or 1000,
vehicle = json.decode(v.vehicle),
garage = garageId,
})
end
end
return data
end

View File

@@ -0,0 +1,81 @@
if Config.Garage ~= 'codem-garage' then
return
end
RegisterNetEvent('phone:setVehicleToOutSide', function(plate)
local str = [[
UPDATE owned_vehicles
SET parking = '', stored = 0
WHERE plate = ?
]]
if Config.Framework == 'qb' then
str = [[
UPDATE player_vehicles
SET parking = 0
WHERE plate = ?
]]
end
MySQL.Sync.execute(str, { plate })
end)
function getGarageData(identifier, plate)
local str = [[
SELECT * FROM owned_vehicles WHERE owner = ? AND (type = 'vehicle' OR type = 'car')
]]
if Config.Framework == 'qb' then
str = [[
SELECT * FROM player_vehicles WHERE citizenid = ?
]]
end
if plate then
str = str .. ([[
AND plate = "%s"
]]):format(plate)
end
local result = MySQL.Sync.fetchAll(str, { identifier })
if not result[1] then return false end
local data = {}
if Config.Framework == 'qb' then
for k, v in pairs(result) do
local garageId = v.parking
local inGarage = v.stored == 1 or v.stored == 2
if v.stored == 0 then
garageId = 'OUT'
end
table.insert(data, {
name = v.vehicle,
plate = v.plate,
inGarage = v.stored,
fuel = v.fuel or 1000,
engine = v.engine or 1000,
body = v.body or 1000,
vehicle = json.decode(v.mods),
garage = garageId,
})
end
else
for k, v in pairs(result) do
local vehicle = json.decode(v.vehicle)
if not vehicle then return end
local inGarage = v.stored
local garageId = v.parking
if not inGarage then
garageId = 'OUT'
end
table.insert(data, {
name = vehicle.model,
plate = v.plate,
inGarage = v.stored,
fuel = vehicle.fuel or 1000,
engine = vehicle.engine or 1000,
body = vehicle.body or 1000,
vehicle = json.decode(v.vehicle),
garage = garageId,
})
end
end
return data
end

View File

@@ -0,0 +1,79 @@
if Config.Garage ~= 'default' then
return
end
RegisterNetEvent('phone:setVehicleToOutSide', function(plate)
local str = [[
UPDATE owned_vehicles
SET garage = 'OUT', stored = 0
WHERE plate = ?
]]
if Config.Framework == 'qb' then
str = [[
UPDATE player_vehicles
SET state = 0
WHERE plate = ?
]]
end
MySQL.Sync.execute(str, { plate })
end)
function getGarageData(identifier, plate)
local str = [[
SELECT * FROM owned_vehicles WHERE owner = ? AND (type = 'vehicle' OR type = 'car')
]]
if Config.Framework == 'qb' then
str = [[
SELECT * FROM player_vehicles WHERE citizenid = ?
]]
end
if plate then
str = str .. ([[
AND plate = "%s"
]]):format(plate)
end
local result = MySQL.Sync.fetchAll(str, { identifier })
if not result[1] then return false end
local data = {}
if Config.Framework == 'qb' then
for k, v in pairs(result) do
local garageId = v.garage or v.parking
local inGarage = v.state == 1 or v.state == 2
if v.state == 0 then
garageId = 'OUT'
end
table.insert(data, {
name = v.vehicle,
plate = v.plate,
inGarage = inGarage,
fuel = v.fuel or 1000,
engine = v.engine or 1000,
body = v.body or 1000,
vehicle = json.decode(v.mods),
garage = garageId,
})
end
else
for k, v in pairs(result) do
local vehicle = json.decode(v.vehicle)
if not vehicle then return end
local inGarage = v.stored == 1
local garageId = v.garage or v.parking
table.insert(data, {
name = vehicle.model,
plate = v.plate,
inGarage = inGarage,
fuel = vehicle.fuel or 1000,
engine = vehicle.engine or 1000,
body = vehicle.body or 1000,
vehicle = json.decode(v.vehicle),
garage = garageId,
})
end
end
return data
end

View File

@@ -0,0 +1,95 @@
if Config.Garage ~= 'jg-advancedgarages' then
return
end
RegisterNetEvent('phone:setVehicleToOutSide', function(plate)
local str = [[
UPDATE owned_vehicles
SET in_garage = 0
WHERE plate = ?
]]
if Config.Framework == 'qb' then
str = [[
UPDATE player_vehicles
SET in_garage = 0
WHERE plate = ?
]]
end
MySQL.Sync.execute(str, { plate })
end)
function getGarageData(identifier, plate)
local str = [[
SELECT * FROM owned_vehicles WHERE owner = ? AND (type = 'vehicle' OR type = 'car')
]]
if Config.Framework == 'qb' then
str = [[
SELECT * FROM player_vehicles WHERE citizenid = ?
]]
end
if plate then
str = str .. ([[
AND plate = "%s"
]]):format(plate)
end
local result = MySQL.Sync.fetchAll(str, { identifier })
if not result[1] then return false end
local data = {}
if Config.Framework == 'qb' then
for k, v in pairs(result) do
local inGarage = v.in_garage
local garageId = v.garage_id
local impound = v.impound
if not inGarage then
garageId = v.impound == 1 and 'IMPOUND' or 'OUT'
end
if impound == 1 then
garageId = v.garage_id
inGarage = false
end
table.insert(data, {
name = v.vehicle,
plate = v.plate,
inGarage = inGarage,
fuel = v.fuel * 10 or 1000,
engine = v.engine or 1000,
body = v.body or 1000,
vehicle = json.decode(v.mods),
garage = garageId,
})
end
else
for k, v in pairs(result) do
local vehicle = json.decode(v.vehicle)
if not vehicle then return end
local inGarage = v.in_garage
local garageId = v.garage_id
local impound = v.impound
if not inGarage then
garageId = 'OUT'
end
if impound == 1 then
garageId = v.impound == 1 and 'IMPOUND' or 'OUT'
inGarage = false
end
table.insert(data, {
name = vehicle.model,
plate = v.plate,
inGarage = inGarage,
fuel = v.fuel * 10 or 1000,
engine = vehicle.engine or 1000,
body = vehicle.body or 1000,
vehicle = json.decode(v.vehicle),
garage = garageId,
})
end
end
return data
end

View File

@@ -0,0 +1,79 @@
if Config.Garage ~= 'loaf_garage' then
return
end
RegisterNetEvent('phone:setVehicleToOutSide', function(plate)
local str = [[
UPDATE owned_vehicles
SET garage = 'OUT', stored = 0
WHERE plate = ?
]]
if Config.Framework == 'qb' then
str = [[
UPDATE player_vehicles
SET state = 0
WHERE plate = ?
]]
end
MySQL.Sync.execute(str, { plate })
end)
function getGarageData(identifier, plate)
local str = [[
SELECT * FROM owned_vehicles WHERE owner = ? AND (type = 'vehicle' OR type = 'car')
]]
if Config.Framework == 'qb' then
str = [[
SELECT * FROM player_vehicles WHERE citizenid = ?
]]
end
if plate then
str = str .. ([[
AND plate = "%s"
]]):format(plate)
end
local result = MySQL.Sync.fetchAll(str, { identifier })
if not result[1] then return false end
local data = {}
if Config.Framework == 'qb' then
for k, v in pairs(result) do
local garageId = v.garage or v.parking
local inGarage = v.state == 1 or v.state == 2
if v.state == 0 then
garageId = 'OUT'
end
table.insert(data, {
name = v.vehicle,
plate = v.plate,
inGarage = inGarage,
fuel = v.fuel or 1000,
engine = v.engine or 1000,
body = v.body or 1000,
vehicle = json.decode(v.mods),
garage = garageId,
})
end
else
for k, v in pairs(result) do
local vehicle = json.decode(v.vehicle)
if not vehicle then return end
local inGarage = v.stored
local garageId = v.garage or v.parking
table.insert(data, {
name = vehicle.model,
plate = v.plate,
inGarage = inGarage,
fuel = vehicle.fuel or 1000,
engine = vehicle.engine or 1000,
body = vehicle.body or 1000,
vehicle = json.decode(v.vehicle),
garage = garageId,
})
end
end
return data
end

View File

@@ -0,0 +1,84 @@
if Config.Garage ~= 'lunar_garage' then
return
end
RegisterNetEvent('phone:setVehicleToOutSide', function(plate)
local str = [[
UPDATE owned_vehicles
SET stored = 0
WHERE plate = ?
]]
if Config.Framework == 'qb' then
str = [[
UPDATE player_vehicles
SET stored = 0
WHERE plate = ?
]]
end
MySQL.Sync.execute(str, { plate })
end)
function getGarageData(identifier, plate)
local str = [[
SELECT * FROM owned_vehicles WHERE owner = ? AND type = 'car' and job is NULL
]]
if Config.Framework == 'qb' then
str = [[
SELECT * FROM player_vehicles WHERE citizenid = ? and (type = 'car' OR type = 'automobile') and job is NULL
]]
end
if plate then
str = str .. ([[
AND plate = "%s"
]]):format(plate)
end
local result = MySQL.Sync.fetchAll(str, { identifier })
if not result[1] then return false end
local data = {}
if Config.Framework == 'qb' then
for k, v in pairs(result) do
local garageId = 'OUT'
local inGarage = v.stored == 1 or v.stored == true
if inGarage then
garageId = 'IN'
end
table.insert(data, {
name = v.vehicle,
plate = v.plate,
inGarage = inGarage,
fuel = v.fuel or 1000,
engine = v.engine or 1000,
body = v.body or 1000,
vehicle = json.decode(v.mods),
garage = garageId,
})
end
else
for k, v in pairs(result) do
local vehicle = json.decode(v.vehicle)
if not vehicle then return end
local garageId = 'OUT'
local inGarage = v.stored == 1 or v.stored == true
if inGarage then
garageId = 'IN'
end
table.insert(data, {
name = vehicle.model,
plate = v.plate,
inGarage = inGarage,
fuel = vehicle.fuel or 1000,
engine = vehicle.engine or 1000,
body = vehicle.body or 1000,
vehicle = json.decode(v.vehicle),
garage = garageId,
})
end
end
return data
end

View File

@@ -0,0 +1,93 @@
if Config.Garage ~= 'okokGarage' then
return
end
RegisterNetEvent('phone:setVehicleToOutSide', function(plate)
local str = [[
UPDATE owned_vehicles
SET parking = '', stored = 0
WHERE plate = ?
]]
if Config.Framework == 'qb' then
str = [[
UPDATE player_vehicles
SET state = 0
WHERE plate = ?
]]
end
MySQL.Sync.execute(str, { plate })
end)
function getGarageData(identifier, plate)
local str = [[
SELECT *, cast(`stored` as signed) as `stored` FROM owned_vehicles WHERE owner = ? AND (type = 'vehicle' OR type = 'car')
]]
if Config.Framework == 'qb' then
str = [[
SELECT *, cast(`state` as signed) as `state` FROM player_vehicles WHERE citizenid = ?
]]
end
if plate then
str = str .. ([[
AND plate = "%s"
]]):format(plate)
end
local result = MySQL.Sync.fetchAll(str, { identifier })
if not result[1] then return false end
local data = {}
if Config.Framework == 'qb' then
for k, v in pairs(result) do
if type(v.state) ~= 'number' then
v.state = tonumber(v.state)
end
local garageId = v.garage or v.parking
local inGarage = v.state == 1
if v.state == 0 then
garageId = 'OUT'
if tonumber(v.state) == 2 then
garageId = 'IMPOUNDED'
end
end
table.insert(data, {
name = v.vehicle,
plate = v.plate,
inGarage = inGarage,
fuel = v.fuel or 1000,
engine = v.engine or 1000,
body = v.body or 1000,
vehicle = json.decode(v.mods),
garage = garageId,
})
end
else
for k, v in pairs(result) do
local vehicle = json.decode(v.vehicle)
if not vehicle then return end
if type(v.stored) ~= 'number' then
v.stored = tonumber(v.stored)
end
local inGarage = v.stored == 1
local garageId = v.garage or v.parking
if not inGarage then
garageId = 'OUT'
if tonumber(v.stored) == 2 then
garageId = 'IMPOUNDED'
end
end
table.insert(data, {
name = vehicle.model,
plate = v.plate,
inGarage = inGarage,
fuel = vehicle.fuel or 1000,
engine = vehicle.engine or 1000,
body = vehicle.body or 1000,
vehicle = json.decode(v.vehicle),
garage = garageId,
})
end
end
return data
end

View File

@@ -0,0 +1,120 @@
if Config.Garage ~= 'qs-advancedgarages' then
return
end
RegisterNetEvent('phone:setVehicleToOutSide', function(plate)
local str = [[
UPDATE owned_vehicles
SET garage = 'OUT', stored = 0
WHERE plate = ?
]]
if Config.Framework == 'qb' then
str = [[
UPDATE player_vehicles
SET garage = 'OUT', state = 0
WHERE plate = ?
]]
end
MySQL.Sync.execute(str, { plate })
end)
function getGarageData(identifier, plate)
local str = [[
SELECT * FROM owned_vehicles WHERE owner = ? AND (type = 'vehicle' OR type = 'car')
]]
if Config.Framework == 'qb' then
str = [[
SELECT * FROM player_vehicles WHERE citizenid = ?
]]
end
if plate then
str = str .. ([[
AND plate = "%s"
]]):format(plate)
end
local result = MySQL.Sync.fetchAll(str, { identifier })
if not result[1] then return false end
local data = {}
if Config.Framework == 'qb' then
local impoundGarages = exports['qs-advancedgarages']:getImpoundGarages()
for k, v in pairs(result) do
local inImpound = false
if impoundGarages and impoundGarages[v.garage] then
inImpound = true
end
local garageId = v.garage or v.parking
local inGarage = (v.state == 1 or v.state == 2) and not inImpound
if v.state == 0 then
garageId = 'OUT'
end
table.insert(data, {
name = v.vehicle,
plate = v.plate,
inGarage = inGarage,
fuel = v.fuel or 1000,
engine = v.engine or 1000,
body = v.body or 1000,
vehicle = json.decode(v.mods),
garage = garageId,
})
end
else
local impoundGarages = exports['qs-advancedgarages']:getImpoundGarages()
for k, v in pairs(result) do
local vehicle = json.decode(v.vehicle)
if not vehicle then return end
local inImpound = false
if impoundGarages and impoundGarages[v.garage] then
inImpound = true
end
local inGarage = true
local garageId = v.garage
print('garageId', garageId)
print('inImpound', inImpound)
if v.garage == 'OUT' or inImpound then
inGarage = false
end
print('inGarage', inGarage)
table.insert(data, {
name = vehicle.model,
plate = v.plate,
inGarage = inGarage,
fuel = vehicle.fuel or 1000,
engine = vehicle.engine or 1000,
body = vehicle.body or 1000,
vehicle = json.decode(v.vehicle),
garage = garageId,
})
end
end
return data
end
RegisterNetEvent('qs-smartphone-pro:addToPersistent', function(plate, netId)
local src = source
local identifier = GetIdentifier(src)
local str = ([[
SELECT 1 FROM %s WHERE plate = ? AND %s = ? AND jobVehicle = ? LIMIT 1
]]):format(garageTable, garageIdentifierColumn)
local result = MySQL.Sync.fetchAll(str,
{ plate, identifier, '' })
if not result[1] then
return Error(src, 'Tried to exploit qs-smartphone-pro:addToPersistent')
end
local response = exports['qs-advancedgarages']:setVehicleToPersistent(netId)
if not response then
Error(plate, 'Failed to add vehicle to persistent')
return
end
Debug(plate, 'Added vehicle to persistent')
end)

View File

@@ -0,0 +1,135 @@
if Config.Garage ~= 'vms_garagesv2' then
return
end
RegisterNetEvent('phone:setVehicleToOutSide', function(plate)
local plate = plate
local queryVehicleData = 'SELECT garage, garageSpotID FROM owned_vehicles WHERE plate = ? AND impound_data IS NULL AND impound_date IS NULL'
if Config.Framework == 'qb' then
queryVehicleData = 'SELECT garage, garageSpotID FROM player_vehicles WHERE plate = ? AND impound_data IS NULL AND impound_date IS NULL'
end
local vehicleData = MySQL.query.await(queryVehicleData, { plate })
if vehicleData and vehicleData[1] then
TriggerEvent('vms_garagesv2:vehicleTakenByPhone', vehicleData[1].garage, vehicleData[1].garageSpotID)
end
Citizen.CreateThread(function()
Citizen.Wait(3000)
local foundNetId = nil
local allVehicles = GetAllVehicles()
for i = 1, #allVehicles do
if DoesEntityExist(allVehicles[i]) then
local vehPlate = GetVehicleNumberPlateText(allVehicles[i])
local cleanedPlate = vehPlate:match('^%s*(.-)%s*$')
if cleanedPlate == plate then
foundNetId = NetworkGetNetworkIdFromEntity(allVehicles[i])
break
end
end
end
local str = [[
UPDATE owned_vehicles
SET garage = NULL, garageSpotID = NULL
]]
if Config.Framework == 'qb' then
str = [[
UPDATE player_vehicles
SET garage = NULL, garageSpotID = NULL
]]
end
if foundNetId then
str = str .. ', netid = ? WHERE plate = ?'
MySQL.Sync.execute(str, { foundNetId, plate })
else
str = str .. ' WHERE plate = ?'
MySQL.Sync.execute(str, { plate })
end
end)
end)
function getGarageData(identifier, plate)
local str = [[
SELECT * FROM owned_vehicles WHERE owner = ? AND (type = 'vehicle' OR type = 'car') AND impound_data IS NULL AND impound_date IS NULL
]]
if Config.Framework == 'qb' then
str = [[
SELECT * FROM player_vehicles WHERE citizenid = ? AND (type = 'vehicle' OR type = 'car' OR type = 'automobile') AND impound_data IS NULL AND impound_date IS NULL
]]
end
if plate then
str = str .. ([[
AND plate = "%s"
]]):format(plate)
end
print(str)
local result = MySQL.Sync.fetchAll(str, { identifier })
if not result[1] then
return false
end
local data = {}
if Config.Framework == 'qb' then
for k, v in pairs(result) do
local mods = json.decode(v.mods)
if not mods then
return
end
local inGarage = false
local garageId = 'OUT'
if v.garage then
local label, coords = exports['vms_garagesv2']:getGarageInfo(v.garage)
inGarage = true
garageId = label
elseif v.impound then
garageId = 'IMPOUND'
end
table.insert(data, {
name = mods.model,
plate = v.plate,
inGarage = inGarage,
fuel = mods.fuel or 1000,
engine = mods.engine or 1000,
body = mods.body or 1000,
vehicle = mods,
garage = garageId,
})
end
else
for k, v in pairs(result) do
local vehicle = json.decode(v.vehicle)
if not vehicle then
return
end
local inGarage = false
local garageId = 'OUT'
print(v.garage)
if v.garage then
local label, coords = exports['vms_garagesv2']:getGarageInfo(v.garage)
inGarage = true
garageId = label
elseif v.impound then
garageId = 'IMPOUND'
end
table.insert(data, {
name = vehicle.model,
plate = v.plate,
inGarage = inGarage,
fuel = vehicle.fuel or 1000,
engine = vehicle.engine or 1000,
body = vehicle.body or 1000,
vehicle = vehicle,
garage = garageId,
})
end
end
return data
end

View File

@@ -0,0 +1,90 @@
if Config.Inventory ~= 'ak47_inventory' then
return
end
ak47_inventory = exports['ak47_inventory']
function GetUserData(identifier)
local str = ([[
SELECT %s FROM %s WHERE %s = ?
]]):format(Config.Framework == 'esx' and 'firstname, lastname, phone_number' or 'charinfo', userColumn, identifierTable)
local result = MySQL.Sync.fetchAll(str, {
identifier
})
result = result[1]
if not result then return false end
local firstname, lastname, phone
if Config.Framework == 'esx' then
firstname = result.firstname
lastname = result.lastname
phone = result.phone_number
elseif Config.Framework == 'qb' then
local data = json.decode(result.charinfo)
firstname = data.firstname
lastname = data.lastname
phone = data.phone
end
if not phone and Config.Framework == 'esx' then
phone = Config.Prefix .. math.random(StartDigit, FinishDigit)
MySQL.Sync.execute('UPDATE `users` SET `phone_number` = ? WHERE `identifier` = ?', {
phone,
identifier
})
end
return firstname, lastname, phone
end
function InitPhoneMeta(src, slot, data)
local identifier = GetIdentifier(src)
ak47_inventory:SetItemInfo(identifier, slot, data)
Debug('Init phone meta', src, slot, data)
end
function SaveMetadataToInventory(src, customNumber)
local identifier = GetIdentifier(src)
local items = ak47_inventory:GetInventoryItems(identifier)
if not items then return end
local phone = customNumber or MetaData[src].phoneNumber
local itemToUpdate = nil
for k, v in pairs(items) do
if Config.Phones[v.name] then
local meta = v.info
if meta.phoneNumber == phone and PhoneIsUseable(meta.uniqueId) then
itemToUpdate = v
break
elseif v.category == 'uniqueItem' then
itemToUpdate = v
break
end
end
end
ak47_inventory:SetItemInfo(identifier, itemToUpdate.slot, MetaData[src])
end
local usedPhone = {} -- This fix for the laggy phone
function RegisterItems()
for k, v in pairs(Config.Phones) do
RegisterUsableItem(k, function(source, item)
local time = os.time()
if usedPhone[source] and usedPhone[source] > time then return end
usedPhone[source] = time + 2
local player = GetPlayerFromId(source)
if not item.info or not item.info?.phoneNumber then
local identifier = GetIdentifier(source)
local firstname, lastname = GetUserData(identifier)
local info = CreatePhoneMetaData({
firstname = firstname,
lastname = lastname,
identifier = identifier,
})
item.info = info
InitPhoneMeta(source, item.slot, info)
Debug('Created phone meta')
end
Debug('loading with', item.info.phoneNumber)
TriggerClientEvent('phone:openPhone', source, v, k, item.info)
end)
end
end

View File

@@ -0,0 +1,90 @@
if Config.Inventory ~= 'ak47_qb_inventory' then
return
end
ak47_qb_inventory = exports['ak47_qb_inventory']
function GetUserData(identifier)
local str = ([[
SELECT %s FROM %s WHERE %s = ?
]]):format(Config.Framework == 'esx' and 'firstname, lastname, phone_number' or 'charinfo', userColumn, identifierTable)
local result = MySQL.Sync.fetchAll(str, {
identifier
})
result = result[1]
if not result then return false end
local firstname, lastname, phone
if Config.Framework == 'esx' then
firstname = result.firstname
lastname = result.lastname
phone = result.phone_number
elseif Config.Framework == 'qb' then
local data = json.decode(result.charinfo)
firstname = data.firstname
lastname = data.lastname
phone = data.phone
end
if not phone and Config.Framework == 'esx' then
phone = Config.Prefix .. math.random(StartDigit, FinishDigit)
MySQL.Sync.execute('UPDATE `users` SET `phone_number` = ? WHERE `identifier` = ?', {
phone,
identifier
})
end
return firstname, lastname, phone
end
function InitPhoneMeta(src, slot, data)
local identifier = GetIdentifier(src)
ak47_qb_inventory:SetItemInfo(identifier, slot, data)
Debug('Init phone meta', src, slot, data)
end
function SaveMetadataToInventory(src, customNumber)
local identifier = GetIdentifier(src)
local items = ak47_qb_inventory:GetInventoryItems(identifier)
if not items then return end
local phone = customNumber or MetaData[src].phoneNumber
local itemToUpdate = nil
for k, v in pairs(items) do
if Config.Phones[v.name] then
local meta = v.info
if meta.phoneNumber == phone and PhoneIsUseable(meta.uniqueId) then
itemToUpdate = v
break
elseif v.category == 'uniqueItem' then
itemToUpdate = v
break
end
end
end
ak47_qb_inventory:SetItemInfo(identifier, itemToUpdate.slot, MetaData[src])
end
local usedPhone = {} -- This fix for the laggy phone
function RegisterItems()
for k, v in pairs(Config.Phones) do
RegisterUsableItem(k, function(source, item)
local time = os.time()
if usedPhone[source] and usedPhone[source] > time then return end
usedPhone[source] = time + 2
local player = GetPlayerFromId(source)
if not item.info or not item.info?.phoneNumber then
local identifier = GetIdentifier(source)
local firstname, lastname = GetUserData(identifier)
local info = CreatePhoneMetaData({
firstname = firstname,
lastname = lastname,
identifier = identifier,
})
item.info = info
InitPhoneMeta(source, item.slot, info)
Debug('Created phone meta')
end
Debug('loading with', item.info.phoneNumber)
TriggerClientEvent('phone:openPhone', source, v, k, item.info)
end)
end
end

View File

@@ -0,0 +1,119 @@
if Config.Inventory ~= 'codem-inventory' then
return
end
CodemInventory = exports['codem-inventory']
function GetUserData(identifier)
local str = ([[
SELECT %s FROM %s WHERE %s = ?
]]):format(Config.Framework == 'esx' and 'firstname, lastname, phone_number' or 'charinfo', userColumn, identifierTable)
local result = MySQL.Sync.fetchAll(str, {
identifier
})
result = result[1]
if not result then return false end
local firstname, lastname, phone
if Config.Framework == 'esx' then
firstname = result.firstname
lastname = result.lastname
phone = result.phone_number
elseif Config.Framework == 'qb' then
local data = json.decode(result.charinfo)
firstname = data.firstname
lastname = data.lastname
phone = data.phone
end
if not phone and Config.Framework == 'esx' then
phone = Config.Prefix .. math.random(StartDigit, FinishDigit)
MySQL.Sync.execute('UPDATE `users` SET `phone_number` = ? WHERE `identifier` = ?', {
phone,
identifier
})
end
return firstname, lastname, phone
end
function InitPhoneMeta(src, slot, data)
if Config.Framework == 'esx' then
CodemInventory:SetItemMetadata(src, slot, data)
else
CodemInventory:SetItemMetadata(src, slot, data)
-- local player = GetPlayerFromId(src)
-- player.PlayerData.items[slot].info.metadata = data.metadata
-- player.PlayerData.items[slot].info.charinfo = data.charinfo
-- player.PlayerData.items[slot].info.phoneNumber = data.phoneNumber
-- player.PlayerData.items[slot].info.owneridentifier = data.owneridentifier
-- player.Functions.SetInventory(player.PlayerData.items)
end
Debug('Init phone meta', src, slot, data)
end
function SaveMetadataToInventory(src, customNumber)
local player = GetPlayerFromId(src)
local items = GetItems(player)
local slot = 0
--local meta
if not items then return Debug('Save metadata to inventory failed. items is nil', 'Player src:', src) end
local phone = customNumber or MetaData[src].phoneNumber
for k, v in pairs(items) do
for phoneName, phoneData in pairs(Config.Phones) do
if v.name == phoneName then
local meta = v.info and v.info or v.metadata
--print('Test1'..json.encode(meta))
--print('Test2'..meta.phoneNumber)
if meta.phoneNumber == phone and PhoneIsUseable(meta.uniqueId) then
slot = v.slot
break
end
end
end
end
CodemInventory:SetItemMetadata(src, slot, MetaData[src])
end
function RegisterItems()
for k, v in pairs(Config.Phones) do
RegisterUsableItem(k, function(source, item, item)
local player = GetPlayerFromId(source)
if not item?.info or not item?.info?.phoneNumber then
local result = MySQL.Sync.fetchAll('SELECT firstname, lastname FROM users WHERE identifier = ?', {
player.identifier
})
result = result[1]
local info = CreatePhoneMetaData({
firstname = result.firstname,
lastname = result.lastname,
identifier = player.identifier,
})
item.info = info
print(json.encode(item))
CodemInventory:SetItemMetadata(source, item.slot, info)
Debug('Created phone meta')
end
TriggerClientEvent('phone:openPhone', source, v, k, item.info)
end)
end
end
exports('handleDeleteItem', function(source, itemData)
if itemData then
local metaPhone = MetaData[source]?.phoneNumber
local itemIsPhone = ItemIsPhone(itemData.name)
if not itemIsPhone then return end
local itemPhoneNumber = itemData.info.phoneNumber
if metaPhone and itemPhoneNumber and itemPhoneNumber == metaPhone then
MetaData[source] = nil
TriggerClientEvent('phone:UpdatedMeta', source, nil)
Debug('Cleared metadata. for: ' .. source)
end
else
local metaPhone = MetaData[source]?.phoneNumber
local existPhone = FindUserExistPhone(source, metaPhone)
if not existPhone then
MetaData[source] = nil
TriggerClientEvent('phone:UpdatedMeta', source, nil)
Debug('Cleared metadata. for: ' .. source)
end
end
end)

View File

@@ -0,0 +1,96 @@
if Config.Inventory ~= 'core_inventory' then
return
end
CoreInventory = exports['core_inventory']
function GetUserData(identifier)
local str = ([[
SELECT %s FROM %s WHERE %s = ?
]]):format(Config.Framework == 'esx' and 'firstname, lastname, phone_number' or 'charinfo', userColumn, identifierTable)
local result = MySQL.Sync.fetchAll(str, {
identifier
})
result = result[1]
if not result then return false end
local firstname, lastname, phone
if Config.Framework == 'esx' then
firstname = result.firstname
lastname = result.lastname
phone = result.phone_number
elseif Config.Framework == 'qb' then
local data = json.decode(result.charinfo)
firstname = data.firstname
lastname = data.lastname
phone = data.phone
end
if not phone and Config.Framework == 'esx' then
phone = Config.Prefix .. math.random(StartDigit, FinishDigit)
MySQL.Sync.execute('UPDATE `users` SET `phone_number` = ? WHERE `identifier` = ?', {
phone,
identifier
})
end
return firstname, lastname, phone
end
function InitPhoneMeta(src, slot, data)
local identifier = GetIdentifier(src)
local inventory = 'content-' .. identifier:gsub(':', '')
CoreInventory:updateMetadata(inventory, slot, data)
Debug('Init phone meta', src, slot, data)
end
function SaveMetadataToInventory(src, customNumber)
local identifier = GetIdentifier(src)
local inventory = 'content-' .. identifier:gsub(':', '')
local items = CoreInventory:getInventory(inventory)
if not items then return end
local phone = customNumber or MetaData[src].phoneNumber
local itemToUpdate = nil
for k, v in pairs(items) do
if Config.Phones[v.name] then
local meta = v.info or v.metadata
if meta.phoneNumber == phone and PhoneIsUseable(meta.uniqueId) then
itemToUpdate = v
break
elseif v.category == 'uniqueItem' then
itemToUpdate = v
break
end
end
end
CoreInventory:updateMetadata(inventory, itemToUpdate.id, MetaData[src])
end
local usedPhone = {} -- This fix for the laggy phone
function RegisterItems()
for k, v in pairs(Config.Phones) do
RegisterUsableItem(k, function(source, item, itemData)
local time = os.time()
if usedPhone[source] and usedPhone[source] > time then return end
usedPhone[source] = time + 2
local player = GetPlayerFromId(source)
if not type(item) ~= 'table' and type(itemData) == 'table' then
item = itemData
end
item.info = item.metadata
if not item.info or not item.info?.phoneNumber then
local identifier = GetIdentifier(source)
local firstname, lastname = GetUserData(identifier)
local info = CreatePhoneMetaData({
firstname = firstname,
lastname = lastname,
identifier = identifier,
})
item.info = info
InitPhoneMeta(source, item.id, info)
Debug('Created phone meta')
end
Debug('loading with', item.info.phoneNumber)
TriggerClientEvent('phone:openPhone', source, v, k, item.info)
end)
end
end

View File

@@ -0,0 +1,36 @@
if Config.Inventory ~= 'default' then
return
end
function GetUserData(identifier)
if Config.Framework == 'standalone' then
return GetStandaloneUserData(identifier)
end
local str = ([[
SELECT %s FROM %s WHERE %s = ?
]]):format(Config.Framework == 'esx' and 'firstname, lastname, phone_number' or 'charinfo', userColumn, identifierTable)
local result = MySQL.Sync.fetchAll(str, {
identifier
})
result = result[1]
if not result then return false end
local firstname, lastname, phone
if Config.Framework == 'esx' then
firstname = result.firstname
lastname = result.lastname
phone = result.phone_number
elseif Config.Framework == 'qb' then
local data = json.decode(result.charinfo)
firstname = data.firstname
lastname = data.lastname
phone = data.phone
end
if not phone and Config.Framework == 'esx' then
phone = Config.Prefix .. math.random(StartDigit, FinishDigit)
MySQL.Sync.execute('UPDATE `users` SET `phone_number` = ? WHERE `identifier` = ?', {
phone,
identifier
})
end
return firstname, lastname, phone
end

View File

@@ -0,0 +1,104 @@
if Config.Inventory ~= 'origen_inventory' then
return
end
OrigenInventory = exports['origen_inventory']
function GetUserData(identifier)
local str = ([[
SELECT %s FROM %s WHERE %s = ?
]]):format(Config.Framework == 'esx' and 'firstname, lastname, phone_number' or 'charinfo', userColumn, identifierTable)
local result = MySQL.Sync.fetchAll(str, {
identifier
})
result = result[1]
if not result then return false end
local firstname, lastname, phone
if Config.Framework == 'esx' then
firstname = result.firstname
lastname = result.lastname
phone = result.phone_number
elseif Config.Framework == 'qb' then
local data = json.decode(result.charinfo)
firstname = data.firstname
lastname = data.lastname
phone = data.phone
end
if not phone and Config.Framework == 'esx' then
phone = Config.Prefix .. math.random(StartDigit, FinishDigit)
MySQL.Sync.execute('UPDATE `users` SET `phone_number` = ? WHERE `identifier` = ?', {
phone,
identifier
})
end
return firstname, lastname, phone
end
function InitPhoneMeta(src, slot, data)
Debug('src', src, 'Slot', slot, 'Data', data)
local metadata = {
metadata = data.metadata,
charinfo = data.charinfo,
phoneNumber = data.phoneNumber,
owneridentifier = data.owneridentifier
}
OrigenInventory:setMetadata(src, slot, metadata)
Debug('Init phone meta', src, slot, data)
end
function SaveMetadataToInventory(src, customNumber)
local userData = OrigenInventory:getInventory(src)
local items = userData.inventory
if not items then return end
local phone = customNumber or MetaData[src].phoneNumber
for k, v in pairs(items) do
local meta = v.metadata
if meta.phoneNumber == phone and PhoneIsUseable(meta.uniqueId) then
OrigenInventory:setMetadata(src, k, MetaData[src])
Debug('Saved metadata to inventory', src, k, MetaData[src])
break
end
end
end
function RegisterItems()
for k, v in pairs(Config.Phones) do
RegisterUsableItem(k, function(source, item)
if not item?.metadata or not item?.metadata?.phoneNumber then
local identifier = GetIdentifier(source)
local firstname, lastname = GetUserData(identifier)
local info = CreatePhoneMetaData({
firstname = firstname,
lastname = lastname,
identifier = identifier,
})
item.metadata = info
InitPhoneMeta(source, item.slot, info)
Debug('Created phone meta')
end
TriggerClientEvent('phone:openPhone', source, v, k, item.metadata)
end)
end
end
exports('handleDeleteItem', function(source, itemData)
if itemData then
local metaPhone = MetaData[source]?.phoneNumber
local itemIsPhone = ItemIsPhone(itemData.name)
if not itemIsPhone then return end
local itemPhoneNumber = itemData.metadata.phoneNumber
if metaPhone and itemPhoneNumber and itemPhoneNumber == metaPhone then
MetaData[source] = nil
TriggerClientEvent('phone:UpdatedMeta', source, nil)
Debug('Cleared metadata. for: ' .. source)
end
else
local metaPhone = MetaData[source]?.phoneNumber
local existPhone = FindUserExistPhone(source, metaPhone)
if not existPhone then
MetaData[source] = nil
TriggerClientEvent('phone:UpdatedMeta', source, nil)
Debug('Cleared metadata. for: ' .. source)
end
end
end)

View File

@@ -0,0 +1,134 @@
if Config.Inventory ~= 'ox_inventory' then
return
end
ox_inventory = exports['ox_inventory']
function GetUserData(identifier)
local str = ([[
SELECT %s FROM %s WHERE %s = ?
]]):format(Config.Framework == 'esx' and 'firstname, lastname, phone_number' or 'charinfo', userColumn, identifierTable)
local result = MySQL.Sync.fetchAll(str, {
identifier
})
result = result[1]
if not result then return false end
local firstname, lastname, phone
if Config.Framework == 'esx' then
firstname = result.firstname
lastname = result.lastname
phone = result.phone_number
elseif Config.Framework == 'qb' then
local data = json.decode(result.charinfo)
firstname = data.firstname
lastname = data.lastname
phone = data.phone
end
if not phone and Config.Framework == 'esx' then
phone = Config.Prefix .. math.random(StartDigit, FinishDigit)
MySQL.Sync.execute('UPDATE `users` SET `phone_number` = ? WHERE `identifier` = ?', {
phone,
identifier
})
end
return firstname, lastname, phone
end
function InitPhoneMeta(src, slot, data)
Error('You failed to adapt phone to ox_inventory properly! Please check the docs!')
end
function SaveMetadataToInventory(src, customNumber)
local player = GetPlayerFromId(src)
local items = GetItems(player)
local slot = 0
if not items then return Debug('Save metadata to inventory failed. items is nil', 'Player src:', src) end
local phone = customNumber or MetaData[src].phoneNumber
for k, v in pairs(items) do
local meta = v.info and v.info or v.metadata
if meta.phoneNumber == phone and PhoneIsUseable(meta.uniqueId) then
slot = v.slot
if v.info then
v.info = MetaData[src]
else
v.metadata = MetaData[src]
end
break
end
end
MetaData[src].description = Lang('PHONE_NUI_INVENTORY_INFORMATION') .. ' ' .. MetaData[src].phoneNumber
ox_inventory:SetMetadata(src, slot, MetaData[src])
end
function RegisterItems() end
RegisterNetEvent('phone:usePhoneItem', function(itemData)
local src = source
local identifier = GetIdentifier(src)
local itemName = itemData.name
local colorData = Config.Phones[itemName]
if not Config.UniquePhone then
local meta = GetDataForWithOutMetaData(src)
TriggerClientEvent('phone:openPhone', src, colorData, itemName, meta)
return
end
if not itemData.metadata or not itemData.metadata.phoneNumber then return TriggerClientEvent('phone:client:sendTextMessage', src, Lang('PHONE_NOTIFICATION_PHONE_USE_OTHER'), 'error') end
TriggerClientEvent('phone:openPhone', src, colorData, itemName, itemData.metadata)
end)
exports('handleDeleteItem', function(source, itemData)
if itemData then
local metaPhone = MetaData[source]?.phoneNumber
local itemIsPhone = ItemIsPhone(itemData.name)
if not itemIsPhone then return end
local itemPhoneNumber = itemData.info.phoneNumber
if metaPhone and itemPhoneNumber and itemPhoneNumber == metaPhone then
MetaData[source] = nil
TriggerClientEvent('phone:UpdatedMeta', source, nil)
Debug('Cleared metadata. for: ' .. source)
end
else
local metaPhone = MetaData[source]?.phoneNumber
local existPhone = FindUserExistPhone(source, metaPhone)
if not existPhone then
MetaData[source] = nil
TriggerClientEvent('phone:UpdatedMeta', source, nil)
Debug('Cleared metadata. for: ' .. source)
end
end
TriggerClientEvent('phone:closePhone', source)
end)
local function getPhoneWithNotPhoneNumber(source)
local player = GetPlayerFromId(source)
local items = GetItems(player)
for a, x in pairs(Config.Phones) do
for k, v in pairs(items) do
local meta = v?.info or v?.metadata
if v.name == a and not meta.phoneNumber then
return v
end
end
end
return false
end
RegisterNetEvent('phone:itemAdd', function()
local src = source
local item = getPhoneWithNotPhoneNumber(src)
if not item then return print('OX Error: item is nil. You need to take a new phone. And we hope you did read the docs well.') end
if not item?.metadata.phoneNumber then
local identifier = GetIdentifier(src)
local firstname, lastname, phone = GetUserData(identifier)
if not firstname then return print('OX Error: firstname is nil') end
local metadata = CreatePhoneMetaData({
firstname = firstname,
lastname = lastname,
identifier = identifier,
})
item.metadata = metadata
metadata.description = Lang('PHONE_NUI_INVENTORY_INFORMATION') .. ' ' .. metadata.phoneNumber
ox_inventory:SetMetadata(src, item.slot, metadata)
return
end
end)

View File

@@ -0,0 +1,88 @@
if Config.Inventory ~= 'qb-inventory' then
return
end
function GetUserData(identifier)
local str = ([[
SELECT charinfo FROM players WHERE citizenid = ?
]])
local result = MySQL.Sync.fetchAll(str, {
identifier
})
if not result[1] then return false end
local charinfo = json.decode(result[1].charinfo)
Debug('GetUserData', identifier, 'firstname', charinfo.firstname, 'lastname', charinfo.lastname)
return charinfo.firstname, charinfo.lastname, charinfo.phone
end
function InitPhoneMeta(src, slot, data)
local player = GetPlayerFromId(src)
player.PlayerData.items[slot].info.metadata = data.metadata
player.PlayerData.items[slot].info.charinfo = data.charinfo
player.PlayerData.items[slot].info.phoneNumber = data.phoneNumber
player.PlayerData.items[slot].info.owneridentifier = data.owneridentifier
player.Functions.SetInventory(player.PlayerData.items)
Debug('Init phone meta', src, slot, data)
end
function SaveMetadataToInventory(src, customNumber)
local player = GetPlayerFromId(src)
local items = GetItems(player)
if not items then return end
local phone = customNumber or MetaData[src].phoneNumber
for k, v in pairs(items) do
local meta = v.info and v.info or v.metadata
if meta.phoneNumber == phone and PhoneIsUseable(meta.uniqueId) then
if v.info then
v.info = MetaData[src]
else
v.metadata = MetaData[src]
end
break
end
end
player.Functions.SetInventory(items)
end
function RegisterItems()
for k, v in pairs(Config.Phones) do
RegisterUsableItem(k, function(source, item)
local player = GetPlayerFromId(source)
if not item?.info or not item?.info?.phoneNumber then
local identifier = GetIdentifier(source)
local firstname, lastname = GetUserData(identifier)
local info = CreatePhoneMetaData({
firstname = firstname,
lastname = lastname,
identifier = identifier,
})
item.info = info
InitPhoneMeta(source, item.slot, info)
Debug('Created phone meta')
end
TriggerClientEvent('phone:openPhone', source, v, k, item.info)
end)
end
end
exports('handleDeleteItem', function(source, itemData)
if itemData then
local metaPhone = MetaData[source]?.phoneNumber
local itemIsPhone = ItemIsPhone(itemData.name)
if not itemIsPhone then return end
local itemPhoneNumber = itemData.info.phoneNumber
if metaPhone and itemPhoneNumber and itemPhoneNumber == metaPhone then
MetaData[source] = nil
TriggerClientEvent('phone:UpdatedMeta', source, nil)
Debug('Cleared metadata. for: ' .. source)
end
else
local metaPhone = MetaData[source]?.phoneNumber
local existPhone = FindUserExistPhone(source, metaPhone)
if not existPhone then
MetaData[source] = nil
TriggerClientEvent('phone:UpdatedMeta', source, nil)
Debug('Cleared metadata. for: ' .. source)
end
end
end)

View File

@@ -0,0 +1,109 @@
if Config.Inventory ~= 'qs-inventory' then
return
end
QSInventory = exports['qs-inventory']
ItemList = exports['qs-inventory']:GetItemList()
function GetUserData(identifier)
local str = ([[
SELECT %s FROM %s WHERE %s = ?
]]):format(Config.Framework == 'esx' and 'firstname, lastname, phone_number' or 'charinfo', userColumn, identifierTable)
local result = MySQL.Sync.fetchAll(str, {
identifier
})
result = result[1]
if not result then return false end
local firstname, lastname, phone
if Config.Framework == 'esx' then
firstname = result.firstname
lastname = result.lastname
phone = result.phone_number
elseif Config.Framework == 'qb' then
local data = json.decode(result.charinfo)
firstname = data.firstname
lastname = data.lastname
phone = data.phone
end
if not phone and Config.Framework == 'esx' then
phone = Config.Prefix .. math.random(StartDigit, FinishDigit)
MySQL.Sync.execute('UPDATE `users` SET `phone_number` = ? WHERE `identifier` = ?', {
phone,
identifier
})
end
Debug('GetUserData', identifier, 'firstname', firstname, 'lastname', lastname, 'phone', phone)
return firstname, lastname, phone
end
function InitPhoneMeta(src, slot, data)
if Config.Framework == 'esx' then
QSInventory:SetItemMetadata(src, slot, data)
else
local player = GetPlayerFromId(src)
player.PlayerData.items[slot].info.metadata = data.metadata
player.PlayerData.items[slot].info.charinfo = data.charinfo
player.PlayerData.items[slot].info.phoneNumber = data.phoneNumber
player.PlayerData.items[slot].info.owneridentifier = data.owneridentifier
player.Functions.SetInventory(player.PlayerData.items)
end
Debug('Init phone meta', src, slot, data)
end
function SaveMetadataToInventory(src, customNumber)
local player = GetPlayerFromId(src)
local items = GetItems(player)
local slot = 0
if not items then return Debug('Save metadata to inventory failed. items is nil', 'Player src:', src) end
local phone = customNumber or MetaData[src].phoneNumber
for k, v in pairs(items) do
local meta = v.info and v.info or v.metadata
if meta.phoneNumber == phone and PhoneIsUseable(meta.uniqueId) then
slot = v.slot
break
end
end
QSInventory:SetItemMetadata(src, slot, MetaData[src])
end
function RegisterItems()
for k, v in pairs(Config.Phones) do
RegisterUsableItem(k, function(source, item)
local identifier = GetIdentifier(source)
if not item?.info or not item?.info?.phoneNumber then
local firstname, lastname = GetUserData(identifier)
local info = CreatePhoneMetaData({
firstname = firstname,
lastname = lastname,
identifier = identifier,
})
item.info = info
InitPhoneMeta(source, item.slot, info)
Debug('Created phone meta')
end
TriggerClientEvent('phone:openPhone', source, v, k, item.info)
end)
end
end
exports('handleDeleteItem', function(source, itemData)
if itemData then
local metaPhone = MetaData[source]?.phoneNumber
local itemIsPhone = ItemIsPhone(itemData.name)
if not itemIsPhone then return end
local itemPhoneNumber = itemData.info.phoneNumber
if metaPhone and itemPhoneNumber and itemPhoneNumber == metaPhone then
MetaData[source] = nil
TriggerClientEvent('phone:UpdatedMeta', source, nil)
Debug('Cleared metadata. for: ' .. source)
end
else
local metaPhone = MetaData[source]?.phoneNumber
local existPhone = FindUserExistPhone(source, metaPhone)
if not existPhone then
MetaData[source] = nil
TriggerClientEvent('phone:UpdatedMeta', source, nil)
Debug('Cleared metadata. for: ' .. source)
end
end
end)

View File

@@ -0,0 +1,100 @@
---@diagnostic disable
if Config.Inventory ~= 'tgiann-inventory' then
return
end
function GetUserData(identifier)
local str = ([[
SELECT %s FROM %s WHERE %s = ?
]]):format(Config.Framework == 'esx' and 'firstname, lastname, phone_number' or 'charinfo', userColumn, identifierTable)
local result = MySQL.Sync.fetchAll(str, {
identifier
})
result = result[1]
if not result then return false end
local firstname, lastname, phone
if Config.Framework == 'esx' then
firstname = result.firstname
lastname = result.lastname
phone = result.phone_number
elseif Config.Framework == 'qb' then
local data = json.decode(result.charinfo)
firstname = data.firstname
lastname = data.lastname
phone = data.phone
end
if not phone and Config.Framework == 'esx' then
phone = Config.Prefix .. math.random(StartDigit, FinishDigit)
MySQL.Sync.execute('UPDATE `users` SET `phone_number` = ? WHERE `identifier` = ?', {
phone,
identifier
})
end
return firstname, lastname, phone
end
function InitPhoneMeta(src, slot, info)
local item = exports["tgiann-inventory"]:GetItemBySlot(src, slot)
if not item then return end
exports["tgiann-inventory"]:UpdateItemMetadata(src, item.name, item.slot, info)
Debug('Init phone meta', src, json.encode(item))
end
function SaveMetadataToInventory(src, customNumber)
local items = exports["tgiann-inventory"]:GetPlayerItems(src)
if not items then return end
local phone = customNumber or MetaData[src].phoneNumber
for _, v in pairs(items) do
local meta = v.info
if meta.phoneNumber == phone and PhoneIsUseable(meta.uniqueId) then
exports["tgiann-inventory"]:UpdateItemMetadata(src, v.name, v.slot, MetaData[src])
break
end
end
end
function RegisterItems()
for k, v in pairs(Config.Phones) do
print(k, "registired")
RegisterUsableItem(k, function(source, item)
if not item?.info or not item?.info?.phoneNumber then
local identifier = GetIdentifier(source)
local firstname, lastname = GetUserData(identifier)
local info = CreatePhoneMetaData({
firstname = firstname,
lastname = lastname,
identifier = identifier,
})
item.info = info
InitPhoneMeta(source, item.slot, info)
Debug('Created phone meta')
print('Created phone meta')
end
print("open")
print(json.encode(item))
TriggerClientEvent('phone:openPhone', source, v, k, item.info)
end)
end
end
exports('handleDeleteItem', function(source, itemData)
if itemData then
local metaPhone = MetaData[source]?.phoneNumber
local itemIsPhone = ItemIsPhone(itemData.name)
if not itemIsPhone then return end
local itemPhoneNumber = itemData.info.phoneNumber
if metaPhone and itemPhoneNumber and itemPhoneNumber == metaPhone then
MetaData[source] = nil
TriggerClientEvent('phone:UpdatedMeta', source, nil)
Debug('Cleared metadata. for: ' .. source)
end
else
local metaPhone = MetaData[source]?.phoneNumber
local existPhone = FindUserExistPhone(source, metaPhone)
if not existPhone then
MetaData[source] = nil
TriggerClientEvent('phone:UpdatedMeta', source, nil)
Debug('Cleared metadata. for: ' .. source)
end
end
end)

View File

@@ -0,0 +1,35 @@
local securedFileTypes = {
'image',
'audio',
'video'
}
---@param source number
---@param fileType string
---@return string
lib.callback.register('phone:getPresignedUrl', function(source, fileType)
if Config.Webhook == '' then
Error('Webhook is empty, please set a webhook in the server/custom/webhooks/webhooks.lua file. Or you are not be able to use the voice recorder, camera, and video recorder.')
return ''
end
if not table.includes(securedFileTypes, fileType) then
Error('Invalid file type', fileType, 'source', source)
return ''
end
local url = ('https://fmapi.net/api/v2/presigned-url?fileType=%s'):format(fileType)
local promise = promise.new()
PerformHttpRequest(url, function(err, text, headers)
local data = json.decode(text)
if not data then
return promise:resolve('')
end
if data.status ~= 'ok' then
Error('Failed to get presigned url', data)
return promise:resolve('')
end
promise:resolve(data.data.presignedUrl)
end, 'GET', nil, {
Authorization = Config.Webhook
})
return Citizen.Await(promise)
end)

View File

@@ -0,0 +1,31 @@
RegisterServerCallback('phone:getBankData', function(source, cb)
local src = source
local bankMoney = GetBankMoney(src)
local invoices = GetInvoices(src)
cb({
balance = bankMoney,
invoices = invoices,
})
end)
RegisterServerCallback('phone:payInvoice', function(source, cb, invoiceId)
local src = source
local bill = MySQL.Sync.fetchAll('SELECT * FROM `phone_bills` WHERE `id` = ?', { invoiceId })
if not bill[1] then
TriggerClientEvent('phone:client:sendTextMessage', src, Lang('PHONE_NOTIFICATION_BANK_BILL_NO_DATA'), 'error')
return cb(false)
end
bill = bill[1]
local price = bill.price
local sender = bill.sender
local bankMoney = GetBankMoney(src)
if bankMoney >= price then
MySQL.Sync.execute('DELETE FROM `phone_bills` WHERE `id` = ?', { invoiceId })
RemoveBankMoney(src, price)
TriggerClientEvent('phone:client:sendTextMessage', src, Lang('PHONE_NOTIFICATION_BANK_BILL_PAID') .. price, 'success')
cb(true)
else
TriggerClientEvent('phone:client:sendTextMessage', src, Lang('PHONE_NOTIFICATION_BANK_BILL_NO_MONEY'), 'error')
cb(false)
end
end)

View File

@@ -0,0 +1,153 @@
function CreateQuests(source)
if GetResourceState('qs-inventory') ~= 'started' then
Debug('qs-inventory not started, skipping phone quest creation.')
return
end
local quest1 = exports['qs-inventory']:createQuest(source, {
name = 'hack_catcord',
title = 'Catcord Hacker',
description = 'Hack your smartphone to unlock hidden Catcord rooms.',
reward = 150,
requiredLevel = 1
})
local quest2 = exports['qs-inventory']:createQuest(source, {
name = 'use_taxi_app',
title = 'Call Me a Cab',
description = 'Take a ride using the Taxi app.',
reward = 100,
requiredLevel = 0
})
local quest3 = exports['qs-inventory']:createQuest(source, {
name = 'download_apps',
title = 'App Collector',
description = 'Download 5 different apps on your phone.',
reward = 200,
requiredLevel = 1
})
local quest4 = exports['qs-inventory']:createQuest(source, {
name = 'create_tweet',
title = 'First Tweet',
description = 'Post your first tweet using the Twitter app on your phone.',
reward = 150,
requiredLevel = 0
})
local quest5 = exports['qs-inventory']:createQuest(source, {
name = 'buy_crypto',
title = 'Crypto Curious',
description = 'Buy your first cryptocurrency.',
reward = 250,
requiredLevel = 2
})
local quest6 = exports['qs-inventory']:createQuest(source, {
name = 'take_photo',
title = 'Say Cheese!',
description = 'Take a photo using your smartphone camera.',
reward = 100,
requiredLevel = 0
})
local quest7 = exports['qs-inventory']:createQuest(source, {
name = 'make_call',
title = 'Can You Hear Me?',
description = 'Make a phone call using your smartphone.',
reward = 100,
requiredLevel = 0
})
local quest8 = exports['qs-inventory']:createQuest(source, {
name = 'create_contact',
title = 'Stay Connected',
description = 'Add a new contact to your smartphone.',
reward = 100,
requiredLevel = 0
})
local quest9 = exports['qs-inventory']:createQuest(source, {
name = 'send_email',
title = 'Inbox Outbox',
description = 'Send an email using your smartphone.',
reward = 150,
requiredLevel = 0
})
local quest10 = exports['qs-inventory']:createQuest(source, {
name = 'send_money_bank_app',
title = 'Mobile Transfer',
description = 'Send money to another player using the banking app.',
reward = 200,
requiredLevel = 1
})
local quest11 = exports['qs-inventory']:createQuest(source, {
name = 'register_social_network',
title = 'Social Starter',
description = 'Register an account on a social media app.',
reward = 150,
requiredLevel = 0
})
local quest12 = exports['qs-inventory']:createQuest(source, {
name = 'post_instagraph',
title = 'Insta Moment',
description = 'Create a post and upload a photo using Instagraph.',
reward = 200,
requiredLevel = 1
})
local quest13 = exports['qs-inventory']:createQuest(source, {
name = 'post_ticktock',
title = 'TickTock Star',
description = 'Post a video on the TickTock app.',
reward = 200,
requiredLevel = 1
})
local quest14 = exports['qs-inventory']:createQuest(source, {
name = 'post_yellow_pages',
title = 'Business Blast',
description = 'Create a public post using Yellow Pages.',
reward = 150,
requiredLevel = 0
})
local quest15 = exports['qs-inventory']:createQuest(source, {
name = 'get_job_jobcenter',
title = 'Career Kickstart',
description = 'Get a job using the Job Center app on your smartphone.',
reward = 200,
requiredLevel = 0
})
local quest16 = exports['qs-inventory']:createQuest(source, {
name = 'rent_vehicle_aventon',
title = 'Ready to Ride',
description = 'Rent a vehicle using the Aventon app on your smartphone.',
reward = 200,
requiredLevel = 0
})
Debug('Phone quests assigned to player:', source, {
hack_catcord = quest1,
use_taxi_app = quest2,
download_apps = quest3,
create_tweet = quest4,
buy_crypto = quest5,
take_photo = quest6,
make_call = quest7,
create_contact = quest8,
send_email = quest9,
send_money_bank_app = quest10,
register_social_network = quest11,
post_instagraph = quest12,
post_ticktock = quest13,
post_yellow_pages = quest14,
get_job_jobcenter = quest15,
rent_vehicle_aventon = quest16
})
end

View File

@@ -0,0 +1,22 @@
local salty = exports['saltychat']
RegisterNetEvent('phone:addToCall', function(callId)
local src = source
if Config.Voice == 'salty' then
salty:AddPlayerToCall(tostring(callId), src)
end
end)
RegisterNetEvent('phone:removeFromCall', function(callId)
local src = source
if Config.Voice == 'salty' then
salty:RemovePlayerFromCall(tostring(callId), src)
end
end)
RegisterNetEvent('phone:toggleSpeaker', function(enabled)
local src = source
if Config.Voice == 'salty' then
salty:SetPhoneSpeaker(src, enabled == true)
end
end)

View File

@@ -0,0 +1,20 @@
--[[
Discord webhook configuration, here you can configure the private webhook
that will store all your images and below you can optionally make public
webhooks for certain apps/social networks.
In case you don't know how to create a webhook, we recommend that you read
the documentation or watch the following video: https://www.youtube.com/watch?v=fKksxz2Gdnc
If you will use public webhooks, create a new channel for each config,
remember that the main Config.Webhook should be private.
]]
-- Mandatory webhook or Fivemanage token [https://www.fivemanage.com] (full use)
Config.Webhook = ''
-- Optional webhook (public use)
Config.TikTokWebhook = ''
Config.TwitterWebhook = ''
Config.InstagramWebhook = ''
Config.YellowPagesWebhook = ''