I have a question about this, how can I save the tools in this part?
I have no idea how to add the tools to that part, I suppose it is like that but I don’t think it works:
local DataManager = require(game.ServerScriptService:WaitForChild("DataStore"):WaitForChild("Configurations"):WaitForChild("DataManager"))
game.Players.PlayerAdded:Connect(function(player)
local Profile = DataManager:Get(player, true)
local Backpack = playe:WaitForChild("Backpack")
Backpack.ChildAdded:Connect(function()
for _, Tools in pairs(Backpack:GetChildren()) do
Profile.Data.Items = Tools
end
end)
First of all, you can’t save Instances with ProfileService (and with any DataStore Module actually).
What you could do is save the tools name and when you need to load them, you could just simply fetch the tool name in a folder containing all the tools available.
The folder should be something like this in the workspace:
local DataManager = require(game.ServerScriptService:WaitForChild("DataStore"):WaitForChild("Configurations"):WaitForChild("DataManager"))
game.Players.PlayerAdded:Connect(function(player)
local Profile = DataManager:Get(player, true)
local Backpack = player:WaitForChild("Backpack")
for _, ToolName in pairs (Profile.Items) do
local ToolToClone = game.Workspace.Tools:FindFirstChild(toolName):Clone()
ToolToClone.Parent = Backpack
end
end)
game.Players.PlayerRemoving:Connect(function(player)
local Profile = DataManager:Get(player, true)
local Backpack = player:WaitForChild("Backpack")
local ToolsToSave = {}
for _, Tool in pairs (Backpack:GetChildren()) do
ToolsToSave[#ToolsToSave+1] = Tool.Name
end
Profile.Items = ToolsToSave
end)
I did it directly from the script that handles the ProfileService
function cachedProfiles:Get(player, yield)
local profile = cachedProfiles[player]
if yield and not profile then
repeat task.wait(0.1)
profile = cachedProfiles[player]
until profile or (not player.Parent)
end
if profile then
return profile
end
end
and to get the tools (this is a server script):
Players.PlayerAdded:Connect(function(player)
local Profile = DataManager:Get(player, true)
for _, Tools in pairs(Profile.Data.Tools) do
if not toolsFolder:FindFirstChild(Tools) then continue end
local Tool = toolsFolder[Tools]:Clone()
Tool.Parent = player:WaitForChild("Backpack")
local ToolGear = toolsFolder[Tools]:Clone()
ToolGear.Parent = player:WaitForChild("StarterGear")
end
end)
ProfileService calls release on the profiles almost instantaneously, long before my code has a chance to call ListenToHopReady(). How would I work around this? My first thought would be to yield the profile’s release, but that doesn’t sound like a very good idea…
Since it seems like the profile is being removed from your profile table before your BindToClose call happens.
My solution to this:
On your :ListenToRelease call on PlayerAdded, check if ProfileService.ServiceLocked is true, that means the game is shutting down, if yes, then listen to :ListenToServerHopReady and inside that handler teleport the player.
Edit: you also need to have a counter for players that haven’t been teleported yet, and then yield until that counter is 0 on a :BindToClose call. Please don’t call :GetPlayers every Heartbeat though.
That should work.
Sadly all that is a side effect of ProfileService not using deferred events, if it did this wouldn’t be an issue.
Afaik his problem seems to be that :ListenToRelease makes his Profiles table be empty right away, so when he goes over the profiles to listen for hop ready, there’s nothing.
ProfileService’s :BindToClose runs, profiles start to be released
:ListenToRelease on every profile runs, profile is removed from Profiles table
His own :BindToClose call is now fired
No profiles on his Profiles table are found, TO BE EVEN LISTENING FOR.
Unlike ScriptSignals, :BindToClose fires in the order of first to last connected. Bad behaviour right? Sadly it can’t be changed :/
Fixing this is a question of making ProfileService yield for a Heartbeat fire (or deferred resume) before releasing all profiles.
No, because of the way that ProfileService works, that wouldn’t be a well designed thing to add.
ProfileService is in a way pretty raw, you’re expected to handle signals for data yourself.
You can always wrap Profiles in another more higher level class; after all, you’re probably only gonna really need to use the main profile reference sometimes. Inside that higher level class you can have custom methods for handling specific data, and keep signals for changes, etc.
You can always make that higher level class redirect to a real profile indexes, so you’re able to use everything with no issues other than indexing speed, but that’s not that important for stuff like DataStores.
I’m trying to understand how to use global updates. Just watched okeanskiy’s tutorials on it but I still have some questions.
Is it possible to save instances as data when adding a new active update?
I’m not sure of any way to figure out how to determine which global update id has what data. If I wanted to clear or edit a certain update, how do I get the id of that update?
Is it possible to have functions or yields in data when adding a new active update?
also wondering if it’s possible to handle lock and handle an active update within one forloop, for example:
for _,Update in pairs (globalUpdates:GetActiveUpdates()) do
globalUpdates:LockActiveUpdate(Update[1])
module.HandleLockedUpdate(player, globalUpdates, Update)
end
instead of
for _,Update in pairs (globalUpdates:GetActiveUpdates()) do
globalUpdates:LockActiveUpdate(Update[1])
end
globalUpdates:ListenToNewLockedUpdate(function(ID, Data)
module.HandleLockedUpdate(player, globalUpdates, {ID, Data})
end)
So I ran into this error randomly, which thankfully happened to my Profile so I became aware of it. I haven’t had any other instances of this happening to players. This problem would keep occurring with the same error when I would rejoin the same server where the error first occurred. Joining a different/new server would fix my Profile through Force-Loading, but if I have a game with 100 player servers, there might not be any other servers for a player to join.
What is the best method to resolve this so it doesn’t happen again?
local function PlayerAdded(player)
local profile = GameProfileStore:LoadProfileAsync(
"Player_" .. player.UserId,
"ForceLoad"
)
if profile ~= nil then
profile:Reconcile() --This replaced the InitializeProfileTemplate(profile) function
profile:ListenToRelease(function()
OnProfileReleased(player, profile)
Profiles[player] = nil
-- The profile could've been loaded on another Roblox server:
player:Kick("Profile might've been loaded on another Roblox server.")
end)
if player:IsDescendantOf(Players) == true then
Profiles[player] = profile
-- A profile has been successfully loaded:
OnProfileLoaded(player, profile)
else
-- Player left before the profile loaded:
profile:Release()
end
else
-- The profile couldn't be loaded possibly due to other
-- Roblox servers trying to load this profile at the same time:
player:Kick("Profile couldn't be loaded.")
end
end
Players.PlayerRemoving:Connect(function(player)
local profile = Profiles[player]
if profile ~= nil then
-- Don't release profile until Inventory is finished working
if player:GetAttribute("InventoryIsBusy") ~= false then
repeat RunService.Stepped:Wait()
if DEBUG_PRINT then
warn("Waiting for [" .. player.Name .. "]'s Inventory to not be busy.")
end
until player:GetAttribute("InventoryIsBusy") == false
end
profile:Release()
end
end)