I figured out how to set the second member in sSlotInfo struct. It’s cumbersome, but you have to set the individual members, int by int, and keep track of the offset for the remaining members. Like so:
local sSlotInfo = DataView.ArrayBuffer(128)
sSlotInfo:SetInt32(0, 0)
sSlotInfo:SetInt32(0, sGuid:GetInt32(0))
sSlotInfo:SetInt32(8, sGuid:GetInt32(8))
sSlotInfo:SetInt32(16, sGuid:GetInt32(16))
sSlotInfo:SetInt32(24, sGuid:GetInt32(24))
sSlotInfo:SetInt32(16, 0)
sSlotInfo:SetInt32(24, 0)
sSlotInfo:SetInt32(32, 0)
I have now ported TuffyTown’s code into Lua and added some code for weapons which, unfortunately, doesn’t work. It’s annoying because the WEAPON_MELEE_LANTERN should added to your inventory so you can equip after switching weapon.
It’s very cool to see food (e.g., CONSUMABLE_PEACHES_CAN) finally in my inventory in RedM, but when I select and use it, nothing happens. It would be very interesting to see if we can hook an event or someway find out how to detect this action and implement it ourselves. Here’s my Lua port:
function NewGuid()
local struct = DataView.ArrayBuffer(8 * 4)
struct:SetInt32(0, 0)
struct:SetInt32(8, 0)
struct:SetInt32(16, 0)
struct:SetInt32(24, 0)
return struct
end
function NewSlotInfo()
local guid = NewGuid()
local struct = DataView.ArrayBuffer(8 * 8)
-- Begin guid memmber
struct:SetInt32(0, guid:GetInt32(0))
struct:SetInt32(8, guid:GetInt32(8))
struct:SetInt32(16, guid:GetInt32(16))
struct:SetInt32(24, guid:GetInt32(24))
-- end guid member
struct:SetInt32(32, 0) -- int f_1;
struct:SetInt32(40, 0) -- int f_2;
struct:SetInt32(48, 0) -- int f_3;
struct:SetInt32(56, 0) -- int slotId
struct.GetGuid = function()
return guid:Buffer()
end
struct.SetGuid = function(newGuid)
struct:SetInt32(0, newGuid:GetInt32(0))
struct:SetInt32(8, newGuid:GetInt32(8))
struct:SetInt32(16, newGuid:GetInt32(16))
struct:SetInt32(24, newGuid:GetInt32(24))
end
return struct
end
function NewItemInfo()
local struct = DataView.ArrayBuffer(8 * 6)
struct:SetInt32(0, 0)
struct:SetInt32(8, 0)
struct:SetInt32(16, 0)
struct:SetInt32(24, 0)
struct:SetInt32(32, 0)
struct:SetInt32(40, 0)
struct:SetInt32(48, 0)
return struct
end
function GetPlayerInventoryItemGUID(item, pGuid, slotId)
local outGuid = NewGuid()
local result = Citizen.InvokeNative(0x886DFD3E185C8A89, 1, pGuid, item, slotId, outGuid:Buffer(), Citizen.ResultAsInteger());
if result ~= 1 then
print("ERROR: Failed to execute INVENTORY_GET_GUID_FROM_ITEMID")
end
return outGuid;
end
-- Gets an item's GUID from the inventory
function GetPlayerInventoryGUID()
return GetPlayerInventoryItemGUID(`CHARACTER`, NewGuid():Buffer(), `SLOTID_NONE`);
end
-- Gets an item's group hash (eInvItemGroup)
function GetItemGroup(item)
local info = NewItemInfo()
if false == ItemdatabaseIsKeyValid(item, 0) then
print("ERROR: ItemdatabaseIsKeyValid is not valid")
return 0
end
if false == Citizen.InvokeNative(0xFE90ABBCBFDC13B2, item, info:Buffer()) then
print("ERROR: ItemdatabaseFilloutItemInfo returned error")
return 0
end
return info:GetInt32(16);
end
-- Gets an item's slot info data
function GetItemSlotInfo(item)
local slotInfo = NewSlotInfo()
slotInfo:SetGuid(GetPlayerInventoryGUID())
slotInfo:SetInt32(56, `SLOTID_SATCHEL`)
local group = GetItemGroup(item)
if group == `CLOTHING` then
if Citizen.InvokeNative(0x780C5B9AE2819807, item, `SLOTID_WARDROBE`) then -- _INVENTORY_FITS_SLOT_ID
slotInfo:SetGuid( GetPlayerInventoryItemGUID(`WARDROBE`, slotInfo:GetGuid(), `SLOTID_WARDROBE`) )
slotInfo:SetInt32(56, GetDefaultItemSlotInfo(item, `WARDROBE`))
else
slotInfo:SetInt32(56, GetDefaultItemSlotInfo(item, `SLOTID_WARDROBE`))
end
elseif group == `WEAPON` then
if Citizen.InvokeNative(0x780C5B9AE2819807, item, `SLOTID_WEAPON_0`) then
slotInfo:SetInt32(56, `SLOTID_WEAPON_0`)
end
if Citizen.InvokeNative(0x780C5B9AE2819807, item, `SLOTID_WEAPON_1`) then
slotInfo:SetInt32(56, `SLOTID_WEAPON_1`)
end
elseif group == `HORSE` then
slotInfo:SetInt32(56, `SLOTID_ACTIVE_HORSE`)
elseif group == `EMOTE` then
elseif group == `UPGRADE` then
if Citizen.InvokeNative(0x780C5B9AE2819807, item, `SLOTID_UPGRADE`) then
slotInfo:SetInt32(56, `SLOTID_UPGRADE`)
end
else
if Citizen.InvokeNative(0x780C5B9AE2819807, item, `SLOTID_SATCHEL`) then
slotInfo:SetInt32(56, `SLOTID_SATCHEL`)
elseif Citizen.InvokeNative(0x780C5B9AE2819807, item, `SLOTID_WARDROBE`) then
slotInfo:SetInt32(56, `SLOTID_WARDROBE`)
else
slotInfo:SetInt32(56, GetDefaultItemSlotInfo(item, `CHARACTER`))
end
end
return slotInfo
end
-- Adds an item to the player inventory via GUID
function AddItemWithGUID(item, guid, slotInfo, quantity, addReason)
if false == Citizen.InvokeNative(0xB881CA836CC4B6D4, slotInfo:GetGuid()) then
print("INVALID GUID")
return false
end
if false == Citizen.InvokeNative(0xCB5D11F9508A928D, 1, guid:Buffer(), slotInfo:GetGuid(), item, slotInfo:GetInt32(56), quantity, addReason) then
print("FAILED TO ADD TO INVENTORY")
return false
end
return true;
end
-- Adds an item to the player inventory via hash
-- This is the main function you will be calling to add items to your inventory
function AddItemToInventory(item, quantity)
local slotInfo = GetItemSlotInfo(item);
local guid = GetPlayerInventoryItemGUID(item, slotInfo:GetGuid(), slotInfo:GetInt32(56));
return AddItemWithGUID(item, guid, slotInfo, quantity, `ADD_REASON_DEFAULT`);
end
Example use:
AddItemToInventory(`CONSUMABLE_PEACHES_CAN`, 1)