I have another script that saves every 2 minutes, so I know that the save script does work. It just doesn't save when someone leaves or the game closes.
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local DS = game:GetService("DataStoreService"):GetDataStore("Data")
function save(player)
local data = DS:GetAsync(player.UserId)
data["tokens"] = player:FindFirstChild("Tok").Value
data["combatLogged"] = player:FindFirstChild("CombatLogged").Value
DS:SetAsync(player.UserId, data)
print("Data Saved!")
end
Players.PlayerRemoving:Connect(function(player)
wait(3)
save(player)
print("Saved "..player.Name.."'s data!")
end)
game:BindToClose(function()
wait(1)
for i, player in ipairs(Players:GetPlayers()) do
coroutine.wrap(save)(player)
print("Saved "..player.Name.."'s data!")
end
end)

2 comments
Remove the wait, I think that should help
The wait is so that the script doesn't instantly end, there is a max amount of time that the client is able to stay open when leaving the game and it is well under that.