This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
RPMGamer's profile picture

RedNet Emails: Back and Forth messaging

Started by RPMGamer, 14 February 2018 - 09:37 AM
RPMGamer #1
Posted 14 February 2018 - 10:37 AM
Hello, I am making a server that receives rednet messages and sends them out to the specified ID. I realise this has been done before, but I am new and want to create a back and forth messaging system. I have currently developed a system that can send a message, then waits for a reply, stopping you from typing until you get one. I want to be able to send more than 1 message at a time, like you would on your actual computer. By this I mean I want to be able to type on seperate lines, send multiple messages, for example:

Friend: did you see the news last nite?
Friend: night**
Me: Yea I did
Me: Scary right?
Me: I like onions

So you are not limited to send 1 message at a time and then wait for a reply.
Bomb Bloke #2
Posted 14 February 2018 - 11:57 AM
Each of your scripts runs in a co-routine. When a script wants to get some sort of input - be it via the user, a modem, etc - it'll usually "yield", pausing its execution until ComputerCraft resumes it with "event" data. Events detail things like users pressing buttons, modem messages incoming, and so on. Usually, os.pullEvent() is used to yield for event data.

When you call a function like read(), the code within that function pulls key and char events over and over until the user hits enter, and then returns a string describing the buttons pressed. When you call rednet.receive(), the code within that function does something similar, pulling all events from the front of the queue until a rednet_message event appears there.

Functions like read() and rednet.receive() are what we call "event eaters" - new events are added to the end of a queue, and these functions pull and discard all events from the front of that queue until they get to the one they want. If a user types something while your script is executing rednet.receive(), for example, odds are the events for those button presses will be tossed out the window.

There are two ways of dealing with this problem. One is to write your own loop for handling key / char / rednet_message events, one that can handle all the relevant types for your script so that you don't have to call read() / rednet.receive(). read()'s a fairly complex function, though, so re-writing your own version is a fair bit of work.

A much easier way is to run more co-routines within your script, which can be resumed with a copy of all events your main script gets resumed by. If one of these is looking for keyboard events, and one for rednet events, then each can discard the ones it doesn't want without affecting the other.

The parallel API makes this a lot easier: you can pass it multiple functions, and it'll run them as individual co-routines (switching execution between them whenever they pull an event by yielding). Eg:

local function getKeyboardInput()
	while true do
		--# read() messages from the user in front of the computer,
		--# print them to the screen, and send them to the other user.
	end
end

local function getRednetMessages()
	while true do
		--# Listen for rednet messages and print them to the screen.
	end
end

parallel.waitForAny(getKeyboardInput, getRednetMessages) --# Note the lack of brackets after the function names.

The window API is also worth a look - if you have one window for user input and one window for messages, then redirect terminal output from one to the other immediately before and after writing out incoming rednet messages, you'll find it much easier to keep track of where the cursor should be.
RPMGamer #3
Posted 14 February 2018 - 02:52 PM
Thanks! This helped a lot!