Can't run a function inside a function?

Hello, could someone help me fix this issue in my script?

  1. What do you want to achieve? This chunk of code is part of a larger script that creates leaderstats and loads/saves data. As turning strings to booleans is not a built-in function, I made (borrowed lol) a function that turns strings into booleans (tobool()). I want to run this in my function that unpacks the save data in a datastore (a large string)

  2. What is the issue? tobool() is not running properly in the function. However, when it was used outside of the function, it worked properly. This is only erroring when the function actually runs (line 111), so the functions are likely being defined properly.

  3. What solutions have you tried so far? I have tried using tobool(v) instead of tobool() as the 4th parameter, but it still returns a nil value.

tobool() function:

function tobool(str)
	if str == "true" or str == "false" or str == "nil" then
		local boolNew

		if str == "true" then
			boolNew = true
		elseif str == "false" then
			boolNew = false
		elseif str == "nil" then
			boolNew = nil
		end

		return boolNew
	else
		warn("Parameter must be a string!")
		return
	end
end

unpacksave() function:

function unpacksave(target_datastore, target_folder, target_table, function_type)
	local packedstring = target_datastore:GetAsync(userId)
	print(packedstring)

	unpacked_table = string.split(packedstring, ",")

	for i, v in unpacked_table do
		print(tostring(i), tostring(v), typeof(v))
		print(tostring(player:WaitForChild(tostring(target_folder.Name)[target_table[i]].Value))
		function_type(v)
		player:WaitForChild(tostring(target_folder.Name))[target_table[i]].Value = function_type(v)
	end
end

Where unpacksave() actually runs:

unpacksave(tools_store, toolfolder, tools, tobool())

Entire script:

local players = game.Players
local datastoreserv = game:GetService("DataStoreService")
local coins_store = datastoreserv:GetDataStore("Coins")
local tools_store = datastoreserv:GetDataStore("Tools")
local tempstats_store = datastoreserv:GetDataStore("TemporaryStats")

--Player-independent functions

function tobool(str)
	if str == "true" or str == "false" or str == "nil" then
		local boolNew

		if str == "true" then
			boolNew = true
		elseif str == "false" then
			boolNew = false
		elseif str == "nil" then
			boolNew = nil
		end

		return boolNew
	else
		warn("Parameter must be a string!")
		return
	end
end

players.PlayerAdded:Connect(function(player)
	userId = player.UserId
	
	--Player-dependent functions
	
	local tosavevalue = ""

	function packsave(folder_to_search, datastore_to_search)
		for i, v in folder_to_search do
			if i <= 1 then
				tosavevalue = tosavevalue ..tostring(v.Value)
			else
				tosavevalue = tosavevalue.. "," ..tostring(v.Value)
			end

			datastore_to_search:SetAsync(userId, tosavevalue)
			print(tosavevalue, tostring(v.Value))
		end
	end

	function unpacksave(target_datastore, target_folder, target_table, function_type)
		local packedstring = target_datastore:GetAsync(userId)
		print(packedstring)

		unpacked_table = string.split(packedstring, ",")

		for i, v in unpacked_table do
			print(tostring(i), tostring(v), typeof(v))
			print(tostring(player:WaitForChild(tostring(target_folder.Name))[target_table[i]].Value))
			function_type(v)
			player:WaitForChild(tostring(target_folder.Name))[target_table[i]].Value = function_type(v)
		end
	end
	
	function instanceload()
		print("aa")
	end
	
	--Setting leaderstats
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player
	
	coins = Instance.new("IntValue")
	coins.Name = "Coins"
	coins.Parent = leaderstats
	coins.Value = 0
	
	--Setting hidden values (folders)
	toolfolder = Instance.new("Folder")
	toolfolder.Name = "ToolsFolder"
	toolfolder.Parent = player
	
	tempstatfolder = Instance.new("Folder")
	tempstatfolder.Name = "TempStats"
	tempstatfolder.Parent = player
	
	--Setting hidden values (tables)
	--NOTE: tools_owned and similar tables are only used in pre-data loading (instance generation)
	tools = {"rustybucket", "woodenbucket"}
	local tools_owned = {false, false}
	
	tempstats = {"capacity", "max_capacity"}
	local tempstat_values = {0, 10}
	
	--Setting hidden values (instances) (Nothing for now :( )

	--Creating the tools owned values
	for i, v in tools_owned do
		local newInstance = Instance.new("BoolValue")
		newInstance.Name = tools[i]
		newInstance.Value = v
		newInstance.Parent = toolfolder
	end
	
	--Loading data
	wait(3)

	local savedcoins = coins_store:GetAsync(userId)
	print(tostring(savedcoins))
	coins.Value = savedcoins
	
	unpacksave(tools_store, toolfolder, tools, tobool())
	
end)

players.PlayerRemoving:Connect(function()

	local setSuccess, errorMessage = pcall(function()
		
		coins_store:SetAsync(userId, coins.Value)
		
		--Saving multivalues with string to unpack
		
		packsave(toolfolder:GetChildren(), tools_store)
		
	end)

	if not setSuccess then
		errorMessage = "Data not saved!"
		warn(errorMessage)
	end

end)

(btw sry if this code is really messy, I haven’t tried to optimise it)

Thanks for reading this post!

1 Like

when you type function: tobool()
the str variable in the function is nil, not the string “nil”. I have no idea what is is your variable “v” is in

But Im pretty sure its the same thing as nil.
Seem like you only think of the string “nil” in your if statement, add a ==nil as well

Reading the code snippet, it looks like you don’t pass anything into the toobool() function. So, there’s nothing for it to convert there. Also, the variable “v” doesn’t exist outside of the for i, v loop. Since you’re passing nil (nil, not the string “nil”), it passes into the else statement in the function and returns nil.

Is there a way to get v out of the loop without using return?

You can set a placeholder variable to nil before the loop starts, and when you find the desired object inside the loop, set that placeholder variable to v. Like this:

local placeholder = nil

for i, v in pairs(workspace:GetChildren()) do
  if v.Name == "the part i want" then
    placeholder = v
  end
end

-- now placeholder = the part i want and I can access it outside of the loop.

For some reason, tobool doesn’t seem to be running even if it isn’t a variable IN a function:
For example: This does NOT print

	function unpacksave(target_datastore, target_folder, target_table, function_type)
		local packedstring = target_datastore:GetAsync(userId)
		local v = nil
		print(packedstring)

		unpacked_table = string.split(packedstring, ",")

		for i, v in unpacked_table do
			print(tostring(i), tostring(v), typeof(v))
			print(tostring(player:WaitForChild(tostring(target_folder.Name))[target_table[i]].Value))
			print(tostring(function_type("false")))
			function_type(v)
			player:WaitForChild(tostring(target_folder.Name))[target_table[i]].Value = function_type(v)
		end
	end

This does print:

	print(tostring(tobool("true")))

(I still don’t know why it’s broken, v should be defined in the for loop?)

Just to clarify, none of the print statements in that function are running? Also, I’m not seeing where tobool() is being called in the larger code snippet you sent.

1 Like

I’m calling tobool() as a parameter in the unpacksave() at the bottom
Currently using a temp fix with separate functions for unpacking bool and int values

Can I see how you’re calling the tobool function again?

Also, just to make sure, are any of the print statements in the function you sent running?