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

A computer to control others remotely over rednet

Started by todo, 25 October 2015 - 02:58 AM
todo #1
Posted 25 October 2015 - 03:58 AM
Hi,

I have a mp world with a couple of friends where we have a big underground laboratory with different rooms and such.
At the entrance to each room I've added computers with a very simple program that shows the name of that room as text on a connected monitor.
Our doors are also opened/closed by a small cc program I wrote which just checks for a redstone input from pressure plates and then turns on/off a few drawbridges from tinker's construct.

I've now gotten that (I think at least :)/>) amazing idea to have some sort of Main Control room where I have a computer which is connected via rednet to all the other computers and which is able
to change the text on each monitor and lock the doors if need be. Think; Laboratory Lockdown - Nobody enters/leaves! (I like giving my minecraft builds some life/story behind it :D/>)
I've been trying hard to figure out how to do this best with my very limited knowledge with CC and Lua.
One thing I have a hard time figuring out is that when my doors is looking for a redstone event all the time, how will it be able to get commands from a remote computer?

So my big question is if some of you guys could help me out, and give me some pointers to what kind of stuff I need to look into to make this possible.
I'm not asking for a finished program that does exactly what I'm talking about, but maybe some links to good tutorials about this stuff, or perhaps even some finished programs some of you/others already made
that would work with a few tweaks.
Just about anything would be a huge help :)/>

Oh, and btw these a the two simple programs I made to control the doors and display the text on the monitors if you need to see those:
Pretty horrific stuff I know! :P/>

Doors

rs.setOutput("left", true)
rs.setOutput("right", true)
while true do
  --wait for a redstone event.
  local event = os.pullEvent("redstone")
  --test for input
  local BState=rs.getInput("back")
  local FState=rs.getInput("front")
  --if true
  if BState or FState then
	rs.setOutput("left", false)
	rs.setOutput("right", false)
	sleep(3)
	rs.setOutput("left", true)
	rs.setOutput("right", true)
	sleep(3)
  end
end

Monitors

monitors = {
peripheral.wrap("left");
peripheral.wrap("right");
--For monitors on each side of computer
}
function allMonitorsClear()
  for i=1,#monitors do
monitors[i].clear()
  end
end
function header(height, text, tSize, color)
  for i=1,#monitors do
   w, h = monitors[i].getSize()
   monitors[i].setTextScale(tSize)
   monitors[i].setTextColor(color)
   monitors[i].setCursorPos((w-string.len(text))/2+1, height)
   monitors[i].write(text)
  end
end
--placeholder is needed for first line (cant figure why?)
--everytime I log in or server restarts the first line is all broken without it
--Seems like it have something to do with w-string.len(text))/2+1
header(1, "ph", 2, colors.lime)
allMonitorsClear()
header(1, "AE2", 2, colors.lime)
header(2, "Control", 2, colors.lime)

Sorry about any poor grammar, English isn't my native language :)/>

Thanks,
-todo

Here is a few screenies so you have an idea of what I am talking about:

A few of the monitors I would love to be able to change the text on when in "lockdown" :D/>, including the big monitor which is just running a "screensaver" I found on these forums a while back


A couple of monitors down a hall


And this is the door using drawbridges which I would like to be able to lock from the remote computer
Lupus590 #2
Posted 25 October 2015 - 04:19 PM
rather than wait for a redstone event, wait for any event and then check what type of event it is
todo #3
Posted 25 October 2015 - 07:54 PM
rather than wait for a redstone event, wait for any event and then check what type of event it is

See, that's what makes this so hard for me… I would've never thought about that. I mean it makes a lot of sense.
So am I right when I say that I need to make some kind of "client" program for the text monitors and door program which is waiting for any event from the "server" computer and then set up a If statement to tell it what to do if it's a rednet event or if it's a redstone signal coming in?
Lupus590 #4
Posted 25 October 2015 - 09:44 PM
yes, you can modify your doors program in your original post
Edited on 25 October 2015 - 08:44 PM
Bomb Bloke #5
Posted 26 October 2015 - 03:50 AM
The trick with events is that most anything that "waits" for anything is using events to do it. For example, when you call sleep(), the function then goes off and calls os.startTimer() for you and then waits for the resulting timer event to appear in the event queue. rednet.receive() also uses a timer (if you specify a time-out value), and returns based on whether it spots the timer event first, or a rednet_message event.

