Player Inventory implemented as Collection objects

A player might own many (100 or more) items, some of which are “stackable” and thus have a usage count internally stored as a value, others which are not stackable, and each have their own custom data.

These could be stored in a collection called “inventory”. I don’t want their key to be some catalog ID, since multiple copies of the same item can exist. I would rather it be some instance ID assigned on “insertion”, so I can refer and examine each object uniquely. Is it really meant that I manage generating that guid(key) myself on adding an object in custom go.lang?

An implementation of some of the things a player owns in the JollyRoger project stores objects in a deck in a List object. Managing a huge inventory in a single object storage seems like massive overhead for lists of medium complexity or size - any operation like adding or removing would involve reading the entire list, and then writing the entire thing back into storage. (and you’d STILL end up generating some unique guid yourself anyways, to differentiate between items)

Am I missing something fundamental about document storage systems? Is there another API that adds an item to a collection with an empty key, but assigns one for you?

thanks!

Barry

1 Like

Using Nakama’s storage feature the most straightforward way to do it is to have each item be its own object. You can then list storage for that collection+user_id when you need to read the whole inventory, and use the standard read/write operations to access individual items in the inventory.

Alternatively you can store it as one single storage object and use JSONB functions and operators to access/update individual fields inside the inventory object without rewriting the whole thing each time. This sounds like what you’re leaning towards based on your initial post.

Both of these would likely involve a bit of runtime code so you can maintain control over the inventory.

Which is best depends on min/max/average size of inventory, how often is it read vs written, is it read all together frequently or is it useful to get portions of it. If you can answer some of these maybe I can offer further advice?

My question is more about what you would use as a key for the inventory collection.

If each item instance is its own storage object, you wouldn’t be able to use the catalogItemID since there could be multiple copies of the same object. There would need to be some generator for that ID. An SQL database when inserting a new object would return the auto-incremented primary key back on insert.

I’ve implemented a guid generator in server side script that can generate a random key to use on insert. It feels like I can’t be the first person that’s run into this before, so it feels like there should be a better way?

I’m using this for more than just implementation of my inventory, but an implementation of a store and catalog system.

Yes, you’re not the first person building a store/catalog and inventory system on Nakama. The implementation details vary depending on the use case but here’s a typical one.

Store/catalog:

  • A collection called catalog with keys representing items that can be purchased.
  • Keys are usually item IDs of some sort.
  • Owner is the system user.
  • Permissions allow public read access to the object.
  • Value usually contains information like price, description etc.
  • The store can be browsed from the client directly with the appropriately filtered storage listing request.
  • Purchases are made through a RPC function that deducts from the user’s wallet and adds the item to their inventory.

Player inventory:

  • A collection called inventory representing individual player inventories.
  • Keys are either item IDs or a unique reference for the item (the guid you’re suggesting, assigned at purchase time in the purchase RPC function).
  • Owner is the player user ID.
  • Permissions allow owner read but no write access.
  • Value contains perhaps info about the number of copies of that item you own (unless each copy is its own key with its own guid like you propose).
  • Listing items to view the inventory is again a storage listing operation.
  • RPC functions can be exposed to move items around the inventory, “consume” items, or whatever is appropriate.

Generally there’s enough logic that needs to live in RPC functions (purchase exchange of item for currency) that assigning an ID to the purchased item being done in the server rather than database hasn’t been a problem so far.

In my opinion I would key inventory items on the item ID that matches the store/catalog entry for that item, and in the value somewhere I would track how many copies of that item the player owns.

I tried to look how up this could be done, I searched for “lua jsonb” and “nakama jsonb” but I couldn’t find a way to implement the methods in the link in the runtime module.
I’m missing something I’m sure so what’s the link?

(By the way thank you this post has been very helpful)

JSONB functions and operators do not need special support or dedicated functions in Nakama or its runtime feature. You can just write your standard SQL statements that use the operators and execute them through the runtime SQL exec and query functions.

1 Like