server/editable.lua
local tgiCore = tgiCoreExports:getCore()
local function GiveStarterItems(source)
local src = source
if config.framework == "qb" then
Wait(2000)
local Player = tgiCore.getPlayer(src)
for _, v in pairs(tgiCore.core.Shared.StarterItems) do
local info = {}
if v.item == "id_card" then
info.citizenid = Player.PlayerData.citizenid
info.firstname = Player.PlayerData.charinfo.firstname
info.lastname = Player.PlayerData.charinfo.lastname
info.birthdate = Player.PlayerData.charinfo.birthdate
info.gender = Player.PlayerData.charinfo.gender
info.nationality = Player.PlayerData.charinfo.nationality
elseif v.item == "driver_license" then
info.firstname = Player.PlayerData.charinfo.firstname
info.lastname = Player.PlayerData.charinfo.lastname
info.birthdate = Player.PlayerData.charinfo.birthdate
info.type = "Class C Driver License"
end
tgiCore.addItem(Player, v.item, v.amount, false, info)
end
end
end
-- For QB
local function loadHouseData(src)
local HouseGarages = {}
local Houses = {}
local result = MySQL.query.await('SELECT * FROM houselocations', {})
if result[1] ~= nil then
for _, v in pairs(result) do
local owned = false
if tonumber(v.owned) == 1 then
owned = true
end
local garage = v.garage ~= nil and json.decode(v.garage) or {}
Houses[v.name] = {
coords = json.decode(v.coords),
owned = owned,
price = v.price,
locked = true,
adress = v.label,
tier = v.tier,
garage = garage,
decorations = {},
}
HouseGarages[v.name] = {
label = v.label,
takeVehicle = garage,
}
end
end
TriggerClientEvent("qb-garages:client:houseGarageConfig", src, HouseGarages)
TriggerClientEvent("qb-houses:client:setHouseConfig", src, Houses)
end
tgiCore.cbFunction('tgiann-multichar:spawnselector:getOwnedHouses', function(_, cb, cid)
local houses = querySync('SELECT * FROM player_houses WHERE citizenid = ?', { cid })
cb(houses)
end)
local function getSkinData(identifier)
local skinData
if config.tgiann_clothing then
local result = singleSync('SELECT `skin`, `model` FROM `tgiann_skin` WHERE `citizenid` = ?', { identifier })
if result?.model and result?.skin then
skinData = {
model = result.model,
skin = json.decode(result.skin)
}
end
elseif config.framework == "qb" then
local result = singleSync('SELECT `skin`, `model` FROM playerskins WHERE citizenid = ? AND active = ?', { identifier, 1 })
skinData = {
model = result.model,
skin = json.decode(result.skin)
}
end
return skinData
end
function getPlayerChars(src)
local charData = {}
local identifier = GetPlayerIdentifierByType(src, config.identifierType):gsub(string.format("%s:", config.identifierType), "")
if config.framework == "esx" then
local response = querySync('SELECT `identifier`, `accounts`, `firstname`, `lastname`, `dateofbirth`, `sex`, `job`, `height`, `position` FROM `users` WHERE `identifier` LIKE @identifier', {
["@identifier"] = "%" .. identifier
})
for i = 1, #response do
local data = response[i]
data.accounts = json.decode(data.accounts)
local _, _, number = string.find(data.identifier, "char(%d+):")
local index = tonumber(number)
charData[index] = {
playerData = {
index = index,
identifier = data.identifier,
name = data.firstname .. " " .. data.lastname,
job = data.job,
lastLocation = json.decode(data.position)
},
uiData = {
{
icon = "bank.svg",
label = lang.bank,
value = tgiCore.FormatNum(data.accounts.bank) .. "$"
},
{
icon = "money.svg",
label = lang.money,
value = tgiCore.FormatNum(data.accounts.money) .. "$"
},
{
icon = "dob.svg",
label = lang.dateOfBirth,
value = data.dateofbirth
},
{
icon = "sex.svg",
label = lang.sex,
value = data.sex == "m" and lang.sexMale or lang.sexFemale
},
{
icon = "height.svg",
label = lang.height,
value = data.height .. "cm"
},
}
}
local imgData = singleSync('SELECT `img` FROM `tgiann_multichar_img` WHERE `citizenid` = ?', { data.identifier })
charData[index].playerData.img = imgData?.img
charData[index].skinData = getSkinData(data.identifier)
end
elseif config.framework == "qb" then
local license = GetPlayerIdentifierByType(src, config.identifierType)
local response = querySync('SELECT `citizenid`, `cid`, `license`, `money`, `charinfo`, `job`, `position` FROM `players` WHERE `license` = ?', {
license
})
for i = 1, #response do
local data = response[i]
data.charinfo = json.decode(data.charinfo)
data.money = json.decode(data.money)
data.job = json.decode(data.job)
local index = tonumber(data.cid)
charData[index] = {
playerData = {
index = index,
citizenid = data.citizenid,
identifier = data.license,
name = data.charinfo.firstname .. " " .. data.charinfo.lastname,
job = data.job.label,
lastLocation = json.decode(data.position)
},
uiData = {
{
icon = "bank.svg",
label = lang.bank,
value = tgiCore.FormatNum(data.money.bank) .. "$"
},
{
icon = "money.svg",
label = lang.money,
value = tgiCore.FormatNum(data.money.money) .. "$"
},
{
icon = "dob.svg",
label = lang.dateOfBirth,
value = data.charinfo.birthdate
},
{
icon = "sex.svg",
label = lang.sex,
value = data.charinfo.gender == 0 and lang.sexMale or lang.sexFemale
},
}
}
local imgData = singleSync('SELECT `img` FROM `tgiann_multichar_img` WHERE `citizenid` = ?', { data.citizenid })
charData[index].playerData.img = imgData?.img
charData[index].skinData = getSkinData(data.citizenid)
end
end
return charData
end
function getPlayerCharAmounts(src)
local identifier = GetPlayerIdentifierByType(src, config.identifierType)
if config.framework == "esx" then
local esxIdentifier = identifier:gsub(string.format("%s:", config.identifierType), "")
result = singleSync('SELECT COUNT(*) FROM users WHERE `identifier` LIKE @identifier', { ["@identifier"] = "%" .. esxIdentifier })
elseif config.framework == "qb" then
result = singleSync('SELECT COUNT(*) FROM players WHERE `license` = ?', { identifier })
end
return result["COUNT(*)"]
end
tgiCore.cbFunction("tgiann-multichar:multichar:deleteChar", function(source, cb, playerData)
local src = source
local playerIdentifier = GetPlayerIdentifierByType(src, "license")
local identifier = config.framework == "esx" and playerData.identifier or playerData.citizenid
if config.framework == "esx" then
if removeBeforeDelimiter(identifier, ":") ~= removeBeforeDelimiter(playerIdentifier, ":") then
print(("[^8ANTI-CHEAT^7] Player ^5%s %s (%s)^7 tried to delete another player's character"):format(GetPlayerName(src), src, playerIdentifier))
DropPlayer(src, "Tried to delete another player's character")
cb(false)
return
end
elseif config.framework == "qb" then
local result = MySQL.scalar.await('SELECT license FROM players where citizenid = ?', { playerData.citizenid })
if playerIdentifier ~= result then
print(("[^8ANTI-CHEAT^7] Player ^5%s %s (%s)^7 tried to delete another player's character"):format(GetPlayerName(src), src, playerIdentifier))
DropPlayer(src, "Tried to delete another player's character")
cb(false)
return
end
end
local query = "DELETE FROM `%s` WHERE %s = ?"
local queries = {}
local deleteTables = config.deleteTables[config.framework]
for i = 1, #deleteTables do
local deleteTable = deleteTables[i]
queries[#queries + 1] = { query = query:format(deleteTable.table, deleteTable.column), values = { identifier } }
end
transaction(queries, function(result)
if result then
print(("[^2INFO^7] Player ^5%s %s^7 has deleted a character ^5(%s)^7"):format(GetPlayerName(src), src, identifier))
cb(true)
else
error("\n^1Transaction failed while trying to delete " .. identifier .. "^0")
cb(false)
end
end)
end)
RegisterNetEvent("tgiann-multichar:multichar:createChar")
AddEventHandler("tgiann-multichar:multichar:createChar", function(charData)
local src = source
if config.framework == "esx" then
local data = {
firstname = charData.firstName,
lastname = charData.lastName,
dateofbirth = string.format("%s/%s/%s", charData.day, charData.month, charData.year),
sex = charData.isMale and "m" or "f",
height = charData.height
}
local charId = string.format("char%s", charData.createCharIndex)
TriggerEvent("esx:onPlayerJoined", src, charId, data)
elseif config.framework == "qb" then
local newData = {}
newData.cid = charData.createCharIndex
newData.charinfo = {
firstname = charData.firstName,
lastname = charData.lastName,
nationality = "",
birthdate = string.format("%s/%s/%s", charData.day, charData.month, charData.year),
gender = charData.isMale and 0 or 1,
height = charData.height,
cid = charData.createCharIndex
}
if tgiCore.core.Player.Login(src, false, newData) then
if config.qb_apartments and Apartments?.Starting then
SetPlayerRoutingBucket(src, (GetPlayerPed(src) .. math.random(1, 999)))
tgiCore.core.Commands.Refresh(src)
loadHouseData(src)
TriggerClientEvent("tgiann-multichar:multichar:qbCharCreated", src, newData)
GiveStarterItems(src)
else
tgiCore.core.Commands.Refresh(src)
loadHouseData(src)
TriggerClientEvent("tgiann-multichar:multichar:qbCharCreated", src, newData)
GiveStarterItems(src)
end
end
end
end)
tgiCore.cbFunction("tgiann-multichar:spawnselector:CharacterChosen", function(source, cb, identifier)
local src = source
if config.framework == "esx" then
TriggerEvent("esx:onPlayerJoined", src, removeAfterDelimiter(identifier, ":"))
cb("")
else
if tgiCore.core.Player.Login(src, identifier) then
tgiCore.core.Commands.Refresh(src)
loadHouseData(src)
cb("")
end
end
end)
function playerLogout(src)
if config.framework == "esx" then
TriggerEvent("esx:playerLogout", src)
else
tgiCore.core.Player.Logout(src)
end
TriggerClientEvent("tgiann_multichar:multichar:client:logout", src)
end
RegisterNetEvent("tgiann_multichar:logout")
AddEventHandler("tgiann_multichar:logout", function()
playerLogout(source)
end)
exports("Logout", playerLogout)
-- the player increases the character unlock slot by one with each purchase
RegisterCommand("tbx_multichar_limit", function(source, args)
if source > 0 then return end
local tbxId = args[1]
local customerId = args[2]
local serverId = tonumber(args[3])
local identifier = GetPlayerIdentifierByType(serverId, config.identifierType)
insert('INSERT INTO tgiann_multichar (identifier, customerId) VALUES (?, ?) ON DUPLICATE KEY UPDATE `limit`=`limit`+1', {
identifier,
customerId,
})
end)
Last updated