This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
empty789's profile picture

Computer crashes on event, help pls

Started by empty789, 20 November 2016 - 07:01 PM
empty789 #1
Posted 20 November 2016 - 08:01 PM
Hi guys,

im trying to make a BigReactors CC script, to monitor reactor and Turbines and control the Rpm and things.
Now i encountered a problem with events, i use a timer to update the Interface and now try to use other events like "char" or "mouse_click". If any other event than "timer" happens, the computer crashes and restarts itself and i can't find any mistake in this code. I looked at others, how they do it and its similar to them.

Spoiler

modem = peripheral.wrap("back")


--
-- settings
-- filename: name of the file where the settings will be saved
-- color_background: color of the background of the monitor
-- color_txt: font color
-- color_border: color of the border of the whole monitor
-- color_panel: color of the panels where the text will be
-- color_header: color of the header line of panels
-- targetSpeed: RPM that the reactor should aim for
-- rodLevel: insertionlevel of fuelrods
-- updateTime: time in Sec, how fast to update the GUI
settings = {
	filename = "settings.dat";
	color_background = colors.blue;
	color_txt = colors.white;
	color_border = colors.black;
	color_panel = colors.lightBlue;
	color_header = colors.gray;
	targetSpeed = 1820;
	rodLevel = 999;
updateTime = 2;
}


-- table of tables of (list-matrix) monitors, turbines, reactors and chests
local p = {
	mon = { };
	turb = { };
	reactor = { };
	chest = { };
}
-- gets all peripherals that the modem receives
local peripherals = modem.getNamesRemote()

-- Temp variable, to save updateTime
--local oldUpdateTime = 0
local statusCalibrateRpm


