function DataStore.SaveAsync(B)return(Promise.async(function(a,R)if not B.valueUpdated then a(false)return end if RunService:IsStudio()and not SaveInStudio then warn(("\068\097\116\097 \115\116\111\114\101 \037\115 \097\116\116\101\109\112\116\101\100 \116\111 \115\097\118\101 \105\110 \115\116\117\100\105\111 \119\104\105\108\101 \083\097\118\101\073\110\083\116\117\100\105\111 \105\115 \102\097\108\115\101\046"):format(B.Name))if not SaveInStudioObject then warn("\089\111\117 \099\097\110 \115\101\116 \116\104\101 \118\097\108\117\101 \111\102 \116\104\105\115 \098\121 \099\114\101\097\116\105\110\103 \097 \066\111\111\108\086\097\108\117\101 \110\097\109\101\100 \083\097\118\101\073\110\083\116\117\100\105\111 \105\110 \083\101\114\118\101\114\083\116\111\114\097\103\101\046")end a(false)return end if B.backup then warn("\084\104\105\115 \100\097\116\097 \115\116\111\114\101 \105\115 \097 \098\097\099\107\117\112 \115\116\111\114\101\044 \097\110\100 \116\104\117\115 \119\105\108\108 \110\111\116 \098\101 \115\097\118\101\100\046")a(false)return end if B.value~=nil then local N=clone(B.value)if B.beforeSave then local a,o=pcall(B.beforeSave,N,B)if a then N=o else R(o,Constants.SaveFailure.BeforeSaveError)return end end local o=Verifier.testValidity(N)if o then R(o,Constants.SaveFailure.InvalidData)return end return(B.savingMethod:Set(N)):andThen(function()a(true,N)end)end end)):andThen(function(a,R)if a then for a,N in pairs(B.afterSave)do local o,l=pcall(N,R,B)if not o then end end B.valueUpdated=false end end)end function DataStore.BindToClose(a,B)table.insert(a.bindToClose,B)end function DataStore.GetKeyValue(a,B)return(a.value or{})[B]end function DataStore.SetKeyValue(R,B,a)if not R.value then R.value=R:Get({})end R.value[B]=a end local B={}do function B.BeforeInitialGet(a,B)a.combinedBeforeInitialGet=B end function B.BeforeSave(a,B)a.combinedBeforeSave=B end function B.Get(R,B,a)local N=R.combinedStore:Get({})local o=N[R.combinedName]if not a then if o==nil then o=B else if R.combinedBeforeInitialGet and not R.combinedInitialGot then o=R.combinedBeforeInitialGet(o)end end end R.combinedInitialGot=true N[R.combinedName]=clone(o)R.combinedStore:Set(N,true)return clone(o)end function B.Set(R,B,a)local N=R.combinedStore:GetTable({})N[R.combinedName]=B R.combinedStore:Set(N,a)R:_Update(a)end function B.Update(a,B)a:Set(B(a:Get()))a:_Update()end function B.Save(B)B.combinedStore:Save()end function B.OnUpdate(a,B)if not a.onUpdateCallbacks then a.onUpdateCallbacks={B}else a.onUpdateCallbacks[#a.onUpdateCallbacks+1]=B end end function B._Update(a,B)if not B then for B,R in pairs(a.onUpdateCallbacks or{})do R(a:Get(),a)end end a.combinedStore:_Update(true)end function B.SetBackup(a,B)a.combinedStore:SetBackup(B)end end local a={}a.__index=DataStore

function DataStore:SaveAsync()
	return Promise.async(function(resolve, reject)
		if not self.valueUpdated then
			--   warn(("Data store %s was not saved as it was not updated."):format(self.Name))
			resolve(false)
			return
		end

		if RunService:IsStudio() and not SaveInStudio then
			warn(("Data store %s attempted to save in studio while SaveInStudio is false."):format(self.Name))
			if not SaveInStudioObject then
				warn("You can set the value of this by creating a BoolValue named SaveInStudio in ServerStorage.")
			end
			resolve(false)
			return
		end

		if self.backup then
			  warn("This data store is a backup store, and thus will not be saved.")
			resolve(false)
			return
		end

		if self.value ~= nil then
			local save = clone(self.value)

			if self.beforeSave then
				local success, result = pcall(self.beforeSave, save, self)

				if success then
					save = result
				else
					reject(result, Constants.SaveFailure.BeforeSaveError)
					return
				end
			end

			local problem = Verifier.testValidity(save)
			if problem then
				reject(problem, Constants.SaveFailure.InvalidData)
				return
			end

			return self.savingMethod:Set(save):andThen(function()
				resolve(true, save)
			end)
		end
	end):andThen(function(saved, save)
		if saved then
			for _, afterSave in pairs(self.afterSave) do
				local success, err = pcall(afterSave, save, self)

				if not success then
				--	warn("Error on AfterSave: "..err)
				end
			end

			self.valueUpdated = false
		end
	end)
end

function DataStore:BindToClose(callback)
	table.insert(self.bindToClose, callback)
end

function DataStore:GetKeyValue(key)
	return (self.value or {})[key]
end

function DataStore:SetKeyValue(key, newValue)
	if not self.value then
		self.value = self:Get({})
	end

	self.value[key] = newValue
end

local CombinedDataStore = {}

do
	function CombinedDataStore:BeforeInitialGet(modifier)
		self.combinedBeforeInitialGet = modifier
	end

	function CombinedDataStore:BeforeSave(modifier)
		self.combinedBeforeSave = modifier
	end

	function CombinedDataStore:Get(defaultValue, dontAttemptGet)
		local tableResult = self.combinedStore:Get({})
		local tableValue = tableResult[self.combinedName]

		if not dontAttemptGet then
			if tableValue == nil then
				tableValue = defaultValue
			else
				if self.combinedBeforeInitialGet and not self.combinedInitialGot then
					tableValue = self.combinedBeforeInitialGet(tableValue)
				end
			end
		end

		self.combinedInitialGot = true
		tableResult[self.combinedName] = clone(tableValue)
		self.combinedStore:Set(tableResult, true)
		return clone(tableValue)
	end

	function CombinedDataStore:Set(value, dontCallOnUpdate)
		local tableResult = self.combinedStore:GetTable({})
		tableResult[self.combinedName] = value
		self.combinedStore:Set(tableResult, dontCallOnUpdate)
		self:_Update(dontCallOnUpdate)
	end

	function CombinedDataStore:Update(updateFunc)
		self:Set(updateFunc(self:Get()))
		self:_Update()
	end

	function CombinedDataStore:Save()
		self.combinedStore:Save()
	end

	function CombinedDataStore:OnUpdate(callback)
		if not self.onUpdateCallbacks then
			self.onUpdateCallbacks = { callback }
		else
			self.onUpdateCallbacks[#self.onUpdateCallbacks + 1] = callback
		end
	end

	function CombinedDataStore:_Update(dontCallOnUpdate)
		if not dontCallOnUpdate then
			for _, callback in pairs(self.onUpdateCallbacks or {}) do
				callback(self:Get(), self)
			end
		end

		self.combinedStore:_Update(true)
	end

	function CombinedDataStore:SetBackup(retries)
		self.combinedStore:SetBackup(retries)
	end
end

local DataStoreMetatable = {}

DataStoreMetatable.__index = DataStore
