--[[ Base Monitor 1.9.1 This script allows you to monitor caches, tanks, barrels and chests Monitoring chests requires an open peripheral proxy, the same goes for buildcraft tanks. You can build one of more computers and set one of them as the main server by setting isMain to true. This will let it receive information from other computers. For the main server to receive info from other computers you need to attach a wireless modem to each computer. Peripherals can be attached to any side you like, the script will automatically work out where the peripherals are. Changes since 1.9 Added support for minecraft chests behind Advanced Peripherals Added support for Liquid tanks behind Advanced Peripherals Changes since 1.8 Added support for the Advanced Peripherals Block Reader Added support for Liquids in the RS Bridge Changes since 1.7 Updated the script for ComputerCraft Tweaked. Chests and Tanks have different function names when getting info via modems. Added checks to support both new and old methods. Added support for industrial foregoing blackhole tanks. Replacing multiple spaces in names with a single space. Updated Energy section to support new function names. Changes since 1.6 Made significant changed to how peripherals are checked and processed. Redesigned how the contents is processed and stored so that there is a timestamp. The timestamp allows remote computer information to be processed correctly. Each computer must have a unique id set, if the same id is used for two systems, then the last one to update the table will win and you won't see all the content. Added ItemsFullPercentAt and FluidFullPercentAt to set what level is considered full. Changes since 1.5 Added a workaround to ignore BuildCraft pipes if attached Changes since 1.4 Added support for PeripheralPlusOne on Minecraft 1.12.2 Currently only supports ME Systems via the ME Bridge Changes since 1.3 Changed filterexclude to blacklist and added whitelist Changes since 1.2 Changed the way ME systems are processed as it was very slow. Added filtering so that certain names of items can be excluded. This was again a problem on ME systems with a lot of items in them. Changes since 1.1 Fixed a bug with tanks. Used to check if getInventoryName existed to determine if the peripheral is a tank or not. Now using the getType function instead. Changed the string.match to string.find http://youtu.be/KT-2hKjUpGA --]] -- Below are values you can change local isMain = true; local id = "Main Base"; local UpdateIntervalSeconds = 60; local ItemsFullPercentAt = 256; local FluidFullPercentAt = 256; local VersionInfo = "Base Monitor 1.9.1"; local titleTextColor = colors.blue; local titleBackColor = colors.white; local tankTextColor = colors.black; local tankBackColor = colors.lime; local chestTextColor = colors.white; local chestBackColor = colors.purple; local cacheTextColor = colors.white; local cacheBackColor = colors.cyan; local powerTextColor = colors.black; local powerBackColor = colors.orange; --[[ Add or remove values here to exclude items from being displayed. It is case insensitive and it will look for matches. So an item called "Nether Brick" will not be displayed if any of the following is set "Brick","brick","rick","ck" This also means that of you set a filter call "iron" then it will remove all items containing iron. it will not show Iron Ore, Iron Block, Iron Helmet, etc. --]] local blacklist = {"Flesh","Nugget","Brain","Sapling","Seed","egg","eye"}; --[[ Add or remove values here to only show items matching these names. It is case insensitive and it will look for matches. So an item called "Nether Brick" will be displayed if any of the following is set "Brick","brick","rick","ck" This also means that of you set a filter called "iron" then it will show all items containing iron. it will show show Iron Ore, Iron Block, Iron Helmet, etc. To disable the whitelist set it to local whitelist = ""; To enable the whitelist set it to local whitelist = {"Diamond","Gold"}; --]] local whitelist = ""; local NameLen = 18; local mainChannel = 2; -- Above are values you can change print("Starting "..VersionInfo); local peripherals = peripheral.getNames(); local mon; local wmod; local x,y; local CurColumn = 0; local MaxColumn; local ColumnWidth; local CurLine = 2; local ContentData = {}; function padString (sText, iLen) local iTextLen = string.len(sText); -- Too short, pad if (iTextLen < iLen) then local iDiff = iLen - iTextLen; return(sText..string.rep(" ",iDiff)); end -- Too long, trim if (iTextLen > iLen) then return(string.sub(sText,1,iLen)); end -- Exact length return(sText); end function prepmonitor(objectmon) mon = peripheral.wrap(objectmon); if (mon.isColor() == false) then titleTextColor = colors.black; titleBackColor = colors.white; tankTextColor = colors.black; tankBackColor = colors.white; chestTextColor = colors.black; chestBackColor = colors.white; cacheTextColor = colors.black; cacheBackColor = colors.white; powerTextColor = colors.black; powerBackColor = colors.white; end end function updateTable(strSource,strName,strAmount,timestamp,strLegend) local isWhitelisted = true; if (type(whitelist) == "table") then isWhitelisted = false; for l,filter in pairs(whitelist) do if (string.find(string.lower(strName),string.lower(filter)) ~= nil) then isWhitelisted = true; end end end if (isWhitelisted == false) then return; end if (type(blacklist) == "table") then for l,filter in pairs(blacklist) do if (string.find(string.lower(strName),string.lower(filter)) ~= nil) then return; end end end if (ContentData[strSource] == nil) then ContentData[strSource] = {}; end if (ContentData[strSource][timestamp] == nil) then ContentData[strSource][timestamp] = {}; end if (ContentData[strSource][timestamp][strName] == nil) then ContentData[strSource][timestamp][strName] = {}; end if (ContentData[strSource][timestamp][strName]["count"] == nil) then ContentData[strSource][timestamp][strName]["count"] = strAmount; else ContentData[strSource][timestamp][strName]["count"] = ContentData[strSource][timestamp][strName]["count"] + strAmount; end ContentData[strSource][timestamp][strName]["legend"] = strLegend; end function printmon(strName,strAmount,strMax,strLegend) local textColor; local backColor; local FullPercentAt = ItemsFullPercentAt; if (strLegend == "#") then textColor = chestTextColor; backColor = chestBackColor; strLegend = ""; end if (strLegend == "+") then textColor = tankTextColor; backColor = tankBackColor; FullPercentAt = FluidFullPercentAt; strLegend = ""; end if (strLegend == "*") then textColor = powerTextColor; backColor = powerBackColor; strLegend = ""; end if (strLegend == "$") then textColor = cacheTextColor; backColor = cacheBackColor; strLegend = ""; end local line = string.format("%s %3i%s",padString(strName,NameLen+1),strAmount,padString(strLegend,1)); if (strAmount >= 1000000) then line = string.format("%s %3iM%s",padString(strName,NameLen),math.floor(strAmount/1000000),padString(strLegend,1)); elseif (strAmount >= 1000) then line = string.format("%s %3iK%s",padString(strName,NameLen),math.floor(strAmount/1000),padString(strLegend,1)); end local ColPadding = 0; if (CurColumn > 0) then ColPadding = 1; end local CurX = math.floor((CurColumn*ColumnWidth))+math.floor(CurColumn*ColPadding)+1; if (CurColumn == 0) then -- print("CurX:"..CurX); end mon.setCursorPos(CurX,CurLine); --local percent = strAmount / strMax * 100; mon.setBackgroundColor(backColor); local percent = strAmount / FullPercentAt * 100; if (percent > 100) then percent = 100; end local barlength = math.floor(percent / 100 * (string.len(line)-1)); --if (CurColumn == 0) then -- barlength = barlength + 1; --end if (string.len(line) > barlength) then local msg = string.sub(line,1,barlength); mon.setTextColor(textColor); mon.write(msg); --[[if (percent == 0) then mon.setBackgroundColor(); else mon.setBackgroundColor(colors.black); end--]] mon.setBackgroundColor(colors.black); mon.setTextColor(backColor); mon.write(string.sub(line,barlength+1,-2)) else local spaces = barlength - string.len(line); mon.write(line); mon.write(string.rep(" ",spaces)); end mon.setTextColor(colors.white); CurColumn = CurColumn + 1; if (CurColumn > MaxColumn) then CurColumn = 0; CurLine = CurLine + 1; end return true; end -- Find a monitor function findMonitor() for i,name in pairs(peripherals) do for j,method in pairs(peripheral.getMethods(name)) do if (method == 'getCursorPos') then prepmonitor(name); end end end end -- Find a wireless modem function findWirelessModem() local foundWireless = false; for i,name in pairs(peripherals) do for j,method in pairs(peripheral.getMethods(name)) do if (method == 'isWireless') then wmod = peripheral.wrap(name); if (wmod.isWireless()) then wmod.closeAll(); foundWireless = true; break; else wmod = {}; end end end if (foundWireless) then break; end end end function collectLocalInfo() local timestamp = os.clock(); for i,name in pairs(peripherals) do local p = peripheral.wrap(name); local displayNames = {}; if (p.getBlockData ~= nil) then print("Processing Advanced Peripherals"); local blockdata = p.getBlockData(); if (blockdata.Items ~= nil) then local blockitems; if (blockdata.Items.Items ~= nil) then blockitems = blockdata.Items.Items; else blockitems = blockdata.Items; end if (blockitems) then print("Processing Item Storage via Advanced Peripherals"); local items = {}; for j in pairs(blockitems) do local iteminfo = blockitems[j]; displayname = iteminfo.id; if (blockitems[j].Item ~= nil) then -- Workaround for Mekanism bins displayname = blockitems[j].Item.id; end if (displayname) then if(string.find(displayname,":") ~= nil) then k = string.find(displayname,":")+1; displayname = string.sub(displayname,k); end displayname = string.gsub(displayname,"%s+"," "); local itemcount = iteminfo.Count; if (itemcount == nil and iteminfo.SizeOverride ~= nil) then itemcount = iteminfo.SizeOverride; end if (itemcount == nil) then itemcount = 0; end if (not items[displayname]) then items[displayname] = itemcount; else items[displayname] = items[displayname] + itemcount; end end end local k = 0; for key,val in pairs(items) do k = k + 1; updateTable(id,key,val,timestamp,"#"); end end end if (blockdata.GasTanks) then print("Processing Gas Storage via Advanced Peripherals"); local items = {}; for j in pairs(blockdata.GasTanks) do local iteminfo = blockdata.GasTanks[j]; displayname = iteminfo.stored.gasName; if (displayname) then if(string.find(displayname,":") ~= nil) then k = string.find(displayname,":")+1; displayname = string.sub(displayname,k); end displayname = string.gsub(displayname,"%s+"," "); local amount = 0; if (not items[displayname]) then amount = iteminfo.stored.amount; if (amount == nil) then amount = 0; end amount = math.floor(amount/1000); items[displayname] = amount; else amount = iteminfo.stored.amount; if (amount == nil) then amount = 0; end amount = math.floor(amount/1000); items[displayname] = items[displayname] + amount; end end end local k = 0; for key,val in pairs(items) do k = k + 1; updateTable(id,key,val,timestamp,"+"); end end if (blockdata.FluidTanks) then print("Processing Fluid Storage via Advanced Peripherals"); local items = {}; for j in pairs(blockdata.FluidTanks) do local iteminfo = blockdata.FluidTanks[j]; displayname = iteminfo.stored.FluidName; if (displayname) then if(string.find(displayname,":") ~= nil) then k = string.find(displayname,":")+1; displayname = string.sub(displayname,k); end displayname = string.gsub(displayname,"%s+"," "); local amount = 0; if (not items[displayname]) then amount = iteminfo.stored.Amount; if (amount == nil) then amount = 0; end amount = math.floor(amount/1000); items[displayname] = amount; else amount = iteminfo.stored.Amount; if (amount == nil) then amount = 0; end amount = math.floor(amount/1000); items[displayname] = items[displayname] + amount; end end end local k = 0; for key,val in pairs(items) do k = k + 1; updateTable(id,key,val,timestamp,"+"); end end end if (p.getTankInfo ~= nil or p.getFilledPercentage ~= nil or p.tanks) then print("Processing Tank"); local iteminfo; if (p.getTankInfo ~= nil) then iteminfo = p.getTankInfo(); end if (p.getFilledPercentage ~= nil) then iteminfo = p.getStored(); end if (p.tanks ~= nil) then tankinfo = p.tanks(); -- Industrial Foregoing blackhole tank if (tankinfo[1] ~= nil) then iteminfo = tankinfo[1]; end end if (iteminfo ~= nil) then local displayname = "Empty"; local amount = 0; if (iteminfo[1] ~= nil) then if (iteminfo[1].contents) then displayname = iteminfo[1].contents.rawName; amount = iteminfo[1].contents.amount; amount = math.floor(amount/1000); end end if (iteminfo.name ~= nil) then displayname = iteminfo.name; end if (iteminfo.amount ~= nil) then amount = iteminfo.amount; amount = math.floor(amount/1000); end if(string.find(displayname,":") ~= nil) then k = string.find(displayname,":")+1; displayname = string.sub(displayname,k); end displayname = string.gsub(displayname,"%s+"," "); if (amount ~= 0) then updateTable(id,displayname,amount,timestamp,"+"); end end end if (p.getStoredItems ~= nil) then print("Processing Cache"); local iteminfo = p.getStoredItems(); if (iteminfo) then local displayname = iteminfo.display_name; updateTable(id,displayname,iteminfo.qty,timestamp,"$"); end end if (p.getEnergyStored ~= nil or p.getTotalEnergy ~= nil or p.getEnergy ~= nil) then print("Processing Energy"); local energy; if (p.getEnergyStored ~= nil) then energy = p.getEnergyStored(); end if (p.getTotalEnergy ~= nil) then energy = p.getTotalEnergy(); end if (p.getEnergy ~= nil) then energy = p.getEnergy(); end if (energy ~= nil) then updateTable(id,"Energy",energy,timestamp,"*"); end end if (p.getInventorySize ~= nil or p.size ~= nil) then print("Processing Chest"); local chestSize = 0; if (p.getInventorySize) then chestSize = p.getInventorySize(); end if (p.size) then chestSize = p.size(); end if (chestSize ~= nil) then local items = {}; for j=1,chestSize,1 do local iteminfo = nil; if (p.getStackInSlot) then iteminfo = p.getStackInSlot(j); end if (p.getItemDetail) then iteminfo = p.getItemDetail(j); end if (iteminfo) then displayname = iteminfo.display_name; if (displayname == nil) then displayname = iteminfo.displayName; end if (displayname) then displayname = string.gsub(displayname,"%s+"," "); if (not items[displayname]) then local itemcount = iteminfo.qty; if (itemcount == nil) then itemcount = iteminfo.count; end items[displayname] = itemcount; else local itemcount = iteminfo.qty; if (itemcount == nil) then itemcount = iteminfo.count; end items[displayname] = items[displayname] + itemcount; end end end end local k = 0; for key,val in pairs(items) do k = k + 1; updateTable(id,key,val,timestamp,"#"); end end end if (p.getAvailableItems ~= nil) then print("Processing ME System"); local itemarray = p.getAvailableItems(); if (itemarray ~= nil) then for j=1,table.getn(itemarray),1 do if (itemarray[j].size > 0) then local fingerprint = itemarray[j].fingerprint; if ( (displayNames[fingerprint.id] == nil) or (displayNames[fingerprint.id] == fingerprint.id)) then local ItemDetail = p.getItemDetail(fingerprint); if (ItemDetail ~= nil) then displayNames[fingerprint.id] = ItemDetail.basic().display_name; else displayNames[fingerprint.id] = fingerprint.id; end end updateTable(id,displayNames[fingerprint.id],itemarray[j].size,timestamp,"#"); end end end end if (p.listItems ~= nil) then print("Processing ME/RS Bridge"); local itemarray = p.listItems(); if (itemarray ~= nil) then for j=1,table.getn(itemarray),1 do if (itemarray[j].amount > 0) then local fingerprint = itemarray[j].name; local displayName = itemarray[j].displayName; displayName = string.gsub(displayName,"%s+"," "); updateTable(id,displayName,itemarray[j].amount,timestamp,"#"); end end end if (p.listFluids ~= nil) then local fluidarray = p.listFluids(); if (fluidarray ~= nil) then for j=1,table.getn(fluidarray),1 do if (fluidarray[j].amount > 0) then local fingerprint = fluidarray[j].name; local displayName = fluidarray[j].displayName; displayName = string.gsub(displayName,"%s+"," "); local amount = fluidarray[j].amount; amount = math.floor(amount/1000); updateTable(id,displayName,amount,timestamp,"+"); end end end end end print("Done"); end end function updateMonitor() x,y = mon.getSize(); ColumnWidth = NameLen + 7; MaxColumn = math.floor(x / (ColumnWidth))-1; mon.setBackgroundColor(colors.black); mon.clear(); CurColumn = 0; CurLine = 1; mon.setCursorPos(1,1); mon.setTextColor(colors.white); mon.setTextScale(0.5); mon.write(VersionInfo); -- Sort by Base names local sortedSources = {}; for n in pairs(ContentData) do table.insert(sortedSources, n); end table.sort(sortedSources); local name = ""; for i,source in ipairs(sortedSources) do if (name ~= source) then name = source; CurColumn = 0; mon.setTextColor(titleTextColor); mon.setBackgroundColor(titleBackColor); mon.setCursorPos(1,CurLine+1); mon.write(padString("Contents for "..name,x-1)); CurLine = CurLine + 2; end sortedTimestamps = {}; for timestamp in pairs(ContentData[source]) do table.insert(sortedTimestamps,timestamp); end table.sort(sortedTimestamps); latest = nil; for j=table.maxn(sortedTimestamps),1,-1 do if (latest == nil) then latest = sortedTimestamps[j]; else ContentData[source][sortedTimestamps[j]] = nil; end end for itemname in pairs(ContentData[source][latest]) do displayname = itemname; count = ContentData[source][latest][itemname]["count"]; legend = ContentData[source][latest][itemname]["legend"]; max = 0; printmon(displayname,count,max,legend); end end end -- This is the main section of the script findMonitor(); findWirelessModem(); if (isMain == true) then if (type(wmod.isWireless) == "function") then wmod.open(mainChannel); else print("You don't have a wireless modem, and this is set as the main computer"); end end ContentData = {}; local timerUpdate = os.startTimer(UpdateIntervalSeconds); local updateCount = 0; local wirelessEventCount = 0; -- Perform Initial Collection and Update the Monitor collectLocalInfo(); updateMonitor(); -- Main program loop while true do local event, param1, param2, param3, param4, param5 = os.pullEvent(); print("Received event:"..event); if (event == "timer") then if (param1 == timerUpdate) then collectLocalInfo(); if (wmod) then if (isMain == false) then wmod.transmit(mainChannel,1,ContentData); end end updateMonitor(); wirelessEventCount = 0; timerUpdate = os.startTimer(UpdateIntervalSeconds); end end if (event == "modem_message") then if (isMain == true) then wirelessEventCount = wirelessEventCount + 1; for source,data in pairs(param4) do if (ContentData[source] == nil) then ContentData[source] = {}; end ContentData[source] = param4[source]; end if (wirelessEventCount >= 10) then timerUpdate = os.startTimer(1); end end end if (event == "monitor_touch") or (event == "monitor_resize") then print("Updating the Monitor"); updateMonitor(); end if (event == "peripheral") or (event == "peripheral_detach") then print("Updating the peripheral list"); peripherals = peripheral.getNames(); end end