Server storage retrieval logic

Hi all, I’d like your thoughts on how should I design this next part of my game, if:

1- Am I on the right path and what are the Nakama functions to it?

2- Or am I totally wrong and what should I be pursuing then?

The part I need help with is the following:

  • It’s an asynchronous multiplayer scene, from a racing game. After the player runs a race, it’s “ghost” data is stored to the Storage server. That part is pretty straightforward.

  • My logic was, when loading this scene, I’d ask the server for a number of all the collections stored with the “ghost data” label in it, randomize values within this number, and get 3 collections from those, and run them in the scene, so that the client can “compete” against this ghosts.

But is it possible to do such a thing? Get a number of collections in the stored engine and retrieve them randomly like an array?

For example, let’s say an array of ghost data has 500 entries, I could randomize and retrive positions 56, 110 and 457 from the array, load it and go.

I’m talking about arrays to have as an example of what I meant, but I know the storage is not an array list.

Thank you all beforehand, sorry if I’m not really clear, I’d be happy to explain more details if anyone needs.

Hi luiscesjr,

only way to pick random N is to fetch all object ids with storageList request, which will not be very performant if you have many objects to fetch.

One way to sample data is to do it at write time rather than read time. When you are ready to save you do it only with some probability, not every time. So your ghost saving logic might be like following:

  1. using random number generator decide if you want to save ghost data at all with some prbability lets say 10%.
  2. if you are saving, then fetch small N currently saved ghost records and pick one to replace
  3. save new ghost object, delete one you picked to replace

Then when it’s time to race, you fetch all N ghost entries and pick K you want to be in a race.

If you go with this route, you can extend logic by having multiple “buckets” of N ghost entries one per skill level , so that player competes with ghosts with adequate skill level.

1 Like

Thanks for the suggestions! I hadn’t come across this, probably my very bad searching skills, but I then should use(As per docs):

var limit = 100 # default is 10.
var objects : NakamaAPI.ApiStorageObjectList = yield(client.list_storage_objects_async(session, "saves", session.user_id, limit), "completed")

And work my way through it. There is a limit there, of objects to list, will it throw an error if the stored objects are less than the limit? I imagine not, right? I’ll start coding and testing! Thank you.

Edit I’m getting a problem with that, even though I wrote all the ghosts as permission level 2 (Global read), The above code call only retrieves the current user’s data. Did I miss anything?

Apparently Unity has a different methos call for both User’s and Everyone else:

An issue when trying list public objects in Unity - Heroic Labs

And even tought Godot also has the list_users_storage_objects_async function, I get an error saying it expects 5 arguments.
For that, the fifth arument should be null, an empty string:

yield(NakamaGlobals.client.list_users_storage_objects_async(session, collection_name, session.user_id, limit, ""), "completed")

And while this code works, the result is the same, only my current user get’s listed.

Aside from my problem, the docs could be updated to include this second form of storage listing

I cannot edit my last post, so sorry for double posting. But I wanted to share the solution.

Since list_users_storage_objects_async does not work as intended retrieving other user’s data, I searched more and found this post here in the forums. My best guess about why it does not work here is about the cursor, but I have absolutely no idea how to populate the cursor on the client side.

So well, the solution was use @zyro’s RPC code, and now it works, successfully implemented. Now that it works, I will implement @yamlcoder’s ideas for a better more efficient code. Thank you all!