This is a read-only snapshot of the ComputerCraft forums,
taken in April 2020.
[Lua][Red Net][Programming] Red Net Question
Started by EmTeaKay, 21 June 2012 - 12:59 AMPosted 21 June 2012 - 02:59 AM
How can I type a message and check for a rednet message at the same time?
Posted 21 June 2012 - 09:52 AM
it is possible using coroutines here is an example of a simple send receive program. just type the message you want to send and it will send it for you. if you leave the to : section blank it will broadcast.
(THIS has only been tested on off line) Please report any bugs to me and i will do what i can to fix them.
(THIS has only been tested on off line) Please report any bugs to me and i will do what i can to fix them.
Spoiler
function readADV( _sReplaceChar, _tHistory ) -- slightly modified read function credit to dan200 for original
term.setCursorBlink( true )
local sLine = ""
local nHistoryPos = nil
local nPos = 0
if _sReplaceChar then
_sReplaceChar = string.sub( _sReplaceChar, 1, 1 )
end
local w, h = term.getSize()
local sx, sy = term.getCursorPos()
local function redraw()
local nScroll = 0
if sx + nPos >= w then
nScroll = (sx + nPos) - w
end
term.setCursorPos( sx, sy )
term.write( string.rep(" ", w - sx + 1) )
term.setCursorPos( sx, sy )
if _sReplaceChar then
term.write( string.rep(_sReplaceChar, string.len(sLine) - nScroll) )
else
term.write( string.sub( sLine, nScroll + 1 ) )
end
term.setCursorPos( sx + nPos - nScroll, sy )
end
while true do
local sEvent, param = os.pullEvent()
if sEvent == "char" then
sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )
nPos = nPos + 1
redraw()
elseif sEvent == "key" then
if param == 28 then
-- Enter
break
elseif param == 203 then
-- Left
if nPos > 0 then
nPos = nPos - 1
redraw()
end
elseif param == 205 then
-- Right
if nPos < string.len(sLine) then
nPos = nPos + 1
redraw()
end
elseif param == 200 or param == 208 then
-- Up or down
if _tHistory then
if param == 200 then
-- Up
if nHistoryPos == nil then
if #_tHistory > 0 then
nHistoryPos = #_tHistory
end
elseif nHistoryPos > 1 then
nHistoryPos = nHistoryPos - 1
end
else
-- Down
if nHistoryPos == #_tHistory then
nHistoryPos = nil
elseif nHistoryPos ~= nil then
nHistoryPos = nHistoryPos + 1
end
end
if nHistoryPos then
sLine = _tHistory[nHistoryPos]
nPos = string.len( sLine )
else
sLine = ""
nPos = 0
end
redraw()
end
elseif param == 14 then
-- Backspace
if nPos > 0 then
sLine = string.sub( sLine, 1, nPos - 1 ) .. string.sub( sLine, nPos + 1 )
nPos = nPos - 1
redraw()
end
end
else
redraw()
end
end
term.setCursorBlink( false )
term.setCursorPos( w + 1, sy )
return sLine
end
local function writer()
while true do
coroutine.yield()
term.setCursorPos(1,1)
term.clearLine()
if stat == "to" then
write("To :")
elseif stat == "mes" then
write("Mes :")
end
end
end
function writer2()
term.setCursorPos(1,1)
term.clearLine()
if stat == "to" then
write("To :")
elseif stat == "mes" then
write("Mes :")
end
end
local function send()
while true do
local sizX,sizY = term.getSize()
term.setCursorPos(6,1)
stat = "to"
writer2()
local id = tonumber(readADV())
term.setCursorPos(6,1)
stat = "mes"
writer2()
local message = readADV()
rednet.send(id,message)
end
end
local function recive()
local lastX,lastY = 1,2
while true do
term.setCursorBlink( true )
local event = {coroutine.yield()}
term.setCursorBlink( false )
if event[1] == "rednet_message" then
local sizX,sizY = term.getSize()
term.setCursorPos(1,lastY)
print("Frm: "..event[2].." Dist: "..event[4].."M Mes: "..event[3])
lastX,lastY = term.getCursorPos()
end
end
end
local function openRednet()
local listOfSides = rs.getSides()
for i = 1,6 do
if peripheral.isPresent(listOfSides[i]) and peripheral.getType(listOfSides[i]) == "modem" then
rednet.open(listOfSides[i])
return listOfSides[i]
end
end
end
modemOn = openRednet()
if modemOn == nil then
print("No WIFI Modem")
error()
else
print("Opened wifi on "..modemOn.." side")
end
term.clear()
term.setCursorPos(1,1)
local stat = nil
local reciveHandel = coroutine.create(recive)
local writerHandel = coroutine.create(writer)
local sendHandel = coroutine.create(send)
while true do -- start a loop
local e,e1,e2,e3,e4,e5 = os.pullEvent()
coroutine.resume(reciveHandel,e,e1,e2,e3,e4,e5)
coroutine.resume(writerHandel)
coroutine.resume(sendHandel,e,e1,e2,e3,e4,e5)
end
Posted 21 June 2012 - 02:27 PM
Wow! That's big and long. That's what I wanted, but not that long. So I'm not going to use that. But, it looks excellent.
Posted 21 June 2012 - 02:50 PM
Looks Great! I will have to use it. EmTeaKay, That length is nothing when you get into servers, FTP, Chat, E-mail…
Posted 21 June 2012 - 02:58 PM
There is not a lot I can do to shorten it. It needs the custom readADV() script to function correctly. I have posted it on http://pastebin.com/ here is the link. http://pastebin.com/EP6TyqtVWow! That's big and long. That's what I wanted, but not that long. So I'm not going to use that. But, it looks excellent.
in computer craft copy past this in. if the http api is active your computer will automatically download my program to the computer you are using.
pastebin get EP6TyqtV BasicIRC
the main problem is that read() is not designed to work in a coroutine and you need your own ver to make it interruptible (when a message arrives.)Thanks.Looks Great! I will have to use it. EmTeaKay, That length is nothing when you get into servers, FTP, Chat, E-mail…
Posted 21 June 2012 - 05:09 PM
I have timed some lines that are not requited (sort of)
IRC lite
that is the smallest I can make if I'm shore that other's could make a shorter ver But for now this is as small as I can make it without sacrificing functionality. I have saved 44 lines from 185 to 141 .
IRC lite
Spoiler
function readADV() -- slightly modified read function credit to dan200 for original
term.setCursorBlink( true )
local sLine = ""
local nPos = 0
local w, h = term.getSize()
local sx, sy = term.getCursorPos()
local function redraw()
local nScroll = 0
if sx + nPos >= w then
nScroll = (sx + nPos) - w
end
term.setCursorPos( sx, sy )
term.write( string.rep(" ", w - sx + 1) )
term.setCursorPos( sx, sy )
term.write( string.sub( sLine, nScroll + 1 ) )
term.setCursorPos( sx + nPos - nScroll, sy )
end
while true do
local sEvent, param = os.pullEvent()
if sEvent == "char" then
sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 )
nPos = nPos + 1
redraw()
elseif sEvent == "key" then
if param == 28 then
-- Enter
break
elseif param == 203 then
-- Left
if nPos > 0 then
nPos = nPos - 1
redraw()
end
elseif param == 205 then
-- Right
if nPos < string.len(sLine) then
nPos = nPos + 1
redraw()
end
elseif param == 14 then
-- Backspace
if nPos > 0 then
sLine = string.sub( sLine, 1, nPos - 1 ) .. string.sub( sLine, nPos + 1 )
nPos = nPos - 1
redraw()
end
end
else
redraw()
end
end
term.setCursorBlink( false )
term.setCursorPos( w + 1, sy )
return sLine
end
local function writer()
while true do
coroutine.yield()
writer2()
end
end
function writer2()
term.setCursorPos(1,1)
term.clearLine()
if stat == "to" then
write("To :")
elseif stat == "mes" then
write("Mes :")
end
end
local function send()
while true do
local sizX,sizY = term.getSize()
term.setCursorPos(6,1)
stat = "to"
writer2()
local id = tonumber(readADV())
term.setCursorPos(6,1)
stat = "mes"
writer2()
local message = readADV()
rednet.send(id,message)
end
end
local function recive()
local lastX,lastY = 1,2
while true do
term.setCursorBlink( true )
local event = {coroutine.yield()}
term.setCursorBlink( false )
if event[1] == "rednet_message" then
local sizX,sizY = term.getSize()
term.setCursorPos(1,lastY)
print("Frm: "..event[2].." Dist: "..event[4].."M Mes: "..event[3])
lastX,lastY = term.getCursorPos()
end
end
end
local function openRednet()
local listOfSides = rs.getSides()
for i = 1,6 do
if peripheral.isPresent(listOfSides[i]) and peripheral.getType(listOfSides[i]) == "modem" then
rednet.open(listOfSides[i])
return listOfSides[i]
end
end
end
modemOn = openRednet()
if not modemOn then
print("No WIFI Modem")
error()
else
print("Opened wifi on "..modemOn.." side")
end
term.clear()
term.setCursorPos(1,1)
local stat = nil
local reciveHandel = coroutine.create(recive)
local writerHandel = coroutine.create(writer)
local sendHandel = coroutine.create(send)
while true do -- start a loop
local e,e1,e2,e3,e4,e5 = os.pullEvent()
coroutine.resume(reciveHandel,e,e1,e2,e3,e4,e5)
coroutine.resume(writerHandel)
coroutine.resume(sendHandel,e,e1,e2,e3,e4,e5)
end
that is the smallest I can make if I'm shore that other's could make a shorter ver But for now this is as small as I can make it without sacrificing functionality. I have saved 44 lines from 185 to 141 .
Posted 21 June 2012 - 05:10 PM
Nice… so what does this do again? i want to know if i can impliment it
Posted 21 June 2012 - 05:17 PM
It allows you to send messages over rednet to any user that is running this while being able to receive messages at the same time. the receiving computers id is specified or left blank for broadcasting. It is a simple system.
It does as this request requires.
It does as this request requires.
How can I type a message and check for a rednet message at the same time?
As for you implementing it go ahead I release this under no licensing do what ever the hell you like with it.Nice… so what does this do again? i want to know if i can impliment it
Posted 21 June 2012 - 05:57 PM
It would be a lot easier if there were some kind of api to run two functions at the same time…
Oh! wait, there is one: the parallel api.
It would look something like this:
Oh! wait, there is one: the parallel api.
It would look something like this:
local function send()
local msg = read()
rednet.broadcast(msg) -- you can change it to send to an specific id
end
local function receive()
local id, msg = rednet.receive()
-- do whatever you want with the message
end
parallel.waitForAny(send, receive)
So good Dan added this to CC :P/>/>Posted 21 June 2012 - 06:12 PM
It would be a lot easier if there were some kind of api to run two functions at the same time…
Oh! wait, there is one: the parallel api.
It would look something like this:So good Dan added this to CC :P/>/>local function send() local msg = read() rednet.broadcast(msg) -- you can change it to send to an specific id end local function receive() local id, msg = rednet.receive() -- do whatever you want with the message end parallel.waitForAny(send, receive)
a this only broadcasts
b have you tryed to use read in a coroutine before also what happens if you are mid message and you recive a message. there are many things you are not taking into consideration there.
I would like to expand my programing skill and knowledge could you please post a working system using the above that doesn't cut you off mid message and updates the screen correctly.
Posted 21 June 2012 - 06:31 PM
That was just an example of how you can use it (actually it would just work to send/receive once, since there's no loop), but it wouldn't be to hard to make it work correctly.
This is a more complete example:
This is a more complete example:
local nW, nH = term.getSize()
local function send()
while true do
term.setCursorPos(1, nH - 1)
term.clearLine()
local msg = read()
rednet.broadcast(msg) -- you could change this to rednet.send() and use a predefined id, or make the user input the id.
end
end
local function receive()
while true do
local id, msg = rednet.receive()
local x, y = term.getCursorPos()
term.setCursorPos(1, 1) -- write messages on the first line
print(id, ": ", msg)
term.setCurorPos(x, y)
end
end
parallel.waitForAny(send, receive)
There's still some things that would need to be changed, but it should work. It would greatly depend on what you'r trying to do, if you want a chat system, you need to print the messages in the right place, but for other things you might just need to do something for the received message, in that case it's not necesary.Posted 21 June 2012 - 07:18 PM
That was just an example of how you can use it (actually it would just work to send/receive once, since there's no loop), but it wouldn't be to hard to make it work correctly.
This is a more complete example:There's still some things that would need to be changed, but it should work. It would greatly depend on what you'r trying to do, if you want a chat system, you need to print the messages in the right place, but for other things you might just need to do something for the received message, in that case it's not necesary.local nW, nH = term.getSize() local function send() while true do term.setCursorPos(1, nH - 1) term.clearLine() local msg = read() rednet.broadcast(msg) -- you could change this to rednet.send() and use a predefined id, or make the user input the id. end end local function receive() while true do local id, msg = rednet.receive() local x, y = term.getCursorPos() term.setCursorPos(1, 1) -- write messages on the first line print(id, ": ", msg) term.setCurorPos(x, y) end end parallel.waitForAny(send, receive)
He was looking for a program that does what the program I produced does a basic IRC
Wow! That's big and long. That's what I wanted, but not that long. So I'm not going to use that. But, it looks excellent.
so if i add a loop around the "parallel.waitForAny(send, receive)" line the program will run till it hits a time limit on the rednet.receive() function or a message is received or a message is typed and sent. Going by your code if you receive a message or the time limit runs down while in the process of sending the message you were writing would be lost. This is why I chose to use coroutines directly instead of the parallel system witch is based on them anyway.
Could you please try my program and then try to replicate its functionality with parallel function. By my understanding of lua and coroutine it will not work as you expect it to.
Posted 21 June 2012 - 07:44 PM
Here's an even more complete example:
It's not tested, bit it should let you send and receive messages. The received messages are wrote to a new line. If the screen is full, it clears it and starts writing messages from the start (not the best, but it's the easiest solution I found).
local nScreenW, nScreenH = term.getSize()
local nLine = 0
local function clear()
term.clear()
term.setCursorPos(1, 1)
end
local function connect()
for _,s in ipairs(rs.getSides()) do
if peripheral.isPresent(s) and peripheral.getType(s) == "modem" then
rednet.open(side)
return true
end
end
return false
end
local function send()
while true do
term.setCursorPos(1, nScreenH - 1)
local msg = read()
term.setCursorPos(1, nScreenH - 1)
term.clearLine()
write("To: ")
local id = tonumber(read())
if id then
rednet.send(id, msg)
end
end
end
local function receive()
while true do
local id, msg = rednet.receive()
local x, y = term.getCursorPos()
if nLine >= nScreenH then
for i = 1, nScreenH - 2 do
term.setCursorPos(1, i)
term.clearLine()
end
nLine = 1
end
term.setCursorPos(1, nLine)
nLine = nLine + print(id, ": ", msg)
term.setCursorPos(x, y)
end
end
if not connect() then
print("No modem found")
return
end
clear()
parallel.waitForAny(send, receive)
Still not perfect, and needs some changes, but I don't have time now to do it.It's not tested, bit it should let you send and receive messages. The received messages are wrote to a new line. If the screen is full, it clears it and starts writing messages from the start (not the best, but it's the easiest solution I found).
Posted 21 June 2012 - 08:28 PM
one bug rednet.open(side) should be rednet.open(s) and text over writes the test you are typing.
I concede it is possible to use parallel.waitForAny() for this but equally it would work with parallel.waitForAll()
this program demonstrates some of the short falls for the reed function. it doesn't redraw a the screen unless you have made a change. so it will not update when test is dumped on top of it. this is why my code is so long as i have to include a modified reed function.
I would like to see a finished polished ver of this code. also I request you try mine to see how I coped with the various problems like text over write.
I concede it is possible to use parallel.waitForAny() for this but equally it would work with parallel.waitForAll()
this program demonstrates some of the short falls for the reed function. it doesn't redraw a the screen unless you have made a change. so it will not update when test is dumped on top of it. this is why my code is so long as i have to include a modified reed function.
I would like to see a finished polished ver of this code. also I request you try mine to see how I coped with the various problems like text over write.
Posted 21 June 2012 - 09:20 PM
In this case, it's the same, since none of the functions stop/returns.I concede it is possible to use parallel.waitForAny() for this but equally it would work with parallel.waitForAll()
You'r right, read() has some problems when doing something like this, that's why I don't think this is the best way to do a chat program (neither coroutines nor parallel), since all you have to do is handle some events. I made a chat program and it doesn't use coroutines or parallel (wich are basically the same), it's on the program library if you want to take a look at it.this program demonstrates some of the short falls for the reed function. it doesn't redraw a the screen unless you have made a change. so it will not update when test is dumped on top of it. this is why my code is so long as i have to include a modified reed function.
For other things it would be better/easier to use parallel. Mostly when you don't need to use read() or redraw the screen.
I don't think I will finish that code, since it was just an example, and I don't think it's the best way to do this.I would like to see a finished polished ver of this code. also I request you try mine to see how I coped with the various problems like text over write.
I readed your code, and there's a lot of things that could be improved, and some things that has to be removed. Like:
local function writer()
while true do
coroutine.yield()
writer2()
end
end
why do you even need that function?Posted 21 June 2012 - 10:59 PM
Not sure why your readADV function is so long. Here's how Bosschat handles multitasking and writing characters.
function writeChar(char) --Future update will be able to make longer messages
term.setCursorPos(charNum + string.len(username) + 3, cursorY) --right now limit is 48 minus username length and 2 extra characters
if charNum <= 48 - (string.len(username) + 2) then --so it all fits on-screen
term.write(char)
message[charNum] = char
charNum = charNum + 1
end
end
function handleEvent()
local evt, p1, p2 = os.pullEvent()
if evt == "char" then
writeChar(p1)
elseif evt == "key" then
handleKey(p1)
elseif evt == "rednet_message" then
messageReceive(p1, p2)
elseif evt == "timer" then
handleTimers(p1)
elseif evt == "peripheral" then
handleModem(p1)
updatePast("Modem detected on " .. p1) --custom function that will display messages, pass message as parameter.
updatePast("Network restored.")
elseif evt == "peripheral_detach" then
updatePast("Modem detached on " .. p1)
updatePast("No network connectivity.")
end
end
Also, small preview for next update.Posted 22 June 2012 - 04:01 AM
this function is run as a coroutine .It prints the to : or the mes : on the screen so it over writes every update instead of just ounce.This is where it is activated.In this case, it's the same, since none of the functions stop/returns.
You'r right, read() has some problems when doing something like this, that's why I don't think this is the best way to do a chat program (neither coroutines nor parallel), since all you have to do is handle some events. I made a chat program and it doesn't use coroutines or parallel (wich are basically the same), it's on the program library if you want to take a look at it.
For other things it would be better/easier to use parallel. Mostly when you don't need to use read() or redraw the screen.
I don't think I will finish that code, since it was just an example, and I don't think it's the best way to do this.
I readed your code, and there's a lot of things that could be improved, and some things that has to be removed. Like:why do you even need that function?local function writer() while true do coroutine.yield() writer2() end end
local reciveHandel = coroutine.create(recive)
local writerHandel = coroutine.create(writer) -- writer function starts run here
local sendHandel = coroutine.create(send)
while true do -- start a loop
local e,e1,e2,e3,e4,e5 = os.pullEvent()
coroutine.resume(reciveHandel,e,e1,e2,e3,e4,e5)
coroutine.resume(writerHandel) -- write function over writes test printed by recive function
coroutine.resume(sendHandel,e,e1,e2,e3,e4,e5) -- reed over writes all end result all information stays where I want it on the screen.
end
so you could remove it but the to : or mes : would be over write by part of a received message as the messages scroll up.
readADV() is a direct copy of the read function with a few pieces removed (unnecessary in this task) and a change made to how it redraws the screen allowing it to redraw always instead of just after chars are added or removed. so it is huge because of this. if read was more coroutine friendlily i would not have had to include that at all. also my system can Handel large messages up to the full screen size - one row. There is no user name thought as this is low level basic communications / network testing.Not sure why your readADV function is so long. Here's how Bosschat handles multitasking and writing characters.
Posted 22 June 2012 - 05:03 PM
I know when it's used and what it does, but it's still unnecesary. If you handle the rewrite, you don't need that. If you'r going to rewrite the read function, then just don't use coroutines and handle the events yourself, it's easier and shorter to write.this function is run as a coroutine .It prints the to : or the mes : on the screen so it over writes every update instead of just ounce.This is where it is activated.In this case, it's the same, since none of the functions stop/returns.
You'r right, read() has some problems when doing something like this, that's why I don't think this is the best way to do a chat program (neither coroutines nor parallel), since all you have to do is handle some events. I made a chat program and it doesn't use coroutines or parallel (wich are basically the same), it's on the program library if you want to take a look at it.
For other things it would be better/easier to use parallel. Mostly when you don't need to use read() or redraw the screen.
I don't think I will finish that code, since it was just an example, and I don't think it's the best way to do this.
I readed your code, and there's a lot of things that could be improved, and some things that has to be removed. Like:why do you even need that function?local function writer() while true do coroutine.yield() writer2() end end
local reciveHandel = coroutine.create(recive) local writerHandel = coroutine.create(writer) -- writer function starts run here local sendHandel = coroutine.create(send) while true do -- start a loop local e,e1,e2,e3,e4,e5 = os.pullEvent() coroutine.resume(reciveHandel,e,e1,e2,e3,e4,e5) coroutine.resume(writerHandel) -- write function over writes test printed by recive function coroutine.resume(sendHandel,e,e1,e2,e3,e4,e5) -- reed over writes all end result all information stays where I want it on the screen. end
so you could remove it but the to : or mes : would be over write by part of a received message as the messages scroll up.