--
-- go through all
-- monitors, BigReactors-Turbines,
-- BigReactors-Reactors, diamond-chests REVIEW COMMENT
-- and put them in the according list in the next available slot
-- @param peripherals table of peripherals available
--
for index, connection in pairs(peripherals) do
	if peripheral.getType(connection) == "monitor" then
		p.mon[#p.mon + 1] = peripheral.wrap(connection)
	elseif peripheral.getType(connection) == "BigReactors-Turbine" then
		p.turb[#p.turb + 1] = peripheral.wrap(connection)
	elseif peripheral.getType(connection) == "BigReactors-Reactor" then
		p.reactor[#p.reactor + 1] = peripheral.wrap(connection)
	elseif peripheral.getType(connection) == "diamond" then
		p.chest[#p.chest + 1] = peripheral.wrap(connection)
	else
		print(peripheral.getType(connection))
		print("Was not added!")
	end
end


--
-- print out number of
-- monitors, turbines, reactors and chests
--
print("New connections:")
print("Monitors:		" .. #p.mon)
print("Turbines:		" .. #p.turb)
print("Reactors:		" .. #p.reactor)
print("Chests:		  " .. #p.chest)
--
-- save a table under a given name
-- @param table table of parameters
-- @param name name of the file
--
function save(table, name)
	local file = fs.open(name, "w")
	file.write(textutils.serialize(table))
	file.close()
end


--
-- load a table with a given name
-- @param name name of the file that will be loaded
--
function load(name)
	local file = fs.open(name, "r")
	local data = file.readAll()
	file.close()
	return textutils.unserialize(data)
end
------------------------------------------------------------------------------------------------------------
----------------------------Style functions-----------------------------------------------------------------
------------------------------------------------------------------------------------------------------------

-- max x, y coordinate of Mon[1]
monX, monY = p.mon[1].getSize()


--
-- clear monitor and reset cursorPosition
--
function clear()
	p.mon[1].setBackgroundColor(settings.color_background)
	p.mon[1].clear()
	p.mon[1].setCursorPos(1, 1)
end


--
-- get Text onto the screen
-- @param x x-Position
-- @param y y-Position
-- @param text text that will be put onto the screen
-- @param color_txt font color
-- @param color_background background color
--
function drawText(x, y, text, color_txt, color_background)
	p.mon[1].setBackgroundColor(color_background)
	p.mon[1].setTextColor(color_txt)
	p.mon[1].setCursorPos(x, y)
	p.mon[1].write(text)
end


--
-- draws a line out of char or spaces if !char (rectangle)
-- @param x x-Position
-- @param y y-Position
-- @param length length in x-axis
-- @param size size of the line (y-axis)
-- @param color_bar background color
-- @param char line made of specific char
--
function drawLine(x, y, length, size, color_bar, char)
	for yPos = y, y + size - 1 do
		p.mon[1].setBackgroundColor(color_bar)
		p.mon[1].setCursorPos(x, yPos)
		if char then
			p.mon[1].write(string.rep(char, length))
		else
			p.mon[1].write(string.rep(" ", length))
		end
	end
end


--
-- draws a progressbar
-- @param x x-Position
-- @param y y-Position
-- @param name
-- @param length length in x-axis
-- @param size size in y-axis
-- @param minVal min Value
-- @param maxVal max Value
-- @param color_bar color of the actual bar
-- @param color_background background color
--
function drawProg(x, y, name, length, size, minVal, maxVal, color_bar, color_background)
	drawLine(x, y, length, size, color_background)
	local barSize = math.floor((minVal / maxVal) * length)
	drawLine(x, y, barSize, size, color_bar)
	local text = name .. " " .. math.floor((minVal / maxVal) * 100) .. "%"
	local backgroundcolor = color_bar
	local x_Position, y_Position
	if barSize > monX / 2 + #text / 2 then
		-- drawText(monX / 2 - #text / 2 + 2, y + size / 2, text, settings.color_txt, color_bar)
		x_Position = monX / 2 - #text / 2 + 2
		y_Position = y + size / 2
	elseif barSize > #text then
		-- drawText((x + barSize) - #text, y + size / 2, text, settings.color_txt, color_bar)
		x_Position =(x + barSize) - #text
		y_Position = y + size / 2
	else
		-- drawText(monX / 2 - #text / 2 + 2, y + size / 2, text, settings.color_txt, color_background)
		backgroundcolor = color_background
		x_Position = monX / 2 - #text / 2 + 2
		y_Position = y + size / 2
	end
	drawText(x_Position, y_Position, text, settings.color_txt, backgroundcolor)
end


--
-- draws text in the center (y-axis)
-- @param y y-Position
-- @param text text that will be centered
-- @param color_txt font color
-- @param color_background background color
--
function centerText(y, text, color_txt, color_background)
	drawText(monX / 2 - #text / 2 + 2, y, text, color_txt, color_background)
end


--
-- draws turbine panel with information of all trubines:
-- number, Active, RPM, RF/t, Engaged
-- @param x x-Position
-- @param y y-Position
--
function displayTurbine_bottom(x, y)
	local turbActive, coilsEngaged, font_color
	for i = 1, #p.turb do
		drawText(x, y + i, "#" .. i, settings.color_txt, settings.color_panel)
		if (p.turb[i].getActive()) then
			turbActive = "True"
			font_color = colors.green
		else
			turbActive = "False"
			font_color = colors.red
		end
		drawText(10 + x, y + i, turbActive, font_color, settings.color_panel)
		drawText(18 + x, y + i, tostring(math.floor(p.turb[i].getRotorSpeed())), settings.color_txt, settings.color_panel)
		drawText(24 + x, y + i, tostring(math.floor(p.turb[i].getEnergyProducedLastTick())), settings.color_txt, settings.color_panel)
		if (p.turb[i].getInductorEngaged()) then
			coilsEngaged = "True"
			font_color = colors.green
		else
			coilsEngaged = "False"
			font_color = colors.red
		end
		drawText(31 + x, y + i, coilsEngaged, font_color, settings.color_panel)

	end
end

--
-- draw routine for displayTurbine
--
function displayTurbine(x, y)
	drawPanel(x - 1, x + 38, y - 1, y + 1 + #p.turb, settings.color_panel)
	drawText(x, y, "Turbine", settings.color_header, settings.color_panel)
	drawText(x + 10, y, "Active", settings.color_header, settings.color_panel)
	drawText(x + 18, y, "RPM", settings.color_header, settings.color_panel)
	drawText(x + 24, y, "RF/t ", settings.color_header, settings.color_panel)
	drawText(x + 31, y, "Engaged", settings.color_header, settings.color_panel)
if (#p.turb ~= 0) then
  displayTurbine_bottom(x,y)
end
end


--
-- draws Reactoroverview-panel which displays overall information:
-- Active, Heat, Fuel, Cost, Steam, React, #Rods REVIEW, Rodlvl
-- @param x x-Position
-- @param y y-Position
--
function displayReactor(x, y)
	drawPanel(x - 1, x + 18, y - 1, y + 11, settings.color_panel)

	drawText(x, y, "Reactoroverview", settings.color_header, settings.color_panel)
if (#p.reactor ~= 0) then
  displayReactor_bottom(x, y)
end
end
--
-- helper function for displayReactor
-- displays everything below "Heat:"-line
--
function displayReactor_bottom(x, y)
	drawText(x + 1, y + 3, "Fuel: ", settings.color_txt, settings.color_panel)
	local fuelMax = p.reactor[1].getFuelAmountMax()
	local fuelAmount = p.reactor[1].getFuelAmount()
	local fuelPerc =(fuelAmount / fuelMax) * 100
local reactorActive, reactorheat, font_color
	drawText(x + 1, y + 1, "Active: ", settings.color_txt, settings.color_panel)
	if (p.reactor[1].getActive()) then
		reactorActive = "True"
		font_color = colors.green
	else
		reactorActive = "False"
		font_color = colors.red
	end
	drawText(x + 9, y + 1, reactorActive, font_color, settings.color_panel)
	drawText(x + 1, y + 2, "Heat: ", settings.color_txt, settings.color_panel)
	if (p.reactor[1].getFuelTemperature() > 2000) then
		font_color = colors.red
	elseif (p.reactor[1].getFuelTemperature() > 1000) then
		font_color = colors.purple
	else
		font_color = colors.white
	end
	drawText(x + 9, y + 2, tostring(math.floor(p.reactor[1].getFuelTemperature())) .. " C", font_color, settings.color_panel)
	drawText(x + 9, y + 3, round(fuelPerc, 1) .. " %", settings.color_txt, settings.color_panel)
	drawText(x + 1, y + 4, "Cost: ", settings.color_txt, settings.color_panel)
	temp = round(p.reactor[1].getFuelConsumedLastTick(), 2)
	drawText(x + 9, y + 4, temp .. " mb/t", settings.color_txt, settings.color_panel)
	drawText(x + 1, y + 5, "Steam: ", settings.color_txt, settings.color_panel)
	drawText(x + 9, y + 5, p.reactor[1].getHotFluidProducedLastTick() .. " mb/t", settings.color_txt, settings.color_panel)
	drawText(x + 1, y + 6, "React: ", settings.color_txt, settings.color_panel)
	drawText(x + 9, y + 6, tostring(math.floor(p.reactor[1].getFuelReactivity())) .. " %", settings.color_txt, settings.color_panel)
	drawText(x + 1, y + 7, "Rods#: ", settings.color_txt, settings.color_panel)
	drawText(x + 9, y + 7, tostring(math.floor(p.reactor[1].getNumberOfControlRods())), settings.color_txt, settings.color_panel)
	drawText(x + 1, y + 8, "Rodlvl: ", settings.color_txt, settings.color_panel)
	drawText(x + 9, y + 8, tostring(math.floor(p.reactor[1].getControlRodLevel(0))), settings.color_txt, settings.color_panel)
drawText(x , y + 9, "Estimated Runtime", settings.color_header, settings.color_panel)
drawText(x + 1, y + 10, calculateFuelTime(), settings.color_txt, settings.color_panel)
end

--
-- draw a panel
-- @param xStart Starting point x-Position
-- @param xEnd End point x-Position
-- @param yStart Starting point y-Position
-- @param yEnd End point y-Position
-- @param color color of the panel
--
function drawPanel(xStart, xEnd, yStart, yEnd, color)
	p.mon[1].setBackgroundColor(color)
	for j = yStart, yEnd do
		for i = xStart, xEnd do
			p.mon[1].setCursorPos(i, j)
			p.mon[1].write(" ")
		end
	end
end

function showInfo()
term.clear()
term.setCursorPos(1,1)
print("--Peripherals connected--")
print("Monitors:		" .. #p.mon)
print("Turbines:		" .. #p.turb)
print("Reactors:		" .. #p.reactor)
print("Chests:		  " .. #p.chest)
print("-------------------------")
print("press R for reboot")
end

------------------------------------------------------------------------------------------------------------
----------------------------Functionality-------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------

--
-- rounds the given number
-- @param number given number to be rounded
-- @param decimal rounding accuracy
--
function round(number, decimal)
	local multiplier = 10 ^(decimal or 0)
	return math.floor(number * multiplier + 0.5) / multiplier
end


--
-- test if a file exists
-- @param name name of the file
--
function file_exists(name)
	local file = io.open(name, "r")
	if file ~= nil then io.close(file) return true else return false end
end


--
-- calibrates RPM of all turbines by disengaging if speed is to low
-- and engaging if speed is less or equal than targeted speed
--
function calibrateRpm()
if oldUpdateTime == 0 then
  oldUpdateTime = settings.updateTime -- save the Actual update time
end
	for i = 1, #p.turb do
		if (p.turb[i].getRotorSpeed() < settings.targetSpeed - 10) then
			if (p.turb[i].getInductorEngaged() == true) then
				p.turb[i].setInductorEngaged(false)
  statusCalibrateRpm = true
			end
		elseif(p.turb[i].getRotorSpeed() >= settings.targetSpeed) then
			p.turb[i].setInductorEngaged(true)
   --settings.updateTime = oldUpdateTime -- reset update time to actual value
   --oldUpdateTime = 0 -- reset value
	statusCalibrateRpm = false
		end
	end
end


--
-- calculates the remaining time the reactor could run
-- based on the remaining fuel
--
function calculateFuelTime()
	if (#p.reactor ~= 0) then
		local cost = p.reactor[1].getFuelConsumedLastTick()
		local fuelAmount = 0
		local runtimeHrs, runtimeMin, runtimeSec, time
		for i = 1, p.chest[1].getInventorySize() do
			if (p.chest[1].getStackInSlot(i)) ~= nil then
				item_name = p.chest[1].getStackInSlot(i)
				if (item_name.display_name == "Yellorium Ingot" or item_name.display_name == "Blutonium Ingot") then
					fuelAmount = fuelAmount + item_name.qty
				end
			end
		end
		fuelAmount =(fuelAmount * 1000) + p.reactor[1].getFuelAmount()
		--print("Fuelamount: " .. fuelAmount .. " mb")
		--print("Cost:	   " .. cost .. " mb/t")
		runtimeSec = fuelAmount / cost / 20
		runtimeMin = runtimeSec / 60
		runtimeHrs = runtimeMin / 60
		-- todo: return String mit Stunden, Minuten, Sekunden
		time = tostring(math.floor(runtimeHrs)) .. "h" .. tostring(math.floor(runtimeMin % 60)) .. "m" .. tostring(math.floor(runtimeSec % 60)).."s"
  return time
	else
		return "no Reactor"
	end
end


--
-- sets the most efficient Rodlevel inside of the reactor
-- could be inaccurate if the fuel level is below 100%
--
function setRodLevelForSteam()
	if (#p.turb ~= 0) and (#p.reactor ~= 0) then
		if (settings.rodLevel == 999) then
   centerText(monY/2, "Setting up the fuelrods, please wait...", settings.color_txt, settings.color_background)
			while (p.reactor[1].getFuelTemperature() > 100) do
				p.reactor[1].setAllControlRodLevels(100)
				p.reactor[1].setActive(false)
				print("Temperatur is to high to messure. Please Wait till " .. math.floor(p.reactor[1].getFuelTemperature()) .. "<100 C")
				sleep(2)
			end
			--
			print("Setting up the Rodlevel for the amount of Turbines connected...")
			sleep(1)
			local turbs = #p.turb
			local steamNeeded = turbs * 2000
			local actualSteam = 0
			settings.rodLevel = 100
			--
			if (p.reactor[1].getFuelAmount() <(p.reactor[1].getFuelAmountMax() -1000)) then
				term.setTextColor(colors.red)
				print("Fuel Level below 100%, calculation of Rodlevel may be wrong")
				term.setTextColor(colors.white)
				sleep(0.5)
			end
			--
			p.reactor[1].setActive(true)
			while (steamNeeded > actualSteam) do
				print("Steam needed: " .. steamNeeded .. " Output: " .. p.reactor[1].getHotFluidProducedLastTick() .. " Rodlevel: " .. p.reactor[1].getControlRodLevel(0))
				settings.rodLevel = settings.rodLevel - 1
				p.reactor[1].setAllControlRodLevels(settings.rodLevel)
				sleep(2)
				actualSteam = p.reactor[1].getHotFluidProducedLastTick()
			end
			--
			print("Perfect Rodlevel: " .. settings.rodLevel)
			save(settings, settings.filename)
			print("Settings saved")
		end
print("Setting Rodlevels")
p.reactor[1].setAllControlRodLevels(settings.rodLevel)
	else
		print("GO CRAFT A FUCKING REACTOR YOU LAZY BASTERD, or a Turbine")
	end
end


--
-- updates the GUI
--
function update()
	clear()
	displayTurbine(3, 3)
	displayReactor(60, 3)
	calibrateRpm()
showInfo()

end


--
-- initializes the reactor setup
--
function init()
	if (file_exists(settings.filename)) then
		settings = load(settings.filename)
	end
	clear()

	setRodLevelForSteam()
	sleep(0.5)
	print("Activating Turbines")
	sleep(0.5)
	for i = 1, #p.turb do
		p.turb[i].setActive(true)
	end
	print("Setup Ready and running!")
end

init()

------------------------------------------------------------------------------------------------------------
----------------------------Main loop-----------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------
while true do
update()
	save(settings, settings.filename)
if(statusCalibrateRpm == false) then
  tID = os.startTimer(settings.updateTime) --start updateTimer
else
  tID = os.startTimer(0.5) --start calibrate timer
end
local evt, p1, p2, p3 = os.pullEvent()
repeat

if (evt == "char") then
print("event!")
if (p1 == "r") then
  print("REBOOT")
  os.reboot()
end
end


until (evt == "timer" and p1 == tID)

	--sleep(settings.updateTime)
end

This is the whole script, and this is the important part for my problem i think, the Main loop:

Spoiler

while true do
update()
	save(settings, settings.filename)
if(statusCalibrateRpm == false) then
  tID = os.startTimer(settings.updateTime) --start updateTimer
else
  tID = os.startTimer(0.5) --start calibrate timer
end
local evt, p1, p2, p3 = os.pullEvent()
repeat

if (evt == "char") then
print("event!")
if (p1 == "r") then
  print("REBOOT")
  os.reboot()
end
end


until (evt == "timer" and p1 == tID)

	--sleep(settings.updateTime)
end

I tried to google this problem, but couldnt find any solution. Perhaps im to dump to "name" this problem, but what ever.
If anyone sees the problem pls tell me.

Thanks in advance!
Edited on 20 November 2016 - 10:12 PM
Bomb Bloke #2
Posted 20 November 2016 - 11:24 PM
When a computer/turtle starts running code, ComputerCraft starts a ten second timer. If that code doesn't yield before that timer ends then ComputerCraft will either crash the script or the whole computer (depending on the nature of the functions your script is calling). After each yield, any other systems waiting to run code may do so, then after they've all yielded, processing continues with a new time limit.

The reason why is that running your code chews up valuable server processing power, and so it shouldn't be able to monopolise it. In fact, only ONE CC device can run code at a time: While one is doing something, none of the others can do anything until it yields.

Whether or not it takes more than ten seconds for your code to execute has a little to do with the power of the Minecraft server it's running on, and a lot to do with how often you allow your code to yield. Pulling events (eg getting typed characters or checking timers) triggers a yield, and many commands (eg turtle movements, sleeping, or getting text input from the user) have to pull events to work anyway. Basically, anything that triggers a pause is pulling an event in order to do it, and in order to pull an event the code yields.

In your code, you pull one event, and then start a "repeat" loop that examines that one single event over and over again - without ever attempting to pull another. Move your "local evt, p1, p2, p3 = os.pullEvent()" into that loop.
empty789 #3
Posted 21 November 2016 - 07:53 AM
Yeah i found my mistake… I was sitting on that problem for 3 hours and couldnt find the solution. After i posted here, a friend of mine with nearly no coding experience asked the right question, why i pull the event outside the repeat and how this is working… I feel so dumb :/

Thanks for your reply!
empty789 #4
Posted 22 November 2016 - 04:14 PM
i got a new problem: the Monitor size of my SP world differs from the Multiplayer server i play on, see yourself, exactly same code.
Both monitors 5x8, same size, different layout?

Singleplayer
Spoilerhttps://images.disco...WKjDiilNbPeSRxs

Multiplayer
Spoilerhttps://images.disco...XuYCWp7SrMPFs2g

Why is it like that?
KingofGamesYami #5
Posted 22 November 2016 - 10:34 PM
Looks like the text scale has been set to 0.5 somehow.
Dog #6
Posted 23 November 2016 - 12:40 AM
Probably the easiest fix would be to set their text scale to the size you desire when you wrap the monitors…

p.mon[#p.mon + 1] = peripheral.wrap(connection) --# this is your code
p.mon[#p.mon].setTextScale(1)                              --# set the text scale to the desired value (0.5 through 5)