Datastore being throttled

My script handles many datastores and it throttles as soon as I join the game, and multiple times throughout the play session. Also upon leaving. Here is my script:

local DataStoreService = game:GetService("DataStoreService")
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")

local playerDataStore = DataStoreService:GetDataStore("PlayerData_V36")
local rupeesStore = DataStoreService:GetOrderedDataStore("RupeesLeaderboard")
local callsStore = DataStoreService:GetOrderedDataStore("CallsLeaderboard")
local callCentersStore = DataStoreService:GetOrderedDataStore("CallCentersLeaderboard")

local assignedPlots = {}
local tier2AssignedPlots = {}
local tier3AssignedPlots = {}
local tier4AssignedPlots = {}
local VIP_GAMEPASS_ID = 1226680892

local freeUnlockMap = {
	unlockRoomPart = "baljeetRoomDoor",
	unlockRoom2Part = "office1Door",
	unlockRoom3Part = "office2Door",
	unlock2ndFloorPart = "2ndFloorDoor",
	unlock3rdFloorPart = "3rdFloorDoor"
}

local tier2FreeUnlockMap = {
	unlockRoomPart = "RoomDoor",
	frontDoorPart = "frontDoorModel"
}

local function updateRupeesLeaderboard(plr, value)
	pcall(function()
		rupeesStore:SetAsync(tostring(plr.UserId), value)
	end)
end

local function updateCallsLeaderboard(plr, value)
	pcall(function()
		callsStore:SetAsync(tostring(plr.UserId), value)
	end)
end


local function updateCallCentersLeaderboard(plr, value)
	pcall(function()
		callCentersStore:SetAsync(tostring(plr.UserId), value)
	end)
end

local function savePlayerPlotObjects(plr, plotName)
	local workspacePlot = workspace:FindFirstChild(plotName)
	local replicatedPlot = game.ReplicatedStorage:FindFirstChild(plotName)
	local dataToSave = {}

	if workspacePlot then
		for _, model in ipairs(workspacePlot:GetChildren()) do
			if model:FindFirstChild("buyable") then
				table.insert(dataToSave, model.Name)
			end
		end
	end

	if replicatedPlot then
		for _, doorName in pairs(freeUnlockMap) do
			if replicatedPlot:FindFirstChild(doorName) then
				table.insert(dataToSave, doorName)
			end
		end
	end

	pcall(function()
		playerDataStore:SetAsync("Plot_" .. plr.UserId, dataToSave)
	end)
end

local function saveTier2PlotObjects(plr, plotName)
	local workspacePlot = workspace:FindFirstChild(plotName)
	local replicatedPlot = game.ReplicatedStorage:FindFirstChild(plotName)
	local dataToSave = {}

	if workspacePlot then
		for _, model in ipairs(workspacePlot:GetChildren()) do
			if model:FindFirstChild("buyable") then
				table.insert(dataToSave, model.Name)
			end
		end
	end

	if replicatedPlot then
		for _, doorName in pairs(tier2FreeUnlockMap) do
			if replicatedPlot:FindFirstChild(doorName) then
				table.insert(dataToSave, doorName)
			end
		end
	end

	pcall(function()
		playerDataStore:SetAsync("tier2Plot_" .. plr.UserId, dataToSave)
	end)
end

local function saveTier3PlotObjects(plr, plotName)
	local workspacePlot = workspace:FindFirstChild(plotName)
	local replicatedPlot = game.ReplicatedStorage:FindFirstChild(plotName)
	local dataToSave = {}

	if workspacePlot then
		for _, model in ipairs(workspacePlot:GetChildren()) do
			if model:FindFirstChild("buyable") then
				table.insert(dataToSave, model.Name)
			end
		end
	end

	pcall(function()
		playerDataStore:SetAsync("tier3Plot_" .. plr.UserId, dataToSave)
	end)
end

local function saveTier4PlotObjects(plr, plotName)
	local workspacePlot = workspace:FindFirstChild(plotName)
	local replicatedPlot = game.ReplicatedStorage:FindFirstChild(plotName)
	local dataToSave = {}

	if workspacePlot then
		for _, model in ipairs(workspacePlot:GetChildren()) do
			if model:FindFirstChild("buyable") then
				table.insert(dataToSave, model.Name)
			end
		end
	end

	pcall(function()
		playerDataStore:SetAsync("tier4Plot_" .. plr.UserId, dataToSave)
	end)
end

local function loadPlayerPlotObjects(plr, plotName)
	local success, data = pcall(function()
		return playerDataStore:GetAsync("Plot_" .. plr.UserId)
	end)
	if not success or not data then return end

	local sourceFolder = game.ReplicatedStorage:FindFirstChild(plotName)
	local destination = workspace:FindFirstChild(plotName)
	if not sourceFolder or not destination then return end

	for _, modelName in ipairs(data) do
		local original = sourceFolder:FindFirstChild(modelName)
		if original then
			local clone = original:Clone()
			clone.Parent = destination
		end
	end

	for _, part in ipairs(destination:GetDescendants()) do
		if part:IsA("BasePart") and part.Name == "BuyPart" then
			local modelNameValue = part:FindFirstChild("modelName")
			if modelNameValue and table.find(data, modelNameValue.Value) then
				part.Parent = game.ReplicatedStorage:FindFirstChild(plotName)
			end
		end
	end

	for buttonName, doorName in pairs(freeUnlockMap) do
		if destination:FindFirstChild(doorName) and table.find(data, doorName) then
			destination[doorName].Parent = sourceFolder
			if destination:FindFirstChild(buttonName) then
				destination[buttonName].Parent = sourceFolder
			end
		end
	end
end

local function loadTier2PlayerPlotObjects(plr, plotName)
	local success, data = pcall(function()
		return playerDataStore:GetAsync("tier2Plot_" .. plr.UserId)
	end)
	if not success or not data then return end

	local sourceFolder = game.ReplicatedStorage:FindFirstChild(plotName)
	local destination = workspace:FindFirstChild(plotName)
	if not sourceFolder or not destination then return end

	for _, modelName in ipairs(data) do
		local original = sourceFolder:FindFirstChild(modelName)
		if original then
			local clone = original:Clone()
			clone.Parent = destination
		end
	end

	for _, part in ipairs(destination:GetDescendants()) do
		if part:IsA("BasePart") and part.Name == "BuyPart" then
			local modelNameValue = part:FindFirstChild("modelName")
			if modelNameValue and table.find(data, modelNameValue.Value) then
				part.Parent = game.ReplicatedStorage:FindFirstChild(plotName)
			end
		end
	end

	for buttonName, doorName in pairs(tier2FreeUnlockMap) do
		if destination:FindFirstChild(doorName) and table.find(data, doorName) then
			destination[doorName].Parent = sourceFolder
			if destination:FindFirstChild(buttonName) then
				destination[buttonName].Parent = sourceFolder
			end
		end
	end
end

local function loadTier3PlayerPlotObjects(plr, plotName)
	local success, data = pcall(function()
		return playerDataStore:GetAsync("tier3Plot_" .. plr.UserId)
	end)
	if not success or not data then return end

	local sourceFolder = game.ReplicatedStorage:FindFirstChild(plotName)
	local destination = workspace:FindFirstChild(plotName)
	if not sourceFolder or not destination then return end

	for _, modelName in ipairs(data) do
		local original = sourceFolder:FindFirstChild(modelName)
		if original then
			local clone = original:Clone()
			clone.Parent = destination
		end
	end

	for _, part in ipairs(destination:GetDescendants()) do
		if part:IsA("BasePart") and part.Name == "BuyPart" then
			local modelNameValue = part:FindFirstChild("modelName")
			if modelNameValue and table.find(data, modelNameValue.Value) then
				part.Parent = game.ReplicatedStorage:FindFirstChild(plotName)
			end
		end
	end
end

local function loadTier4PlayerPlotObjects(plr, plotName)
	local success, data = pcall(function()
		return playerDataStore:GetAsync("tier4Plot_" .. plr.UserId)
	end)
	if not success or not data then return end

	local sourceFolder = game.ReplicatedStorage:FindFirstChild(plotName)
	local destination = workspace:FindFirstChild(plotName)
	if not sourceFolder or not destination then return end

	for _, modelName in ipairs(data) do
		local original = sourceFolder:FindFirstChild(modelName)
		if original then
			local clone = original:Clone()
			clone.Parent = destination
		end
	end

	for _, part in ipairs(destination:GetDescendants()) do
		if part:IsA("BasePart") and part.Name == "BuyPart" then
			local modelNameValue = part:FindFirstChild("modelName")
			if modelNameValue and table.find(data, modelNameValue.Value) then
				part.Parent = game.ReplicatedStorage:FindFirstChild(plotName)
			end
		end
	end
end

