Last active
July 13, 2025 16:53
-
-
Save HooferDevelops/3f92947da5fde9a94a63353b47bb23a2 to your computer and use it in GitHub Desktop.
CustomDatastoreService
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --[[ | |
| CustomDatastoreService | |
| -- | |
| This wrapper was made SPECIFICALLY for ProfileService. | |
| What does this mean? | |
| - This will not contain all native DataStore functions, as I | |
| - only added support for the ones needed for ProfileService, | |
| - because that is what I myself am using this for. | |
| Current Functions: | |
| -- Main Initializer -- | |
| CustomDatastoreService:GetDataStore(name: string, ) --> PseudoDataStore | |
| -- Custom Functions -- | |
| PseudoDataStore:ObtainGetSetBudget() --> table | |
| PseudoDataStore:BudgetWait(budget_type: string) --> bool | |
| -- Pseudo Functions -- | |
| PseudoDataStore:GetAsync(key: string, OPTIONAL_custom_main_store: table?, OPTIONAL_custom_main_store_meta: Instance?) --> string | table, Instance | |
| PseudoDataStore:SetAsync(key: string, value: string | table, user_ids: table?, options: Instance?) --> Instance | |
| PseudoDataStore:UpdateAsync(key: string, func: any) --> string | table, Instance | |
| PseudoDataStore:GetVersionAsync(key : string, ver : number) --> string | table, Instance | |
| PseudoDataStore:ListVersionsAsync(key: string, sort_dir: number?, min_date: number?, max_date: number?, page_size: number?) --> Instance | |
| ]]-- | |
| local DataStoreService = game:GetService("DataStoreService") | |
| local PseudoDataStore = {} | |
| PseudoDataStore.__index = PseudoDataStore | |
| function PseudoDataStore.new(name: string, scope: string?, options: Instance?) | |
| local self = setmetatable({}, PseudoDataStore) | |
| self.Datastore = DataStoreService:GetDataStore(name, scope, options) | |
| return self | |
| end | |
| function PseudoDataStore:ObtainGetSetBudget() | |
| local set = DataStoreService:GetRequestBudgetForRequestType(Enum.DataStoreRequestType.SetIncrementAsync) | |
| local get = DataStoreService:GetRequestBudgetForRequestType(Enum.DataStoreRequestType.GetAsync) | |
| return { | |
| Get = get, | |
| Set = set | |
| } | |
| end | |
| function PseudoDataStore:BudgetWait(budget_type: string) | |
| local budget = self:ObtainGetSetBudget() | |
| if (budget[budget_type] < 60) then | |
| repeat | |
| task.wait(1) | |
| warn("Awaiting budget", budget_type) | |
| budget = self:ObtainGetSetBudget() | |
| until not budget[budget_type] < 60 | |
| end | |
| return true | |
| end | |
| function PseudoDataStore:GetAsync(key: string, OPTIONAL_custom_main_store: table?, OPTIONAL_custom_main_store_meta: Instance?) | |
| self:BudgetWait("Get") | |
| local main_store, main_store_meta | |
| if (OPTIONAL_custom_main_store and OPTIONAL_custom_main_store_meta) then | |
| main_store, main_store_meta = OPTIONAL_custom_main_store, OPTIONAL_custom_main_store_meta | |
| else | |
| main_store, main_store_meta = self.Datastore:GetAsync(key.."_root") | |
| end | |
| if (not main_store) then | |
| main_store = { | |
| ver = 0, | |
| partitions = 0 | |
| } | |
| else | |
| main_store = game:GetService("HttpService"):JSONDecode(main_store) | |
| end | |
| local resultant_data = nil | |
| local index = 0 | |
| repeat | |
| self:BudgetWait("Get") | |
| local index_store, index_store_meta = self.Datastore:GetAsync( | |
| string.format("%s_%s_%s", | |
| key, | |
| tostring(index), | |
| tostring(main_store.ver) | |
| ) | |
| ) | |
| if (index_store) then | |
| if (not resultant_data) then | |
| resultant_data = "" | |
| end | |
| resultant_data ..= index_store | |
| end | |
| index += 1 | |
| task.wait() | |
| until index >= main_store.partitions | |
| pcall(function() -- hah, when in doubt, pcall it | |
| resultant_data = game:GetService("HttpService"):JSONDecode(resultant_data) | |
| end) | |
| return resultant_data, main_store_meta | |
| end | |
| function PseudoDataStore:SetAsync(key: string, value: string | table, user_ids: table?, options: Instance?) | |
| self:BudgetWait("Get") | |
| local main_store, main_store_meta = self.Datastore:GetAsync(key.."_root") | |
| if (not main_store) then | |
| main_store = { | |
| ver = 0, | |
| partitions = 0 | |
| } | |
| else | |
| main_store = game:GetService("HttpService"):JSONDecode(main_store) | |
| end | |
| self:BudgetWait("Set") | |
| main_store.ver += 1 | |
| if (typeof(value) == "table") then | |
| value = game:GetService("HttpService"):JSONEncode(value) | |
| else | |
| value = tostring(value) | |
| end | |
| local function splitByChunk(text, chunkSize) | |
| local s = {} | |
| for i=1, #text, chunkSize do | |
| s[#s+1] = text:sub(i,i+chunkSize - 1) | |
| end | |
| return s | |
| end | |
| local partitions = splitByChunk(value, 4*10^6) | |
| main_store.partitions = #partitions | |
| local index = 0 | |
| repeat | |
| self:BudgetWait("Set") | |
| self.Datastore:SetAsync( | |
| string.format("%s_%s_%s", | |
| key, | |
| tostring(index), | |
| tostring(main_store.ver) | |
| ), | |
| partitions[index+1] | |
| ) | |
| index += 1 | |
| task.wait() | |
| until index >= main_store.partitions | |
| self:BudgetWait("Set") | |
| local variant = self.Datastore:SetAsync(key.."_root", game:GetService("HttpService"):JSONEncode(main_store), user_ids) | |
| return variant | |
| end | |
| function PseudoDataStore:UpdateAsync(key: string, func: any) | |
| local data, meta = self:GetAsync(key) | |
| local new_data, user_ids, options = func(data, meta) | |
| local set = self:SetAsync(key, new_data, user_ids, options) | |
| return new_data, meta | |
| end | |
| function PseudoDataStore:GetVersionAsync(key: string, ver: number) | |
| local value, info = self.Datastore:GetVersionAsync(key.."_root", ver) | |
| local pseudo_value, pseudo_info = self:GetAsync(key, value, info) | |
| return pseudo_value, pseudo_info | |
| end | |
| function PseudoDataStore:ListVersionsAsync(key: string, sort_dir: number?, min_date: number?, max_date: number?, page_size: number?) | |
| return self.Datastore:ListVersionsAsync(key.."_root", sort_dir, min_date, max_date, page_size) | |
| end | |
| local CustomDatastoreService = {} | |
| function CustomDatastoreService:GetDataStore(name: string, scope: string?, options: Instance?) | |
| return PseudoDataStore.new(name, scope, options) | |
| end | |
| return CustomDatastoreService |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment