Advertisement
HandieAndy

Railcraft Station

Jan 20th, 2017
416
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 9.33 KB | None | 0 0
  1. --Station Program:
  2. --  Keeps track of trains at each track
  3. --  Can choose which train to dispatch
  4. --Constants:
  5. local ticketMachine = peripheral.wrap("back")
  6. local mon
  7. local mon_x, mon_y
  8. local note_block
  9. local stationDisplayOffset = 0
  10. local RedstoneSide = "bottom"
  11. rednet.open("front")
  12. --Station Name:
  13. local STATION_NAME
  14. --Station Dest:
  15. local STATION_DEST
  16. --Server Computer ID:
  17. local SERVER_ID
  18. --File to hold station data:
  19. local STATION_FILE = "stations"
  20. --Protocols:
  21. local METADATA_PROT = "md"
  22. local METADATA_RQ = "rq"
  23. local UPDATE_PROT = "ud"
  24. local UPDATE_RQ = "rq"
  25. local DISPATCH_PROT = "dp"
  26. local REQUEST_PROT = "rq"
  27. local STATION_LIST_PROT = "sl"
  28. local STATION_LIST_RQ = "rq"
  29. local REBOOT_PROT = "rb"
  30. local REBOOT_RQ = "rb"
  31. --Data on each track available for control.
  32. local tracks
  33. --Data for every station in the network, for dispatch choices.
  34. local stations
  35. --Returns the number of items in a table.
  36. function tableSize(tbl)
  37.     local count = 0
  38.     for i in pairs(tbl) do count = count + 1 end
  39.     return count
  40. end
  41.  
  42. --Gets the information of a train at a specific track.
  43. function scanTrainAtTrack(trackNumber)
  44.     local trainData = {}
  45.     local ids = tracks[trackNumber].sensor.getMinecartIds()
  46.     for i in pairs(ids) do
  47.         local success, rawdata = pcall(tracks[trackNumber].sensor.getMinecartData, ids[i])
  48.         if (success) then
  49.             local data = rawdata.all()
  50.             --Test if the locomotive is numbered, and check that it is above this sensor.
  51.             if ((string.len(data.name) < 4) and (data.position.x < 1) and (data.position.z < 1) and (data.position.x > -1) and (data.position.z > -1)) then
  52.                 tracks[trackNumber].train = tonumber(data.name)
  53.                 return
  54.             end
  55.         end
  56.     end
  57.     tracks[trackNumber].train = -1
  58. end
  59.  
  60. --Scans all tracks and saves the data to the trains table.
  61. function scanAllTracks()
  62.     for i in pairs(tracks) do
  63.         scanTrainAtTrack(i)
  64.     end
  65. end
  66.  
  67. --Handles ticket creation failure.
  68. function onTicketMachineFailure()
  69.     print("Unable to create ticket.")
  70. end
  71.  
  72. --Creates a ticket for a destination and sends it to a train, the train departs.
  73. function dispatchTrack(dest, trackNumber)
  74.     local success = ticketMachine.createTicket(dest, 1)
  75.     if (not success) then
  76.         onTicketMachineFailure()
  77.         return
  78.     end
  79.     rs.setBundledOutput(RedstoneSide, tracks[trackNumber].ticketColor)
  80.     os.sleep(1)
  81.     rs.setBundledOutput(RedstoneSide, 0)
  82.     print("Train "..tracks[trackNumber].train.." dispatched to "..dest..".")
  83. end
  84.  
  85. --Dispatches the given train by ID
  86. function dispatchTrain(dest, trainId)
  87.     for i in pairs(tracks) do
  88.         if (tracks[i].train == trainId) then
  89.             dispatchTrack(dest, i)
  90.         end
  91.     end
  92. end
  93.  
  94. --Dispatches the first train available to leave.
  95. function dispatchFirstAvailableTrain(dest)
  96.     for i in pairs(tracks) do
  97.         if (tracks[i].train ~= -1) then
  98.             dispatchTrack(dest, i)
  99.             return
  100.         end
  101.     end
  102.     print("No train available to dispatch.")
  103. end
  104.  
  105. --Sends station name, dest, ID, and track number to the server, upon request.
  106. function sendMetadata()
  107.     rednet.send(SERVER_ID, {name = STATION_NAME, dest = STATION_DEST, id = os.getComputerID(), trackCount = tableSize(tracks)}, METADATA_PROT)
  108.     print("Metadata sent to the server.")
  109. end
  110.  
  111. --Sends an updated list of trains at this station to the server.
  112. function sendUpdate()
  113.     local trains = {}
  114.     for i in pairs(tracks) do
  115.         if (tracks[i].train ~= -1) then
  116.             table.insert(trains, tracks[i].train)
  117.         end
  118.     end
  119.     rednet.send(SERVER_ID, trains, UPDATE_PROT)
  120.     print("Update sent to server.")
  121. end
  122.  
  123. --Sends a request to the server to send a train to a new destination.
  124. function sendRequest(dest)
  125.     rednet.send(SERVER_ID, dest, REQUEST_PROT)
  126.     print("Sent request for a train to "..dest)
  127. end
  128.  
  129. --Initializes the station.
  130. function init()
  131.     term.clear()
  132.     term.setCursorPos(1,1)
  133.     print("Initializing station...")
  134.     local f = fs.open("station_config", "r")
  135.     local config = textutils.unserialize(f.readAll())
  136.     f.close()
  137.     STATION_NAME = config.name
  138.     STATION_DEST = config.dest
  139.     SERVER_ID = config.server_id
  140.     mon = peripheral.wrap(config.monitor_id)
  141.     note_block = peripheral.wrap(config.note_block_id)
  142.     mon_x, mon_y = mon.getSize()
  143.     tracks = config.tracks
  144.     for i in pairs(tracks) do
  145.         tracks[i].sensor = peripheral.wrap(tracks[i].sensor_id)
  146.     end
  147.     sendMetadata()
  148.     scanAllTracks()
  149.     printTrains()
  150.     sendUpdate()
  151. end
  152.  
  153. --Sets up the monitor display.
  154. function initMonitor()
  155.     mon.setBackgroundColor(colors.white)
  156.     mon.clear()
  157.     mon.setCursorPos(1,1)
  158.     mon.setTextColor(colors.lightGray)
  159.     mon.setBackgroundColor(colors.black)
  160.     for i = 1, mon_x do
  161.         mon.setCursorPos(i,1)
  162.         mon.write(" ")
  163.     end
  164.     mon.setCursorPos(1,1)
  165.     mon.write(STATION_NAME)
  166.     mon.setCursorPos(mon_x-1,2)
  167.     mon.setTextColor(colors.white)
  168.     mon.setBackgroundColor(colors.lime)
  169.     mon.write("/\\")
  170.     mon.setBackgroundColor(colors.red)
  171.     mon.setCursorPos(mon_x-1,3)
  172.     mon.write("\\/")
  173.     mon.setTextColor(colors.gray)
  174.     mon.setBackgroundColor(colors.white)
  175.     mon.setCursorPos(1,2)
  176.     mon.write("Click a station to depart.")
  177.     mon.setCursorPos(1,3)
  178.     mon.write("Departing Track: ")
  179.     loadStationList()
  180.     displayStations()
  181. end
  182.  
  183. --Displays the destinations on the screen.
  184. function displayStations()
  185.     mon.setBackgroundColor(colors.white)
  186.     for i=4,mon_y do
  187.         for k=1,mon_x do
  188.             mon.setCursorPos(k,i)
  189.             mon.write(" ")
  190.         end
  191.     end
  192.     for i=1,mon_y-4 do
  193.         mon.setCursorPos(1,i+3)
  194.         if (i % 2 == 0) then
  195.             mon.setTextColor(colors.lightBlue)
  196.             mon.setBackgroundColor(colors.gray)
  197.         else
  198.             mon.setTextColor(colors.blue)
  199.             mon.setBackgroundColor(colors.lightGray)
  200.         end
  201.         if (i+stationDisplayOffset <= tableSize(stations)) then
  202.             for i=1,mon_x do mon.write(" ") end
  203.             mon.setCursorPos(1,i+3)
  204.             if (stations[i+stationDisplayOffset].dest == STATION_DEST) then
  205.                 mon.setTextColor(colors.magenta)
  206.             end
  207.             mon.write(stations[i+stationDisplayOffset].name)
  208.         end
  209.     end
  210. end
  211.  
  212. --Displays the list of trains at this station.
  213. function printTrains()
  214.     print("Trains:")
  215.     for i in pairs(tracks) do
  216.         if (tracks[i].train ~= -1) then
  217.             print("  Track: "..i.." Train: "..tracks[i].train)
  218.         end
  219.     end
  220. end
  221.  
  222. --Saves the list of stations to a file.
  223. function saveStationList()
  224.     local f = fs.open(STATION_FILE, "w")
  225.     f.write(textutils.serialize(stations))
  226.     f.close()
  227. end
  228.  
  229. --Reads the stations list from a file.
  230. function loadStationList()
  231.     if (not fs.exists(STATION_FILE)) then
  232.         local f = fs.open(STATION_FILE, "w")
  233.         f.write("{}")
  234.         f.close()
  235.         stations = {}
  236.         requestStationList()
  237.     else
  238.         local f = fs.open(STATION_FILE, "r")
  239.         stations = textutils.unserialize(f.readAll())
  240.         f.close()
  241.     end
  242. end
  243.  
  244. --What to do if the server updates the stations list:
  245. function onStationListReceived(newStationList)
  246.     stations = newStationList
  247.     saveStationList()
  248.     displayStations()
  249.     print("  Received updated stations list.")
  250. end
  251.  
  252. --Ask the server for a copy of the stations list.
  253. function requestStationList()
  254.     rednet.send(SERVER_ID, STATION_LIST_RQ, STATION_LIST_PROT)
  255.     print("Requested stations list.")
  256. end
  257.  
  258. --Handles monitor touch events and what to do.
  259. function onMonitorTouch(x,y)
  260.     --Check if the user clicked one of the arrows.
  261.     if ((y < 4) and (x > mon_x-2)) then
  262.         if (y == 2 and stationDisplayOffset > 0) then
  263.         --Clicked up
  264.             stationDisplayOffset = stationDisplayOffset - 1
  265.         elseif (y == 3 and stationDisplayOffset < tableSize(stations)-1) then
  266.         --Clicked down.
  267.             stationDisplayOffset = stationDisplayOffset + 1
  268.         end
  269.         displayStations()
  270.     elseif (y > 3) then
  271.     --Clicked on a station.
  272.         if (stations[y-3+stationDisplayOffset].dest ~= STATION_DEST) then
  273.             sendRequest(stations[y-3+stationDisplayOffset].dest)
  274.         end
  275.     end
  276. end
  277.  
  278. --Handles dispatch requests.
  279. function onDispatchRequestReceived(msg)
  280.     mon.setCursorPos(19,3)
  281.     mon.setTextColor(colors.lime)
  282.     mon.setBackgroundColor(colors.white)
  283.     for i in pairs(tracks) do
  284.         if (tracks[i].train == msg[2]) then
  285.             mon.write(tonumber(string.format("%." .. (0) .. "f", i)))
  286.             note_block.setPitch(20)
  287.             for k=1,i do
  288.                 note_block.triggerNote()
  289.                 os.sleep(0.4)
  290.             end
  291.             os.sleep(1)
  292.         end
  293.     end
  294.     dispatchTrain(msg[1],msg[2])
  295. end
  296.  
  297. --What to do after a train has been detected leaving.
  298. function onTrainDeparture(trackNumber)
  299.     mon.setBackgroundColor(colors.white)
  300.     mon.setCursorPos(19,3)
  301.     mon.write("   ")
  302.     tracks[trackNumber].train = -1
  303. end
  304.  
  305. --Listens for events. Main event handler.
  306. function eventHandler()
  307.     local event,p1,p2,p3,p4,p5 = os.pullEvent()
  308.     if (event == "rednet_message") then
  309.         if (p3 == METADATA_PROT and p2 == METADATA_RQ) then
  310.             sendMetadata()
  311.             sendUpdate()
  312.         elseif (p3 == UPDATE_PROT and p2 == UPDATE_RQ) then
  313.             sendUpdate()
  314.         elseif (p3 == DISPATCH_PROT) then
  315.             --Dispatch message: destination and train id
  316.             onDispatchRequestReceived(p2)
  317.         elseif (p3 == STATION_LIST_PROT) then
  318.             --Update list of stations.
  319.             onStationListReceived(p2)
  320.         elseif (p3 == REBOOT_PROT and p2 == REBOOT_RQ) then
  321.             os.reboot()
  322.         end
  323.     elseif (event == "redstone") then
  324.         for i in pairs(tracks) do
  325.             --Test if a train arrived.
  326.             if (tracks[i].train == -1 and rs.testBundledInput(RedstoneSide, tracks[i].detectorColor)) then
  327.                 scanTrainAtTrack(i)
  328.                 sendUpdate()
  329.             --Test if a train left.
  330.             elseif (tracks[i].train ~= -1 and rs.testBundledInput(RedstoneSide, tracks[i].detectorColor) == false) then
  331.                 onTrainDeparture(i)
  332.             end
  333.         end
  334.     elseif (event == "monitor_touch") then
  335.         onMonitorTouch(p2,p3)
  336.     end
  337. end
  338.  
  339. --Main Loop:
  340. init()
  341. initMonitor()
  342. while (true) do
  343.     eventHandler()
  344. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement