function DataStore.SaveAsync(A)return(Promise.async(function(O,V)if not A.valueUpdated then warn(("\068\097\116\097 \115\116\111\114\101 \037\115 \119\097\115 \110\111\116 \115\097\118\101\100 \097\115 \105\116 \119\097\115 \110\111\116 \117\112\100\097\116\101\100\046"):format(A.Name))O(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(A.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 O(false)return end if A.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")O(false)return end if A.value~=nil then local p=clone(A.value)if A.beforeSave then local O,c=pcall(A.beforeSave,p,A)if O then p=c else V(c,Constants.SaveFailure.BeforeSaveError)return end end local c=Verifier.testValidity(p)if c then V(c,Constants.SaveFailure.InvalidData)return end return(A.savingMethod:Set(p)):andThen(function()O(true,p)end)end end)):andThen(function(O,V)if O then for O,p in ipairs(A.afterSave)do local c,Q=pcall(p,V,A)if not c then warn("\069\114\114\111\114 \111\110 \065\102\116\101\114\083\097\118\101\058",Q)end end A.valueUpdated=false end end)end function DataStore.BindToClose(O,A)table.insert(O.bindToClose,A)end function DataStore.GetKeyValue(O,A)return(O.value or{})[A]end function DataStore.SetKeyValue(V,A,O)if not V.value then V.value=V:Get({})end V.value[A]=O end local A={}do function A.BeforeInitialGet(O,A)O.combinedBeforeInitialGet=A end function A.BeforeSave(O,A)O.combinedBeforeSave=A end function A.Get(V,A,O)local p=V.combinedStore:Get({})local c=p[V.combinedName]if not O then if c==nil then c=A else if V.combinedBeforeInitialGet and not V.combinedInitialGot then c=V.combinedBeforeInitialGet(c)end end end V.combinedInitialGot=true p[V.combinedName]=clone(c)V.combinedStore:Set(p,true)return clone(c)end function A.Set(V,A,O)return(V.combinedStore:GetAsync({})):andThen(function(p)p[V.combinedName]=A V.combinedStore:Set(p,O)V:_Update(O)end)end function A.Update(O,A)O:Set(A(O:Get()))end function A.Save(A)A.combinedStore:Save()end function A.OnUpdate(O,A)if not O.onUpdateCallbacks then O.onUpdateCallbacks={A}else table.insert(O.onUpdateCallbacks,A)end end function A._Update(O,A)if not A then for A,V in ipairs(O.onUpdateCallbacks or{})do V(O:Get(),O)end end O.combinedStore:_Update(true)end function A.SetBackup(O,A)O.combinedStore:SetBackup(A)end end local O={}O.__index=DataStore
--[[**
	<description>
	Asynchronously saves the data to the data store.
	</description>
**--]]
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 ipairs(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)
		return self.combinedStore:GetAsync({}):andThen(function(tableResult)
			tableResult[self.combinedName] = value
			self.combinedStore:Set(tableResult, dontCallOnUpdate)
			self:_Update(dontCallOnUpdate)
		end)
	end

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

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

	function CombinedDataStore:OnUpdate(callback)
		if not self.onUpdateCallbacks then
			self.onUpdateCallbacks = { callback }
		else
			table.insert(self.onUpdateCallbacks, callback)
		end
	end

	function CombinedDataStore:_Update(dontCallOnUpdate)
		if not dontCallOnUpdate then
			for _, callback in ipairs(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
