function DataStore.SaveAsync(C)return(Promise.async(function(J,t)if not C.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(C.Name))J(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(C.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 J(false)return end if C.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")J(false)return end if C.value~=nil then local O=clone(C.value)if C.beforeSave then local J,m=pcall(C.beforeSave,O,C)if J then O=m else t(m,Constants.SaveFailure.BeforeSaveError)return end end local m=Verifier.testValidity(O)if m then t(m,Constants.SaveFailure.InvalidData)return end return(C.savingMethod:Set(O)):andThen(function()J(true,O)end)end end)):andThen(function(J,t)if J then for J,O in pairs(C.afterSave)do local m,h=pcall(O,t,C)if not m then warn("\069\114\114\111\114 \111\110 \065\102\116\101\114\083\097\118\101\058 "..h)end end C.valueUpdated=false end end)end function DataStore.BindToClose(J,C)table.insert(J.bindToClose,C)end function DataStore.GetKeyValue(J,C)return(J.value or{})[C]end function DataStore.SetKeyValue(t,C,J)if not t.value then t.value=t:Get({})end t.value[C]=J end local C={}do function C.BeforeInitialGet(J,C)J.combinedBeforeInitialGet=C end function C.BeforeSave(J,C)J.combinedBeforeSave=C end function C.Get(t,C,J)local O=t.combinedStore:Get({})local m=O[t.combinedName]if not J then if m==nil then m=C else if t.combinedBeforeInitialGet and not t.combinedInitialGot then m=t.combinedBeforeInitialGet(m)end end end t.combinedInitialGot=true O[t.combinedName]=clone(m)t.combinedStore:Set(O,true)return clone(m)end function C.Set(t,C,J)local O=t.combinedStore:GetTable({})O[t.combinedName]=C t.combinedStore:Set(O,J)t:_Update(J)end function C.Update(J,C)J:Set(C(J:Get()))J:_Update()end function C.Save(C)C.combinedStore:Save()end function C.OnUpdate(J,C)if not J.onUpdateCallbacks then J.onUpdateCallbacks={C}else J.onUpdateCallbacks[#J.onUpdateCallbacks+1]=C end end function C._Update(J,C)if not C then for C,t in pairs(J.onUpdateCallbacks or{})do t(J:Get(),J)end end J.combinedStore:_Update(true)end function C.SetBackup(J,C)J.combinedStore:SetBackup(C)end end local J={}J.__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 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
