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

ModemRS Program

Started by Jyzarc, 13 December 2013 - 10:01 PM
Jyzarc #1
Posted 13 December 2013 - 11:01 PM
Version 2.0.1 is out!

Video demonstrating this: http://www.youtube.com/watch?v=86Zv5jY5SWQ&feature=youtu.be

So, this is a fairly simple program that provides a way to send digital redstone, bundled redstone, and analog redstone over modems, including wireless modems. I know this program isn't that useful or amazing, but it took a while to make, and I am happy with how it turned out, so I thought I would share.

How it works:
SpoilerThere are two types of computers, inputs and outputs. Input computers wait for a redstone signal on every side in the redstone sides array, and then transmit a message to all of the channels in the channels array, containing the digital, analog, and bundled signals. The output computers wait for a modem message from any connected channels, then it outputs the bundled signal, and either the digital or analog signal depending on if the analog bool variable is true or false, to all of the sides specified.

How to use:
SpoilerThere are only 5 things you have to set up for each computer, the first 5 lines of code, you shouldn't have to edit anything else.

modemSides: This is an array of sides that modems are connected to, most likely you will only have one, but in some cases you may have 2 or more.

Example: local modemSides = {"left","right}

channels: This is an array of connected channels, channels sort of act as frequencies, so an input with channel 1 will not transmit to an output with channel 2, but an input with channel 1 and 2 will. And an output with 1 and 2 will be receive messages from both

Example: local channels = {1,2}

computerType: Either "input" or "output", pretty straightforward

Example: local computerType = "input"

rs_sides: For input computers this is a list of sides it will accept redstone signals from, for outputs it is the list of sides it will output signals to.

Example: local rs_sides = {"left"}

analog: This is a boolean variable that only applies to output computers, if true this will output the analog signal (1-15), if false it will just output true or false.

Example: local analog = true

Download:
http://pastebin.com/VY7nxFy7

Known issues:
SpoilerNone at the moment

Changelog:
Spoiler2.0.1:
Fixed crash when setting the stack to 0

2.0.0:
Full rewrite
code cleaned up
fixed: signals overwrite eachother
fixed: if a modem is missing program crashes
fixed: bundled cable signals from different computers added incorrectly

Legal Stuff:
SpoilerI cant be bothered to release this under a license. Basically just do whatever you want, use my source code, redistribute, modify, sell it for doge coins, I really don't care.

Feel free to report bugs or suggest features, enjoy!
Edited on 19 December 2013 - 09:29 PM
theoriginalbit #2
Posted 14 December 2013 - 01:57 AM
Just as a point of learning for you in Lua you can define multiple variables on a single line, for example like so

local sChannel, rChannel = 1, 2
Also this means you could condense these

local event
local sModemSide
local sChannel
local replyChannel
local message
local sDistance
local analogNumber
local bundledNumber
local rsState
local i
local x
local y
local bool1
local bool2
local serializedInfo
to this

local event, sModemSide, sChannel, replyChannel, message, sDistance, analogNumber, bundledNumber, rsState, i, x, y, bool1, bool2, serializedInfo
and it will still mean that all these variables are initialised in the local scope.

Other points that could be made are with the addBools function

local function addBools(bool1,bool2)
  if bool1 or bool2 then
	return true
  else
	return false
  end
end
this is one area that always annoys me when people do it, a conditional statement resolves to a boolean so it knows which branch to execute, so having a conditional that then just returns a boolean is pointless, just return the conditional

local function addBools(b1, b2)
  return b1 or b2
end

I'm glad to see that you're making use of local variables and functions, it's very rare to see in new programmers!

Other points I wish to bring up is any variables that are defined in a function's signature are already local meaning they are not required to be defined elsewhere
the following is pointless unless you plan on using x,y elsewhere, in which case inside the function `foo` there will be a naming conflict if you wish to use the x/y from the scope above.

local x, y
local function foo(x,y)
  print(x,y)
end
the same also applies for, for loops… the variable defined in the for loop initialiser is localised to that loop.

it should be noted that this

local rs_info = {bundled,analog,state,ID}
is equivalent to this

local rs_info = {}
since the variables inside the table constructor are nil variables. did you mean to initialise keys here?

second to last, you should also attempt to check if the peripheral on the given sides are actually modems before wrapping them, with peripheral.getType

Lastly, it should be noted that if you don't wish to accept a return value (after the one you want) you don't have to, it should also be noted that it is general convention for variables you wish not to use are named with _ for example this

event,sModemSide,sChannel,replyChannel,message,sDistance = os.pullEvent("modem_message")
could become this

_, _, _, _, message = os.pullEvent("modem_message")
which makes it much easier for you to see what variables you're wanting… obviously this all comes down to style though.

Overal a good program/api, just a few places that could do with some "spit and polish". I hope everything I've covered above makes sense and helps you in your future programmes.
Edited on 14 December 2013 - 12:58 AM
Lupus590 #3
Posted 15 December 2013 - 03:05 PM
fix suggestion for know issue.
when an output computer recives a massage to activate redstone, it stores the id of the computer that sent the message (I recommend an array for this).
when an output computer recives a message to deactivate redstone it, it checks the stored ids, if the sender is the last id in the array then the computer deactivates the redstone and removes the id from the array (rouge/sentinal value [suggest -1]), if there is another id in the array then it keeps the redstone on but removes the sender of the off signal.
Jyzarc #4
Posted 17 December 2013 - 08:28 PM
Just as a point of learning for you in Lua you can define multiple variables on a single line, for example like so

local sChannel, rChannel = 1, 2
Also this means you could condense these

local event
local sModemSide
local sChannel
local replyChannel
local message
local sDistance
local analogNumber
local bundledNumber
local rsState
local i
local x
local y
local bool1
local bool2
local serializedInfo
to this

local event, sModemSide, sChannel, replyChannel, message, sDistance, analogNumber, bundledNumber, rsState, i, x, y, bool1, bool2, serializedInfo
and it will still mean that all these variables are initialised in the local scope.

Other points that could be made are with the addBools function

local function addBools(bool1,bool2)
  if bool1 or bool2 then
	return true
  else
	return false
  end
end
this is one area that always annoys me when people do it, a conditional statement resolves to a boolean so it knows which branch to execute, so having a conditional that then just returns a boolean is pointless, just return the conditional

local function addBools(b1, b2)
  return b1 or b2
end

I'm glad to see that you're making use of local variables and functions, it's very rare to see in new programmers!

Other points I wish to bring up is any variables that are defined in a function's signature are already local meaning they are not required to be defined elsewhere
the following is pointless unless you plan on using x,y elsewhere, in which case inside the function `foo` there will be a naming conflict if you wish to use the x/y from the scope above.

local x, y
local function foo(x,y)
  print(x,y)
end
the same also applies for, for loops… the variable defined in the for loop initialiser is localised to that loop.

it should be noted that this

local rs_info = {bundled,analog,state,ID}
is equivalent to this

local rs_info = {}
since the variables inside the table constructor are nil variables. did you mean to initialise keys here?

second to last, you should also attempt to check if the peripheral on the given sides are actually modems before wrapping them, with peripheral.getType

Lastly, it should be noted that if you don't wish to accept a return value (after the one you want) you don't have to, it should also be noted that it is general convention for variables you wish not to use are named with _ for example this

event,sModemSide,sChannel,replyChannel,message,sDistance = os.pullEvent("modem_message")
could become this

_, _, _, _, message = os.pullEvent("modem_message")
which makes it much easier for you to see what variables you're wanting… obviously this all comes down to style though.

Overal a good program/api, just a few places that could do with some "spit and polish". I hope everything I've covered above makes sense and helps you in your future programmes.

1: Yes I am aware, but thats not really my style of code.

2. I don't know what I was thinking. I will definitely fix that

3. I still don't really understand how Lua scope works, I may try to clean some redundancy up.

4. Yeah, again just not my style. I like putting members (even if they are empty) when I declare them

5. I think I have found a good way to do that

6. I was originally planning on possibly using those, but I decided against it and never got around to that.

Thanks for the suggestions!

fix suggestion for know issue.
when an output computer recives a massage to activate redstone, it stores the id of the computer that sent the message (I recommend an array for this).
when an output computer recives a message to deactivate redstone it, it checks the stored ids, if the sender is the last id in the array then the computer deactivates the redstone and removes the id from the array (rouge/sentinal value [suggest -1]), if there is another id in the array then it keeps the redstone on but removes the sender of the off signal.
Thats what I originally was thinking, but it would end up pretty bulky and wouldn't work as well for bundled. However I do have another idea for how to fix it. Basically there will just be a variable that stores how many "true"s or "false"es there are and adds/subtracts. Analog will be a little different. and bundled will be the same except for each individual signal
Lupus590 #5
Posted 18 December 2013 - 09:05 AM
add/subtract?
am I right in thinking:
if there are 4 computers
computer 1 (R1) is the receiver
computers 2-4 are senders (S2-4)
then S2 sends an on signal to R1
R1 adds 1 to a variable to track the state of the redstone, RSState is now 1 (was 0)
because RSState is > 0 redstone is activated by R1
some time later S3 sends an on signal and R1 increments RSState to 2
soon after S2 sends an off signal, R1 decrements RSState to 1
later S4 sends and off signal and R1 decrements RSState to 0
RSState is now = 0 therefore it's not > 0 therefore R1 turns off the redstone

But in a normal redstone OR gate (which I'm assuming you are trying to achieve) R1 would still have active redstone because s3 is still on
this problem is made worse if (continuing from previous scenario) S3 sends an off signal
because of the new off signal R1 will decrease RSState again turning it to -1 from zero
it would then take 2 senders to turn the redstone on

another advantage of recording the id's of the signal senders at the receiver is that you could change the or gate to an and gate or a complex mix of gates
e.g. of complex gate

(S2 And S3) or S4
the above example will turn on if S4 is on or if both S2 and S3 are on

that said about recording the ids, what if a sender (unlabelled) gets destroyed after sending an on signal? the receiver will always be on
with your method you could send another off signal from another computer and then remove the computer or get it to replace the lost one

my method would require the receiver's code to be rewritten or the variables edited (don't ask me how to edit a variable outside of a program i have no idea how to do it, i know it's possible [not sure about in computercraft {although the computers in CC are just bit of memory in your physical machine, if you could identify the bytes in your physical machine that represent the CC computer the you could change the variables (I'm rambling aren't i? [wow, what a lot of brackets])}])

edit: <spelling/grammar corrections - hmm, I still don't have sentences (no full stops) >
Edited on 19 December 2013 - 01:15 PM
Jyzarc #6
Posted 19 December 2013 - 05:29 PM
add/subtract?
am I right in thinking:
if there are 4 computers
computer 1 (R1) is the receiver
computers 2-4 are senders (S2-4)
then S2 sends an on signal to R1
R1 adds 1 to a variable to track the state of the redstone, RSState is now 1 (was 0)
because RSState is > 0 redstone is activated by R1
some time later S3 sends an on signal and R1 increments RSState to 2
soon after S2 sends an off signal, R1 decrements RSState to 1
later S4 sends and off signal and R1 decrements RSState to 0
RSState is now = 0 therefore it's not > 0 therefore R1 turns off the redstone

But in a normal redstone OR gate (which I'm assuming you are trying to achieve) R1 would still have active redstone because s3 is still on
this problem is made worse if (continuing from previous scenario) S3 sends an off signal
because of the new off signal R1 will decrease RSState again turning it to -1 from zero
it would then take 2 senders to turn the redstone on

another advantage of recording the id's of the signal senders at the receiver is that you could change the or gate to an and gate or a complex mix of gates
e.g. of complex gate

(S2 And S3) or S4
the above example will turn on if S4 is on or if both S2 and S3 are on

that said about recording the ids, what if a sender (unlabelled) gets destroyed after sending an on signal? the receiver will always be on
with your method you could send another off signal from another computer and then remove the computer or get it to replace the lost one

my method would require the receiver's code to be rewritten or the variables edited (don't ask me how to edit a variable outside of a program i have no idea how to do it, i know it's possible [not sure about in computercraft {although the computers in CC are just bit of memory in your physical machine, if you could identify the bytes in your physical machine that represent the CC computer the you could change the variables (I'm rambling aren't i? [wow, what a lot of brackets])}])

edit: <spelling/grammar corrections - hmm, I still don't have sentences (no full stops) >

I really dont understand what you are saying. First of all, if a state never turns on then how is it gonna turn off? When the computer turns on it sends the signal to the output computers before it waits for an RS signal change. I have tested the new system quite a bit and it doesnt seem to fail. The idea was not to make an or gate, thats just kind of how it worked out. I originally wanted it to just be a wireless redstone type thing. but then I thought it wouldnt be too hard to make it be able to send or receive from multiple channels. I dont understand what you are saying about editing variables, and if I did it your way I wouldnt be able to detect if a computer got broken, the idea is you set up your computers correctly and if you break one you should just have to restart them all. But my source code is there if you want to edit it and add your own features.

Edit: just updated it, so feel free to try it out and report any bugs to me
Edited on 19 December 2013 - 05:20 PM
theoriginalbit #7
Posted 19 December 2013 - 10:01 PM
since the bundled cable colours are on a binary scale, any reference to this

local bundledValues = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768}
can be replaced with

2^i

EDIT: oh it should also be noted that as of the last few ComputerCraft versions rednet/modem messages can be tables or strings
Edited on 19 December 2013 - 09:03 PM
Bomb Bloke #8
Posted 19 December 2013 - 10:20 PM
since the bundled cable colours are on a binary scale, any reference to this

local bundledValues = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768}
can be replaced with

2^i
2^(i-1). Though this should be slightly more efficient again:

bit.blshift(1,i-1)
Jyzarc #9
Posted 19 December 2013 - 10:31 PM
since the bundled cable colours are on a binary scale, any reference to this

local bundledValues = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768}
can be replaced with

