BindableEvent not firing

Hi there,

I started making a data management module for a framework, and I have ran into a problem. Basically, on the player data load function, I have a bindable that is supposed to fire when the data is fully loaded, but it doesn’t.

Here is the function in question:

--[[

	DataStoreObject:LoadDataAsync(player: Player, reconcileData: boolean?): PlayerDataObject

	Loads the player data and allows you to change it.
	
	[player]: The player the data should be loaded for.
	[reconcileData (Optional)]: Will automatically make any loaded profile reconcile its data. 

--]]

function DataStoreObject:LoadDataAsync(player: Player, reconcileData: boolean?)
	reconcileData = reconcileData or true
	
	local PlayerDataObject = setmetatable({ }, DataStoreObjectHidden)
	local PlayerProfile = self.DataStore:LoadProfileAsync(string.format(Settings.KeyStringPattern, player.UserId))
	
	PlayerDataObject.KeyChanged = Signal.new() :: ScriptSignal
	PlayerDataObject.KeyRemoved = Signal.new() :: ScriptSignal
	PlayerDataObject.DataLoaded  = Signal.new() :: ScriptSignal -- Signal that doesn't work.
	PlayerDataObject.LoadedPlayers = { } :: LoadedPlayers
	PlayerDataObject.Player = player
	
	if PlayerProfile then
		PlayerProfile:AddUserId(player.UserId)
		
		if reconcileData then
			PlayerProfile:Reconcile()
		end
		
		PlayerProfile:ListenToRelease(function()
			PlayerDataObject.LoadedPlayers[player] = nil
			player:Kick("Code 1:\n\n Player data was loaded on another server.")
		end)
		
		if player:IsDescendantOf(Players) then
			PlayerDataObject.LoadedPlayers[player] = PlayerProfile
			PlayerDataObject.DataLoaded:Fire() -- Where it fires
		else
			PlayerProfile:Release()
		end
	else
		player:Kick("Code 2:\n\n Player data was trying to be loaded on another server at the same time.")
	end
	
	return PlayerDataObject
end

Everything works, even past the point it fires, but it just doesn’t fire for whatever reason.

Here is the script where I load the data:

local DataService = require(script.Parent.DataService)
local Players = game:GetService("Players")
local QC = require(script.QuickAccess)

local MyDataStore = DataService.CreateDataStore("PlayerData", {LogInTimes = 0})

Players.PlayerAdded:Connect(function(Player)
	local PlayerData = MyDataStore:LoadDataAsync(Player)

    -- tried printing player data here and such, it worked so obviously it loads.
	
	PlayerData.DataLoaded:Connect(function()
		local LogInTimesKey = PlayerData:GetKey("LogInTimes")
		print(Player.Name, LogInTimesKey)
		
		PlayerData:SetKey("LogInTimes", LogInTimesKey + 1)
		
		PlayerData.KeyChanged:Connect(function(key, value)
			if key == "LogInTimes" then
				LogInTimesKey = value
			end
		end)
		
		---
		
		local leaderstats = Instance.new("Folder")

		leaderstats.Name = "leaderstats"
		leaderstats.Parent = Player

		local LogInTimes = Instance.new("NumberValue")

		LogInTimes.Name = "Log-in Times"
		LogInTimes.Value = LogInTimesKey
		LogInTimes.Parent = Player
	end)
end)

Players.PlayerRemoving:Connect(function(Player)
	MyDataStore:ReleaseSessionLock(Player)
end)

MyDataStore.SessionLockReleased:Connect(function(player: Player)
	print(string.format("Released session lock for %s.", player.Name))
end)

Hope you can help, and thanks!

Your code looks correct, so my only guess here would be race conditions since the event may be firing before the listener is connected

1 Like

Ah, you’re probably right. It looks like I called the load function before I could listen to it. How would I combat this though? My best guess would be to somehow yield the thread until the data is loaded, though I don’t know how to do this either.

Usually, what I would do is try to make the code run asynchronously so the loader runs and listener is connected at the same time.

But if that doesn’t work, you can try creating the signal inside the PlayerAdded signal and passing it as an argument to DataStore:LoadDataAsync, but it may look messy:

Players.PlayerAdded:Connect(function(player)
   local signal = Signal.new() -- Create and establish a new signal here

   signal:Connect(function()
     -- Connect the listener to the signal
   end)

   DataStore:LoadDataAsync(player, ..., signal) -- Load the player's data and fire the provided signal
   -- Though, again, this is kind of messy
end)
1 Like

Yeah I’ll probably do this. But how would I do this? (sorry kind of new to this async stuff.)

You can use task.spawn, task.defer, or task.synchronize and task.desynchronize. However, now looking at your code, I’m not sure if the latter two will work because require doesn’t work in parallel

1 Like

So like this kind of?

if player:IsDescendantOf(Players) then
			PlayerDataObject.LoadedPlayers[player] = PlayerProfile
			task.spawn(function() -- Create a new thread
				task.delay(1, function() -- Delay
					PlayerDataObject.DataLoaded:Fire()
				end)
			end)
		else
			PlayerProfile:Release()
		end

If you could give a quick little code snippet and guide me through it that would be great as well.

That should work, however, you can get rid of task.spawn in this case since task.delay runs asynchronously

if player:IsDescendantOf(Players) then
   PlayerDataObject.LoadedPlayers[player] = PlayerProfile

   -- task.delay works asynchronously, so the task scheduler will wait 1 second to execute
   -- the provided function without interupting the rest of the code
   task.delay(1, function() -- Delay
	  PlayerDataObject.DataLoaded:Fire()
   end)
else
   PlayerProfile:Release()
end
1 Like

One more question: Is there any way I can possibly delay until the event is listening, or no?

1 Like

In regular Luau, no, however, I assume Signal is a custom Module, so you would probably have to add that functionality

1 Like

Hey man thanks for helping me! I greatly appreciate it.

What I did:

In @stravant’s GoodSignal module, I added _listening to the constructor. I then set it to true whenever the event is connected, then false on disconnect.

Here is my code now:

	if player:IsDescendantOf(Players) then
			PlayerDataObject.LoadedPlayers[player] = PlayerProfile
			task.defer(function()
				repeat task.wait(0.25) until PlayerDataObject.DataLoaded._listening == true
				PlayerDataObject.DataLoaded:Fire()
			end)
		else
			PlayerProfile:Release()
		end
1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.