My time saver script is not working

I created a script for countdown quests. I want the time in the north to be saved from the local script and I don’t know how to do it. Here is the local script.

local Players = game:GetService("Players")
local moduleSc = require(game.ReplicatedStorage.Abbreviate)
local player = Players.LocalPlayer
local Endurance = player:WaitForChild("Endurance")
local questFrame = script.Parent.Parent.Parent.Parent.Parent.QuestGui.Frame
local reward = questFrame.DailyQuest2.QuestReward
local percent = questFrame.DailyQuest2:WaitForChild("Percent")
local claim = questFrame.DailyQuest2:WaitForChild("Claim")
local progressBar = questFrame.DailyQuest2:WaitForChild("bar")
local questClaim = game.ReplicatedStorage:WaitForChild("QuestClaimRemote")

local DailyQuests = {
    {description = "Collect 100 Endurance", target = 100, rewardAmount = 100},
    {description = "Collect 1000 Endurance", target = 1000, rewardAmount = 250},
    {description = "Collect 100000 Endurance", target = 100000, rewardAmount = 500},
    {description = "Collect 1000000 Endurance", target = 1000000, rewardAmount = 700},
    {description = "Collect 10000000 Endurance", target = 10000000, rewardAmount = 1500},
    {description = "Collect 100000000 Endurance", target = 100000000, rewardAmount = 2000},
    {description = "Collect 1000000000 Endurance", target = 1000000000, rewardAmount = 2400},
    {description = "Collect 10000000000 Endurance", target = 10000000000, rewardAmount = 2700},
    {description = "Collect 100000000000 Endurance", target = 100000000000, rewardAmount = 3000},
    {description = "Collect 1000000000000 Endurance", target = 1e12, rewardAmount = 3500},
    {description = "Collect 10000000000000 Endurance", target = 1e13, rewardAmount = 4500},
    {description = "Collect 100000000000000 Endurance", target = 1e14, rewardAmount = 5000},
    {description = "Collect 1000000000000000 Endurance", target = 1e15, rewardAmount = 5500},
    {description = "Collect 10000000000000000 Endurance", target = 1e16, rewardAmount = 6000},
    {description = "Collect 100000000000000000 Endurance", target = 1e17, rewardAmount = 7000},
    {description = "Collect 1000000000000000000 Endurance", target = 1e18, rewardAmount = 8500},
    {description = "Collect 10000000000000000000 Endurance", target = 1e19, rewardAmount = 9500},
    {description = "Collect 100000000000000000000 Endurance", target = 1e20, rewardAmount = 10000},
    {description = "Collect 1000000000000000000000 Endurance", target = 1e21, rewardAmount = 12500},
    {description = "Collect 10000000000000000000000 Endurance", target = 1e22, rewardAmount = 15000},
    {description = "Collect 100000000000000000000000 Endurance", target = 1e23, rewardAmount = 17500},
    {description = "Collect 1000000000000000000000000 Endurance", target = 1e24, rewardAmount = 20000},
    {description = "Collect 10000000000000000000000000 Endurance", target = 1e25, rewardAmount = 25000},
    {description = "Collect 100000000000000000000000000 Endurance", target = 1e26, rewardAmount = 30000},
    {description = "Collect 1000000000000000000000000000 Endurance", target = 1e27, rewardAmount = 35000},
    {description = "Collect 10000000000000000000000000000 Endurance", target = 1e28, rewardAmount = 40000},
    {description = "Collect 100000000000000000000000000000 Endurance", target = 1e29, rewardAmount = 45000},
    {description = "Collect 1000000000000000000000000000000 Endurance", target = 1e30, rewardAmount = 50000},
}

local currentQuestIndex = player:GetAttribute("CurrentQuestIndex") or 1
local maxQuestsCompleted = #DailyQuests
local questCompleted = false

-- Function to update quest status
local function updateQuest()
    if currentQuestIndex > maxQuestsCompleted then
        percent.Text = "MAX"
        reward.Text = ""
        claim.Visible = false
        progressBar.Size = UDim2.new(1, 0, 1, 0)
    else
        local currentQuest = DailyQuests[currentQuestIndex]
        percent.Text = "Endurance: " .. moduleSc.abbreviate(Endurance.Value) .. " / " .. moduleSc.abbreviate(currentQuest.target)
        reward.Text = "Reward: " .. currentQuest.rewardAmount .. " coins"
        claim.Visible = false
        progressBar.Size = UDim2.new(0, 0, 1, 0)
        progressBar.BackgroundColor3 = Color3.fromRGB(255, 0, 0) -- Red color
    end
end

