Skip to content

Instantly share code, notes, and snippets.

@solareon
Created August 20, 2024 15:48
Show Gist options
  • Save solareon/7133a635fa56191a3d5a17a696a1abb8 to your computer and use it in GitHub Desktop.
Save solareon/7133a635fa56191a3d5a17a696a1abb8 to your computer and use it in GitHub Desktop.
qb-inventory to ox_inventory conversion code
convertDatabase = function()
local Items = {}
local function newItem(data)
data.weight = data.weight or 0
Items[data.name] = data
end
for type, data in pairs(lib.load('data.weapons')) do
for k, v in pairs(data) do
v.name = k
v.close = type == 'Ammo' and true or false
v.weight = v.weight or 0
if type == 'Weapons' then
---@cast v OxWeapon
v.model = v.model or k -- actually weapon type or such? model for compatibility
v.hash = joaat(v.model)
v.stack = v.throwable and true or false
v.durability = v.durability or 0.05
v.weapon = true
else
v.stack = true
end
v[type == 'Ammo' and 'ammo' or type == 'Components' and 'component' or type == 'Tints' and 'tint' or 'weapon'] = true
if isServer then v.client = nil else
v.count = 0
v.server = nil
local clientData = v.client
if clientData?.image then
clientData.image = setImagePath(clientData.image)
end
end
ItemList[k] = v
end
end
for k, v in pairs(lib.load('data.items')) do
v.name = k
local success, response = pcall(newItem, v)
if not success then
warn(('An error occurred while creating item "%s" callback!\n^1SCRIPT ERROR: %s^0'):format(k, response))
end
end
Items.cash = Items.money
local function Items.Metadata(inv, item, metadata, count)
if type(inv) ~= 'table' then inv = Inventory(inv) end
if not item.weapon then metadata = not metadata and {} or type(metadata) == 'string' and {type=metadata} or metadata end
if not count then count = 1 end
---@cast metadata table<string, any>
if item.weapon then
if type(metadata) ~= 'table' then metadata = {} end
if not metadata.durability then metadata.durability = 100 end
if not metadata.ammo and item.ammoname then metadata.ammo = 0 end
if not metadata.components then metadata.components = {} end
if metadata.registered ~= false and (metadata.ammo or item.name == 'WEAPON_STUNGUN') then
local registered = type(metadata.registered) == 'string' and metadata.registered or inv?.player?.name
metadata.registered = registered
metadata.serial = GenerateSerial(metadata.serial)
end
if item.hash == `WEAPON_PETROLCAN` or item.hash == `WEAPON_HAZARDCAN` or item.hash == `WEAPON_FERTILIZERCAN` or item.hash == `WEAPON_FIREEXTINGUISHER` then
metadata.ammo = metadata.durability
end
else
local container = Items.containers[item.name]
if container then
count = 1
metadata.container = metadata.container or GenerateText(3)..os.time()
metadata.size = container.size
elseif not next(metadata) then
if item.name == 'identification' then
count = 1
metadata = {
type = inv.player.name,
description = locale('identification', (inv.player.sex) and locale('male') or locale('female'), inv.player.dateofbirth)
}
elseif item.name == 'garbage' then
local trashType = trash[math.random(1, #trash)]
metadata.image = trashType.image
metadata.weight = trashType.weight
metadata.description = trashType.description
end
end
if not metadata.durability then
metadata = setItemDurability(ItemList[item.name], metadata)
end
end
if count > 1 and not item.stack then
count = 1
end
local response = TriggerEventHooks('createItem', {
inventoryId = inv and inv.id,
metadata = metadata,
item = item,
count = count,
})
if type(response) == 'table' then
metadata = response
end
if metadata.imageurl and Utils.IsValidImageUrl then
if Utils.IsValidImageUrl(metadata.imageurl) then
Utils.DiscordEmbed('Valid image URL', ('Created item "%s" (%s) with valid url in "%s".\n%s\nid: %s\nowner: %s'):format(metadata.label or item.label, item.name, inv.label, metadata.imageurl, inv.id, inv.owner, metadata.imageurl), metadata.imageurl, 65280)
else
Utils.DiscordEmbed('Invalid image URL', ('Created item "%s" (%s) with invalid url in "%s".\n%s\nid: %s\nowner: %s'):format(metadata.label or item.label, item.name, inv.label, metadata.imageurl, inv.id, inv.owner, metadata.imageurl), metadata.imageurl, 16711680)
metadata.imageurl = nil
end
end
return metadata, count
end
local function slotWeight(item, slot, ignoreCount)
local weight = ignoreCount and item.weight or item.weight * (slot.count or 1)
if not slot.metadata then slot.metadata = {} end
if item.ammoname and slot.metadata.ammo then
local ammoWeight = Items(item.ammoname)?.weight
if ammoWeight then
weight += (ammoWeight * slot.metadata.ammo)
end
end
if item.hash == `WEAPON_PETROLCAN` then
weight += 15000 * (slot.metadata.ammo / 100)
end
if slot.metadata.components then
for i = #slot.metadata.components, 1, -1 do
local componentWeight = Items(slot.metadata.components[i])?.weight
if componentWeight then
weight += componentWeight
end
end
end
if slot.metadata.weight then
weight += ignoreCount and slot.metadata.weight or (slot.metadata.weight * (slot.count or 1))
end
return weight
end
local function convertInventory(playerId, items)
if type(items) == 'table' then
local returnData, totalWeight = table.create(#items, 0), 0
local slot = 0
for _, data in pairs(items) do
local item = Items(data.name)
if item?.name then
local metadata, count = Items.Metadata(playerId, item, data.info, data.amount or data.count or 1)
local weight = slotWeight(item, { count = count, metadata = metadata })
totalWeight += weight
slot += 1
returnData[slot] = {
name = item.name,
label = item.label,
weight = weight,
slot = slot,
count = count,
description =
item.description,
metadata = metadata,
stack = item.stack,
close = item.close
}
end
end
return returnData, totalWeight
end
end
local users = MySQL.query.await('SELECT citizenid, inventory, money FROM players')
if not users then return end
local count = 0
local parameters = {}
for i = 1, #users do
local inventory, slot = {}, 0
local user = users[i]
local items = user.inventory and json.decode(user.inventory) or {}
local accounts = user.money and json.decode(user.money) or {}
for k, v in pairs(accounts) do
if type(v) == 'table' then break end
if k == 'cash' then k = 'money' end
if server.accounts[k] and Items(k) and v > 0 then
slot += 1
inventory[slot] = {slot=slot, name=k, count=v}
end
end
local shouldConvert = false
for _, v in pairs(items) do
if Items(v?.name) then
slot += 1
inventory[slot] = {slot=slot, name=v.name, count=v.amount, metadata = type(v.info) == 'table' and v.info or {}}
if v.type == "weapon" then
inventory[slot].metadata.durability = v.info.quality or 100
inventory[slot].metadata.ammo = v.info.ammo or 0
inventory[slot].metadata.components = {}
inventory[slot].metadata.serial = v.info.serie or lib.string.random('111111AAA111111')
inventory[slot].metadata.quality = nil
end
end
shouldConvert = v.amount and true
end
if shouldConvert then
count += 1
parameters[count] = { 'UPDATE players SET inventory = ? WHERE citizenid = ?', { json.encode(inventory), user.citizenid } }
end
end
if count > 0 then
print(('^2[info]^7 Converting %s user inventories to new data format'):format(count))
if not MySQL.transaction.await(parameters) then
return Print('^1[error]^7 An error occurred while converting player inventories')
end
Wait(100)
else
print('^2[info]^7 No user inventories to convert. Skipping..')
end
local plates = MySQL.query.await('SELECT plate, citizenid FROM player_vehicles')
if plates then
for i = 1, #plates do
plates[plates[i].plate] = plates[i].citizenid
end
local oldqbdumpsterfire, trunk = pcall(MySQL.query.await, 'SELECT plate, items FROM trunkitems')
if oldqbdumpsterfire and trunk then
table.wipe(parameters)
count = 0
local vehicles = {}
for _, v in pairs(trunk) do
local owner = plates[v.plate]
if owner then
if not vehicles[owner] then
vehicles[owner] = {}
end
if not vehicles[owner][v.plate] then
local items = json.decode(v.items) or {}
local inventory, slot = {}, 0
for _, v in pairs(items) do
if Items(v?.name) then
slot += 1
inventory[slot] = {slot=slot, name=v.name, count=v.amount, metadata = type(v.info) == 'table' and v.info or {}}
if v.type == "weapon" then
inventory[slot].metadata.durability = v.info.quality or 100
inventory[slot].metadata.ammo = v.info.ammo or 0
inventory[slot].metadata.components = {}
inventory[slot].metadata.serial = v.info.serie or lib.string.random('111111AAA111111')
inventory[slot].metadata.quality = nil
end
end
end
vehicles[owner][v.plate] = true
count += 1
parameters[count] = { 'UPDATE player_vehicles SET trunk = ? WHERE plate = ? AND citizenid = ?', { json.encode(inventory), v.plate, owner } }
end
end
end
print(('^2[info]^7 Moving ^3%s^0 trunks to the player_vehicles table'):format(count))
if count > 0 then
if not MySQL.transaction.await(parameters) then
return print('An error occurred while converting trunk inventories')
end
Wait(100)
end
end
local glovebox = oldqbdumpsterfire and MySQL.query.await('SELECT plate, items FROM gloveboxitems')
if glovebox then
table.wipe(parameters)
count = 0
local vehicles = {}
for _, v in pairs(glovebox) do
local owner = plates[v.plate]
if owner then
if not vehicles[owner] then
vehicles[owner] = {}
end
if not vehicles[owner][v.plate] then
local items = json.decode(v.items) or {}
local inventory, slot = {}, 0
for _, v in pairs(items) do
if Items(v?.name) then
slot += 1
inventory[slot] = {slot=slot, name=v.name, count=v.amount, metadata = type(v.info) == 'table' and v.info or {}}
if v.type == "weapon" then
inventory[slot].metadata.durability = v.info.quality or 100
inventory[slot].metadata.ammo = v.info.ammo or 0
inventory[slot].metadata.components = {}
inventory[slot].metadata.serial = v.info.serie or lib.string.random()
inventory[slot].metadata.quality = nil
end
end
end
vehicles[owner][v.plate] = true
count += 1
parameters[count] = { 'UPDATE player_vehicles SET glovebox = ? WHERE plate = ? AND citizenid = ?', { json.encode(inventory), v.plate, owner } }
end
end
end
print(('^2[info]^7 Moving ^3%s^0 gloveboxes to the player_vehicles table'):format(count))
if count > 0 then
if not MySQL.transaction.await(parameters) then
return print('^1[error]^7 An error occurred while converting glovebox inventories')
end
end
end
end
local qbEvidence = MySQL.query.await("SELECT stash, items FROM stashitems WHERE stash LIKE '% | Drawer%'")
if qbEvidence then
table.wipe(parameters)
count = 0
local oxEvidence = {}
for i = 1, #qbEvidence do
local qbStash = qbEvidence[i]
local name = 'evidence-'..qbStash.stash:sub(12)
local items = convertInventory(nil, (qbStash.items and json.decode(qbStash.items) or {}))
--- evidence numbers can be shared between locations, so need to maintain map and merge.
if oxEvidence[name] then
for k = 1, #items do
oxEvidence[name][#oxEvidence[name]+1] = items[k]
end
else
oxEvidence[name] = items
end
end
for name, items in pairs(oxEvidence) do
count += 1
parameters[count] = { "INSERT INTO ox_inventory (owner, name, data) VALUES ('', ?, ?) ON DUPLICATE KEY UPDATE name = VALUES(name), data = VALUES(data)", {
name, json.encode(items)
}}
end
print(('^2[info]^7 Creating ^3%s^0 evidence lockers from ^3%s^0 lockers by merging duplicate locker numbers'):format(count, #qbEvidence))
if count > 0 then
if not MySQL.transaction.await(parameters) then
return print('^1[error]^7 An error occurred while converting evidence lockers')
end
end
end
print('^2[info]^7 Successfully converted user and vehicle inventories')
end
@solareon
Copy link
Author

An incomplete fragment to convert old qb-inv format to new ox_inv format. Doesn't work due to multiple external functions missing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment