Live / Offline Data Manipulation For players

Hello !

This post is pretty much a follow-up of that one.

Basicaly, I’m using an ordered datastore to update the data of players and keep track of the manual changes throught a log ordered datastore.
You can write a new entry, each will have a unique key (telling all the information you need) and will have their value to the last log value + 1 (so we can order them).
When a player join the game, he loads this log journal, check all the changes to make to his data since the last time he was playing, then he can play. This allow me to update the data of players if they are on the same server as I’m, on a different one, or even if they are offline.

After a bit of testing I came up with this code, which seems to work fine.

I’d like some feedback, thoughts, reviews, anything you want :slight_smile:

local DataStoreService = game:GetService("DataStoreService")
local ServerLogs = DataStoreService:GetOrderedDataStore("Server_Logs")

local Promise = require(game.Promise)
local KeyCache = {}

local Logs = {}

function LiveUpdate(Player, Action, Key) -- update if the player is currently playing
    [TODO]
    -- if the player is playing in this server then do the action and update his client with a remote, add the key to his datatable.RecentLogRead
    -- if the palyer is offline or playing in another server, use messaging service to all servers and send the key, if a server detect the name of the player, he does the action 
end

function WriteRawServerLog(Key)
    return Promise.async(function(resolve)
        resolve(ServerLogs:SetAsync(Key, os.time()))
    end)
end

function Logs:WriteServerLog(Key)
    return WriteRawServerLog(Key):await()
end

function Logs:WritePlayerLog(Staff, Player, Action)
    local Success, Id
    local Rank = 0

    if game.Players:FindFirstChild(Player.Name) then
        Id = Player.UserId
        Rank = Player.Rank
    else
        Success, Id = Promise.async(function(resolve)
            resolve(game.Players:GetUserIdFromNameAsync(Player.Name))
        end):await()
        if not Success then
            warn("Can't get the UserId of", Player.Name)
            return "Can't get the UserId of "..Player.Name
        end
        --get rank with noblox in group
    end

    local PlayerLogs = DataStoreService:GetOrderedDataStore(Id.."_Logs")
    local Key = "-"..Staff.Rank.."-"..Staff.UserId.."-"..os.time().."-"..Action.Id.."-"..Action.Parameter
    -- LogId     -    StaffRank   -      StaffId     -     Time      -   ActionId    -      Parameter
    --  (6)     (1)     (2)      (1)      (10)      (1)    (10)     (1)    (2)      (1)       (10)         = 45 the length of the key cant be >50
    local ServerKey = "-"..Staff.Rank.."-"..Staff.UserId.."-"..Rank.."-"..Id.."-"..Action.Id.."-"..Action.Parameter
    -- LogId           -   StaffRank    -      StaffId     -  PlrRank -  PlrId -   ActionId    -      Parameter
    --  (6)           (1)     (2)      (1)      (10)      (1)   (2)  (1) (10) (1)    (2)      (1)       (10)         = 48

    local Progress = 0
    Success = false

    Success = Promise.async(function(resolve)
        resolve(PlayerLogs:GetSortedAsync(false, 1):GetCurrentPage()[1]) -- getting the last log value of the player
    end):andThen(function(mostRecentKeyPage)
        Progress += 1

        local Value
        if mostRecentKeyPage then
            Value = mostRecentKeyPage.value + 1 -- there was a log before
        else
            Value = 1 -- this is the first entry
        end

        if KeyCache[Player.Name] then
            if KeyCache[Player.Name] <= Value then
                Value += 1 -- this is to make sure every key is unique
            end
        end
        KeyCache[Player.Name] = Value
        Key = Value..Key -- this is to make sure every key is unique
        ServerKey = Value..ServerKey -- this is to make sure every key is unique
        print("Writing "..Key.." at "..Value)

        return Promise.async(function(resolve)
            resolve(PlayerLogs:SetAsync(Key, Value)) -- setting the new log in the ordered datastore of the player
        end)
    end):andThen(function()
        Progress += 1
        return WriteRawServerLog(ServerKey) -- setting the new log in the ordered datastore of the server
    end):await()
    KeyCache[Player.Name] = nil

    if Success then
        print("Log saved")
        LiveUpdate(Player, Action, Key) -- there was no problem
        return
    end

    if Progress == 0 then -- dealing with problems
        warn("Can't get the last Log")
        return "Can't get the last Log"
    elseif Progress == 1 then
        warn("Log didn't save")
        return "Log didn't save"
    else
        LiveUpdate(Player, Action, Key)
        Success = false
        Success = self:WriteServerLog(ServerKey)
        if not Success then
            warn("Log didn't save to server")
            return "Log didn't save to server"
        end
    end
end

Thx for reading !

1 Like