Advertisement
XLT_Frank

Minecraft Tank Monitor

May 9th, 2014
558
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- tankmon
  2. -- http://www.computercraft.info/forums2/index.php?/topic/15689-dead-simple-railcraft-tank-monitoring/
  3. -- Tank monitoring program edited by RikuSS4
  4. -- Original program by Forgotten_Boy
  5. -- Hardware detector program by Sharidan
  6. -- Requires OpenPeripherals (OP). Tested with version 3.0.
  7. -- Supports iron & steel Railcraft tanks, Open Block tanks, Ender Tanks, AE ExtraCells tanks,
  8. -- TConstruct tanks, and Extra Utilities Drums.
  9. -- Also supports multiple tanks, and tanks attached with modems.
  10. -- If I missed any tanks, let me know. I will add it to the list.
  11. -- Setup:
  12. -- Place an Advanced Computer with wireless modem and with tankmon on it adjacent to a tank.  Run "tankmon".
  13. -- Setup another Advanced Computer with wireless modem and with tankmon on it adjacent to an advanced monitor and/or terminal glass bridge.  Run "tankmon".
  14. -- Your monitor should now show the contents of the tank.  Add as many tanks as you like and the server will simply add them to the display.
  15. -- The size of the monitor or locations of the modems don't matter, place them anywhere on the computer.  The monitor can be resized while tankmon is running.
  16.  
  17. -- Optional Setup:
  18. -- Place an Advanced Computer with wired and wireless modems with lan cables connecting all tanks with lan modems attached to tanks and to computer.  
  19. -- Run "tankmon".
  20. -- Setup another Advanced Computer with wireless modem and with tankmon on it adjacent to an advanced monitor and/or terminal glass bridge.
  21. -- Run "tankmon".
  22. -- Your monitor should now show the contents of the tanks.  Add as many tanks as you like and the server will simply add them to the display.
  23. -- The size of the monitor or locations of the modems don't matter, place them anywhere on the computer.  The monitor can be resized while tankmon is running.
  24.  
  25. -- Advanced usage:
  26. -- On the client, you can use tankmon to trigger a redstone signal when the tank reaches a certain threshold (specified as 0 to 100, a percentage).  
  27. -- For example:
  28. -- tankmon 100 left
  29. -- tankmon 0 top
  30. -- The first example will send redstone output on the left when the tank is full.  
  31. -- The second example will send redstone output on the top when the tank is empty.
  32.  
  33. -- Variable definitions
  34. local valve, monitor, screenw, screenh
  35. local serverID = nil
  36. local clients = {}
  37. local args = {...}
  38. local redLimit, redside, on
  39. local sides = {"left", "right", "top", "bottom", "front", "back"};
  40. local tankTypes = {"rcirontankvalvetile","rcsteeltankvalvetile","iron_tank_valve", "steel_tank_valve", "openblocks_tank", "drum", "ender_tank", "cofh_thermalexpansion_tank", "net_minecraft_src_buildcraft_factory_tiletank", "tileentitycertustank", "tconstruct_lavatank"};
  41. local scale = 0.75 --Scale for monitor text
  42. local skipEmpty = true --Skip showing empty tanks
  43. local count = 0 --Counter for tanks
  44.  
  45. ----------------------------------------------------
  46. -- Terminal Bridge Glasses Variable definitions
  47. ----------------------------------------------------
  48. local bridge = {}
  49. bridge["TankText"] = {}
  50. bridge["TankBackground"] = {}
  51. bridge["TankTexture"] = {}
  52. -------------------------------------------------------
  53. -- Terminal Bridge Glasses display variable definitions
  54. -- Feel free to alter these to your liking
  55. -------------------------------------------------------
  56. bridge["BackgroundColor"] = 0x000000 --Background Bar color
  57. bridge["TextColor"] = 0x33B5E5 --Text color
  58. bridge["TextScale"] = 1 --Text Scale
  59. bridge["ExtendBackground"] = true --Extend Black background behind text
  60. bridge["BarWidth"] = 25 --Tank bar width
  61. bridge["BarHeight"] = 50 --Tank bar height
  62. bridge["XOffset"] = 5 --X Offset for displaying info
  63. bridge["YOffset"] = 50 --Y Offset for displaying info
  64. bridge["XSpacing"] = 5 --Space between columns
  65. bridge["YSpacing"] = 5 --Space between rows
  66. bridge["Alpha"] = 1 --Alpha value of bar background
  67. bridge["LinesAmt"] = 3 --Number of text lines after tank bar
  68. bridge["MaxCols"] = 3 --Max Number of cols to display per page
  69. bridge["MaxRows"] = 3 --Max Number of rows to display per page
  70. -------------------------------------------------------
  71. -- Which row to start with. This will be changed to
  72. -- automatically change based on user input in chat
  73. -- command box.
  74. -------------------------------------------------------
  75. bridge["StartRow"] = 0 --Min Row to display
  76. -------------------------------------------------------
  77. -- Altering these does nothing
  78. -------------------------------------------------------
  79. bridge["CurrentRow"] = 1 --Current Row
  80. bridge["CurrentCol"] = 1 --Current Col
  81.  
  82. ----------------------------------------------------
  83. -- Function definitions
  84. ----------------------------------------------------
  85. local liquidNameColors = {
  86.                {"water", colors.blue, "Water" },
  87.                {"lava", colors.orange, "Lava" },
  88.                {"liquidforce", colors.yellow, "Liquid Force" },
  89.                {"turpentine", colors.brown, "Turpentine" },
  90.                {"poison", colors.purple, "Poison" },
  91.                {"latex", colors.white, "Latex" },
  92.                {"ardite.molten", colors.pink, "Molten Ardite" },
  93.                {"gold.molten", colors.orange, "Molten Gold" },
  94.                {"blood", colors.red, "Blood" },
  95.                {"copper.molten", colors.orange, "Molten Copper" },
  96.                {"obsidian.molten", colors.gray, "Molten Obsidian" },
  97.                {"bop.honey", colors.yellow, "Honey" },
  98.                {"sap", colors.brown, "Sap" },
  99.                {"liquidnitrogen", colors.cyan, "Liquid Nitrogen" },
  100.                {"iron.molten", colors.gray, "Molten Iron" },
  101.                {"bop.liquidpoison", colors.purple, "Liquid Poison" },
  102.                {"alumite.molten", colors.pink, "Molten Ardite" },
  103.                {"cobalt.molten", colors.cyan, "Molten Cobalt" },
  104.                {"bop.springwater", colors.blue, "Spring Water" },
  105.                {"glowstone", colors.yellow, "Energized Glowstone" },
  106.                {"resin", colors.brown, "Resin" },
  107.                {"emerald.liquid", colors.lime, "Liquified Emerald" },
  108.                {"pinkslime", colors.pink, "Pink Slime" },
  109.                {"redstone", colors.orange, "Destabilized Redstone" },
  110.                {"xpjuice", colors.lime, "Liquid XP" },
  111.                {"Mob Essence", colors.lime, "Mob Essence" },
  112.                {"oil", colors.gray, "Oil" },
  113.                {"fluid.oil", colors.gray, "Oil" },
  114.                {"aluminum.molten", colors.lightGray, "Molten Aluminum" },
  115.                {"manyullyn.molten", colors.purple, "Molten Manyullyn" },
  116.                {"stone.seared", colors.gray, "Seared Stone" },
  117.                {"creosote", colors.green, "Creosote Oil" },
  118.                {"sludge", colors.brown, "Sludge" },
  119.                {"fluid.seedoil", colors.yellow, "Fuel" },
  120.                {"bioethanol", colors.lime, "Ethanol" },
  121.                {"fluid.bioethanol", colors.lime, "Ethanol" },
  122.                {"acid", colors.lime, "Acid" },
  123.                {"biomass", colors.lime, "Biomass" },
  124.                {"immibis.liquidxp", colors.lime, "Liquid XP" },
  125.                {"electrum.molten", colors.yellow, "Molten Electrum" },
  126.                {"sewage", colors.brown, "Sewage" },
  127.                {"slime.blue", colors.cyan, "Liquid Blueslime" },
  128.                {"tin.molten", colors.lightGray, "Molten Tin" },
  129.                {"aluminumbrass.molten", colors.orange, "Molten Aluminum Brass" },
  130.                {"milk", colors.white, "Milk" },
  131.                {"fuel", colors.yellow, "Fuel" },
  132.                {"fluid.fuel", colors.yellow, "Fuel" },
  133.                {"biofuel", colors.green, "Biofuel" },
  134.                {"fluid.biofuel", colors.green, "Biofuel" },
  135.                {"chocolatemilk", colors.brown, "Chocolate Milk" },
  136.                {"glass.molten", colors.lightGray, "Molten Glass" },
  137.                {"cryotheum", colors.cyan, "Gelid Cryotheum" },
  138.                {"pyrotheum", colors.orange, "Blazing Pyrotheum" },
  139.                {"pinkslime", colors.pink, "Pink Slime" },
  140.                {"platinum.molten", colors.cyan, "Molten Platinum" },
  141.                {"coal", colors.gray, "Liquifacted Coal" },
  142.                {"lead.molten", colors.gray, "Molten Lead" },
  143.                {"mushroomsoup", colors.brown, "Mushroom Soup" },
  144.                {"silver.molten", colors.lightGray, "Molten Silver" },
  145.                {"nickel.molten", colors.cyan, "Molten Nickel" },
  146.                {"ender", colors.green, "Resonant Ender" },
  147.                {"invar.molten", colors.lightGray, "Molten Invar" },
  148.                {"glue", colors.white, "Glue" },
  149.                {"meat", colors.pink, "Meat" },
  150.                {"steel.molten", colors.gray, "Molten Steel" },
  151.                {"bronze.molten", colors.brown, "Molten Bronze" },
  152.                {"uumatter", colors.purple, "UU Matter" }
  153.                }
  154.  
  155. function cls()
  156.    term.clear()
  157.    term.setCursorPos(1,1)
  158.    term.setCursorBlink(false)
  159. end
  160. function clm()
  161.    if monitor then
  162.       monitor.setBackgroundColor(colors.black)
  163.       monitor.setTextScale(scale)
  164.       monitor.clear()
  165.       monitor.setCursorPos(1,1)
  166.       monitor.setCursorBlink(false)
  167.    end
  168. end
  169. function clb()
  170.    if bridge["peripheral"] then
  171.       bridge["peripheral"].clear()
  172.    end
  173. end
  174.  
  175. function table.merge(tbl1, tbl2)
  176.    for k,v in ipairs(tbl2) do
  177.       table.insert(tbl1, v)
  178.    end
  179.    return tbl1
  180. end
  181.  
  182. function split(str, wordNum)
  183.    local splitString = {}
  184.    for tmp in str:gmatch("%w+") do
  185.       table.insert(splitString, tmp)
  186.    end
  187.    return splitString[wordNum] or ""
  188. end
  189.  
  190. local function getLiquidColor(liquid)
  191.    for c, color in pairs (liquidNameColors) do
  192.       if (liquid == color[1]) or (liquid == color[3]) then
  193.          return color[2]
  194.       end
  195.    end
  196.    return colors.white;
  197. end
  198.  
  199. local function getDeviceSide(deviceType)
  200.     for i,side in pairs(sides) do
  201.         if (peripheral.isPresent(side)) then
  202.             if (peripheral.getType(side)) == string.lower(deviceType) then
  203.                 return side;
  204.             end
  205.         end
  206.     end
  207. end
  208.  
  209. function hardwareDetector(...)
  210.   local self = {}
  211.   -- Initialize internal hardware list
  212.   self._devList = {}
  213.  
  214.   -- Internal worker function
  215.   -- Checks a boolean value and returns the
  216.   -- corresponding supplied value
  217.   local function iif(bool, resultTrue, resultFalse)
  218.     if (bool) then
  219.       return resultTrue;
  220.     else
  221.       return resultFalse;
  222.     end
  223.   end
  224.   local function split(str, pat)
  225.     local t = {}
  226.     local fpat = "(.-)" .. pat
  227.     local last_end = 1
  228.     local s, e, cap = str:find(fpat, 1)
  229.     while s do
  230.       if s ~= 1 or cap ~= "" then
  231.         table.insert(t,cap)
  232.       end
  233.       last_end = e+1
  234.       s, e, cap = str:find(fpat, last_end)
  235.     end -- while
  236.     if last_end <= #str then
  237.       cap = str:sub(last_end)
  238.       table.insert(t, cap)
  239.     end
  240.     return t
  241.   end
  242.   local function splitType(str)
  243.     local typ, adv = str, nil
  244.     local r = split(str, ":")
  245.     if (#r == 2) then
  246.       typ = r[1]
  247.       adv = r[2]
  248.     end
  249.     return typ, adv;
  250.   end
  251.   local function wrapID(value)
  252.     if (value == nil) then
  253.       return "offline"
  254.     else
  255.       return tostring(value)
  256.     end
  257.   end
  258.   local function addDevice(label, devType, remote)
  259.     local lcdt = string.lower(devType)
  260.     local adv = "n/a";
  261.     local pCall = function() end;
  262.     if (remote) then
  263.       pCall = function(label, method)
  264.         return remote.callRemote(label, method)
  265.       end;
  266.     else
  267.       pCall = function(label, method)
  268.         return peripheral.call(label, method)
  269.       end;
  270.     end
  271.     if (lcdt == "modem") then
  272.       adv = iif(pCall(label, "isWireless"), "wireless", "cable")
  273.     elseif (lcdt == "monitor") then
  274.       adv = iif(pCall(label, "isColor"), "advanced", "normal")
  275.     elseif (lcdt == "computer" or lcdt == "turtle") then
  276.       adv = tostring(wrapID(pCall(label, "getID")))
  277.     elseif (lcdt == "drive") then
  278.       if (disk.isPresent(label)) then
  279.         if (disk.hasData(label)) then
  280.           adv = "floppy";
  281.         elseif (disk.hasAudio(label)) then
  282.           adv = "music";
  283.         else
  284.           adv = "unknown";
  285.         end
  286.       else
  287.         adv = "empty"
  288.       end
  289.     end
  290.     table.insert(self._devList, {label, devType, adv});
  291.     if (lcdt == "modem" and string.lower(adv) == "cable") then
  292.       return true;
  293.     end
  294.   end
  295.  
  296.   -- Detects all connected peripherals
  297.   function self.detect()
  298.     self._devList = {};
  299.     local sides = rs.getSides();
  300.     local remoteSide = {};
  301.     for i, side in pairs(sides) do
  302.       local devType = peripheral.getType(side);
  303.       if (devType) then
  304.         if (addDevice(side, devType)) then
  305.           table.insert(remoteSide, side);
  306.         end
  307.       end -- if
  308.     end -- for-do
  309.    
  310.     if (#remoteSide > 0) then
  311.       -- There was a cable modem attached, so we need to loop through all remote peripherals too
  312.       for r = 1, #remoteSide do
  313.         local rp = peripheral.wrap(remoteSide[r]);
  314.         local lst = rp.getNamesRemote()
  315.         for r = 1, #lst do
  316.           local name = lst[r]
  317.           local devType = rp.getTypeRemote(name);
  318.           if (devType) then
  319.             addDevice(name, devType, rp);
  320.           end
  321.         end
  322.       end -- for r
  323.     end
  324.   end
  325.  
  326.   -- Returns a tuple of the first matching peripheral
  327.   function self.find(...)
  328.     local args={...}
  329.     if (#args > 0) then
  330.       local idx = 0;
  331.       for i, sideType in pairs(self._devList) do
  332.         for a = 1, #args do
  333.           local findType = args[a];
  334.           if (type(findType) == "string") then
  335.             local typ, adv = splitType(findType);
  336.             if (string.lower(typ) == string.lower(self._devList[i][2])) then
  337.               if (adv) then
  338.                 if (string.lower(adv) == string.lower(self._devList[i][3])) then
  339.                   -- We found a device of this type
  340.                   idx = i;
  341.                 end
  342.               else
  343.                 -- We found a device of this type
  344.                 idx = i;
  345.               end
  346.               if (idx > 0) then
  347.                 return tostring(self._devList[idx][1]), tostring(self._devList[idx][2]), tostring(self._devList[idx][3])
  348.               end
  349.             end
  350.           end
  351.         end
  352.       end
  353.       return nil;
  354.     else
  355.       error("No device type specified.", 0)
  356.     end
  357.   end
  358.  
  359.   -- Returns a complete list of peripherals
  360.   function self.getAll()
  361.     return self._devList;
  362.   end
  363.  
  364.   -- Returns a list of all matching peripherals
  365.   function self.getList(...)
  366.       local args={...}
  367.       local results = {}
  368.       if (#args > 0) then
  369.          for i, sideType in pairs(self._devList) do
  370.             for a = 1, #args do
  371.                local findType = args[a];
  372.                if (type(findType) == "string") then
  373.                   if (string.lower(findType) == string.lower(self._devList[i][2])) then
  374.                      -- We found a device of this type
  375.                      table.insert(results, {tostring(self._devList[i][1]), tostring(self._devList[i][2]), tostring(self._devList[i][3])})
  376.                   end
  377.                elseif (type(findType) == "table") then
  378.                   for i2, entry in pairs(findType) do
  379.                      if (type(entry) == "string") then
  380.                         if (string.lower(entry) == string.lower(self._devList[i][2])) then
  381.                            -- We found a device of this type
  382.                            table.insert(results, {tostring(self._devList[i][1]), tostring(self._devList[i][2]), tostring(self._devList[i][3])})
  383.                         end
  384.                      end
  385.                   end
  386.                end
  387.             end
  388.          end
  389.          return results;
  390.       else
  391.          error("No device type specified.", 0);
  392.       end
  393.    end
  394.  
  395.   -- Determines if the device is remote or not
  396.   function self.isRemote(dev)
  397.     if (type(dev) == "string") then
  398.       local sides = rs.getSides();
  399.       for i, s in pairs(sides) do
  400.         if (string.lower(dev) == string.lower(s)) then
  401.           return nil;
  402.         end
  403.       end
  404.       return true;
  405.     else
  406.       error("Device connect string expected.", 0);
  407.     end
  408.   end
  409.  
  410.   -- Internal calls, don't mess with these
  411.   self.detect()
  412.  
  413.   local args = {...};
  414.   if (#args > 0) then
  415.     return self.find(...);
  416.   else
  417.     -- If no parameters were passed,
  418.     -- return the hardware object
  419.     return self;
  420.   end
  421. end
  422.  
  423. local function showLevel(count,total,filled,color,label,rawLabel, amt, threshold, signal)
  424.    if (monitor) then
  425.       local screenw, screenh = monitor.getSize()
  426.       --total = total + 1
  427.       if (not screenw) then
  428.          return nil;
  429.          -- monitor has been broken
  430.       end
  431.  
  432.       local starty = screenh -  math.floor((screenh * filled))
  433.       local width  = math.ceil(screenw / total)
  434.       local offset = math.ceil((screenw / total) * (count-1))
  435.       local amtw = string.len(amt)
  436.       local thresholdy = (threshold and ( screenh - ((threshold / 100) * screenh)))
  437.    
  438.       if (count == total) then
  439.       --  the final column should use up the remaining space.  A hack!
  440.          width = screenw - offset
  441.       end
  442.  
  443.       if (thresholdy and thresholdy < 1) then
  444.          thresholdy = 1
  445.       else
  446.          if (thresholdy and thresholdy > screenh) then
  447.             thresholdy = screenh
  448.          end
  449.       end
  450.  
  451.       term.redirect(monitor)
  452.       for c=starty, screenh + 1, 1 do
  453.          for line=0, width, 1 do
  454.             paintutils.drawPixel(line + offset, c, color)
  455.          end
  456.       end
  457.       if (thresholdy) then
  458.          local thresholdColor = color
  459.          for line=0, width, 1 do
  460.             thresholdColor = color
  461.             if (signal) then
  462.                thresholdColor = colors.red
  463.             else
  464.                -- makes a dotted line when there is no redstone signal
  465.                if (line % 2 == 0) then
  466.                   thresholdColor = colors.red
  467.                else
  468.                   thresholdColor = color
  469.                end
  470.             end
  471.             paintutils.drawPixel(line + offset, thresholdy, thresholdColor)
  472.          end
  473.       end
  474.  
  475.       --truncate the label to the width of the bar.
  476.       monLabel = string.sub(rawLabel, 1, math.max((width - 1), 0))
  477.  
  478.       monitor.setBackgroundColor(color)
  479.       if (color == colors.white) then
  480.          monitor.setTextColor(colors.black)
  481.       end
  482.    
  483.       labely = math.min((starty + 1), screenh - 1)
  484.       monitor.setCursorPos(offset + 1, labely)
  485.       monitor.setTextScale(scale)
  486.       write(monLabel)
  487.    
  488.       if (amtw <= width) then
  489.          amty = math.min(labely + 1, screenh)
  490.          monitor.setCursorPos(offset + 1, amty)
  491.          write(amt)
  492.       end
  493.       monitor.setTextColor(colors.white)
  494.       term.restore()
  495.    end
  496.    if (bridge["peripheral"]) then
  497.       --Maximum length string can be
  498.       local cutoffPoint = math.ceil(bridge["BarWidth"] / (8*bridge["TextScale"]))
  499.  
  500.       bridge["CurrentRow"] = math.floor((count+bridge["MaxCols"]-1)/bridge["MaxCols"])
  501.       bridge["CurrentCol"] = ((count+bridge["MaxCols"]-1) - bridge["CurrentRow"]*bridge["MaxCols"]) + 1
  502.      
  503.       if (bridge["CurrentRow"] > bridge["StartRow"]) and (bridge["CurrentRow"] <= (bridge["StartRow"] + bridge["MaxRows"])) then
  504.          --Heigth including extra lines below tank display
  505.          local fullHeight = bridge["BarHeight"]+((8*bridge["TextScale"])*(bridge["LinesAmt"]))
  506.          --X and Y coords for tank displays
  507.          local x = bridge["XOffset"] + ((bridge["BarWidth"] + bridge["XSpacing"]) * (bridge["CurrentCol"]-1))
  508.          local y = bridge["YOffset"] + ((fullHeight+bridge["YSpacing"])*(bridge["CurrentRow"]-bridge["StartRow"]-1))
  509.          --Draw tank background using liquid texture
  510.          if bridge["ExtendBackground"] then
  511.             bridge["TankBackground"][count] = bridge["peripheral"].addBox(x,y,bridge["BarWidth"],fullHeight,bridge["BackgroundColor"],bridge["Alpha"])
  512.          else
  513.             bridge["TankBackground"][count] = bridge["peripheral"].addBox(x,y,bridge["BarWidth"],bridge["BarHeight"],bridge["BackgroundColor"],bridge["Alpha"])
  514.          end
  515.          bridge["TankTexture"][count] = bridge["peripheral"].addLiquid(x+1,y+1+math.ceil(bridge["BarHeight"]-(bridge["BarHeight"] * filled)),bridge["BarWidth"]-2,(bridge["BarHeight"] * filled)-2,label)
  516.          --Display info to bridge
  517.          bridge["TankText"][count] = bridge["TankText"][count] or {}
  518.          for i=0,(bridge["LinesAmt"]-1) do
  519.             bridge["TankText"][count][i] = bridge["peripheral"].addText((x+2), (bridge["BarHeight"]+y+((8*bridge["TextScale"])*i)),"",bridge["TextColor"])
  520.             bridge["TankText"][count][i].setScale(scale)
  521.          end
  522.          bridge["TankText"][count][0].setText(string.sub(split(rawLabel,1), 1, cutoffPoint))
  523.          bridge["TankText"][count][1].setText(string.sub(split(rawLabel,2), 1, cutoffPoint))
  524.          bridge["TankText"][count][2].setText(string.sub(tostring(math.floor(filled*100)).."%", 1, cutoffPoint))
  525.       end
  526.    end
  527. end
  528.  
  529. local function tankStats(tank)
  530.     if(tank) then
  531.       local name = tank["name"] or nil
  532.       local rawName = tank["rawName"] or nil
  533.         local amt = tank["amount"]
  534.         local size = tank["capacity"]
  535.         local filled = (amt and 1 / (size / amt)) or 0
  536.       local threshold = tank["redLimit"] or -1
  537.       local signalOn = tank["on"] or false
  538.         return name, rawName, amt, size, filled, threshold, signalOn
  539.     else
  540.         return nil;
  541.     end
  542. end
  543.  
  544. local function tableCount(t)
  545.     local total=0
  546.     for k,v in pairs (t) do
  547.         total = total + 1
  548.     end
  549.     return total
  550. end
  551.  
  552. function printTable(tt, indent)
  553.    print(tableToString(tt, indent))
  554. end
  555.  
  556. function tableToString (tt, indent, done)
  557.   done = done or {}
  558.   indent = indent or 0
  559.   if type(tt) == "table" then
  560.     local sb = {}
  561.     for key, value in pairs (tt) do
  562.       table.insert(sb, string.rep (" ", indent)) -- indent it
  563.       if type (value) == "table" and not done [value] then
  564.         done [value] = true
  565.         table.insert(sb, "{\n");
  566.         table.insert(sb, tableToString (value, indent + 2, done))
  567.         table.insert(sb, string.rep (" ", indent)) -- indent it
  568.         table.insert(sb, "}\n");
  569.       elseif "number" == type(key) then
  570.         table.insert(sb, string.format("\"%s\"\n", tostring(value)))
  571.       else
  572.         table.insert(sb, string.format("%s = \"%s\"\n", tostring (key), tostring(value)))
  573.        end
  574.     end
  575.     return table.concat(sb)
  576.   else
  577.     return tt .. "\n"
  578.   end
  579. end
  580.  
  581. function table.contains(tbl, element)
  582.   for _, value in pairs(tbl) do
  583.     if value == element then
  584.       return true
  585.     end
  586.   end
  587.   return false
  588. end
  589.  
  590. local function findTank(tbl)
  591.    if type(tbl) == "table" then
  592.       for index,value in pairs(tbl) do
  593.          if type(value) == "table" then
  594.             if value["capacity"] then
  595.                return tbl
  596.             else
  597.                return findTank(value)
  598.             end
  599.          end
  600.       end
  601.    else
  602.       return nil
  603.    end
  604. end
  605. local function findTanks(tbl)
  606.    local tblTemp = {}
  607.    if type(tbl) == "table" then
  608.       for index,value in pairs(tbl) do
  609.          if type(value) == "table" then
  610.             if value["capacity"] then
  611.                table.insert(tblTemp, value)
  612.             else
  613.                table.insert(tblTemp, findTank(value))
  614.             end
  615.          end
  616.       end
  617.    end
  618.    return tblTemp
  619. end
  620. local function updateDisplay()
  621.    --printTable(findTanks(clients))
  622. --end
  623. --local function tmp()
  624.     local count = 1
  625.    local lstTanks = {}
  626.    local total = 0
  627.  
  628.    clm()
  629.    clb()
  630.  
  631.    if tableCount(clients) > 0 then
  632.       local i = 1
  633.       for ix,client in pairs (clients) do
  634.          local tanks = findTanks(client)
  635.          table.merge(lstTanks, tanks)
  636.          if (i <= 15) then
  637.             term.setCursorPos(1,6+i)
  638.             term.clearLine()
  639.             print("Client "..i.." # of Tanks: "..tostring(#tanks))
  640.          end
  641.          i = i + 1
  642.       end
  643.       total = #lstTanks
  644.       term.setCursorPos(1,6)
  645.       term.clearLine()
  646.       print("Total # of Tanks: "..tostring(total))
  647.       for _,tankInfo in pairs (lstTanks) do
  648.             local name, rawName, amt, size, filled, threshold, signalOn = tankStats(tankInfo)
  649.             local color = getLiquidColor(rawName)
  650.             local unit = ""
  651.             local amount = math.max(amt or 0, 0)
  652.             --print("Name: "..tostring(name))
  653.             --print("Raw Name: "..tostring(rawName))
  654.             --print("color: "..tostring(color))
  655.             --print("amt: "..tostring(amt))
  656.             --print("size: "..tostring(size))
  657.             --print("filled: "..tostring(filled))
  658.    
  659.             if not (name) and (skipEmpty) then total = total - 1 end
  660.             if name or (not (name) and not (skipEmpty)) then
  661.                if (amount > 1000000) then
  662.                   unit="M"
  663.                   amount=string.format("%.2f", math.floor(amt / 1000) / 1000)
  664.                   --unit="K Buckets"
  665.                   --amount=string.format("%i", math.floor(amt / 1000) / 1000)
  666.                else
  667.                   if(amount > 0) then
  668.                      unit="K"
  669.                      amount=string.format("%.2f", amt / 1000)
  670.                      --unit=" Buckets"
  671.                      --amount=string.format("%i", amt / 1000)
  672.                   else
  673.                      amount = ""
  674.                   end
  675.                end
  676.                amount = amount..unit
  677.                showLevel(count, total, filled, color, name or "Empty", rawName or "Empty", amount, threshold, signalOn)
  678.                count = count + 1    
  679.             --end
  680.          end
  681.       end
  682.    end
  683.    return nil;
  684. end
  685.  
  686. local function broadcast ()
  687.     cls()
  688.     print("_____________ tankmon Server started __________")
  689.     print("Broadcasting that tank display is available...")
  690.     print("Hold Ctrl+T to Terminate.")
  691.     while true do
  692.         rednet.broadcast(os.getComputerID())
  693.         term.setCursorPos(1, 5)
  694.         term.clearLine()
  695.         write("Connected tankmon clients: " .. tableCount(clients))
  696.         sleep(7)
  697.     end
  698. end
  699.  
  700. local function receive()
  701.   while true do
  702.     local senderID, message, distance = rednet.receive()
  703.     if (message) then
  704.         local data = textutils.unserialize(message)
  705.         clients[senderID] = data
  706.     end
  707.   end
  708. end
  709.  
  710. local function display()
  711.     while true do
  712.       updateDisplay()
  713.       sleep(2.5)
  714.     end
  715. end
  716.  
  717. local function connect()
  718.     cls()
  719.    print("Looking for a tankmon server in range...")
  720.     while true do
  721.         local senderID, message, distance = rednet.receive()
  722.         serverID = senderID
  723.       print()
  724.       print("Connected to server " ..tostring(serverID)..".")
  725.       sleep(3)
  726.   end  
  727. end
  728.  
  729. local function publishTank()
  730.    while true do
  731.       if (serverID) then
  732.          local hw = hardwareDetector()
  733.          lstTanks = hw.getList(tankTypes)
  734.          if (type(lstTanks) == "table") then
  735.             if (#lstTanks > 0) then
  736.                local info = {}
  737.                for i, tank in pairs(lstTanks) do
  738.                   if not tank[1]["capacity"] then
  739.                      lstTanks[i][1] = peripheral.wrap(lstTanks[i][1]).getTankInfo("bottom")[1]
  740.                   end
  741.                end
  742.                cls()
  743.                print("** Sending out tank information **")
  744.                print("Number of tanks: "..#lstTanks)
  745.                for i, tank in pairs(lstTanks) do
  746.                   -- establish whether redstone signal should be sent
  747.                   local name, rawName, amt, size, filled, threshold, signalOn = tankStats(tank[1])
  748.                   on = false
  749.                   pctFilled = filled * 100
  750.                   if (filled and redLimit and redLimit==0 and filled==0) then
  751.                      on = true
  752.                   else
  753.                      if(filled and redLimit and filled <= redLimit) then
  754.                         on=true
  755.                      end
  756.                   end
  757.                   if(redside) then
  758.                      rs.setOutput(redside, on)
  759.                   end
  760.                   -- use rednet to update the server with this tank's info.
  761.                   tank[1]["redLimit"] = redLimit
  762.                   tank[1]["on"] = on
  763.                   table.insert(info, tank[1])
  764.                   if (redLimit and redside) then
  765.                      print("Redstone signal on: " .. tostring(on))
  766.                   end
  767.                   if (i <= 12) then
  768.                      term.setCursorPos(1,3 + i)
  769.                      term.clearLine()
  770.                      if tank[1]["amount"] then
  771.                         write("** Tank "..i.." contains: " .. tostring(tank[1]["amount"]).."mB of "..tostring(tank[1]["name"]))
  772.                      else
  773.                         write("** Tank "..i.." is empty.")
  774.                      end
  775.                   end
  776.                end
  777.                if (redLimit and redside) then
  778.                   print("Redstone threshold: " .. tostring(redLimit))
  779.                   print("Redstone output side: " .. tostring(redside))
  780.                end
  781.                rednet.send(serverID, textutils.serialize(info), false)
  782.             end
  783.          end
  784.         end
  785.         sleep(math.random(1,5))
  786.   end
  787. end
  788.  
  789. -------------------------------------------------------
  790. -- Hardware setup and detection
  791. -------------------------------------------------------
  792. local hw = hardwareDetector()
  793. local screenSide, _, _ = hw.find("monitor:advanced");
  794. local bridgeSide, _, _ = hw.find("openperipheral_glassesbridge");
  795. local modemSide, _, _ = hardwareDetector("modem:wireless")
  796. lstTanks = hw.getList(tankTypes)
  797.  
  798. if (modemSide) then
  799.     local modem = peripheral.wrap(modemSide)
  800. else
  801.     error("A wireless modem must be attached to this computer.")
  802. end
  803.  
  804. if (#lstTanks > 0) and (bridgeSide or screenSide) then
  805.     error("Either a screen or a tank valve can be connected, not both.")
  806. end
  807.  
  808. if (screenSide) then
  809.    monitor = peripheral.wrap(screenSide)
  810.     if(not monitor.isColor()) then
  811.         error("The attached monitor must be Advanced.  Get some gold!")
  812.     end
  813.    screenw, screenh = monitor.getSize()
  814.     clm()
  815. end
  816. if (bridgeSide) then
  817.    bridge["peripheral"] = peripheral.wrap(bridgeSide)
  818.    clb()
  819. end
  820.  
  821. ---------------------------------------
  822. --the Main
  823. ---------------------------------------
  824.  
  825. rednet.open(modemSide)
  826. if (#lstTanks > 0) then
  827.     -- client mode
  828.     redLimit = args[1]
  829.     redside = args[2]
  830.     if (redLimit and not redside) then
  831.         print("A threshold and redstone side must both be present.")
  832.         print("e.g. tankmon 100 top")
  833.         error()
  834.     end
  835.     if (redLimit) then
  836.         redLimit = tonumber(redLimit)
  837.         print("")
  838.         print("Tank will send redstone signal at or below " .. tostring(redLimit) .. "% on side " .. redside)
  839.     end
  840.     -- clear outstanding redstone signals.
  841.     for i,side in pairs(sides) do
  842.         rs.setOutput(side, false)
  843.     end
  844.    parallel.waitForAll(connect, publishTank)
  845. else
  846.     -- server mode
  847.     parallel.waitForAll(broadcast, receive, display)
  848. end
  849. rednet.close(modemSide)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement