local version = '1.7.0' system.print("----------------------------------------") system.print("DU-Mining-Units-Monitoring version " .. version) system.print("----------------------------------------") fontSize = 25 --export: font size for each line on the screen calibrationSecondsRedLevel = 604800 --export: The time in seconds from last calibration above the time will be displayed in red. Default to 259200 (3 days / 72h) calibrationSecondsYellowLevel = 86400 --export: The time in seconds from last calibration above the time will be displayed in yellow. Default to 86400 (1 day / 24h) calibrationGracePeriodHours = 72 --export: MyDU only: The number of hours before the calibration start to lower (server setting) calibrationCooldownHour = 24 --export: MyDU only: the number of hours between two calibration are possible (server setting) local renderScript = [[ local json = require('json') local fromScript = json.decode(getInput()) or {} pool = fromScript[1] or {} data = fromScript[2] or {} images = {} for k,p in pairs(pool) do if images[k] == nil or not isImageLoaded(images[k]) then images[k] = loadImage("resources_generated/env/" .. p[4]) end end local rx,ry = getResolution() local back=createLayer() local front=createLayer() font_size = ]] .. fontSize .. [[ local mini=loadFont('Play',12) local small=loadFont('Play',14) local smallBold=loadFont('Play-Bold',18) local itemName=loadFont('Play-Bold',font_size) local itemNameSmall=loadFont('Play-Bold',font_size*0.75) local itemNameXs=loadFont('Play-Bold',font_size*0.65) setBackgroundColor( 15/255,24/255,29/255) setDefaultStrokeColor( back,Shape_Line,0,0,0,0.5) setDefaultShadow( back,Shape_Line,6,0,0,0,0.5) setDefaultFillColor( front,Shape_BoxRounded,249/255,212/255,123/255,1) setDefaultFillColor( front,Shape_Text,0,0,0,1) setDefaultFillColor( front,Shape_Box,0.075,0.125,0.156,1) setDefaultFillColor( front,Shape_Text,0.710,0.878,0.941,1) function format_number(value) local formatted = value while true do formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1 %2') if (k==0) then break end end return formatted 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 round(a,b)if b then return utils.round(a/b)*b end;return a>=0 and math.floor(a+0.5)or math.ceil(a-0.5)end function getRGBGradient(a,b,c,d,e,f,g)a=-1*math.cos(a*math.pi)/2+0.5;local h=b-a*(b-e)local i=c-a*(c-f)local j=d-a*(d-g)return h,i,j end function renderHeader(title) local h_factor = 12 local h = 35 addLine( back,0,h+12,rx,h+12) addBox(front,0,12,rx,h) addText(front,smallBold,title,44,35) end local storageBar = createLayer() setDefaultFillColor(storageBar,Shape_Text,110/255,166/255,181/255,1) setDefaultFillColor(storageBar,Shape_Box,0.075,0.125,0.156,1) setDefaultFillColor(storageBar,Shape_Line,1,1,1,1) local storageYellow = createLayer() setDefaultFillColor(storageYellow,Shape_Text,249/255,212/255,123/255,1) setDefaultFillColor(storageYellow,Shape_Box,249/255,212/255,123/255,1) local storageDark = createLayer() setDefaultFillColor(storageDark,Shape_Text,63/255,92/255,102/255,1) setDefaultFillColor(storageDark,Shape_Box,13/255,24/255,28/255,1) local storageRed = createLayer() setDefaultFillColor(storageRed,Shape_Text,177/255,42/255,42/255,1) setDefaultFillColor(storageRed,Shape_Box,177/255,42/255,42/255,1) local storageGreen = createLayer() setDefaultFillColor(storageGreen,Shape_Text,34/255,177/255,76/255,1) setDefaultFillColor(storageGreen,Shape_Box,34/255,177/255,76/255,1) local imagesLayer = createLayer() local gaugeColorLayer = createLayer() function renderResistanceBar(ore_id, status, time, prod_rate, calibration, optimal, efficiency, cal_time, x, y, w, h, withTitle) local quantity_x_pos = font_size * 6.7 local percent_x_pos = font_size * 2 local colorLayer = storageGreen local status_text = "RUNNING" if (status == 1) or (status == 3) or (status == 4) then colorLayer = storageRed if status == 3 then status_text = 'OUTPUT FULL' elseif status == 1 then status_text = 'STOPPED' elseif status == 4 then status_text = 'NO CONTAINER' end end local calibrationRequiredTime = ((calibration-optimal)/.625)*3600 if (]] .. calibrationGracePeriodHours .. [[ * 3600) - cal_time > 0 then calibrationRequiredTime = calibrationRequiredTime + (]] .. calibrationGracePeriodHours .. [[ * 3600) - cal_time end if calibration < optimal then calibrationRequiredTime = (]] .. calibrationCooldownHour .. [[ * 3600) - cal_time end local colorRequiredCalibrationLayer = storageBar if calibrationRequiredTime < 86400 then colorRequiredCalibrationLayer = storageYellow end if calibrationRequiredTime < 43200 then colorRequiredCalibrationLayer = storageRed end if calibrationRequiredTime < 0 then calibrationRequiredTime = "REQUIRED" else calibrationRequiredTime = SecondsToClockString(calibrationRequiredTime) end pcal = calibration if pcal > optimal then pcal = optimal end if optimal > 0 then pcal = pcal / optimal else pcal = 1 end local r = 34/255 local g = 177/255 local b = 76/255 if pcal < 1 then r,g,b = getRGBGradient(pcal,177/255,42/255,42/255,249/255,212/255,123/255) end local CalibrationTimeColorLayer = storageGreen if cal_time > 86400 then CalibrationTimeColorLayer = storageYellow end if cal_time > 259200 then CalibrationTimeColorLayer = storageRed end addBox(storageBar,x,y,w,h) if withTitle then addText(storageBar, small, "ORE", x, y-5) addText(storageBar, small, "STATUS", x+w-60, y-5) setNextTextAlign(storageBar, AlignH_Center, AlignV_Bottom) addText(storageBar, small, "TIME & RATE", x+(w*0.3), y-3) setNextTextAlign(storageBar, AlignH_Center, AlignV_Bottom) addText(storageBar, small, "Calibration", x+(w*0.45), y-3) setNextTextAlign(storageBar, AlignH_Center, AlignV_Bottom) addText(storageBar, small, "CALIBRATION REQUIRED IN", x+(w*0.65), y-3) setNextTextAlign(storageBar, AlignH_Center, AlignV_Bottom) addText(storageBar, small, "EFFICIENCY", x+(w*0.80), y-3) end local ore_name = 'No Ore Selected' if pool and pool["i"..ore_id] and tonumber(ore_id) > 0 then ore_name = pool["i"..ore_id][3] end addText(storageBar, itemName, ore_name, x+15+font_size, y+h-font_size/2) setNextFillColor(gaugeColorLayer, r, g, b, 1) addBox(gaugeColorLayer,x,y+h-3,w*calibration/100,3) if tonumber(ore_id) > 0 and images["i"..ore_id] and isImageLoaded(images["i"..ore_id]) then addImage(imagesLayer, images["i"..ore_id], x+10, y+5, font_size, font_size) end setNextTextAlign(storageBar, AlignH_Center, AlignV_Middle) addText(storageBar, itemNameXs, SecondsToClockString(time), x+(w*0.3), y+(h/4)-3) setNextTextAlign(storageBar, AlignH_Center, AlignV_Middle) if (prod_rate-round(prod_rate)) == 0 then prod_rate = round(prod_rate) end addText(storageBar, itemNameXs, format_number(prod_rate) .. 'L', x+(w*0.3), y+(h/4)+(h/4)+(h/4)-3) setNextTextAlign(CalibrationTimeColorLayer, AlignH_Center, AlignV_Middle) addText(CalibrationTimeColorLayer, itemNameXs, SecondsToClockString(cal_time), x+(w*0.45), y+(h/4)-3) setNextFillColor(gaugeColorLayer, r, g, b, 1) setNextTextAlign(gaugeColorLayer, AlignH_Center, AlignV_Middle) if (calibration-round(calibration)) == 0 then calibration = round(calibration) end if (optimal-round(optimal)) == 0 then optimal = round(optimal) end addText(gaugeColorLayer, itemNameXs, format_number(calibration) .. '% / ' ..format_number(optimal) .. '%', x+(w*0.45), y+(h/4)+(h/4)+(h/4)-3) setNextTextAlign(colorRequiredCalibrationLayer, AlignH_Center, AlignV_Middle) addText(colorRequiredCalibrationLayer, itemNameSmall, calibrationRequiredTime, x+(w*0.65), y+(h/2)-3) setNextTextAlign(storageBar, AlignH_Center, AlignV_Middle) if (efficiency-round(efficiency)) == 0 then efficiency = round(efficiency) end addText(storageBar, itemNameSmall, format_number(efficiency) .. '%', x+(w*0.80), y+(h/2)-3) setNextTextAlign(colorLayer, AlignH_Right, AlignV_Middle) addText(colorLayer, itemName, status_text, x+w-10, y+(h/2)-3) end function renderPool(pool) local h_factor = 12 local h = 35 addLine( back,0,ry-h+h_factor,rx,ry-h+h_factor) addBox(front,0,ry-h-h_factor,rx,h) local nb_col = 1 for k,v in pairs(pool) do nb_col = nb_col + 1 end local n = 1 for k,v in pairs(pool) do setNextTextAlign(storageBar, AlignH_Center, AlignV_Bottom) addText(storageBar, small, v[3], (rx/nb_col)*n, ry-h-h_factor) if isImageLoaded(images[k]) then addImage(storageBar, images[k], (rx/nb_col)*n-h-h, ry-(h/2)-h_factor-(h/2)+2, h-4, h-4) end setNextTextAlign(storageBar, AlignH_Center, AlignV_Middle) addText(storageBar, itemNameSmall, format_number(round(v[1])) .. " / " .. format_number(round(v[2])), (rx/nb_col)*n+5, ry-(h/2)-h_factor) n = n + 1 end end renderHeader('MINING UNITS MONITORING v]] .. version .. [[') start_h = 75 local h = font_size + font_size / 2 for i,mu in ipairs(data) do renderResistanceBar(tostring(mu[3]), mu[1], mu[2], mu[4], mu[5], mu[6], mu[7], mu[8], 44, start_h, rx-88, h, i==1) start_h = start_h+h+15 end if fromScript[1] then renderPool(pool) end requestAnimationFrame(10) ]] screens = {} mining_units = {} for slot_name, slot in pairs(unit) do if type(slot) == "table" and type(slot.export) == "table" and slot.getClass then slot.slotname = slot_name if slot.getClass():lower() == 'screenunit' then table.insert(screens,slot) slot.setRenderScript(renderScript) elseif slot.getClass():lower() == 'miningunit' then table.insert(mining_units,slot) end end end if #screens == 0 then system.print("No screen detected") else table.sort(screens, function(a,b) return a.slotname < b.slotname end) local plural = "" if #screens > 1 then plural = "s" end system.print(#screens .. " screen" .. plural .. " connected") end if #mining_units == 0 then system.print("No mining unit detected") else table.sort(mining_units, function(a,b) return a.slotname < b.slotname end) local plural = "" if #mining_units > 1 then plural = "s" end system.print(#mining_units .. " mining unit" .. plural .. " connected") end function round(a,b)if b then return utils.round(a/b)*b end;return a>=0 and math.floor(a+0.5)or math.ceil(a-0.5)end ores = {} --Nested Coroutines by Jericho coroutinesTable = {} --all functions here will become a coroutine MyCoroutines = { function() screen_data = {} pool = {} for index, mu in ipairs(mining_units) do local mup = mu.getOrePools() for _,p in ipairs(mup) do if ores[p.id] == nil then local item_data = system.getItem(p.id) ores["i" .. p.id] = { item_data.locDisplayName, item_data.iconPath:gsub("resources_generated/env/","") } end pool["i" .. p.id] = {p.available, p.maximum, ores["i" .. p.id][1], ores["i" .. p.id][2]} end local mu_data = { mu.getState(), round(mu.getRemainingTime()), mu.getActiveOre(), round(mu.getProductionRate()*100)/100, round(mu.getCalibrationRate()*10000)/100, round(mu.getOptimalRate()*10000)/100, round(mu.getEfficiency()*10000)/100, round(mu.getLastExtractionTime()), } table.insert(screen_data, mu_data) coroutine.yield(coroutinesTable[1]) end for index, screen in pairs(screens) do local toSend = { pool, screen_data } screen.setScriptInput(json.encode(toSend)) end end } function initCoroutines() for _,f in pairs(MyCoroutines) do local co = coroutine.create(f) table.insert(coroutinesTable, co) end end initCoroutines() runCoroutines = function() for i,co in ipairs(coroutinesTable) do if coroutine.status(co) == "dead" then coroutinesTable[i] = coroutine.create(MyCoroutines[i]) end if coroutine.status(co) == "suspended" then assert(coroutine.resume(co)) end end end MainCoroutine = coroutine.create(runCoroutines)