Problem:

Elevated High Speed Rail, wanted computer control of multiple switching points, with message routing, configuration files, and local manual control of switch points. Easy to write scripts to automate travel between points on multiplayer world, and GPS enabled all along the route.

Solution:

RailControl 1.0

To Use:

Computer at rail terminal, computers all along the rail line just within range of each other, and computers at switching points all equipped with modems (side doesn't matter).

Each computer needs the terminal numbers to route messages added as 4 digit numeric (ex: terminal 9, entered as 0009). This includes computers that aren't running the program that may want to send or receive messages. Set program as startup and enter information. Once main program is running (routing editing will come up if there is no routeTable file), hiiting 'u' will allow editing the routing table, 'g' will allow you to enter GPS information to allow this computer to act as GPS HOST, and letter for the sides will manually switch on the redstone for that side (first letters except for bottom which is an 'o'). 'x' will exit the program.

To control a switch point near or far, open rednet, send a message of the format "XXXXsb" where XXXX is the terminal side is the side and b is a boolean T or F. Example: rednet.send(7, "0053ft") will communicate to the first relay to send terminal 53 the front redstone needs turned on. sending "XXXXss" will return a status message including GPS coordinates if it is enabled (read code for what the order of the zeroes or ones, or modify to suit yourself).

Play with it, and if you need help, I will do my best… already working on version 2.0:
Next version will have secure mode for controlling that secret door, terminal control for the end stops, and configuration file, version 3 will probably have automatic routing configuration (need to think about that for a while). I will gladly consider ANY feature additions.

Also: If you like my code (or it is just barely acceptable - I see that the copy and paste lost some of the code formatting, blank lines, etc.) and you have ideas or needs that require LUA programming ComputerCraft in a multiplayer environment, contact me privately, I have a bit of free time just now, and I really enjoyed getting this to work.

Thanks for considering,

-Thad (tover153)
Spoiler

--RailControl
--  Local and remote redstone control and GPS HOST replacement
--  pseudo routing table for network management in complex environments
--
--  TODO:
--   add debug mode with various print messages (probably toggle from menu)
--Translate computerID to 4 digits
local function myID()
local holdID = tostring(os.computerID())
local currentLength = string.len(holdID)
for n = 1, (4 - currentLength) do
  holdID = "0" .. holdID
end
return holdID
end
--print header
local function printHeader()
term.clear()
term.setCursorPos(1,1)
print ("Welcome to RailControl")
print ("This program is not Copyright by Thad L. Overturf")
print ("Terminal ", me)
if gpsAvailable then
  print("GPS Enabled - location:", gpsX, ",", gpsY, ",", gpsZ)
end
print ()
print ("(f)ront, (b)ack, (r)ight, (l)eft")
print ("(t)op, and b(o)ttom will toggle sides")
print ()
print ("(g) will setup GPS, (u) will edit routes")
print ("(x) to exit")
end
--Open Modem ("borrowed" from GPS code)
local sOpenedSide = nil
local function open()
local bOpen, sFreeSide = false, nil
for n,sSide in pairs(rs.getSides()) do
  if peripheral.getType( sSide ) == "modem" then
   sFreeSide = sSide
   if rednet.isOpen( sSide ) then
	bOpen = true
	break
   end
  end
end

if not bOpen then
  if sFreeSide then
   print( "No modem active. Opening "..sFreeSide.." modem" )
   rednet.open( sFreeSide )
   sOpenedSide = sFreeSide
   return true
  else
   print( "No modem attached" )
   return false
  end
end
return true
end
--Close Modem (likewise "borrowed")
function close()
if sOpenedSide then
  rednet.close( sOpenedSide )
end
end
--read routing table
local function readRoute()
if  not fs.exists("routeTable") then
  print("No routing table")
  return false
end
r = fs.open("routeTable","r")
routesIn = r.readLine()
r.close()
routes = textutils.unserialize(routesIn)
-- local routeNumber = (string.len(routesIn)) / 4
-- for myCnt = 0, routeNumber - 1 do
  -- routes[myCnt] = tonumber(string.sub(routesIn, (myCnt * 4) + 1, (myCnt * 4)+4))
  -- print(routes[myCnt])
-- end
return true
end
--send to routing members except originator
local function sendRoute(inText)
for n, routesOut in pairs(routes) do
  if tonumber(routesOut) == id then
   print("Skipping")
	else
   rednet.send(tonumber(routesOut), inText)
  end
end
end
--send to All routing members
local function sendRouteAll(inText)
for n, routesOut in pairs(routes) do
  rednet.send(tonumber(routesOut), inText)
end
end
--check if gps available and read
local function openGPS()
if not fs.exists("location") then
  return false
end
g = fs.open("location","r")
gpsString = g.readLine()
gps = textutils.unserialize(gpsString)
gpsX = gps[1]
gpsY = gps[2]
gpsZ = gps[3]
g.close()
return true
end
--create status message
local function makeStatus()
local statusMessage = ""
for n,sSide in pairs(rs.getSides()) do
  --statusMessage = statusMessage .. sSide
  if rs.getOutput( sSide ) == true then
   statusMessage = statusMessage .. "01"
	else
   statusMessage = statusMessage .. "00"
  end
end
if gpsAvailable then
  statusMessage = statusMessage .. gpsX .. "X" .. gpsY .. "Y" .. gpsZ .. "Z"
end
return statusMessage
end
--set all redstones
local function setARS(vValue)
for n,sSide in pairs(rs.getSides()) do
  rs.setOutput(sSide, vValue)
end
end
--set redstone on side to value
local function setRS(sSide, value)
rs.setOutput (sSide, value)
end
--toggle redstone on a side
local function toggleRS(sSide)
if rs.getOutput(sSide) == true then
  rs.setOutput(sSide, false)
else
  rs.setOutput(sSide, true)
end
end
--set up GPS
local function setupGPS()
os.pullEventRaw() -- gets g out of keyboard buffer
gw = fs.open("location","w")
write("X: ")
local sX = read(nil)
write("Y: ")
local sY = read(nil)
write("Z: ")
local sZ = read(nil)
gw.write(textutils.serialize({sX,sY,sZ}))
gw.close()
gpsAvailable = openGPS()
printHeader()
return
end
--edit routes
local function editRoutes(show)
--os.pullEventRaw()
--if  not fs.exists("routeTable") then
-- rr = fs.open("routeTable","w")
-- rr.close()
--end
term.clear()
term.setCursorPos(1,1)
print("You are editing the routing table, you need")
print("at least one entry, entered as 4 digits")
print(" if this computer should route to computer 9")
print(" then enter 0009 as entry 1 in routing table")
print("delete works off of the record number, so to")
print(" delete record number two, just enter 2")
print()
if show then
  print("(l)ist, (a)dd, (d)elete, (w)rite, e(x)it")
end
eEnd = false
while not eEnd do
  local event, param1 = os.pullEvent ("char")
  if param1 == "l" then
   for n, routeArray in pairs(routes) do
	print(n, " ", routeArray)
   end
  end
  if param1 == "w" then
   local numberOfRoutes = 0
   for n,routesInTable in pairs(routes) do
	numberOfRoutes = n
   end
   if numberOfRoutes > 0 then
	gw = fs.open("routeTable","w")
	gw.write(textutils.serialize(routes))
	gw.close()
	if numberOfRoutes == 1 then
	 print (numberOfRoutes, " route written")
	  else
	 print (numberOfRoutes, " routes written")
	end
	 else
	print("There must be entries in the routing table")
   end
  end
  if param1 == "a" then
   local nextNumber = 0
   for n, routeArray in pairs(routes) do
	nextNumber = n
   end
   nextNumber = nextNumber + 1
   local routeToAdd = read()
   routes[nextNumber] = routeToAdd
  end
  if param1 == "d" then
   local numberToDelete = read()
   routes[tonumber(numberToDelete)] = nil
  end
  if param1 == "x" then
   if  not fs.exists("routeTable") then
	print("There must be entries in the routing table")
	 else
	eEnd = true
   end
  end
  print("(l)ist, (a)dd, (d)elete, (w)rite, e(x)it")
end
return true
end
--START PROGRAM
sleep(0.1)
me = myID()
cid = os.computerID()
routes = {}
while not readRoute() do
editRoutes(true)
end
gpsAvailable = openGPS()
printHeader()
if open() then
print("Waiting...")
  else
return
end
--print(makeStatus())
bEnd = false
parallel.waitForAll(
function()
  while not bEnd do
   event, id, text = os.pullEvent()
   if event == "key" then
	--print(id)
	if id == 38 then toggleRS("left") end
	if id == 19 then toggleRS("right") end
	if id == 33 then toggleRS("front") end
	if id == 48 then toggleRS("back") end
	if id == 20 then toggleRS("top") end
	if id == 24 then toggleRS("bottom") end
	if id == 45 then bEnd = true end
	if id == 34 then setupGPS() end
	if id == 22 then
	 editRoutes(false)
	 printHeader()
	end
   end
   if event == "rednet_message" then
	if text == "PING" then
	 if gpsAvailable then
	  rednet.send(id, textutils.serialize({gpsX,gpsY,gpsZ}))
	 end
	end
	dest = string.sub(text, 1, 4)
	cmd = string.sub(text, 5, 6)
	if dest == me then
	 print("Remote Message received from ", id, " - ", cmd)
	 if cmd == "ss" then
	  sleep(0.4)
	  sendRouteAll(makeStatus())
	 end
	 if cmd == "ft" then setRS("front", true) end
	 if cmd == "ff" then setRS("front", false) end
	 if cmd == "bt" then setRS("back", true) end
	 if cmd == "bf" then setRS("back", false) end
	 if cmd == "lt" then setRS("left", true) end
	 if cmd == "lf" then setRS("left", false) end
	 if cmd == "rt" then setRS("right", true) end
	 if cmd == "rf" then setRS("right", false) end
	 if cmd == "tt" then setRS("top", true) end
	 if cmd == "tf" then setRS("top", false) end
	 if cmd == "ot" then setRS("bottom", true) end
	 if cmd == "of" then setRS("bottom", false) end
	 if cmd == "at" then setARS(true) end
	 if cmd == "af" then setARS(false) end
	  else
	 sendRoute(text)
	 sleep (0.4)
	end
   end
  end
  os.pullEventRaw() -- gets x out of keyboard buffer
end
)