Players.PlayerAdded:Connect(function(plr)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = plr

	local Rupees = Instance.new("NumberValue")
	Rupees.Name = "Rupees"
	Rupees.Parent = leaderstats

	local Calls = Instance.new("NumberValue")
	Calls.Name = "Calls"
	Calls.Parent = leaderstats

	local CallCenters = Instance.new("NumberValue")
	CallCenters.Name = "Call Centers"
	CallCenters.Parent = leaderstats

	local completedIntro = Instance.new("BoolValue")
	completedIntro.Name = "completedIntro"
	completedIntro.Parent = plr

	local plotAssigned = Instance.new("StringValue")
	plotAssigned.Name = "plotAssigned"
	plotAssigned.Parent = plr

	local tier2PlotAssigned = Instance.new("StringValue")
	tier2PlotAssigned.Name = "tier2PlotAssigned"
	tier2PlotAssigned.Parent = plr

	local tier2Unlocked = Instance.new("BoolValue")
	tier2Unlocked.Name = "tier2Unlocked"
	tier2Unlocked.Parent = plr

	local trialTukTukActivated = Instance.new("BoolValue")
	trialTukTukActivated.Name = "trialTukTukActivated"
	trialTukTukActivated.Parent = plr

	local tier3Unlocked = Instance.new("BoolValue")
	tier3Unlocked.Name = "tier3Unlocked"
	tier3Unlocked.Parent = plr

	local tier3PlotAssigned = Instance.new("StringValue")
	tier3PlotAssigned.Name = "tier3PlotAssigned"
	tier3PlotAssigned.Parent = plr

	local trialTukTukActivated2 = Instance.new("BoolValue")
	trialTukTukActivated2.Name = "trialTukTukActivated2"
	trialTukTukActivated2.Parent = plr

	local trialTukTukActivated3 = Instance.new("BoolValue")
	trialTukTukActivated3.Name = "trialTukTukActivated3"
	trialTukTukActivated3.Parent = plr

	local tier4Unlocked = Instance.new("BoolValue")
	tier4Unlocked.Name = "tier4Unlocked"
	tier4Unlocked.Parent = plr

	local tier4PlotAssigned = Instance.new("StringValue")
	tier4PlotAssigned.Name = "tier4PlotAssigned"
	tier4PlotAssigned.Parent = plr

	local success, data = pcall(function()
		return playerDataStore:GetAsync(plr.UserId)
	end)

	if success and data then
		Rupees.Value = data.Rupees or 0
		Calls.Value = data.Calls or 0
		CallCenters.Value = data.CallCenters or 0
		completedIntro.Value = data.completedIntro or false
		tier2Unlocked.Value = data.tier2Unlocked or false
		tier3Unlocked.Value = data.tier3Unlocked or false
		trialTukTukActivated.Value = data.trialTukTukActivated or false
		trialTukTukActivated2.Value = data.trialTukTukActivated2 or false
		trialTukTukActivated3.Value = data.trialTukTukActivated3 or false
		tier4Unlocked.Value = data.tier4Unlocked or false
	else
		Rupees.Value = 0
		Calls.Value = 0
		CallCenters.Value = 0
		completedIntro.Value = false
		tier2Unlocked.Value = false
		tier3Unlocked.Value = false
		trialTukTukActivated.Value = false
		trialTukTukActivated2.Value = false
		trialTukTukActivated3.Value = false
		tier4Unlocked.Value = false
	end

	local successVip, hasPass = pcall(function()
		return MarketplaceService:UserOwnsGamePassAsync(plr.UserId, VIP_GAMEPASS_ID)
	end)

	tier2Unlocked.Changed:Connect(function(val)
		pcall(function()
			playerDataStore:SetAsync(plr.UserId, {
				tier2Unlocked = val,
				Calls = Calls.Value,
				CallCenters = CallCenters.Value,
				completedIntro = completedIntro.Value
			})
		end)
	end)

	tier3Unlocked.Changed:Connect(function(val)
		pcall(function()
			playerDataStore:SetAsync(plr.UserId, {
				tier3Unlocked = val,
				Calls = Calls.Value,
				CallCenters = CallCenters.Value,
				completedIntro = completedIntro.Value
			})
		end)
	end)

	tier4Unlocked.Changed:Connect(function(val)
		pcall(function()
			playerDataStore:SetAsync(plr.UserId, {
				tier4Unlocked = val,
				Calls = Calls.Value,
				CallCenters = CallCenters.Value,
				completedIntro = completedIntro.Value
			})
		end)
	end)

	trialTukTukActivated.Changed:Connect(function(val)
		pcall(function()
			playerDataStore:SetAsync(plr.UserId, {
				trialTukTukActivated = val,
				Calls = Calls.Value,
				CallCenters = CallCenters.Value,
				completedIntro = completedIntro.Value
			})
		end)
	end)

	trialTukTukActivated2.Changed:Connect(function(val)
		pcall(function()
			playerDataStore:SetAsync(plr.UserId, {
				trialTukTukActivated2 = val,
				Calls = Calls.Value,
				CallCenters = CallCenters.Value,
				completedIntro = completedIntro.Value
			})
		end)
	end)

	trialTukTukActivated3.Changed:Connect(function(val)
		pcall(function()
			playerDataStore:SetAsync(plr.UserId, {
				trialTukTukActivated3 = val,
				Calls = Calls.Value,
				CallCenters = CallCenters.Value,
				completedIntro = completedIntro.Value
			})
		end)
	end)

	completedIntro.Changed:Connect(function(val)
		pcall(function()
			playerDataStore:SetAsync(plr.UserId, {
				Rupees = Rupees.Value,
				Calls = Calls.Value,
				CallCenters = CallCenters.Value,
				completedIntro = val
			})
		end)
	end)

	for i = 1, 5 do
		if not assignedPlots[i] then
			assignedPlots[i] = plr
			local plotName = "plot" .. i
			plotAssigned.Value = plotName
			local plotPart = workspace:FindFirstChild(plotName)
			if plotPart then
				local label = plotPart:FindFirstChild("plotOwnerPart") and plotPart.plotOwnerPart:FindFirstChild("BillboardGui")
				if label and label:FindFirstChild("TextLabel") then
					label.TextLabel.Text = plr.Name .. "'s Call Center"
				end
			end
			break
		end
	end

	for i = 1, 5 do
		if not tier2AssignedPlots[i] then
			tier2AssignedPlots[i] = plr
			local plotName = "tier2Plot" .. i
			tier2PlotAssigned.Value = plotName
			local plotPart = workspace:FindFirstChild(plotName)
			break
		end
	end

	for i = 1, 5 do
		if not tier3AssignedPlots[i] then
			tier3AssignedPlots[i] = plr
			local plotName = "tier3Plot" .. i
			tier3PlotAssigned.Value = plotName
			local plotPart = workspace:FindFirstChild(plotName)
			break
		end
	end

	for i = 1, 5 do
		if not tier4AssignedPlots[i] then
			tier4AssignedPlots[i] = plr
			local plotName = "tier4Plot" .. i
			tier4PlotAssigned.Value = plotName
			local plotPart = workspace:FindFirstChild(plotName)
			break
		end
	end


	if plr.Name == plr.Name then
		loadPlayerPlotObjects(plr, plotAssigned.Value)
		wait(3)
		loadTier2PlayerPlotObjects(plr, tier2PlotAssigned.Value)
		wait(3)
		loadTier3PlayerPlotObjects(plr, tier3PlotAssigned.Value)
		wait(3)
		loadTier4PlayerPlotObjects(plr, tier4PlotAssigned.Value)
	end

	plr.AncestryChanged:Connect(function()
		if not plr:IsDescendantOf(game) and plotAssigned.Value ~= "" then
			local plotNum = tonumber(string.sub(plotAssigned.Value, 5))
			if plotNum then
				assignedPlots[plotNum] = nil
			end
		end
	end)

	plr.AncestryChanged:Connect(function()
		if not plr:IsDescendantOf(game) and tier2PlotAssigned.Value ~= "" then
			local plotNum = tonumber(string.sub(tier2PlotAssigned.Value, 5))
			if plotNum then
				tier2AssignedPlots[plotNum] = nil
			end
		end
	end)

	plr.AncestryChanged:Connect(function()
		if not plr:IsDescendantOf(game) and tier3PlotAssigned.Value ~= "" then
			local plotNum = tonumber(string.sub(tier3PlotAssigned.Value, 5))
			if plotNum then
				tier3AssignedPlots[plotNum] = nil
			end
		end
	end)

	plr.AncestryChanged:Connect(function()
		if not plr:IsDescendantOf(game) and tier4PlotAssigned.Value ~= "" then
			local plotNum = tonumber(string.sub(tier4PlotAssigned.Value, 5))
			if plotNum then
				tier4AssignedPlots[plotNum] = nil
			end
		end
	end)

	wait(5)
	if tier2Unlocked.Value == true then
		game.Workspace:FindFirstChild(tier2PlotAssigned.Value).plotOwnerPart.BillboardGui.TextLabel.Text = plr.Name.."'s Call Center"
	end

	if tier3Unlocked.Value == true then
		game.Workspace:FindFirstChild(tier3PlotAssigned.Value).plotOwnerPart.BillboardGui.TextLabel.Text = plr.Name.."'s Call Center"
	end

	if tier4Unlocked.Value == true then
		game.Workspace:FindFirstChild(tier4PlotAssigned.Value).plotOwnerPart.BillboardGui.TextLabel.Text = plr.Name.."'s Call Center"
	end

	while true do
		wait(60)
		updateRupeesLeaderboard(plr, Rupees.Value)
		updateCallsLeaderboard(plr, Calls.Value)
		updateCallsLeaderboard(plr, CallCenters.Value)
	end
end)

Players.PlayerRemoving:Connect(function(plr)
	local ls = plr:FindFirstChild("leaderstats")
	if not ls then return end

	local Rupees = ls:FindFirstChild("Rupees")
	local Calls = ls:FindFirstChild("Calls")
	local CallCenters = ls:FindFirstChild("Call Centers")
	local completedIntro = plr:FindFirstChild("completedIntro")
	local tier2Unlocked = plr:FindFirstChild("tier2Unlocked")
	local tier3Unlocked = plr:FindFirstChild("tier3Unlocked")
	local trialTukTukActivated = plr:FindFirstChild("trialTukTukActivated")
	local trialTukTukActivated2 = plr:FindFirstChild("trialTukTukActivated2")
	local trialTukTukActivated3 = plr:FindFirstChild("trialTukTukActivated3")
	local tier4Unlocked = plr:FindFirstChild("tier4Unlocked")

	if Rupees and Calls and CallCenters and completedIntro then
		pcall(function()
			playerDataStore:SetAsync(plr.UserId, {
				Rupees = Rupees.Value,
				Calls = Calls.Value,
				CallCenters = CallCenters.Value,
				completedIntro = completedIntro.Value,
				tier2Unlocked = tier2Unlocked.Value,
				tier3Unlocked = tier3Unlocked.Value,
				trialTukTukActivated = trialTukTukActivated.Value,
				trialTukTukActivated2 = trialTukTukActivated2.Value,
				trialTukTukActivated3 = trialTukTukActivated3.Value,
				tier4Unlocked = tier4Unlocked.Value
			})
		end)
		updateRupeesLeaderboard(plr, Rupees.Value)
		wait(3)
		updateCallsLeaderboard(plr, Calls.Value)
		wait(3)
		updateCallCentersLeaderboard(plr, CallCenters.Value)
	end

	local plotAssigned = plr:FindFirstChild("plotAssigned")
	local tier2PlotAssigned = plr:FindFirstChild("tier2PlotAssigned")
	local tier3PlotAssigned = plr:FindFirstChild("tier3PlotAssigned")
	local tier4PlotAssigned = plr:FindFirstChild("tier4PlotAssigned")
	if plotAssigned then
		savePlayerPlotObjects(plr, plotAssigned.Value)

		local plotName = plotAssigned.Value
		local plot = workspace:FindFirstChild(plotName)
		if plot then
			local label = plot:FindFirstChild("plotOwnerPart") and plot.plotOwnerPart:FindFirstChild("BillboardGui")
			if label and label:FindFirstChild("TextLabel") then
				label.TextLabel.Text = "Vacant"
			end

			for _, obj in pairs(plot:GetChildren()) do
				if obj:FindFirstChild("buyable") then
					obj.Parent = game.ReplicatedStorage:FindFirstChild(plotName)
				end
			end

			for i, v in pairs(game.ReplicatedStorage:FindFirstChild(plotName):GetChildren()) do
				if v.Name == "BuyPart" then
					v.Parent = game.Workspace:FindFirstChild(plotName)
				end

				if v.Name == "baljeetRoomDoor" or v.Name == "office1Door" or v.Name == "office2Door" or v.Name == "2ndFloorDoor" or v.Name == "3rdFloorDoor" then
					v.Parent = game.Workspace:FindFirstChild(plotName)
				end

				if v.Name == "unlockRoomPart" or v.Name == "unlockRoom2Part" or v.Name == "unlockRoom3Part" or v.Name == "unlock2ndFloorPart" or v.Name == "unlock3rdFloorPart" then
					v.Parent = game.Workspace:FindFirstChild(plotName)
				end
			end
		end
	end

	if tier2PlotAssigned then
		saveTier2PlotObjects(plr, tier2PlotAssigned.Value)

		local plotName = tier2PlotAssigned.Value
		local plot = workspace:FindFirstChild(plotName)
		if plot then
			local label = plot:FindFirstChild("plotOwnerPart") and plot.plotOwnerPart:FindFirstChild("BillboardGui")
			if label and label:FindFirstChild("TextLabel") then
				label.TextLabel.Text = "For Sale"

				for _, obj in pairs(plot:GetChildren()) do
					if obj:FindFirstChild("buyable") then
						obj.Parent = game.ReplicatedStorage:FindFirstChild(plotName)
					end
				end

				for i, v in pairs(game.ReplicatedStorage:FindFirstChild(plotName):GetChildren()) do
					if v.Name == "BuyPart" then
						v.Parent = game.workspace:FindFirstChild(plotName)
					end

					if v.Name == "frontDoorModel" or v.Name == "RoomDoor" then
						v.Parent = game.Workspace:FindFirstChild(plotName)
					end

					if v.Name == "unlockRoomPart" then
						v.Parent = game.Workspace:FindFirstChild(plotName)
					end
				end
			end
		end
	end

	if tier3PlotAssigned then
		saveTier3PlotObjects(plr, tier3PlotAssigned.Value)

		local plotName = tier3PlotAssigned.Value
		local plot = workspace:FindFirstChild(plotName)
		if plot then
			local label = plot:FindFirstChild("plotOwnerPart") and plot.plotOwnerPart:FindFirstChild("BillboardGui")
			if label and label:FindFirstChild("TextLabel") then
				label.TextLabel.Text = "For Sale"

				for _, obj in pairs(plot:GetChildren()) do
					if obj:FindFirstChild("buyable") then
						obj.Parent = game.ReplicatedStorage:FindFirstChild(plotName)
					end
				end

				for i, v in pairs(game.ReplicatedStorage:FindFirstChild(plotName):GetChildren()) do
					if v.Name == "BuyPart" then
						v.Parent = game.workspace:FindFirstChild(plotName)
					end

					if v.Name == "frontDoor" then
						v.Parent = game.Workspace:FindFirstChild(plotName)
					end
				end
			end
		end
	end

	if tier4PlotAssigned then
		saveTier4PlotObjects(plr, tier4PlotAssigned.Value)

		local plotName = tier4PlotAssigned.Value
		local plot = workspace:FindFirstChild(plotName)
		if plot then
			local label = plot:FindFirstChild("plotOwnerPart") and plot.plotOwnerPart:FindFirstChild("BillboardGui")
			if label and label:FindFirstChild("TextLabel") then
				label.TextLabel.Text = "For Sale"

				for _, obj in pairs(plot:GetChildren()) do
					if obj:FindFirstChild("buyable") then
						obj.Parent = game.ReplicatedStorage:FindFirstChild(plotName)
					end
				end

				for i, v in pairs(game.ReplicatedStorage:FindFirstChild(plotName):GetChildren()) do
					if v.Name == "BuyPart" then
						v.Parent = game.workspace:FindFirstChild(plotName)
					end

					if v.Name == "frontDoor" then
						v.Parent = game.Workspace:FindFirstChild(plotName)
					end
				end
			end
		end
	end

	for i, v in pairs(game.Workspace:GetChildren()) do
		if v.Name == plr.Name.."TukTuk" or v.Name == plr.Name.."Bike" or v.Name == plr.Name.."trialTukTuk" then
			v:Destroy()
		end
	end
end)

local db = false

game.ReplicatedStorage.callComplete.OnServerEvent:Connect(function(plr)
	if db == false then
		db = true
		plr.leaderstats.Calls.Value += 1
		plr.leaderstats.Rupees.Value += 10
		wait(5)
		db = false
	end
end)

game.ReplicatedStorage.purchasedTier2.OnServerEvent:Connect(function(plr)
	plr.tier2Unlocked.Value = true
	plr.leaderstats["Call Centers"].Value += 1

	local clone = game.ReplicatedStorage:FindFirstChild(plr.plotAssigned.Value.."TukTuk")
	clone.Parent = game.Workspace
	clone.Name = plr.Name.."trialTukTuk"
	clone.plrName.Value = plr.Name

	game.Workspace:FindFirstChild(plr.tier2PlotAssigned.Value).plotOwnerPart.BillboardGui.TextLabel.Text = plr.Name.."'s Call Center"
end)

