function DataStore2.Combine(c,...)for T,m in pairs({...})do combinedDataStoreInfo[m]=c end end function DataStore2.ClearCache()DataStoreCache={}end function DataStore2.__call(m,c,T)assert(typeof(c)=="\115\116\114\105\110\103"and typeof(T)=="\073\110\115\116\097\110\099\101",("\068\097\116\097\083\116\111\114\101\050\040\041 \065\080\073 \099\097\108\108 \101\120\112\101\099\116\101\100 \123\115\116\114\105\110\103 \100\097\116\097\083\116\111\114\101\078\097\109\101\044 \073\110\115\116\097\110\099\101 \112\108\097\121\101\114\125\044 \103\111\116 \123\037\115\044 \037\115\125"):format(typeof(c),typeof(T)))if DataStoreCache[T]and DataStoreCache[T][c]then return DataStoreCache[T][c]elseif combinedDataStoreInfo[c]then local m=DataStore2(combinedDataStoreInfo[c],T)m:BeforeSave(function(c)for m in pairs(c)do if combinedDataStoreInfo[m]then local B=DataStore2(m,T)local u=B:Get(nil,true)if u~=nil then if B.combinedBeforeSave then u=B.combinedBeforeSave(clone(u))end c[m]=u end end end return c end)local B=setmetatable({combinedName=c;combinedStore=m},{__index=function(c,T)return CombinedDataStore[T]or m[T]end})if not DataStoreCache[T]then DataStoreCache[T]={}end DataStoreCache[T][c]=B return B end local B={}B.Name=c B.UserId=T.UserId B.callbacks={}B.beforeInitialGet={}B.afterSave={}B.bindToClose={}B.savingMethod=SavingMethods.OrderedBackups.new(B)setmetatable(B,DataStoreMetatable)local u,G=Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116"),false game:BindToClose(function()if not G then u.Event:wait()end local c=B:Get(nil,true)for m,B in pairs(B.bindToClose)do B(T,c)end end)local Y Y=T.AncestryChanged:Connect(function()if T:IsDescendantOf(game)then return end Y:Disconnect()if game.ServerScriptService.DataSave.Value==true then B:Save()end u:Fire()G=true delay(40,function()DataStoreCache[T]=nil end)end)if not DataStoreCache[T]then DataStoreCache[T]={}end DataStoreCache[T][c]=B return B end return setmetatable(DataStore2,DataStore2)
--[[**
	<description>
	Run this once to combine all keys provided into one "main key".
	Internally, this means that data will be stored in a table with the key mainKey.
	This is used to get around the 2-DataStore2 reliability caveat.
	</description>

	<parameter name = "mainKey">
	The key that will be used to house the table.
	</parameter>

	<parameter name = "...">
	All the keys to combine under one table.
	</parameter>
**--]]
function DataStore2.Combine(mainKey, ...)
	for _, name in pairs({ ... }) do
		combinedDataStoreInfo[name] = mainKey
	end
end

function DataStore2.ClearCache()
	DataStoreCache = {}
end

function DataStore2:__call(dataStoreName, player)
	assert(
		typeof(dataStoreName) == "string" and typeof(player) == "Instance",
		("DataStore2() API call expected {string dataStoreName, Instance player}, got {%s, %s}"):format(
			typeof(dataStoreName),
			typeof(player)
		)
	)
	if DataStoreCache[player] and DataStoreCache[player][dataStoreName] then
		return DataStoreCache[player][dataStoreName]
	elseif combinedDataStoreInfo[dataStoreName] then
		local dataStore = DataStore2(combinedDataStoreInfo[dataStoreName], player)

		dataStore:BeforeSave(function(combinedData)
			for key in pairs(combinedData) do
				if combinedDataStoreInfo[key] then
					local combinedStore = DataStore2(key, player)
					local value = combinedStore:Get(nil, true)
					if value ~= nil then
						if combinedStore.combinedBeforeSave then
							value = combinedStore.combinedBeforeSave(clone(value))
						end
						combinedData[key] = value
					end
				end
			end

			return combinedData
		end)

		local combinedStore = setmetatable({
			combinedName = dataStoreName,
			combinedStore = dataStore,
		}, {
			__index = function(self, key)
				return CombinedDataStore[key] or dataStore[key]
			end,
		})

		if not DataStoreCache[player] then
			DataStoreCache[player] = {}
		end

		DataStoreCache[player][dataStoreName] = combinedStore
		return combinedStore
	end

	local dataStore = {}

	dataStore.Name = dataStoreName
	dataStore.UserId = player.UserId

	dataStore.callbacks = {}
	dataStore.beforeInitialGet = {}
	dataStore.afterSave = {}
	dataStore.bindToClose = {}
	dataStore.savingMethod = SavingMethods.OrderedBackups.new(dataStore)

	setmetatable(dataStore, DataStoreMetatable)

	local event, fired = Instance.new("BindableEvent"), false

	game:BindToClose(function()
		if not fired then
			event.Event:wait()
		end

		local value = dataStore:Get(nil, true)

		for _, bindToClose in pairs(dataStore.bindToClose) do
			bindToClose(player, value)
		end
	end)

	local playerLeavingConnection
	playerLeavingConnection = player.AncestryChanged:Connect(function()
		if player:IsDescendantOf(game) then
			return
		end
		playerLeavingConnection:Disconnect()
		if game.ServerScriptService.DataSave.Value == true then
			dataStore:Save()
		end
		event:Fire()
		fired = true

		delay(40, function() --Give a long delay for people who haven't figured out the cache :^(
			DataStoreCache[player] = nil
		end)
	end)

	if not DataStoreCache[player] then
		DataStoreCache[player] = {}
	end

	DataStoreCache[player][dataStoreName] = dataStore

	return dataStore
end

return setmetatable(DataStore2, DataStore2)
