Lua making game loop and other functions - lua

So like i have mainloop and many other functions but i cant call them because of there is infinitive loop how can i make them so i can call the functions.
local socket = require("socket")
local function sleep(sec)
socket.select(nil, nil, sec)
end
coroutine.wrap(function()
while true do
sleep(1)
end
end)()
print("bob") -- like here
like in code it doesn't print bob because there is loop is way avoid that i tried using corountines but they didnt work

Normally I would suggest using non-blocking commands, but I'm not certain what socket.select is doing. It appears you are misusing it as a blocking timer.

Related

nodemcu with Lua and 8266 tmr.stop

Note: This is a copy of a question asked here
Hi
I am completely new to EPS8266 and Lua (but not to programming - my first CPU was an 8080...)
Using a nodemcu HUZZA from adafruit
Anyway I am testing some timer stuff and running into this:
tmr.alarm(0, 500, 1, function()
print("I'm here")
tmr.stop(0)
end)
Without the stop, the loop keeps printing, with it the tmr.stop(0) stops. ... so far so good.
But if I want to start the timer again like:
tmr.alarm(0, 500, 1, function()
print("I'm here")
tmr.stop(0)
-- do some stuff
tmr.start(0)
end)
I get an error: PANIC: unprotected error in call to Lua API...
The documentation says that the tmr is still registered when stop is called.
A call to tmr.state(0) does the same. Only tmr.stop(0) seems to works as expected.
Thanks for your thoughts.
The documentation says to no longer use static timers
Static timers are deprecated and will be removed later. Use the OO API initiated with tmr.create().
If you want complete control over when the functions in the timer callback are executed you need a ALARM_SEMI instance upon which you call start whenever needed. It'll fire exactly once for every time you call start on it.
local mytimer = tmr.create()
mytimer:register(500, tmr.ALARM_SEMI, function() print("I'm here") end)
-- do stuff here
-- then whenever needed trigger the timer
mytimer:start()
Note that mytimer is not unregistered and not garbage collected.
Based on the documentation, you need to use tmr.ALARM_SEMI as your alarm mode.
ALARM_SEMI is described by the documentation as:
tmr.ALARM_SEMI manually repeating alarm (call tmr.start() to
restart)
tmr.ALARM_SEMI is equal to 2. Based on that, this should work:
tmr.alarm(0, 500, 2, function()
print("I'm here")
tmr.stop(0)
-- do some stuff
tmr.start(0)
end)

Computercraft lua change value later

ok, Im almost completely new to lua and computercraft but I have alot of creativity. I'm trying to write code that will reprint a variable every second. here is what I have so far:
display = "Loading..."
While true do
sleep(1)
term.clear()
term.setCursorPos(1,1)
print (display)
end
sleep(3)
display = "hello"
I want to use it to render a 2d game, the "display" variable would change often and thus why i want it to be updated every second.
It does indeed refresh every second when I run the code but for some reason I cant seem to get the "display" variable to change after 3 seconds to test it.
What am I doing wrong?
while true is an infinite loop. The script never reaches sleep(3).
Perhaps you want to replace while true with for i=1,3.
I am not experienced in Lua, but this might be a solution: answer on SO
In the UI thread, run:
while ((status=lua_resume(L_coroutine, 0)) == LUA_YIELD) {
semaphore_wait(); /* whatever the appropriate C# call is */
}
"Wait for response" should look something like:
while not results[my_result] do
coroutine.yield()
end
The "incoming message" function should look like the following in Lua:
results[cur_result]=parsed_message

How do I make os.pullEvent not yield?