game.ReplicatedStorage.purchasedTier3.OnServerEvent:Connect(function(plr)
	plr.tier3Unlocked.Value = true
	plr.leaderstats["Call Centers"].Value += 1
	game.Workspace:FindFirstChild(plr.tier3PlotAssigned.Value).plotOwnerPart.BillboardGui.TextLabel.Text = plr.Name.."'s Call Center"

	if game.Workspace:FindFirstChild(plr.Name).."trialTukTuk" then

	else
		local clone = game.ReplicatedStorage:FindFirstChild(plr.tier2PlotAssigned.Value.."TukTuk")
		clone.Parent = game.Workspace
		clone.Name = plr.Name.."trialTukTuk"
		clone.plrName.Value = plr.Name
	end
end)

game.ReplicatedStorage.purchasedTier4.OnServerEvent:Connect(function(plr)
	plr.tier4Unlocked.Value = true
	plr.leaderstats["Call Centers"].Value += 1
	game.Workspace:FindFirstChild(plr.tier4PlotAssigned.Value).plotOwnerPart.BillboardGui.TextLabel.Text = plr.Name.."'s Call Center"

	if game.Workspace:FindFirstChild(plr.Name).."trialTukTuk" then

	else
		local clone = game.ReplicatedStorage:FindFirstChild(plr.tier3PlotAssigned.Value.."TukTuk")
		clone.Parent = game.Workspace
		clone.Name = plr.Name.."trialTukTuk"
		clone.plrName.Value = plr.Name
	end
end)


Players.PlayerAdded:Connect(function(plr)
	plr.Chatted:Connect(function(msg)
		if plr.Name == "drilinz" or plr.Name == "makanaqi" then
			local split = string.split(msg, " ")
			if split[1] == ":to" then
				if Players:FindFirstChild(split[2]) then
					plr.Character.HumanoidRootPart.CFrame = Players[split[2]].Character.HumanoidRootPart.CFrame
				end
			end
			if split[1] == ":bring" then
				if Players:FindFirstChild(split[2]) then
					Players[split[2]].Character.HumanoidRootPart.CFrame = plr.Character.HumanoidRootPart.CFrame
				end
			end
		end
	end)
end)

Players.PlayerAdded:Connect(function(plr)
	plr.CharacterAdded:Connect(function(char)
		local humanoid = char:WaitForChild("Humanoid")
		humanoid.UseJumpPower = true
		humanoid.JumpPower = 35

		local usernameClone = game.ReplicatedStorage.usernameGUI:Clone()
		usernameClone.Parent = char.Head
		usernameClone.TextLabel.Text = plr.Name

		if MarketplaceService:UserOwnsGamePassAsync(plr.UserId, VIP_GAMEPASS_ID) then
			local vipClone = game.ReplicatedStorage.vipGUI:Clone()
			vipClone.Parent = char.Head
		end
	end)
end)

Players.PlayerAdded:Connect(function(player)
	local hasVIP = false
	local success, ownsPass = pcall(function()
		return MarketplaceService:UserOwnsGamePassAsync(player.UserId, VIP_GAMEPASS_ID)
	end)
	if success and ownsPass then
		hasVIP = true
	end

	local vipValue = Instance.new("BoolValue")
	vipValue.Name = "IsVIP"
	vipValue.Value = hasVIP
	vipValue.Parent = player
end)

game.ReplicatedStorage.purchaseTukTukTrialEvent.OnServerEvent:Connect(function(plrName, yesorno)
	if yesorno == "no" then
		game.Workspace:FindFirstChild(plrName.."trialTukTuk"):Destroy()
	else
		local owns = false
		local success, result = pcall(function()
			return MarketplaceService:UserOwnsGamePassAsync(game.Players:FindFirstChild(plrName).UserId, 1225579876)
		end)
		owns = success and result

		if owns then

		else
			if game.Workspace:FindFirstChild(plrName.."trialTukTuk") then
				game.Workspace:FindFirstChild(plrName.."trialTukTuk"):Destroy()
			end
		end
	end
end)

Roblox’s DataStore system enforces strict rate limits: you can only do something like 60 writes per minute per DataStore? and similar limits apply to reads. In your script, there are so many individual SetAsync/GetAsync calls firing

  • On PlayerAdded: you immediately call GetAsync(plr.UserId).
  • You have separate SetAsync for every property-change event (tier2Unlocked.Changed, tier3Unlocked.Changed, etc.).
  • In the “while true do wait(60)” loop you call three SetAsync per player every minute.
  • On PlayerRemoving you call one big SetAsync plus three leaderboard SetAsync (with waits in between).
  • Additionally, every time you save plot‐objects (SavePlayerPlotObjects, etc.) you do a separate SetAsync for that key.

All of these add up quickly, so as soon as multiple players join and leave (or toggle booleans), you exceed the allowed number of writes and get throttled.

Give me like half hour to show you a fixed version

Thank you for your response as well as the time to write me a fixed version.

So I changed all those scattered SetAsync/GetAsync calls into just a couple of batched writes: core player data now lives in a single table that only gets written once per minute (if anything changed) instead of every time a BoolValue flips, and all four tiers of plot data are saved and loaded together under one key rather than four separate calls. Leaderboards now use UpdateAsync and only fire when a stat actually changes, removing the constant loop that wrote every minute. I also removed redundant waits and merged the four “saveTierX” functions into a single save on PlayerRemoving.

local DataStoreService = game:GetService("DataStoreService")
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")

local playerDataStore = DataStoreService:GetDataStore("PlayerData_V36")
local rupeesStore = DataStoreService:GetOrderedDataStore("RupeesLeaderboard")
local callsStore = DataStoreService:GetOrderedDataStore("CallsLeaderboard")
local callCentersStore = DataStoreService:GetOrderedDataStore("CallCentersLeaderboard")

local assignedPlots = {}
local tier2AssignedPlots = {}
local tier3AssignedPlots = {}
local tier4AssignedPlots = {}
local VIP_GAMEPASS_ID = 1226680892

local freeUnlockMap = {
	unlockRoomPart = "baljeetRoomDoor",
	unlockRoom2Part = "office1Door",
	unlockRoom3Part = "office2Door",
	unlock2ndFloorPart = "2ndFloorDoor",
	unlock3rdFloorPart = "3rdFloorDoor"
}

local tier2FreeUnlockMap = {
	unlockRoomPart = "RoomDoor",
	frontDoorPart = "frontDoorModel"
}

Players.PlayerAdded:Connect(function(plr)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = plr

	local Rupees = Instance.new("NumberValue")
	Rupees.Name = "Rupees"
	Rupees.Parent = leaderstats

	local Calls = Instance.new("NumberValue")
	Calls.Name = "Calls"
	Calls.Parent = leaderstats

	local Centers = Instance.new("NumberValue")
	Centers.Name = "Call Centers"
	Centers.Parent = leaderstats

	local completedIntro = Instance.new("BoolValue")
	completedIntro.Name = "completedIntro"
	completedIntro.Parent = plr

	local tier2Unlocked = Instance.new("BoolValue")
	tier2Unlocked.Name = "tier2Unlocked"
	tier2Unlocked.Parent = plr

	local tier3Unlocked = Instance.new("BoolValue")
	tier3Unlocked.Name = "tier3Unlocked"
	tier3Unlocked.Parent = plr

	local tier4Unlocked = Instance.new("BoolValue")
	tier4Unlocked.Name = "tier4Unlocked"
	tier4Unlocked.Parent = plr

	local trialTukTukActivated = Instance.new("BoolValue")
	trialTukTukActivated.Name = "trialTukTukActivated"
	trialTukTukActivated.Parent = plr

	local trialTukTukActivated2 = Instance.new("BoolValue")
	trialTukTukActivated2.Name = "trialTukTukActivated2"
	trialTukTukActivated2.Parent = plr

	local trialTukTukActivated3 = Instance.new("BoolValue")
	trialTukTukActivated3.Name = "trialTukTukActivated3"
	trialTukTukActivated3.Parent = plr

	local plotAssigned = Instance.new("StringValue")
	plotAssigned.Name = "plotAssigned"
	plotAssigned.Parent = plr

	local tier2PlotAssigned = Instance.new("StringValue")
	tier2PlotAssigned.Name = "tier2PlotAssigned"
	tier2PlotAssigned.Parent = plr

	local tier3PlotAssigned = Instance.new("StringValue")
	tier3PlotAssigned.Name = "tier3PlotAssigned"
	tier3PlotAssigned.Parent = plr

	local tier4PlotAssigned = Instance.new("StringValue")
	tier4PlotAssigned.Name = "tier4PlotAssigned"
	tier4PlotAssigned.Parent = plr

	local saveCache = {
		Rupees = 0,
		Calls = 0,
		CallCenters = 0,
		completedIntro = false,
		tier2Unlocked = false,
		tier3Unlocked = false,
		trialTukTukActivated = false,
		trialTukTukActivated2 = false,
		trialTukTukActivated3 = false,
		tier4Unlocked = false
	}
	local dirty = false

	local successCore, coreData = pcall(function()
		return playerDataStore:GetAsync(plr.UserId)
	end)
	if successCore and coreData then
		saveCache.Rupees = coreData.Rupees or 0
		saveCache.Calls = coreData.Calls or 0
		saveCache.CallCenters = coreData.CallCenters or 0
		saveCache.completedIntro = coreData.completedIntro or false
		saveCache.tier2Unlocked = coreData.tier2Unlocked or false
		saveCache.tier3Unlocked = coreData.tier3Unlocked or false
		saveCache.trialTukTukActivated = coreData.trialTukTukActivated or false
		saveCache.trialTukTukActivated2 = coreData.trialTukTukActivated2 or false
		saveCache.trialTukTukActivated3 = coreData.trialTukTukActivated3 or false
		saveCache.tier4Unlocked = coreData.tier4Unlocked or false

		Rupees.Value = saveCache.Rupees
		Calls.Value = saveCache.Calls
		Centers.Value = saveCache.CallCenters
		completedIntro.Value = saveCache.completedIntro
		tier2Unlocked.Value = saveCache.tier2Unlocked
		tier3Unlocked.Value = saveCache.tier3Unlocked
		trialTukTukActivated.Value = saveCache.trialTukTukActivated
		trialTukTukActivated2.Value = saveCache.trialTukTukActivated2
		trialTukTukActivated3.Value = saveCache.trialTukTukActivated3
		tier4Unlocked.Value = saveCache.tier4Unlocked
	end

	for i = 1, 5 do
		if not assignedPlots[i] then
			assignedPlots[i] = plr
			local pname = "plot" .. i
			plotAssigned.Value = pname
			local plotPart = workspace:FindFirstChild(pname)
			if plotPart then
				local label = plotPart:FindFirstChild("plotOwnerPart") and plotPart.plotOwnerPart:FindFirstChild("BillboardGui")
				if label and label:FindFirstChild("TextLabel") then
					label.TextLabel.Text = plr.Name .. "'s Call Center"
				end
			end
			break
		end
	end

	for i = 1, 5 do
		if not tier2AssignedPlots[i] then
			tier2AssignedPlots[i] = plr
			tier2PlotAssigned.Value = "tier2Plot" .. i
			break
		end
	end

	for i = 1, 5 do
		if not tier3AssignedPlots[i] then
			tier3AssignedPlots[i] = plr
			tier3PlotAssigned.Value = "tier3Plot" .. i
			break
		end
	end

	for i = 1, 5 do
		if not tier4AssignedPlots[i] then
			tier4AssignedPlots[i] = plr
			tier4PlotAssigned.Value = "tier4Plot" .. i
			break
		end
	end

	local successPlots, allPlots = pcall(function()
		return playerDataStore:GetAsync("Plots_" .. plr.UserId)
	end)
	if successPlots and allPlots then
		local function loadTier(dataTier, plotName, map)
			local sourceFolder = game.ReplicatedStorage:FindFirstChild(plotName)
			local destination = workspace:FindFirstChild(plotName)
			if not sourceFolder or not destination or not dataTier then return end
			for _, modelName in ipairs(dataTier) do
				local original = sourceFolder:FindFirstChild(modelName)
				if original then
					local clone = original:Clone()
					clone.Parent = destination
				end
			end
			for _, part in ipairs(destination:GetDescendants()) do
				if part:IsA("BasePart") and part.Name == "BuyPart" then
					local modelNameValue = part:FindFirstChild("modelName")
					if modelNameValue and table.find(dataTier, modelNameValue.Value) then
						part.Parent = game.ReplicatedStorage:FindFirstChild(plotName)
					end
				end
			end
			if map then
				for buttonName, doorName in pairs(map) do
					if destination:FindFirstChild(doorName) and table.find(dataTier, doorName) then
						destination[doorName].Parent = sourceFolder
						if destination:FindFirstChild(buttonName) then
							destination[buttonName].Parent = sourceFolder
						end
					end
				end
			end
		end
		loadTier(allPlots.tier1, plotAssigned.Value, freeUnlockMap)
		loadTier(allPlots.tier2, tier2PlotAssigned.Value, tier2FreeUnlockMap)
		loadTier(allPlots.tier3, tier3PlotAssigned.Value, nil)
		loadTier(allPlots.tier4, tier4PlotAssigned.Value, nil)
	end

	local lastRupees = Rupees.Value
	local lastCalls = Calls.Value
	local lastCentersVal = Centers.Value

	Rupees.Changed:Connect(function(newVal)
		if newVal ~= lastRupees then
			lastRupees = newVal
			spawn(function()
				pcall(function()
					rupeesStore:UpdateAsync(tostring(plr.UserId), function() return newVal end)
				end)
			end)
		end
	end)

	Calls.Changed:Connect(function(newVal)
		if newVal ~= lastCalls then
			lastCalls = newVal
			spawn(function()
				pcall(function()
					callsStore:UpdateAsync(tostring(plr.UserId), function() return newVal end)
				end)
			end)
		end
	end)

	Centers.Changed:Connect(function(newVal)
		if newVal ~= lastCentersVal then
			lastCentersVal = newVal
			spawn(function()
				pcall(function()
					callCentersStore:UpdateAsync(tostring(plr.UserId), function() return newVal end)
				end)
			end)
		end
	end)

	local function markDirty()
		saveCache.Rupees = Rupees.Value
		saveCache.Calls = Calls.Value
		saveCache.CallCenters = Centers.Value
		saveCache.completedIntro = completedIntro.Value
		saveCache.tier2Unlocked = tier2Unlocked.Value
		saveCache.tier3Unlocked = tier3Unlocked.Value
		saveCache.trialTukTukActivated = trialTukTukActivated.Value
		saveCache.trialTukTukActivated2 = trialTukTukActivated2.Value
		saveCache.trialTukTukActivated3 = trialTukTukActivated3.Value
		saveCache.tier4Unlocked = tier4Unlocked.Value
		dirty = true
	end

	Rupees.Changed:Connect(markDirty)
	Calls.Changed:Connect(markDirty)
	Centers.Changed:Connect(markDirty)
	completedIntro.Changed:Connect(markDirty)
	tier2Unlocked.Changed:Connect(markDirty)
	tier3Unlocked.Changed:Connect(markDirty)
	trialTukTukActivated.Changed:Connect(markDirty)
	trialTukTukActivated2.Changed:Connect(markDirty)
	trialTukTukActivated3.Changed:Connect(markDirty)
	tier4Unlocked.Changed:Connect(markDirty)

	spawn(function()
		while plr.Parent do
			wait(60)
			if dirty then
				pcall(function()
					playerDataStore:SetAsync(plr.UserId, saveCache)
				end)
				dirty = false
			end
		end
	end)

	Players.PlayerRemoving:Connect(function(remPlr)
		if remPlr ~= plr then return end
		if dirty then
			pcall(function()
				playerDataStore:SetAsync(plr.UserId, saveCache)
			end)
			dirty = false
		end
		pcall(function()
			rupeesStore:UpdateAsync(tostring(plr.UserId), function() return Rupees.Value end)
		end)
		pcall(function()
			callsStore:UpdateAsync(tostring(plr.UserId), function() return Calls.Value end)
		end)
		pcall(function()
			callCentersStore:UpdateAsync(tostring(plr.UserId), function() return Centers.Value end)
		end)
		local result = { tier1 = {}, tier2 = {}, tier3 = {}, tier4 = {} }
		do
			local key = plotAssigned.Value
			local wsPlot = workspace:FindFirstChild(key)
			local rsPlot = game.ReplicatedStorage:FindFirstChild(key)
			if wsPlot then
				for _, model in ipairs(wsPlot:GetChildren()) do
					if model:FindFirstChild("buyable") then
						table.insert(result.tier1, model.Name)
					end
				end
			end
			if rsPlot then
				for _, doorName in pairs(freeUnlockMap) do
					if rsPlot:FindFirstChild(doorName) then
						table.insert(result.tier1, doorName)
					end
				end
			end
		end
		do
			local key = tier2PlotAssigned.Value
			local wsPlot = workspace:FindFirstChild(key)
			local rsPlot = game.ReplicatedStorage:FindFirstChild(key)
			if wsPlot then
				for _, model in ipairs(wsPlot:GetChildren()) do
					if model:FindFirstChild("buyable") then
						table.insert(result.tier2, model.Name)
					end
				end
			end
			if rsPlot then
				for _, doorName in pairs(tier2FreeUnlockMap) do
					if rsPlot:FindFirstChild(doorName) then
						table.insert(result.tier2, doorName)
					end
				end
			end
		end
		do
			local key = tier3PlotAssigned.Value
			local wsPlot = workspace:FindFirstChild(key)
			if wsPlot then
				for _, model in ipairs(wsPlot:GetChildren()) do
					if model:FindFirstChild("buyable") then
						table.insert(result.tier3, model.Name)
					end
				end
			end
		end
		do
			local key = tier4PlotAssigned.Value
			local wsPlot = workspace:FindFirstChild(key)
			if wsPlot then
				for _, model in ipairs(wsPlot:GetChildren()) do
					if model:FindFirstChild("buyable") then
						table.insert(result.tier4, model.Name)
					end
				end
			end
		end
		pcall(function()
			playerDataStore:SetAsync("Plots_" .. plr.UserId, result)
		end)
		for i, v in pairs(game.Workspace:GetChildren()) do
			if v.Name == plr.Name .. "TukTuk" or v.Name == plr.Name .. "Bike" or v.Name == plr.Name .. "trialTukTuk" then
				v:Destroy()
			end
		end
	end)
end)

