Coroutine not working

Hello,
My data save is not working and my coroutine is not working.
Video showing scripts (at the end my studio crashes)


Video showing not saving:

Data script:

local datastore = game:GetService("DataStoreService")
local moneystore = datastore:GetDataStore("Stats")
game.Players.PlayerAdded:Connect(function(p)
	local leader = Instance.new("IntValue",p)
	leader.Name = "leaderstats"
	local mon = Instance.new("NumberValue",leader)
	mon.Name = "Money"
	local so = Instance.new("StringValue",leader)
	so.Name = "Job"
	local ren = Instance.new("NumberValue",leader)
	ren.Name = "Reputation"
	local gor = moneystore:GetAsync(p.UserId)
	if gor~=nil then
		mon.Value = gor[1]
		so.Value = gor[2]
		ren.Value = gor[3]
	else
		gor = {mon.Value,so.Value,ren.Value}
	end
	for i,v in pairs(script.Notice:GetChildren()) do
		local sog = v:Clone()
		sog.Parent = p
	end
end)
game.Players.PlayerRemoving:Connect(function(p)
	moneystore:SetAsync(p.UserId,{p.leaderstats.Money.Value,p.leaderstats.Job.Value,p.leaderstats.Reputation.Value})
	print('sag')
end)
local function save(v)
	local a = coroutine.wrap(function()
		moneystore:SetAsync(v.UserId,{v.leaderstats.Money.Value,v.leaderstats.Job.Value,v.leaderstats.Reputation.Value})
		print('jiesh')
	end)
end
game:BindToClose(function()
	for i,v in pairs(game.Players:GetPlayers()) do
		save(v)
	end
end)

