I see, well thank you, I’ll keep digging into it and see what else I can do with it.
Yeah of course, if you have any questions you can PM me too, I use replica service in my main project so I may be able to help you with it. Otherwise good luck!
Did you ever find a fix for this? I’ve been using ProfileService for months, but just recently my load times have spiked to 60 seconds minimum and it’s killing my retention.
Yes, I switched to using EasyProfile for my Profile Service Manager. You can see my post here asking about value changes. It seems to work pretty well but with the occasional reports of it being slow every so often but that’s with any game
The documentation seems to be broken so here is my code to manage it, just to save you some time:
local DataErrorMessage = "Could not load data, try again shortly. If issue persists, open a ticket!"
local LoadType = "ForceLoad" --"Steal"
local gameProperties, srv = _G.GameProperties, _G.GameServices
local profileService = require(script:WaitForChild("EasyProfile"))
local playerTemplate = require(script:WaitForChild("PlayerTemplate"))
local DataKey = gameProperties.DataKey
local ProfileStore = profileService.CreateProfileStore(
DataKey,
playerTemplate,
"<default_key>-<userid>"
)
local PSManager = {
Profiles = {}
}
local function HandleGlobalKey(globalKey, profile) --> Value, Key, KeyId
local value, key, keyId = globalKey.Value, globalKey.Key, globalKey.KeyId
if not keyId then
return
end
if key == "Warning" then
if value == "reset" then
profile.Data.Warnings = {}
elseif value == "remove" then
local warning = value.warning and tonumber(value.warning)
if not warning or not profile.Data.Warnings[warning] then
return
end
table.remove(profile.Data.Warnings, warning)
elseif typeof(value) == "table" then
table.insert(profile.Data.Warnings, {
admin = value.admin,
reason = value.reason,
warnedAt = value.sendTime
})
end
end
end
local function PlayerAdded(player : Player)
local start_time, timeJoined = tick(), os.time()
ProfileStore:LoadProfileAsync(player, true, LoadType):After(function(success, playerProfile, ...)
--print(tick() - start_time.."s")
if not success then
player:Kick(DataErrorMessage)
return
end
local metaData = playerProfile:GetMetaData()
if metaData.ProfileActiveSession.jobId ~= game.JobId then
player:Kick("Profile is already loaded in another server, please wait before rejoining! If this continues, open a ticket!")
return
end
--/ Create leaderstats
playerProfile:CreateProfileLeaderstats(player, {"KOs", "WOs", "Cash"})
local profile = playerProfile.Profile
profile.TimeJoined = timeJoined
local dummy = {
Data = {
TimeJoined = profile.TimeJoined
}
}
local callbacks = {}
--/ Value Changing
dummy.Data.__index = function(_,index)
return profile.Data[index]
end
dummy.__index = function(_,index)
if (index ~= "Data") then
return profile[index]
end
end
dummy.Data.__newindex = function(_,index,value)
profile.Data[index] = value
local callback = callbacks[index]
if not callback or typeof(callback) ~= "table" then return end
for _, callback in callback do
coroutine.wrap(callback)(value)
end
end
dummy.__newindex = function(_,index,value)
profile[index] = value
end
setmetatable(dummy.Data,dummy.Data)
setmetatable(dummy,dummy)
function dummy:OnDataValueChanged(index, callback)
if (not callbacks[index]) then
callbacks[index] = {}
end
table.insert(callbacks[index],callback)
local Connection = {}
function Connection:Disconnect()
table.remove(callbacks[index],table.find(callbacks[index],callback))
end
return Connection
end
--/ Global Keys
for _, globalKey in playerProfile:GetGlobalKeys() do
coroutine.wrap(HandleGlobalKey)(globalKey, profile)
end
playerProfile.GlobalKeyAdded:Connect(function(globalKey)
HandleGlobalKey(globalKey, profile)
end)
PSManager.Profiles[player] = dummy
end)
end
for _, player in srv.players:GetPlayers() do
coroutine.wrap(PlayerAdded)(player)
end
srv.players.PlayerAdded:Connect(PlayerAdded)
srv.players.PlayerRemoving:Connect(function(player : Player)
if PSManager.Profiles[player] ~= nil then
PSManager.Profiles[player] = nil
ProfileStore:UnclaimSessionLock(player, nil)
end
end)
function PSManager:WaitForPlayerLoaded(player : Player) : Profile
local profile = self.Profiles[player] if profile then return profile end
repeat task.wait() profile = self.Profiles[player] until profile return profile
end
function PSManager:FetchProfile(...) : Profile
return self:WaitForPlayerLoaded(...)
end
function PSManager:GetProfileStore()
return ProfileStore
end
function PSManager:GetPlayerTemplate()
return playerTemplate
end
function PSManager:GetOfflinePlayerStore(userId : number) : Profile
if not userId or not tonumber(userId) then
return
end
userId = tonumber(userId)
return ProfileStore:GetProfileAsync(
profileService.IsProfileKeyValid(userId, ProfileStore)
):Await()
end
return PSManager
Hope that helps!
It might help, but for now it actually makes things harder sadly lol
Thank you anyway though, you’re the first person I’ve gotten any sort of info from so far. Unfortunately my game is already live and switching Data templates right now could be catastrophic. I’ll tinker with Easy Profile and see if I can come up with a viable way to transition over though, thanks again!
My game was published aswell when I did the change, as long as you continue using ProfileService you shouldn’t have any issues. EasyProfile uses ProfileService so it should be alright. I would just try and play around with it and look at my code to see how I did it
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.