-- Function to update progress bar
local function updateProgressBar()
    if currentQuestIndex > maxQuestsCompleted then return end

    local currentQuest = DailyQuests[currentQuestIndex]
    local progress = math.min(Endurance.Value / currentQuest.target, 1)
    percent.Text = "Endurance: " .. moduleSc.abbreviate(Endurance.Value) .. " / " .. moduleSc.abbreviate(currentQuest.target)
    progressBar.Size = UDim2.new(progress, 0, 1, 0)

    if Endurance.Value >= currentQuest.target then
        questCompleted = true
        claim.Visible = true
        percent.Text = "Completed! You can claim the reward."
        progressBar.BackgroundColor3 = Color3.fromRGB(0, 255, 0) -- Green color
    else
        questCompleted = false
        claim.Visible = false
        progressBar.BackgroundColor3 = Color3.fromRGB(255, 0, 0) -- Red color
    end
end

-- Function to claim the reward
local function claimReward()
    if questCompleted then
        questClaim:FireServer(currentQuestIndex)
        currentQuestIndex = currentQuestIndex + 1
        player:SetAttribute("CurrentQuestIndex", currentQuestIndex)
        updateQuest()
    end
end

-- Function to start the countdown timer
local function startTimer()
    local timeRemaining = 23 * 3600 + 59 * 60 + 59 -- 23:59:59 in seconds

    while true do
        while timeRemaining > 0 do
            wait(1)
            timeRemaining = timeRemaining - 1

            local hours = math.floor(timeRemaining / 3600)
            local minutes = math.floor((timeRemaining % 3600) / 60)
            local seconds = timeRemaining % 60

            questFrame.Time.Text = string.format("%02d:%02d:%02d", hours, minutes, seconds)
        end

        -- Reset quests and time
        currentQuestIndex = 1
        player:SetAttribute("CurrentQuestIndex", currentQuestIndex)
        percent.Text = ""
        reward.Text = ""
        claim.Visible = false
        progressBar.Size = UDim2.new(0, 0, 1, 0)
        updateQuest()

        -- Reset time to 23:59:59
        timeRemaining = 23 * 3600 + 59 * 60 + 59
    end
end

-- Connect events
Endurance.Changed:Connect(updateProgressBar)
claim.MouseButton1Click:Connect(claimReward)
updateQuest() -- Initial setup
startTimer() -- Start the timer
print("Quest script started.") 



/// server script 
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local questDataStore = DataStoreService:GetDataStore("QuestData")
local replicatedStorage = game:GetService("ReplicatedStorage")

local questClaim = Instance.new("RemoteEvent", replicatedStorage)
questClaim.Name = "QuestClaimRemote"

local timeUpdateEvent = Instance.new("RemoteEvent", replicatedStorage)
timeUpdateEvent.Name = "TimeUpdateRemote"

local DailyQuests = {
    {description = "Collect 100 Endurance", target = 100, rewardAmount = 100},
    {description = "Collect 1000 Endurance", target = 1000, rewardAmount = 250},
    {description = "Collect 100000 Endurance", target = 100000, rewardAmount = 500},
    {description = "Collect 1000000 Endurance", target = 1000000, rewardAmount = 700},
    {description = "Collect 10000000 Endurance", target = 10000000, rewardAmount = 1500},
    {description = "Collect 100000000 Endurance", target = 100000000, rewardAmount = 2000},
    {description = "Collect 1000000000 Endurance", target = 1000000000, rewardAmount = 2400},
    {description = "Collect 10000000000 Endurance", target = 10000000000, rewardAmount = 2700},
    {description = "Collect 100000000000 Endurance", target = 100000000000, rewardAmount = 3000},
    {description = "Collect 1000000000000 Endurance", target = 1e12, rewardAmount = 3500},
    {description = "Collect 10000000000000 Endurance", target = 1e13, rewardAmount = 4500},
    {description = "Collect 100000000000000 Endurance", target = 1e14, rewardAmount = 5000},
    {description = "Collect 1000000000000000 Endurance", target = 1e15, rewardAmount = 5500},
    {description = "Collect 10000000000000000 Endurance", target = 1e16, rewardAmount = 6000},
    {description = "Collect 100000000000000000 Endurance", target = 1e17, rewardAmount = 7000},
    {description = "Collect 1000000000000000000 Endurance", target = 1e18, rewardAmount = 8500},
    {description = "Collect 10000000000000000000 Endurance", target = 1e19, rewardAmount = 9500},
    {description = "Collect 100000000000000000000 Endurance", target = 1e20, rewardAmount = 10000},
    {description = "Collect 1000000000000000000000 Endurance", target = 1e21, rewardAmount = 12500},
    {description = "Collect 10000000000000000000000 Endurance", target = 1e22, rewardAmount = 15000},
    {description = "Collect 100000000000000000000000 Endurance", target = 1e23, rewardAmount = 17500},
    {description = "Collect 1000000000000000000000000 Endurance", target = 1e24, rewardAmount = 20000},
    {description = "Collect 10000000000000000000000000 Endurance", target = 1e25, rewardAmount = 25000},
    {description = "Collect 100000000000000000000000000 Endurance", target = 1e26, rewardAmount = 30000},
    {description = "Collect 1000000000000000000000000000 Endurance", target = 1e27, rewardAmount = 35000},
    {description = "Collect 10000000000000000000000000000 Endurance", target = 1e28, rewardAmount = 40000},
    {description = "Collect 100000000000000000000000000000 Endurance", target = 1e29, rewardAmount = 45000},
    {description = "Collect 1000000000000000000000000000000 Endurance", target = 1e30, rewardAmount = 50000},
}

