Hi!
I'm planning to create a game where users can share their outfits with each other.
The problem I face is that it seems quite impossible to do this with the Roblox DataStore Service. The only way it would be possible to implement such a system purely with services that Roblox provides would be to have globally stored lists of all outfits that would all have their own ID. However, this seems to be very unstable and inefficient. The other solution I came up with was to host my own server where the outfits are stored, sorted and then sent back through a custom written API
My question is, are there any options that I'm missing? Is there a way to avoid hosting my own API to achieve this?
from my personal experience with roblox datastores, I believe using two data stores (one hosting the outfits, and another hosting the owners of the specific outfits) would work fine.
we save outfits inside an OutfitIDStore with a unique ID (generate a unique ID and save a table with all the IDs) and then append that same ID to a user's outfits list (get the user's table and append the outfit ID to it)
this code has NOT been tested
-- TODO: test code local DataStoreService = game:GetService('DataStoreService') local OutfitIDStore = DataStoreService:GetDataStore('OUTFIT_STORE') local UserIDStore = DataStoreService:GetDataStore('USER_STORE') local Chars = ('abcdefghijklmnopqrstuvwxyz0123456789').split('') local GenericLength = 6 -- DATASTORE FUNCTIONS local function GetOutfitIDStore(key) if key == nil then error(('missing argument key (got %s, expected not nil)').format(tostring(key))) end return pcall(function() OutfitIDStore:GetAsync(key) end) end local function SetOutfitIDStore(key, data) if key == nil then error(('missing argument key (got %s').format(tostring(key))) end if data == nil then error(('missing argument data (got %s)').format(tostring(key))) end return pcall(function() OutfitIDStore:SetAsync(key, data) end) end local function GetUserIDStore(key) if key == nil then error(('missing argument key (got %s, expected not nil)').format(tostring(key))) end return pcall(function() UserIDStore:GetAsync(key) end) end local function SetUserIDStore(key, data) if key == nil then error(('missing argument key (got %s').format(tostring(key))) end if data == nil then error(('missing argument data (got %s)').format(tostring(key))) end return pcall(function() UserIDStore:SetAsync(key, data) end) end local function GenerateUniqueID(length: int) if type(length) ~= 'number' then length = GenericLength end local ID = '' for i = 1, length do ID = ID + Chars[math.random(1, #Chars)] end local ok, data = GetOutfitIDStore(ID) if not ok and type(data) ~= 'table' then return ID else return GenerateUniqueID(length) end end -- OUTFIT FUNCTIONS local function SaveOutfit(Accessories: table, UserID: int) assert(Accessories, 'no accessories provided.') assert(UserID, 'no userid provided.') -- upload outfit to database local ID = GenerateUniqueID() local UploadSuccess, Message = SetOutfitIDStore(ID, Accessories) if not UploadSuccess and Message ~= nil then -- upload error, handle. end local GetSuccess, Data = GetUserIDStore(UserID) if not GetSuccess and Data == nil then -- get error, handle. end local UpdatedTable = Data table.insert(UpdatedTable, ID) local SetSuccess, Message = SetUserIDStore(UserID, UpdatedTable) if not SetSuccess and Message ~= nil then -- set error, handle. end end local function RemoveOutfit(ID: str, UserID: int) local GetSuccess, Data = GetUserIDStore(UserID) if not GetSuccess and Data == nil then -- get error, handle. end if not table.find(Data, ID) then return false, ('User %i is not the owner of outfit (%s)').format(UserID, ID) end local UpdatedTable = Data table.remove(UpdatedTable, table.find(Data, ID)) local SetSuccess, Message = SetUserIDStore(UserID, UpdatedTable) if not SetSuccess and Message ~= nil then -- set error, handle. end end local function GetOutfitFromID(ID) return GetOutfitIDStore(ID) end local function GetUserOufits(UserID) return GetUserIDStore(UserID) end