function API.GetDataStore(c,E,S)assert(type(E)=="\115\116\114\105\110\103","\068\097\116\097\083\116\111\114\101 \110\097\109\101 \109\117\115\116 \098\101 \097 \115\116\114\105\110\103\059 \103\111\116"..type(E))assert(type(S)=="\115\116\114\105\110\103"or S==nil,"\068\097\116\097\083\116\111\114\101 \115\099\111\112\101 \109\117\115\116 \098\101 \097 \115\116\114\105\110\103\059 \103\111\116"..type(S))S=S or"\103\108\111\098\097\108"if allStores[S]and allStores[S][E]then return allStores[S][E]end local o={}local C={}local f={}function C.SetAsync(c,E,S)assert(S~=nil,"\086\097\108\117\101 \099\097\110\110\111\116 \098\101 \110\105\108")o[E]=S if f[E]then for E,c in pairs(f[E])do spawn(function()c(S)end)end end end function C.UpdateAsync(c,E,S)local C=S(o[E])assert(C~=nil,"\086\097\108\117\101 \099\097\110\110\111\116 \098\101 \110\105\108")o[E]=C if f[E]then for E,S in pairs(f[E])do spawn(function()S(C)end)end end end function C.GetAsync(S,E)return o[E]end function C.RemoveAsync(S,E)o[E]=nil if f[E]then for E,S in pairs(f[E])do spawn(function()S(nil)end)end end end function C.IncrementAsync(c,E,S)if S==nil then S=1 end assert(type(S)=="\110\117\109\098\101\114","\067\097\110 \111\110\108\121 \105\110\099\114\101\109\101\110\116 \110\117\109\098\101\114\115")c:UpdateAsync(E,function(E)if E==nil then return E end assert(type(E)=="\110\117\109\098\101\114","\067\097\110 \111\110\108\121 \105\110\099\114\101\109\101\110\116 \110\117\109\098\101\114\115")return E+S end)end function C.OnUpdate(c,E,S)assert(type(S)=="\102\117\110\099\116\105\111\110","\085\112\100\097\116\101 \102\117\110\099\116\105\111\110 \097\114\103\117\109\101\110\116 \109\117\115\116 \098\101 \097 \102\117\110\099\116\105\111\110")if not f[E]then f[E]={S}else table.insert(f[E],S)end end if not allStores[S]then allStores[S]={}end allStores[S][E]=C return C end function API.GetGlobalDataStore(E)return E:GetDataStore("\103\108\111\098\097\108","\103\108\111\098\097\108")end function API.GetOrderedDataStore(c,E,S)local o=c:GetDataStore(E,S)local C={}local f={}function f.GetAsync(S,E)return o:GetAsync(E)end function f.SetAsync(c,E,S)assert(type(S)=="\110\117\109\098\101\114","\086\097\108\117\101 \109\117\115\116 \098\101 \097 \110\117\109\098\101\114")o:SetAsync(E,S)C[E]=S end function f.UpdateAsync(c,E,S)o:UpdateAsync(E,function(c)local o=S(c)assert(type(o)=="\110\117\109\098\101\114","\086\097\108\117\101 \109\117\115\116 \098\101 \097 \110\117\109\098\101\114")C[E]=o return o end)end function f.IncrementAsync(c,E,S)o:IncrementAsync(E,S)C[E]=(C[E]or 0)+S end function f.RemoveAsync(S,E)o:RemoveAsync(E)C[E]=nil end function f.GetSortedAsync(f,E,S,c,o)assert(type(S)=="\110\117\109\098\101\114"and math.floor(S)>0,"\080\097\103\101\083\105\122\101 \109\117\115\116 \098\101 \097\110 \105\110\116\101\103\101\114 \097\110\100 \103\114\101\097\116\101\114 \116\104\097\110 \048")assert(c==nil or type(c)=="\110\117\109\098\101\114","\077\105\110\086\097\108\117\101 \109\117\115\116 \098\101 \097 \110\117\109\098\101\114")assert(o==nil or type(o)=="\110\117\109\098\101\114","\077\097\120\086\097\108\117\101 \109\117\115\116 \098\101 \097 \110\117\109\098\101\114")if c and o then assert(c<=o,"\077\105\110\086\097\108\117\101 \109\117\115\116 \098\101 \108\101\115\115 \111\114 \101\113\117\097\108 \116\111 \077\097\120\086\097\108\117\101")end local X={}for E,S in pairs(C)do local C=(not c or S>=c)and(not o or S<=o)if C then table.insert(X,{key=E,value=S})end end table.sort(X,E and function(E,S)return E.value<S.value end or function(E,S)return S.value<E.value end)S=math.floor(S)local O={IsFinished=false}for E,c in pairs(X)do local o=math.ceil(E/S)local C=O[o]if not C then C={}O[o]=C end local f=(E-1)%S+1 C[f]=c end do local E=1 function O.GetCurrentPage(S)return S[E]end function O.AdvanceToNextPageAsync(S)local c=#O if E<c then E=E+1 end S.IsFinished=E>=c end end return O end return f end function API.GetRequestBudgetForRequestType(S,E)return realDataStoreService:GetRequestBudgetForRequestType(E)end


