Algorithm for Inventory system

I am going to make an Inventory system but I can’t even think about the algorithm. I need some suggestions.

This is how I think about it;

  • Create an empty Inventory table for the player in SQL when he connects for his first time ** if it isn’t his first time then send his inventory table with nets for clientside gui
  • On player try to pick an item, start a net to server about it and do checks & if ok then write it to the Inventory table for the player
  • Reply with a net from server to the player who picked the item to update his clientside inventory table for GUI
  • Do all these communication with nets when player drop/pickup/remove things from/to his inventory.

I don’t think my plan is efficient so I need help.

Create a new table per player? That sounds like bad practice to me.

Do you have any other idea? I mean inserting into a big table by the way. Not creating it

Inventory table:

item_uid (unique ref to that inv item)
item_entity (what is it?)
item_player (who is carrying it)

I may be underthinking this but you then need function for
picking stuff up:
check if item can be picked up
check if player is allowed to pick up (arrested, dead, full inv)
remove entity
create new row in inventory table

dropping stuff ( item_uid <int> item you wish to drop )
does that item exist in their inventory ie is item_player = player for item_uid = item_uid
are they allowed to drop?
remove row
create entity

I have never created an inventory addon so there could be better ways of doing it. I’m just saying what comes to my mind.

Firstly, you would need to create a new row per player not a new table as, some what, mentioned above.
You can store the players current inventory on the server by setting a player variable like player.inventory = {}. When ever the player attempts to add something to their inventory, send a net message to the server, do your validity checks, and add it to their inventory table, then send a net message back telling them to update the table on their end too. When you update the players table, you will also have to update the players inventory in the sql table. Which you could do by using tabletojson and storing it in a text field or something.

When the player first connects and you need to send them their inventory, you would run an sql query and set ply.inventory = jsontotable(query data) Then send them a net message with their inventory and update the table variable on the clients side.

I think it should be done as you said. Thanks

[editline]3rd March 2017[/editline]

Thanks, that makes sense as well.

Storing things as json in sql is bad practice, because if you store it as json and you want to query all players who have a specific item, you wont be able to do that.
He should definitely do what mdeceiver79 said, instead of storing as json.

If he doesn’t plan on querying every player that has ever joined his server, I don’t really see a problem.

As Metamist says it’s bad practice, it also brings issues with concurrency, if you one of your queries uses an outdated json-blob for the players items will go missing or duplicated. You also need to send the entire inventory with each and every edit instead of just saying which item is to be added or removed from the table. In the end it brings a lot of issues.

you can first check if the table exists then check if the player’s invetory exists in the table easy just check wat the value returns.

This function creates an inventory table:

[lua]function Player:CreateInventory()

local Inventory = {}

for i=1,32 do 
	table.insert(Inventory, {Slot = 0, ID = 0, Quantity = 0, Ref = "" })
end

return Inventory

end[/lua]

This sets an item on a designated slot:

[lua]function Player:SetItem(slot, id, quantity)

self.Inventory[slot].Slot     = slot
self.Inventory[slot].ID       = id
self.Inventory[slot].Quantity = quantity
self.Inventory[slot].Ref 	  = ITEM_DB[tonumber(id)].Ref

end[/lua]

This function gives an item to a player, if he doesn’t already have the item in the inventory it puts it to a unassigned slot:

[lua]
function Player:GiveItem(id, quantity)
local inv = self.Inventory

	for k, v in pairs(self.Inventory) do
		if v.ID == id then

			inv[k].Slot = k
			inv[k].Quantity = v.Quantity + quantity

			break
		end

		if v.ID == 0 then

			inv[k] = {Slot = k, ID = id, Quantity = quantity, Ref = ITEM_DB[id].Ref}

			break
		end
	end

end[/lua]

Removing an item :

[lua]
function Player:RemoveItem(id, quantity)
local inv = self.Inventory

	for k, v in pairs(inv) do
		if v.ID == id then

			local quant = v.Quantity

			if (quant - quantity) &gt; 0 then

				inv[k].Quantity = v.Quantity - quantity

				break
			elseif (quant - quantity) &lt;= 0 then

				self:ClearSlot(v.Slot)

				break	
			end
			break
		end
	end

end[/lua]

This changes an item with an other slot or another item(Item is in the 2nd slot, you want to put it into the 30th slot):

[lua]function Player:ChangeItemSlot(oldslot, newslot) --If there’s an item in the newslot, switch it

	local inv = self.Inventory

	if newslot &gt; 32 && oldslot &gt; 32 then

		print('Slot number is too high')
		return

	elseif oldslot == newslot then
		
		print("Can't have the same slot number!")
		return

	elseif oldslot &gt; newslot then

		local old = oldslot
		oldslot = newslot
		newslot = old

	end

	for k, v in pairs(inv) do 

		if self:SlotIsEmpty(newslot) then
			self:SetItem(newslot, v.ID, v.Quantity)
			self:ClearSlot(oldslot)
			
			break
		end

		if not self:SlotIsEmpty(newslot) then
			local oldid, oldquantity = inv[newslot].ID, inv[newslot].Quantity
			self:SetItem(newslot, v.ID, v.Quantity)
			self:SetItem(oldslot, oldid, oldquantity)

			break
		end
	end	

end[/lua]

And some utility functions :

[lua]function Player:SlotIsEmpty(slot)
local inv = self.Inventory

if inv[slot].ID == 0 then
	return true
else
	return false
end

end

function Player:ClearSlot(slot)
local inv = self.Inventory

for k,v in pairs(inv) do
	if v.Slot == slot then
		inv[k] = {Slot = 0, ID = 0, Quantity = 0, Ref = ""}
		break
	end
end

end[/lua]

And finally to create the inventory:

[lua]function GM:PlayerInitialSpawn(ply)
ply.Inventory = ply:CreateInventory()
end[/lua]

I don’t recommend that you copy and paste this(It’s probably not going to work), but it can give you an idea on how to design an inventory system.