local v={}v.__index=v local m=5 local u=2 local q=game:GetService("\068\097\116\097\083\116\111\114\101\083\101\114\118\105\099\101")if game.PlaceId==0 then q=require(script:WaitForChild("\077\111\099\107\068\097\116\097\083\116\111\114\101\083\101\114\118\105\099\101"))end local d={GetAsync=Enum.DataStoreRequestType.GetAsync,SetAsync=Enum.DataStoreRequestType.SetIncrementAsync,RemoveAsync=Enum.DataStoreRequestType.SetIncrementAsync;OnUpdate=Enum.DataStoreRequestType.OnUpdate,IncrementAsync=Enum.DataStoreRequestType.SetIncrementAsync}local function X(v)return q:GetRequestBudgetForRequestType(d[v])end function v.new(m,u)local d=setmetatable({DataStore=q:GetDataStore(m,u)},v)d.Failed=d.Shared.Event.new()return d end function v.Try(T,v,q,d)local F=X(v)if F==0 then end local s=nil for X=1,m,1 do local F,p=pcall(function()return T.DataStore[v](T.DataStore,q,d)end)if F then s=p break elseif X==m then warn("\068\097\116\097\083\116\111\114\101 "..(v..(" \102\097\105\108\101\100\058 "..tostring(p))))T.Failed:Fire(v,q,tostring(p))else wait(u)end end return s end function v.OnUpdate(u,v,m)return u.DataStore:OnUpdate(v,m)end function v.GetAsync(m,v)return m:Try("\071\101\116\065\115\121\110\099",v)end function v.IncrementAsync(u,v,m)return u:Try("\073\110\099\114\101\109\101\110\116\065\115\121\110\099",v,m)end function v.SetAsync(u,v,m)return u:Try("\083\101\116\065\115\121\110\099",v,m)end function v.RemoveAsync(m,v)return m:Try("\082\101\109\111\118\101\065\115\121\110\099",v)end function v.UpdateAsync(u,v,m)return u:Try("\085\112\100\097\116\101\065\115\121\110\099",v,m)end return v
-- Safe Data Store
-- Crazyman32
-- February 3, 2017

--[[
	
	Works exactly like the real DataStore.

	safeDataStore.Failed(method, key, errorMessage)
	
--]]



local SafeDataStore = {}
SafeDataStore.__index = SafeDataStore

local MAX_ATTEMPTS = 5
local ATTEMPT_INTERVAL = 2


local dataStoreService = game:GetService("DataStoreService")
if (game.PlaceId == 0) then
	dataStoreService = require(script:WaitForChild("MockDataStoreService"))
end

-- Map DataStoreService methods to associated RequestTypes:
local requestTypes = {
	GetAsync = Enum.DataStoreRequestType.GetAsync;
	SetAsync = Enum.DataStoreRequestType.SetIncrementAsync;
	RemoveAsync = Enum.DataStoreRequestType.SetIncrementAsync;
	OnUpdate = Enum.DataStoreRequestType.OnUpdate;
	IncrementAsync = Enum.DataStoreRequestType.SetIncrementAsync;
}


local function GetBudget(method)
	return dataStoreService:GetRequestBudgetForRequestType(requestTypes[method])
end


function SafeDataStore.new(name, scope)
	
	local self = setmetatable({
		DataStore = dataStoreService:GetDataStore(name, scope);
	}, SafeDataStore)

	self.Failed = self.Shared.Event.new()
	
	return self
	
end


function SafeDataStore:Try(method, k, v)
	local budget = GetBudget(method)
	if (budget == 0) then
		-- Do something in later implementation
	end
	local value = nil
	for i = 1,MAX_ATTEMPTS do
		local success,v = pcall(function()
			return self.DataStore[method](self.DataStore, k, v)
		end)
		if (success) then
			value = v
			break
		elseif (i == MAX_ATTEMPTS) then
			warn("DataStore " .. method .. " failed: " .. tostring(v))
			self.Failed:Fire(method, k, tostring(v))
		else
			wait(ATTEMPT_INTERVAL)
		end
	end
	return value
end


function SafeDataStore:OnUpdate(key, callback)
	return self.DataStore:OnUpdate(key, callback)
end


function SafeDataStore:GetAsync(key)
	return self:Try("GetAsync", key)
end


function SafeDataStore:IncrementAsync(key, delta)
	return self:Try("IncrementAsync", key, delta)
end


function SafeDataStore:SetAsync(key, value)
	return self:Try("SetAsync", key, value)
end


function SafeDataStore:RemoveAsync(key)
	return self:Try("RemoveAsync", key)
end


function SafeDataStore:UpdateAsync(key, transformFunction)
	return self:Try("UpdateAsync", key, transformFunction)
end


return SafeDataStore