Advertisement
Alakazard12

GlassMon Server

Feb 18th, 2017
187
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 13.20 KB | None | 0 0
  1. local CHANNEL_GLASS = 10033
  2. -- Wireless Init
  3. local modem = peripheral.find("modem")
  4. if not modem then
  5.     printError("no modem attached")
  6.     return
  7. end
  8.  
  9. modem.open(CHANNEL_GLASS)
  10.  
  11.  
  12. local MSG_TYPE_NEW = 0x1
  13. local MSG_TYPE_UPDATE = 0x2
  14. local MSG_TYPE_INIT = 0x3
  15. local MSG_TYPE_LISTENER = 0x4
  16.  
  17. local MSG_REACTOR_SETACTIVE = 0xEE0
  18.  
  19. local MSG_TYPE_REPLY_NEW = 0xFF0
  20.  
  21. -- Glasses Bridge
  22.  
  23. local bridge = peripheral.find("openperipheral_bridge")
  24.  
  25. if not bridge then
  26.     printError("Could not find peripheral bridge!")
  27.     return
  28. end
  29.  
  30.  
  31. local function CalcCenterX(x, width)
  32.     return (width / 2) + x
  33. end
  34. local function CalcCenterY(y, height)
  35.     return (height / 2) + y
  36. end
  37.  
  38. local title_layout = {
  39.     background = {
  40.         type = "box";
  41.         x = 20;
  42.         y = 20;
  43.         width = 100;
  44.         height = 10;
  45.         color = 0x333333;
  46.         opacity = 0.7;
  47.     };
  48.     title = {
  49.         type = "text";
  50.         text = "GlassMon";
  51.         x = CalcCenterX(20, 100);
  52.         y = CalcCenterY(20, 10);
  53.         z = 1;
  54.         scale = 0.7;
  55.         color = 0x7777FF;
  56.         object_anchor = {"MIDDLE", "MIDDLE"};
  57.     };
  58. }
  59.  
  60. local function RenderLayout(layout)
  61.     local objects = {}
  62.  
  63.     for i,v in pairs(layout) do
  64.         local object
  65.         if v.type == "box" then
  66.             object = bridge.addBox(v.x or 0, v.y or 0, v.width or 10, v.height or 10, v.color, v.opacity)
  67.         elseif v.type == "text" then
  68.             object = bridge.addText(v.x or 0, v.y or 0, v.text, v.color)
  69.  
  70.             if v.scale then
  71.                 object.setScale(v.scale)
  72.             end
  73.         else
  74.             return nil, "invalid object type: " .. v.type
  75.         end
  76.  
  77.         if v.object_anchor then
  78.             object.setObjectAnchor(v.object_anchor[1], v.object_anchor[2])
  79.         end
  80.         if v.z then
  81.             object.setZ(v.z)
  82.         end
  83.  
  84.         objects[i] = object
  85.     end
  86.  
  87.     return objects
  88. end
  89.  
  90. local cHeight = 33
  91.  
  92. local function AllocateScreen(width, height)
  93.     local nHeight = cHeight
  94.     cHeight = cHeight + height + 3
  95.     return 20, nHeight
  96. end
  97.  
  98. bridge.clear()
  99.  
  100. local success, err = RenderLayout(title_layout)
  101. if not success then
  102.     pritnError(err)
  103. end
  104.  
  105. bridge.sync()
  106.  
  107. local status_msg = bridge.addText(0, 10, "")
  108. status_msg.setAlignment("MIDDLE", "TOP")
  109. status_msg.setVisible(false)
  110.  
  111.  
  112. -- Components
  113.  
  114. local component_data = {}
  115.  
  116. local lbase = math.log(10)
  117. local si_prefixes = {
  118.     [-4] = "p";
  119.     [-3] = "n";
  120.     [-2] = "u";
  121.     [-1] = "m";
  122.     [0] = "WTF";
  123.     [1] = "k";
  124.     [2] = "M";
  125.     [3] = "G";
  126.     [4] = "T";
  127.     [5] = "P";
  128.     [6] = "E";
  129.     [7] = "Z";
  130.     [8] = "Y";
  131. }
  132. local si_low = -4
  133. local si_high = 8
  134.  
  135. local function Round(number, decimals)
  136.     return math.floor((number * 10^decimals) + 0.5) / 10^decimals
  137. end
  138.  
  139. local function FormatSI(number, unit)
  140.     local mult = 1
  141.     if number < 0 then
  142.         mult = -1
  143.         number = -number
  144.     end
  145.  
  146.     local brack = math.floor((math.log(number) / lbase) / 3)
  147.     brack = math.min(math.max(brack, si_low), si_high)
  148.     if brack == 0 then
  149.         return tostring(mult * Round(number, 3)) .. " " .. unit
  150.     end
  151.  
  152.     number = number / 10^(brack * 3)
  153.     return tostring(Round(mult * number, 3)) .. " " .. si_prefixes[brack] .. unit
  154. end
  155.  
  156. local reactors = {}
  157.  
  158. local component_handlers = {
  159.     ["energy_storage"] = {
  160.         new = function(name, id, data)
  161.             local x, y = AllocateScreen(100, 40)
  162.  
  163.             local c_layout = RenderLayout({
  164.                 title_background = {
  165.                     type = "box";
  166.                     x = x;
  167.                     y = y;
  168.                     width = 100;
  169.                     height = 10;
  170.                     color = 0x333333;
  171.                     opacity = 0.7;
  172.                 };
  173.                 title = {
  174.                     type = "text";
  175.                     text = name;
  176.                     x = CalcCenterX(x, 100);
  177.                     y = CalcCenterY(y, 10);
  178.                     z = 1;
  179.                     scale = 0.7;
  180.                     color = 0x7777FF;
  181.                     object_anchor = {"MIDDLE", "MIDDLE"};
  182.                 };
  183.                 info_background = {
  184.                     type = "box";
  185.                     x = x;
  186.                     y = y + 10;
  187.                     width = 100;
  188.                     height = 30;
  189.                     color = 0x333333;
  190.                     opacity = 0.7;
  191.                 };
  192.                 stored = {
  193.                     type = "text";
  194.                     text = "Not Available";
  195.                     x = x + 5;
  196.                     y = CalcCenterY(y + 10, 10);
  197.                     z = 1;
  198.                     scale = 0.7;
  199.                     color = 0xD3692C;
  200.                     object_anchor = {"LEFT", "MIDDLE"}
  201.                 };
  202.                 percentage = {
  203.                     type = "text";
  204.                     text = "Not Available";
  205.                     x = x + 5;
  206.                     y = CalcCenterY(y + 20, 10);
  207.                     z = 1;
  208.                     scale = 0.7;
  209.                     color = 0xD3692C;
  210.                     object_anchor = {"LEFT", "MIDDLE"}
  211.                 };
  212.                 increase = {
  213.                     type = "text";
  214.                     text = "Not Available";
  215.                     x = x + 5;
  216.                     y = CalcCenterY(y + 30, 10);
  217.                     z = 1;
  218.                     scale = 0.7;
  219.                     color = 0xD3692C;
  220.                     object_anchor = {"LEFT", "MIDDLE"}
  221.                 };
  222.             })
  223.             component_data[id].layout = c_layout
  224.         end;
  225.  
  226.         update = function(id, data)
  227.             local cdata = component_data[id]
  228.             local layout = cdata.layout
  229.             layout.stored.setText(FormatSI(data.stored, "RF") .. " / " .. FormatSI(data.max, "RF"))
  230.             layout.percentage.setText(tostring(Round((data.stored / data.max) * 100, 2)) .. "% full")
  231.  
  232.             if cdata.last_update then
  233.                 local increase = (data.stored - cdata.last_stored) / (os.clock() - cdata.last_update) / 20
  234.                 layout.increase.setText("Rate: " .. FormatSI(increase, "RF/t"))
  235.             end
  236.  
  237.             cdata.last_update = os.clock()
  238.             cdata.last_stored = data.stored
  239.  
  240.             bridge.sync()
  241.         end;
  242.     };
  243.  
  244.     ["reactor"] = {
  245.         new = function(name, id, data)
  246.             table.insert(reactors, id)
  247.             local x, y = AllocateScreen(100, 30)
  248.  
  249.             local c_layout = RenderLayout({
  250.                 title_background = {
  251.                     type = "box";
  252.                     x = x;
  253.                     y = y;
  254.                     width = 100;
  255.                     height = 10;
  256.                     color = 0x333333;
  257.                     opacity = 0.7;
  258.                 };
  259.                 title = {
  260.                     type = "text";
  261.                     text = name;
  262.                     x = CalcCenterX(x, 100);
  263.                     y = CalcCenterY(y, 10);
  264.                     z = 1;
  265.                     scale = 0.7;
  266.                     color = 0x7777FF;
  267.                     object_anchor = {"MIDDLE", "MIDDLE"};
  268.                 };
  269.                 info_background = {
  270.                     type = "box";
  271.                     x = x;
  272.                     y = y + 10;
  273.                     width = 100;
  274.                     height = 20;
  275.                     color = 0x333333;
  276.                     opacity = 0.7;
  277.                 };
  278.                 active = {
  279.                     type = "text";
  280.                     text = "Not Available";
  281.                     x = x + 5;
  282.                     y = CalcCenterY(y + 10, 10);
  283.                     z = 1;
  284.                     scale = 0.7;
  285.                     color = 0xD3692C;
  286.                     object_anchor = {"LEFT", "MIDDLE"};
  287.                 };
  288.                 rate = {
  289.                     type = "text";
  290.                     text = "Not Available";
  291.                     x = x + 5;
  292.                     y = CalcCenterY(y + 20, 10);
  293.                     z = 1;
  294.                     scale = 0.7;
  295.                     color = 0xD3692C;
  296.                     object_anchor = {"LEFT", "MIDDLE"};
  297.                 };
  298.             })
  299.  
  300.             component_data[id].layout = c_layout
  301.         end;
  302.  
  303.         update = function(id, data)
  304.             local cdata = component_data[id]
  305.             local layout = cdata.layout
  306.  
  307.             if data.active then
  308.                 layout.active.setColor(0x326806)
  309.                 layout.active.setText("Active")
  310.             else
  311.                 layout.active.setColor(0x7C0404)
  312.                 layout.active.setText("Inactive")
  313.             end
  314.             layout.rate.setText("Rate: " .. FormatSI(data.rate, "RF/t"))
  315.         end;
  316.     };
  317.  
  318.     ["me_storage"] = {
  319.         new = function(name, id, data)
  320.             local x, y = AllocateScreen(100, 20)
  321.  
  322.             local c_layout = RenderLayout({
  323.                 title_background = {
  324.                     type = "box";
  325.                     x = x;
  326.                     y = y;
  327.                     width = 100;
  328.                     height = 10;
  329.                     color = 0x333333;
  330.                     opacity = 0.7;
  331.                 };
  332.                 title = {
  333.                     type = "text";
  334.                     text = name;
  335.                     x = CalcCenterX(x, 100);
  336.                     y = CalcCenterY(y, 10);
  337.                     z = 1;
  338.                     scale = 0.7;
  339.                     color = 0x7777FF;
  340.                     object_anchor = {"MIDDLE", "MIDDLE"};
  341.                 };
  342.                 info_background = {
  343.                     type = "box";
  344.                     x = x;
  345.                     y = y + 10;
  346.                     width = 100;
  347.                     height = 10;
  348.                     color = 0x333333;
  349.                     opacity = 0.7;
  350.                 };
  351.                 cpu_avail = {
  352.                     type = "text";
  353.                     text = "Not Available";
  354.                     x = x + 5;
  355.                     y = CalcCenterY(y + 10, 10);
  356.                     z = 1;
  357.                     scale = 0.7;
  358.                     color = 0xD3692C;
  359.                     object_anchor = {"LEFT", "MIDDLE"}
  360.                 };
  361.             })
  362.  
  363.             component_data[id].layout = c_layout
  364.         end;
  365.  
  366.         update = function(id, data)
  367.             local cdata = component_data[id]
  368.             local layout = cdata.layout
  369.  
  370.             if data.cpu_avail == 0 then
  371.                 layout.cpu_avail.setColor(0xEE0000)
  372.             else
  373.                 layout.cpu_avail.setColor(0xD3692C)
  374.             end
  375.             layout.cpu_avail.setText("Crafting CPUs: " .. tostring(data.cpu_avail) .. " / " .. tostring(data.cpu_max))
  376.             bridge.sync()
  377.         end;
  378.     };
  379.  
  380.     ["players"] = {
  381.         new = function(name, id, data)
  382.             if not component_data["players"] then
  383.                 local x, y = 123, 20
  384.                 local c_layout = RenderLayout({
  385.                     title_background = {
  386.                         type = "box";
  387.                         x = x;
  388.                         y = y;
  389.                         width = 100;
  390.                         height = 10;
  391.                         color = 0x333333;
  392.                         opacity = 0.7;
  393.                     };
  394.                     title = {
  395.                         type = "text";
  396.                         text = name;
  397.                         x = CalcCenterX(x, 100);
  398.                         y = CalcCenterY(y, 10);
  399.                         z = 1;
  400.                         scale = 0.7;
  401.                         color = 0x7777FF;
  402.                         object_anchor = {"MIDDLE", "MIDDLE"};
  403.                     };
  404.                     info_background = {
  405.                         type = "box";
  406.                         x = x;
  407.                         y = y + 10;
  408.                         width = 100;
  409.                         height = 10;
  410.                         color = 0x333333;
  411.                         opacity = 0.7;
  412.                     };
  413.                 })
  414.  
  415.                 component_data["players"] = {layout = c_layout, clients = {}}
  416.             end
  417.         end;
  418.  
  419.         update = function(id, data)
  420.             local cdata = component_data["players"]
  421.             local layout = cdata.layout
  422.  
  423.             if not cdata.names then
  424.                 cdata.names = {}
  425.             end
  426.             cdata.clients[id] = data.players
  427.  
  428.             local all_players = {}
  429.             for _,v in pairs(cdata.clients) do
  430.                 for __,p in pairs(v) do
  431.                     if not all_players[p] then
  432.                         table.insert(all_players, p)
  433.                         all_players[p] = true
  434.                     end
  435.                 end
  436.             end
  437.  
  438.             layout.info_background.setHeight(#all_players * 10)
  439.             for i,v in ipairs(all_players) do
  440.                 if not cdata.names[i] then
  441.                     cdata.names[i] = bridge.addText(128, 25 + (i * 10), v, 0xD3692C)
  442.                     cdata.names[i].setObjectAnchor("left", "middle")
  443.                     cdata.names[i].setZ(1)
  444.                     cdata.names[i].setScale(0.7)
  445.                 else
  446.                     cdata.names[i].setText(v)
  447.                     cdata.names[i].setVisible(true)
  448.                 end
  449.             end
  450.  
  451.             for i = #all_players + 1, #cdata.names do
  452.                 cdata.names[i].setVisible(false)
  453.             end
  454.         end;
  455.     };
  456. }
  457.  
  458. local function Send(type, message, destination, component_id, rid)
  459.     modem.transmit(CHANNEL_GLASS, 0, {
  460.         protocol = "GLASS_MESSAGE";
  461.         destination = destination;
  462.         type = type;
  463.         message = message;
  464.         component_id = component_id;
  465.         rid = rid;
  466.     })
  467. end
  468.  
  469. local function SendListener(id, component_id, ...)
  470.     Send(MSG_TYPE_LISTENER, {id = MSG_REACTOR_SETACTIVE, args = {...}}, nil, component_id, nil)
  471. end
  472.  
  473. local commands = {
  474.     ["update"] = function(args)
  475.         status_msg.setColor(0xFFFFFF)
  476.         status_msg.setText("Updating...")
  477.         status_msg.setVisible(true)
  478.         bridge.sync()
  479.  
  480.         local request = http.get("http://pastebin.com/raw/4GZMXX3u")
  481.         if request then
  482.             local source = request.readAll()
  483.             local success, err = loadstring(source)
  484.             if not success then
  485.                 status_msg.setColor(0xEE0000)
  486.                 status_msg.setText("Could not update: " .. err)
  487.                 bridge.sync()
  488.             else
  489.                 local file = fs.open("/startup", "w")
  490.                 file.write(source)
  491.                 file.close()
  492.                 os.reboot()
  493.             end
  494.         else
  495.             status_msg.setColor(0xEE0000)
  496.             status_msg.setText("Could not update: request failed")
  497.             bridge.sync()
  498.         end
  499.     end;
  500.  
  501.     ["reboot"] = function(args)
  502.         os.reboot()
  503.     end;
  504.  
  505.     ["reactor"] = function(args)
  506.         if #args ~= 0 then
  507.             local command = args[1]:lower()
  508.             if command == "on" then
  509.                 for i,v in pairs(reactors) do
  510.                     SendListener(MSG_REACTOR_SETACTIVE, v, true)
  511.                 end
  512.             elseif command == "off" then
  513.                 for i,v in pairs(reactors) do
  514.                     SendListener(MSG_REACTOR_SETACTIVE, v, false)
  515.                 end
  516.             end
  517.         end
  518.     end;
  519. }
  520.  
  521. local function Receive(component_id)
  522.     while true do
  523.         local event, side, schannel, rchannel, message, dist = os.pullEvent()
  524.         if event == "modem_message" then
  525.             if schannel == CHANNEL_GLASS and type(message) == "table" and message.protocol == "GLASS_MESSAGE" and message.destination == -1 then
  526.                 return rchannel, message.type, message.message, message.component_id, message.rid
  527.             end
  528.         elseif event == "glasses_chat_command" then
  529.             local args = {}
  530.             for part in message:gmatch("[^ ]+") do
  531.                 table.insert(args, part)
  532.             end
  533.             local command = args[1]
  534.             table.remove(args, 1)
  535.  
  536.             local callback = commands[command]
  537.             if callback then
  538.                 callback(args)
  539.             end
  540.         end
  541.     end
  542. end
  543.  
  544. local function Reply(type, rchannel, rid, message)
  545.     Send(type, message, rchannel, nil, rid)
  546. end
  547.  
  548. local s_component_id = 0
  549.  
  550. local function RegisterNew(message, reply, rid)
  551.     if type(message) ~= "table" then
  552.         return
  553.     end
  554.     local cType = message.type
  555.     local cName = message.name
  556.     if not cType or not cName then
  557.         return
  558.     end
  559.  
  560.     local component_id = s_component_id
  561.     s_component_id = s_component_id + 1
  562.  
  563.     local handler = component_handlers[cType]
  564.     component_data[component_id] = {update = handler and handler.update}
  565.     if handler and handler.new then
  566.         handler.new(cName, component_id, message.data)
  567.     end
  568.  
  569.     print("Registered new " .. cType .. " named " .. cName .. " with id " .. component_id)
  570.  
  571.     Reply(MSG_TYPE_REPLY_NEW, reply, rid, {component_id = component_id})
  572. end
  573.  
  574. Send(MSG_TYPE_INIT, nil, nil, nil, nil)
  575.  
  576. while true do
  577.     local rChannel, mType, message, component_id, rid = Receive()
  578.  
  579.     local success, err = pcall(function()
  580.         if mType == MSG_TYPE_NEW then
  581.             RegisterNew(message, rChannel, rid)
  582.         elseif mType == MSG_TYPE_UPDATE then
  583.             local data = component_data[component_id]
  584.             if data and data.update then
  585.                 data.update(component_id, message)
  586.             end
  587.         else
  588.             print("Unknown message type")
  589.         end
  590.     end)
  591.  
  592.     if not success then
  593.         print("Error running event: " .. err)
  594.         status_msg.setColor(0xEE0000)
  595.         status_msg.setText("Error running event: " .. err)
  596.         status_msg.setVisible(true)
  597.         bridge.sync()
  598.     end
  599. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement