I'm trying to secure the doors of my CNC with switchs that send a Signal to my Laptop (I got Mach 4 on it). I created this Code that should make the Spindle stay still if the doors aren't locked, but I always get an error that says :
[string""]1576 attempt to call global 'SicherheitsKreis' (a Nil value) stack traceback:
I've tried to move the Code around and read topics on this, but Nothing works.
Does someone have a solution ?
Here's all my Code :
function SicherheitsKreis(Schliesserstate, Oeffnerstate)
if (Schliesserstate ==0 and Oeffnerstate ==1 ) then
mc.mcSpindleSetDirection(inst,0)
elseif (Schliesserstate == 1 and Oeffnerstate == 0 ) then
local sigh = mc.mcSignalGetHandle(inst, mc.OSIG_SPINDLEON);
local sigState = mc.mcSignalGet State(sigh);
if (sigState == 1) then
mc.mcSpindleSetDirection(inst,0)
else
mc.mcSpindleSetDirection(inst,1);
end
else
mc.mcSpindleSetDirection(inst,0)
end
end
if (mc.mcInEditor() == 1) then
SicherheitsKreis()
end
The Code that I'm using to call SicherheitsKreis is :
local inst = mc.mcGetInstance()
local hsigSchliesser = mc.mcSignalGetHandle(inst, mc.ISIG_INPUT8);
local hsigOeffner = mc.mcSignalGetHandle (inst, mc.ISIG_INPUT9);
local Schliesserstate = mc.mcSignalGetState(hsigSchliesser);
local Oeffnerstate = mc.mcSignalGetState(hsigSchliesser);
SicherheitsKreis(Schliesserstate, Oeffnerstate)
This Script is typed in Mach 4 and the function is saved as a m function (nach4 has free m function that the user can customize) in the Memory of Mach 4 (for my Computer it is m146)
Your code:
function SicherheitsKreis(Schliesserstate, Oeffnerstate)
...
end
First possibility is that code is in some other function or other element, so it is not global. Second possibility is that you run SicherheitsKreis(Schliesserstate, Oeffnerstate) before loading this part of code. Third (very uncommon) is that you override it by SicherheitsKreis = nil or equivalent. There is no other possibilities.
Related
I'm new to Lua and was following the tutorial on https://wowwiki.fandom.com/wiki/AddOn_tutorial but i just cant get it to work; i have copied the code but i get the error message "attempt to call a global 'functionname' (a nil value)" on both the SetMapToCurrentZone() and the GetPlayerMapPosition("player") functions.
This is the entire Lua file;
local zone = nil
local TimeSinceLastUpdate = 0
local function UpdateCoordinates(self, elapsed)
if zone ~= GetRealZoneText() then
zone = GetRealZoneText()
SetMapToCurrentZone()
end
TimeSinceLastUpdate = TimeSinceLastUpdate + elapsed
if TimeSinceLastUpdate > .5 then
TimeSinceLastUpdate = 0
local posX, posY = GetPlayerMapPosition("player");
local x = math.floor(posX * 10000)/100
local y = math.floor(posY*10000)/100
eCoordinatesFontString:SetText("|c98FB98ff("..x..", "..y..")")
end
end
function eCoordinates_OnLoad(self, event,...)
self:RegisterEvent("ADDON_LOADED")
end
function eCoordinates_OnEvent(self, event, ...)
if event == "ADDON_LOADED" and ... == "eCoordinates" then
self:UnregisterEvent("ADDON_LOADED")
eCoordinates:SetSize(100, 50)
eCoordinates:SetPoint("TOP", "Minimap", "BOTTOM", 5, -5)
eCoordinates:SetScript("OnUpdate", UpdateCoordinates)
local coordsFont = eCoordinates:CreateFontString("eCoordinatesFontString", "ARTWORK", "GameFontNormal")
coordsFont:SetPoint("CENTER", "eCoordinates", "CENTER", 0, 0)
coordsFont:Show()
eCoordinates:Show()
end
end
How do i fix it?
These functions have been renamed and moved to a wrapper object in 8.0, to C_Map.GetBestMapForUnit (requiring "player" as parameter to yield the same result) and C_Map.GetPlayerMapPosition respectively.
You can probably expect more functions that are called later to throw the same error, their lines just couldn't be reached before. I can check the whole code example when I'm at a desktop again, but you may simply look up these functions on Wowpedia, especially other map-related functions.
I suggest using Wowpedia over Wowwiki, it's a personal preference/impression, the former seems to receive more constant updates.
(The two seem to be merging again now, after splitting 10 years ago)
I'm currently starting work on a text adventure game in Lua--no addons, just pure Lua for my first project. In essence, here is my problem; I'm trying to find out how I can do a "reverse lookup" of a table using one of its variables. Here's an example of what I've tried to do:
print("What are you trying to take?")
bag = {}
gold = {name="Gold",ap=3}
x = io.read("*l")
if x == "Gold" then
table.insert(bag,gold)
print("You took the " .. gold.name .. ".")
end
Obviously, writing a line like this with every single object in the game would be very... exhausting--especially since I think I'll be able to use this solution for not just taking items but movement from room to room using a reverse lookup with each room's (x,y) coordinates. Anyone have any ideas on how to make a more flexible system that can find a table by the player typing in one of its variables? Thanks in advance!
-blockchainporter
This doesn't directly answer your question as you asked it, but I think it would serve the purpose of what you are trying to do. I create a table called 'loot' which can hold many objects, and the player can place any of these in their 'bag' by typing the name.
bag = {}
loot = {
{name="Gold", qty=3},
{name="Axe", qty=1},
}
print("What are you trying to take?")
x = io.read("*l")
i = 1
while loot[i] do
if (x == loot[i].name) then
table.insert(bag, table.remove(loot,i))
else
i = i + 1
end
end
For bonus points, you could check 'bag' to see if the player has some of that item already and then just update the quantity...
while loot[i] do
if (x == loot[i].name) then
j, found = 1, nil
while bag[j] do
if (x == bag[j].name) then
found = true
bag[j].qty = bag[j].qty + loot[i].qty
table.remove(loot,i)
end
j = j + 1
end
if (not found) then
table.insert(bag, table.remove(loot,i))
end
else
i = i + 1
end
end
Again, this isn't a 'reverse lookup' solution like you asked for... but I think it is closer to what you are trying to do by letting a user choose to loot something.
My disclaimer is that I don't use IO functions in my own lua usage, so I have to assume that your x = io.read("*l") is correct.
PS. If you only ever want objects to have a name and qty, and never any other properties (like condition, enchantment, or whatever) then you could also simplify my solution by using key/val pairs:
bag = {}
loot = { ["Gold"] = 3, ["Axe"] = 1 }
print("What are you trying to take?")
x = io.read("*l")
for name, qty in pairs(loot) do
if x == name then
bag.name = (bag.name or 0) + qty
loot.name = nil
end
end
I have a few notes to start before I specifically address your question. (I just want to do this before I forget, so please bear with me!)
I recommend printing to the terminal using stderr instead of stdout--the Lua function print uses the latter. When I am writing a Lua script, I often create a C-style function called eprintf to print formatted output to stderr. I implement it like this:
local function eprintf(fmt, ...)
io.stderr:write(string.format(fmt, ...))
return
end
Just be aware that, unlike print, this function does not automatically append a newline character to the output string; to do so, remember to put \n at the end of your fmt string.
Next, it may be useful to define a helper function that calls io.read("*l") to get an entire line of input. In writing some example code to help answer your question, I called my function getline--like the C++ function that has similar behavior--and defined it like this:
local function getline()
local read = tostring(io.read("*l"))
return read
end
If I correctly understand what it is you are trying to do, the player will have an inventory--which you have called bag--and he can put items into it by entering item names into stdin. So, for instance, if the player found a treasure chest with gold, a sword, and a potion in it and he wanted to take the gold, he would type Gold into stdin and it would be placed in his inventory.
Based on what you have so far, it looks like you are using Lua tables to create these items: each table has a name index and another called ap; and, if a player's text input matches an item's name, the player picks that up item.
I would recommend creating an Item class, which you could abstract nicely by placing it in its own script and then loading it as needed with require. This is a very basic Item class module I wrote:
----------------
-- Item class --
----------------
local Item = {__name = "Item"}
Item.__metatable = "metatable"
Item.__index = Item
-- __newindex metamethod.
function Item.__newindex(self, k, v)
local err = string.format(
"type `Item` does not have member `%s`",
tostring(k)
)
return error(err, 2)
end
-- Item constructor
function Item.new(name_in, ap_in)
assert((name_in ~= nil) and (ap_in ~= nil))
local self = {
name = name_in,
ap = ap_in
}
return setmetatable(self, Item)
end
return Item
From there, I wrote a main driver to encapsulate some of the behavior you described in your question. (Yes, I know my Lua code looks more like C.)
#!/usr/bin/lua
-------------
-- Modules --
-------------
local Item = assert(require("Item"))
local function eprintf(fmt, ...)
io.stderr:write(string.format(fmt, ...))
return
end
local function printf(fmt, ...)
io.stdout:write(string.format(fmt, ...))
return
end
local function getline()
local read = tostring(io.read("*l"))
return read
end
local function main(argc, argv)
local gold = Item.new("Gold", 3)
printf("gold.name = %s\ngold.ap = %i\n", gold.name, gold.ap)
return 0
end
main(#arg, arg)
Now, as for the reverse search which you described, at this point all you should have to do is check the user's input against an Item's name. Here it is in the main function:
local function main(argc, argv)
local gold = Item.new("Gold", 3)
local bag = {}
eprintf("What are you trying to take? ")
local input = getline()
if (input == gold.name) then
table.insert(bag, gold)
eprintf("You took the %s.\n", gold.name)
else
eprintf("Unrecognized item `%s`.\n", input)
end
return 0
end
I hope this helps!
I am using Gideros and getting this error:
main.lua:47: attempt to index a nil value
stack traceback:
main.lua:47: in function 'func'
[string "compatibility.lua"]:36: in function <[string "compatibility.lua"]:35>
I have this piece of code and as soon as the text is displayed, it gives me the above mentioned error:How can I fix this?
function onEnter()
function youLoose()
local font2 = TTFont.new("billo.ttf", 20, "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
LooserText = TextField.new(font2, "You Loose , Try AGAIN?")
LooserText:setPosition(100, 100)
stage:addChild(LooserText)
Timer = Timer.delayedCall(1000, removing)
end --line 36
end
function removing()
LooserText:getParent():removeChild(LooserText) --line 47
end
The index nil error means that on that line you are probably getting nil as a return value from LooserText:getParent().
Why you would be getting nil for that I can't tell you other than presumably because it doesn't have one.
The documentation indicates that there is no error condition for Stage.addChild except that the object added must be a Sprite. TextField inherits Sprite so there is no apparent reason for you to get this error. However, you should not re-assign the return value of delayedCall to a global variable of same name as the Timer class, this could affect other parts of the application. Since you don't use the returned Timer instance, I have removed the assignment. Also, if the stage:addChild succeeded then the removing can use stage. One thing that is strange is that your onEnter just defines youLose() but does not call it or return it, is this part of code you ommitted? In any case, you need to add some sanity checks to verify that what you think is happening is really happening w/r/t child add/remove:
function onEnter()
function youLoose()
local font2 = TTFont.new("billo.ttf", 20, "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
LoserText = TextField.new(font2, "You Lose , Try AGAIN?")
LoserText:setPosition(100, 100)
print('Stage num children:' .. stage:getNumChildren())
stage:addChild(LoserText)
print('Stage num children:' .. stage:getNumChildren())
print('LoserText is stage child #' .. stage:getChildIndex(LoserText))
Timer.delayedCall(1000, removing)
end
end
function removing()
print('Stage num children:' .. stage:getNumChildren())
print('LoserText is stage child #' .. stage:getChildIndex(LoserText))
stage:removeChild(LoserText)
print('Stage num children:' .. stage:getNumChildren())
end
My game engine pushes a value on to the lua stack as a parameter to a function and then invokes it using lua_pcall. The lua code will run and call additional lua functions. Eventually this lua code will invoke a C function. Is it possible for this function to retrieve the value that was originally pushed on to the stack?
Its like this:
<engine function A>
pushes parameter value X on to stack for lua
<lua func>
<lua func>
<lua func>
<engine function B>
can I extract the values X that was pushed by function A here?
Yes, with a combination of getinfo, getlocal and getupvalue you can get all that information (you can even change those values using set* functions).
Here is a fragment from MobDebug that returns stack information along with a table of locals and upvalues at each level. The variables at each level will be indexed in the same order they appear in the code (starting from parameters). For each get* function you can use their C equivalents (lua_getinfo, lua_getlocal, and lua_getupvalue), but the logic should be exactly the same.
local function stack(start)
local function vars(f)
local func = debug.getinfo(f, "f").func
local i = 1
local locals = {}
while true do
local name, value = debug.getlocal(f, i)
if not name then break end
if string.sub(name, 1, 1) ~= '(' then locals[name] = {value, tostring(value)} end
i = i + 1
end
i = 1
local ups = {}
while func and true do -- check for func as it may be nil for tail calls
local name, value = debug.getupvalue(func, i)
if not name then break end
ups[name] = {value, tostring(value)}
i = i + 1
end
return locals, ups
end
local stack = {}
for i = (start or 0), 100 do
local source = debug.getinfo(i, "Snl")
if not source then break end
table.insert(stack, {
{source.name, source.source, source.linedefined,
source.currentline, source.what, source.namewhat, source.short_src},
vars(i+1)})
if source.what == 'main' then break end
end
return stack
end
I'm using a proprietary platform that reported memory usage in realtime on screen. I decided to use a Class.lua I found on http://lua-users.org/wiki/SimpleLuaClasses
However, I noticed memory issues when purging object created by this using a simple Account class. Specifically, I would start with say 146k of memory used, create 1000 objects of a class that just holds an integer instance variable and store each object into a table.
The memory used is now 300k
I would then exit, iterating through the table and setting each element in the table to nil. But would never get back the 146k, usually after this I am left using 210k or something similar. If I run the load sequence again during the same session, it does not exceed 300k so it is not a memory leak.
I have tried creating 1000 integers in a table and setting these to nil, which does give me back 146k.
In addition I've tried a simpler class file (Account2.lua) that doesn't rely on a class.lua. This still incurs memory fragmentation but not as much as the one that uses Class.lua
Can anybody explain what is going on here? How can I purge these objects and get back the memory?
here is the code
--------Class.lua------
-- class.lua
-- Compatible with Lua 5.1 (not 5.0).
--http://lua-users.org/wiki/SimpleLuaClasses
function class(base,ctor)
local c = {} -- a new class instance
if not ctor and type(base) == 'function' then
ctor = base
base = nil
elseif type(base) == 'table' then
-- our new class is a shallow copy of the base class!
for i,v in pairs(base) do
c[i] = v
end
c._base = base
end
-- the class will be the metatable for all its objects,
-- and they will look up their methods in it.
c.__index = c
-- expose a ctor which can be called by ()
local mt = {}
mt.__call = function(class_tbl,...)
local obj = {}
setmetatable(obj,c)
if ctor then
ctor(obj,...)
else
-- make sure that any stuff from the base class is initialized!
if base and base.init then
base.init(obj,...)
end
end
return obj
end
c.init = ctor
c.instanceOf = function(self,klass)
local m = getmetatable(self)
while m do
if m == klass then return true end
m = m._base
end
return false
end
setmetatable(c,mt)
return c
end
--------Account.lua------
--Import Class template
require 'class'
local classname = "Account"
--Declare class Constructor
Account = class(function(acc,balance)
--Instance variables declared here.
if(balance ~= nil)then
acc.balance = balance
else
--default value
acc.balance = 2097
end
acc.classname = classname
end)
--------Account2.lua------
local account2 = {}
account2.classname = "unnamed"
account2.balance = 2097
-----------Constructor 1
do
local metatable = {
__index = account2;
}
function Account2()
return setmetatable({}, metatable);
end
end
--------Main.lua------
require 'Account'
require 'Account2'
MAX_OBJ = 5000;
test_value = 1000;
Obj_Table = {};
MODE_ACC0 = 0 --integers
MODE_ACC1 = 1 --Account
MODE_ACC2 = 2 --Account2
TEST_MODE = MODE_ACC0;
Lua_mem = 0;
function Load()
for i=1, MAX_OBJ do
if(TEST_MODE == MODE_ACC0 )then
table.insert(Obj_Table, test_value);
elseif(TEST_MODE == MODE_ACC1 )then
table.insert(Obj_Table, Account(test_value)); --Account.lua
elseif(TEST_MODE == MODE_ACC2 )then
table.insert(Obj_Table, Account2()); --Account2.lua
Obj_Table[i].balance = test_value;
end
end
end
function Purge()
--metatable purge
if(TEST_MODE ~= MODE_ACC0)then
--purge stage 0:
print("set each elements metatable to nil")
for i=1, MAX_OBJ do
setmetatable(Obj_Table[i], nil);
end
end
--purge stage 1:
print("set table element to nil")
for i=1, MAX_OBJ do
Obj_Table[i] = nil;
end
--purge stage 2:
print("start table.remove...");
for i=1, MAX_OBJ do
table.remove(Obj_Table, i);
end
print("...end table.remove");
--purge stage 3:
print("create new object_table {}");
Obj_Table= {};
--purge stage 4:
print("collectgarbage('collect')");
collectgarbage('collect');
end
--Loop callback, called every tick
function OnUpdate()
Lua_mem = collectgarbage('count');
collectgarbage('collect');
end
--Loop rendering callback
function OnRender()
DrawText(Lua_mem );
end
-------------------
--NOTE:
--code starts in idle awaiting input from user
--On first input, runs Load(), on exit runs Purge()
--Where DrawText() draws the string parameter passed, to screen.
--Update
I've updated the code with suggestions from comments below, and will post my findings later today.
--Update 2
Well I've tried the above code, and it does seem collectgarbage("count") reports lua giving me back all the memory in all three scenarios.
Here are my results for collectgarbage('count')
ACC0
- On start: 25.567K used
- On Load: 89.334K used
- On Purge: 25.567K used
ACC1
- On start: 25.567K used
- On Load: 440.567k used
- On Purge: 25.567K used
ACC2
- On start: 25.327K used
- On Load: 245.34K used
- On Purge: 25.327K used
You need to force the garbage collector to reclaim the memory (see collectgarbage("collect")).
Main.lua:
--purge stage 0:
print("set each elements metatable to nil")
for i=1, MAX_OBJ do
setmetatable(Obj_Table[i], nil);
end
According to the documentation of Lua you can not reset a tables metatable by trying to set it to nil. It just equals the function getmetatable(). So the objects keep being linked.
Most dynamic languages don't really release memory back to system, but keep it ready for future allocations instead. Try to create some objects after Lua reported memory decrease - Lua should use this freed memory it kept to yourself and platform memory consumption won't increase.