PeachGaming

TrainControl Server Beta

Oct 6th, 2019
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.42 KB | None | 0 0
  1. --PeachMaster's MTC and Digital Interlocking System: A system for MTC and W-MTC, but this one is for standard MTC
  2. --Hi! you are not supposted to access this file. get out debil cyka blyat
  3. --...unless you know what you're doing. I mean, why are you doing this? This file isn't really for editing.
  4. --You get what you get and you don't throw a fit. That's what my kindergarden teacher said.
  5.  
  6. -- Menu API provided by cyanisaac and ProjectB, licensed under the MIT license.
  7. --JSON API provided by ElvishJerricco.
  8. --Initalize all the things!
  9. --Initalize signalblocks
  10. --TrainControl 1.1
  11. --Use one channel instead of multiple for signal communications
  12. local sbraw = fs.open("signalDatabase", "r")
  13. local cdraw = fs.open("computerdatabase", "r")
  14. local sraw = fs.open("system", "r")
  15. local craw = fs.open("config", "r")
  16. os.loadAPI("menu")
  17. local signalBlocks = textutils.unserialise(sbraw.readAll())
  18. local system = sraw.readAll()
  19. local computerDatabase = textutils.unserialise(cdraw.readAll())
  20. local config
  21. local clientsDoneInSelfTest = {}
  22. local radio = peripheral.find("pdmInstructionRadio")
  23. local sendQueue
  24. sbraw.close()
  25. sraw.close()
  26. cdraw.close()
  27. local modem = peripheral.find("modem")
  28. if modem == nil then
  29. error("TrainControl cannot continue because a modem has not been found.")
  30. end
  31.  
  32. if fs.exists("menu") == false then
  33. print("Downloading menu API..stand by..")
  34. shell.run("pastebin get UK4ATXvH menu")
  35. sleep(1)
  36. end
  37.  
  38. if fs.exists("json") == false then
  39. print("Downloading JSON API..stand by..")
  40. shell.run("pastebin get 4nRg9CHU json")
  41. sleep(1)
  42. end
  43.  
  44. if fs.exists("encrypt") == false then
  45. print("Downloading encryption API...stand by..")
  46. shell.run("pastebin get WRTfH0yx encrypt")
  47. sleep(1)
  48. end
  49.  
  50.  
  51.  
  52.  
  53. os.loadAPI("menu")
  54. os.loadAPI("json")
  55. os.loadAPI("encrypt")
  56.  
  57.  
  58. --Oh yeah, don't forget about the main functions.
  59.  
  60. local function setup()
  61. local madeConfig = {}
  62. term.clear()
  63. term.setCursorPos(1,1)
  64. print("Please set a name for this system for identification (ex. railroad/divison name): ")
  65. local systemName = read()
  66. madeConfig["SystemName"] = systemName
  67. menu.doInfoScreen("Welcome to TrainControl!", "Hi, Welcome! This will help you set up the program to get your trains running safely.")
  68. local theMenu = {"Modem using Rednet (most recommended)", "Bundled Redstone", "Redstone (least recommended, don't use it)"}
  69. madeConfig["SignalConnectionType"] = menu.doMenu("TrainControl Setup | Signal Connection Type", theMenu)
  70. theMenu = {"MTC", "W-MTC", "Don't use it"}
  71. madeConfig["UseMTC"] = menu.doMenu("TrainControl Setup | MTC Type", theMenu)
  72.  
  73. while true do
  74. term.clear()
  75. term.setCursorPos(1,1)
  76.  
  77. print("Please define a channel for Modem communications. It doesn't really matter which one you choose, as long as it's not being used for something else.")
  78. local ModemChannel = read()
  79. local hmm = tonumber(ModemChannel)
  80. if hmm ~= nil then
  81.  
  82. if hmm > 65535 then
  83.  
  84. print("That was not a valid channel. Channels cannot as be higher than 65535.")
  85. else
  86. madeConfig["ModemChannel"] = hmm
  87. break
  88. end
  89.  
  90. else
  91. print("That was not a valid channel. Channels must be numbers and as high as 65535.")
  92. end
  93. end
  94.  
  95. term.clear()
  96. term.setCursorPos(1,1)
  97. print("Please define a channel for Terminal communications. It doesn't really matter which one you choose, as long as it's not being used for something else.")
  98. local terminalChannel = read()
  99. madeConfig["TerminalChannel"] = terminalChannel
  100.  
  101. term.clear()
  102. term.setCursorPos(1,1)
  103.  
  104.  
  105.  
  106. menu.doInfoScreen("Setup Complete!", "TrainControl will start after you press ENTER.")
  107. print(textutils.serialise(madeConfig))
  108. config = madeConfig
  109. local writeConfig = fs.open("config", "w")
  110. writeConfig.write(textutils.serialise(config))
  111. writeConfig.close()
  112. sleep(2)
  113.  
  114.  
  115. end
  116.  
  117. local function getSomethingFromTable(theTable, thingWanted) -- A workaround to crappy CC/Lua. >:(
  118. for k, v in pairs(theTable) do
  119. if k == thingWanted then
  120. return v
  121. end
  122. end
  123. end
  124.  
  125. local function saveTableFile(path, watchuwant) -- Quicker way to do things w o a h
  126. local handle = fs.open(path, "w")
  127. handle.write(textutils.serialise(whatchuwant))
  128. handle.close()
  129. end
  130.  
  131. local function loadTableFile(path) -- Quiciker way to do things w o a h
  132. local handle = fs.open(path, "r")
  133. local thing = textutils.unserialise(handle.readAll())
  134. handle.close()
  135. return thing
  136. end
  137.  
  138.  
  139. local function doEncrypt(thing1)
  140.  
  141. -- local ok = encrypt.encrypt(thing1, "kgkg499tgi34ikg39koowklfow0o349")
  142. --return ok
  143. return thing1
  144. end
  145.  
  146. local function doDecrypt(thing)
  147. -- local ok = encrypt.decrypt(thing, "kgkg499tgi34ikg39koowklfow0o349")
  148. -- return ok
  149. return thing
  150. end
  151.  
  152.  
  153. local function controlSignals()
  154. --Signal status meanings:
  155. --1 = Unoccupied, green
  156. --2 = Unoccupied, yellow (train in next block so use caution)
  157. --3 = Occupied, train is in it.
  158.  
  159. --Reload the signaldatabase, just in case anything was changed.
  160. signalDatabase = loadTableFile("signalDatabase")
  161. if config.SignalConnectionType == 1 then
  162.  
  163. --Connection type is Modem based, so do everything modem related here.
  164. local event, side, sendChannel, replyChannel, message, distance = os.pullEvent()
  165.  
  166. if event == "modem_message" then
  167. local response = doDecrypt(message)
  168.  
  169. if response.funct == "blockOccupied" then
  170. signalBlocks[response.source].status = 3
  171.  
  172. if getSomethingFromTable(signalBlocks[response.source], "prev") ~= "none" then
  173. local previousSignal = getSomethingFromTable(signalBlocks[response.source], "prev")
  174.  
  175. if getSomethingFromTable(signalBlocks[response.source], "prev").status ~= 3 then signalBlocks[previousSignal].status = 2 end
  176. print("Sending a signal update to the previous signal.")
  177. modem.transmit(config["ModemChannel"], config["ModemChannel"], doEncrypt({funct = "updateSignalStatus", signalStatus = getSomethingFromTable(signalBlocks, previousSignal).status, to = getSomethingFromTable(signalBlocks, previousSignal).name}))
  178. end
  179.  
  180. print(response.source.." is occupied. ")
  181.  
  182. end
  183. if response.funct == "blockReleased" then
  184. print(response.source)
  185. signalBlocks[response.source].status = 1
  186. print(response.source.." is released.")
  187.  
  188. if getSomethingFromTable(signalBlocks[response.source], "prev") ~= "none" then
  189. local previousSignal = getSomethingFromTable(signalBlocks[response.source], "prev")
  190. if getSomethingFromTable(signalBlocks[response.source], "prev").status ~= 3 then signalBlocks[previousSignal].status = 1 end
  191. print("Sending signalupdate to the previous signal.")
  192. modem.transmit(config["ModemChannel"], config["ModemChannel"], doEncrypt({funct = "updateSignalStatus", signalStatus = getSomethingFromTable(signalBlocks, previousSignal).status, to = getSomethingFromTable(signalBlocks, previousSignal).name}))
  193. end
  194.  
  195. end
  196. if getSomethingFromTable(signalBlocks[response.source], "next") ~= "none" and signalBlocks[response.source].occupiedBy ~= nil and config["UseMTC"] == 2 then
  197. local nextSignal = getSomethingFromTable(signalBlocks[response.source], "next")
  198. print("Sending a signal update for W-MTC to the previous signal. ")
  199. modem.transmit(config["ModemChannel"], config["ModemChannel"], doEncrypt({funct = "updateSignalStatus", signalStatus = getSomethingFromTable(signalBlocks, nextSignal).status, to = getSomethingFromTable(signalBlocks, previousSignal).name, isWMTCOkay = true}))
  200. else
  201. modem.transmit(config["ModemChannel"], config["ModemChannel"], doEncrypt({funct = "updateSignalStatus", signalStatus = getSomethingFromTable(signalBlocks, nextSignal).status, to = getSomethingFromTable(signalBlocks, previousSignal).name, isWMTCOkay = false}))
  202. end
  203.  
  204. if response.funct == "switchOccupied" then
  205. print(response.source.. " is occupied!")
  206. signalBlocks[response.source].status = 1
  207.  
  208.  
  209. end
  210.  
  211. if response.funct == "switchReleased" then
  212. print(response.source.. "is released!")
  213. signalBlocks[response.source].status = 0
  214. end
  215.  
  216. if response.funct == "setSwitchStatus" then
  217. --owo
  218. modem.transmit(getSomethingFromTable(tonumber(config["ModemChannel"]), tonumber(config["ModemChannel"]), encrypt(textutils.serialise({funct = "updateSwitchStatus", switchStatus = response.switchStatus})))
  219. end
  220.  
  221. --Alright, we got that, now send it to the signals.
  222. if response.source ~= "Terminal" then
  223. modem.transmit(config["ModemChannel"], config["ModemChannel"], doEncrypt({funct = "updateSignalStatus", signalStatus = getSomethingFromTable(signalBlocks, response.source).status, to = getSomethingFromTable(signalBlocks, response.source).name, isWMTCOkay = getSomethingFromTable(signalBlocks, response.source).isWMTCOkay}))
  224. end
  225. if config["UseMTC"] == 2 then
  226. --Alright..W-MTC on..generate a MTC data packet.
  227. local speedLimit1
  228. local nextSpeedLimit1
  229. local speedChange1
  230. local changeX
  231. local changeY
  232. local changeZ
  233. local endSoon1
  234. local xStopPoint
  235. local yStopPoint
  236. local zStopPoint
  237. local mtcStats
  238. local nextSignal = getSomethingFromTable(signalBlocks[response.source], "next")
  239. if getSomethingFromTable(signalBlocks[nextSignal], "status") == 3 then
  240. speedLimit = getSomethingFromTable(signalBlocks[response.source], "yellowSpeedLimit")
  241. endSoon = true
  242. xStopPoint = getSomethingFromTable(signalBlocks[nextSignal], "positionX")
  243. yStopPoint = getSomethingFromTable(signalBlocks[nextSignal], "positionY")
  244. zStopPoint = getSomethingFromTable(signalBlocks[nextSignal], "positionZ")
  245. end
  246. if getSomethingFromTable(signalBlocks[nextSignal], "status") == 2 then
  247. nextSpeedLimit = getSomethingFromTable(signalBlocks[response.source], "yellowSpeedLimit")
  248. speedChange = true
  249. changeX = getSomethingFromTable(signalBlocks[nextSignal], "positionX")
  250. changeY = getSomethingFromTable(signalBlocks[nextSignal], "positionY")
  251. changeZ = getSomethingFromTable(signalBlocks[nextSignal], "positionZ")
  252. end
  253.  
  254. --Alright..generate the JSON.
  255. local send = {speedLimit = speedLimit1, nextSpeedLimit = nextSpeedLimit1, speedChange = speedChange1, endSoon = endSoon1}
  256.  
  257. if endSoon1 then
  258. send["xStopPoint"] = xStopPoint
  259. send["yStopPoint"] = yStopPoint
  260. send["zStopPoint"] = zStopPoint
  261. end
  262.  
  263. if getSomethingFromTable(signalBlocks[response.source], "next") == "none" then
  264. mtcStat = 2
  265. send["mtcStatus"] = mtcStat
  266. end
  267.  
  268. if speedChange1 then
  269. send["nextSpeedLimitChangeX"] = changeX
  270. send["nextSpeedLimitChangeY"] = changeY
  271. send["nextSpeedLimitChangeZ"] = changeZ
  272. end
  273. --Is it done? Okay, print it just in case.
  274. print(textutils.serialise(send))
  275. --Okay, it's finally done, put it into the queue.
  276. if signalBlocks[response.source].occupiedBy ~= nil then
  277.  
  278. signalBlocks[response.source].sendTo = {funct = "sendToTrain", sendTo = signalBlocks[response.source].occupiedBy, send1 = send}
  279. end
  280. end
  281. --Also, finally, save it to the file so it can be used later.
  282. -- saveTableFile("signaldatabase", signalDatabase)
  283. if response.funct == "radio_message" then
  284. --Okay, it came from a train. Let's check it out.
  285. local response1 = response.message
  286. print(textutils.serialise(response1))
  287. if response1.funct == "attemptConnection" then
  288. --Attempting..alright..welcome!
  289. --Give temp data, actual limits will be sent on the next update
  290. local send = {funct = "startlevel2", speedLimit = 60, nextSpeedLimit = 0, speedChange = false, stationStopSoon = false, mtcStatus = 1 }
  291.  
  292. end
  293.  
  294. if response1.funct == "update" then
  295. --Great, an update! There may have been something you have missed, so I'm going to send it to you.
  296. signalBlocks[response.signalBlock].occupiedBy = response.sendChannel
  297.  
  298. if signalBlocks[response.signalBlock].sendTo ~= nil then
  299. modem.transmit(signalBlock[response.signalBlock].wirelessRadioChannel, modem["ModemChannel"], signalBlocks[response.source].sendTo)
  300. end
  301.  
  302. end
  303.  
  304. if response1.funct == "disconnect" then
  305.  
  306. end
  307.  
  308. end
  309.  
  310. end
  311.  
  312. --No? it's not a modem message? Then maybe it's something else.
  313.  
  314.  
  315. end
  316. end
  317.  
  318. local function starts_with(str, start)
  319. return str:sub(1, #start) == start
  320. end
  321.  
  322. local function ends_with(str, ending)
  323. return ending == "" or str:sub(-#ending) == ending
  324. end
  325.  
  326. local function powerUpSelfTest()
  327.  
  328.  
  329. --Okay, host the system via rednet.
  330.  
  331. --...test for all of them.
  332. if config.SignalConnectionType == 1 then
  333. --rednet.send(72, {71, "test", "test!!!"})
  334.  
  335. for key,value in pairs( computerDatabase ) do
  336. local send = doEncrypt({funct = "attemptConnection", to = key})
  337. print("Attempting connection to "..key)
  338. modem.transmit(tonumber(config["ModemChannel"]), tonumber(config["ModemChannel"]), send)
  339.  
  340. --Wait for a response, but also there's a timeout.
  341. local timeout = os.startTimer(15)
  342. while true do
  343. local event = {os.pullEvent()}
  344. if event[1] == "modem_message" then
  345. --Decode the response.
  346. local response = doDecrypt(event[5])
  347. if response.funct == "ok" then
  348. print("Connection to "..response.source.."is okay.")
  349. table.insert(clientsDoneInSelfTest, response.source)
  350. break
  351. end
  352. elseif event[1] == "timer" and event[2] == timeout then
  353. print("Connection to "..key.." aborted because it took too long.")
  354.  
  355. return false
  356. end
  357.  
  358. end
  359.  
  360. end
  361.  
  362. end
  363. return true
  364. end
  365.  
  366.  
  367.  
  368.  
  369.  
  370.  
  371.  
  372. ---..initalized? Great! now print stuff.
  373. term.setCursorPos(1,1)
  374. print(fs.exists("config") )
  375. if fs.exists("config") then
  376. local craw = fs.open("config", "r")
  377. local theconfig = textutils.unserialise(craw.readAll())
  378. config = theconfig
  379. craw.close()
  380. else
  381. setup()
  382. end
  383. term.clear()
  384. term.setTextColor(colors.green)
  385. textutils.slowPrint("PeachMaster's MTC and Digital Interlocking System", 15)
  386. print("This copy is for: "..getSomethingFromTable(config, "SystemName"))
  387. term.setTextColor(colors.white)
  388. modem.open(tonumber(config["ModemChannel"]))
  389. modem.open(tonumber(config["TerminalChannel"]))
  390. if powerUpSelfTest() then
  391. print("Power Up Self Test completed succesfully!")
  392. while true do
  393. controlSignals()
  394. end
  395.  
  396. else
  397.  
  398. end
Add Comment
Please, Sign In to add comment