function API:GetDataStore(name, scope)
	assert(type(name) == "string", "DataStore name must be a string; got" .. type(name))
	assert(type(scope) == "string" or scope == nil, "DataStore scope must be a string; got" .. type(scope))
	scope = (scope or "global")
	if (allStores[scope] and allStores[scope][name]) then
		return allStores[scope][name]
	end
	local data = {}
	local d = {}
	local updateListeners = {}
	function d:SetAsync(k, v)
		assert(v ~= nil, "Value cannot be nil")
		data[k] = v
		if (updateListeners[k]) then
			for _,f in pairs(updateListeners[k]) do
				spawn(function() f(v) end)
			end
		end
	end
	function d:UpdateAsync(k, func)
		local v = func(data[k])
		assert(v ~= nil, "Value cannot be nil")
		data[k] = v
		if (updateListeners[k]) then
			for _,f in pairs(updateListeners[k]) do
				spawn(function() f(v) end)
			end
		end
	end
	function d:GetAsync(k)
		return data[k]
	end
	function d:RemoveAsync(k)
		data[k] = nil
		if (updateListeners[k]) then
			for _,f in pairs(updateListeners[k]) do
				spawn(function() f(nil) end)
			end
		end
	end
	function d:IncrementAsync(k, delta)
		if (delta == nil) then delta = 1 end
		assert(type(delta) == "number", "Can only increment numbers")
		self:UpdateAsync(k, function(num)
			if (num == nil) then
				return num
			end
			assert(type(num) == "number", "Can only increment numbers")
			return (num + delta)
		end)
	end
	function d:OnUpdate(k, onUpdateFunc)
		assert(type(onUpdateFunc) == "function", "Update function argument must be a function")
		if (not updateListeners[k]) then
			updateListeners[k] = {onUpdateFunc}
		else
			table.insert(updateListeners[k], onUpdateFunc)
		end
	end
	if (not allStores[scope]) then
		allStores[scope] = {}
	end
	allStores[scope][name] = d
	return d
end


function API:GetGlobalDataStore()
	return self:GetDataStore("global", "global")
end


function API:GetOrderedDataStore(name, scope)
	local dataStore = self:GetDataStore(name, scope)
	local allData = {}
	local d = {}
	function d:GetAsync(k)
		return dataStore:GetAsync(k)
	end
	function d:SetAsync(k, v)
		assert(type(v) == "number", "Value must be a number")
		dataStore:SetAsync(k, v)
		allData[k] = v
	end
	function d:UpdateAsync(k, func)
		dataStore:UpdateAsync(k, function(oldValue)
			local v = func(oldValue)
			assert(type(v) == "number", "Value must be a number")
			allData[k] = v
			return v
		end)
	end
	function d:IncrementAsync(k, delta)
		dataStore:IncrementAsync(k, delta)
		allData[k] = ((allData[k] or 0) + delta)
	end
	function d:RemoveAsync(k)
		dataStore:RemoveAsync(k)
		allData[k] = nil
	end
	function d:GetSortedAsync(isAscending, pageSize, minValue, maxValue)
		assert(type(pageSize) == "number" and math.floor(pageSize) > 0, "PageSize must be an integer and greater than 0")
		assert(minValue == nil or type(minValue) == "number", "MinValue must be a number")
		assert(maxValue == nil or type(maxValue) == "number", "MaxValue must be a number")
		if (minValue and maxValue) then
			assert(minValue <= maxValue, "MinValue must be less or equal to MaxValue")
		end
		local data = {}
		for k,v in pairs(allData) do
			local pass = ((not minValue or v >= minValue) and (not maxValue or v <= maxValue))
			if (pass) then
				table.insert(data, {key = k, value = v})
			end
		end
		table.sort(data,
			(isAscending and
				function(a, b) return (a.value < b.value) end
			or
				function(a, b) return (b.value < a.value) end
			)
		)
		pageSize = math.floor(pageSize)
		local pages = {IsFinished = false}
		for i,v in pairs(data) do
			local pageNum = math.ceil(i / pageSize)
			local page = pages[pageNum]
			if (not page) then
				page = {}
				pages[pageNum] = page
			end
			local index = (((i - 1) % pageSize) + 1)
			page[index] = v
		end
		do
			local currentPage = 1
			function pages:GetCurrentPage()
				return self[currentPage]
			end
			function pages:AdvanceToNextPageAsync()
				local numPages = #pages
				if (currentPage < numPages) then
					currentPage = (currentPage + 1)
				end
				self.IsFinished = (currentPage >= numPages)
			end
		end
		return pages
	end
	return d
end


function API:GetRequestBudgetForRequestType(requestType)
	return realDataStoreService:GetRequestBudgetForRequestType(requestType)
end

