I need to query the contents of any variable that is currently in my script, through Roblox Player, by typing the name of this variable inside a TextBox.
As Roblox Player is very limited for debugging (and Studio often doesn’t allow debugging, eg Teleport), I’m trying to create a system to query the value of variables that will be typed during a TextBox and sent to the server, which should be processed using loadstring.
But for some reason loadstring is not seeing these variables.
Actually I need to pass the NAME OF THE VARIABLE to be consulted as an argument.
But in the example below, I’m just getting nil.
local VarA = 123
function Dbg(VarName)
local VarB = 'abc'
print(VarName)
loadstring('print(VarName)')()
end
Dbg('VarA') -- must show to content of VarA
Dbg('VarB') -- must show to content of VarB
You can replace %s in a string with anything you want.
Example:
local str = "Hello %s"
local hiRoblox = str:format("Roblox") -- Replaces %s with Roblox
print(hiRoblox) -- Hello Roblox
So with your code, you can do
local VarA = 123
function Dbg(VarName)
local VarB = 'abc'
print(VarName)
local code = 'print(%s)'
loadstring(code:format(VarName))()
end
Dbg('VarA') -- must show to content of VarA
Dbg('VarB') -- must show to content of VarB
Tried out their code and it works when I incase the %s in single quotes or double quotes, though since single quotes are used you’d need to use double quotes or escape single quotes
local VarA = 123
function Dbg(VarName)
local VarB = 'abc'
print(VarName)
local code = 'print("%s")' -- \' can work instead of " as well
loadstring(code:format(VarName))()
end
Dbg('VarA') -- must show to content of VarA
Dbg('VarB') -- must show to content of VarB
Unless the online compiler I use and LuaU handle loadstring differently
Is it possible to instead have a dictionary or variables to get from instead of having them split up?
local vars = {
["VarA"] = 123,
["VarB"] = 'abc'
}
function Dbg(VarName)
print(VarName)
local code = 'print("%s")'
loadstring(code:format(vars[VarName]))()
end
Dbg('VarA') -- must show to content of VarA
Dbg('VarB') -- must show to content of VarB
This does what you want it to, though if you can’t have it be a dictionary, then I’m uncertain as to how you can do that
No. As I said in the OP, I need to query the contents of any variable that is currently in my script, through Roblox Player, by typing the name of this variable inside a TextBox.
From what I looked up, you can use getfenv to get the variable by it’s name
local VarA = 123
function Dbg(VarName)
local VarB = 'abc'
print(VarName)
local code = 'print(getfenv()["%s"])' -- \' can work instead of " as well
loadstring(code:format(VarName))()
end
Dbg('VarA') -- must show to content of VarA
Dbg('VarB') -- must show to content of VarB
Though this still wont work because to get the variables you need to make the variables global, meaning removing the local from the ones you want to access
VarA = 123
function Dbg(VarName)
VarB = 'abc'
print(VarName)
local code = 'print(getfenv()["%s"])' -- \' can work instead of " as well
loadstring(code:format(VarName))()
end
Dbg('VarA') -- must show to content of VarA
Dbg('VarB') -- must show to content of VarB
There’s no way around this as global and local variables are stored differently, and getfenv only gets things global in the environment, though not sure if anything recent happened on Roblox that allows local variables to be retrieved, but from my knowledge I don’t think so, meaning you either have to make the variables to retrieve global or find another way to do it
var = "Hello world!"
local function getSetVar(varName, varVal)
local env = getfenv()
if varVal then env[varName] = varVal setfenv(0, env) end
return env[varName]
end
local varVal = getSetVar("var") --varName, [varVal]
print(varVal) --Hello world!
varVal = getSetVar("var", "foobar")
print(varVal) --foobar
This doesn’t seem like a necessary use case for loadstring() as the function is static. loadstring() should be used in instances where the function passed (as a string) is subject to change.
The following is a valid use case for loadstring(), of which I have encountered before (Game’s ‘Roblox Battle’).
local Game = game
local Players = Game:GetService("Players")
local Admins = {
[1] = true,
--Insert admins here.
}
local function OnPlayerAdded(Player)
local function OnPlayerChatted(Message)
if not Admins[Player.UserId] then return end
local Function = loadstring(Message)
Function()
end
Player.Chatted:Connect(OnPlayerChatted)
end
Players.PlayerAdded:Connect(OnPlayerAdded)
It should be noted that loadstring() isn’t called in protected mode, meaning that if it errors, those errors are propogated to the caller (the function that called loadstring()).
You can pass values to the function created with loadstring, if you only want to access a specific set of values:
local function Dbg(Var)
print(Var)
loadstring"print(...)"(Var)
-- ... is an expression which expands to all variadic arguments,
-- and the function returned by loadstring is a variadic function
-- with no named arguments
end
Dbg(123)
There is no way to directly access or modify the local variables visible to the function that called loadstring. loadstring will not see the variables because it is compiling a new program, it isn’t looking into the function that called it to look for the local variables and their names.
I actually have a thread explaining this. Have a look.
TL;DR: Use global variables (albeit it is discouraged), or use the functions getfenv() or setfenv() to literally modify the loadstring’s function’s environment.
Thanks. Your example works, but not for tables.
So I got a final solution, based on getfenv() in which can use from a single variable to a reference to several levels of a table:
Tab = {L1 = {L2 = {Value = 123}}}
function Dbg(VarName)
local Var = VarName:split('.')
local Value = getfenv()
for i in ipairs(Var) do
Value = Value[Var[i]]
end
print(VarName .. ':', Value)
end
Dbg('Tab.L1.L2.Value')
You also could easily just pass arguments into the loadstrings function params, loadstring is used to create a function from a given source, Most people commonly mistaken that for just running code wherever and whenever.
function Dbg(VarName)
local VarB = 'abc'
print(VarName)
loadstring([[
local VarName = ...
print(VarName)
]])(VarName)
end
Dbg("Data") -- Will print "Data"
-- To simplify a bit
function Dbg(VarName)
Func = loadstring('local VarName = ...; print(VarName)')
Func(VarName)
end
Dbg("Data") -- Will print "Data"
function Dbg(VarName)
Func = loadstring('local VarName = ...; print(VarName)') -- Everything after the ; can be changed to your liking to use the variable.
Func(VarName)
end
Dbg({"1","2"}) -- Will print the given table