[READ-ONLY] Mirror of https://github.com/thoda-dev/DU-Industry-HUD. A simple HUD for monitoring and managing industry in Dual Universe
dual-universe lua
0

Configure Feed

Select the types of activity you want to include in your feed.

v4.3.0 - added an option to disable storage monitoring

Thomas (Feb 22, 2023, 7:43 PM +0100) 40bb90dd 978b82e0

+240 -228
+1 -1
Master Program/config.json
··· 1 - {"events":[],"handlers":[{"code":"--[[\n DU-Nested-Coroutines by Jericho\n Permit to easier avoid CPU Load Errors\n Source available here: https://github.com/Jericho1060/du-nested-coroutines\n]]--\n\nif coroutine.status(MainCoroutine) == \"dead\" then\n MainCoroutine = coroutine.create(runCoroutines)\nend\nif coroutine.status(MainCoroutine) == \"suspended\" then\n assert(coroutine.resume(MainCoroutine))\nend","filter":{"args":[],"signature":"onUpdate()","slotKey":"-4"},"key":"0"},{"code":"if tonumber(text) then\n if #text > 8 then\n system.print(\"the value should not be higher than 99 999 999.\")\n else\n craft_quantity_digits = {\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\"}\n for i = #text, 1, -1 do\n local c = text:sub(i,i)\n craft_quantity_digits[9-(#text-(i-1))] = c\n end\n end\nelse\n system.print(\"You must type a Number\")\nend","filter":{"args":[{"variable":"*"}],"signature":"onInputText(text)","slotKey":"-4"},"key":"1"},{"code":"if hud.actions.stop[action] ~= nil then\n local success, message = pcall(hud.actions.stop[action])\n if not success then\n system.print(\"Action Stop '\" .. action .. \"' Error : \" .. message) \n end\nend","filter":{"args":[{"variable":"*"}],"signature":"onActionStop(action)","slotKey":"-4"},"key":"2"},{"code":"if hud.actions.start[action] ~= nil then\n local success, message = pcall(hud.actions.start[action])\n if not success then\n system.print(\"Action Start '\" .. action .. \"' Error : \" .. message) \n end\nend","filter":{"args":[{"variable":"*"}],"signature":"onActionStart(action)","slotKey":"-4"},"key":"3"},{"code":"Storage.clear()","filter":{"args":[],"signature":"onStop()","slotKey":"-1"},"key":"4"},{"code":"version = \"v4.2.1\"\n--[[\n DU Industry HUD By Jericho\n]]\nlocal log_split = \"=================================================\"\n--printing version in lua chat\nsystem.print(log_split)local a=\"\"local b=math.ceil((50-#version-2)/2)for c=1,b,1 do a=a..'='end;a=a..\" \"..version..\" \"for c=1,b,1 do a=a..'='end;system.print(a)system.print(log_split)\n--[[\n Lua parameters\n]]\nfontSize = 12 --export: the fonct size\nshowRecipeData = true --export: display the recipe ingredients in the machine detail\n\nenableRefinerMonitoring = true --export: enable or disable the Refiners monitoring\nenableAssemblyMonitoring = true --export: enable or disable the Assembly lines monitoring\nenableSmelterMonitoring = true --export: enable or disable the Smelters monitoring\nenableChemicalMonitoring = true --export: enable or disable the Chemical industries monitoring\nenableElectronicsMonitoring = true --export: enable or disable the Electronics Industries monitoring\nenableGlassMonitoring = true --export: enable or disable the Glass Furnace monitoring\nenableHoneycombMonitoring = true --export: enable or disable the Honeycomb Refineries monitoring\nenableRecyclerMonitoring = true --export: enable or disable the Recyclers monitoring\nenableMetalworkMonitoring = true --export: enable or disable the Metalworks monitoring\nenable3DPrinterMonitoring = true --export: enable or disable the 3D Printers monitoring\nenableTransferMonitoring = true --export: enable or disable the transfer units monitoring\nenableRemoteControl = true --export: enable the HUD to control machines (start/stop/batch/maintain)\nelementsByPage = 20 --export: maximum amount of elements displayed on a single page\ndateFormat = \"en\" --export: the country code to format the date\nmaxAmountOfElementsLoadedByFrame = 500 --export: if cpu load errors at start, lower that value\nmachinesRefreshedByFrame = 100 --how many machines are refreshed by frame\nmachineDetailDisplayDistance = 0 --export: the distance in meters to display the machine details\ndisplayType = 0 --export: the default display type: 0=ALL, 1=Table, 2=Augmented Reality\ndisplayMode = 0 --export: the default display type: 0=ALL, 1=Industry Only, 2=Storage Only, 3=None\nsortingType = 1 --export: the default sorting of elements in table: 1=Element Name, 2=Item in containers or product of industries, 3=Element ID\n\n\n--[[\n\treceivers channels for each type of machine\n]]\nchannel_for_refiner = \"receiver_refiner\" --export: receiver channel to send orders to refiners\nchannel_for_assembly = \"receiver_assembly\" --export: receiver channel to send orders to assembly lines\nchannel_for_smelter = \"receiver_smelters\" --export: receiver channel to send orders to smelters\nchannel_for_chemical = \"receiver_chemical\" --export: receiver channel to send orders to chemical indutries\nchannel_for_electronics = \"receiver_electronics\" --export: receiver channel to send orders to electronic industries\nchannel_for_glass = \"receiver_glass\" --export: receiver channel to send orders to glass furnace\nchannel_for_honeycomb = \"receiver_honeycomb_recycler\" --export: receiver channel to send orders to honeycomb refiniries\nchannel_for_recycler = \"receiver_honeycomb_recycler\" --export: receiver channel to send orders to recylers\nchannel_for_metalwork = \"receiver_metalworks\" --export: receiver channel to send orders to metalworks\nchannel_for_3d_printer = \"receiver_3dprinters\" --export: receiver channel to send orders to 3d printers\nchannel_for_transfer = \"receiver_transfert\" --export: receiver channel to send orders to tranfer units\n\n--Storage options\ncontainerProficiencyLvl = 5 --export: Talent level for Container Proficiency\ncontainerOptimizationLvl = 0 --export: Talent level for Container Optimization\nstorages_prefix_list = 's1,s2,s3,s4,s5,s6,s7,s8,s9' --export: the list of the prefixes used for the storage monitoring, comma separated values\n\n--split a string on a delimiter By jericho\nfunction strSplit(a,b)result={}for c in(a..b):gmatch(\"(.-)\"..b)do table.insert(result,c)end;return result end\n--formatting numbers by adding a space between thousands by Jericho\nfunction format_number(a)local b=a;while true do b,k=string.gsub(b,\"^(-?%d+)(%d%d%d)\",'%1 %2')if k==0 then break end end;return b end\n--Utility functions By jericho, see full source at https://github.com/Jericho1060/DualUniverse\nfunction removeDuplicatesInTable(a)local b={}local c={}for d,e in ipairs(a)do if not b[e]then c[#c+1]=e;b[e]=true end end;return c end;function strSplit(a,b)result={}for c in(a..b):gmatch(\"(.-)\"..b)do table.insert(result,c)end;return result end;function SecondsToClockString(a)local a=tonumber(a)if a==nil or a<=0 then return\"-\"else days=string.format(\"%2.f\",math.floor(a/(3600*24)))hours=string.format(\"%2.f\",math.floor(a/3600-days*24))mins=string.format(\"%2.f\",math.floor(a/60-hours*60-days*24*60))secs=string.format(\"%2.f\",math.floor(a-hours*3600-days*24*60*60-mins*60))str=\"\"if tonumber(days)>0 then str=str..days..\"d \"end;if tonumber(hours)>0 then str=str..hours..\"h \"end;if tonumber(mins)>0 then str=str..mins..\"m \"end;if tonumber(secs)>0 then str=str..secs..\"s\"end;return str end end;function removeQualityInName(a)if not a then return''end;return a:lower():gsub('basic ',''):gsub('uncommon ',''):gsub('advanced ',''):gsub('rare ',''):gsub('exotic ','')end;function has_value(a,b)for c,d in ipairs(a)do if d==b then return true end end;return false end\n--return RGB colors calculated from a gradient between two colors\nfunction getRGBGradient(a,b,c,d,e,f,g,h,i,j)a=-1*math.cos(a*math.pi)/2+0.5;local k=0;local l=0;local m=0;if a>=.5 then a=(a-0.5)*2;k=e-a*(e-h)l=f-a*(f-i)m=g-a*(g-j)else a=a*2;k=b-a*(b-e)l=c-a*(c-f)m=d-a*(d-g)end;return k,l,m end\n--time script to get client date and time by Jericho, see full source at https://github.com/Jericho1060/DualUniverse\nfunction DUCurrentDateTime(a)local b=system.getUtcTime()if not a then b=b+system.getUtcOffset()end;local c=24*60*60;local d=365*c;local e=d+c;local f=4*d+c;local g=4;local h=1970;local i={-1,30,58,89,119,150,180,211,242,272,303,333,364}local j={}for k=1,2 do j[k]=i[k]end;for k=3,13 do j[k]=i[k]+1 end;local l,m,n,o,p,q,r,s;local t=i;s=b;l=math.floor(s/f)s=s-l*f;l=l*4+h;if s>=d then l=l+1;s=s-d;if s>=d then l=l+1;s=s-d;if s>=e then l=l+1;s=s-e else t=j end end end;m=math.floor(s/c)s=s-m*c;local n=1;while t[n]<m do n=n+1 end;n=n-1;local o=m-t[n]p=(math.floor(b/c)+g)%7;if p==0 then p=7 end;q=math.floor(s/3600)s=s-q*3600;r=math.floor(s/60)function round(u,v)if v then return utils.round(u/v)*v end;return u>=0 and math.floor(u+0.5)or math.ceil(u-0.5)end;s=round(s-r*60)local w={\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\",\"Sunday\"}local x={\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\",\"Sun\"}local y={\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\"}local z={\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"}return l,n,o,q,r,s,p,w[p],x[p],y[n],z[n],m+1 end\n \n--databank hub library By Jericho, see full source at https://github.com/Jericho1060/DualUniverse\nbankhub={}function bankhub:new(banks)o={}setmetatable(o,self)self.__index=self;o.banks=banks or{}function o.clear()return o:_clear()end;function o.getNbKeys()return o:_getNbKeys()end;function o.getKeys()return o:_getKeys()end;function o.hasKey(a)return o:_hasKey(a)end;function o.getStringValue(a)return o:_getStringValue(a)end;function o.getIntValue(a)return o:_getIntValue(a)end;function o.getFloatValue(a)return o:_getFloatValue(a)end;return o end;function bankhub:add(b)table.insert(self.banks,b)self.banks_size=#self.banks end;function bankhub:_clear()for c,d in pairs(self.banks)do d.clear()end end;function bankhub:_getNbKeys()local e=0;for c,d in pairs(self.banks)do e=e+d.getNbKeys()end;return e end;function bankhub:_getKeys()local e={}for c,d in pairs(self.banks)do local f=json.decode(d.getKeys())for c,g in pairs(f)do table.insert(e,g)end end;return json.encode(e)end;function bankhub:_hasKey(a)for c,d in pairs(self.banks)do if d.hasKey(a)==1 then return 1 end end;return 0 end;function bankhub:_getStringValue(a)for c,d in pairs(self.banks)do if d.hasKey(a)==1 then return d.getStringValue(a)end end;return nil end;function bankhub:_getIntValue(a)for c,d in pairs(self.banks)do if d.hasKey(a)==1 then return banks.getIntValue(a)end end;return nil end;function bankhub:_getFloatValue(a)for c,d in pairs(self.banks)do if d.hasKey(a)==1 then return banks.getFloatValue(a)end end;return nil end\n--time script to get client date and time by Jericho, see full source at https://github.com/Jericho1060/DualUniverse\nfunction DUCurrentDateTime(a)local b=system.getUtcTime()if not a then b=b+system.getUtcOffset()end;local c=24*60*60;local d=365*c;local e=d+c;local f=4*d+c;local g=4;local h=1970;local i={-1,30,58,89,119,150,180,211,242,272,303,333,364}local j={}for k=1,2 do j[k]=i[k]end;for k=3,13 do j[k]=i[k]+1 end;local l,m,n,o,p,q,r,s;local t=i;s=b;l=math.floor(s/f)s=s-l*f;l=l*4+h;if s>=d then l=l+1;s=s-d;if s>=d then l=l+1;s=s-d;if s>=e then l=l+1;s=s-e else t=j end end end;m=math.floor(s/c)s=s-m*c;local n=1;while t[n]<m do n=n+1 end;n=n-1;local o=m-t[n]p=(math.floor(b/c)+g)%7;if p==0 then p=7 end;q=math.floor(s/3600)s=s-q*3600;r=math.floor(s/60)function round(u,v)if v then return utils.round(u/v)*v end;return u>=0 and math.floor(u+0.5)or math.ceil(u-0.5)end;s=round(s-r*60)local w={\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\",\"Sunday\"}local x={\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\",\"Sun\"}local y={\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\"}local z={\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"}return l,n,o,q,r,s,p,w[p],x[p],y[n],z[n],m+1 end\n\nstatusList = {\"STOPPED\",\"RUNNING\",\"MISSING INGREDIENT\",\"OUTPUT FULL\",\"NO OUTPUT CONTAINER\",\"PENDING\",\"MISSING SCHEMATIC\",\"SERVER ERROR\", \"STOP REQUESTED\"}\nfunction getIndustryStatusClass(status)\n if status == 1 then\n return \"text-info\"\n elseif status == 2 then\n return \"text-success\"\n elseif ((status >= 3) and (status <= 5)) or (status == 7) then\n return \"text-danger\"\n elseif status == 6 then\n return \"text-primary\"\n elseif status >= 8 and status <= 9 then\n return \"text-warning\"\n end\n return \"\" --default value for other status that can be added\nend\nfunction getIndustryStatusBgClass(status)\n if status then\n if status == 1 then\n return \"bg-info\"\n elseif status == 2 then\n return \"bg-success\"\n elseif ((status >= 3) and (status <= 5)) or (status == 7) then\n return \"bg-danger\"\n elseif status == 6 then\n return \"bg-primary\"\n elseif status >= 8 and status <= 9 then\n return \"bg-warning\"\n end\n end\n return \"\" --default value for other status that can be added\nend\nfunction getIndustryStatusBorderClass(status)\n if status then\n if status == 1 then\n return \"border-info\"\n elseif status == 2 then\n return \"border-success\"\n elseif ((status >= 3) and (status <= 5)) or (status == 7) then\n return \"border-danger\"\n elseif status == 6 then\n return \"border-primary\"\n elseif status >= 8 and status <= 9 then\n return \"border-warning\"\n end\n end\n return \"\" --default value for other status that can be added\nend\nfunction ConvertLocalToWorld(a,b,c,d,e)local f={a[1]*c[1],a[1]*c[2],a[1]*c[3]}local g={a[2]*d[1],a[2]*d[2],a[2]*d[3]}local h={a[3]*e[1],a[3]*e[2],a[3]*e[3]}return{f[1]+g[1]+h[1]+b[1],f[2]+g[2]+h[2]+b[2],f[3]+g[3]+h[3]+b[3]}end\n\n\nchannels = {}\nchannels['refiner'] = channel_for_refiner\nchannels['assembly line'] = channel_for_assembly\nchannels['smelter'] = channel_for_smelter\nchannels['chemical industry'] = channel_for_chemical\nchannels['electronics industry'] = channel_for_electronics\nchannels['glass furnace'] = channel_for_glass\nchannels['honeycomb refinery'] = channel_for_honeycomb\nchannels['recycler'] = channel_for_recycler\nchannels['metalwork industry'] = channel_for_metalwork\nchannels['3d printer'] = channel_for_3d_printer\nchannels['transfer unit'] = channel_for_transfer\n\nbootstrap_css_colors = [[<style>.text-white {color: #fff !important;}.text-primary {color: #007bff !important;}.text-secondary {color: #6c757d !important;}.text-success {color: #28a745 !important;}.text-info {color: #17a2b8 !important;}.text-warning {color: #ffc107 !important;}.text-danger {color: #dc3545 !important;}.text-light {color: #f8f9fa !important;}.text-dark {color: #343a40 !important;}.text-body {color: #212529 !important;}.text-muted {color: #6c757d !important;}.text-black-50 {color: rgba(0, 0, 0, 0.5) !important;}.text-white-50 {color: rgba(255, 255, 255, 0.5) !important;}.bg-primary {background-color: #007bff !important;}.bg-secondary {background-color: #6c757d !important;}.bg-success {background-color: #28a745 !important;}.bg-info {background-color: #17a2b8 !important;}.bg-warning {background-color: #ffc107 !important;}.bg-danger {background-color: #dc3545 !important;}.bg-light {background-color: #f8f9fa !important;}.bg-dark {background-color: #343a40 !important;}.bg-white {background-color: #fff !important;}.bg-transparent {background-color: transparent !important;}.border-primary {border-color: #007bff !important;}.border-secondary {border-color: #6c757d !important;}.border-success {border-color: #28a745 !important;}.border-info {border-color: #17a2b8 !important;}.border-warning {border-color: #ffc107 !important;}.border-danger {border-color: #dc3545 !important;}.border-light {border-color: #f8f9fa !important;}.border-dark {border-color: #343a40 !important;}.border-white {border-color: #fff !important;}\n</style>]]\nbase_css = [[<style>.ib{position:absolute;opacity:.75;transform: translate(-50%, -50%);}.tier0{font-weight:bold;padding:5px;margin-right:5px;color:black;background-color:#fff;}.tier1{font-weight:bold;padding:5px;margin-right:5px;color:black;background-color:#fff;}.tier2{font-weight:bold;padding:5px;margin-right:5px;color:white;background-color:green;}.tier3{font-weight:bold;padding:5px;margin-right:5px;color:white;background-color:blue;}.tier4{font-weight:bold;padding:5px;margin-right:5px;color:white;background-color:purple;}.tier5{font-weight:bold;padding:5px;margin-right:5px;color:white;background-color:orange;}hr{border-top:1px solid #343a40;border-collapse:collapse;}.hr-light{border-top:1px solid #f8f9fa;}.hud_container{z-index:1000;font-size:]] .. fontSize .. [[px;border: 1px solid black;border-radius:5px;background-color: rgba(15,24,29,.85);padding:10px;}.hud_time{position: absolute;bottom: ]] .. tostring((100/1080)*100) .. [[vh;right: ]] .. tostring((10/1920)*100) .. [[vw;text-transform: uppercase;font-weight: bold;}.hud_machine_types_container{position: absolute;top: ]] .. tostring((80/1080)*100) .. [[vh;left: ]] .. tostring((10/1920)*100) .. [[vw;text-transform: uppercase;font-weight: bold;}.hud_machine_status_container{position: absolute;top: ]] .. tostring((10/1080)*100) .. [[vh;left: ]] .. tostring((10/1920)*100) .. [[vw;text-transform: uppercase;font-weight: bold;}.hud_table_container{position: absolute;top:]] .. tostring((80/1080)*100) .. [[vh;left:]] .. tostring((225/1920)*100) .. [[vw;}.hud_table_container td,.hud_table_container th, .hud_machine_control th{border-bottom:1px solid #f8f9fa;}small{font-size:.75em;}.hud_table_container td.row_selected,.hud_table_container th.row_selected{border:2px solid green;}.hud_machine_control{position: absolute;top: ]] .. tostring((300/1080)*100) .. [[vh;right: ]] .. tostring((10/1920)*100) .. [[vw;text-transform: uppercase;font-weight: bold;}</style>]]\n\n\ndatabanks = {}\ncore = nil\nemitter = nil\nindustries_id = {}\nstorages_id = {}\nindustries = {}\nstorages = {}\nelementsTypes = {}\nstoragesTypes = {}\nschematicContainer = nil\nschematicContainerId = construct.getSchematicContainerId()\nschematicStorage = {}\nfor slot_name, slot in pairs(unit) do\n if\n type(slot) == \"table\"\n and type(slot.export) == \"table\"\n and slot.getClass\n then\n if slot.getClass():lower() == 'databankunit' then\n table.insert(databanks, slot)\n elseif slot.getClass():lower():find(\"coreunit\") then\n core = slot\n elseif slot.getClass():lower() == 'emitterunit' then\n emitter = slot\n elseif schematicContainerId ~= nil and slot.getClass():lower():find('container') then\n if slot.getId() == schematicContainerId then\n schematicContainer = slot\n end\n end\n end\nend\n\nif core == nil then\n system.print(\"Connection to the core is missing\")\n unit.exit()\nend\nif schematicContainerId == nil then\n system.print(\"No Schematic Container set on the Construct\")\nend\nif schematicContainer == nil then\n system.print(\"Schematic Container is not linked to the board\")\nend\n\nif emitter == nil then \n enableRemoteControl = false\n system.print(\"Connect an Emitter to enable machine control from industry\")\nend\nif #databanks == 0 then \n enableRemoteControl = false\n system.print(\"No Databank linked\")\nend\n\n--init of bank hub\nStorage = bankhub:new(databanks)\n\n--construct pos for AR data\nconstructPos = construct.getWorldPosition()\nconstructRight = construct.getWorldRight()\nconstructForward = construct.getWorldForward()\nconstructUp = construct.getWorldUp()\n\n--script variables\nstorage_prefix = strSplit(storages_prefix_list, ',')\ndisplayTypes = {\"ALL\", \"Table\", \"Augmented Reality\"}\ndisplayModes = {\"ALL\", \"Industry\", \"Storage\", \"None\"}\nsortingTypes = {\"Element Name\", \"Item\", \"Element ID\"}\ninit = false\ninitIndex = 1\nelementsIdList = {}\nmachines_count = {}\nstorages_count = {}\nmachines_positions = {}\nstorages_positions = {}\nsystem.showScreen(true)\nstatusFilter = 0\nstatusFilterType = 0\nmaxFilterType = 0\nmaxOnPage=1\nhtml_filters = \"\"\nhtml_filters_types = \"\"\nhtml_filter_storage = \"\"\nhtml_machines = \"\"\nhtml_storage = \"\"\nhtml_time = \"\"\nhtml_ar_selected = \"\"\nhtml_control = \"\"\nhtml_credits = [[<div class=\"hud_container\" style=\"position:absolute;left:5px;bottom:5px;font-size:10px;padding:5px;\">]] .. version .. [[ - Powered By jericho1060</div>]]\n\n--pagination var\npage = 1\nmaxPage = 1\nselectedRow = 1\nselected_machine=nil\nselected_container=nil\n\n--control machine var\ncommand_1 = \"\"\ncommand_2 = \"\"\ncommand_3 = \"\"\ncraft_quantity_digits = {\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\"}\n\n--keyPressed\nctrlPressed = false\n\n\n--[[\n DU INDUSTRY HUD By Jericho\n]]\nschematicRefreshTime = 0\nhud = {}\nhud.coroutines = {}\nif schematicContainer ~= nil then\n hud.coroutines.getSchematics = function ()\n schematicRefreshTime = math.ceil(schematicContainer.updateContent())\n end\nend\nhud.coroutines.init = function()\n if not init then\n elementsTypes = {}\n industries_id = {}\n industries = {}\n\n storagesTypes = {}\n storages_id = {}\n storages = {}\n\n elementsIdList = core.getElementIdList()\n\n for index,id in ipairs(elementsIdList) do\n elementType = core.getElementDisplayNameById(id):lower()\n if (elementType:find(\"assembly line\") and enableAssemblyMonitoring == true) or\n (elementType:find(\"glass furnace\") and enableGlassMonitoring == true) or\n (elementType:find(\"3d printer\") and enable3DPrinterMonitoring == true) or\n (elementType:find(\"smelter\") and enableSmelterMonitoring == true) or\n (elementType:find(\"recycler\") and enableRecyclerMonitoring == true) or\n (elementType:find(\"refinery\") and enableHoneycombMonitoring == true) or\n (elementType:find(\"refiner\") and enableRefinerMonitoring == true) or\n (elementType:find(\"industry\")\n and (\n (elementType:find(\"chemical\") and enableChemicalMonitoring == true) or\n (elementType:find(\"electronics\") and enableElectronicsMonitoring == true) or\n (elementType:find(\"metalwork\") and enableMetalworkMonitoring == true)\n )\n ) or\n (elementType == \"transfer unit\" and enableTransferMonitoring == true) or\n elementType:lower():find(\"container\")\n then\n local formatedType = removeQualityInName(elementType)\n local pos = core.getElementPositionById(id)\n if elementType:lower():find(\"container\") then\n if storages_count[formatedType] ~= nil then\n storages_count[formatedType] = storages_count[formatedType] + 1\n else\n storages_count[formatedType] = 1\n end\n table.insert(storages_id, id)\n storages_positions['i'..id] = pos\n table.insert(storagesTypes, formatedType)\n else\n pos[3] = pos[3] + 1\n if machines_count[formatedType] ~= nil then\n machines_count[formatedType] = machines_count[formatedType] + 1\n else\n machines_count[formatedType] = 1\n end\n table.insert(industries_id, id)\n machines_positions['i'..id] = pos\n table.insert(elementsTypes, formatedType)\n end\n end\n\n if index % maxAmountOfElementsLoadedByFrame == 0 then\n coroutine.yield(self.init)\n end\n end\n elementsTypes = removeDuplicatesInTable(elementsTypes)\n table.sort(elementsTypes, function(a,b) return a:lower() < b:lower() end)\n selected_type = elementsTypes[1]\n init = true\n system.print(\"All elements loaded\")\n system.print(#storages_id .. \" storage elements found\")\n system.print(#industries_id .. \" industries found\")\n end\nend\nhud.coroutines.loadIndustries = function()\n if init and (displayMode == 0 or displayMode == 1) then\n for index,id in ipairs(industries_id) do\n local pos = machines_positions['i'..id]\n local data = core.getElementIndustryInfoById(id)\n if industries[\"i\"..tostring(id)] == nil then industries[\"i\"..tostring(id)] = {} end\n local mode = \"\"\n local tableMode = \"\"\n local maintainOrBatchQuantity = 0\n if data.maintainProductAmount > 0 then\n mode = \"<div><strong>Mode:</strong> Maintain \" .. math.floor(data.currentProductAmount) ..\"/\" .. math.floor(data.maintainProductAmount) .. \"</div>\"\n tableMode = \"Maintain \" .. math.floor(data.currentProductAmount) ..\"/\" .. math.floor(data.maintainProductAmount)\n maintainOrBatchQuantity=math.floor(data.maintainProductAmount)\n elseif data.batchesRequested > 0 and data.batchesRequested <= 99999999 then\n local current = data.batchesRequested - data.batchesRemaining\n if data.batchesRemaining < 0 then current = 0 end\n mode = \"<div><strong>Mode:</strong> Produce \" .. math.floor(current) .. \"/\" .. math.floor(data.batchesRequested) .. \"</div>\"\n tableMode = \"Produce \" .. math.floor(current) .. \"/\" .. math.floor(data.batchesRequested)\n maintainOrBatchQuantity=math.floor(data.batchesRequested)\n end\n local production = {locDisplayNameWithSize=\"No recipe selected\", tier=0}\n local schematicName = \"\"\n local tableSchematicName = \"\"\n local tableSchematicQuantity = \"\"\n local schematicColor = \"success\"\n local state = data.state\n local time=\"\"\n local tableTime=\"\"\n local recipe=\"\"\n local industryType = core.getElementDisplayNameById(id)\n local schematicId = data.requiredSchematicIds[1] or 0\n if schematicId > 0 and not industryType:lower():find(\"transfer\") then\n local sch = system.getItem(schematicId)\n local shematicQuantity = schematicStorage[\"s\" .. schematicId] or 0\n if shematicQuantity < data.requiredSchematicAmount then schematicColor = \"danger\" end\n schematicName = '<div><strong>Schematic:</strong> ' .. format_number(shematicQuantity):gsub(\".0\", \"\") .. \"/\" .. format_number(data.requiredSchematicAmount) .. \" \" .. sch.locDisplayNameWithSize .. \"</div>\"\n tableSchematicName = sch.locDisplayNameWithSize\n tableSchematicQuantity = format_number(shematicQuantity):gsub(\".0\", \"\") .. \"/\" .. format_number(data.requiredSchematicAmount)\n end\n if #data.currentProducts > 0 then\n local item_id = data.currentProducts[1].id\n production = system.getItem(item_id)\n if id ~= \"947806142\" and id ~= \"1010524904\" and not industryType:lower():find(\"transfer\") then\n if showRecipeData then\n local rdata = system.getRecipes(item_id)\n if #rdata > 0 then\n local r = nil\n for _,recipe in pairs(rdata) do\n if recipe.products[1].id == item_id then\n r = recipe\n break\n end\n end\n if r then\n recipe = \"<div><strong>Recipe:</strong>\"\n for _,v in pairs(r.ingredients) do\n local item = system.getItem(v.id)\n recipe = recipe .. \"<br>&nbsp;&nbsp;&nbsp;&nbsp;- \" .. v.quantity .. \" x \" .. item.locDisplayNameWithSize\n end\n recipe = recipe .. \"</div>\"\n end\n end\n end\n end\n if data.remainingTime == 0 and data.state == 2 then\n state = 8\n end\n if data.stopRequested and data.state ~= 1 then\n state = 9\n end\n if data.remainingTime > 0 then\n time = \"<div><strong>Time:</strong> \" .. SecondsToClockString(data.remainingTime) .. \"</div>\"\n tableTime = SecondsToClockString(data.remainingTime)\n end\n end\n local productionName = '<div><strong>Product</strong>: ' .. production.locDisplayNameWithSize .. '</div>'\n local productId = ''\n if production.id then\n productId = \"<div><strong>Main Product ID:</strong> \" .. production.id .. \"</div>\"\n end\n local elementName = core.getElementNameById(id)\n industries[\"i\"..tostring(id)] = {\n id=id,\n screenPos=library.getPointOnScreen(ConvertLocalToWorld(pos, constructPos, constructRight, constructForward, constructUp)),\n name=\"<div><strong>Industry Name:</strong> [\" .. id .. \"] \" .. elementName .. \"</div>\",\n tableName=elementName,\n type=\"<div><strong>Industry Type:</strong> \" .. industryType .. \"</div>\",\n tableType=industryType,\n typeFilter=removeQualityInName(industryType),\n state=state,\n production=production,\n productId=productId,\n productionName=productionName,\n mode=mode,\n tableMode=tableMode,\n remainingTime=time,\n tableTime=tableTime,\n schematic=schematicName,\n schematicColor=schematicColor,\n maintainOrBatchQuantity=maintainOrBatchQuantity,\n tableSchematic=tableSchematicName,\n tableSchematicQuantity=tableSchematicQuantity,\n recipe=recipe,\n stopRequested=data.stopRequested\n }\n if index % machinesRefreshedByFrame == 0 then\n coroutine.yield(self.loadIndustries)\n end\n end\n end\nend\nhud.coroutines.loadStorage = function()\n for index,id in ipairs(storages_id) do\n local pos = storages_positions['i'..id]\n local elementType = core.getElementDisplayNameById(id)\n local base_name = core.getElementNameById(id)\n local splitted = strSplit(base_name,'_')\n local item_id = nil\n local prefix = nil\n if #splitted > 1 then\n prefix = splitted[1]\n item_id = splitted[2]\n end\n local container = {\n id = id,\n type=elementType,\n name = \"[\" .. id .. \"] \" .. base_name,\n tableName = base_name,\n prefix = prefix,\n item_id = item_id,\n monitor = false,\n screenPos=library.getPointOnScreen(ConvertLocalToWorld(pos, constructPos, constructRight, constructForward, constructUp)),\n }\n if item_id and prefix then\n for _,sprefix in ipairs(storage_prefix) do\n if prefix:lower() == sprefix:lower() then\n container.monitor = true\n container.item = system.getItem(item_id)\n break\n end\n end\n end\n local container_size = \"XS\"\n local container_empty_mass = 0\n local container_volume = 0\n local contentQuantity = 0\n local percent_fill = 0\n if not elementType:lower():find(\"hub\") then\n local containerMaxHP = core.getElementMaxHitPointsById(id)\n if containerMaxHP > 68000 then\n container_size = \"XXL\"\n container_empty_mass = 88410\n container_volume = 512000 * (containerProficiencyLvl * 0.1) + 512000\n elseif containerMaxHP > 33000 then\n container_size = \"XL\"\n container_empty_mass = 44210\n container_volume = 256000 * (containerProficiencyLvl * 0.1) + 256000\n elseif containerMaxHP > 17000 then\n container_size = \"L\"\n container_empty_mass = 14842.7\n container_volume = 128000 * (containerProficiencyLvl * 0.1) + 128000\n elseif containerMaxHP > 7900 then\n container_size = \"M\"\n container_empty_mass = 7421.35\n container_volume = 64000 * (containerProficiencyLvl * 0.1) + 64000\n elseif containerMaxHP > 900 then\n container_size = \"S\"\n container_empty_mass = 1281.31\n container_volume = 8000 * (containerProficiencyLvl * 0.1) + 8000\n else\n container_size = \"XS\"\n container_empty_mass = 229.09\n container_volume = 1000 * (containerProficiencyLvl * 0.1) + 1000\n end\n else\n if splitted[3] then\n container_size = splitted[3]\n end\n if splitted[4] then\n container_amount = splitted[4]\n end\n local volume = 0\n container_volume_list = {xxl=512000, xl=256000, l=128000, m=64000, s=8000, xs=1000}\n container_size = container_size:lower()\n if container_volume_list[container_size] then\n volume = container_volume_list[container_size]\n end\n container_volume = (volume * containerProficiencyLvl * 0.1 + volume)\n container_empty_mass = 55.8\n end\n local totalMass = core.getElementMassById(id)\n local contentMassKg = totalMass - container_empty_mass\n container.totalMass = totalMass\n container.emptyMass = container_empty_mass\n container.contentMass = contentMassKg\n container.maxVolume = container_volume\n container.size = container_size\n if container.item == nil or container.item.name == \"InvalidItem\" then\n container.percent = 0\n container.quantity = 0\n else\n container.quantity = contentMassKg / (container.item.unitMass - (container.item.unitMass * (containerOptimizationLvl * 0.05)))\n container.percent = utils.round((container.item.unitVolume * container.quantity) * 100 / container_volume)\n end\n storages['i'..id] = container\n if index % machinesRefreshedByFrame == 0 then\n coroutine.yield(self.loadStorage)\n end\n end\nend\nhud.coroutines.renderHelper = function()\n local year, month, day, hour, minute, second = DUCurrentDateTime()\n html_time = [[<div class=\"hud_time hud_container\"><div style=\"text-align:center;\">]] .. string.format(\"%02d/%02d/%04d %02d:%02d:%02d\",day,month,year,hour,minute,second) .. [[</div><div style=\"text-align:right;\"><hr class=\"hr-light\"><style>.dm]] .. displayMode .. [[{border: 1px solid #28a745 !important;}.dp]] .. displayType .. [[{border: 1px solid #28a745 !important;}.sortType]] .. sortingType .. [[{border: 1px solid #28a745 !important;}</style><div>]]\n for i,v in ipairs(sortingTypes) do\n html_time = html_time .. '<span class=\"sortType' .. i ..'\" style=\"margin:5px;\">' .. v .. '</span>'\n if i < #sortingTypes then html_time = html_time .. \"|\" end\n end\n html_time = html_time .. ' - Sorting Type - Alt + 6</div><div>'\n for i,v in ipairs(displayTypes) do\n html_time = html_time .. '<span class=\"dp' .. (i-1) .. '\" style=\"margin:5px;\">' .. v .. '</span>'\n if i < #displayTypes then html_time = html_time .. \"|\" end\n end\n html_time = html_time .. ' - Display Type - Alt + 7</div><div>'\n for i,v in ipairs(displayModes) do\n html_time = html_time .. '<span class=\"dm' .. (i-1) .. '\" style=\"margin:5px;\">' .. v .. '</span>'\n if i < #displayModes then html_time = html_time .. \"|\" end\n end\n html_time = html_time .. ' - Display Mode - Alt + 8</div>'\n html_time = html_time .. '<div>Reload HUD - Alt + 9</div>'\n if schematicContainer ~= nil then\n html_time = html_time .. '<hr class=\"hr-light\"><div>Schematic Storage Refresh in ' .. schematicRefreshTime .. 's</div>'\n end\n html_time = html_time .. '</div></div>'\nend\nhud.coroutines.renderIndustries = function()\n local html = \"\"\n local html_table = \"\"\n local lastMachine = 0\n local firstMachine = 0\n local totalPage = 1\n local selectedMachine = nil\n if displayMode == 0 or displayMode == 1 then\n local selectedIndustries = {}\n for k,industry in pairs(industries) do\n if (statusFilter == 0 or industry.state == statusFilter) and (statusFilterType == 0 or (statusFilterType <= #elementsTypes and industry.typeFilter:lower() == elementsTypes[statusFilterType])) then\n if displayType == 0 then\n table.insert(selectedIndustries, industry)\n elseif displayType == 1 then\n table.insert(selectedIndustries, industry)\n elseif displayType == 2 then\n if industry.screenPos[1] > 0 and industry.screenPos[1] < 1 and industry.screenPos[2] > 0 and industry.screenPos[2] < 1 then\n table.insert(selectedIndustries, industry)\n end\n end\n end\n end\n if (displayType == 0 or displayType == 1) and statusFilterType <= #elementsTypes then\n totalPage = math.ceil(#selectedIndustries/elementsByPage)\n firstMachine = (page - 1) * elementsByPage + 1\n lastMachine = page * elementsByPage\n if lastMachine > #selectedIndustries then\n lastMachine = #selectedIndustries\n end\n html_table = html_table .. '<div class=\"hud_container hud_table_container\"><div style=\"text-align:center;border-bottom:1px solid white;\">&#x2191; &nbsp;&nbsp; Arrow Up</div><table style=\"width:100%\"><tr><th>&#x2190; &nbsp;&nbsp; Arrow Left</th><th> Page ' .. page .. '/' .. totalPage .. ' (from ' .. firstMachine .. ' to ' .. lastMachine .. ' on ' .. #selectedIndustries .. ')</th><th>Arrow Right &nbsp;&nbsp; &#x2192;</th></tr></table><table><tr><th>id</th><th>Machine Name & Type</th><th>Selected Recipe & schematic</th><th>Status</th><th>Mode</th><th>Time Remaining</th></tr>'\n end\n local count = 1\n if sortingType == 1 then\n table.sort(selectedIndustries, function(a,b) return a.tableName < b.tableName end)\n elseif sortingType == 2 then\n table.sort(selectedIndustries, function(a,b) return a.production.locDisplayNameWithSize < b.production.locDisplayNameWithSize end)\n elseif sortingType == 3 then\n table.sort(selectedIndustries, function(a,b) return a.id < b.id end)\n end\n for k,industry in pairs(selectedIndustries) do\n if (displayType == 0 or displayType == 2) and industry.screenPos[1] > 0 and industry.screenPos[1] < 1 and industry.screenPos[2] > 0 and industry.screenPos[2] < 1 then\n local showDetail = false\n if industry.screenPos[3] <= machineDetailDisplayDistance then\n showDetail = true\n elseif industry.screenPos[1] < 0.55 and industry.screenPos[1] > 0.45 and industry.screenPos[2] < 0.55 and industry.screenPos[2] > 0.45 then\n showDetail = true\n end\n local font_size = fontSize * ((200-industry.screenPos[3])/200)\n local zindex = utils.round(1000 - industry.screenPos[3])\n html = html .. [[<div class=\"ib\" style=\"left:]] .. utils.round(industry.screenPos[1]*100) .. [[%;top:]] .. utils.round(industry.screenPos[2]*100) .. [[%;font-size:]] .. font_size .. [[px;z-index:]]..zindex..[[;\"><div class=\"]] .. getIndustryStatusBgClass(industry.state) .. [[\" style=\"padding:2px;text-transform:capitalize;\"><span class=\"tier]] .. industry.production.tier .. [[\">T]] .. industry.production.tier .. [[</span><strong>]] .. industry.production.locDisplayNameWithSize .. [[</strong></div>]]\n if showDetail then\n html = html .. [[<div class=\"bg-light text-dark\" style=\"margin-top:2px;padding:2px;\"><div class=\"]] .. getIndustryStatusClass(industry.state) .. [[\"><strong>]] .. statusList[industry.state] .. [[</strong></div><div>]] .. industry.productId .. industry.name .. industry.type .. industry.mode .. industry.schematic .. industry.remainingTime .. industry.recipe ..[[</div></div>]]\n end\n html = html .. [[</div>]]\n end\n if (displayType == 0 or displayType == 1) then\n local selectedClass = \"\"\n if selectedRow == (count + 1 - firstMachine)then\n selectedClass = \"row_selected\"\n selectedMachine = industry\n end\n if count >= firstMachine and count <= lastMachine then\n html_table = html_table .. '<tr><th class=\"' .. selectedClass .. '\">' .. industry.id .. '</th><th class=\"' .. selectedClass .. '\"><span class=\"' .. getIndustryStatusClass(industry.state) .. '\">' .. industry.tableName .. '</span><br><small>' .. industry.tableType .. '</small></th><th class=\"' .. selectedClass .. '\">' .. industry.production.locDisplayNameWithSize .. '<br><small class=\"text-' .. industry.schematicColor .. '\">' .. industry.tableSchematicQuantity .. \" \" .. industry.tableSchematic .. '</small></th><th class=\"' .. selectedClass .. '\"><span class=\"' .. getIndustryStatusClass(industry.state) .. '\">' .. statusList[industry.state] .. '</span></th><th class=\"' .. selectedClass .. '\">' .. industry.tableMode .. '</th><th class=\"' .. selectedClass .. '\">' .. industry.tableTime .. '</th></tr>'\n end\n end\n count = count + 1\n end\n if (displayType == 0 or displayType == 1) and statusFilterType <= #elementsTypes then\n html_table = html_table .. '</table><table style=\"width:100%\"><tr><th>&#x2190; &nbsp;&nbsp; Arrow Left</th><th> Page ' .. page .. '/' .. totalPage .. ' (from ' .. firstMachine .. ' to ' .. lastMachine .. ' on ' .. #selectedIndustries .. ')</th><th>Arrow Right &nbsp;&nbsp; &#x2192;</th></tr></table><div style=\"text-align:center;border-bottom:1px solid white;\">&#x2193; &nbsp;&nbsp; Arrow Down</div></div>'\n maxPage = totalPage\n maxOnPage = lastMachine-firstMachine+1\n end\n end\n html_machines = html .. html_table\n selected_machine = selectedMachine\nend\nhud.coroutines.renderStorage = function()\n local html = \"\"\n local html_table = \"\"\n local lastStorage = 0\n local firstStorage = 0\n local totalPage = 1\n local selectedStorage = nil\n if displayMode == 0 or displayMode == 2 then\n local selectedStorages = {}\n for k,storage in pairs(storages) do\n if statusFilterType >= maxFilterType and storage.monitor then\n if displayType == 0 then\n table.insert(selectedStorages, storage)\n elseif displayType == 1 then\n table.insert(selectedStorages, storage)\n end\n end\n end\n if (displayType == 0 or displayType == 2) then\n for k,storage in pairs(storages) do\n if storage.screenPos[1] > 0 and storage.screenPos[1] < 1 and storage.screenPos[2] > 0 and storage.screenPos[2] < 1 then\n local showDetail = false\n if storage.screenPos[3] <= machineDetailDisplayDistance then\n showDetail = true\n elseif storage.screenPos[1] < 0.55 and storage.screenPos[1] > 0.45 and storage.screenPos[2] < 0.55 and storage.screenPos[2] > 0.45 then\n showDetail = true\n end\n local font_size = fontSize * ((200-storage.screenPos[3])/200)\n local zindex = utils.round(1000 - storage.screenPos[3])\n local displayName = storage.name\n local tierBox = ''\n local itemBox = ''\n local fillGauge = ''\n if storage.item ~= nil and storage.item.name ~= \"InvalidItem\" then\n displayName = format_number(utils.round(storage.quantity*100)/100) .. \" \" .. storage.item.locDisplayNameWithSize .. \" (\" .. storage.percent .. \"%)\"\n tierBox = '<span class=\"tier' .. storage.item.tier .. '\">T' .. storage.item.tier .. '</span>'\n local i = storage.item\n local gaugePercent = storage.percent\n if storage.percent > 100 then\n gaugePercent = 100\n end\n local r,g,b = getRGBGradient(gaugePercent/100,177,42,42,249,212,123,34,177,76)\n r = utils.round(r)\n g = utils.round(g)\n b = utils.round(b)\n itemBox = [[<hr><div><strong>Item ID:</strong> ]] .. i.id .. [[</div><div><strong>Item Name:</strong> ]] .. i.locDisplayNameWithSize .. [[</div><div><strong>Item Unit Mass:</strong> ]] .. i.unitMass .. [[ kg</div><div><strong>Item Unit Volume:</strong> ]] .. i.unitVolume .. [[ m<sup>3</sup></div>]]\n fillGauge = '<div style=\"position:absolute;bottom:0;left:0px;width:' .. gaugePercent .. '%;background-color:rgb(' .. r .. ',' .. g ..',' .. b .. ');height:3px;z-index:' .. (zindex+1) .. ';\"></div>'\n end\n html = html .. [[<div class=\"ib\" style=\"left:]] .. utils.round(storage.screenPos[1]*100) .. [[%;top:]] .. utils.round(storage.screenPos[2]*100) .. [[%;font-size:]] .. font_size .. [[px;z-index:]]..zindex..[[;\"><div class=\"bg-light text-dark\" style=\"padding:2px;padding-bottom:5px;text-transform:capitalize;position:relative;\">]] .. tierBox .. [[<strong>]] .. displayName .. [[</strong>]] .. fillGauge .. [[</div>]]\n if showDetail then\n html = html .. [[<div class=\"bg-light text-dark\" style=\"margin-top:2px;padding:2px;\"><div><strong>Container Type:</strong> ]] .. storage.type .. \" \" .. storage.size .. [[</div>]] .. itemBox .. [[</div></div>]]\n end\n html = html .. [[</div>]]\n end\n end\n end\n if (displayType == 0 or displayType == 1) and statusFilterType >= maxFilterType then\n totalPage = math.ceil(#selectedStorages/elementsByPage)\n firstStorage = (page - 1) * elementsByPage + 1\n lastStorage = page * elementsByPage\n if lastStorage > #selectedStorages then\n lastStorage = #selectedStorages\n end\n html_table = html_table .. '<div class=\"hud_container hud_table_container\"><div style=\"text-align:center;border-bottom:1px solid white;\">&#x2191; &nbsp;&nbsp; Arrow Up</div><table style=\"width:100%\"><tr><th>&#x2190; &nbsp;&nbsp; Arrow Left</th><th> Page ' .. page .. '/' .. totalPage .. ' (from ' .. firstStorage .. ' to ' .. lastStorage .. ' on ' .. #selectedStorages .. ')</th><th>Arrow Right &nbsp;&nbsp; &#x2192;</th></tr></table><table><tr><th>id</th><th>Storage Name & Type</th><th>Item Name</th><th>Quantity</th><th style=\"width:100px;\">Percent fill</th></tr>'\n local count = 1\n if sortingType == 1 then\n table.sort(selectedStorages, function(a,b) return a.tableName < b.tableName end)\n elseif sortingType == 2 then\n table.sort(selectedStorages, function(a,b) return a.item.locDisplayNameWithSize < b.item.locDisplayNameWithSize end)\n elseif sortingType == 3 then\n table.sort(selectedStorages, function(a,b) return a.id < b.id end)\n end\n for k,storage in pairs(selectedStorages) do\n if count >= firstStorage and count <= lastStorage then\n local selectedClass = \"\"\n if selectedRow == (count + 1 - firstStorage)then\n selectedClass = \"row_selected\"\n selectedStorage = storage\n end\n local item_name = \"\"\n if storage.item ~= nil and storage.item.name ~= \"InvalidItem\" then\n item_name = storage.item.locDisplayNameWithSize\n end\n local gaugePercent = storage.percent\n if storage.percent > 100 then\n gaugePercent = 100\n end\n local r,g,b = getRGBGradient(gaugePercent/100,177,42,42,249,212,123,34,177,76)\n r = utils.round(r)\n g = utils.round(g)\n b = utils.round(b)\n html_table = html_table .. '<tr><th class=\"' .. selectedClass .. '\">' .. storage.id .. '</th><th class=\"' .. selectedClass .. '\">' .. storage.tableName .. '<br><small>' .. storage.type .. ' ' .. storage.size .. '</small></th><th class=\"' .. selectedClass .. '\">' .. item_name .. '</th><th class=\"' .. selectedClass .. '\">' .. format_number(utils.round(storage.quantity*100)/100) .. '</th><th class=\"' .. selectedClass .. '\">' .. storage.percent .. '%<br><div style=\"border:1px solid black;position:relative;height:5px;\"><div style=\"position:absolute;left:0;top:0;width:' .. gaugePercent .. '%;background-color:rgb(' .. r .. ',' .. g ..',' .. b .. ');height:5px;\"></div></div></th></tr>'\n end\n count = count + 1\n end\n html_table = html_table .. '</table><table style=\"width:100%\"><tr><th>&#x2190; &nbsp;&nbsp; Arrow Left</th><th> Page ' .. page .. '/' .. totalPage .. ' (from ' .. firstStorage .. ' to ' .. lastStorage .. ' on ' .. #selectedStorages .. ')</th><th>Arrow Right &nbsp;&nbsp; &#x2192;</th></tr></table><div style=\"text-align:center;border-bottom:1px solid white;\">&#x2193; &nbsp;&nbsp; Arrow Down</div></div>'\n maxPage = totalPage\n maxOnPage = lastStorage-firstStorage+1\n end\n end\n html_storage = html .. html_table\n selected_storage = selectedStorage\nend\nhud.coroutines.renderFilterStatus = function()\n html_filters = \"<style>\"\n html_filters = html_filters .. \".bg{margin:5px;padding:2px;}.bg\" .. (statusFilter+1) .. \"{border: 1px solid #28a745 !important;}\"\n html_filters = html_filters .. \"</style>\"\n html_filters = html_filters .. [[<div class=\"hud_container hud_machine_status_container\"><div><span class=\"bg bg1\" >ALL</span>|]]\n for i,status in ipairs(statusList) do\n html_filters = html_filters .. [[<span class=\"bg bg]] .. (i+1) .. [[ ]] .. getIndustryStatusClass(i) .. [[\">]] .. statusList[i] .. [[</span>]]\n if i < #statusList then html_filters = html_filters .. '|' end\n end\n html_filters = html_filters .. '</div>'\n html_filters = html_filters .. [[<hr class=\"hr-light\"><table style=\"width:100%;\"><tr><td style=\"padding-left:5px;\">&#x2190; &nbsp;&nbsp; Ctrl+Arrow Left</td><td style=\"text-align:right;padding-right:5px;\">Ctrl+Arrow Right &nbsp;&nbsp; &#x2192;</td></tr></table></div>]]\nend\nhud.coroutines.renderFilterType = function()\n maxFilterType = #elementsTypes\n if displayMode == 0 then\n maxFilterType = #elementsTypes + 1\n elseif displayMode == 2 then\n maxFilterType = 0\n end\n html_filters_types = \"<style>\"\n html_filters_types = html_filters_types .. \".bgt\" .. (statusFilterType+1) .. \"{border: 2px solid #28a745 !important;}\"\n html_filters_types = html_filters_types .. \"</style>\"\n html_filters_types = html_filters_types .. '<div class=\"hud_container hud_machine_types_container\" style=\"text-align:center;\"><div>&#x2191; &nbsp;&nbsp; Ctrl+Arrow Up</div><hr class=\"hr-light\">'\n if displayMode == 0 or displayMode == 1 then\n html_filters_types = html_filters_types .. '<div class=\"bgt1\" style=\"margin:5px;\">ALL Industries (' .. #industries_id .. ')</div>'\n for i,v in ipairs(elementsTypes) do\n html_filters_types = html_filters_types .. '<div class=\"bgt' .. (i+1) .. '\" style=\"margin:5px;\">' .. v .. ' (' .. machines_count[v] .. ')</div>'\n end\n end\n if displayMode == 0 or displayMode == 2 then\n local bgtclass = 'bgt' .. (#elementsTypes + 2)\n if displayMode == 2 then\n bgtclass = 'bgt1'\n end\n html_filters_types = html_filters_types .. '<div class=\"' .. bgtclass .. '\" style=\"margin:5px;\">Storage (' .. #storages_id .. ')</div>'\n end\n html_filters_types = html_filters_types .. '<hr class=\"hr-light\"><div>&#x2193; &nbsp;&nbsp; Ctrl+Arrow Down</div></div>'\nend\nhud.coroutines.renderSelectedAR = function()\n local html = \"\"\n if displayType == 0 or displayType == 1 then\n if selected_machine then\n local industry = selected_machine\n html = html .. [[<div class=\"ib ]] .. getIndustryStatusBorderClass(industry.state) .. [[\" style=\"border:5px solid white;left:]] .. utils.round(industry.screenPos[1]*100) .. [[%;top:]] .. utils.round(industry.screenPos[2]*100) .. [[%;font-size:]] .. fontSize .. [[px;z-index:1000;\"><div class=\"]] .. getIndustryStatusBgClass(industry.state) .. [[\" style=\"padding:2px;text-transform:capitalize;\"><span class=\"tier]] .. industry.production.tier .. [[\">T]] .. industry.production.tier .. [[</span><strong>]] .. industry.production.locDisplayNameWithSize .. [[</strong></div><div class=\"bg-light text-dark\" style=\"margin-top:2px;padding:2px;\"><div class=\"]] .. getIndustryStatusClass(industry.state) .. [[\"><strong>]] .. statusList[industry.state] .. [[</strong></div><div>]] .. industry.productId .. industry.name .. industry.type .. industry.mode .. industry.schematic .. industry.remainingTime .. industry.recipe ..[[</div></div></div>]]\n elseif selected_storage then\n local storage = selected_storage\n local displayName = storage.name\n local tierBox = ''\n local itemBox = ''\n local fillGauge = ''\n local gaugePercent = storage.percent\n if storage.percent > 100 then\n gaugePercent = 100\n end\n local r,g,b = getRGBGradient(gaugePercent/100,177,42,42,249,212,123,34,177,76)\n r = utils.round(r)\n g = utils.round(g)\n b = utils.round(b)\n if storage.item ~= nil and storage.item.name ~= \"InvalidItem\" then\n displayName = format_number(utils.round(storage.quantity*100)/100) .. \" \" .. storage.item.locDisplayNameWithSize .. \" (\" .. storage.percent .. \"%)\"\n tierBox = '<span class=\"tier' .. storage.item.tier .. '\">T' .. storage.item.tier .. '</span>'\n local i = storage.item\n\n itemBox = [[<hr><div><strong>Item ID:</strong> ]] .. i.id .. [[</div><div><strong>Item Name:</strong> ]] .. i.locDisplayNameWithSize .. [[</div><div><strong>Item Unit Mass:</strong> ]] .. i.unitMass .. [[ kg</div><div><strong>Item Unit Volume:</strong> ]] .. i.unitVolume .. [[ m<sup>3</sup></div>]]\n fillGauge = '<div style=\"position:absolute;bottom:0;left:0px;width:' .. gaugePercent .. '%;background-color:rgb(' .. r .. ',' .. g ..',' .. b .. ');height:3px;z-index:1000;\"></div>'\n end\n html = html .. [[<div class=\"ib\" style=\"border: 5px solid rgb(]] .. r .. [[,]] .. g ..[[,]] .. b .. [[);left:]] .. utils.round(storage.screenPos[1]*100) .. [[%;top:]] .. utils.round(storage.screenPos[2]*100) .. [[%;font-size:]] .. fontSize .. [[px;z-index:1000;\"><div class=\"bg-light text-dark\" style=\"padding:2px;padding-bottom:5px;text-transform:capitalize;position:relative;\">]] .. tierBox .. [[<strong>]] .. displayName .. [[</strong>]] .. fillGauge .. [[</div><div class=\"bg-light text-dark\" style=\"margin-top:2px;padding:2px;\"><div><strong>Container Type:</strong> ]] .. storage.type .. \" \" .. storage.size .. [[</div>]] .. itemBox .. [[</div></div>]]\n html = html .. [[</div>]]\n end\n end\n html_ar_selected = html\nend\nhud.coroutines.renderControlSelectedIndustry = function()\n local html = \"\"\n if #databanks > 0 and emitter ~= nil and selected_machine ~= nil and (displayType == 0 or displayType == 1) then\n local industry = selected_machine\n html = '<div class=\"hud_container hud_machine_control\" style=\"text-align:center;\"><div class=\"' .. getIndustryStatusClass(industry.state) .. '\">' .. industry.tableName .. '<br><small>' .. statusList[industry.state] .. '</small></div><hr class=\"hr-light\"><div>' .. industry.production.locDisplayNameWithSize .. '</div>'\n if industry.state == 1 or industry.state == (#statusList - 1) then\n command_1 = \"START\"\n command_2 = \"BATCH\"\n command_3 = \"MAINTAIN\"\n html = html .. '<table style=\"width:100%;\"><tr><th style=\"text-align:left;width:100px;\">START</th><th style=\"width:100px;\"></th><th style=\"text-align:right;width:100px;\">Alt+1</th></tr><tr><th style=\"text-align:left;\">START BATCH</th><th rowspan=\"2\">Quantity:<br>'\n local has_quantity = false\n for k,v in pairs(craft_quantity_digits) do\n if tonumber(v) == nil then v = 0 end\n if tonumber(v) > 0 then\n has_quantity = true\n end\n end\n if not has_quantity then\n local value = tostring(math.floor(industry.maintainOrBatchQuantity))\n for i = #value, 1, -1 do\n local c = value:sub(i,i)\n craft_quantity_digits[9-(#value-(i-1))] = c\n end\n end\n for digit_index,digit in pairs(craft_quantity_digits) do\n html = html .. digit\n end\n html = html .. '</th><th style=\"text-align:right;\">ALT+2</th></tr><tr><th style=\"text-align:left;\">MAINTAIN</th><th style=\"text-align:right;\">ALT+3</th></tr></table>'\n elseif industry.state < #statusList then\n command_1 = \"STOP\"\n command_2 = \"SOFT_STOP\"\n command_3 = \"HARD_STOP\"\n html = html .. [[<table><tr><th style=\"text-align:left;width:250px;\">STOP</th><th style=\"text-align:right;width:50px;\">ALT+1</th></tr><tr><th style=\"text-align:left;\">FINISH AND STOP</th><th style=\"text-align:right;\">ALT+2</th></tr><tr><th style=\"text-align:left;\">STOP AND ALLOW MATERIAL LOSS</th><th style=\"text-align:right;\">ALT+3</th></tr></table>]]\n else\n html = html .. '<div>Pending stop, please wait</div>'\n end\n html = html .. '</div>'\n end\n html_control = html\nend\nhud.coroutines.renderHud = function()\n local html = bootstrap_css_colors .. base_css .. html_ar_selected\n if displayMode ~= 3 then\n html = html .. html_filters_types\n if displayMode == 0 or displayMode == 1 then\n html = html .. html_machines .. html_filters .. html_control\n end\n if displayMode == 0 or displayMode == 2 then\n html = html .. html_storage\n end\n end\n html = html .. html_time .. html_credits\n system.setScreen(html)\nend\nhud.actions = {}\nhud.actions.start = {}\nhud.actions.stop = {}\nhud.actions.start.brake = function() ctrlPressed = true end\nhud.actions.stop.brake = function() ctrlPressed = false end\nhud.actions.start.down = function()\n if ctrlPressed and displayMode < 3 then\n statusFilterType = statusFilterType + 1\n if statusFilterType > maxFilterType then statusFilterType = 0 end\n onFilterChange()\n elseif displayMode < 3 then\n selectedRow = selectedRow + 1\n if selectedRow > maxOnPage then selectedRow = 1 end\n onRowChange()\n end\nend\nhud.actions.start.up = function()\n if ctrlPressed and displayMode < 3 then\n statusFilterType = statusFilterType - 1\n local max = #elementsTypes\n if statusFilterType < 0 then statusFilterType = maxFilterType end\n onFilterChange()\n elseif displayMode < 3 then\n selectedRow = selectedRow - 1\n if selectedRow < 1 then selectedRow = maxOnPage end\n onRowChange()\n end\nend\nhud.actions.start.option1 = function()\n if #databanks > 0 and emitter ~= nil and selected_machine ~= nil and (displayType == 0 or displayType == 1) then\n --Send Command 1\n for _,db in pairs(databanks) do\n db.setStringValue(selected_machine.id, command_1)\n end\n emitter.send(channels[selected_machine.typeFilter:lower()], \"\")\n end\nend\nhud.actions.start.option2 = function()\n if #databanks > 0 and emitter ~= nil and selected_machine ~= nil and (displayType == 0 or displayType == 1) then\n --Send Command 2\n for _,db in pairs(databanks) do\n if command_2:find(\"MAINTAIN\") or command_2:find(\"BATCH\") then\n craft_quantity = \"\"\n for _,digit in pairs(craft_quantity_digits) do\n craft_quantity = craft_quantity .. digit\n end\n command_2 = command_2 .. \"_\" .. craft_quantity\n end\n db.setStringValue(selected_machine.id, command_2)\n if command_2:find(\"MAINTAIN\") then command_2 = \"MAINTAIN\" end\n if command_2:find(\"BATCH\") then command_2 = \"BATCH\" end\n end\n emitter.send(channels[selected_machine.typeFilter:lower()], \"\")\n end\nend\nhud.actions.start.option3 = function()\n if #databanks > 0 and emitter ~= nil and selected_machine ~= nil and (displayType == 0 or displayType == 1) then\n --Send Command 3\n for _,db in pairs(databanks) do\n if command_3:find(\"MAINTAIN\") or command_3:find(\"BATCH\") then\n craft_quantity = \"\"\n for _,digit in pairs(craft_quantity_digits) do\n craft_quantity = craft_quantity .. digit\n end\n command_3 = command_3 .. \"_\" .. craft_quantity\n end\n db.setStringValue(selected_machine.id, command_3)\n if command_3:find(\"MAINTAIN\") then command_3 = \"MAINTAIN\" end\n if command_3:find(\"BATCH\") then command_3 = \"BATCH\" end\n end\n emitter.send(channels[selected_machine.typeFilter:lower()], \"\")\n end\nend\nhud.actions.start.option6 = function()\n sortingType = sortingType + 1\n if sortingType < 0 then sortingType = #sortingTypes end\n if sortingType > (#sortingTypes) then sortingType = 1 end\nend\nhud.actions.start.option7 = function()\n displayType = displayType + 1\n if displayType < 0 then displayType = (#displayTypes-1) end\n if displayType > (#displayTypes-1) then displayType = 0 end\nend\nhud.actions.start.option8 = function()\n displayMode = displayMode + 1\n if displayMode < 0 then displayMode = (#displayModes-1) end\n if displayMode > (#displayModes-1) then displayMode = 0 end\nend\nhud.actions.start.option9 = function()\n init = false\nend\nhud.actions.start.strafeleft = function()\n if ctrlPressed and (displayMode == 0 or displayMode == 1) then\n statusFilter = statusFilter - 1\n if statusFilter < 0 then statusFilter = #statusList end\n onFilterChange()\n elseif (displayType == 0 or displayType == 1) then\n page = page - 1\n if page < 1 then page = maxPage end\n onTablePageChange()\n end\nend\nhud.actions.start.straferight = function()\n if ctrlPressed and (displayMode == 0 or displayMode == 1) then\n statusFilter = statusFilter + 1\n if statusFilter > #statusList then statusFilter = 0 end\n onFilterChange()\n elseif (displayType == 0 or displayType == 1) then\n page = page + 1\n if page > maxPage then page = 1 end\n onTablePageChange()\n end\nend\n\n--[[\n DU-Nested-Coroutines by Jericho\n Permit to easier avoid CPU Load Errors\n Source available here: https://github.com/Jericho1060/du-nested-coroutines\n]]--\n\ncoroutinesTable = {}\n\nfunction initCoroutines()\n for k,f in pairs(hud.coroutines) do\n coroutinesTable[k] = coroutine.create(f)\n end\nend\n\ninitCoroutines()\n\nfor k,f in pairs(coroutinesTable) do system.print(k) end\n\nrunCoroutines = function()\n for k,co in pairs(coroutinesTable) do\n if coroutine.status(co) == \"dead\" then\n coroutinesTable[k] = coroutine.create(hud.coroutines[k])\n end\n if coroutine.status(co) == \"suspended\" then\n assert(coroutine.resume(co))\n end\n end\nend\n\nMainCoroutine = coroutine.create(runCoroutines)\n\nunit.hideWidget()\n\nfunction onTablePageChange()\n selectedRow = 1\n onRowChange()\nend\n\nfunction onFilterChange()\n onTablePageChange()\n page = 1\nend\n\nfunction onRowChange()\n craft_quantity_digits = {\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\"}\nend\n","filter":{"args":[],"signature":"onStart()","slotKey":"-1"},"key":"5"},{"code":"local content = schematicContainer.getContent()\nfor _,s in pairs(content) do\n schematicStorage[\"s\" .. s.id] = s.quantity\nend","filter":{"args":[],"signature":"onContentUpdate()","slotKey":"0"},"key":"6"}],"methods":[],"slots":{"0":{"name":"slot1","type":{"events":[],"methods":[]}},"1":{"name":"slot2","type":{"events":[],"methods":[]}},"2":{"name":"slot3","type":{"events":[],"methods":[]}},"3":{"name":"slot4","type":{"events":[],"methods":[]}},"4":{"name":"slot5","type":{"events":[],"methods":[]}},"5":{"name":"slot6","type":{"events":[],"methods":[]}},"6":{"name":"slot7","type":{"events":[],"methods":[]}},"7":{"name":"slot8","type":{"events":[],"methods":[]}},"8":{"name":"slot9","type":{"events":[],"methods":[]}},"9":{"name":"slot10","type":{"events":[],"methods":[]}},"-5":{"name":"library","type":{"events":[],"methods":[]}},"-4":{"name":"system","type":{"events":[],"methods":[]}},"-3":{"name":"player","type":{"events":[],"methods":[]}},"-2":{"name":"construct","type":{"events":[],"methods":[]}},"-1":{"name":"unit","type":{"events":[],"methods":[]}}}} 1 + {"events":[],"handlers":[{"code":"--[[\n DU-Nested-Coroutines by Jericho\n Permit to easier avoid CPU Load Errors\n Source available here: https://github.com/Jericho1060/du-nested-coroutines\n]]--\n\nif coroutine.status(MainCoroutine) == \"dead\" then\n MainCoroutine = coroutine.create(runCoroutines)\nend\nif coroutine.status(MainCoroutine) == \"suspended\" then\n assert(coroutine.resume(MainCoroutine))\nend","filter":{"args":[],"signature":"onUpdate()","slotKey":"-4"},"key":"3"},{"code":"if tonumber(text) then\n if #text > 8 then\n system.print(\"the value should not be higher than 99 999 999.\")\n else\n craft_quantity_digits = {\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\"}\n for i = #text, 1, -1 do\n local c = text:sub(i,i)\n craft_quantity_digits[9-(#text-(i-1))] = c\n end\n end\nelse\n system.print(\"You must type a Number\")\nend","filter":{"args":[{"variable":"*"}],"signature":"onInputText(text)","slotKey":"-4"},"key":"4"},{"code":"if hud.actions.stop[action] ~= nil then\n local success, message = pcall(hud.actions.stop[action])\n if not success then\n system.print(\"Action Stop '\" .. action .. \"' Error : \" .. message) \n end\nend","filter":{"args":[{"variable":"*"}],"signature":"onActionStop(action)","slotKey":"-4"},"key":"5"},{"code":"if hud.actions.start[action] ~= nil then\n local success, message = pcall(hud.actions.start[action])\n if not success then\n system.print(\"Action Start '\" .. action .. \"' Error : \" .. message) \n end\nend","filter":{"args":[{"variable":"*"}],"signature":"onActionStart(action)","slotKey":"-4"},"key":"6"},{"code":"Storage.clear()","filter":{"args":[],"signature":"onStop()","slotKey":"-1"},"key":"1"},{"code":"version = \"v4.3.0\"\n--[[\n DU Industry HUD By Jericho\n]]\nlocal log_split = \"=================================================\"\n--printing version in lua chat\nsystem.print(log_split)local a=\"\"local b=math.ceil((50-#version-2)/2)for c=1,b,1 do a=a..'='end;a=a..\" \"..version..\" \"for c=1,b,1 do a=a..'='end;system.print(a)system.print(log_split)\n--[[\n Lua parameters\n]]\nfontSize = 12 --export: the fonct size\nshowRecipeData = true --export: display the recipe ingredients in the machine detail\n\nenableRefinerMonitoring = true --export: enable or disable the Refiners monitoring\nenableAssemblyMonitoring = true --export: enable or disable the Assembly lines monitoring\nenableSmelterMonitoring = true --export: enable or disable the Smelters monitoring\nenableChemicalMonitoring = true --export: enable or disable the Chemical industries monitoring\nenableElectronicsMonitoring = true --export: enable or disable the Electronics Industries monitoring\nenableGlassMonitoring = true --export: enable or disable the Glass Furnace monitoring\nenableHoneycombMonitoring = true --export: enable or disable the Honeycomb Refineries monitoring\nenableRecyclerMonitoring = true --export: enable or disable the Recyclers monitoring\nenableMetalworkMonitoring = true --export: enable or disable the Metalworks monitoring\nenable3DPrinterMonitoring = true --export: enable or disable the 3D Printers monitoring\nenableTransferMonitoring = true --export: enable or disable the transfer units monitoring\nenableStorageMonitoring = true --export: enable or disable the storage monitoring\nenableRemoteControl = true --export: enable the HUD to control machines (start/stop/batch/maintain)\nelementsByPage = 20 --export: maximum amount of elements displayed on a single page\ndateFormat = \"en\" --export: the country code to format the date\nmaxAmountOfElementsLoadedByFrame = 500 --export: if cpu load errors at start, lower that value\nmachinesRefreshedByFrame = 100 --how many machines are refreshed by frame\nmachineDetailDisplayDistance = 0 --export: the distance in meters to display the machine details\ndisplayType = 0 --export: the default display type: 0=ALL, 1=Table, 2=Augmented Reality\ndisplayMode = 0 --export: the default display type: 0=ALL, 1=Industry Only, 2=Storage Only, 3=None\nsortingType = 1 --export: the default sorting of elements in table: 1=Element Name, 2=Item in containers or product of industries, 3=Element ID\n\n\n--[[\n\treceivers channels for each type of machine\n]]\nchannel_for_refiner = \"receiver_refiner\" --export: receiver channel to send orders to refiners\nchannel_for_assembly = \"receiver_assembly\" --export: receiver channel to send orders to assembly lines\nchannel_for_smelter = \"receiver_smelters\" --export: receiver channel to send orders to smelters\nchannel_for_chemical = \"receiver_chemical\" --export: receiver channel to send orders to chemical indutries\nchannel_for_electronics = \"receiver_electronics\" --export: receiver channel to send orders to electronic industries\nchannel_for_glass = \"receiver_glass\" --export: receiver channel to send orders to glass furnace\nchannel_for_honeycomb = \"receiver_honeycomb_recycler\" --export: receiver channel to send orders to honeycomb refiniries\nchannel_for_recycler = \"receiver_honeycomb_recycler\" --export: receiver channel to send orders to recylers\nchannel_for_metalwork = \"receiver_metalworks\" --export: receiver channel to send orders to metalworks\nchannel_for_3d_printer = \"receiver_3dprinters\" --export: receiver channel to send orders to 3d printers\nchannel_for_transfer = \"receiver_transfert\" --export: receiver channel to send orders to tranfer units\n\n--Storage options\ncontainerProficiencyLvl = 5 --export: Talent level for Container Proficiency\ncontainerOptimizationLvl = 0 --export: Talent level for Container Optimization\nstorages_prefix_list = 's1,s2,s3,s4,s5,s6,s7,s8,s9' --export: the list of the prefixes used for the storage monitoring, comma separated values\n\n--split a string on a delimiter By jericho\nfunction strSplit(a,b)result={}for c in(a..b):gmatch(\"(.-)\"..b)do table.insert(result,c)end;return result end\n--formatting numbers by adding a space between thousands by Jericho\nfunction format_number(a)local b=a;while true do b,k=string.gsub(b,\"^(-?%d+)(%d%d%d)\",'%1 %2')if k==0 then break end end;return b end\n--Utility functions By jericho, see full source at https://github.com/Jericho1060/DualUniverse\nfunction removeDuplicatesInTable(a)local b={}local c={}for d,e in ipairs(a)do if not b[e]then c[#c+1]=e;b[e]=true end end;return c end;function strSplit(a,b)result={}for c in(a..b):gmatch(\"(.-)\"..b)do table.insert(result,c)end;return result end;function SecondsToClockString(a)local a=tonumber(a)if a==nil or a<=0 then return\"-\"else days=string.format(\"%2.f\",math.floor(a/(3600*24)))hours=string.format(\"%2.f\",math.floor(a/3600-days*24))mins=string.format(\"%2.f\",math.floor(a/60-hours*60-days*24*60))secs=string.format(\"%2.f\",math.floor(a-hours*3600-days*24*60*60-mins*60))str=\"\"if tonumber(days)>0 then str=str..days..\"d \"end;if tonumber(hours)>0 then str=str..hours..\"h \"end;if tonumber(mins)>0 then str=str..mins..\"m \"end;if tonumber(secs)>0 then str=str..secs..\"s\"end;return str end end;function removeQualityInName(a)if not a then return''end;return a:lower():gsub('basic ',''):gsub('uncommon ',''):gsub('advanced ',''):gsub('rare ',''):gsub('exotic ','')end;function has_value(a,b)for c,d in ipairs(a)do if d==b then return true end end;return false end\n--return RGB colors calculated from a gradient between two colors\nfunction getRGBGradient(a,b,c,d,e,f,g,h,i,j)a=-1*math.cos(a*math.pi)/2+0.5;local k=0;local l=0;local m=0;if a>=.5 then a=(a-0.5)*2;k=e-a*(e-h)l=f-a*(f-i)m=g-a*(g-j)else a=a*2;k=b-a*(b-e)l=c-a*(c-f)m=d-a*(d-g)end;return k,l,m end\n--time script to get client date and time by Jericho, see full source at https://github.com/Jericho1060/DualUniverse\nfunction DUCurrentDateTime(a)local b=system.getUtcTime()if not a then b=b+system.getUtcOffset()end;local c=24*60*60;local d=365*c;local e=d+c;local f=4*d+c;local g=4;local h=1970;local i={-1,30,58,89,119,150,180,211,242,272,303,333,364}local j={}for k=1,2 do j[k]=i[k]end;for k=3,13 do j[k]=i[k]+1 end;local l,m,n,o,p,q,r,s;local t=i;s=b;l=math.floor(s/f)s=s-l*f;l=l*4+h;if s>=d then l=l+1;s=s-d;if s>=d then l=l+1;s=s-d;if s>=e then l=l+1;s=s-e else t=j end end end;m=math.floor(s/c)s=s-m*c;local n=1;while t[n]<m do n=n+1 end;n=n-1;local o=m-t[n]p=(math.floor(b/c)+g)%7;if p==0 then p=7 end;q=math.floor(s/3600)s=s-q*3600;r=math.floor(s/60)function round(u,v)if v then return utils.round(u/v)*v end;return u>=0 and math.floor(u+0.5)or math.ceil(u-0.5)end;s=round(s-r*60)local w={\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\",\"Sunday\"}local x={\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\",\"Sun\"}local y={\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\"}local z={\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"}return l,n,o,q,r,s,p,w[p],x[p],y[n],z[n],m+1 end\n \n--databank hub library By Jericho, see full source at https://github.com/Jericho1060/DualUniverse\nbankhub={}function bankhub:new(banks)o={}setmetatable(o,self)self.__index=self;o.banks=banks or{}function o.clear()return o:_clear()end;function o.getNbKeys()return o:_getNbKeys()end;function o.getKeys()return o:_getKeys()end;function o.hasKey(a)return o:_hasKey(a)end;function o.getStringValue(a)return o:_getStringValue(a)end;function o.getIntValue(a)return o:_getIntValue(a)end;function o.getFloatValue(a)return o:_getFloatValue(a)end;return o end;function bankhub:add(b)table.insert(self.banks,b)self.banks_size=#self.banks end;function bankhub:_clear()for c,d in pairs(self.banks)do d.clear()end end;function bankhub:_getNbKeys()local e=0;for c,d in pairs(self.banks)do e=e+d.getNbKeys()end;return e end;function bankhub:_getKeys()local e={}for c,d in pairs(self.banks)do local f=json.decode(d.getKeys())for c,g in pairs(f)do table.insert(e,g)end end;return json.encode(e)end;function bankhub:_hasKey(a)for c,d in pairs(self.banks)do if d.hasKey(a)==1 then return 1 end end;return 0 end;function bankhub:_getStringValue(a)for c,d in pairs(self.banks)do if d.hasKey(a)==1 then return d.getStringValue(a)end end;return nil end;function bankhub:_getIntValue(a)for c,d in pairs(self.banks)do if d.hasKey(a)==1 then return banks.getIntValue(a)end end;return nil end;function bankhub:_getFloatValue(a)for c,d in pairs(self.banks)do if d.hasKey(a)==1 then return banks.getFloatValue(a)end end;return nil end\n--time script to get client date and time by Jericho, see full source at https://github.com/Jericho1060/DualUniverse\nfunction DUCurrentDateTime(a)local b=system.getUtcTime()if not a then b=b+system.getUtcOffset()end;local c=24*60*60;local d=365*c;local e=d+c;local f=4*d+c;local g=4;local h=1970;local i={-1,30,58,89,119,150,180,211,242,272,303,333,364}local j={}for k=1,2 do j[k]=i[k]end;for k=3,13 do j[k]=i[k]+1 end;local l,m,n,o,p,q,r,s;local t=i;s=b;l=math.floor(s/f)s=s-l*f;l=l*4+h;if s>=d then l=l+1;s=s-d;if s>=d then l=l+1;s=s-d;if s>=e then l=l+1;s=s-e else t=j end end end;m=math.floor(s/c)s=s-m*c;local n=1;while t[n]<m do n=n+1 end;n=n-1;local o=m-t[n]p=(math.floor(b/c)+g)%7;if p==0 then p=7 end;q=math.floor(s/3600)s=s-q*3600;r=math.floor(s/60)function round(u,v)if v then return utils.round(u/v)*v end;return u>=0 and math.floor(u+0.5)or math.ceil(u-0.5)end;s=round(s-r*60)local w={\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\",\"Sunday\"}local x={\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\",\"Sun\"}local y={\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\"}local z={\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"}return l,n,o,q,r,s,p,w[p],x[p],y[n],z[n],m+1 end\n\nstatusList = {\"STOPPED\",\"RUNNING\",\"MISSING INGREDIENT\",\"OUTPUT FULL\",\"NO OUTPUT CONTAINER\",\"PENDING\",\"MISSING SCHEMATIC\",\"SERVER ERROR\", \"STOP REQUESTED\"}\nfunction getIndustryStatusClass(status)\n if status == 1 then\n return \"text-info\"\n elseif status == 2 then\n return \"text-success\"\n elseif ((status >= 3) and (status <= 5)) or (status == 7) then\n return \"text-danger\"\n elseif status == 6 then\n return \"text-primary\"\n elseif status >= 8 and status <= 9 then\n return \"text-warning\"\n end\n return \"\" --default value for other status that can be added\nend\nfunction getIndustryStatusBgClass(status)\n if status then\n if status == 1 then\n return \"bg-info\"\n elseif status == 2 then\n return \"bg-success\"\n elseif ((status >= 3) and (status <= 5)) or (status == 7) then\n return \"bg-danger\"\n elseif status == 6 then\n return \"bg-primary\"\n elseif status >= 8 and status <= 9 then\n return \"bg-warning\"\n end\n end\n return \"\" --default value for other status that can be added\nend\nfunction getIndustryStatusBorderClass(status)\n if status then\n if status == 1 then\n return \"border-info\"\n elseif status == 2 then\n return \"border-success\"\n elseif ((status >= 3) and (status <= 5)) or (status == 7) then\n return \"border-danger\"\n elseif status == 6 then\n return \"border-primary\"\n elseif status >= 8 and status <= 9 then\n return \"border-warning\"\n end\n end\n return \"\" --default value for other status that can be added\nend\nfunction ConvertLocalToWorld(a,b,c,d,e)local f={a[1]*c[1],a[1]*c[2],a[1]*c[3]}local g={a[2]*d[1],a[2]*d[2],a[2]*d[3]}local h={a[3]*e[1],a[3]*e[2],a[3]*e[3]}return{f[1]+g[1]+h[1]+b[1],f[2]+g[2]+h[2]+b[2],f[3]+g[3]+h[3]+b[3]}end\n\n\nchannels = {}\nchannels['refiner'] = channel_for_refiner\nchannels['assembly line'] = channel_for_assembly\nchannels['smelter'] = channel_for_smelter\nchannels['chemical industry'] = channel_for_chemical\nchannels['electronics industry'] = channel_for_electronics\nchannels['glass furnace'] = channel_for_glass\nchannels['honeycomb refinery'] = channel_for_honeycomb\nchannels['recycler'] = channel_for_recycler\nchannels['metalwork industry'] = channel_for_metalwork\nchannels['3d printer'] = channel_for_3d_printer\nchannels['transfer unit'] = channel_for_transfer\n\nbootstrap_css_colors = [[<style>.text-white {color: #fff !important;}.text-primary {color: #007bff !important;}.text-secondary {color: #6c757d !important;}.text-success {color: #28a745 !important;}.text-info {color: #17a2b8 !important;}.text-warning {color: #ffc107 !important;}.text-danger {color: #dc3545 !important;}.text-light {color: #f8f9fa !important;}.text-dark {color: #343a40 !important;}.text-body {color: #212529 !important;}.text-muted {color: #6c757d !important;}.text-black-50 {color: rgba(0, 0, 0, 0.5) !important;}.text-white-50 {color: rgba(255, 255, 255, 0.5) !important;}.bg-primary {background-color: #007bff !important;}.bg-secondary {background-color: #6c757d !important;}.bg-success {background-color: #28a745 !important;}.bg-info {background-color: #17a2b8 !important;}.bg-warning {background-color: #ffc107 !important;}.bg-danger {background-color: #dc3545 !important;}.bg-light {background-color: #f8f9fa !important;}.bg-dark {background-color: #343a40 !important;}.bg-white {background-color: #fff !important;}.bg-transparent {background-color: transparent !important;}.border-primary {border-color: #007bff !important;}.border-secondary {border-color: #6c757d !important;}.border-success {border-color: #28a745 !important;}.border-info {border-color: #17a2b8 !important;}.border-warning {border-color: #ffc107 !important;}.border-danger {border-color: #dc3545 !important;}.border-light {border-color: #f8f9fa !important;}.border-dark {border-color: #343a40 !important;}.border-white {border-color: #fff !important;}\n</style>]]\nbase_css = [[<style>.ib{position:absolute;opacity:.75;transform: translate(-50%, -50%);}.tier0{font-weight:bold;padding:5px;margin-right:5px;color:black;background-color:#fff;}.tier1{font-weight:bold;padding:5px;margin-right:5px;color:black;background-color:#fff;}.tier2{font-weight:bold;padding:5px;margin-right:5px;color:white;background-color:green;}.tier3{font-weight:bold;padding:5px;margin-right:5px;color:white;background-color:blue;}.tier4{font-weight:bold;padding:5px;margin-right:5px;color:white;background-color:purple;}.tier5{font-weight:bold;padding:5px;margin-right:5px;color:white;background-color:orange;}hr{border-top:1px solid #343a40;border-collapse:collapse;}.hr-light{border-top:1px solid #f8f9fa;}.hud_container{z-index:1000;font-size:]] .. fontSize .. [[px;border: 1px solid black;border-radius:5px;background-color: rgba(15,24,29,.85);padding:10px;}.hud_time{position: absolute;bottom: ]] .. tostring((100/1080)*100) .. [[vh;right: ]] .. tostring((10/1920)*100) .. [[vw;text-transform: uppercase;font-weight: bold;}.hud_machine_types_container{position: absolute;top: ]] .. tostring((80/1080)*100) .. [[vh;left: ]] .. tostring((10/1920)*100) .. [[vw;text-transform: uppercase;font-weight: bold;}.hud_machine_status_container{position: absolute;top: ]] .. tostring((10/1080)*100) .. [[vh;left: ]] .. tostring((10/1920)*100) .. [[vw;text-transform: uppercase;font-weight: bold;}.hud_table_container{position: absolute;top:]] .. tostring((80/1080)*100) .. [[vh;left:]] .. tostring((225/1920)*100) .. [[vw;}.hud_table_container td,.hud_table_container th, .hud_machine_control th{border-bottom:1px solid #f8f9fa;}small{font-size:.75em;}.hud_table_container td.row_selected,.hud_table_container th.row_selected{border:2px solid green;}.hud_machine_control{position: absolute;top: ]] .. tostring((300/1080)*100) .. [[vh;right: ]] .. tostring((10/1920)*100) .. [[vw;text-transform: uppercase;font-weight: bold;}</style>]]\n\n\ndatabanks = {}\ncore = nil\nemitter = nil\nindustries_id = {}\nstorages_id = {}\nindustries = {}\nstorages = {}\nelementsTypes = {}\nstoragesTypes = {}\nschematicContainer = nil\nschematicContainerId = construct.getSchematicContainerId()\nschematicStorage = {}\nfor slot_name, slot in pairs(unit) do\n if\n type(slot) == \"table\"\n and type(slot.export) == \"table\"\n and slot.getClass\n then\n if slot.getClass():lower() == 'databankunit' then\n table.insert(databanks, slot)\n elseif slot.getClass():lower():find(\"coreunit\") then\n core = slot\n elseif slot.getClass():lower() == 'emitterunit' then\n emitter = slot\n elseif schematicContainerId ~= nil and slot.getClass():lower():find('container') then\n if slot.getId() == schematicContainerId then\n schematicContainer = slot\n end\n end\n end\nend\n\nif core == nil then\n system.print(\"Connection to the core is missing\")\n unit.exit()\nend\nif schematicContainerId == nil then\n system.print(\"No Schematic Container set on the Construct\")\nend\nif schematicContainer == nil then\n system.print(\"Schematic Container is not linked to the board\")\nend\n\nif emitter == nil then \n enableRemoteControl = false\n system.print(\"Connect an Emitter to enable machine control from industry\")\nend\nif #databanks == 0 then \n enableRemoteControl = false\n system.print(\"No Databank linked\")\nend\n\n--init of bank hub\nStorage = bankhub:new(databanks)\n\n--construct pos for AR data\nconstructPos = construct.getWorldPosition()\nconstructRight = construct.getWorldRight()\nconstructForward = construct.getWorldForward()\nconstructUp = construct.getWorldUp()\n\n--script variables\nstorage_prefix = strSplit(storages_prefix_list, ',')\ndisplayTypes = {\"ALL\", \"Table\", \"Augmented Reality\"}\ndisplayModes = {\"ALL\", \"Industry\", \"Storage\", \"None\"}\nif not enableStorageMonitoring then\n displayModes = {\"ALL\", \"Industry\", \"None\"}\nend\nsortingTypes = {\"Element Name\", \"Item\", \"Element ID\"}\ninit = false\ninitIndex = 1\nelementsIdList = {}\nmachines_count = {}\nstorages_count = {}\nmachines_positions = {}\nstorages_positions = {}\nsystem.showScreen(true)\nstatusFilter = 0\nstatusFilterType = 0\nmaxFilterType = 0\nmaxOnPage=1\nhtml_filters = \"\"\nhtml_filters_types = \"\"\nhtml_filter_storage = \"\"\nhtml_machines = \"\"\nhtml_storage = \"\"\nhtml_time = \"\"\nhtml_ar_selected = \"\"\nhtml_control = \"\"\nhtml_credits = [[<div class=\"hud_container\" style=\"position:absolute;left:5px;bottom:5px;font-size:10px;padding:5px;\">]] .. version .. [[ - Powered By jericho1060</div>]]\n\n--pagination var\npage = 1\nmaxPage = 1\nselectedRow = 1\nselected_machine=nil\nselected_container=nil\n\n--control machine var\ncommand_1 = \"\"\ncommand_2 = \"\"\ncommand_3 = \"\"\ncraft_quantity_digits = {\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\"}\n\n--keyPressed\nctrlPressed = false\n\n\n--[[\n DU INDUSTRY HUD By Jericho\n]]\nschematicRefreshTime = 0\nhud = {}\nhud.coroutines = {}\nif schematicContainer ~= nil then\n hud.coroutines.getSchematics = function ()\n schematicRefreshTime = math.ceil(schematicContainer.updateContent())\n end\nend\nhud.coroutines.init = function()\n if not init then\n elementsTypes = {}\n industries_id = {}\n industries = {}\n\n storagesTypes = {}\n storages_id = {}\n storages = {}\n\n elementsIdList = core.getElementIdList()\n\n for index,id in ipairs(elementsIdList) do\n elementType = core.getElementDisplayNameById(id):lower()\n if (elementType:find(\"assembly line\") and enableAssemblyMonitoring == true) or\n (elementType:find(\"glass furnace\") and enableGlassMonitoring == true) or\n (elementType:find(\"3d printer\") and enable3DPrinterMonitoring == true) or\n (elementType:find(\"smelter\") and enableSmelterMonitoring == true) or\n (elementType:find(\"recycler\") and enableRecyclerMonitoring == true) or\n (elementType:find(\"refinery\") and enableHoneycombMonitoring == true) or\n (elementType:find(\"refiner\") and enableRefinerMonitoring == true) or\n (elementType:find(\"industry\")\n and (\n (elementType:find(\"chemical\") and enableChemicalMonitoring == true) or\n (elementType:find(\"electronics\") and enableElectronicsMonitoring == true) or\n (elementType:find(\"metalwork\") and enableMetalworkMonitoring == true)\n )\n ) or\n (elementType == \"transfer unit\" and enableTransferMonitoring == true) or\n elementType:lower():find(\"container\")\n then\n local formatedType = removeQualityInName(elementType)\n local pos = core.getElementPositionById(id)\n if elementType:lower():find(\"container\") and enableStorageMonitoring then\n if storages_count[formatedType] ~= nil then\n storages_count[formatedType] = storages_count[formatedType] + 1\n else\n storages_count[formatedType] = 1\n end\n table.insert(storages_id, id)\n storages_positions['i'..id] = pos\n table.insert(storagesTypes, formatedType)\n elseif not elementType:lower():find(\"container\") then\n pos[3] = pos[3] + 1\n if machines_count[formatedType] ~= nil then\n machines_count[formatedType] = machines_count[formatedType] + 1\n else\n machines_count[formatedType] = 1\n end\n table.insert(industries_id, id)\n machines_positions['i'..id] = pos\n table.insert(elementsTypes, formatedType)\n end\n end\n\n if index % maxAmountOfElementsLoadedByFrame == 0 then\n coroutine.yield()\n end\n end\n elementsTypes = removeDuplicatesInTable(elementsTypes)\n table.sort(elementsTypes, function(a,b) return a:lower() < b:lower() end)\n selected_type = elementsTypes[1]\n init = true\n system.print(\"All elements loaded\")\n system.print(#storages_id .. \" storage elements found\")\n system.print(#industries_id .. \" industries found\")\n end\nend\nhud.coroutines.loadIndustries = function()\n if init and (displayMode == 0 or displayMode == 1) then\n for index,id in ipairs(industries_id) do\n local pos = machines_positions['i'..id]\n local data = core.getElementIndustryInfoById(id)\n if industries[\"i\"..tostring(id)] == nil then industries[\"i\"..tostring(id)] = {} end\n local mode = \"\"\n local tableMode = \"\"\n local maintainOrBatchQuantity = 0\n if data.maintainProductAmount > 0 then\n mode = \"<div><strong>Mode:</strong> Maintain \" .. math.floor(data.currentProductAmount) ..\"/\" .. math.floor(data.maintainProductAmount) .. \"</div>\"\n tableMode = \"Maintain \" .. math.floor(data.currentProductAmount) ..\"/\" .. math.floor(data.maintainProductAmount)\n maintainOrBatchQuantity=math.floor(data.maintainProductAmount)\n elseif data.batchesRequested > 0 and data.batchesRequested <= 99999999 then\n local current = data.batchesRequested - data.batchesRemaining\n if data.batchesRemaining < 0 then current = 0 end\n mode = \"<div><strong>Mode:</strong> Produce \" .. math.floor(current) .. \"/\" .. math.floor(data.batchesRequested) .. \"</div>\"\n tableMode = \"Produce \" .. math.floor(current) .. \"/\" .. math.floor(data.batchesRequested)\n maintainOrBatchQuantity=math.floor(data.batchesRequested)\n end\n local production = {locDisplayNameWithSize=\"No recipe selected\", tier=0}\n local schematicName = \"\"\n local tableSchematicName = \"\"\n local tableSchematicQuantity = \"\"\n local schematicColor = \"success\"\n local state = data.state\n local time=\"\"\n local tableTime=\"\"\n local recipe=\"\"\n local industryType = core.getElementDisplayNameById(id)\n local schematicId = data.requiredSchematicIds[1] or 0\n if schematicId > 0 and not industryType:lower():find(\"transfer\") then\n local sch = system.getItem(schematicId)\n local shematicQuantity = schematicStorage[\"s\" .. schematicId] or 0\n if shematicQuantity < data.requiredSchematicAmount then schematicColor = \"danger\" end\n schematicName = '<div><strong>Schematic:</strong> ' .. format_number(shematicQuantity):gsub(\".0\", \"\") .. \"/\" .. format_number(data.requiredSchematicAmount) .. \" \" .. sch.locDisplayNameWithSize .. \"</div>\"\n tableSchematicName = sch.locDisplayNameWithSize\n tableSchematicQuantity = format_number(shematicQuantity):gsub(\".0\", \"\") .. \"/\" .. format_number(data.requiredSchematicAmount)\n end\n if #data.currentProducts > 0 then\n local item_id = data.currentProducts[1].id\n production = system.getItem(item_id)\n if id ~= \"947806142\" and id ~= \"1010524904\" and not industryType:lower():find(\"transfer\") then\n if showRecipeData then\n local rdata = system.getRecipes(item_id)\n if #rdata > 0 then\n local r = nil\n for _,recipe in pairs(rdata) do\n if recipe.products[1].id == item_id then\n r = recipe\n break\n end\n end\n if r then\n recipe = \"<div><strong>Recipe:</strong>\"\n for _,v in pairs(r.ingredients) do\n local item = system.getItem(v.id)\n recipe = recipe .. \"<br>&nbsp;&nbsp;&nbsp;&nbsp;- \" .. v.quantity .. \" x \" .. item.locDisplayNameWithSize\n end\n recipe = recipe .. \"</div>\"\n end\n end\n end\n end\n if data.remainingTime == 0 and data.state == 2 then\n state = 8\n end\n if data.stopRequested and data.state ~= 1 then\n state = 9\n end\n if data.remainingTime > 0 then\n time = \"<div><strong>Time:</strong> \" .. SecondsToClockString(data.remainingTime) .. \"</div>\"\n tableTime = SecondsToClockString(data.remainingTime)\n end\n end\n local productionName = '<div><strong>Product</strong>: ' .. production.locDisplayNameWithSize .. '</div>'\n local productId = ''\n if production.id then\n productId = \"<div><strong>Main Product ID:</strong> \" .. production.id .. \"</div>\"\n end\n local elementName = core.getElementNameById(id)\n industries[\"i\"..tostring(id)] = {\n id=id,\n screenPos=library.getPointOnScreen(ConvertLocalToWorld(pos, constructPos, constructRight, constructForward, constructUp)),\n name=\"<div><strong>Industry Name:</strong> [\" .. id .. \"] \" .. elementName .. \"</div>\",\n tableName=elementName,\n type=\"<div><strong>Industry Type:</strong> \" .. industryType .. \"</div>\",\n tableType=industryType,\n typeFilter=removeQualityInName(industryType),\n state=state,\n production=production,\n productId=productId,\n productionName=productionName,\n mode=mode,\n tableMode=tableMode,\n remainingTime=time,\n tableTime=tableTime,\n schematic=schematicName,\n schematicColor=schematicColor,\n maintainOrBatchQuantity=maintainOrBatchQuantity,\n tableSchematic=tableSchematicName,\n tableSchematicQuantity=tableSchematicQuantity,\n recipe=recipe,\n stopRequested=data.stopRequested\n }\n if index % machinesRefreshedByFrame == 0 then\n coroutine.yield()\n end\n end\n end\nend\nif enableStorageMonitoring then\n hud.coroutines.loadStorage = function()\n if init and (displayMode == 0 or displayMode == 2) then\n for index,id in ipairs(storages_id) do\n local pos = storages_positions['i'..id]\n local elementType = core.getElementDisplayNameById(id)\n local base_name = core.getElementNameById(id)\n local splitted = strSplit(base_name,'_')\n local item_id = nil\n local prefix = nil\n if #splitted > 1 then\n prefix = splitted[1]\n item_id = splitted[2]\n end\n local container = {\n id = id,\n type=elementType,\n name = \"[\" .. id .. \"] \" .. base_name,\n tableName = base_name,\n prefix = prefix,\n item_id = item_id,\n monitor = false,\n screenPos=library.getPointOnScreen(ConvertLocalToWorld(pos, constructPos, constructRight, constructForward, constructUp)),\n }\n if item_id and prefix then\n for _,sprefix in ipairs(storage_prefix) do\n if prefix:lower() == sprefix:lower() then\n container.monitor = true\n container.item = system.getItem(item_id)\n break\n end\n end\n end\n local container_size = \"XS\"\n local container_empty_mass = 0\n local container_volume = 0\n local contentQuantity = 0\n local percent_fill = 0\n if not elementType:lower():find(\"hub\") then\n local containerMaxHP = core.getElementMaxHitPointsById(id)\n if containerMaxHP > 68000 then\n container_size = \"XXL\"\n container_empty_mass = 88410\n container_volume = 512000 * (containerProficiencyLvl * 0.1) + 512000\n elseif containerMaxHP > 33000 then\n container_size = \"XL\"\n container_empty_mass = 44210\n container_volume = 256000 * (containerProficiencyLvl * 0.1) + 256000\n elseif containerMaxHP > 17000 then\n container_size = \"L\"\n container_empty_mass = 14842.7\n container_volume = 128000 * (containerProficiencyLvl * 0.1) + 128000\n elseif containerMaxHP > 7900 then\n container_size = \"M\"\n container_empty_mass = 7421.35\n container_volume = 64000 * (containerProficiencyLvl * 0.1) + 64000\n elseif containerMaxHP > 900 then\n container_size = \"S\"\n container_empty_mass = 1281.31\n container_volume = 8000 * (containerProficiencyLvl * 0.1) + 8000\n else\n container_size = \"XS\"\n container_empty_mass = 229.09\n container_volume = 1000 * (containerProficiencyLvl * 0.1) + 1000\n end\n else\n if splitted[3] then\n container_size = splitted[3]\n end\n if splitted[4] then\n container_amount = splitted[4]\n end\n local volume = 0\n container_volume_list = {xxl=512000, xl=256000, l=128000, m=64000, s=8000, xs=1000}\n container_size = container_size:lower()\n if container_volume_list[container_size] then\n volume = container_volume_list[container_size]\n end\n container_volume = (volume * containerProficiencyLvl * 0.1 + volume)\n container_empty_mass = 55.8\n end\n local totalMass = core.getElementMassById(id)\n local contentMassKg = totalMass - container_empty_mass\n container.totalMass = totalMass\n container.emptyMass = container_empty_mass\n container.contentMass = contentMassKg\n container.maxVolume = container_volume\n container.size = container_size\n if container.item == nil or container.item.name == \"InvalidItem\" then\n container.percent = 0\n container.quantity = 0\n else\n container.quantity = contentMassKg / (container.item.unitMass - (container.item.unitMass * (containerOptimizationLvl * 0.05)))\n container.percent = utils.round((container.item.unitVolume * container.quantity) * 100 / container_volume)\n end\n storages['i'..id] = container\n if index % machinesRefreshedByFrame == 0 then\n coroutine.yield()\n end\n end\n end\n end\nend\nhud.coroutines.renderHelper = function()\n local year, month, day, hour, minute, second = DUCurrentDateTime()\n html_time = [[<div class=\"hud_time hud_container\"><div style=\"text-align:center;\">]] .. string.format(\"%02d/%02d/%04d %02d:%02d:%02d\",day,month,year,hour,minute,second) .. [[</div><div style=\"text-align:right;\"><hr class=\"hr-light\"><style>.dm]] .. displayMode .. [[{border: 1px solid #28a745 !important;}.dp]] .. displayType .. [[{border: 1px solid #28a745 !important;}.sortType]] .. sortingType .. [[{border: 1px solid #28a745 !important;}</style><div>]]\n for i,v in ipairs(sortingTypes) do\n html_time = html_time .. '<span class=\"sortType' .. i ..'\" style=\"margin:5px;\">' .. v .. '</span>'\n if i < #sortingTypes then html_time = html_time .. \"|\" end\n end\n html_time = html_time .. ' - Sorting Type - Alt + 6</div><div>'\n for i,v in ipairs(displayTypes) do\n html_time = html_time .. '<span class=\"dp' .. (i-1) .. '\" style=\"margin:5px;\">' .. v .. '</span>'\n if i < #displayTypes then html_time = html_time .. \"|\" end\n end\n html_time = html_time .. ' - Display Type - Alt + 7</div><div>'\n for i,v in ipairs(displayModes) do\n html_time = html_time .. '<span class=\"dm' .. (i-1) .. '\" style=\"margin:5px;\">' .. v .. '</span>'\n if i < #displayModes then html_time = html_time .. \"|\" end\n end\n html_time = html_time .. ' - Display Mode - Alt + 8</div>'\n html_time = html_time .. '<div>Reload HUD - Alt + 9</div>'\n if schematicContainer ~= nil then\n html_time = html_time .. '<hr class=\"hr-light\"><div>Schematic Storage Refresh in ' .. schematicRefreshTime .. 's</div>'\n end\n html_time = html_time .. '</div></div>'\nend\nhud.coroutines.renderIndustries = function()\n local html = \"\"\n local html_table = \"\"\n local lastMachine = 0\n local firstMachine = 0\n local totalPage = 1\n local selectedMachine = nil\n if displayMode == 0 or displayMode == 1 then\n local selectedIndustries = {}\n for k,industry in pairs(industries) do\n if (statusFilter == 0 or industry.state == statusFilter) and (statusFilterType == 0 or (statusFilterType <= #elementsTypes and industry.typeFilter:lower() == elementsTypes[statusFilterType])) then\n if displayType == 0 then\n table.insert(selectedIndustries, industry)\n elseif displayType == 1 then\n table.insert(selectedIndustries, industry)\n elseif displayType == 2 then\n if industry.screenPos[1] > 0 and industry.screenPos[1] < 1 and industry.screenPos[2] > 0 and industry.screenPos[2] < 1 then\n table.insert(selectedIndustries, industry)\n end\n end\n end\n end\n if (displayType == 0 or displayType == 1) and statusFilterType <= #elementsTypes then\n totalPage = math.ceil(#selectedIndustries/elementsByPage)\n firstMachine = (page - 1) * elementsByPage + 1\n lastMachine = page * elementsByPage\n if lastMachine > #selectedIndustries then\n lastMachine = #selectedIndustries\n end\n html_table = html_table .. '<div class=\"hud_container hud_table_container\"><div style=\"text-align:center;border-bottom:1px solid white;\">&#x2191; &nbsp;&nbsp; Arrow Up</div><table style=\"width:100%\"><tr><th>&#x2190; &nbsp;&nbsp; Arrow Left</th><th> Page ' .. page .. '/' .. totalPage .. ' (from ' .. firstMachine .. ' to ' .. lastMachine .. ' on ' .. #selectedIndustries .. ')</th><th>Arrow Right &nbsp;&nbsp; &#x2192;</th></tr></table><table><tr><th>id</th><th>Machine Name & Type</th><th>Selected Recipe & schematic</th><th>Status</th><th>Mode</th><th>Time Remaining</th></tr>'\n end\n local count = 1\n if sortingType == 1 then\n table.sort(selectedIndustries, function(a,b) return a.tableName < b.tableName end)\n elseif sortingType == 2 then\n table.sort(selectedIndustries, function(a,b) return a.production.locDisplayNameWithSize < b.production.locDisplayNameWithSize end)\n elseif sortingType == 3 then\n table.sort(selectedIndustries, function(a,b) return a.id < b.id end)\n end\n for k,industry in pairs(selectedIndustries) do\n if (displayType == 0 or displayType == 2) and industry.screenPos[1] > 0 and industry.screenPos[1] < 1 and industry.screenPos[2] > 0 and industry.screenPos[2] < 1 then\n local showDetail = false\n if industry.screenPos[3] <= machineDetailDisplayDistance then\n showDetail = true\n elseif industry.screenPos[1] < 0.55 and industry.screenPos[1] > 0.45 and industry.screenPos[2] < 0.55 and industry.screenPos[2] > 0.45 then\n showDetail = true\n end\n local font_size = fontSize * ((200-industry.screenPos[3])/200)\n local zindex = utils.round(1000 - industry.screenPos[3])\n html = html .. [[<div class=\"ib\" style=\"left:]] .. utils.round(industry.screenPos[1]*100) .. [[%;top:]] .. utils.round(industry.screenPos[2]*100) .. [[%;font-size:]] .. font_size .. [[px;z-index:]]..zindex..[[;\"><div class=\"]] .. getIndustryStatusBgClass(industry.state) .. [[\" style=\"padding:2px;text-transform:capitalize;\"><span class=\"tier]] .. industry.production.tier .. [[\">T]] .. industry.production.tier .. [[</span><strong>]] .. industry.production.locDisplayNameWithSize .. [[</strong></div>]]\n if showDetail then\n html = html .. [[<div class=\"bg-light text-dark\" style=\"margin-top:2px;padding:2px;\"><div class=\"]] .. getIndustryStatusClass(industry.state) .. [[\"><strong>]] .. statusList[industry.state] .. [[</strong></div><div>]] .. industry.productId .. industry.name .. industry.type .. industry.mode .. industry.schematic .. industry.remainingTime .. industry.recipe ..[[</div></div>]]\n end\n html = html .. [[</div>]]\n end\n if (displayType == 0 or displayType == 1) then\n local selectedClass = \"\"\n if selectedRow == (count + 1 - firstMachine)then\n selectedClass = \"row_selected\"\n selectedMachine = industry\n end\n if count >= firstMachine and count <= lastMachine then\n html_table = html_table .. '<tr><th class=\"' .. selectedClass .. '\">' .. industry.id .. '</th><th class=\"' .. selectedClass .. '\"><span class=\"' .. getIndustryStatusClass(industry.state) .. '\">' .. industry.tableName .. '</span><br><small>' .. industry.tableType .. '</small></th><th class=\"' .. selectedClass .. '\">' .. industry.production.locDisplayNameWithSize .. '<br><small class=\"text-' .. industry.schematicColor .. '\">' .. industry.tableSchematicQuantity .. \" \" .. industry.tableSchematic .. '</small></th><th class=\"' .. selectedClass .. '\"><span class=\"' .. getIndustryStatusClass(industry.state) .. '\">' .. statusList[industry.state] .. '</span></th><th class=\"' .. selectedClass .. '\">' .. industry.tableMode .. '</th><th class=\"' .. selectedClass .. '\">' .. industry.tableTime .. '</th></tr>'\n end\n end\n count = count + 1\n end\n if (displayType == 0 or displayType == 1) and statusFilterType <= #elementsTypes then\n html_table = html_table .. '</table><table style=\"width:100%\"><tr><th>&#x2190; &nbsp;&nbsp; Arrow Left</th><th> Page ' .. page .. '/' .. totalPage .. ' (from ' .. firstMachine .. ' to ' .. lastMachine .. ' on ' .. #selectedIndustries .. ')</th><th>Arrow Right &nbsp;&nbsp; &#x2192;</th></tr></table><div style=\"text-align:center;border-bottom:1px solid white;\">&#x2193; &nbsp;&nbsp; Arrow Down</div></div>'\n maxPage = totalPage\n maxOnPage = lastMachine-firstMachine+1\n end\n end\n html_machines = html .. html_table\n selected_machine = selectedMachine\nend\nif enableStorageMonitoring then\n hud.coroutines.renderStorage = function()\n local html = \"\"\n local html_table = \"\"\n local lastStorage = 0\n local firstStorage = 0\n local totalPage = 1\n local selectedStorage = nil\n if displayMode == 0 or displayMode == 2 then\n local selectedStorages = {}\n for k,storage in pairs(storages) do\n if statusFilterType >= maxFilterType and storage.monitor then\n if displayType == 0 then\n table.insert(selectedStorages, storage)\n elseif displayType == 1 then\n table.insert(selectedStorages, storage)\n end\n end\n end\n if (displayType == 0 or displayType == 2) then\n for k,storage in pairs(storages) do\n if storage.screenPos[1] > 0 and storage.screenPos[1] < 1 and storage.screenPos[2] > 0 and storage.screenPos[2] < 1 then\n local showDetail = false\n if storage.screenPos[3] <= machineDetailDisplayDistance then\n showDetail = true\n elseif storage.screenPos[1] < 0.55 and storage.screenPos[1] > 0.45 and storage.screenPos[2] < 0.55 and storage.screenPos[2] > 0.45 then\n showDetail = true\n end\n local font_size = fontSize * ((200-storage.screenPos[3])/200)\n local zindex = utils.round(1000 - storage.screenPos[3])\n local displayName = storage.name\n local tierBox = ''\n local itemBox = ''\n local fillGauge = ''\n if storage.item ~= nil and storage.item.name ~= \"InvalidItem\" then\n displayName = format_number(utils.round(storage.quantity*100)/100) .. \" \" .. storage.item.locDisplayNameWithSize .. \" (\" .. storage.percent .. \"%)\"\n tierBox = '<span class=\"tier' .. storage.item.tier .. '\">T' .. storage.item.tier .. '</span>'\n local i = storage.item\n local gaugePercent = storage.percent\n if storage.percent > 100 then\n gaugePercent = 100\n end\n local r,g,b = getRGBGradient(gaugePercent/100,177,42,42,249,212,123,34,177,76)\n r = utils.round(r)\n g = utils.round(g)\n b = utils.round(b)\n itemBox = [[<hr><div><strong>Item ID:</strong> ]] .. i.id .. [[</div><div><strong>Item Name:</strong> ]] .. i.locDisplayNameWithSize .. [[</div><div><strong>Item Unit Mass:</strong> ]] .. i.unitMass .. [[ kg</div><div><strong>Item Unit Volume:</strong> ]] .. i.unitVolume .. [[ m<sup>3</sup></div>]]\n fillGauge = '<div style=\"position:absolute;bottom:0;left:0px;width:' .. gaugePercent .. '%;background-color:rgb(' .. r .. ',' .. g ..',' .. b .. ');height:3px;z-index:' .. (zindex+1) .. ';\"></div>'\n end\n html = html .. [[<div class=\"ib\" style=\"left:]] .. utils.round(storage.screenPos[1]*100) .. [[%;top:]] .. utils.round(storage.screenPos[2]*100) .. [[%;font-size:]] .. font_size .. [[px;z-index:]]..zindex..[[;\"><div class=\"bg-light text-dark\" style=\"padding:2px;padding-bottom:5px;text-transform:capitalize;position:relative;\">]] .. tierBox .. [[<strong>]] .. displayName .. [[</strong>]] .. fillGauge .. [[</div>]]\n if showDetail then\n html = html .. [[<div class=\"bg-light text-dark\" style=\"margin-top:2px;padding:2px;\"><div><strong>Container Type:</strong> ]] .. storage.type .. \" \" .. storage.size .. [[</div>]] .. itemBox .. [[</div></div>]]\n end\n html = html .. [[</div>]]\n end\n end\n end\n if (displayType == 0 or displayType == 1) and statusFilterType >= maxFilterType then\n totalPage = math.ceil(#selectedStorages/elementsByPage)\n firstStorage = (page - 1) * elementsByPage + 1\n lastStorage = page * elementsByPage\n if lastStorage > #selectedStorages then\n lastStorage = #selectedStorages\n end\n html_table = html_table .. '<div class=\"hud_container hud_table_container\"><div style=\"text-align:center;border-bottom:1px solid white;\">&#x2191; &nbsp;&nbsp; Arrow Up</div><table style=\"width:100%\"><tr><th>&#x2190; &nbsp;&nbsp; Arrow Left</th><th> Page ' .. page .. '/' .. totalPage .. ' (from ' .. firstStorage .. ' to ' .. lastStorage .. ' on ' .. #selectedStorages .. ')</th><th>Arrow Right &nbsp;&nbsp; &#x2192;</th></tr></table><table><tr><th>id</th><th>Storage Name & Type</th><th>Item Name</th><th>Quantity</th><th style=\"width:100px;\">Percent fill</th></tr>'\n local count = 1\n if sortingType == 1 then\n table.sort(selectedStorages, function(a,b) return a.tableName < b.tableName end)\n elseif sortingType == 2 then\n table.sort(selectedStorages, function(a,b) return a.item.locDisplayNameWithSize < b.item.locDisplayNameWithSize end)\n elseif sortingType == 3 then\n table.sort(selectedStorages, function(a,b) return a.id < b.id end)\n end\n for k,storage in pairs(selectedStorages) do\n if count >= firstStorage and count <= lastStorage then\n local selectedClass = \"\"\n if selectedRow == (count + 1 - firstStorage)then\n selectedClass = \"row_selected\"\n selectedStorage = storage\n end\n local item_name = \"\"\n if storage.item ~= nil and storage.item.name ~= \"InvalidItem\" then\n item_name = storage.item.locDisplayNameWithSize\n end\n local gaugePercent = storage.percent\n if storage.percent > 100 then\n gaugePercent = 100\n end\n local r,g,b = getRGBGradient(gaugePercent/100,177,42,42,249,212,123,34,177,76)\n r = utils.round(r)\n g = utils.round(g)\n b = utils.round(b)\n html_table = html_table .. '<tr><th class=\"' .. selectedClass .. '\">' .. storage.id .. '</th><th class=\"' .. selectedClass .. '\">' .. storage.tableName .. '<br><small>' .. storage.type .. ' ' .. storage.size .. '</small></th><th class=\"' .. selectedClass .. '\">' .. item_name .. '</th><th class=\"' .. selectedClass .. '\">' .. format_number(utils.round(storage.quantity*100)/100) .. '</th><th class=\"' .. selectedClass .. '\">' .. storage.percent .. '%<br><div style=\"border:1px solid black;position:relative;height:5px;\"><div style=\"position:absolute;left:0;top:0;width:' .. gaugePercent .. '%;background-color:rgb(' .. r .. ',' .. g ..',' .. b .. ');height:5px;\"></div></div></th></tr>'\n end\n count = count + 1\n end\n html_table = html_table .. '</table><table style=\"width:100%\"><tr><th>&#x2190; &nbsp;&nbsp; Arrow Left</th><th> Page ' .. page .. '/' .. totalPage .. ' (from ' .. firstStorage .. ' to ' .. lastStorage .. ' on ' .. #selectedStorages .. ')</th><th>Arrow Right &nbsp;&nbsp; &#x2192;</th></tr></table><div style=\"text-align:center;border-bottom:1px solid white;\">&#x2193; &nbsp;&nbsp; Arrow Down</div></div>'\n maxPage = totalPage\n maxOnPage = lastStorage-firstStorage+1\n end\n end\n html_storage = html .. html_table\n selected_storage = selectedStorage\n end\nend\nhud.coroutines.renderFilterStatus = function()\n html_filters = \"<style>\"\n html_filters = html_filters .. \".bg{margin:5px;padding:2px;}.bg\" .. (statusFilter+1) .. \"{border: 1px solid #28a745 !important;}\"\n html_filters = html_filters .. \"</style>\"\n html_filters = html_filters .. [[<div class=\"hud_container hud_machine_status_container\"><div><span class=\"bg bg1\" >ALL</span>|]]\n for i,status in ipairs(statusList) do\n html_filters = html_filters .. [[<span class=\"bg bg]] .. (i+1) .. [[ ]] .. getIndustryStatusClass(i) .. [[\">]] .. statusList[i] .. [[</span>]]\n if i < #statusList then html_filters = html_filters .. '|' end\n end\n html_filters = html_filters .. '</div>'\n html_filters = html_filters .. [[<hr class=\"hr-light\"><table style=\"width:100%;\"><tr><td style=\"padding-left:5px;\">&#x2190; &nbsp;&nbsp; Ctrl+Arrow Left</td><td style=\"text-align:right;padding-right:5px;\">Ctrl+Arrow Right &nbsp;&nbsp; &#x2192;</td></tr></table></div>]]\nend\nhud.coroutines.renderFilterType = function()\n if displayMode < #displayModes-1 then\n maxFilterType = #elementsTypes\n if displayMode == 0 and enableStorageMonitoring then\n maxFilterType = #elementsTypes + 1\n elseif displayMode == 2 then\n maxFilterType = 0\n end\n html_filters_types = \"<style>.bgt\" .. (statusFilterType+1) .. \"{border: 2px solid #28a745 !important;}</style>\"\n html_filters_types = html_filters_types .. '<div class=\"hud_container hud_machine_types_container\" style=\"text-align:center;\"><div>&#x2191; &nbsp;&nbsp; Ctrl+Arrow Up</div><hr class=\"hr-light\">'\n if displayMode == 0 or displayMode == 1 then\n html_filters_types = html_filters_types .. '<div class=\"bgt1\" style=\"margin:5px;\">ALL Industries (' .. #industries_id .. ')</div>'\n for i,v in ipairs(elementsTypes) do\n html_filters_types = html_filters_types .. '<div class=\"bgt' .. (i+1) .. '\" style=\"margin:5px;\">' .. v .. ' (' .. machines_count[v] .. ')</div>'\n end\n end\n if enableStorageMonitoring and (displayMode == 0 or displayMode == 2) then\n local bgtclass = 'bgt' .. (#elementsTypes + 2)\n if displayMode == 2 then\n bgtclass = 'bgt1'\n end\n html_filters_types = html_filters_types .. '<div class=\"' .. bgtclass .. '\" style=\"margin:5px;\">Storage (' .. #storages_id .. ')</div>'\n end\n html_filters_types = html_filters_types .. '<hr class=\"hr-light\"><div>&#x2193; &nbsp;&nbsp; Ctrl+Arrow Down</div></div>'\n else\n html_filters_types = \"\"\n end\nend\nhud.coroutines.renderSelectedAR = function()\n local html = \"\"\n if displayType == 0 or displayType == 1 then\n if selected_machine then\n local industry = selected_machine\n html = html .. [[<div class=\"ib ]] .. getIndustryStatusBorderClass(industry.state) .. [[\" style=\"border:5px solid white;left:]] .. utils.round(industry.screenPos[1]*100) .. [[%;top:]] .. utils.round(industry.screenPos[2]*100) .. [[%;font-size:]] .. fontSize .. [[px;z-index:1000;\"><div class=\"]] .. getIndustryStatusBgClass(industry.state) .. [[\" style=\"padding:2px;text-transform:capitalize;\"><span class=\"tier]] .. industry.production.tier .. [[\">T]] .. industry.production.tier .. [[</span><strong>]] .. industry.production.locDisplayNameWithSize .. [[</strong></div><div class=\"bg-light text-dark\" style=\"margin-top:2px;padding:2px;\"><div class=\"]] .. getIndustryStatusClass(industry.state) .. [[\"><strong>]] .. statusList[industry.state] .. [[</strong></div><div>]] .. industry.productId .. industry.name .. industry.type .. industry.mode .. industry.schematic .. industry.remainingTime .. industry.recipe ..[[</div></div></div>]]\n elseif selected_storage then\n local storage = selected_storage\n local displayName = storage.name\n local tierBox = ''\n local itemBox = ''\n local fillGauge = ''\n local gaugePercent = storage.percent\n if storage.percent > 100 then\n gaugePercent = 100\n end\n local r,g,b = getRGBGradient(gaugePercent/100,177,42,42,249,212,123,34,177,76)\n r = utils.round(r)\n g = utils.round(g)\n b = utils.round(b)\n if storage.item ~= nil and storage.item.name ~= \"InvalidItem\" then\n displayName = format_number(utils.round(storage.quantity*100)/100) .. \" \" .. storage.item.locDisplayNameWithSize .. \" (\" .. storage.percent .. \"%)\"\n tierBox = '<span class=\"tier' .. storage.item.tier .. '\">T' .. storage.item.tier .. '</span>'\n local i = storage.item\n\n itemBox = [[<hr><div><strong>Item ID:</strong> ]] .. i.id .. [[</div><div><strong>Item Name:</strong> ]] .. i.locDisplayNameWithSize .. [[</div><div><strong>Item Unit Mass:</strong> ]] .. i.unitMass .. [[ kg</div><div><strong>Item Unit Volume:</strong> ]] .. i.unitVolume .. [[ m<sup>3</sup></div>]]\n fillGauge = '<div style=\"position:absolute;bottom:0;left:0px;width:' .. gaugePercent .. '%;background-color:rgb(' .. r .. ',' .. g ..',' .. b .. ');height:3px;z-index:1000;\"></div>'\n end\n html = html .. [[<div class=\"ib\" style=\"border: 5px solid rgb(]] .. r .. [[,]] .. g ..[[,]] .. b .. [[);left:]] .. utils.round(storage.screenPos[1]*100) .. [[%;top:]] .. utils.round(storage.screenPos[2]*100) .. [[%;font-size:]] .. fontSize .. [[px;z-index:1000;\"><div class=\"bg-light text-dark\" style=\"padding:2px;padding-bottom:5px;text-transform:capitalize;position:relative;\">]] .. tierBox .. [[<strong>]] .. displayName .. [[</strong>]] .. fillGauge .. [[</div><div class=\"bg-light text-dark\" style=\"margin-top:2px;padding:2px;\"><div><strong>Container Type:</strong> ]] .. storage.type .. \" \" .. storage.size .. [[</div>]] .. itemBox .. [[</div></div>]]\n html = html .. [[</div>]]\n end\n end\n html_ar_selected = html\nend\nhud.coroutines.renderControlSelectedIndustry = function()\n local html = \"\"\n if #databanks > 0 and emitter ~= nil and selected_machine ~= nil and (displayType == 0 or displayType == 1) then\n local industry = selected_machine\n html = '<div class=\"hud_container hud_machine_control\" style=\"text-align:center;\"><div class=\"' .. getIndustryStatusClass(industry.state) .. '\">' .. industry.tableName .. '<br><small>' .. statusList[industry.state] .. '</small></div><hr class=\"hr-light\"><div>' .. industry.production.locDisplayNameWithSize .. '</div>'\n if industry.state == 1 or industry.state == (#statusList - 1) then\n command_1 = \"START\"\n command_2 = \"BATCH\"\n command_3 = \"MAINTAIN\"\n html = html .. '<table style=\"width:100%;\"><tr><th style=\"text-align:left;width:100px;\">START</th><th style=\"width:100px;\"></th><th style=\"text-align:right;width:100px;\">Alt+1</th></tr><tr><th style=\"text-align:left;\">START BATCH</th><th rowspan=\"2\">Quantity:<br>'\n local has_quantity = false\n for k,v in pairs(craft_quantity_digits) do\n if tonumber(v) == nil then v = 0 end\n if tonumber(v) > 0 then\n has_quantity = true\n end\n end\n if not has_quantity then\n local value = tostring(math.floor(industry.maintainOrBatchQuantity))\n for i = #value, 1, -1 do\n local c = value:sub(i,i)\n craft_quantity_digits[9-(#value-(i-1))] = c\n end\n end\n for digit_index,digit in pairs(craft_quantity_digits) do\n html = html .. digit\n end\n html = html .. '</th><th style=\"text-align:right;\">ALT+2</th></tr><tr><th style=\"text-align:left;\">MAINTAIN</th><th style=\"text-align:right;\">ALT+3</th></tr></table>'\n elseif industry.state < #statusList then\n command_1 = \"STOP\"\n command_2 = \"SOFT_STOP\"\n command_3 = \"HARD_STOP\"\n html = html .. [[<table><tr><th style=\"text-align:left;width:250px;\">STOP</th><th style=\"text-align:right;width:50px;\">ALT+1</th></tr><tr><th style=\"text-align:left;\">FINISH AND STOP</th><th style=\"text-align:right;\">ALT+2</th></tr><tr><th style=\"text-align:left;\">STOP AND ALLOW MATERIAL LOSS</th><th style=\"text-align:right;\">ALT+3</th></tr></table>]]\n else\n html = html .. '<div>Pending stop, please wait</div>'\n end\n html = html .. '</div>'\n end\n html_control = html\nend\nhud.coroutines.renderHud = function()\n local html = bootstrap_css_colors .. base_css .. html_ar_selected\n if displayMode ~= 3 then\n html = html .. html_filters_types\n if displayMode == 0 or displayMode == 1 then\n html = html .. html_machines .. html_filters .. html_control\n end\n if displayMode == 0 or displayMode == 2 then\n html = html .. html_storage\n end\n end\n html = html .. html_time .. html_credits\n system.setScreen(html)\nend\nhud.actions = {}\nhud.actions.start = {}\nhud.actions.stop = {}\nhud.actions.start.brake = function() ctrlPressed = true end\nhud.actions.stop.brake = function() ctrlPressed = false end\nhud.actions.start.down = function()\n if ctrlPressed and displayMode < 3 then\n statusFilterType = statusFilterType + 1\n if statusFilterType > maxFilterType then statusFilterType = 0 end\n onFilterChange()\n elseif displayMode < 3 then\n selectedRow = selectedRow + 1\n if selectedRow > maxOnPage then selectedRow = 1 end\n onRowChange()\n end\nend\nhud.actions.start.up = function()\n if ctrlPressed and displayMode < 3 then\n statusFilterType = statusFilterType - 1\n local max = #elementsTypes\n if statusFilterType < 0 then statusFilterType = maxFilterType end\n onFilterChange()\n elseif displayMode < 3 then\n selectedRow = selectedRow - 1\n if selectedRow < 1 then selectedRow = maxOnPage end\n onRowChange()\n end\nend\nhud.actions.start.option1 = function()\n if #databanks > 0 and emitter ~= nil and selected_machine ~= nil and (displayType == 0 or displayType == 1) then\n --Send Command 1\n for _,db in pairs(databanks) do\n db.setStringValue(selected_machine.id, command_1)\n end\n emitter.send(channels[selected_machine.typeFilter:lower()], \"\")\n end\nend\nhud.actions.start.option2 = function()\n if #databanks > 0 and emitter ~= nil and selected_machine ~= nil and (displayType == 0 or displayType == 1) then\n --Send Command 2\n for _,db in pairs(databanks) do\n if command_2:find(\"MAINTAIN\") or command_2:find(\"BATCH\") then\n craft_quantity = \"\"\n for _,digit in pairs(craft_quantity_digits) do\n craft_quantity = craft_quantity .. digit\n end\n command_2 = command_2 .. \"_\" .. craft_quantity\n end\n db.setStringValue(selected_machine.id, command_2)\n if command_2:find(\"MAINTAIN\") then command_2 = \"MAINTAIN\" end\n if command_2:find(\"BATCH\") then command_2 = \"BATCH\" end\n end\n emitter.send(channels[selected_machine.typeFilter:lower()], \"\")\n end\nend\nhud.actions.start.option3 = function()\n if #databanks > 0 and emitter ~= nil and selected_machine ~= nil and (displayType == 0 or displayType == 1) then\n --Send Command 3\n for _,db in pairs(databanks) do\n if command_3:find(\"MAINTAIN\") or command_3:find(\"BATCH\") then\n craft_quantity = \"\"\n for _,digit in pairs(craft_quantity_digits) do\n craft_quantity = craft_quantity .. digit\n end\n command_3 = command_3 .. \"_\" .. craft_quantity\n end\n db.setStringValue(selected_machine.id, command_3)\n if command_3:find(\"MAINTAIN\") then command_3 = \"MAINTAIN\" end\n if command_3:find(\"BATCH\") then command_3 = \"BATCH\" end\n end\n emitter.send(channels[selected_machine.typeFilter:lower()], \"\")\n end\nend\nhud.actions.start.option6 = function()\n sortingType = sortingType + 1\n if sortingType < 0 then sortingType = #sortingTypes end\n if sortingType > (#sortingTypes) then sortingType = 1 end\nend\nhud.actions.start.option7 = function()\n displayType = displayType + 1\n if displayType < 0 then displayType = (#displayTypes-1) end\n if displayType > (#displayTypes-1) then displayType = 0 end\nend\nhud.actions.start.option8 = function()\n displayMode = displayMode + 1\n if displayMode < 0 then displayMode = (#displayModes-1) end\n if displayMode > (#displayModes-1) then displayMode = 0 end\nend\nhud.actions.start.option9 = function()\n init = false\nend\nhud.actions.start.strafeleft = function()\n if ctrlPressed and (displayMode == 0 or displayMode == 1) then\n statusFilter = statusFilter - 1\n if statusFilter < 0 then statusFilter = #statusList end\n onFilterChange()\n elseif (displayType == 0 or displayType == 1) then\n page = page - 1\n if page < 1 then page = maxPage end\n onTablePageChange()\n end\nend\nhud.actions.start.straferight = function()\n if ctrlPressed and (displayMode == 0 or displayMode == 1) then\n statusFilter = statusFilter + 1\n if statusFilter > #statusList then statusFilter = 0 end\n onFilterChange()\n elseif (displayType == 0 or displayType == 1) then\n page = page + 1\n if page > maxPage then page = 1 end\n onTablePageChange()\n end\nend\n\n--[[\n DU-Nested-Coroutines by Jericho\n Permit to easier avoid CPU Load Errors\n Source available here: https://github.com/Jericho1060/du-nested-coroutines\n]]--\n\ncoroutinesTable = {}\n\nfunction initCoroutines()\n for k,f in pairs(hud.coroutines) do\n coroutinesTable[k] = coroutine.create(f)\n end\nend\n\ninitCoroutines()\n\nfor k,f in pairs(coroutinesTable) do system.print(k) end\n\nrunCoroutines = function()\n for k,co in pairs(coroutinesTable) do\n if coroutine.status(co) == \"dead\" then\n coroutinesTable[k] = coroutine.create(hud.coroutines[k])\n end\n if coroutine.status(co) == \"suspended\" then\n assert(coroutine.resume(co))\n end\n end\nend\n\nMainCoroutine = coroutine.create(runCoroutines)\n\nunit.hideWidget()\n\nfunction onTablePageChange()\n selectedRow = 1\n onRowChange()\nend\n\nfunction onFilterChange()\n onTablePageChange()\n page = 1\nend\n\nfunction onRowChange()\n craft_quantity_digits = {\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\",\"0\"}\nend\n","filter":{"args":[],"signature":"onStart()","slotKey":"-1"},"key":"2"},{"code":"local content = schematicContainer.getContent()\nfor _,s in pairs(content) do\n schematicStorage[\"s\" .. s.id] = s.quantity\nend","filter":{"args":[],"signature":"onContentUpdate()","slotKey":"0"},"key":"0"}],"methods":[],"slots":{"0":{"name":"slot1","type":{"events":[],"methods":[]}},"1":{"name":"slot2","type":{"events":[],"methods":[]}},"2":{"name":"slot3","type":{"events":[],"methods":[]}},"3":{"name":"slot4","type":{"events":[],"methods":[]}},"4":{"name":"slot5","type":{"events":[],"methods":[]}},"5":{"name":"slot6","type":{"events":[],"methods":[]}},"6":{"name":"slot7","type":{"events":[],"methods":[]}},"7":{"name":"slot8","type":{"events":[],"methods":[]}},"8":{"name":"slot9","type":{"events":[],"methods":[]}},"9":{"name":"slot10","type":{"events":[],"methods":[]}},"-5":{"name":"library","type":{"events":[],"methods":[]}},"-4":{"name":"system","type":{"events":[],"methods":[]}},"-3":{"name":"player","type":{"events":[],"methods":[]}},"-2":{"name":"construct","type":{"events":[],"methods":[]}},"-1":{"name":"unit","type":{"events":[],"methods":[]}}}}
+239 -227
Master Program/source/unit/onStart.lua
··· 1 - version = "v4.2.1" 1 + version = "v4.3.0" 2 2 --[[ 3 3 DU Industry HUD By Jericho 4 4 ]] ··· 22 22 enableMetalworkMonitoring = true --export: enable or disable the Metalworks monitoring 23 23 enable3DPrinterMonitoring = true --export: enable or disable the 3D Printers monitoring 24 24 enableTransferMonitoring = true --export: enable or disable the transfer units monitoring 25 + enableStorageMonitoring = true --export: enable or disable the storage monitoring 25 26 enableRemoteControl = true --export: enable the HUD to control machines (start/stop/batch/maintain) 26 27 elementsByPage = 20 --export: maximum amount of elements displayed on a single page 27 28 dateFormat = "en" --export: the country code to format the date ··· 63 64 function getRGBGradient(a,b,c,d,e,f,g,h,i,j)a=-1*math.cos(a*math.pi)/2+0.5;local k=0;local l=0;local m=0;if a>=.5 then a=(a-0.5)*2;k=e-a*(e-h)l=f-a*(f-i)m=g-a*(g-j)else a=a*2;k=b-a*(b-e)l=c-a*(c-f)m=d-a*(d-g)end;return k,l,m end 64 65 --time script to get client date and time by Jericho, see full source at https://github.com/Jericho1060/DualUniverse 65 66 function DUCurrentDateTime(a)local b=system.getUtcTime()if not a then b=b+system.getUtcOffset()end;local c=24*60*60;local d=365*c;local e=d+c;local f=4*d+c;local g=4;local h=1970;local i={-1,30,58,89,119,150,180,211,242,272,303,333,364}local j={}for k=1,2 do j[k]=i[k]end;for k=3,13 do j[k]=i[k]+1 end;local l,m,n,o,p,q,r,s;local t=i;s=b;l=math.floor(s/f)s=s-l*f;l=l*4+h;if s>=d then l=l+1;s=s-d;if s>=d then l=l+1;s=s-d;if s>=e then l=l+1;s=s-e else t=j end end end;m=math.floor(s/c)s=s-m*c;local n=1;while t[n]<m do n=n+1 end;n=n-1;local o=m-t[n]p=(math.floor(b/c)+g)%7;if p==0 then p=7 end;q=math.floor(s/3600)s=s-q*3600;r=math.floor(s/60)function round(u,v)if v then return utils.round(u/v)*v end;return u>=0 and math.floor(u+0.5)or math.ceil(u-0.5)end;s=round(s-r*60)local w={"Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"}local x={"Mon","Tue","Wed","Thu","Fri","Sat","Sun"}local y={"January","February","March","April","May","June","July","August","September","October","November","December"}local z={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}return l,n,o,q,r,s,p,w[p],x[p],y[n],z[n],m+1 end 66 - 67 + 67 68 --databank hub library By Jericho, see full source at https://github.com/Jericho1060/DualUniverse 68 69 bankhub={}function bankhub:new(banks)o={}setmetatable(o,self)self.__index=self;o.banks=banks or{}function o.clear()return o:_clear()end;function o.getNbKeys()return o:_getNbKeys()end;function o.getKeys()return o:_getKeys()end;function o.hasKey(a)return o:_hasKey(a)end;function o.getStringValue(a)return o:_getStringValue(a)end;function o.getIntValue(a)return o:_getIntValue(a)end;function o.getFloatValue(a)return o:_getFloatValue(a)end;return o end;function bankhub:add(b)table.insert(self.banks,b)self.banks_size=#self.banks end;function bankhub:_clear()for c,d in pairs(self.banks)do d.clear()end end;function bankhub:_getNbKeys()local e=0;for c,d in pairs(self.banks)do e=e+d.getNbKeys()end;return e end;function bankhub:_getKeys()local e={}for c,d in pairs(self.banks)do local f=json.decode(d.getKeys())for c,g in pairs(f)do table.insert(e,g)end end;return json.encode(e)end;function bankhub:_hasKey(a)for c,d in pairs(self.banks)do if d.hasKey(a)==1 then return 1 end end;return 0 end;function bankhub:_getStringValue(a)for c,d in pairs(self.banks)do if d.hasKey(a)==1 then return d.getStringValue(a)end end;return nil end;function bankhub:_getIntValue(a)for c,d in pairs(self.banks)do if d.hasKey(a)==1 then return banks.getIntValue(a)end end;return nil end;function bankhub:_getFloatValue(a)for c,d in pairs(self.banks)do if d.hasKey(a)==1 then return banks.getFloatValue(a)end end;return nil end 69 70 --time script to get client date and time by Jericho, see full source at https://github.com/Jericho1060/DualUniverse ··· 151 152 schematicStorage = {} 152 153 for slot_name, slot in pairs(unit) do 153 154 if 154 - type(slot) == "table" 155 - and type(slot.export) == "table" 156 - and slot.getClass 155 + type(slot) == "table" 156 + and type(slot.export) == "table" 157 + and slot.getClass 157 158 then 158 159 if slot.getClass():lower() == 'databankunit' then 159 160 table.insert(databanks, slot) ··· 180 181 system.print("Schematic Container is not linked to the board") 181 182 end 182 183 183 - if emitter == nil then 184 + if emitter == nil then 184 185 enableRemoteControl = false 185 186 system.print("Connect an Emitter to enable machine control from industry") 186 187 end 187 - if #databanks == 0 then 188 + if #databanks == 0 then 188 189 enableRemoteControl = false 189 190 system.print("No Databank linked") 190 191 end ··· 202 203 storage_prefix = strSplit(storages_prefix_list, ',') 203 204 displayTypes = {"ALL", "Table", "Augmented Reality"} 204 205 displayModes = {"ALL", "Industry", "Storage", "None"} 206 + if not enableStorageMonitoring then 207 + displayModes = {"ALL", "Industry", "None"} 208 + end 205 209 sortingTypes = {"Element Name", "Item", "Element ID"} 206 210 init = false 207 211 initIndex = 1 ··· 268 272 for index,id in ipairs(elementsIdList) do 269 273 elementType = core.getElementDisplayNameById(id):lower() 270 274 if (elementType:find("assembly line") and enableAssemblyMonitoring == true) or 271 - (elementType:find("glass furnace") and enableGlassMonitoring == true) or 272 - (elementType:find("3d printer") and enable3DPrinterMonitoring == true) or 273 - (elementType:find("smelter") and enableSmelterMonitoring == true) or 274 - (elementType:find("recycler") and enableRecyclerMonitoring == true) or 275 - (elementType:find("refinery") and enableHoneycombMonitoring == true) or 276 - (elementType:find("refiner") and enableRefinerMonitoring == true) or 277 - (elementType:find("industry") 278 - and ( 279 - (elementType:find("chemical") and enableChemicalMonitoring == true) or 280 - (elementType:find("electronics") and enableElectronicsMonitoring == true) or 281 - (elementType:find("metalwork") and enableMetalworkMonitoring == true) 275 + (elementType:find("glass furnace") and enableGlassMonitoring == true) or 276 + (elementType:find("3d printer") and enable3DPrinterMonitoring == true) or 277 + (elementType:find("smelter") and enableSmelterMonitoring == true) or 278 + (elementType:find("recycler") and enableRecyclerMonitoring == true) or 279 + (elementType:find("refinery") and enableHoneycombMonitoring == true) or 280 + (elementType:find("refiner") and enableRefinerMonitoring == true) or 281 + (elementType:find("industry") 282 + and ( 283 + (elementType:find("chemical") and enableChemicalMonitoring == true) or 284 + (elementType:find("electronics") and enableElectronicsMonitoring == true) or 285 + (elementType:find("metalwork") and enableMetalworkMonitoring == true) 282 286 ) 283 - ) or 284 - (elementType == "transfer unit" and enableTransferMonitoring == true) or 285 - elementType:lower():find("container") 286 - then 287 + ) or 288 + (elementType == "transfer unit" and enableTransferMonitoring == true) or 289 + elementType:lower():find("container") 290 + then 287 291 local formatedType = removeQualityInName(elementType) 288 292 local pos = core.getElementPositionById(id) 289 - if elementType:lower():find("container") then 293 + if elementType:lower():find("container") and enableStorageMonitoring then 290 294 if storages_count[formatedType] ~= nil then 291 295 storages_count[formatedType] = storages_count[formatedType] + 1 292 296 else ··· 295 299 table.insert(storages_id, id) 296 300 storages_positions['i'..id] = pos 297 301 table.insert(storagesTypes, formatedType) 298 - else 302 + elseif not elementType:lower():find("container") then 299 303 pos[3] = pos[3] + 1 300 304 if machines_count[formatedType] ~= nil then 301 305 machines_count[formatedType] = machines_count[formatedType] + 1 ··· 309 313 end 310 314 311 315 if index % maxAmountOfElementsLoadedByFrame == 0 then 312 - coroutine.yield(self.init) 316 + coroutine.yield() 313 317 end 314 318 end 315 319 elementsTypes = removeDuplicatesInTable(elementsTypes) ··· 427 431 stopRequested=data.stopRequested 428 432 } 429 433 if index % machinesRefreshedByFrame == 0 then 430 - coroutine.yield(self.loadIndustries) 434 + coroutine.yield() 431 435 end 432 436 end 433 437 end 434 438 end 435 - hud.coroutines.loadStorage = function() 436 - for index,id in ipairs(storages_id) do 437 - local pos = storages_positions['i'..id] 438 - local elementType = core.getElementDisplayNameById(id) 439 - local base_name = core.getElementNameById(id) 440 - local splitted = strSplit(base_name,'_') 441 - local item_id = nil 442 - local prefix = nil 443 - if #splitted > 1 then 444 - prefix = splitted[1] 445 - item_id = splitted[2] 446 - end 447 - local container = { 448 - id = id, 449 - type=elementType, 450 - name = "[" .. id .. "] " .. base_name, 451 - tableName = base_name, 452 - prefix = prefix, 453 - item_id = item_id, 454 - monitor = false, 455 - screenPos=library.getPointOnScreen(ConvertLocalToWorld(pos, constructPos, constructRight, constructForward, constructUp)), 456 - } 457 - if item_id and prefix then 458 - for _,sprefix in ipairs(storage_prefix) do 459 - if prefix:lower() == sprefix:lower() then 460 - container.monitor = true 461 - container.item = system.getItem(item_id) 462 - break 439 + if enableStorageMonitoring then 440 + hud.coroutines.loadStorage = function() 441 + if init and (displayMode == 0 or displayMode == 2) then 442 + for index,id in ipairs(storages_id) do 443 + local pos = storages_positions['i'..id] 444 + local elementType = core.getElementDisplayNameById(id) 445 + local base_name = core.getElementNameById(id) 446 + local splitted = strSplit(base_name,'_') 447 + local item_id = nil 448 + local prefix = nil 449 + if #splitted > 1 then 450 + prefix = splitted[1] 451 + item_id = splitted[2] 452 + end 453 + local container = { 454 + id = id, 455 + type=elementType, 456 + name = "[" .. id .. "] " .. base_name, 457 + tableName = base_name, 458 + prefix = prefix, 459 + item_id = item_id, 460 + monitor = false, 461 + screenPos=library.getPointOnScreen(ConvertLocalToWorld(pos, constructPos, constructRight, constructForward, constructUp)), 462 + } 463 + if item_id and prefix then 464 + for _,sprefix in ipairs(storage_prefix) do 465 + if prefix:lower() == sprefix:lower() then 466 + container.monitor = true 467 + container.item = system.getItem(item_id) 468 + break 469 + end 470 + end 471 + end 472 + local container_size = "XS" 473 + local container_empty_mass = 0 474 + local container_volume = 0 475 + local contentQuantity = 0 476 + local percent_fill = 0 477 + if not elementType:lower():find("hub") then 478 + local containerMaxHP = core.getElementMaxHitPointsById(id) 479 + if containerMaxHP > 68000 then 480 + container_size = "XXL" 481 + container_empty_mass = 88410 482 + container_volume = 512000 * (containerProficiencyLvl * 0.1) + 512000 483 + elseif containerMaxHP > 33000 then 484 + container_size = "XL" 485 + container_empty_mass = 44210 486 + container_volume = 256000 * (containerProficiencyLvl * 0.1) + 256000 487 + elseif containerMaxHP > 17000 then 488 + container_size = "L" 489 + container_empty_mass = 14842.7 490 + container_volume = 128000 * (containerProficiencyLvl * 0.1) + 128000 491 + elseif containerMaxHP > 7900 then 492 + container_size = "M" 493 + container_empty_mass = 7421.35 494 + container_volume = 64000 * (containerProficiencyLvl * 0.1) + 64000 495 + elseif containerMaxHP > 900 then 496 + container_size = "S" 497 + container_empty_mass = 1281.31 498 + container_volume = 8000 * (containerProficiencyLvl * 0.1) + 8000 499 + else 500 + container_size = "XS" 501 + container_empty_mass = 229.09 502 + container_volume = 1000 * (containerProficiencyLvl * 0.1) + 1000 503 + end 504 + else 505 + if splitted[3] then 506 + container_size = splitted[3] 507 + end 508 + if splitted[4] then 509 + container_amount = splitted[4] 510 + end 511 + local volume = 0 512 + container_volume_list = {xxl=512000, xl=256000, l=128000, m=64000, s=8000, xs=1000} 513 + container_size = container_size:lower() 514 + if container_volume_list[container_size] then 515 + volume = container_volume_list[container_size] 516 + end 517 + container_volume = (volume * containerProficiencyLvl * 0.1 + volume) 518 + container_empty_mass = 55.8 463 519 end 464 - end 465 - end 466 - local container_size = "XS" 467 - local container_empty_mass = 0 468 - local container_volume = 0 469 - local contentQuantity = 0 470 - local percent_fill = 0 471 - if not elementType:lower():find("hub") then 472 - local containerMaxHP = core.getElementMaxHitPointsById(id) 473 - if containerMaxHP > 68000 then 474 - container_size = "XXL" 475 - container_empty_mass = 88410 476 - container_volume = 512000 * (containerProficiencyLvl * 0.1) + 512000 477 - elseif containerMaxHP > 33000 then 478 - container_size = "XL" 479 - container_empty_mass = 44210 480 - container_volume = 256000 * (containerProficiencyLvl * 0.1) + 256000 481 - elseif containerMaxHP > 17000 then 482 - container_size = "L" 483 - container_empty_mass = 14842.7 484 - container_volume = 128000 * (containerProficiencyLvl * 0.1) + 128000 485 - elseif containerMaxHP > 7900 then 486 - container_size = "M" 487 - container_empty_mass = 7421.35 488 - container_volume = 64000 * (containerProficiencyLvl * 0.1) + 64000 489 - elseif containerMaxHP > 900 then 490 - container_size = "S" 491 - container_empty_mass = 1281.31 492 - container_volume = 8000 * (containerProficiencyLvl * 0.1) + 8000 493 - else 494 - container_size = "XS" 495 - container_empty_mass = 229.09 496 - container_volume = 1000 * (containerProficiencyLvl * 0.1) + 1000 497 - end 498 - else 499 - if splitted[3] then 500 - container_size = splitted[3] 501 - end 502 - if splitted[4] then 503 - container_amount = splitted[4] 504 - end 505 - local volume = 0 506 - container_volume_list = {xxl=512000, xl=256000, l=128000, m=64000, s=8000, xs=1000} 507 - container_size = container_size:lower() 508 - if container_volume_list[container_size] then 509 - volume = container_volume_list[container_size] 520 + local totalMass = core.getElementMassById(id) 521 + local contentMassKg = totalMass - container_empty_mass 522 + container.totalMass = totalMass 523 + container.emptyMass = container_empty_mass 524 + container.contentMass = contentMassKg 525 + container.maxVolume = container_volume 526 + container.size = container_size 527 + if container.item == nil or container.item.name == "InvalidItem" then 528 + container.percent = 0 529 + container.quantity = 0 530 + else 531 + container.quantity = contentMassKg / (container.item.unitMass - (container.item.unitMass * (containerOptimizationLvl * 0.05))) 532 + container.percent = utils.round((container.item.unitVolume * container.quantity) * 100 / container_volume) 533 + end 534 + storages['i'..id] = container 535 + if index % machinesRefreshedByFrame == 0 then 536 + coroutine.yield() 537 + end 510 538 end 511 - container_volume = (volume * containerProficiencyLvl * 0.1 + volume) 512 - container_empty_mass = 55.8 513 - end 514 - local totalMass = core.getElementMassById(id) 515 - local contentMassKg = totalMass - container_empty_mass 516 - container.totalMass = totalMass 517 - container.emptyMass = container_empty_mass 518 - container.contentMass = contentMassKg 519 - container.maxVolume = container_volume 520 - container.size = container_size 521 - if container.item == nil or container.item.name == "InvalidItem" then 522 - container.percent = 0 523 - container.quantity = 0 524 - else 525 - container.quantity = contentMassKg / (container.item.unitMass - (container.item.unitMass * (containerOptimizationLvl * 0.05))) 526 - container.percent = utils.round((container.item.unitVolume * container.quantity) * 100 / container_volume) 527 - end 528 - storages['i'..id] = container 529 - if index % machinesRefreshedByFrame == 0 then 530 - coroutine.yield(self.loadStorage) 531 539 end 532 540 end 533 541 end ··· 631 639 html_machines = html .. html_table 632 640 selected_machine = selectedMachine 633 641 end 634 - hud.coroutines.renderStorage = function() 635 - local html = "" 636 - local html_table = "" 637 - local lastStorage = 0 638 - local firstStorage = 0 639 - local totalPage = 1 640 - local selectedStorage = nil 641 - if displayMode == 0 or displayMode == 2 then 642 - local selectedStorages = {} 643 - for k,storage in pairs(storages) do 644 - if statusFilterType >= maxFilterType and storage.monitor then 645 - if displayType == 0 then 646 - table.insert(selectedStorages, storage) 647 - elseif displayType == 1 then 648 - table.insert(selectedStorages, storage) 642 + if enableStorageMonitoring then 643 + hud.coroutines.renderStorage = function() 644 + local html = "" 645 + local html_table = "" 646 + local lastStorage = 0 647 + local firstStorage = 0 648 + local totalPage = 1 649 + local selectedStorage = nil 650 + if displayMode == 0 or displayMode == 2 then 651 + local selectedStorages = {} 652 + for k,storage in pairs(storages) do 653 + if statusFilterType >= maxFilterType and storage.monitor then 654 + if displayType == 0 then 655 + table.insert(selectedStorages, storage) 656 + elseif displayType == 1 then 657 + table.insert(selectedStorages, storage) 658 + end 649 659 end 650 660 end 651 - end 652 - if (displayType == 0 or displayType == 2) then 653 - for k,storage in pairs(storages) do 654 - if storage.screenPos[1] > 0 and storage.screenPos[1] < 1 and storage.screenPos[2] > 0 and storage.screenPos[2] < 1 then 655 - local showDetail = false 656 - if storage.screenPos[3] <= machineDetailDisplayDistance then 657 - showDetail = true 658 - elseif storage.screenPos[1] < 0.55 and storage.screenPos[1] > 0.45 and storage.screenPos[2] < 0.55 and storage.screenPos[2] > 0.45 then 659 - showDetail = true 661 + if (displayType == 0 or displayType == 2) then 662 + for k,storage in pairs(storages) do 663 + if storage.screenPos[1] > 0 and storage.screenPos[1] < 1 and storage.screenPos[2] > 0 and storage.screenPos[2] < 1 then 664 + local showDetail = false 665 + if storage.screenPos[3] <= machineDetailDisplayDistance then 666 + showDetail = true 667 + elseif storage.screenPos[1] < 0.55 and storage.screenPos[1] > 0.45 and storage.screenPos[2] < 0.55 and storage.screenPos[2] > 0.45 then 668 + showDetail = true 669 + end 670 + local font_size = fontSize * ((200-storage.screenPos[3])/200) 671 + local zindex = utils.round(1000 - storage.screenPos[3]) 672 + local displayName = storage.name 673 + local tierBox = '' 674 + local itemBox = '' 675 + local fillGauge = '' 676 + if storage.item ~= nil and storage.item.name ~= "InvalidItem" then 677 + displayName = format_number(utils.round(storage.quantity*100)/100) .. " " .. storage.item.locDisplayNameWithSize .. " (" .. storage.percent .. "%)" 678 + tierBox = '<span class="tier' .. storage.item.tier .. '">T' .. storage.item.tier .. '</span>' 679 + local i = storage.item 680 + local gaugePercent = storage.percent 681 + if storage.percent > 100 then 682 + gaugePercent = 100 683 + end 684 + local r,g,b = getRGBGradient(gaugePercent/100,177,42,42,249,212,123,34,177,76) 685 + r = utils.round(r) 686 + g = utils.round(g) 687 + b = utils.round(b) 688 + itemBox = [[<hr><div><strong>Item ID:</strong> ]] .. i.id .. [[</div><div><strong>Item Name:</strong> ]] .. i.locDisplayNameWithSize .. [[</div><div><strong>Item Unit Mass:</strong> ]] .. i.unitMass .. [[ kg</div><div><strong>Item Unit Volume:</strong> ]] .. i.unitVolume .. [[ m<sup>3</sup></div>]] 689 + fillGauge = '<div style="position:absolute;bottom:0;left:0px;width:' .. gaugePercent .. '%;background-color:rgb(' .. r .. ',' .. g ..',' .. b .. ');height:3px;z-index:' .. (zindex+1) .. ';"></div>' 690 + end 691 + html = html .. [[<div class="ib" style="left:]] .. utils.round(storage.screenPos[1]*100) .. [[%;top:]] .. utils.round(storage.screenPos[2]*100) .. [[%;font-size:]] .. font_size .. [[px;z-index:]]..zindex..[[;"><div class="bg-light text-dark" style="padding:2px;padding-bottom:5px;text-transform:capitalize;position:relative;">]] .. tierBox .. [[<strong>]] .. displayName .. [[</strong>]] .. fillGauge .. [[</div>]] 692 + if showDetail then 693 + html = html .. [[<div class="bg-light text-dark" style="margin-top:2px;padding:2px;"><div><strong>Container Type:</strong> ]] .. storage.type .. " " .. storage.size .. [[</div>]] .. itemBox .. [[</div></div>]] 694 + end 695 + html = html .. [[</div>]] 660 696 end 661 - local font_size = fontSize * ((200-storage.screenPos[3])/200) 662 - local zindex = utils.round(1000 - storage.screenPos[3]) 663 - local displayName = storage.name 664 - local tierBox = '' 665 - local itemBox = '' 666 - local fillGauge = '' 667 - if storage.item ~= nil and storage.item.name ~= "InvalidItem" then 668 - displayName = format_number(utils.round(storage.quantity*100)/100) .. " " .. storage.item.locDisplayNameWithSize .. " (" .. storage.percent .. "%)" 669 - tierBox = '<span class="tier' .. storage.item.tier .. '">T' .. storage.item.tier .. '</span>' 670 - local i = storage.item 697 + end 698 + end 699 + if (displayType == 0 or displayType == 1) and statusFilterType >= maxFilterType then 700 + totalPage = math.ceil(#selectedStorages/elementsByPage) 701 + firstStorage = (page - 1) * elementsByPage + 1 702 + lastStorage = page * elementsByPage 703 + if lastStorage > #selectedStorages then 704 + lastStorage = #selectedStorages 705 + end 706 + html_table = html_table .. '<div class="hud_container hud_table_container"><div style="text-align:center;border-bottom:1px solid white;">&#x2191; &nbsp;&nbsp; Arrow Up</div><table style="width:100%"><tr><th>&#x2190; &nbsp;&nbsp; Arrow Left</th><th> Page ' .. page .. '/' .. totalPage .. ' (from ' .. firstStorage .. ' to ' .. lastStorage .. ' on ' .. #selectedStorages .. ')</th><th>Arrow Right &nbsp;&nbsp; &#x2192;</th></tr></table><table><tr><th>id</th><th>Storage Name & Type</th><th>Item Name</th><th>Quantity</th><th style="width:100px;">Percent fill</th></tr>' 707 + local count = 1 708 + if sortingType == 1 then 709 + table.sort(selectedStorages, function(a,b) return a.tableName < b.tableName end) 710 + elseif sortingType == 2 then 711 + table.sort(selectedStorages, function(a,b) return a.item.locDisplayNameWithSize < b.item.locDisplayNameWithSize end) 712 + elseif sortingType == 3 then 713 + table.sort(selectedStorages, function(a,b) return a.id < b.id end) 714 + end 715 + for k,storage in pairs(selectedStorages) do 716 + if count >= firstStorage and count <= lastStorage then 717 + local selectedClass = "" 718 + if selectedRow == (count + 1 - firstStorage)then 719 + selectedClass = "row_selected" 720 + selectedStorage = storage 721 + end 722 + local item_name = "" 723 + if storage.item ~= nil and storage.item.name ~= "InvalidItem" then 724 + item_name = storage.item.locDisplayNameWithSize 725 + end 671 726 local gaugePercent = storage.percent 672 727 if storage.percent > 100 then 673 728 gaugePercent = 100 ··· 676 731 r = utils.round(r) 677 732 g = utils.round(g) 678 733 b = utils.round(b) 679 - itemBox = [[<hr><div><strong>Item ID:</strong> ]] .. i.id .. [[</div><div><strong>Item Name:</strong> ]] .. i.locDisplayNameWithSize .. [[</div><div><strong>Item Unit Mass:</strong> ]] .. i.unitMass .. [[ kg</div><div><strong>Item Unit Volume:</strong> ]] .. i.unitVolume .. [[ m<sup>3</sup></div>]] 680 - fillGauge = '<div style="position:absolute;bottom:0;left:0px;width:' .. gaugePercent .. '%;background-color:rgb(' .. r .. ',' .. g ..',' .. b .. ');height:3px;z-index:' .. (zindex+1) .. ';"></div>' 681 - end 682 - html = html .. [[<div class="ib" style="left:]] .. utils.round(storage.screenPos[1]*100) .. [[%;top:]] .. utils.round(storage.screenPos[2]*100) .. [[%;font-size:]] .. font_size .. [[px;z-index:]]..zindex..[[;"><div class="bg-light text-dark" style="padding:2px;padding-bottom:5px;text-transform:capitalize;position:relative;">]] .. tierBox .. [[<strong>]] .. displayName .. [[</strong>]] .. fillGauge .. [[</div>]] 683 - if showDetail then 684 - html = html .. [[<div class="bg-light text-dark" style="margin-top:2px;padding:2px;"><div><strong>Container Type:</strong> ]] .. storage.type .. " " .. storage.size .. [[</div>]] .. itemBox .. [[</div></div>]] 685 - end 686 - html = html .. [[</div>]] 687 - end 688 - end 689 - end 690 - if (displayType == 0 or displayType == 1) and statusFilterType >= maxFilterType then 691 - totalPage = math.ceil(#selectedStorages/elementsByPage) 692 - firstStorage = (page - 1) * elementsByPage + 1 693 - lastStorage = page * elementsByPage 694 - if lastStorage > #selectedStorages then 695 - lastStorage = #selectedStorages 696 - end 697 - html_table = html_table .. '<div class="hud_container hud_table_container"><div style="text-align:center;border-bottom:1px solid white;">&#x2191; &nbsp;&nbsp; Arrow Up</div><table style="width:100%"><tr><th>&#x2190; &nbsp;&nbsp; Arrow Left</th><th> Page ' .. page .. '/' .. totalPage .. ' (from ' .. firstStorage .. ' to ' .. lastStorage .. ' on ' .. #selectedStorages .. ')</th><th>Arrow Right &nbsp;&nbsp; &#x2192;</th></tr></table><table><tr><th>id</th><th>Storage Name & Type</th><th>Item Name</th><th>Quantity</th><th style="width:100px;">Percent fill</th></tr>' 698 - local count = 1 699 - if sortingType == 1 then 700 - table.sort(selectedStorages, function(a,b) return a.tableName < b.tableName end) 701 - elseif sortingType == 2 then 702 - table.sort(selectedStorages, function(a,b) return a.item.locDisplayNameWithSize < b.item.locDisplayNameWithSize end) 703 - elseif sortingType == 3 then 704 - table.sort(selectedStorages, function(a,b) return a.id < b.id end) 705 - end 706 - for k,storage in pairs(selectedStorages) do 707 - if count >= firstStorage and count <= lastStorage then 708 - local selectedClass = "" 709 - if selectedRow == (count + 1 - firstStorage)then 710 - selectedClass = "row_selected" 711 - selectedStorage = storage 734 + html_table = html_table .. '<tr><th class="' .. selectedClass .. '">' .. storage.id .. '</th><th class="' .. selectedClass .. '">' .. storage.tableName .. '<br><small>' .. storage.type .. ' ' .. storage.size .. '</small></th><th class="' .. selectedClass .. '">' .. item_name .. '</th><th class="' .. selectedClass .. '">' .. format_number(utils.round(storage.quantity*100)/100) .. '</th><th class="' .. selectedClass .. '">' .. storage.percent .. '%<br><div style="border:1px solid black;position:relative;height:5px;"><div style="position:absolute;left:0;top:0;width:' .. gaugePercent .. '%;background-color:rgb(' .. r .. ',' .. g ..',' .. b .. ');height:5px;"></div></div></th></tr>' 712 735 end 713 - local item_name = "" 714 - if storage.item ~= nil and storage.item.name ~= "InvalidItem" then 715 - item_name = storage.item.locDisplayNameWithSize 716 - end 717 - local gaugePercent = storage.percent 718 - if storage.percent > 100 then 719 - gaugePercent = 100 720 - end 721 - local r,g,b = getRGBGradient(gaugePercent/100,177,42,42,249,212,123,34,177,76) 722 - r = utils.round(r) 723 - g = utils.round(g) 724 - b = utils.round(b) 725 - html_table = html_table .. '<tr><th class="' .. selectedClass .. '">' .. storage.id .. '</th><th class="' .. selectedClass .. '">' .. storage.tableName .. '<br><small>' .. storage.type .. ' ' .. storage.size .. '</small></th><th class="' .. selectedClass .. '">' .. item_name .. '</th><th class="' .. selectedClass .. '">' .. format_number(utils.round(storage.quantity*100)/100) .. '</th><th class="' .. selectedClass .. '">' .. storage.percent .. '%<br><div style="border:1px solid black;position:relative;height:5px;"><div style="position:absolute;left:0;top:0;width:' .. gaugePercent .. '%;background-color:rgb(' .. r .. ',' .. g ..',' .. b .. ');height:5px;"></div></div></th></tr>' 736 + count = count + 1 726 737 end 727 - count = count + 1 738 + html_table = html_table .. '</table><table style="width:100%"><tr><th>&#x2190; &nbsp;&nbsp; Arrow Left</th><th> Page ' .. page .. '/' .. totalPage .. ' (from ' .. firstStorage .. ' to ' .. lastStorage .. ' on ' .. #selectedStorages .. ')</th><th>Arrow Right &nbsp;&nbsp; &#x2192;</th></tr></table><div style="text-align:center;border-bottom:1px solid white;">&#x2193; &nbsp;&nbsp; Arrow Down</div></div>' 739 + maxPage = totalPage 740 + maxOnPage = lastStorage-firstStorage+1 728 741 end 729 - html_table = html_table .. '</table><table style="width:100%"><tr><th>&#x2190; &nbsp;&nbsp; Arrow Left</th><th> Page ' .. page .. '/' .. totalPage .. ' (from ' .. firstStorage .. ' to ' .. lastStorage .. ' on ' .. #selectedStorages .. ')</th><th>Arrow Right &nbsp;&nbsp; &#x2192;</th></tr></table><div style="text-align:center;border-bottom:1px solid white;">&#x2193; &nbsp;&nbsp; Arrow Down</div></div>' 730 - maxPage = totalPage 731 - maxOnPage = lastStorage-firstStorage+1 732 742 end 743 + html_storage = html .. html_table 744 + selected_storage = selectedStorage 733 745 end 734 - html_storage = html .. html_table 735 - selected_storage = selectedStorage 736 746 end 737 747 hud.coroutines.renderFilterStatus = function() 738 748 html_filters = "<style>" ··· 747 757 html_filters = html_filters .. [[<hr class="hr-light"><table style="width:100%;"><tr><td style="padding-left:5px;">&#x2190; &nbsp;&nbsp; Ctrl+Arrow Left</td><td style="text-align:right;padding-right:5px;">Ctrl+Arrow Right &nbsp;&nbsp; &#x2192;</td></tr></table></div>]] 748 758 end 749 759 hud.coroutines.renderFilterType = function() 750 - maxFilterType = #elementsTypes 751 - if displayMode == 0 then 752 - maxFilterType = #elementsTypes + 1 753 - elseif displayMode == 2 then 754 - maxFilterType = 0 755 - end 756 - html_filters_types = "<style>" 757 - html_filters_types = html_filters_types .. ".bgt" .. (statusFilterType+1) .. "{border: 2px solid #28a745 !important;}" 758 - html_filters_types = html_filters_types .. "</style>" 759 - html_filters_types = html_filters_types .. '<div class="hud_container hud_machine_types_container" style="text-align:center;"><div>&#x2191; &nbsp;&nbsp; Ctrl+Arrow Up</div><hr class="hr-light">' 760 - if displayMode == 0 or displayMode == 1 then 761 - html_filters_types = html_filters_types .. '<div class="bgt1" style="margin:5px;">ALL Industries (' .. #industries_id .. ')</div>' 762 - for i,v in ipairs(elementsTypes) do 763 - html_filters_types = html_filters_types .. '<div class="bgt' .. (i+1) .. '" style="margin:5px;">' .. v .. ' (' .. machines_count[v] .. ')</div>' 760 + if displayMode < #displayModes-1 then 761 + maxFilterType = #elementsTypes 762 + if displayMode == 0 and enableStorageMonitoring then 763 + maxFilterType = #elementsTypes + 1 764 + elseif displayMode == 2 then 765 + maxFilterType = 0 764 766 end 765 - end 766 - if displayMode == 0 or displayMode == 2 then 767 - local bgtclass = 'bgt' .. (#elementsTypes + 2) 768 - if displayMode == 2 then 769 - bgtclass = 'bgt1' 767 + html_filters_types = "<style>.bgt" .. (statusFilterType+1) .. "{border: 2px solid #28a745 !important;}</style>" 768 + html_filters_types = html_filters_types .. '<div class="hud_container hud_machine_types_container" style="text-align:center;"><div>&#x2191; &nbsp;&nbsp; Ctrl+Arrow Up</div><hr class="hr-light">' 769 + if displayMode == 0 or displayMode == 1 then 770 + html_filters_types = html_filters_types .. '<div class="bgt1" style="margin:5px;">ALL Industries (' .. #industries_id .. ')</div>' 771 + for i,v in ipairs(elementsTypes) do 772 + html_filters_types = html_filters_types .. '<div class="bgt' .. (i+1) .. '" style="margin:5px;">' .. v .. ' (' .. machines_count[v] .. ')</div>' 773 + end 774 + end 775 + if enableStorageMonitoring and (displayMode == 0 or displayMode == 2) then 776 + local bgtclass = 'bgt' .. (#elementsTypes + 2) 777 + if displayMode == 2 then 778 + bgtclass = 'bgt1' 779 + end 780 + html_filters_types = html_filters_types .. '<div class="' .. bgtclass .. '" style="margin:5px;">Storage (' .. #storages_id .. ')</div>' 770 781 end 771 - html_filters_types = html_filters_types .. '<div class="' .. bgtclass .. '" style="margin:5px;">Storage (' .. #storages_id .. ')</div>' 782 + html_filters_types = html_filters_types .. '<hr class="hr-light"><div>&#x2193; &nbsp;&nbsp; Ctrl+Arrow Down</div></div>' 783 + else 784 + html_filters_types = "" 772 785 end 773 - html_filters_types = html_filters_types .. '<hr class="hr-light"><div>&#x2193; &nbsp;&nbsp; Ctrl+Arrow Down</div></div>' 774 786 end 775 787 hud.coroutines.renderSelectedAR = function() 776 788 local html = ""