2^i

EDIT: oh it should also be noted that as of the last few ComputerCraft versions rednet/modem messages can be tables or strings
Yeah I actually did that at first, but for some reason it wasn't working properly. I think the first element ended up being .5 or something, which was confusing. and I forgot to try that again before release, I will probably try to do that in the next version. thanks.
Jyzarc #10
Posted 20 December 2013 - 07:27 PM
So now that I have fixed all the bugs, I am going to be adding some basic logic control. At the moment the computer sort of acts as an or gate if it has multiple channels. Instead of being able to set "and" or "or", you will be able to specify how many need to be on, or you can specify a specific amount, or range of RS signals. Bundled will probably be the same. Analog may be based on how strong/weak the signal has to be, but I am not really sure if I should add that. I may also add something that will be able to invert an output or input
theoriginalbit #11
Posted 20 December 2013 - 09:01 PM
2^(i-1). Though this should be slightly more efficient again:

bit.blshift(1,i-1)
Thanks for the correction :)/> That is slightly more efficient, but harder to understand for someone unfamiliar with bit manipulation, I was just more trying to get Jyzarc away from the statically defining of variables and using lots of tables, trying to show that there's other, and sometimes better, ways to do things.
Edited on 20 December 2013 - 08:01 PM
Jyzarc #12
Posted 25 December 2013 - 11:42 AM
The next update is another full rewrite, in addition to code cleanup, it will be a lot more powerful, flexible and easier to use. However it is going to take a while. While this program isn't meant as a "logic gate" program, you will be able to do most basic logic. You will be able to specify how many computers need to be on, and in the future you will be able to specify the ID of the computer.
Edited on 09 January 2014 - 08:02 PM
Jyzarc #13
Posted 09 January 2014 - 09:07 PM
2^(i-1). Though this should be slightly more efficient again:

bit.blshift(1,i-1)
Thanks for the correction :)/> That is slightly more efficient, but harder to understand for someone unfamiliar with bit manipulation, I was just more trying to get Jyzarc away from the statically defining of variables and using lots of tables, trying to show that there's other, and sometimes better, ways to do things.
I will definitely redo that in the next update, I wasn't exactly trying for the most efficient code, just doing what I was comfortable with. But I am trying to focus now on both making the code look a lot nicer. This is a really useful program, even now without logic, but some of my sloppy coding habits are holding it back a bit I think.
Jyzarc #14
Posted 11 January 2014 - 09:05 PM
Well the rewrite is coming slowly but surely. Logic is pretty much done now, I still need to do error handling, startup output, analog and bundled signal support, and commenting. But if you would like to try it out before release it is here: http://pastebin.com/YHmTWFdi