Lua userdata pass by reference - local functions in different files - lua

I have 2 Lua files, namely mydialog.lua and rangecontrol.lua. The code in mydialog.lua is as follows:
local function mydialog()
--omitted
local wb_responses=activeobj() --wb_responses points to the current activeobj(), say Obj1
UI.m_txt=sys.rangetextcontrol(UI.sbSizerInput:GetStaticBox() ,wb_responses) --wb_responses is passed by reference
--Selection event happened
--Omitted
--If clicked on a checkbox execute the following line
print(wb_responses) --Still prints Obj1 instead of Obj2
end
sys.tools.mydialog=mydialog
Code in rangecontrol.lua:
local function rangetextcontrol(parent, wb_txtBox)
local m_txtBox=nil
m_txtBox=wx.wxTextCtrl( parent, wx.wxID_ANY, "", wx.wxDefaultPosition, wx.wxDefaultSize, 0 )
local function GetRange()
wb_txtBox=activeobj()
local ws=activeobj():cur()
local rng=ws:selection()
if (rng==nil) then return end
m_txtBox:SetValue(rng:tostring()) -- Here wb_txtBox correctly refers to Obj2
end
m_txtBox:Connect( wx.wxEVT_LEFT_DOWN, function(event)
wb_txtBox=activeobj() --Current activeobj() changed, say Obj2
local ws=wb_txtBox:cur()
ws:connect(GetRange) --There is a selection event, call GetRange
event:Skip()
end)
return m_txtBox
end
sys.rangetextcontrol=rangetextcontrol
Briefly what happens:
1) A dialog starts and it has a textcontrol (there might be several textcontrols)
2) When user makes a selection from an object, the text box is populated.
3) My goal is to track from which object the selection is made.
My confusion: Although I pass wb_responses a userdata type, which should be passing by reference to the rangetextcontrol which keeps track of the selections, it seems that wb_responses never changes since it always prints info on Obj1. Therefore, I assume it always points to the first object that it has been initialized with in mydialog.lua. What could I be doing/thinking wrong?

local function mydialog()
--omitted
local wb_responses=activeobj() --wb_responses points to the current activeobj(), say Obj1
UI.m_txt=sys.rangetextcontrol(UI.sbSizerInput:GetStaticBox() ,wb_responses) --wb_responses is passed by reference
--Selection event happened
print(wb_responses) --Still prints Obj1 instead of Obj2
end
You print wbresponses right after you initialize it. How should it change its value? There won't be any event handling between those two lines of code.

Related

problem with event parameters / arguments. (Roblox Studio)