I'm trying to create a while true do loop, that reacts to clicks, using os.pullEvent, and also updates a monitor.
Problem being, it only updates the screen when I press one of the on screen buttons, and I've found out that's because pullEvent stops the script, until an event is fired.
Is it possible to make it so pullEvent doesn't stop me updating the monitor?
function getClick()
event,side,x,y = os.pullEvent("monitor_touch")
button.checkxy(x,y)
end
local tmp = 0;
while true do
button.label(2, 2, "Test "..tmp)
button.screen()
tmp++
getClick()
end
You can easily use the parallel api to run both codes essentially at the same time. How it works is it runs them in sequence until it hits something that uses os.pullEvent and then swaps over and does the other side, and if both stop at something that does os.pullEvent then it keeps swapping between until one yields and continues from there.
local function getClick()
local event,side,x,y = os.pullEvent("monitor_touch")
buttoncheckxy(x,y)
end
local tmp = 0
local function makeButtons()
while true do
button.label(2,2,"Test "..tmp)
button.screen()
tmp++
sleep(0)
end
end
parallel.waitForAny(getClick,makeButtons)
Now if you notice, first thing, I've made your while loop into a function and added a sleep inside it, so that it yields and allows the program to swap. At the end you see parallel.waitForAny() which runs the two functions that are specified and when one of them finishes, which in this case whenever you click on a button, then it ends. Notice however inside the arguments that I'm not calling the functions, I'm just passing them.
I don't have computercraft handy right now or look up the functions but i know that you can use the function os.startTimer(t) that will cause an event in t seconds (I think it is seconds)
usage:
update_rate = 1
local _timer = os.startTimer(update_rate)
while true do
local event = os.pullEvent()
if event == _timer then
--updte_screen()
_timer = os.startTimer(update_rate)
elseif event == --some oter events you want to take action for
--action()
end
end
note: the code is not tested and I didn't use computercraft in quite a while so pleas correct me if i did a mistake.

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, ...)
-- ...

How do i use socket.select?

I need some help using socket "select" function.
My server code is like this:
while true do
for _,server in pairs(servers) do
local client = server:accept()
client:settimeout(5)
local line, err = client:receive()
if not err then
client:send(line .. "_SERVER_SIDE\n")
else
client:Send("___ERRORPC"..err)
end
client:close()
end
end
But now i want to use the select function instead of make a forever loop like this.
Reading this: http://w3.impa.br/~diego/software/luasocket/socket.html
I know that i can use something simmilar than:
socket.select(servers, nil, 5)
But i donĀ“t know how i can use this on the code above. Can anyone help me?
I will have to use this inside a while true statement?
The reading operation (first parameter) means that i can only make an accept/receive]? And the seconds parameter means that i can only make a send?
As per the documentation, select receives one or two arrays of sockets and returns an array of sockets that can safely be read from without blocking and an array of sockets that can be safely written to without blocking and an array of sockets that can safely be written without blocking. An important point is that the first array is for both server sockets that want you want to call accept on and for client sockets that you want to call receive on.
The seconds parameter is just a timeout for the select. It doesn't have to do with how many operations you can make.
The basic thing you are going to have to change in your code is that when a receive call fails with a timeout, instead or giving an error you should add that socket to the array of sockets that you pass to select. This way you can have select tell you when that socket becomes active again.
From the documentation for select: "calling select with a server socket in the receive parameter before a call to accept does not guarantee accept will return immediately. Use the settimeout method or accept might block forever." This means that you'd need to use settimeout before your accept call, but assuming you have a list of opened connections you can work with in servers table, you can use select in the following way:
local canread = socket.select(servers, nil, 1)
for _,client in ipairs(canread) do
local line, err = client:receive()
if not err then
client:send(line .. "_SERVER_SIDE\n")
else
client:send("___ERRORPC"..err)
end
end
socket.select will block for up to 1 second, but will return sooner if there is a socket from the list you provided that can be read from. You can block indefinitely if you use socket.select(servers, nil, 0); blocking for some short time is useful if you need to do some other work while waiting for the input.
Updated to use ipairs instead of pairs as the returns table is keyed both on numbers as well as on sockets themselves, so if one socket can be read from, the returned array looks like {[1] = sock, [sock] = 1}.
single demo
local server = socket.bind("*",7777)
local client_tab = {}
while true do
-- socket.select first param is a table of connected socket,
-- you want a connected socket,you need to call accept()
-- if you do not want to block,you should call settimeout(seconds)
local recvt = socket.select(client_tab, nil, 1)
server:settimeout(1)
local client = server:accept()
if client then
client_tab[#client_tab+1] = client
end
if #recvt > 0 then
-- read clients in recvt
end
end

Resources