[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.2.0 - update for DU 1.3.0 including support for schematic container

Thomas (Feb 12, 2023, 8:05 PM +0100) 5b96d78b d3ff9502

+48 -16
+4
Master Program/slot1/onContentUpdate.lua
··· 1 + local content = schematicContainer.getContent() 2 + for _,s in pairs(content) do 3 + schematicStorage["s" .. s.id] = s.quantity 4 + end
+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":"2"},{"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":"3"},{"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":"4"},{"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":"5"},{"code":"Storage.clear()","filter":{"args":[],"signature":"onStop()","slotKey":"-1"},"key":"0"},{"code":"version = \"v4.1.2\"\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 = {}\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 end\n if slot.getClass():lower():find(\"coreunit\") then\n core = slot\n end\n if slot.getClass():lower() == 'emitterunit' then\n emitter = slot\n end\n end\nend\n\nif core == nil then\n system.print(\"Connection to the core is missing\")\n unit.exit()\nend\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]]\nhud = {}\nhud.coroutines = {}\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 state = data.state\n local time=\"\"\n local tableTime=\"\"\n local recipe=\"\"\n local industryType = core.getElementDisplayNameById(id)\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 local schematicId = production.schematics[1] or 0\n if schematicId > 0 then\n local sch = system.getItem(schematicId)\n schematicName = \"<div><strong>Schematic:</strong> \" .. data.schematicsRemaining .. \" \" .. sch.locDisplayNameWithSize .. \"</div>\"\n tableSchematicName = sch.locDisplayNameWithSize\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 maintainOrBatchQuantity=maintainOrBatchQuantity,\n tableSchematic=tableSchematicName,\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 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>' .. 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":"1"}],"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.2.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\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 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":"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":[]}}}}
+43 -15
Master program/source/unit/onStart.lua
··· 1 - version = "v4.1.2" 1 + version = "v4.2.0" 2 2 --[[ 3 3 DU Industry HUD By Jericho 4 4 ]] ··· 63 63 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 64 --time script to get client date and time by Jericho, see full source at https://github.com/Jericho1060/DualUniverse 65 65 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 - 66 + 67 67 --databank hub library By Jericho, see full source at https://github.com/Jericho1060/DualUniverse 68 68 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 69 --time script to get client date and time by Jericho, see full source at https://github.com/Jericho1060/DualUniverse ··· 146 146 storages = {} 147 147 elementsTypes = {} 148 148 storagesTypes = {} 149 + schematicContainer = nil 150 + schematicContainerId = construct.getSchematicContainerId() 151 + schematicStorage = {} 149 152 for slot_name, slot in pairs(unit) do 150 153 if 151 154 type(slot) == "table" ··· 154 157 then 155 158 if slot.getClass():lower() == 'databankunit' then 156 159 table.insert(databanks, slot) 157 - end 158 - if slot.getClass():lower():find("coreunit") then 160 + elseif slot.getClass():lower():find("coreunit") then 159 161 core = slot 160 - end 161 - if slot.getClass():lower() == 'emitterunit' then 162 + elseif slot.getClass():lower() == 'emitterunit' then 162 163 emitter = slot 164 + elseif schematicContainerId ~= nil and slot.getClass():lower():find('container') then 165 + if slot.getId() == schematicContainerId then 166 + schematicContainer = slot 167 + end 163 168 end 164 169 end 165 170 end ··· 168 173 system.print("Connection to the core is missing") 169 174 unit.exit() 170 175 end 171 - if emitter == nil then 176 + if schematicContainerId == nil then 177 + system.print("No Schematic Container set on the Construct") 178 + end 179 + if schematicContainer == nil then 180 + system.print("Schematic Container is not linked to the board") 181 + end 182 + 183 + if emitter == nil then 172 184 enableRemoteControl = false 173 185 system.print("Connect an Emitter to enable machine control from industry") 174 186 end 175 - if #databanks == 0 then 187 + if #databanks == 0 then 176 188 enableRemoteControl = false 177 189 system.print("No Databank linked") 178 190 end ··· 233 245 --[[ 234 246 DU INDUSTRY HUD By Jericho 235 247 ]] 248 + schematicRefreshTime = 0 236 249 hud = {} 237 250 hud.coroutines = {} 251 + if schematicContainer ~= nil then 252 + hud.coroutines.getSchematics = function () 253 + schematicRefreshTime = math.ceil(schematicContainer.updateContent()) 254 + end 255 + end 238 256 hud.coroutines.init = function() 239 257 if not init then 240 258 elementsTypes = {} ··· 326 344 local production = {locDisplayNameWithSize="No recipe selected", tier=0} 327 345 local schematicName = "" 328 346 local tableSchematicName = "" 347 + local tableSchematicQuantity = "" 348 + local schematicColor = "success" 329 349 local state = data.state 330 350 local time="" 331 351 local tableTime="" 332 352 local recipe="" 333 353 local industryType = core.getElementDisplayNameById(id) 354 + local schematicId = data.requiredSchematicIds[1] or 0 355 + if schematicId > 0 then 356 + local sch = system.getItem(schematicId) 357 + local shematicQuantity = schematicStorage["s" .. schematicId] or 0 358 + if shematicQuantity < data.requiredSchematicAmount then schematicColor = "danger" end 359 + schematicName = '<div><strong>Schematic:</strong> ' .. format_number(shematicQuantity):gsub(".0", "") .. "/" .. format_number(data.requiredSchematicAmount) .. " " .. sch.locDisplayNameWithSize .. "</div>" 360 + tableSchematicName = sch.locDisplayNameWithSize 361 + tableSchematicQuantity = format_number(shematicQuantity):gsub(".0", "") .. "/" .. format_number(data.requiredSchematicAmount) 362 + end 334 363 if #data.currentProducts > 0 then 335 364 local item_id = data.currentProducts[1].id 336 365 production = system.getItem(item_id) ··· 354 383 recipe = recipe .. "</div>" 355 384 end 356 385 end 357 - end 358 - local schematicId = production.schematics[1] or 0 359 - if schematicId > 0 then 360 - local sch = system.getItem(schematicId) 361 - schematicName = "<div><strong>Schematic:</strong> " .. data.schematicsRemaining .. " " .. sch.locDisplayNameWithSize .. "</div>" 362 - tableSchematicName = sch.locDisplayNameWithSize 363 386 end 364 387 end 365 388 if data.remainingTime == 0 and data.state == 2 then ··· 396 419 remainingTime=time, 397 420 tableTime=tableTime, 398 421 schematic=schematicName, 422 + schematicColor=schematicColor, 399 423 maintainOrBatchQuantity=maintainOrBatchQuantity, 400 424 tableSchematic=tableSchematicName, 425 + tableSchematicQuantity=tableSchematicQuantity, 401 426 recipe=recipe, 402 427 stopRequested=data.stopRequested 403 428 } ··· 525 550 end 526 551 html_time = html_time .. ' - Display Mode - Alt + 8</div>' 527 552 html_time = html_time .. '<div>Reload HUD - Alt + 9</div>' 553 + if schematicContainer ~= nil then 554 + html_time = html_time .. '<hr class="hr-light"><div>Schematic Storage Refresh in ' .. schematicRefreshTime .. 's</div>' 555 + end 528 556 html_time = html_time .. '</div></div>' 529 557 end 530 558 hud.coroutines.renderIndustries = function() ··· 589 617 selectedMachine = industry 590 618 end 591 619 if count >= firstMachine and count <= lastMachine then 592 - 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>' .. 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>' 620 + 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>' 593 621 end 594 622 end 595 623 count = count + 1