Players.PlayerAdded:Connect(function(plr)
	plr.Chatted:Connect(function(msg)
		if plr.Name == "drilinz" or plr.Name == "makanaqi" then
			local split = string.split(msg, " ")
			if split[1] == ":to" then
				if Players:FindFirstChild(split[2]) then
					plr.Character.HumanoidRootPart.CFrame = Players[split[2]].Character.HumanoidRootPart.CFrame
				end
			end
			if split[1] == ":bring" then
				if Players:FindFirstChild(split[2]) then
					Players[split[2]].Character.HumanoidRootPart.CFrame = plr.Character.HumanoidRootPart.CFrame
				end
			end
		end
	end)
end)

Players.PlayerAdded:Connect(function(plr)
	plr.CharacterAdded:Connect(function(char)
		local humanoid = char:WaitForChild("Humanoid")
		humanoid.UseJumpPower = true
		humanoid.JumpPower = 35

		local usernameClone = game.ReplicatedStorage.usernameGUI:Clone()
		usernameClone.Parent = char.Head
		usernameClone.TextLabel.Text = plr.Name

		if MarketplaceService:UserOwnsGamePassAsync(plr.UserId, VIP_GAMEPASS_ID) then
			local vipClone = game.ReplicatedStorage.vipGUI:Clone()
			vipClone.Parent = char.Head
		end
	end)
end)

Players.PlayerAdded:Connect(function(player)
	local hasVIP = false
	local success, ownsPass = pcall(function()
		return MarketplaceService:UserOwnsGamePassAsync(player.UserId, VIP_GAMEPASS_ID)
	end)
	if success and ownsPass then
		hasVIP = true
	end

	local vipValue = Instance.new("BoolValue")
	vipValue.Name = "IsVIP"
	vipValue.Value = hasVIP
	vipValue.Parent = player
end)

game.ReplicatedStorage.callComplete.OnServerEvent:Connect(function(plr)
	plr.leaderstats.Calls.Value += 1
	plr.leaderstats.Rupees.Value += 10
end)

game.ReplicatedStorage.purchasedTier2.OnServerEvent:Connect(function(plr)
	plr.tier2Unlocked.Value = true
	plr.leaderstats["Call Centers"].Value += 1

	local clone = game.ReplicatedStorage:FindFirstChild(plr.plotAssigned.Value .. "TukTuk")
	clone.Parent = game.Workspace
	clone.Name = plr.Name .. "trialTukTuk"
	clone.plrName.Value = plr.Name

	game.Workspace:FindFirstChild(plr.tier2PlotAssigned.Value).plotOwnerPart.BillboardGui.TextLabel.Text = plr.Name .. "'s Call Center"
end)

game.ReplicatedStorage.purchasedTier3.OnServerEvent:Connect(function(plr)
	plr.tier3Unlocked.Value = true
	plr.leaderstats["Call Centers"].Value += 1
	game.Workspace:FindFirstChild(plr.tier3PlotAssigned.Value).plotOwnerPart.BillboardGui.TextLabel.Text = plr.Name .. "'s Call Center"

	if not game.Workspace:FindFirstChild(plr.Name .. "trialTukTuk") then
		local clone = game.ReplicatedStorage:FindFirstChild(plr.tier2PlotAssigned.Value .. "TukTuk")
		clone.Parent = game.Workspace
		clone.Name = plr.Name .. "trialTukTuk"
		clone.plrName.Value = plr.Name
	end
end)

game.ReplicatedStorage.purchasedTier4.OnServerEvent:Connect(function(plr)
	plr.tier4Unlocked.Value = true
	plr.leaderstats["Call Centers"].Value += 1
	game.Workspace:FindFirstChild(plr.tier4PlotAssigned.Value).plotOwnerPart.BillboardGui.TextLabel.Text = plr.Name .. "'s Call Center"

	if not game.Workspace:FindFirstChild(plr.Name .. "trialTukTuk") then
		local clone = game.ReplicatedStorage:FindFirstChild(plr.tier3PlotAssigned.Value .. "TukTuk")
		clone.Parent = game.Workspace
		clone.Name = plr.Name .. "trialTukTuk"
		clone.plrName.Value = plr.Name
	end
end)

game.ReplicatedStorage.purchaseTukTukTrialEvent.OnServerEvent:Connect(function(plrName, yesorno)
	if yesorno == "no" then
		local obj = game.Workspace:FindFirstChild(plrName .. "trialTukTuk")
		if obj then obj:Destroy() end
	else
		local owns = false
		local success, result = pcall(function()
			return MarketplaceService:UserOwnsGamePassAsync(game.Players:FindFirstChild(plrName).UserId, 1225579876)
		end)
		owns = success and result
		if not owns then
			local obj = game.Workspace:FindFirstChild(plrName .. "trialTukTuk")
			if obj then obj:Destroy() end
		end
	end
end)

Something is probably missing, but you were smart enough to code this in the first place so you can fix it…


It still outputs the same thing unfortunately.

You should save only one single key-value pairs for each player.

Here is an exemple:

local datatable = {
    Currencies = {
        Coins = 0,
        Gems = 0,
    },
    Tier1Plot = {
        Something = false,
        Somethingelse = true,
    },
    Tier2Plot = {
        Something = false,
        Somethingelse = true,
    },
}

Datastore:SetAsync(Player.UserId, datatable)

I am very unfamiliar with datastores so I wouldn’t be able to implement this myself.

I think it’s worth removing the Autosave you have going on. And only save when the player leaves.

Instead of writing (“saving”) every minute, we now collect all of a player’s stats, flags, and purchased plot items into one single data table and only push it to Roblox’s cloud when that player actually leaves the game. This means we avoid repeatedly hammering the database while they’re playing—everything just lives in memory until they disconnect. The trade‐off is that, if the server crashes or the player’s connection drops unexpectedly, any progress since their last join won’t be saved; but in normal play, all of their data gets saved one time at the end, which drastically cuts down on background database requests.

Like this (its not fully copy and pasteable. read it first)

local DataStoreService    = game:GetService("DataStoreService")
local MarketplaceService  = game:GetService("MarketplaceService")
local Players             = game:GetService("Players")

local playerDataStore     = DataStoreService:GetDataStore("PlayerData_V36")
local rupeesStore         = DataStoreService:GetOrderedDataStore("RupeesLeaderboard")
local callsStore          = DataStoreService:GetOrderedDataStore("CallsLeaderboard")
local callCentersStore    = DataStoreService:GetOrderedDataStore("CallCentersLeaderboard")

local assignedPlots       = {}
local tier2AssignedPlots  = {}
local tier3AssignedPlots  = {}
local tier4AssignedPlots  = {}
local VIP_GAMEPASS_ID     = 1226680892

local freeUnlockMap = {
    unlockRoomPart     = "baljeetRoomDoor",
    unlockRoom2Part    = "office1Door",
    unlockRoom3Part    = "office2Door",
    unlock2ndFloorPart = "2ndFloorDoor",
    unlock3rdFloorPart = "3rdFloorDoor"
}

local tier2FreeUnlockMap = {
    unlockRoomPart  = "RoomDoor",
    frontDoorPart   = "frontDoorModel"
}