Events are pulled from the front of the queue (by yielding - os.pullEvent() is basically a simple wrapper function for coroutine.yield()), so if sleep() is trying to get its timer event, any events that it pulls out before that's found are simply discarded. You can hence miss redstone / rednet / whatever events while sleeping, for instance.

One way around this is to manually rig your code to set up and listen for not only redstone and rednet_message events, but for timer events as well (as opposed to just calling sleep()). Another is to use the parallel API, which allows you to run multiple functions "side by side", each getting their own version of the event queue - if you call sleep() within one, that won't stop the other from being able to get the rednet events it wants, for example.

local function doRedstoneStuff()
  while true do
    --wait for a redstone event.
    local event = os.pullEvent("redstone")
    -- etc
  end
end

local function doRednetStuff()
  while true do
    --wait for a rednet message.
    local id, msg = rednet.receive()
    -- etc
  end
end

parallel.waitForAny(doRedstoneStuff, doRednetStuff)

This technique is also handy when using turtles with rednet, as most functions in the turtle API also yield (in order to pull events indicating whether the attempted action worked or not).

I'd also suggest altering the redstone loop:

while true do
  while not (rs.getInput("back") or rs.getInput("front")) do
    os.pullEvent("redstone")
  end

  rs.setOutput("left", false)
  rs.setOutput("right", false)

  sleep(3)

  while rs.getInput("back") or rs.getInput("front") do
    os.pullEvent("redstone")
  end

  rs.setOutput("left", true)
  rs.setOutput("right", true)
end
Edited on 26 October 2015 - 03:02 AM
todo #6
Posted 26 October 2015 - 02:00 PM
-snip-

This is amazing, thank you! That parallel API looks very powerful.

I did some testing yesterday, but I just couldn't figure out how to make it work properly.
Your first code makes a lot more sense though, so I'm probably gonna scratch mine and try again :D/>

Here is mine, but I can already see problems with it compared to yours.


while true do
  local event = os.pullEvent()
if event == "redstone" then
  local rsState=rs.getInput("back")
  if rsState then
   print("Redstone from back changed!")
   rs.setOutput("top", true)
   sleep(3)
   rs.setOutput("top", false)
  end
elseif event == "modem_message" then
  print("Modem Trying to connect!")
  -- message?
end
end

Again, thank you :)/>
Lupus590 #7
Posted 26 October 2015 - 09:48 PM
os.pull event returns multiple values. The first is the event type, the rest is stuff about the event, including your rednet message
todo #8
Posted 26 October 2015 - 10:31 PM
os.pull event returns multiple values. The first is the event type, the rest is stuff about the event, including your rednet message

Aah I see, so if we take my code I would have to put another parameter after event, something like this:


local event, message = os.pullEvent()

and then use the message string in my modem part?
Bomb Bloke #9
Posted 26 October 2015 - 10:48 PM
Sorta. modem_messages give you their type, the side of the modem the message came from, the channel the message was sent to, the channel the sender recommends you reply on, and then the message (and after that the distance of the sending computer, though you likely won't need to capture that).

So you might do:

local event = {os.pullEvent()}

This takes everything the event returned and dumps it into a table, which the "event" variable will point to. event[1] will then be the event type, event[2] will have the side the message was received on, etc through to event[5], which'll have the message.

if event[1] == "modem_message" then
   -- Do stuff with event[5].

If the other system is using rednet.send() to trigger these messages, then you'd be better off looking for rednet_message events, not modem_message events.

if event[1] == "rednet_message" then
   -- Do stuff with event[3].
Edited on 26 October 2015 - 09:50 PM
todo #10
Posted 26 October 2015 - 11:34 PM
Ah okay, so the [n] is pretty much just the row of the table and I am then able to "pick and choose" what to use? Sorry, like you can hear I'm at the very beginning of learning lua :D/>, although I enjoy it quite a bit :D/>
I'll try and figure out how to make this little program, even though I might return with a few newb questions again :)/>

Thanks both of you.
Bomb Bloke #11
Posted 27 October 2015 - 12:07 AM
Ah okay, so the [n] is pretty much just the row of the table and I am then able to "pick and choose" what to use?

Yep, just like your "monitors" table.