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

1.7.10 Monitor/rednet help: Ticking memory connection

Started by John Stamos, 17 December 2016 - 07:38 PM
John Stamos #1
Posted 17 December 2016 - 08:38 PM
Hello. I'm fairly new to Lua and coding in general so please be gentle with me. I try to organize my code somewhat, but I know only basic methods and am sure my programs are hard on the eyes for even intermediate programmers. I'll do whatever I can to ease you're helping of me :)/> .

I'm playing a SSP 1.7.10 modpack, with CC 1.75 added, and have created multiple computers to read fluid tank and battery fill percentages, then send info (via wireless rednet) to machine controllers (another computer) in order to regulate their on/off.This part of it seems to be fine for the most part. I occasionally find a nil check that I didn't know about, fix it and keep moving on.

However the next thing I added was a computer with monitors to display graphs of these tanks/batteries. Again all via wireless modems. Anyways it will run fine for hours and hours, then occasionally it will begin crashing every time click the computer. Since this computer needs no input from the user, I just try to avoid touching it :P/>; I know what a great solution to a problem.

Next step I added a controller computer (Controller Display) using touchscreen monitors to over-ride the automated on/off of these machines, and display their state. Again, works fine for the majority of the time, but occasionally will begin to crash consistently when I try and access it.

Both crashes involved 'Ticking memory connection'. Both occur when either accessing the computer while it's running, or breaking the computer or ctrl-T the computer when it appears stuck. I'm guessing it involves my shotty use of rednet.receive, or my lack of breaks/nil checks.

Anyways any advice as to why these crashes are occuring, and how to better avoid them would be greatly appreciated.

Controller display:
http://pastebin.com/TfGXfL0k
The code is probably a mess, I've tried to simply it by using a lot of functions, so that it's easier to follow (which it may not be).

Pictures (older, but they at least show the concept):
http://imgur.com/a/U6OBQ

Crash report:
http://pastebin.com/Vea7h6Pb
(I have plenty of these so if more are needed let me know)

In general I have a lot of questions on how to better the code, like how to sync rednet messages properly, instead of waiting 10s for one message, 10s for another etc, which seems impractical when needing to receive many inputs. Anyways again thank you in advance for ANY help. This has been plaguing me for months, and now that I have this system controlling my nuclear reactors I can't stand to live with it being inconsistent anymore.
TYKUHN2 #2
Posted 18 December 2016 - 02:59 AM
I'm interested in what "Ticking memory connection" means… Memory leak? I'll continue debugging but if anyone has input I would appreciate it for later uses.
TYKUHN2 #3
Posted 18 December 2016 - 03:13 AM
Few adaptions:
  1. Change timeout on rednet to 0 and don't assume nil is evil. This will remove downtime between receives.
  2. If you want to retain waits between loops, keep receiving until you reach X amount of time (Try os.timer)
  3. Move initializer before the main loop. Don't do the first receiveRednet, it's not important.
  4. drawBackground2 is called once. Why isn't it part of the Initializer?
Did you provide the script of the computer crashing the game? The one you click?
John Stamos #4
Posted 18 December 2016 - 06:04 AM
Few adaptions:
  1. Change timeout on rednet to 0 and don't assume nil is evil. This will remove downtime between receives.
  2. If you want to retain waits between loops, keep receiving until you reach X amount of time (Try os.timer)
  3. Move initializer before the main loop. Don't do the first receiveRednet, it's not important.
  4. drawBackground2 is called once. Why isn't it part of the Initializer?
Did you provide the script of the computer crashing the game? The one you click?

Thanks for the reply.

1. I suppose for the display controller, it doesn't matter whether they're nil. Is changing timeout to 0 the same as not providing a timeout (runs indefinitely)?
2. Okay, I get that; what do I pass on to the rest of the code if some/all of the state of the machines are unknown? Just a bunch of 'if not message then break end'?
3. ReceiveRednet was in the intializer when the program used strictly bundled redstone instead of rednet to get the previous output, and was used to continue when the game is initially loaded. Probably not needed with Rednet, good catch.
4. This and removing the initializer function are both good suggestions, thanks. I made functions for literally everything even if it didn't make much sense just to ease testing as I was writing it. I had never used parallel, or touchscreen monitors before and something probably pretty simply took me forever to get tbh.

This was the crashlog from the computer running the program posted in the pastebin link. The one with the buttons ON/OFF/AUTO in the pictures. I noticed last time it crashed it was definitely in a rednet.receive state as it had posted to the terminal that one device had been received while the other 2 had not. Not sure why it crashes while waiting for a rednet message.

EDIT:

Don't know how this got posted, please ignore/delete this or the duplicate post which may or may not be approved.
Edited on 18 December 2016 - 05:47 AM
Bomb Bloke #5
Posted 18 December 2016 - 10:39 AM
Regarding the Minecraft crash, I'd be suspecting a conflict with another mod in your pack. FastCraft immediately comes to mind.