Players.PlayerAdded:Connect(function(plr)
    -- 1) Create Instances (leaderstats, BoolValues, StringValues)
    -- (Exact same as before, omitted here for brevity)
    local leaderstats         = Instance.new("Folder", plr); leaderstats.Name = "leaderstats"
    local Rupees              = Instance.new("NumberValue", leaderstats); Rupees.Name = "Rupees"
    local Calls               = Instance.new("NumberValue", leaderstats); Calls.Name = "Calls"
    local CallCenters         = Instance.new("NumberValue", leaderstats); CallCenters.Name = "Call Centers"

    local completedIntro      = Instance.new("BoolValue", plr); completedIntro.Name      = "completedIntro"
    local tier2Unlocked       = Instance.new("BoolValue", plr); tier2Unlocked.Name       = "tier2Unlocked"
    local tier3Unlocked       = Instance.new("BoolValue", plr); tier3Unlocked.Name       = "tier3Unlocked"
    local tier4Unlocked       = Instance.new("BoolValue", plr); tier4Unlocked.Name       = "tier4Unlocked"
    local trialTukTukActivated  = Instance.new("BoolValue", plr); trialTukTukActivated.Name  = "trialTukTukActivated"
    local trialTukTukActivated2 = Instance.new("BoolValue", plr); trialTukTukActivated2.Name = "trialTukTukActivated2"
    local trialTukTukActivated3 = Instance.new("BoolValue", plr); trialTukTukActivated3.Name = "trialTukTukActivated3"

    local plotAssigned        = Instance.new("StringValue", plr); plotAssigned.Name      = "plotAssigned"
    local tier2PlotAssigned   = Instance.new("StringValue", plr); tier2PlotAssigned.Name = "tier2PlotAssigned"
    local tier3PlotAssigned   = Instance.new("StringValue", plr); tier3PlotAssigned.Name = "tier3PlotAssigned"
    local tier4PlotAssigned   = Instance.new("StringValue", plr); tier4PlotAssigned.Name = "tier4PlotAssigned"

    -- 2) Build or load the master data table
    local function makeEmptyPlayerData()
        return {
            Currencies = { Rupees = 0, Calls = 0, CallCenters = 0 },
            Flags = {
                completedIntro        = false,
                tier2Unlocked         = false,
                tier3Unlocked         = false,
                tier4Unlocked         = false,
                trialTukTukActivated  = false,
                trialTukTukActivated2 = false,
                trialTukTukActivated3 = false,
            },
            Plots = { Tier1 = {}, Tier2 = {}, Tier3 = {}, Tier4 = {} }
        }
    end

    local playerData = makeEmptyPlayerData()
    local success, savedData = pcall(function()
        return playerDataStore:GetAsync(plr.UserId)
    end)
    if success and savedData then
        -- Merge savedData into playerData (with defaults)
        playerData.Currencies.Rupees      = savedData.Currencies.Rupees      or 0
        playerData.Currencies.Calls       = savedData.Currencies.Calls       or 0
        playerData.Currencies.CallCenters = savedData.Currencies.CallCenters or 0

        playerData.Flags.completedIntro        = savedData.Flags.completedIntro        or false
        playerData.Flags.tier2Unlocked         = savedData.Flags.tier2Unlocked         or false
        playerData.Flags.tier3Unlocked         = savedData.Flags.tier3Unlocked         or false
        playerData.Flags.tier4Unlocked         = savedData.Flags.tier4Unlocked         or false
        playerData.Flags.trialTukTukActivated  = savedData.Flags.trialTukTukActivated  or false
        playerData.Flags.trialTukTukActivated2 = savedData.Flags.trialTukTukActivated2 or false
        playerData.Flags.trialTukTukActivated3 = savedData.Flags.trialTukTukActivated3 or false

        playerData.Plots.Tier1 = savedData.Plots.Tier1 or {}
        playerData.Plots.Tier2 = savedData.Plots.Tier2 or {}
        playerData.Plots.Tier3 = savedData.Plots.Tier3 or {}
        playerData.Plots.Tier4 = savedData.Plots.Tier4 or {}
    end

    -- 3) Assign instance values from playerData
    Rupees.Value      = playerData.Currencies.Rupees
    Calls.Value       = playerData.Currencies.Calls
    CallCenters.Value = playerData.Currencies.CallCenters

    completedIntro.Value        = playerData.Flags.completedIntro
    tier2Unlocked.Value         = playerData.Flags.tier2Unlocked
    tier3Unlocked.Value         = playerData.Flags.tier3Unlocked
    tier4Unlocked.Value         = playerData.Flags.tier4Unlocked
    trialTukTukActivated.Value  = playerData.Flags.trialTukTukActivated
    trialTukTukActivated2.Value = playerData.Flags.trialTukTukActivated2
    trialTukTukActivated3.Value = playerData.Flags.trialTukTukActivated3

    -- 4) Assign plots (exactly as before)
    for i = 1, 5 do
        if not assignedPlots[i] then
            assignedPlots[i] = plr
            local pname = "plot" .. i
            plotAssigned.Value = pname
            local plotPart = workspace:FindFirstChild(pname)
            if plotPart and plotPart:FindFirstChild("plotOwnerPart") then
                plotPart.plotOwnerPart.BillboardGui.TextLabel.Text = plr.Name .. "'s Call Center"
            end
            break
        end
    end

    for i = 1, 5 do
        if not tier2AssignedPlots[i] then
            tier2AssignedPlots[i] = plr
            tier2PlotAssigned.Value = "tier2Plot" .. i
            break
        end
    end

    for i = 1, 5 do
        if not tier3AssignedPlots[i] then
            tier3AssignedPlots[i] = plr
            tier3PlotAssigned.Value = "tier3Plot" .. i
            break
        end
    end

    for i = 1, 5 do
        if not tier4AssignedPlots[i] then
            tier4AssignedPlots[i] = plr
            tier4PlotAssigned.Value = "tier4Plot" .. i
            break
        end
    end

    -- Load Tier1 objects from playerData.Plots.Tier1
    do
        local plotName = plotAssigned.Value
        local srcFolder = game.ReplicatedStorage:FindFirstChild(plotName)
        local destFolder = workspace:FindFirstChild(plotName)
        if srcFolder and destFolder then
            for _, modelName in ipairs(playerData.Plots.Tier1) do
                local orig = srcFolder:FindFirstChild(modelName)
                if orig then
                    local clone = orig:Clone()
                    clone.Parent = destFolder
                end
            end
            -- (Any door/unlock logic here…)
        end
    end

    -- Load Tier2 objects
    do
        local plotName = tier2PlotAssigned.Value
        local srcFolder = game.ReplicatedStorage:FindFirstChild(plotName)
        local destFolder = workspace:FindFirstChild(plotName)
        if srcFolder and destFolder then
            for _, modelName in ipairs(playerData.Plots.Tier2) do
                local orig = srcFolder:FindFirstChild(modelName)
                if orig then
                    local clone = orig:Clone()
                    clone.Parent = destFolder
                end
            end
        end
    end

    -- Load Tier3 objects
    do
        local plotName = tier3PlotAssigned.Value
        local srcFolder = game.ReplicatedStorage:FindFirstChild(plotName)
        local destFolder = workspace:FindFirstChild(plotName)
        if srcFolder and destFolder then
            for _, modelName in ipairs(playerData.Plots.Tier3) do
                local orig = srcFolder:FindFirstChild(modelName)
                if orig then
                    local clone = orig:Clone()
                    clone.Parent = destFolder
                end
            end
        end
    end

    -- Load Tier4 objects
    do
        local plotName = tier4PlotAssigned.Value
        local srcFolder = game.ReplicatedStorage:FindFirstChild(plotName)
        local destFolder = workspace:FindFirstChild(plotName)
        if srcFolder and destFolder then
            for _, modelName in ipairs(playerData.Plots.Tier4) do
                local orig = srcFolder:FindFirstChild(modelName)
                if orig then
                    local clone = orig:Clone()
                    clone.Parent = destFolder
                end
            end
        end
    end

    -- 5) Track changes to any NumberValue or BoolValue; mark data dirty
    local function markDirty()
        playerData.Currencies.Rupees      = Rupees.Value
        playerData.Currencies.Calls       = Calls.Value
        playerData.Currencies.CallCenters = CallCenters.Value

        playerData.Flags.completedIntro        = completedIntro.Value
        playerData.Flags.tier2Unlocked         = tier2Unlocked.Value
        playerData.Flags.tier3Unlocked         = tier3Unlocked.Value
        playerData.Flags.tier4Unlocked         = tier4Unlocked.Value
        playerData.Flags.trialTukTukActivated  = trialTukTukActivated.Value
        playerData.Flags.trialTukTukActivated2 = trialTukTukActivated2.Value
        playerData.Flags.trialTukTukActivated3 = trialTukTukActivated3.Value
        -- (We’ll save Plots only on leave, not here)
    end

    Rupees.Changed:Connect(markDirty)
    Calls.Changed:Connect(markDirty)
    CallCenters.Changed:Connect(markDirty)
    completedIntro.Changed:Connect(markDirty)
    tier2Unlocked.Changed:Connect(markDirty)
    tier3Unlocked.Changed:Connect(markDirty)
    tier4Unlocked.Changed:Connect(markDirty)
    trialTukTukActivated.Changed:Connect(markDirty)
    trialTukTukActivated2.Changed:Connect(markDirty)
    trialTukTukActivated3.Changed:Connect(markDirty)

    -- 6) Leaderboards: only UpdateAsync when a value actually changes
    local lastRupees, lastCalls, lastCentersVal = Rupees.Value, Calls.Value, CallCenters.Value
   --[[
    Rupees.Changed:Connect(function(newVal)
        if newVal ~= lastRupees then
            lastRupees = newVal
            spawn(function()
                pcall(function()
                    rupeesStore:UpdateAsync(tostring(plr.UserId), function() return newVal end)
                end)
            end)
        end
    end)

    Calls.Changed:Connect(function(newVal)
        if newVal ~= lastCalls then
            lastCalls = newVal
            spawn(function()
                pcall(function()
                    callsStore:UpdateAsync(tostring(plr.UserId), function() return newVal end)
                end)
            end)
        end
    end)

    CallCenters.Changed:Connect(function(newVal)
        if newVal ~= lastCentersVal then
            lastCentersVal = newVal
            spawn(function()
                pcall(function()
                    callCentersStore:UpdateAsync(tostring(plr.UserId), function() return newVal end)
                end)
            end)
        end
    end)
 ]]
    -- 7) No periodic autosave loop—only save on PlayerRemoving now
    Players.PlayerRemoving:Connect(function(remPlr)
        if remPlr ~= plr then return end

        -- (a) One final write of the main table (currencies, flags, plots)
        -- Rebuild the “Plots” sub‐table just before saving:
        do
            -- Tier1:
            local key = plotAssigned.Value
            local wsPlot = workspace:FindFirstChild(key)
            local rsPlot = game.ReplicatedStorage:FindFirstChild(key)
            playerData.Plots.Tier1 = {}
            if wsPlot then
                for _, v in ipairs(wsPlot:GetChildren()) do
                    if v:FindFirstChild("buyable") then
                        table.insert(playerData.Plots.Tier1, v.Name)
                    end
                end
            end
            if rsPlot then
                for _, doorName in pairs(freeUnlockMap) do
                    if rsPlot:FindFirstChild(doorName) then
                        table.insert(playerData.Plots.Tier1, doorName)
                    end
                end
            end
        end

        do
            -- Tier2:
            local key = tier2PlotAssigned.Value
            local wsPlot = workspace:FindFirstChild(key)
            local rsPlot = game.ReplicatedStorage:FindFirstChild(key)
            playerData.Plots.Tier2 = {}
            if wsPlot then
                for _, v in ipairs(wsPlot:GetChildren()) do
                    if v:FindFirstChild("buyable") then
                        table.insert(playerData.Plots.Tier2, v.Name)
                    end
                end
            end
            if rsPlot then
                for _, doorName in pairs(tier2FreeUnlockMap) do
                    if rsPlot:FindFirstChild(doorName) then
                        table.insert(playerData.Plots.Tier2, doorName)
                    end
                end
            end
        end

        do
            -- Tier3:
            local key = tier3PlotAssigned.Value
            local wsPlot = workspace:FindFirstChild(key)
            playerData.Plots.Tier3 = {}
            if wsPlot then
                for _, v in ipairs(wsPlot:GetChildren()) do
                    if v:FindFirstChild("buyable") then
                        table.insert(playerData.Plots.Tier3, v.Name)
                    end
                end
            end
        end

        do
            -- Tier4:
            local key = tier4PlotAssigned.Value
            local wsPlot = workspace:FindFirstChild(key)
            playerData.Plots.Tier4 = {}
            if wsPlot then
                for _, v in ipairs(wsPlot:GetChildren()) do
                    if v:FindFirstChild("buyable") then
                        table.insert(playerData.Plots.Tier4, v.Name)
                    end
                end
            end
        end

        -- Now write the full table once:
        pcall(function()
            playerDataStore:SetAsync(plr.UserId, playerData)
        end)

        -- (b) One final leaderboard update (only if different from “last…”)
        if Rupees.Value ~= lastRupees then
            pcall(function()
                rupeesStore:UpdateAsync(tostring(plr.UserId), function() return Rupees.Value end)
            end)
        end
        wait(0.1)
        if Calls.Value ~= lastCalls then
            pcall(function()
                callsStore:UpdateAsync(tostring(plr.UserId), function() return Calls.Value end)
            end)
        end
        wait(0.1)
        if CallCenters.Value ~= lastCentersVal then
            pcall(function()
                callCentersStore:UpdateAsync(tostring(plr.UserId), function() return CallCenters.Value end)
            end)
        end

        -- (c) Clean up any TukTuks/Bikes/etc.
        for _, v in pairs(workspace:GetChildren()) do
            if v.Name == plr.Name.."TukTuk"
            or v.Name == plr.Name.."Bike"
            or v.Name == plr.Name.."trialTukTuk" then
                v:Destroy()
            end
        end
    end)