local QUEST_RESET_TIME = 24 * 60 * 60 -- Quest reset time in seconds (24 hours)

local function loadQuestData(player)
    local success, data = pcall(function()
        return questDataStore:GetAsync(player.UserId)
    end)

    if success and data then
        player:SetAttribute("CurrentQuestIndex", data.currentQuestIndex or 1)
        if player:FindFirstChild("Coins") then
            player.Coins.Value = data.coins or 0
        end

        -- Load last quest completion time
        local lastQuestTime = data.lastQuestTime or os.time()
        local timeElapsed = os.time() - lastQuestTime
        local timeLeft = QUEST_RESET_TIME - timeElapsed

        if timeLeft <= 0 then
            -- If the reset time has elapsed, reset the quest index
            player:SetAttribute("CurrentQuestIndex", 1)
            timeLeft = QUEST_RESET_TIME -- Update time to 24 hours
        end

        -- Save the last quest completion time
        player:SetAttribute("TimeLeft", timeLeft)
    else
        -- If no data, set initial values
        player:SetAttribute("CurrentQuestIndex", 1)
        if player:FindFirstChild("Coins") then
            player.Coins.Value = 0
        end
        player:SetAttribute("TimeLeft", QUEST_RESET_TIME) -- Set to 24 hours
    end
end

local function saveQuestData(player)
    local data = {
        currentQuestIndex = player:GetAttribute("CurrentQuestIndex"),
        coins = player:FindFirstChild("Coins") and player.Coins.Value or 0,
        lastQuestTime = os.time() -- Save current time as last quest completion time
    }

    local success, err = pcall(function()
        questDataStore:SetAsync(player.UserId, data)
    end)

    if not success then
        warn("Error saving quest data for player " .. player.Name .. ": " .. err)
    end
end

Players.PlayerAdded:Connect(function(player)
    loadQuestData(player)

    -- Save data on player exit
    player.AncestryChanged:Connect(function(_, parent)
        if not parent then
            saveQuestData(player)
        end
    end)

    -- Timer to update state every second
    while player.Parent do
        wait(1) -- Wait 1 second
        local timeLeft = player:GetAttribute("TimeLeft")
        if timeLeft then
            if timeLeft > 0 then
                timeLeft = timeLeft - 1
                player:SetAttribute("TimeLeft", timeLeft) -- Decrease time by 1 second

                -- Send updated time to the client
                timeUpdateEvent:FireClient(player, timeLeft)
            else
                player:SetAttribute("TimeLeft", 0) -- Ensure value doesn't go negative
                timeUpdateEvent:FireClient(player, 0) -- Update time value to 0
            end

            -- Save data every second
            saveQuestData(player)
        end
    end
end)

questClaim.OnServerEvent:Connect(function(player, questIndex)
    local currentQuest = DailyQuests[questIndex]
    if currentQuest and player:GetAttribute("CurrentQuestIndex") == questIndex then
        -- Give reward
        if player:FindFirstChild("Coins") then
            player.Coins.Value = player.Coins.Value + currentQuest.rewardAmount
        end
        player:SetAttribute("CurrentQuestIndex", questIndex + 1) -- Increment quest index

        -- Reset timer to 24 hours after claiming reward
        player:SetAttribute("TimeLeft", QUEST_RESET_TIME) 
        saveQuestData(player) -- Save data after claiming reward
    end
end)
1 Like

Any help is welcome, I don’t know what to do anymore and what the problem is

This is still relevant and I don’t know how to fix it

This is still relevant please help

are you trying to save it for a long time (e.g across servers) or are you just saving it temporarily

For a long time so that when you re-enter it doesn’t say 23:59:59 but the time the player logged in and played and when you exit it says, for example, 23:58:00 and when you log in it says this

This is still relevant please help

You can use tick() or os.date to check the times

instead of using Player.AncestryChanged to detect if the player left try using Players.PlayerRemoving instead, i tested both and player.PlayerRemoving worked better

It didn’t really help, I gave up on it and it’s still relevant, help me fix it, I’ve already spent the whole day and it’s no use

And yes, I would like time to move on when the player is offline.

This is still relevant help me I want to make it so that time goes even when the player is offline

Use tick() to save the time when the quest has started and when the player rejoins get the current tick value and subtract it with saved tick, the result will be time that passed while player was off

More about this:

Where to write in local or server script?

You will have to save data so in server script ofc