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

Too long without yielding NYAN CAT

Started by Mindthoth, 08 January 2017 - 03:27 AM
Mindthoth #1
Posted 08 January 2017 - 04:27 AM
Alright I have this code for naan cat

pastebin.com/YJnT6Adu

but after a while it stop and get a code error:
too long without yielding….
I never seen that error but after research it says it has to do with the loop. I tried adding os.sleep(0) at a few places but it didn't do the job could anyone help me out :3
Edited on 08 January 2017 - 03:27 AM
Bomb Bloke #2
Posted 08 January 2017 - 05:08 AM
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 perform a massive number of calculations and terminal calls per frame - my first guess is that these are taking so long that the script is likely to be killed mid-render. I suggest converting the lines in your "nyans" table to something that can be spammed onto the screen directly using term.blit().
Mindthoth #3
Posted 08 January 2017 - 05:33 PM
oh damn how would I do that xD wouldn't there be an easier way like adding a os.sleep(0) somewhere?
COOLGAMETUBE #4
Posted 08 January 2017 - 06:40 PM
Excatly!

a

sleep(0)
does yield. Just add that to the loop and you should be fine.
TheOddByte #5
Posted 08 January 2017 - 08:49 PM
Excatly!

a

sleep(0)
does yield. Just add that to the loop and you should be fine.

The problem with this is that it can be really slow, and I'd suggest to use os.queueEvent and coroutine.yield instead

local function yield()
    os.queueEvent( "yield" )
    coroutine.yield( "yield" )
end

while processing do
    --# do something
    yield()
end
Bomb Bloke #6
Posted 09 January 2017 - 12:33 AM
Spamming yields would technically "work", but it'd be at no where near the frame rate you're hoping for. The underlying problem is that the code is too slow.

oh damn how would I do that xD wouldn't there be an easier way like adding a os.sleep(0) somewhere?

What do you mean, "easier"? There are plenty of code examples through the link I provided you; term.blit() is a very straight-forward function to use.

But let's say you had a line in your table like this:

"###################'''''@$-$$$$$$'***.'****.'**',,,,,,,,,,,,,,,,",

You'd translate it to the corresponding "paint" values (just use the Replace All function in your text editor of choice for each of the sixteen hues):

"5555555555555555555fffff862666666f7770f77770f77fbbbbbbbbbbbbbbbb",

Then just rig your code to output whole rows at a time:

local out = term.isColour() and term.current() or peripheral.find("monitor", function(side, ob) return ob.isColour() end)

if not out then error("No colorful output device detected, meow :(/>") end

term.redirect(out)

local sizeX, sizeY = out.getSize()
local min_row = math.floor((sizeY - 64) / 2 )
local min_col = math.floor((sizeX - 64) / 2 ) + 1
local spaces = string.rep(" ", 64)

while true do
	for frame = 1, #nyans do
		local curFrame = nyans[frame]

		for y = 1, 64 do
			term.setCursorPos(min_col, min_row + y)
			term.blit(spaces, spaces, curFrame[y])
		end

		sleep(fps)
	end
end

For bonus points, stick a Neural Interface on a cat, use a Neural Connector to place a note block into its modules panel, then do:

pastebin get Zs0JAs1b note
pastebin run cUYTGbpb get CYRmLz78 Songs
note "Songs\Nyan Cat" -r
Anavrins #7
Posted 09 January 2017 - 12:42 AM
There's already a yield at line 810 (called from 837)
The bottleneck is in the drawing, putting a sleep in the drawing routine is gonna make the animation draw even slower.
You should just go with Bomb Bloke's suggestion of using term.blit, you pretty much everything setup up for you, replace every symbols in the image data to the corresponding color according to this list.
Replace the draw function with

function draw(out)
  local sizeX,sizeY = out.getSize()
  while true do
    for frame=1,#nyans do
      for y=1,sizeY do
        out.setCursorPos(1, y)
        out.blit((" "):rep(64), ("f"):rep(64), nyans[frame][y])
      end
      pause()
    end
  end
end
Edit: Got totally ninja'd by Bombbloke
Edited on 08 January 2017 - 11:43 PM