end)

-- (Rest of your event handlers: chat teleport, CharacterAdded GUI, purchasedTier2/3/4, purchaseTukTukTrialEvent, etc. remain unchanged.)

Hi thanks for your response, unfortunately it’s the same output.

i’m actually dealing with the same issue, except my datastore code is definitely a lot less heavy (i think)
image

i only get this error on saving data though, so whenever a player leaves, etc.

local dStoreService = game:GetService("DataStoreService")
local rStorage = game:GetService("ReplicatedStorage")
local sStorage = game:GetService("ServerStorage")
local players = game:GetService("Players")

-- Datastores;
local playerDatastore = dStoreService:GetDataStore("playerData_Debug")

-- Path to events;
local bindableEvents = sStorage:WaitForChild("BindableEvents")

-- Events;
local updateData = bindableEvents:WaitForChild("UpdateData")
local applyClassEffects = bindableEvents:WaitForChild("ApplyClassEffects")

-- Path to functions;
local remoteFunctions = rStorage:WaitForChild("Functions")
local remoteFunctionsFromClient = remoteFunctions:WaitForChild("FromClient")
local functionalityFunctions = remoteFunctionsFromClient:WaitForChild("Functionality")

local bindableFunctions = sStorage:WaitForChild("BindableFunctions")

-- Remote functions;
local playerDataRequest = functionalityFunctions:WaitForChild("RequestData")
local getPlayerData = bindableFunctions:WaitForChild("GetPlayerData")

-- Path to modules;
local modulesFolder = rStorage:WaitForChild("Modules")
local weaponModules = modulesFolder:WaitForChild("WeaponModules")

-- Modules;
local weaponMasteriesModule = require(weaponModules:WaitForChild("WeaponMasteries"))

-- Tables;
local serverPlayerData = {}
local playerRequestTimes = {}

-- Values;
local requestCooldown = 0.075

-- Helper functions;
local function DeepCopy(original: Instance)
	if type(original) ~= "table" then
		return original
	end

	local copy = {}
	for k, v in original do
		copy[k] = DeepCopy(v)
	end
	return copy
end

local function SetToDefaultData(player: Player)
	serverPlayerData[player.UserId] = {
		kills = 0,
		deaths = 0,
		totalXp = 0,
		
		level = 1,
		bonds = 0,
		voidstones = 0,
		xp = 0,
		class = "Survivor",
		traits = {},
		whisper = 0,
		title = "",
		
		weaponMasteries = DeepCopy(weaponMasteriesModule),
		gameMasteries = {},
		classMasteries = {},
		titlesOwned = {},
		clothesOwned = {},
		premiumClothesOwned = {},
		classesOwned = {},
		skinsOwned = {},
		
		settings = {
			Video = {
				[`Field of View`] = 90,
				[`Blood`] = true,
				[`Tracers`] = true
			},
			
			Interface = {
				[`Crosshair`] = true,
				[`Kill Rewards`] = true,
				[`Player Plates`] = true,
				['HUD'] = true
			},
			
			Gameplay = {
				[`Retro ADS`] = false,
			},
			
			Audio = {
				[`Player`] = 1,
				[`Enemy`] = 1,
				[`Weapon`] = 1,
				[`Vega`] = 1,
				['Tinnitus'] = true,
			},
			
			Keybinds = {
				['Use'] = 'E',
				['Parry/Reload'] = 'R',
				['Shove'] = 'Q',
				['Neurocore'] = 'T',
				['Ability'] = 'F',
				['Drop'] = 'G'
			},
		},
		
		clothes = {
			[`Tops`] = "StarterTop_Shirt",
			[`Bottoms`] = "StarterBottom_Pants"
		},
		
		skins = {}
	}
end

local function SetupPlayerInTracker(player: Player, result: any)
	serverPlayerData[player.UserId] = {
		-- total values, used for tracking
		kills = result.kills,
		deaths = result.deaths,
		totalXp = result.totalXp,
		
		-- current values
		level = result.level,
		bonds = result.bonds,
		voidstones = result.voidstones,
		xp = result.xp,
		class = result.class,
		traits = result.traits,
		whisper = result.whisper,
		title = result.title,
		
		-- ownership
		weaponMasteries = result.weaponMasteries, -- this includes progress, masteries completed, weapons completed, etc.
		gameMasteries = result.gameMasteries,
		classMasteries = result.classMasteries,
		titlesOwned = result.titlesOwned,
		clothesOwned = result.clothesOwned,
		premiumClothesOwned = result.premiumClothesOwned,
		classesOwned = result.classesOwned,
		skinsOwned = result.skinsOwned,
		
		-- settings etc.
		settings = result.settings,
		clothes = result.clothes,
		skins = result.skins
	}
end

-- Main functions;
local function OnDataRequest(player: Player, dataRequested: string)
	if typeof(dataRequested) ~= "string" then return end
	
	if playerRequestTimes[player.UserId] then
		while tick() - playerRequestTimes[player.UserId] < requestCooldown do
			task.wait()
		end
	end
	
	if dataRequested == "all" then
		return serverPlayerData[player.UserId]
	end
	
	playerRequestTimes[player.UserId] = tick()
	local data = serverPlayerData[player.UserId][dataRequested]
	
	return data
end

local function UpdateDataInTracker(player: Player, path: string, value: any, forceSet: boolean?)
	local playerData = serverPlayerData[player.UserId]
	
	print(`path is {path} and the value is {value}`)
	
	local isRemoval = false
	local isAppend = false
	local actualValue = value

	if typeof(value) == "string" then
		if value:sub(1, 7) == "REMOVE:" then
			isRemoval = true
			actualValue = value:sub(8)
		elseif value:sub(1, 7) == "APPEND:" then
			isAppend = true
			actualValue = value:sub(8)
		end
	end

	local keys = string.split(path, ".")
	local lastKey = table.remove(keys)

	local ref = playerData
	for _, key in keys do
		local numKey = tonumber(key)
		ref = ref[numKey or key]
		
		if ref == nil then
			return
		end
	end

	local numLastKey = tonumber(lastKey)
	local finalKey = numLastKey or lastKey

	if isAppend then
		if typeof(ref[finalKey]) == "table" then
			local t = ref[finalKey]
			local index = 1
			while t[index] ~= nil do
				index += 1
			end
			t[index] = actualValue
		end
	elseif isRemoval then
		if typeof(ref[finalKey]) == "table" then
			local t = ref[finalKey]
			for i, v in t do
				if v == actualValue then
					table.remove(t, i)
					break
				end
			end
		end
	elseif typeof(ref[finalKey]) == "number" and typeof(actualValue) == "number" then -- stuff like xp, increments by value
		if forceSet then
			ref[finalKey] = actualValue
		else
			ref[finalKey] += actualValue
		end
	else
		ref[finalKey] = actualValue -- stuff like class, directly changed
	end
end

local function OnPlayerAdded(player: Player)
	local success, result = pcall(function()
		return playerDatastore:GetAsync(player.UserId)
	end)
	
	if not success then
		warn(`Failed to fetch {player.Name}'s data`)
		print(`Error log: {result}`)
		player:Kick(`The server failed to fetch your data, rejoin the game. If this keeps happening, please report it in the discord server.`)
		return
	end
	
	if result then
		SetupPlayerInTracker(player, result)
	else
		SetToDefaultData(player)
	end
	
	applyClassEffects:Fire(player, result.class)
end

local function SaveData()
	for userId, data in pairs(serverPlayerData) do
		local success, result = pcall(function()
			local key = tostring(userId)
			
			playerDatastore:UpdateAsync(key, function()
				local newData = {
					kills = data.kills,
					deaths = data.deaths,
					totalXp = data.totalXp,

					level = data.level,
					bonds = data.bonds,
					voidstones = data.voidstones,
					xp = data.xp,
					class = data.class,
					traits = data.traits,
					whisper = data.whisper,
					title = data.title,

					weaponMasteries = data.weaponMasteries,
					titlesOwned = data.titlesOwned,
					clothesOwned = data.clothesOwned,
					premiumClothesOwned = data.premiumClothesOwned,
					classesOwned = data.classesOwned,
					skinsOwned = data.skinsOwned,

					settings = data.settings,
					clothes = data.clothes
				}
				
				return newData
			end)
		end)
		
		if not success then
			warn(`Failed to save {userId}'s data`)
			print(`Error information: {result}`)
			continue
		end
		
		print(`Data for {userId} saved`)
		print(serverPlayerData[userId])
	end
end

local function OnPlayerRemoving(player: Player)
	SaveData()	
	serverPlayerData[player.UserId] = nil
end

local function SaveInIntervals()
	while true do
		local interval = math.random(60, 300)
		task.wait(interval)
		
		SaveData()
	end
end

local function Runtime()
	players.PlayerAdded:Connect(OnPlayerAdded)
	players.PlayerRemoving:Connect(OnPlayerRemoving)
	
	playerDataRequest.OnServerInvoke = OnDataRequest
	getPlayerData.OnInvoke = OnDataRequest
	updateData.Event:Connect(UpdateDataInTracker)
	
	game:BindToClose(SaveData)
	task.spawn(SaveInIntervals)
end

-- Runtime;
Runtime()

Bro damn :sob:

There isn’t anything else calling datastores are there?

Yeah there is, a few global leaderboards placed around the map.

local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local rupeeStore = DataStoreService:GetOrderedDataStore("RupeesLeaderboard")

local layoutTemplate = script.Parent:WaitForChild("Layout")
layoutTemplate.Visible = false

local LEADERBOARD_SIZE = 9
local UPDATE_INTERVAL = 300

local function clearOldEntries()
	for _, child in ipairs(script.Parent:GetChildren()) do
		if child:IsA("Frame") and child.Name:sub(1,6) == "Layout" and child ~= layoutTemplate then
			child:Destroy()
		end
	end
end

local function updateLeaderboard()
	local success, pages = pcall(function()
		return rupeeStore:GetSortedAsync(false, LEADERBOARD_SIZE)
	end)

	if not success then
		warn("Failed to get leaderboard data")
		return
	end

	local topEntries = pages:GetCurrentPage()
	clearOldEntries()

	for rank, entry in ipairs(topEntries) do
		local userId = tonumber(entry.key)
		local rupeesValue = entry.value
		local playerName = "[Unknown]"

		pcall(function()
			playerName = Players:GetNameFromUserIdAsync(userId)
		end)

		local newLayout = layoutTemplate:Clone()
		newLayout.Visible = true
		newLayout.Parent = script.Parent
		newLayout.Name = "Layout" .. rank

		local positionLabel = newLayout:FindFirstChild("positionLabel")
		local usernameLabel = newLayout:FindFirstChild("usernameLabel")
		local amountLabel = newLayout:FindFirstChild("amount")

		if positionLabel then positionLabel.Text = tostring(rank) .. "." end
		if usernameLabel then usernameLabel.Text = playerName end
		if amountLabel then amountLabel.Text = "₹" .. tostring(rupeesValue) end
	end
end

task.spawn(function()
	while true do
		updateLeaderboard()
		wait(UPDATE_INTERVAL)
	end
end)