Basically I have a code that gets fired to a localscript in all players. The speaker / player argument is used to make sure the event is recieved by the correct reciever, and the "allow" argument is a boolean value used for later code. (Don't think about that part).
This is the :FireClient Script
1 game.ReplicatedStorage.AllowDisallow:FireClient(speaker, true)
This is the reciever / localscript
1 game.ReplicatedStorage.AllowDisallow.OnClientEvent:Connect(function(player, allow)
2 if not player.Name == game.Players.LocalPlayer.Name then return end
Error:
attempt to index boolean with 'Name'
My thought is that it erases the player parameter and switches it with the 'allow' bool value. I have tried searching this issue up on google, but I did not find a clear answer.
OTHER INFORMATION:
There's an event in ReplicatedStorage, which is the one im using.
It's called "AllowDisallow". Don't think too much about the name.
The 'allow' argument should be a bool value, and the "player" should be the player.
Sincerely, Mathe
The error is telling you that the player variable in the LocalScript is a boolean, not a Player object.
When you call a RemoteEvent's FireClient function, the first argument indicates which player it is going to, and all the rest are provided as the arguments in the OnClientEvent callback. For example,
-- if the server calls...
RemoteEvent:FireClient(player, a, b, c)
-- the client will receive...
RemoteEvent.OnClientEvent:Connect(function(a, b, c) end)
You just need to update your receiver LocalScript so that the arguments reflect what the server is providing. Then you can remove the LocalPlayer safety check, because the OnClientEvent only fires for the LocalPlayer.
local allowDisallow = game.ReplicatedStorage.AllowDisallow
allowDisallow.OnClientEvent:Connect(function(allow)
-- do some stuff
end)
try to print out the arguments in the server event and check whats wrong

Roblox Lua - attempt to index nil with 'stats' (leaderstats)

i want to make this, when the baseFinal is touched by a block (Bloque) it gives you money and the block is destroyed. it gives me an error: attempt to index nil with 'stats'
local base = script.Parent.Base
local baseFinal = script.Parent.Final
local plr = game.Players.LocalPlayer
baseFinal.Touched:Connect(function(hit)
if hit.Name == "Bloque" then
wait(0.6)
plr.stats.Value = plr.stats.Value + 5 // here is the error
hit:Destroy()
end
end)
The error is telling you that the plr variable is undefined or nil.
Since this code is running in a Script, the issue is how you are accessing the Player object. See the documentation for Players.LocalPlayer :
This property is only defined for LocalScripts (and ModuleScripts required by them), as they run on the client. For the server (on which Script objects run their code), this property is nil.
The way to fix this is to access the Player object another way. One way is to connect to the Players.PlayerAdded signal.
local base = script.Parent.Base
local baseFinal = script.Parent.Final
local connections = {}
game.Players.PlayerAdded:Connect( function(plr)
-- listen for Players to touch the block
local connection = baseFinal.Touched:Connect( function(hit)
if hit.Name == "Bloque" then
wait(0.6)
plr.stats.Money.Value = plr.stats.Money.Value + 5
hit:Destroy()
end
end)
-- hold onto the connection to clean it up later
connections[plr] = connection
end)
-- clean up when the Player leaves
game.Players.PlayerRemoving:Connect( function(plr)
connections[plr]:Disconnect()
end)
This is most likely because when you are trying to reference a value, you must put .Value after it in order to change the value itself. Assuming you have a stats folder, you should use plr.stats.Value.Value instead.
Next time, please show us your object structure so we have a better understanding of what the error is. Thanks.

Create local variables programmatically (in Lua)

Been having fun with a homebrew doco system in Lua. e.g.
fun("abs","return abs value", function (x,y)
return math.abs(x,y) end)
I'm stuck on one detail. I want to make "abs" a local function . But I do not know how to do that programmatically.
Of course, I could write to a field in some Lib object and call it Lib.abs(x,y) and I think that is what I'm going to have to do. BUT can any smart Lua person tell me how to not do that?
I don't think you have much of a choice, as while you can assign a value to a local variable (using debug.setlocal function), it's assigned by index, not by name, so there has to exist a local variable already with that index.
I don't see anything wrong with your suggestion to store the function in a table field.
What I would do is, I'd write(or even override) _G, run your function/program, and then restore it.
function callSandboxed(newGlobals, func)
local oldGlobals = {} --make a new table to store the values to be writen (to make sure we don't lose any values)
for i,_ in pairs(newGlobals) do
table.insert(oldGlobals, _G[i]) --Store the old values
_G[i] = newGlobals[i] --Write the new ones
end
func() --Call your function/program with the new globals
for i,v in pairs(oldGlobals) do
_G[i] = v --Restore everything
end
end
In this case, what you want to do is:
--Paste the callSandboxed function
callSandboxed({abs=math.abs},function()print(abs(-1))end) --Prints 1
If you want to remove ALL the old values from _G (not only the ones you want to replace), then you could use this:
function betterCallSandboxed(newGlobals, func) --There's no point deep copying now, we will replace the whole table
local oldGlobals = _G --Make a new table to store the values to be writen (to make sure we don't lose any values)
_G = newGlobals --Replace it with the new one
func() --Call your function/program with the new globals
_G = oldGlobals
end
Now if inside func, print and math(etc) are nil.

attempt to call a nil value

for i = 1, groupA:getNumChildren() do
local sprite = groupA:getChildAt(i)
if cute.anim[1]:collidesWith(sprite) then
youLoose()
end
end
local function youLoose()
local font3 = TTFont.new("billo.ttf", 20, " 1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,?")
local text7 = TextField.new(font2, "gameover")
text7:setPosition(200, 100)
stage:addChild(text7)
GameLost = Bitmap.new(Texture.new("gameover.jpg"))
Background : removeFromParent()
groupA : removeFromParent()
stage: addChild(GameLost)
alert()
end
It gives an error that says 'attempt to call global youLoose (a nil value), where am I doing it wrong?
Note that collideswith is not the same as collidesWith; if that error you posted is correct, then you posted code that is different from what you are using. It could be that the method really is called collidesWith (it appears to be if it is the one from sprite1), but you used collideswith. Alternatively, if the code posted is what you used, then the error is likely attempt to call collideswith(a nil value), so cute.anim[1] is not a sprite1 object, but it is not nil either otherwise the error would be different.
Once you have fixed this, you'll notice that youLoose is defined after that for loop, when you call youLoose() it is not yet defined. You're going to have to move the local function youLoose() function to before the loop. Because the loop is not itself in a function, but is at module level, it gets executed before any following code, so any functions (local or global) that are used in the loop must be defined before the loop.
Note that "loose" does not mean the same as "lose". Check Grammar-monster to see difference. Probably everywhere you have the word "loose" you should change to "lose".

World of Warcraft Lua - If statement flow

I'm trying to create an addon for World of Warcraft. I have created a function that checks whether a buff has been added to the current player.
Button:RegisterEvent("UNIT_AURA");
local function auraGained(self, event, ...)
if (UnitAura("player", "Heating Up")) then
if (heatingUpIsActive ~= 1) then
heatingUpIsActive = heatingUpIsActive + 1
print (heatingUpIsActive)
end
end
Button:SetScript("OnEvent", auraGained);
This works great, but how do I check if UnitAura is not "Heating Up"?
Also, I would prefer if heatingUpIsActive were a boolean, but it seems to not like when I do that. What is the correct way to create a boolean in Lua?
Your function isn't checking the aura that caused the event. It's looking for "Heating Up" any time any UNIT_AURA event comes by. In fact, it looks like the UNIT_AURA event doesn't actually tell you which aura triggered it. So you can't "check if UnitAura is not "Heating Up"", because you simply don't know what aura caused the event. Perhaps it was even several auras at once.
However, the event does tell you what unit got the aura. It's the first vararg. You should probably check to make sure it's player before doing something
local unitid = ...
if unitid ~= "player" then return end
Also, you didn't explain what problems you had with booleans. You should just be able to say something like
if not heatingUpIsActive then
heatingUpIsActive = true
-- do whatever you want
end
although I never saw any declaration of the variable in your code. It's a bad idea to use globals for things like this, so you should declare
local heatingUpIsActive
before the function declaration, e.g.
local heatingUpIsActive
local function auraGained(self, event, ...)
-- ...

Resources