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

[CC 1.6] 'repeat' program never clears message history

Started by Marukyu, 28 March 2014 - 11:23 AM
Marukyu #1
Posted 28 March 2014 - 12:23 PM
Version:
ComputerCraft 1.6 for Minecraft 1.6.4 (bug is within a lua program and unrelated to CC's internal code)

Description:
In the default CC 1.6 'repeat' program (non-beta version), the elseif-branch at line 73 is never executed, because the check for whether the event is a timer event is an else-branch of the rednet channel check, rather than an else-branch of the event type check. This leads to the program never clearing the message cache and eventually filling up the computer's memory (actual effects not yet tested in gameplay).
This is easily fixed by moving one of the "end" statements above the elseif-line checking for timer events and adjusting the indentation.

Here is the code segment in question: (EDIT: Updated code segment to show control flow problems better, thanks Bomb Bloke!)

if sEvent == "modem_message" then
    if nChannel == rednet.CHANNEL_REPEAT then
	    ... Packet fowarding code ...
    elseif sEvent == "timer" then
        ... *** This branch never executes! *** ...
    end
end

Steps to reproduce:
Let a computer run the 'repeat' program and transmit a large number of messages over a longer timespan.
Edited on 30 March 2014 - 10:34 AM
dan200 #2
Posted 29 March 2014 - 10:46 PM
Read the code again, they get cleared after a 30 second delay
Bomb Bloke #3
Posted 30 March 2014 - 07:07 AM
Dan, you may need to take another look at this one. Let me chop down the quoted section a bit further:

if sEvent == "modem_message" then
	if nChannel == rednet.CHANNEL_REPEAT then
		...
	elseif sEvent == "timer" then
		**** Under what circumstance will this execute?
	end
end
theoriginalbit #4
Posted 30 March 2014 - 07:29 AM
Dan, you may need to take another look at this one. Let me chop down the quoted section a bit further:
OP posted a simplified version of the logic, see full logic


pcall( function()
	local tReceivedMessages = {}
	local tReceivedMessageTimeouts = {}
	local nTransmittedMessages = 0

	while true do
		local sEvent, sModem, nChannel, nReplyChannel, tMessage = os.pullEventRaw()
		if sEvent == "modem_message" then
			--# Got a modem message, rebroadcast it if it's a rednet thing
			if nChannel == rednet.CHANNEL_REPEAT then
				if type( tMessage ) == "table" and tMessage.nMessageID and tMessage.nRecipient then
					if not tReceivedMessages[ tMessage.nMessageID ] then
						--# Ensure we only repeat a message once
						tReceivedMessages[ tMessage.nMessageID ] = true
						tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = tMessage.nMessageID

						--# Send on all other open modems, to the target and to other repeaters
						for n=1,#tModems do
							local sOtherModem = tModems[n]
							peripheral.call( sOtherModem, "transmit", rednet.CHANNEL_REPEAT, nReplyChannel, tMessage )
							peripheral.call( sOtherModem, "transmit", tMessage.nRecipient, nReplyChannel, tMessage )
						end

						--# Log the event
						nTransmittedMessages = nTransmittedMessages + 1
						local x,y = term.getCursorPos()
						term.setCursorPos( 1, y - 1 )
						term.clearLine()
						if nTransmittedMessages == 1 then
							print( nTransmittedMessages .. " message repeated." )
						else
							print( nTransmittedMessages .. " messages repeated." )
						end
					end
				end

			elseif sEvent == "timer" then
				--# Got a timer event, use it to clear the message history
				local nTimer = sModem
				local nMessage = tReceivedMessageTimeout[ nTimer ]
				if nMessage then
					tReceivedMessageTimeout[ nTimer ] = nil
					tReceivedMessages[ nMessage ] = nil
				end

			end
		end
	end
end )
Edited on 30 March 2014 - 05:30 AM
Lyqyd #5
Posted 30 March 2014 - 07:32 AM
The forum's code boxes don't always make this sort of thing easy to see, so here's the code in Sublime Text with a bit of the code folded (lines 12-34 of this function are hidden, but no indentation is changed, and Sublime Text will only fold whole blocks). For clarity, OP's point is that the event handling for timers is inside the event handling for modem messages and will therefore never be reached.

Bomb Bloke #6
Posted 30 March 2014 - 08:33 AM
On that note, I noticed this structure in the rednet API yesterday (line ~190):

    while true do
        local event, p1, p2, p3 = os.pullEvent()
        if event == "rednet_message" then
            ...
        else
            -- Got a timer event, check it's the end of our timeout
            if p1 == timer then
                break
            end
        end
    end

I sorta assumed it was intentional, given that it's an understatement to say that the odds of it messing up due to a stray "key" event are rather low (and it's a half-second timer to boot), but it may be you're inclined to change it. I dunno.
Marukyu #7
Posted 30 March 2014 - 12:39 PM
My bad, I shouldn't have left so much irrelevant code intact. It's pretty difficult to highlight relevant lines of code without formatting within code tags, and on top of that, the single quotes somehow got syntax-highlighted as comment markers.
I updated the original post with a code snippet that shows the problem better, thanks Bomb Bloke!
Wojbie #8
Posted 01 April 2014 - 04:48 PM
Just reporting that this problem still exists in 1.6.1 version of Computercraft.
dan200 #9
Posted 02 April 2014 - 01:53 PM
Thanks. I've fixed this now, it will be in the next version of the mod