OKAY, I think. THINK. This might be it. I’ve broken everything down to datastore bones. Just play it in a separate script located in the same place. Lmk how it does. (If you are in teamplay, make sure to “submit” the scripts, or whatever it was.

local DataStoreService = game:GetService("DataStoreService")
local MarketplaceService = game:GetService("MarketplaceService")
local Players = game:GetService("Players")

local playerDataStore = DataStoreService:GetDataStore("PlayerData_V36_FORUMTEST")
local sessionData = {}

local assignedPlots = {}
local tier2AssignedPlots = {}
local tier3AssignedPlots = {}
local tier4AssignedPlots = {}
local VIP_GAMEPASS_ID = 1226680892

local freeUnlockMap = {
    unlockRoomPart     = "baljeetRoomDoor",
    unlockRoom2Part    = "office1Door",
    unlockRoom3Part    = "office2Door",
    unlock2ndFloorPart = "2ndFloorDoor",
    unlock3rdFloorPart = "3rdFloorDoor"
}

local tier2FreeUnlockMap = {
    unlockRoomPart = "RoomDoor",
    frontDoorPart  = "frontDoorModel"
}

local function makeEmptyData()
    return {
        Currencies = { Rupees = 0, Calls = 0, CallCenters = 0 },
        Flags = {
            completedIntro        = false,
            tier2Unlocked         = false,
            tier3Unlocked         = false,
            tier4Unlocked         = false,
            trialTukTukActivated  = false,
            trialTukTukActivated2 = false,
            trialTukTukActivated3 = false
        },
        Plots = { Tier1 = {}, Tier2 = {}, Tier3 = {}, Tier4 = {} }
    }
end

Players.PlayerAdded:Connect(function(plr)
    local data
    local success, saved = pcall(function() return playerDataStore:GetAsync(plr.UserId) end)
    if success and saved then
        data = saved
    else
        data = makeEmptyData()
    end
    sessionData[plr.UserId] = data

    local leaderstats = Instance.new("Folder", plr)
    leaderstats.Name = "leaderstats"
    local Rupees = Instance.new("NumberValue", leaderstats)
    Rupees.Name = "Rupees"
    Rupees.Value = data.Currencies.Rupees
    local Calls = Instance.new("NumberValue", leaderstats)
    Calls.Name = "Calls"
    Calls.Value = data.Currencies.Calls
    local CallCenters = Instance.new("NumberValue", leaderstats)
    CallCenters.Name = "Call Centers"
    CallCenters.Value = data.Currencies.CallCenters

    local completedIntro = Instance.new("BoolValue", plr)
    completedIntro.Name = "completedIntro"
    completedIntro.Value = data.Flags.completedIntro
    local tier2Unlocked = Instance.new("BoolValue", plr)
    tier2Unlocked.Name = "tier2Unlocked"
    tier2Unlocked.Value = data.Flags.tier2Unlocked
    local tier3Unlocked = Instance.new("BoolValue", plr)
    tier3Unlocked.Name = "tier3Unlocked"
    tier3Unlocked.Value = data.Flags.tier3Unlocked
    local tier4Unlocked = Instance.new("BoolValue", plr)
    tier4Unlocked.Name = "tier4Unlocked"
    tier4Unlocked.Value = data.Flags.tier4Unlocked
    local trialTukTukActivated = Instance.new("BoolValue", plr)
    trialTukTukActivated.Name = "trialTukTukActivated"
    trialTukTukActivated.Value = data.Flags.trialTukTukActivated
    local trialTukTukActivated2 = Instance.new("BoolValue", plr)
    trialTukTukActivated2.Name = "trialTukTukActivated2"
    trialTukTukActivated2.Value = data.Flags.trialTukTukActivated2
    local trialTukTukActivated3 = Instance.new("BoolValue", plr)
    trialTukTukActivated3.Name = "trialTukTukActivated3"
    trialTukTukActivated3.Value = data.Flags.trialTukTukActivated3

    local plotAssigned = Instance.new("StringValue", plr)
    plotAssigned.Name = "plotAssigned"
    local tier2PlotAssigned = Instance.new("StringValue", plr)
    tier2PlotAssigned.Name = "tier2PlotAssigned"
    local tier3PlotAssigned = Instance.new("StringValue", plr)
    tier3PlotAssigned.Name = "tier3PlotAssigned"
    local tier4PlotAssigned = Instance.new("StringValue", plr)
    tier4PlotAssigned.Name = "tier4PlotAssigned"

    local function loadTier(savedList, plotName, map)
        local src = game.ReplicatedStorage:FindFirstChild(plotName)
        local dest = workspace:FindFirstChild(plotName)
        if not savedList or not src or not dest then return end
        for _, name in ipairs(savedList) do
            local orig = src:FindFirstChild(name)
            if orig then
                local clone = orig:Clone()
                clone.Parent = dest
            end
        end
        for _, part in ipairs(dest:GetDescendants()) do
            if part:IsA("BasePart") and part.Name == "BuyPart" then
                local modelNameValue = part:FindFirstChild("modelName")
                if modelNameValue and table.find(savedList, modelNameValue.Value) then
                    part.Parent = game.ReplicatedStorage:FindFirstChild(plotName)
                end
            end
        end
        if map then
            for _, doorName in pairs(map) do
                if dest:FindFirstChild(doorName) and table.find(savedList, doorName) then
                    dest[doorName].Parent = src
                end
            end
        end
    end

    for i = 1, 5 do
        if not assignedPlots[i] then
            assignedPlots[i] = plr
            local name = "plot" .. i
            plotAssigned.Value = name
            local plotPart = workspace:FindFirstChild(name)
            if plotPart and plotPart:FindFirstChild("plotOwnerPart") then
                plotPart.plotOwnerPart.BillboardGui.TextLabel.Text = plr.Name .. "'s Call Center"
            end
            break
        end
    end

    for i = 1, 5 do
        if not tier2AssignedPlots[i] then
            tier2AssignedPlots[i] = plr
            tier2PlotAssigned.Value = "tier2Plot" .. i
            break
        end
    end

    for i = 1, 5 do
        if not tier3AssignedPlots[i] then
            tier3AssignedPlots[i] = plr
            tier3PlotAssigned.Value = "tier3Plot" .. i
            break
        end
    end

    for i = 1, 5 do
        if not tier4AssignedPlots[i] then
            tier4AssignedPlots[i] = plr
            tier4PlotAssigned.Value = "tier4Plot" .. i
            break
        end
    end

    loadTier(data.Plots.Tier1, plotAssigned.Value, freeUnlockMap)
    loadTier(data.Plots.Tier2, tier2PlotAssigned.Value, tier2FreeUnlockMap)
    loadTier(data.Plots.Tier3, tier3PlotAssigned.Value, nil)
    loadTier(data.Plots.Tier4, tier4PlotAssigned.Value, nil)

    Rupees.Changed:Connect(function(val) sessionData[plr.UserId].Currencies.Rupees = val end)
    Calls.Changed:Connect(function(val) sessionData[plr.UserId].Currencies.Calls = val end)
    CallCenters.Changed:Connect(function(val) sessionData[plr.UserId].Currencies.CallCenters = val end)
    completedIntro.Changed:Connect(function(val) sessionData[plr.UserId].Flags.completedIntro = val end)
    tier2Unlocked.Changed:Connect(function(val) sessionData[plr.UserId].Flags.tier2Unlocked = val end)
    tier3Unlocked.Changed:Connect(function(val) sessionData[plr.UserId].Flags.tier3Unlocked = val end)
    tier4Unlocked.Changed:Connect(function(val) sessionData[plr.UserId].Flags.tier4Unlocked = val end)
    trialTukTukActivated.Changed:Connect(function(val) sessionData[plr.UserId].Flags.trialTukTukActivated = val end)
    trialTukTukActivated2.Changed:Connect(function(val) sessionData[plr.UserId].Flags.trialTukTukActivated2 = val end)
    trialTukTukActivated3.Changed:Connect(function(val) sessionData[plr.UserId].Flags.trialTukTukActivated3 = val end)

    game.ReplicatedStorage.callComplete.OnServerEvent:Connect(function(player)
        player.leaderstats.Calls.Value += 1
        player.leaderstats.Rupees.Value += 10
    end)

    game.ReplicatedStorage.purchasedTier2.OnServerEvent:Connect(function(player)
        player.tier2Unlocked.Value = true
        player.leaderstats["Call Centers"].Value += 1
        sessionData[player.UserId].Currencies.CallCenters = player.leaderstats["Call Centers"].Value
        local clone = game.ReplicatedStorage:FindFirstChild(player.plotAssigned.Value .. "TukTuk")
        clone.Parent = game.Workspace
        clone.Name = player.Name .. "trialTukTuk"
        clone.plrName.Value = player.Name
        local part = game.Workspace:FindFirstChild(player.tier2PlotAssigned.Value)
        if part and part:FindFirstChild("plotOwnerPart") then
            part.plotOwnerPart.BillboardGui.TextLabel.Text = player.Name .. "'s Call Center"
        end
    end)

    game.ReplicatedStorage.purchasedTier3.OnServerEvent:Connect(function(player)
        player.tier3Unlocked.Value = true
        player.leaderstats["Call Centers"].Value += 1
        sessionData[player.UserId].Currencies.CallCenters = player.leaderstats["Call Centers"].Value
        local part = game.Workspace:FindFirstChild(player.tier3PlotAssigned.Value)
        if part and part:FindFirstChild("plotOwnerPart") then
            part.plotOwnerPart.BillboardGui.TextLabel.Text = player.Name .. "'s Call Center"
        end
        if not game.Workspace:FindFirstChild(player.Name .. "trialTukTuk") then
            local clone = game.ReplicatedStorage:FindFirstChild(player.tier2PlotAssigned.Value .. "TukTuk")
            clone.Parent = game.Workspace
            clone.Name = player.Name .. "trialTukTuk"
            clone.plrName.Value = player.Name
        end
    end)

    game.ReplicatedStorage.purchasedTier4.OnServerEvent:Connect(function(player)
        player.tier4Unlocked.Value = true
        player.leaderstats["Call Centers"].Value += 1
        sessionData[player.UserId].Currencies.CallCenters = player.leaderstats["Call Centers"].Value
        local part = game.Workspace:FindFirstChild(player.tier4PlotAssigned.Value)
        if part and part:FindFirstChild("plotOwnerPart") then
            part.plotOwnerPart.BillboardGui.TextLabel.Text = player.Name .. "'s Call Center"
        end
        if not game.Workspace:FindFirstChild(player.Name .. "trialTukTuk") then
            local clone = game.ReplicatedStorage:FindFirstChild(player.tier3PlotAssigned.Value .. "TukTuk")
            clone.Parent = game.Workspace
            clone.Name = player.Name .. "trialTukTuk"
            clone.plrName.Value = player.Name
        end
    end)

    plr.Chatted:Connect(function(msg)
        if plr.Name == "drilinz" or plr.Name == "makanaqi" then
            local split = string.split(msg, " ")
            if split[1] == ":to" then
                local target = Players:FindFirstChild(split[2])
                if target and target.Character and plr.Character then
                    plr.Character.HumanoidRootPart.CFrame = target.Character.HumanoidRootPart.CFrame
                end
            elseif split[1] == ":bring" then
                local target = Players:FindFirstChild(split[2])
                if target and target.Character and plr.Character then
                    target.Character.HumanoidRootPart.CFrame = plr.Character.HumanoidRootPart.CFrame
                end
            end
        end
    end)

    plr.CharacterAdded:Connect(function(char)
        local humanoid = char:WaitForChild("Humanoid")
        humanoid.UseJumpPower = true
        humanoid.JumpPower = 35
        local usernameClone = game.ReplicatedStorage.usernameGUI:Clone()
        usernameClone.Parent = char.Head
        usernameClone.TextLabel.Text = plr.Name
        local successPass, ownsPass = pcall(function()
            return MarketplaceService:UserOwnsGamePassAsync(plr.UserId, VIP_GAMEPASS_ID)
        end)
        if successPass and ownsPass then
            local vipClone = game.ReplicatedStorage.vipGUI:Clone()
            vipClone.Parent = char.Head
        end
    end)

    local hasVIP = false
    local succPass, ownsPass = pcall(function()
        return MarketplaceService:UserOwnsGamePassAsync(plr.UserId, VIP_GAMEPASS_ID)
    end)
    if succPass and ownsPass then
        hasVIP = true
    end
    local vipValue = Instance.new("BoolValue", plr)
    vipValue.Name = "IsVIP"
    vipValue.Value = hasVIP
end)

local function PlayerLeaving(plr)
   local data = sessionData[plr.UserId]
    if not data then return end
    do
        local key = plr.plotAssigned.Value
        local wsPlot = workspace:FindFirstChild(key)
        local rsPlot = game.ReplicatedStorage:FindFirstChild(key)
        data.Plots.Tier1 = {}
        if wsPlot then
            for _, v in ipairs(wsPlot:GetChildren()) do
                if v:FindFirstChild("buyable") then
                    table.insert(data.Plots.Tier1, v.Name)
                end
            end
        end
        if rsPlot then
            for _, doorName in pairs(freeUnlockMap) do
                if rsPlot:FindFirstChild(doorName) then
                    table.insert(data.Plots.Tier1, doorName)
                end
            end
        end
    end
    do
        local key = plr.tier2PlotAssigned.Value
        local wsPlot = workspace:FindFirstChild(key)
        local rsPlot = game.ReplicatedStorage:FindFirstChild(key)
        data.Plots.Tier2 = {}
        if wsPlot then
            for _, v in ipairs(wsPlot:GetChildren()) do
                if v:FindFirstChild("buyable") then
                    table.insert(data.Plots.Tier2, v.Name)
                end
            end
        end
        if rsPlot then
            for _, doorName in pairs(tier2FreeUnlockMap) do
                if rsPlot:FindFirstChild(doorName) then
                    table.insert(data.Plots.Tier2, doorName)
                end
            end
        end
    end
    do
        local key = plr.tier3PlotAssigned.Value
        local wsPlot = workspace:FindFirstChild(key)
        data.Plots.Tier3 = {}
        if wsPlot then
            for _, v in ipairs(wsPlot:GetChildren()) do
                if v:FindFirstChild("buyable") then
                    table.insert(data.Plots.Tier3, v.Name)
                end
            end
        end
    end
    do
        local key = plr.tier4PlotAssigned.Value
        local wsPlot = workspace:FindFirstChild(key)
        data.Plots.Tier4 = {}
        if wsPlot then
            for _, v in ipairs(wsPlot:GetChildren()) do
                if v:FindFirstChild("buyable") then
                    table.insert(data.Plots.Tier4, v.Name)
                end
            end
        end
    end
    pcall(function()
        playerDataStore:SetAsync(plr.UserId, data)
    end)
    for _, v in pairs(workspace:GetChildren()) do
        if v.Name == plr.Name .. "TukTuk" or v.Name == plr.Name .. "Bike" or v.Name == plr.Name .. "trialTukTuk" then
            v:Destroy()
        end
    end
end

Players.PlayerRemoving:Connect(PlayerLeaving)
game:BindToClose(function()
    for _, plr in ipairs(Players:GetPlayers()) do
        PlayerLeaving(plr)
    end
end)

What do you mean sorry? The leaderboard datastores have to update in that same script in order for the scripts in the leaderboard to read the player’s data.

The main one, not the global leaderboards placed around the map. OR just insert the code like we’ve already been doing. I just use separate scripts just incase the new one is worse

Yeah, the main one should still save these:

local rupeesStore         = DataStoreService:GetOrderedDataStore("RupeesLeaderboard")
local callsStore          = DataStoreService:GetOrderedDataStore("CallsLeaderboard")
local callCentersStore    = DataStoreService:GetOrderedDataStore("CallCentersLeaderboard")

I want to test it without those for now

We’re sending so many requests it’s overloading everything. SO, I simply put everything into a single datatable, which is the only one being saved.

I just deleted all the global leaderboards except 1. It turns out it’s because there are multiple global leaderboards using the datastore.

The script in each leaderboard:

local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local rupeeStore = DataStoreService:GetOrderedDataStore("RupeesLeaderboard")

local layoutTemplate = script.Parent:WaitForChild("Layout")
layoutTemplate.Visible = false

local LEADERBOARD_SIZE = 9
local UPDATE_INTERVAL = 300

local function clearOldEntries()
	for _, child in ipairs(script.Parent:GetChildren()) do
		if child:IsA("Frame") and child.Name:sub(1,6) == "Layout" and child ~= layoutTemplate then
			child:Destroy()
		end
	end
end

local function updateLeaderboard()
	local success, pages = pcall(function()
		return rupeeStore:GetSortedAsync(false, LEADERBOARD_SIZE)
	end)

	if not success then
		warn("Failed to get leaderboard data")
		return
	end

	local topEntries = pages:GetCurrentPage()
	clearOldEntries()

	for rank, entry in ipairs(topEntries) do
		local userId = tonumber(entry.key)
		local rupeesValue = entry.value
		local playerName = "[Unknown]"

		pcall(function()
			playerName = Players:GetNameFromUserIdAsync(userId)
		end)

		local newLayout = layoutTemplate:Clone()
		newLayout.Visible = true
		newLayout.Parent = script.Parent
		newLayout.Name = "Layout" .. rank

		local positionLabel = newLayout:FindFirstChild("positionLabel")
		local usernameLabel = newLayout:FindFirstChild("usernameLabel")
		local amountLabel = newLayout:FindFirstChild("amount")

		if positionLabel then positionLabel.Text = tostring(rank) .. "." end
		if usernameLabel then usernameLabel.Text = playerName end
		if amountLabel then amountLabel.Text = "₹" .. tostring(rupeesValue) end
	end
end

task.spawn(function()
	while true do
		updateLeaderboard()
		wait(UPDATE_INTERVAL)
	end
end)

Usually leaderboards run off a single script in ServerService, this could be our issue but I have cooked up one final script with ChatGPT verifying it


Your original script fires off far too many individual DataStore calls—dozens of SetAsync, GetAsync, and leaderboard writes.

Although we refactored to batch core player data into one table and remove autosaving, the leaderboard updates still fire too often, leading to persistent throttling.

This is what we need to do.

  • Refactoring Strategy: Single Data Table per Player
  • Handling Leaderboards Efficiently
  • Remove the Per-Minute Leaderboard Loop
  • Monitoring Budgets and Handling Errors

Main Handler:

--[[
    MainDataManager.lua
    Place under ServerScriptService in a Script.
--]]
local DataStoreService   = game:GetService("DataStoreService")
local Players            = game:GetService("Players")
local playerDataStore    = DataStoreService:GetDataStore("PlayerData_V36")

-- In-memory cache
local sessionData = {}

-- 1) Helper to make a blank profile
local function makeEmptyDataTable()
    return {
        Currencies = { Rupees = 0, Calls = 0, CallCenters = 0 },
        Flags = {
            completedIntro        = false,
            tier2Unlocked         = false,
            tier3Unlocked         = false,
            tier4Unlocked         = false,
            trialTukTukActivated  = false,
            trialTukTukActivated2 = false,
            trialTukTukActivated3 = false
        },
        Plots = {
            Tier1 = {}, Tier2 = {}, Tier3 = {}, Tier4 = {}
        }
    }
