function DataStore2.Combine(I,...)for n,M in pairs({...})do combinedDataStoreInfo[M]=I end end function DataStore2.ClearCache()DataStoreCache={}end function DataStore2.__call(M,I,n)assert(typeof(I)=="\115\116\114\105\110\103"and typeof(n)=="\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(I),typeof(n)))if DataStoreCache[n]and DataStoreCache[n][I]then return DataStoreCache[n][I]elseif combinedDataStoreInfo[I]then local M=DataStore2(combinedDataStoreInfo[I],n)M:BeforeSave(function(I)for M in pairs(I)do if combinedDataStoreInfo[M]then local w=DataStore2(M,n)local P=w:Get(nil,true)if P~=nil then if w.combinedBeforeSave then P=w.combinedBeforeSave(clone(P))end I[M]=P end end end return I end)local w=setmetatable({combinedName=I,combinedStore=M},{__index=function(I,n)return CombinedDataStore[n]or M[n]end})if not DataStoreCache[n]then DataStoreCache[n]={}end DataStoreCache[n][I]=w return w end local w={}local P=I..("\047"..n.UserId)w.dataStore=DataStoreService:GetDataStore(P)w.orderedDataStore=DataStoreService:GetOrderedDataStore(P)w.name=I w.player=n w.callbacks={}w.beforeInitialGet={}w.afterSave={}w.bindToClose={}setmetatable(w,DataStoreMetatable)local l,W=Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116"),false game:BindToClose(function()if not W then l.Event:wait()end local I=w:Get(nil,true)for M,w in pairs(w.bindToClose)do w(n,I)end end)Players.PlayerRemoving:connect(function(I)if I==n then w:Save()l:Fire()W=true delay(40,function()DataStoreCache[I]=nil end)end end)if not DataStoreCache[n]then DataStoreCache[n]={}end DataStoreCache[n][I]=w return w end return setmetatable(DataStore2,DataStore2)

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 = {}
	local dataStoreKey = dataStoreName .. "/" .. player.UserId

	dataStore.dataStore = DataStoreService:GetDataStore(dataStoreKey)
	dataStore.orderedDataStore = DataStoreService:GetOrderedDataStore(dataStoreKey)
	dataStore.name = dataStoreName
	dataStore.player = player
	dataStore.callbacks = {}
	dataStore.beforeInitialGet = {}
	dataStore.afterSave = {}
	dataStore.bindToClose = {}

	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)

	Players.PlayerRemoving:connect(function(playerLeaving)
		if playerLeaving == player then
			dataStore:Save()
			event:Fire()
			fired = true

			delay(40, function() --Give a long delay for people who haven't figured out the cache :^(
				DataStoreCache[playerLeaving] = nil
			end)
		end
	end)
	
	--[[spawn(function()
		player:WaitForChild("ClientSaveRequest")
		function player.ClientSaveRequest.OnServerInvoke()
			dataStore:Save()
			return
		end
	end)]]

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

	DataStoreCache[player][dataStoreName] = dataStore

	return dataStore
end

return setmetatable(DataStore2, DataStore2)
