cc-tweaked / CC-Tweaked

Just another ComputerCraft fork
https://tweaked.cc
898 stars 208 forks source link

Turtle movement yields when lots of peripherals attach/detach at once #1155

Open Kan18 opened 1 year ago

Kan18 commented 1 year ago

Minecraft Version

1.19.2

Version

1.100.9

Details

Basically: when while true do print(os.pullEvent()) end is running in a tab in a turtle's multishell, and the turtle disconnects or connects to a wired modem network with a lot of peripherals (I tested with 512 for this) when moving with turtle.forward()/turtle.back(), the turtle movement call sometimes yields until terminated. I think this might be because the peripheral attach and detach events are overflowing the event queue, but I'm not sure.

Video Same video on different link

Logs attached although it doesn't look like anything relevant to this is showing in them: logs.zip

Lupus590 commented 1 year ago

I forget how big the event queue is, but overflowing it does seem to be a plausible explanation.

What kind of setup do you have that means you have turtles causally going past modems with over 500 peripherals connected to the network? Could you isolate your turtles from this network, perhaps using a proxy computer if they have to interact with it? The setup in the video is very artificial.

Kan18 commented 1 year ago

Networks with hundreds of chests are not unheard of on SwitchCraft (To be clear, this affects 1.12, 1.19, and probably other versions but I haven't tested with them) - my base has 275 peripherals. This was how I ran into this bug initially, but I later just moved the wired modem on top of the chest so that the turtle doesn't hit it.

What's a bit interesting about this bug is that I couldn't get it to reproduce if I didn't run the while true do print(os.pullEvent()) end in the REPL in another multishell tab. The other multishell tab wasn't even focused!

Skjolbir commented 1 year ago

Minecraft Version

1.19.2

Version

1.100.9

How are you playing on mc version 1.19.2 ? CC tweaked only supports 1.19.1 as far as I can see?

Kan18 commented 1 year ago

🤷‍♂️ It worked

Skjolbir commented 1 year ago

Can you let me know which release you're using?

SquidDev commented 1 year ago

The latest version should work on both.

zyxkad commented 2 weeks ago

Basically: when while true do print(os.pullEvent()) end is running in a tab in a turtle's multishell, and the turtle disconnects or connects to a wired modem network with a lot of peripherals (I tested with 512 for this) when moving with turtle.forward()/turtle.back(), the turtle movement call sometimes yields until terminated. I think this might be because the peripheral attach and detach events are overflowing the event queue, but I'm not sure.

This issue is quite awhile, but this is how I solved the problem:

local function discardAllEvents()
    local count = 0
    local timer = os.startTimer(0.5)
    while true do
        local event, id = os.pullEvent()
        if event == 'timer' and id == timer then
            print('discarded', count, 'events')
            return
        else
            count = count + 1
            os.cancelTimer(timer)
            timer = os.startTimer(0.5)
        end
    end
end

local function noCareAction(action, ...)
    local thr = coroutine.create(action)
    coroutine.resume(thr, ...)
    discardAllEvents()
end

local function placeModemCol()
    noCareAction(turtle.down)
    for i = 2, 13 do
        -- print('DBUG: moving back')
        noCareAction(turtle.back)
        -- print('DBUG: selecting modem')
        while not selectItem(modemId) do sleep(0.1) end
        -- print('DBUG: placing modem')
        noCareAction(turtle.place)
        -- print('DBUG: activing modem')
        waitForCooldown('useOnBlock')
        -- print('DBUG: using on block')
        automata.useOnBlock()
        discardAllEvents()
    end
    noCareAction(turtle.up)
    for i = 2, 13 do
        noCareAction(turtle.forward)
    end
end
Wojbie commented 2 weeks ago

Yea throwing all events away alongside with coroutinethat is waiting for event is a "solution" but it feels off. Heck all you probably needed to do is just throw away the coroutine.

I know this suggestion may seem extreme but how about changing how event queue works java side and instead of throwing away overflowing events, if queue reaches point its overflowed just delay overflowed events at next tick and so on so on? This would have side benefit of artificially slowing down computers that generate too many events but it would probably need to get thought thru to make sure it don't have side effects i can't think of right now.

zyxkad commented 2 weeks ago

Heck all you probably needed to do is just throw away the coroutine.

No because the actions require the previous action to be done, so I should throw away all events to ensure the action is either success or fail, from the context in my world the action should always success