end

-- 2) Load or initialize on player join
local function onPlayerAdded(plr)
    -- Create leaderstats folder:
    local leaderstats = Instance.new("Folder")
    leaderstats.Name = "leaderstats"
    leaderstats.Parent = plr

    -- Create NumberValues for leaderboards:
    local rupeesVal   = Instance.new("NumberValue", leaderstats); rupeesVal.Name = "Rupees"
    local callsVal    = Instance.new("NumberValue", leaderstats); callsVal.Name = "Calls"
    local centersVal  = Instance.new("NumberValue", leaderstats); centersVal.Name = "Call Centers"

    -- Create BoolValues for flags:
    local completedIntro        = Instance.new("BoolValue", plr); completedIntro.Name = "completedIntro"
    local tier2Unlocked         = Instance.new("BoolValue", plr); tier2Unlocked.Name = "tier2Unlocked"
    local tier3Unlocked         = Instance.new("BoolValue", plr); tier3Unlocked.Name = "tier3Unlocked"
    local tier4Unlocked         = Instance.new("BoolValue", plr); tier4Unlocked.Name = "tier4Unlocked"
    local trialTukTukActivated  = Instance.new("BoolValue", plr); trialTukTukActivated.Name = "trialTukTukActivated"
    local trialTukTukActivated2 = Instance.new("BoolValue", plr); trialTukTukActivated2.Name = "trialTukTukActivated2"
    local trialTukTukActivated3 = Instance.new("BoolValue", plr); trialTukTukActivated3.Name = "trialTukTukActivated3"

    -- Load from DataStore (single key):
    local success, storedData = pcall(function()
        return playerDataStore:GetAsync(plr.UserId)
    end)
    if success and type(storedData) == "table" then
        sessionData[plr.UserId] = storedData
    else
        sessionData[plr.UserId] = makeEmptyDataTable()
    end

    -- Populate in-game values from sessionData
    local data = sessionData[plr.UserId]
    rupeesVal.Value          = data.Currencies.Rupees
    callsVal.Value           = data.Currencies.Calls
    centersVal.Value         = data.Currencies.CallCenters
    completedIntro.Value     = data.Flags.completedIntro
    tier2Unlocked.Value      = data.Flags.tier2Unlocked
    tier3Unlocked.Value      = data.Flags.tier3Unlocked
    tier4Unlocked.Value      = data.Flags.tier4Unlocked
    trialTukTukActivated.Value  = data.Flags.trialTukTukActivated
    trialTukTukActivated2.Value = data.Flags.trialTukTukActivated2
    trialTukTukActivated3.Value = data.Flags.trialTukTukActivated3

    -- Plot assignment logic omitted for brevity; update data.Plots accordingly

    -- 3) Update sessionData on any in-game change (in memory only):
    rupeesVal.Changed:Connect(function(newVal)
        sessionData[plr.UserId].Currencies.Rupees = newVal
    end)
    callsVal.Changed:Connect(function(newVal)
        sessionData[plr.UserId].Currencies.Calls = newVal
    end)
    centersVal.Changed:Connect(function(newVal)
        sessionData[plr.UserId].Currencies.CallCenters = newVal
    end)
    completedIntro.Changed:Connect(function(b) 
        sessionData[plr.UserId].Flags.completedIntro = b 
    end)
    tier2Unlocked.Changed:Connect(function(b) 
        sessionData[plr.UserId].Flags.tier2Unlocked = b 
    end)
    tier3Unlocked.Changed:Connect(function(b) 
        sessionData[plr.UserId].Flags.tier3Unlocked = b 
    end)
    tier4Unlocked.Changed:Connect(function(b) 
        sessionData[plr.UserId].Flags.tier4Unlocked = b 
    end)
    trialTukTukActivated.Changed:Connect(function(b) 
        sessionData[plr.UserId].Flags.trialTukTukActivated = b 
    end)
    trialTukTukActivated2.Changed:Connect(function(b) 
        sessionData[plr.UserId].Flags.trialTukTukActivated2 = b 
    end)
    trialTukTukActivated3.Changed:Connect(function(b) 
        sessionData[plr.UserId].Flags.trialTukTukActivated3 = b 
    end)
    -- Note: You do NOT call any DataStore API here.

end

-- 4) Save once on player leaving
local function onPlayerRemoving(plr)
    local dataToSave = sessionData[plr.UserId]
    if dataToSave then
        local success, err = pcall(function()
            playerDataStore:SetAsync(plr.UserId, dataToSave)
        end)
        if not success then
            warn("Failed to save data for", plr.Name, ":", err)
            -- Optionally retry with backoff here
        end
        sessionData[plr.UserId] = nil
    end
end

Players.PlayerAdded:Connect(onPlayerAdded)
Players.PlayerRemoving:Connect(onPlayerRemoving)
game:BindToClose(function()
    -- Save all remaining players on server shutdown
    for _, plr in pairs(Players:GetPlayers()) do
        onPlayerRemoving(plr)
    end
end)

Leaderboard

--[[
    LeaderboardUpdater.lua
    Place under ServerScriptService in a separate Script.
--]]
local DataStoreService = game:GetService("DataStoreService")
local Players          = game:GetService("Players")

local rupeesStore      = DataStoreService:GetOrderedDataStore("RupeesLeaderboard")
local callsStore       = DataStoreService:GetOrderedDataStore("CallsLeaderboard")
local callCentersStore = DataStoreService:GetOrderedDataStore("CallCentersLeaderboard")

-- Debounce tables to prevent rapid UpdateAsync calls for a single change
local debounceRupees   = {}
local debounceCalls    = {}
local debounceCenters  = {}

-- Utility function for debouncing UpdateAsync
local function updateLeaderboard(key, store, newValue, debounceTable)
    if debounceTable[key] then return end
    debounceTable[key] = true

    -- Fire UpdateAsync in a coroutine to avoid blocking
    task.spawn(function()
        local success, err = pcall(function()
            store:UpdateAsync(key, function(old)
                return newValue
            end)
        end)
        if not success then
            warn("Leaderboard UpdateAsync error for key", key, ":", err)
            -- Optionally implement backoff retry here
        end
        -- Short delay before allowing next update for this key
        task.wait(1)  -- 1 second debounce; adjust as needed
        debounceTable[key] = false
    end)
end

-- Listen for whenever a player's leaderstats change
local function monitorPlayer(plr)
    local userKey = tostring(plr.UserId)

    local function onRupeesChange(newVal)
        updateLeaderboard(userKey, rupeesStore, newVal, debounceRupees)
    end
    local function onCallsChange(newVal)
        updateLeaderboard(userKey, callsStore, newVal, debounceCalls)
    end
    local function onCentersChange(newVal)
        updateLeaderboard(userKey, callCentersStore, newVal, debounceCenters)
    end

    local leaderstats = plr:WaitForChild("leaderstats", 10)
    if leaderstats then
        local rupeesVal  = leaderstats:WaitForChild("Rupees", 5)
        local callsVal   = leaderstats:WaitForChild("Calls", 5)
        local centersVal = leaderstats:WaitForChild("Call Centers", 5)

        rupeesVal.Changed:Connect(onRupeesChange)
        callsVal.Changed:Connect(onCallsChange)
        centersVal.Changed:Connect(onCentersChange)
    end
end

-- Hook PlayerAdded to start listening for that player’s stat changes
Players.PlayerAdded:Connect(function(plr)
    monitorPlayer(plr)
end)

MainDataManager.lua handles exactly one GetAsync per player on join and one SetAsync per player on leave, regardless of how many times the in-game values change. All intermediate mutations are kept in memory in sessionData.

LeaderboardUpdater.lua listens for changes to leaderstats.Rupees, leaderstats.Calls, and leaderstats[“Call Centers”]. Each time one of those NumberValues changes, it uses a short, per-player debounce to do exactly one UpdateAsync to the corresponding ordered DataStore. Because UpdateAsync only writes the new value, you avoid repeated write requests if the player’s value is changed multiple times in quick succession.

You can still run a separate GUI script that does a task.spawn(function() while true do … GetSortedAsync(false, 9) … wait(300) end end) to update the leaderboard frames in the world, but that is only one read every 5 minutes, well within budget.