(Also side note here is that the change of the leaderstates values are server sided. Here is the remote event script for it.

game.ReplicatedStorage.AddRep.OnServerEvent:Connect(function(p,a,s)
	a:Destroy()
	for i,v in pairs(p:GetChildren()) do
		print(v.Name)
	end
	p.leaderstats.Reputation.Value = p.leaderstats.Reputation.Value+math.floor(math.clamp(s,0,p.leaderstats.Money.Value)/5+0.5)
	p.leaderstats.Money.Value = p.leaderstats.Money.Value-math.clamp(s,0,p.leaderstats.Money.Value)
end)

- Br, iSyriux

First of all, you aren’t even executing the coroutine.

a() --Like that.
2 Likes

Hello,

It does not seem to work.

You should get an understanding of what scopes are:

The variable a is out of scope for the BindToClose Connection, therefore resulting in a nil.

But I don’t understand why you’re trying to do it like though, you can just do:

local function save(v)
   coroutine.wrap(function()
      moneystore:SetAsync(...) --Use pcalls for error handling btw.
   end)()
end

game:BindToClose(function()
   for _, client in pairs(game.Players:GetPlayers()) do
      save(client)
   end
end)

Hello,

What is this

That is required for executing the coroutine obviously. That is the reason why your coroutine wasn’t working in the first place.

Hello,

It sometimes works but not in a way that you might expect. It seems like the playerremoved works but the bindtoclose coroutine does not. (coroutine does not work at all)


As you can see, this is an unreliable and ineffective method to save data as it sometimes doesn’t work.

Can you show your latest code? please don’t give a screenshot, its hard for us to modify and give some of the code like that.

You should also use pcalls while saving/loading to avoid data load failures, which can result in data loss.

Hello,

local datastore = game:GetService("DataStoreService")
local moneystore = datastore:GetDataStore("Stats")
game.Players.PlayerAdded:Connect(function(p)
	local leader = Instance.new("IntValue",p)
	leader.Name = "leaderstats"
	local mon = Instance.new("NumberValue",leader)
	mon.Name = "Money"
	local so = Instance.new("StringValue",leader)
	so.Name = "Job"
	local ren = Instance.new("NumberValue",leader)
	ren.Name = "Reputation"
	local gor = moneystore:GetAsync(p.UserId)
	if gor~=nil then
		mon.Value = gor[1]
		so.Value = gor[2]
		ren.Value = gor[3]
	else
		gor = {mon.Value,so.Value,ren.Value}
	end
	for i,v in pairs(script.Notice:GetChildren()) do
		local sog = v:Clone()
		sog.Parent = p
	end
end)
game.Players.PlayerRemoving:Connect(function(p)
	moneystore:SetAsync(p.UserId,{p.leaderstats.Money.Value,p.leaderstats.Job.Value,p.leaderstats.Reputation.Value})
	print('sag')
end)
local function save(v)
	coroutine.wrap(function()
		moneystore:SetAsync(v.UserId,{v.leaderstats.Money.Value,v.leaderstats.Job.Value,v.leaderstats.Reputation.Value})
		print('jiesh')
	end)()
end
game:BindToClose(function()
	for i,v in pairs(game.Players:GetPlayers()) do
		save(v)
	end
end)

Everything seems pretty good, although you need to implement the use of pcalls in your script. To handle errors properly, and you can do like a repeat loop till data is saved successfully too.

Really simple Example, to get an idea:

local success, response
local tries = 0
 
local function saveData()
    local saveData = {v.leaderstats.Money.Value,v.leaderstats.Job.Value,v.leaderstats.Reputation.Value}
    success, response = pcall(moneystore.SetAsync, moneystore, v.UserId, saveData)
    tries += 1
end

repeat 
  wait(7) --So that you don't hit limit of 6 second gap.
  saveData()
until success == true or tries >= 3 --Will try 3 tries to save on max, or till you are not successful saving data.
1 Like

you forgot to use coroutine.resume

Hello,
Unfortunately, the example you have given does not solve my coroutine problem.

Hello,
Where would I put coroutine.resume

local function save(v)
local a = coroutine.wrap(function()
moneystore:SetAsync(v.UserId,{v.leaderstats.Money.Value,v.leaderstats.Job.Value,v.leaderstats.Reputation.Value})
print(‘jiesh’)
end)
coroutine.resume(a)
end

It was to be taken as an example and get an idea, not copy paste that code (If you did, not sure), I really recommend you getting more understanding of what is causing the problem. The coroutine isn’t what is really causing the problem. Make sure you aren’t getting any error in console, if you’re post them here so we can see the error.


@VeinTweek coroutine.wrap doesn’t return the newly created thread, it just returns the function so that will result in an error.

2 Likes

Hello,
This does not seem to work.

Hello,

Your method does not seem to work, and freezes studio.

local datastore = game:GetService("DataStoreService")
local moneystore = datastore:GetDataStore("Stats")
game.Players.PlayerAdded:Connect(function(p)
	local leader = Instance.new("IntValue",p)
	leader.Name = "leaderstats"
	local mon = Instance.new("NumberValue",leader)
	mon.Name = "Money"
	local so = Instance.new("StringValue",leader)
	so.Name = "Job"
	local ren = Instance.new("NumberValue",leader)
	ren.Name = "Reputation"
	local gor = moneystore:GetAsync(p.UserId)
	if gor~=nil then
		mon.Value = gor[1]
		so.Value = gor[2]
		ren.Value = gor[3]
	else
		gor = {mon.Value,so.Value,ren.Value}
	end
	for i,v in pairs(script.Notice:GetChildren()) do
		local sog = v:Clone()
		sog.Parent = p
	end
end)
game.Players.PlayerRemoving:Connect(function(p)
	moneystore:SetAsync(p.UserId,{p.leaderstats.Money.Value,p.leaderstats.Job.Value,p.leaderstats.Reputation.Value})
	print('sag')
end)
local success, response
local tries = 0
local function save(v)
	local a = coroutine.wrap(function()
		pcall(moneystore.SetAsync, moneystore, v.UserId, {p.leaderstats.Money.Value,p.leaderstats.Job.Value,p.leaderstats.Reputation.Value})
		print('jiesh')
	end)
	tries += 1
end
game:BindToClose(function()
	repeat
		wait(7)
		for i,v in pairs(game.Players:GetPlayers()) do
			save(v)
		end
	until success == true or tries >= 3
end)

As per your current script, doesn’t look like you’re even understanding the basics. I mean like you need to use some logic in this case.

Some mistakes I found out with a look:

  1. You aren’t executing the coroutine again, even though I already showed how to.
  2. I had shown you to retry the save function if failed, what you’re doing is just infinite loop it around all the players and running save function inside it, of course resulting in a crash.
  3. You aren’t even setting the success and response variable to the pcall’s return value.
  4. You’re trying to reference the variable p in the save function, which isn’t defined.

What you should be doing is something like this:

local datastore = game:GetService("DataStoreService")
local moneystore = datastore:GetDataStore("Stats")

game.Players.PlayerAdded:Connect(function(p)
	local leader = Instance.new("IntValue",p)
	leader.Name = "leaderstats"
	local mon = Instance.new("NumberValue",leader)
	mon.Name = "Money"
	local so = Instance.new("StringValue",leader)
	so.Name = "Job"
	local ren = Instance.new("NumberValue",leader)
	ren.Name = "Reputation"
	local gor = moneystore:GetAsync(p.UserId)
	if gor~=nil then
		mon.Value = gor[1]
		so.Value = gor[2]
		ren.Value = gor[3]
	else
		gor = {mon.Value,so.Value,ren.Value}
	end
	for i,v in pairs(script.Notice:GetChildren()) do
		local sog = v:Clone()
		sog.Parent = p
	end
end)

local function save(v)
	coroutine.wrap(function()
		local success, response
		local tries = 0
		local saveData = {v.leaderstats.Money.Value,v.leaderstats.Job.Value,v.leaderstats.Reputation.Value}

		success, response = pcall(moneystore.SetAsync, moneystore, v.UserId, saveData)

		repeat
            wait(7)
			success, response = pcall(moneystore.SetAsync, moneystore, v.UserId, saveData)
			tries += 1
		until not success or tries < 3 
	end)()
end


game.Players.PlayerRemoving:Connect(function(p)
	save(p)
end)

game:BindToClose(function()
	for i,v in pairs(game.Players:GetPlayers()) do
		save(v)
	end
end)

Hello,
The solution you gave is still not working.

local datastore = game:GetService("DataStoreService")
local moneystore = datastore:GetDataStore("Stats")

game.Players.PlayerAdded:Connect(function(p)
	local leader = Instance.new("IntValue",p)
	leader.Name = "leaderstats"
	local mon = Instance.new("NumberValue",leader)
	mon.Name = "Money"
	local so = Instance.new("StringValue",leader)
	so.Name = "Job"
	local ren = Instance.new("NumberValue",leader)
	ren.Name = "Reputation"
	local gor = moneystore:GetAsync(p.UserId)
	if gor~=nil then
		mon.Value = gor[1]
		so.Value = gor[2]
		ren.Value = gor[3]
	else
		gor = {mon.Value,so.Value,ren.Value}
	end
	for i,v in pairs(script.Notice:GetChildren()) do
		local sog = v:Clone()
		sog.Parent = p
	end
end)

local function save(v)
	coroutine.wrap(function()
		local success, response
		local tries = 0
		local saveData = {v.leaderstats.Money.Value,v.leaderstats.Job.Value,v.leaderstats.Reputation.Value}

		success, response = pcall(moneystore.SetAsync, moneystore, v.UserId, saveData)

		repeat
            wait(7)
			success, response = pcall(moneystore.SetAsync, moneystore, v.UserId, saveData)
			tries += 1
		until not success or tries < 3 
	end)()
end


game.Players.PlayerRemoving:Connect(function(p)
	save(p)
end)

game:BindToClose(function()
	for i,v in pairs(game.Players:GetPlayers()) do
		save(v)
	end
end)

Are you sure the script is saved and then the game is run? Are you sure the API Services are turned on in studio? Use the pcalls while loading data too, to ensure its loading the data without any errors. Try and see if it works in Roblox player but not studio.

Also wanted to ensure that you’re updating your data from the server side.

I also don’t recommend you to copy paste, first you need to have an understanding of what the code does.