Community made content discoverability?

I’ve been working on a game in my spare time which is a puzzle/obstacle course game.

One of the features I want to have in this game (eventually) is a level editor in which players can create levels and then publish them for others to play. Right now I have a prototype where I am able to successfully create levels and save them to a datastore, and that’s where this post becomes relevant.

What would be the best/most viable way to make sure that other players can find these levels?

This is what I can currently think of:

In short: Store each level with a unique key which anyone can access and then store those keys in two locations

Player id DS: input: player id => output: array of level keys that user has created.
Ordered DS: key: level key, value: timestamp (allows us to sort levels by oldest or newest)

My main issue with this is that it’s quite complicated, doesn’t give much opportunity to look for high quality levels, would be quite a pain to comply with right to erasure requests, and may possibly struggle with request limits.

Does anybody have any other recommendations for a better way to do this? Or would you recommend not even attempting this as the tech isn’t really there to support it atm?

8 Likes

Im the very small lvl in programming, but i have idea:
You can create Value in Workspace with Name “Looks”
And if you have the button “Test” to test content, you can use remoteEvent and with script change Value “Looks”, then safe it with DataStore, and content with very big Value be popular

you could store the ods key as a json table and sort with that.

Could you elaborate more on that idea? I don’t quite understand?

1 Like

store the level data like. Likes, plays, and level id. In a JSON table and save the JSON table as the key of the ods with the value as the timestamp. Then you can sort with the JSON tables data.

Heres a example:

local dss = game:GetService("DataStoreService")
local ods: OrderedDataStore = dss:GetOrderedDataStore("levels")
local httpService = game:GetService("HttpService")

local function get_levels()
    local pages: DataStoreKeyPages = ods:GetSortedAsync(false, 50)
    
    local levels = {}

    for i,v in ipairs(pages:GetCurrentPage()) do
        levels[#levels+1] = httpService:JSONDecode(v.key)
        levels[#levels].timestamp = v.value
    end

    return levels
end
1 Like

I suppose that would be marginally better, but i’d still be limited to sorting the sample I get from one single page, no?

1 Like

Why not use Ratings instead of timestamp?

Although, for rate limits I wouldn’t have much of a clue, maybe using Third party and HttpService is your best method right now

2 Likes

Because then nobody would find new levels :laughing:

I suppose i could do a second ordered datastore which sorts by ratings but now it’s even more complicated and we have the issue of write and access limits.

1 Like

You could store all levels in a table and resort everytime more levels are added.

I am confused by this quote.


Can’t say that I am a fan of storing a level key to access a different datastore in this usage. I would rather have an object that inherently stores the timestamp and then use a sort function.

Personally, my data abstraction library always attaches when the value of a key has been updated last. So I would have something similar to this (pseudo):

arrayOfSortedLevels = {"AmazingLevel" = {
    _id = GUID,
    _lastWrite = time,
    --data
}, "NewLevel" =  {...} }.sort(a, b  => a._lastWrite >= b._lastWrite)

Otherwise, it looks like you could benefit from the usage of datastore scopes.

Edit: I just realised that what you meant was that players should be able globally index levels made by OTHER players. I will be back with a flowchart :woozy_face:

1 Like

Ohh, then you could have an option to search for low ratings, and maybe a different store for newly created items.

I’m not sure but maybe the new DataStore api could support your use case.

Datastore in general is very limiting, you might find it easier to work with Third-party databases.

Another idea is allowing players to share their map and other’s too

The ability for players to upvote/downvote the player custom levels would be nice. That might help making the better quality ones discoverable. Too many downvotes, you could just delete the level. OH maybe make it an expensive game pass to do this, too, so people who make levels will be more serious about it.

2 Likes

I don’t think I quite understand. I agree it would be best if I just had an array which contained values that I could easily change the sort criteria on.

The issue is that I need the solution to be scalable for datastores. I’m not suggesting my game would ever be this popular, but imagine 1,000 levels get created and uploaded every minute. I need a way to access things like the most popular levels, the newest levels, or levels created by a specific user from the datastores.

Tbh it’s very clear datastore were not intended for this use case, but that’s what I’m trying to figure out here if this is even something that’s feasible or if I should just descope it from my project.

Edit: didn’t see your edit when I posted this.

1 Like

I am so sorry for misunderstanding the question! I do think you should clarify that users are supposed to globally index other players’ levels as per written in my Edit.

I am currently drawing up the data flow in a chart, I do have some follow up questions though: 1. Can Users only see levels by users in the game, or every unique player that has ever played. 2. Does users manipulate singular parts or models (Need to better understand how scalable this needs to be).

I do not agree with the sentiment that Roblox’s DataStore can’t handle this task. They’re using Amazon’s DynamoDB in the background which is extremely scalable, low downtime and etc. One of the better noSQLs! Actually my studio worked on a game that has similar gameplay to yours, so it is safe to say that DataStores are viable :slight_smile:

2 Likes

Ideally they would be able to see levels by every unique player that has ever played (and uploaded a level).

Not sure what you mean by this? If you’re refering to how the level is actually stored in the DS. The level is converted into a string which can be converted back into instances. In the level editor sometimes players will be manipulating models and sometimes they will be manipulating individual parts.

1 Like

This is how I would do it

It’s not as good an idea as @ineed_massnow’s, but it might work, maybe for security.

When a map is published, a Discord bot will notify you and you add and/or review it, it could be useful when the map statistics change to manage and if you see something strange, act accordingly.

use an external database which allows you to sort the entire data by your needs. Cache each level appropriately to limit the amount of calls you do. I would recommend sqlite database with tables. This works with right of erasure as you can store a table in SQL and get the level by userid while using a key that represents the level id. and delete it properly. Just my way that I would do. The biggest problem would probably be memory

DataStores aren’t databases, so I’d mostly say yes, the tech isn’t really there.

But also I think your intuition is pretty good—the limits on datastores are big, so you can most certainly get away with splitting primary keys into different ordered datastores based on what you want ranked.

You’ve got the 1 lookup table for levels (level GUID → {title, creatorId, levelData, timestamp, rating}) that you only use for finding details once you actually have a GUID to lookup.

That is unordered.

Then you have separated ordered datastores for anything you want to get by rank (level GUID → timestamp & level GUID → rating).

The biggest issue would be request limits, though. You’d get a page of the top ten levels easily, but then you’d need ten requests from the master level table to get any useful info e.g. to display in a list…

Maybe @kingschool9 is right and you should just host your own database and skirt the problem entirely.

2 Likes