Is changing timeout to 0 the same as not providing a timeout (runs indefinitely)?

No, and I suspect it's not what you want to do.

Whenever something "happens" to a computer (eg a message is received, a timer expires, a user pushes a button, etc), it gets added to the end of that system's event queue. Whenever that system yields - typically done by calling os.pullEvent() - ComputerCraft will then later resume it and pass in the data of the event at the front of the queue.

When you call rednet.receive(), that function starts a timer passed on the number you pass in (if you passed one in), then starts pulling in events over and over, discarding ones it doesn't want. If it gets a rednet_message event first, it returns that, but if it gets the event from its timer first it returns nothing. If you specify a timeout of 0, rednet.receive() will try to respect that.

sleep() does pretty much the same thing, though it's only interested in the timer event. Guess what happens if you call sleep() while rednet_message events are in the queue? They all get discarded, and it becomes impossible to pull them through rednet.receive(). In your case, I can't see any point in doing anything just because a certain amount of time has passed anyway, so you may as well ditch sleep altogether.

Your system of restarting touchEvent / charEvent / receiveRednet over and over again in parallel is also a bit chaotic. Easier to start them each once and let them loop independently (that is to say, stick while loops within those functions instead of calling them from within a single while loop).

Frankly though, it'd be much simpler to just have a single event-handling loop instead of three different functions. If we additionally ditch the round-robin scheme and allow the systems to report their states in any order, then synchronisation becomes a moot issue.

Let's say we rebuild your table like this:

function initializer()--sets initial buttons colors to AUTO
    for n=1, numPeriph do
        buttonColorsTable[n]={colors.lightGray,colors.lightGray,colors.lightBlue,}
        machineMessage[periphTable[n]]={protocolName,'OFF',stateInfo,'AUTO'}
    end
end

So now instead of getting machineMessage[1], machineMessage[2], etc, we can look things up via machineMessage['Reactor 1'], machineMessage['Reactor 2'], etc. Which means that rather than relying on the other computers to transmit in a certain order, we can simply accept any protocols, use those to do an existence check in the machineMessage table, and update data so long as we find a match (following code untested, but it should hopefully at least give you the idea):

Spoiler
initializer()
drawBackground2()
broadCastRednet()
receiveRednet()

while true do
	local event,p1,p2,p3 = os.pullEvent()
	
	if event == 'monitor_touch' then
		mouseWidth = p2
		mouseHeight = p3
		term.setCursorPos(1,3)
		print(mouseWidth, ' x ', mouseHeight)
		checkClickPosition()
	
	elseif event == "char" and p1 == 'x' then
		monitor.setBackgroundColour(colors.black)
		term.setBackgroundColour(colors.black)
		term.clear()
		monitor.clear()
		break
		
	elseif event == "rednet_message" and machineMessage[p3] then  -- machineMessage[p3] counts as false if the key specified by p3 is not found
		p2[5], n = machineMessage[p3][5], machineMessage[p3][5]
		machineMessage[p3] = p2
		
		if not machineMessage[p3][2] then
			term.setCursorPos(1,16)
			print('Error receiving rednet')
			machineMessage[p3][2]='ERROR'
		elseif machineMessage[p3][2]=='ON' then
			buttonColorsTable[n][4]='ON'
		elseif machineMessage[n][2]=='OFF' then
			buttonColorsTable[n][4]='OFF'
		else
			buttonColorsTable[n][4]='ERROR'
			term.setCursorPos(1,16)
			print('Error receiving State')
		end
		
		term.setCursorPos(1,n+5)
		print('receivedRednet', n)
		
		printButtons()
	end
end

You may likewise consider rigging your printing / broadcasting functions to accept data indicating which system they should be dealing with, so that you can update one at a time.
Edited on 18 December 2016 - 09:40 AM
TYKUHN2 #6
Posted 18 December 2016 - 04:49 PM
I'd have to agree on the conflict side. From the crash log the error occurs in the network manager (Still not entirely sure what it means) which when a computer is receiving it's state isn't running, and code is executed on server side anyways. I'd start removing mods one by one to see if they are the cause.
John Stamos #7
Posted 18 December 2016 - 11:03 PM
Bomb Bloke thank you for the response. For some reason I was under the assumption that I'd need parallel in order to receive input from touch/keyboard while updating the display. Obviously not, I fixed it up similar to your example and it looks much cleaner/more flexible.

Thank you for the suggestions about fastcraft, I was literally about to post here saying fastcraft was the problem, as I was accessing all my computers without proble; then MC crashed (again when interacting with the same computer) with a near identical crashlog. I don't get why it runs perfectly for so long, and then randomly just poops.

I'll report back when I narrow down the culprit, thanks again to everyone.