CC: Tweaked

CC: Tweaked

42M Downloads

Commit 47ad7a35 causes turtle.forward() to hang

roobscoob opened this issue ยท 19 comments

commented

Minecraft Version

1.16.x

Version

Bleeding edge commit 47ad7a3

Details

This is an extension of this issue that I'm moving here because this was tested in forge and the commit was here.

No more error is sent, rather the call to turtle.forward never resolves, and the turtle does not move forward

commented

I'm afraid I cannot reproduce this. I'm fairly sure this should never happen under normal circumstances - are you running any other code on your computer, especially which uses coroutines/the parallel API?

I guess might be worth trying this code and seeing what events are being queued:

parallel.waitForAny(function() while true do print(coroutine.yield()) end end, turtle.forward)
commented

If you have a discord, i'd be happy to send you example code that breaks over dm.

That said, running the logger function above shows a turtle response is getting sent (turtle_response 7 true) but the lua code does not progress

commented

You should be able to upload your code as an attachment to your comment.

Hrm, if the event is coming through, that's even stranger. I assume no other turtle functions work - turtle.turnLeft, etc...?

commented

While i agree that there are some things users will just have to accept, the async structure of javascript is pretty core to how it works, and because it is possible to fix, i think that would be better. For example, some of my calls are async:

const response = await fetch("https://postman-echo.com/get?foo1=bar1&foo2=bar2", { headers: { "test": "test" } });
JSON.parse(response.body);
commented

A workaround that I've just discovered by playing around in their playground system, remove the await keyword on your ts file. I've not tested the resulting output, but what it spits out (of my test code) produces what I would write if I was writing the equivalent Lua code without the transpiler.

Edit: Nope, it does turtle:forward() which will break.

Edit2: adding declare const turtle: { forward(this: void): void } to the top of the file fixes that.

while in the example code, removing the async keyword on the function fixes it, in my real code the async function is nessacery. I'll be waiting for an upstream fix in tstl

commented

So what is your real code doing? It's much harder to help when you don't share code.

commented

I think part of the issue is that CC uses events to handle async stuff, so I kinda wonder if you might be better off pretending that async doesn't exist. It's quite a different way of thinking compared to how JavaScript (and I assume TypeScript) works and given that your users are writing code that will be transpiled they will have to accept that some things can't be hidden by the transpiler.

commented

Well my real code here is a set of Typescript wrapper APIs for interacting with the lua code. I can't verify that my API call will be made in a non-async context, and enforcing it would lead to a LOT of user friction. While there are workarounds, (for example wrapping the call to turtle.forward in an async function we don't await the return of) they aren't great, and an upstream fix is a more proper solution

commented

Actually my initial issue was a bit off, the turtle does move, though the call does not return. (I was out of fuel when testing, and didn't notice the error, because it wasn't fired)

And yea, other turtle commands (tried turtle.turnLeft)

I have found the minimum code required to reproduce this issue. Well, as minimum as I can get it.

This was initially discovered when writing code through TypescriptToLua.

Attached is turtleBroken.zip containing:

  • lualib_bundle.lua - the bundled library that tstl injects.
  • source.lua - the transpiled version of source.ts
  • source.ts - the original typescript code
    and a dev environment for working with tstl

both source.lua and lualib_bundle.lua are needed on the turtle.

The expected behavior is that A is printed, the turtle moves, then B is printed.
The actual behavior is that A is printed, the turtle moves, and the script exits.

commented

Just had a go at testing this (modifying the zipped source.lua instead of writing a ts file and transpiling it). I wrote a simple loop that prints events and got nil several times before the program terminated. I believe that TypescriptToLua is not resuming coroutines in the way that CraftOS/CC expects.

My modified file:

require("lualib_bundle");
function broken(self)
    return __TS__AsyncAwaiter(function()
        while true do
            print(os.pullEvent())
        end
    end)
end

broken()

I should note that I am not using the same version of CC as roobscoob is. I have also reproduced the bug with their code.

Edit: reading through lualib_bundle for all the mentions of the coroutine API, whoever wrote this didn't seem to expect Lua to pass multiple values across coroutines, which seems a bit odd as JS can do that (and I assume that TS can too). But they do test for unpack and fallback on table.unpack.

@roobscob does TypescriptToLua have a GitHub repo? I might be bored enough to send them a PR.

commented

A workaround that I've just discovered by playing around in their playground system, remove the await keyword on your ts file. I've not tested the resulting output, but what it spits out (of my test code) produces what I would write if I was writing the equivalent Lua code without the transpiler.

Edit: Nope, it does turtle:forward() which will break.

Edit2: adding declare const turtle: { forward(this: void): void } to the top of the file fixes that.

commented

I did just think of awaiting the turtle.forward, but that didn't help. Looking through the code that the playground keeps generating for me, TSTL just uses coroutines in a way that is fundamentally different and incompatible with CC.

commented

I mean, aside from passing in multiple arguments (assuming that gets fixed), is there anything else that could trip it up?

commented

I've gotten simple ts-only code to transpile fine even with async stuff

commented

Yeah, I think the best advice I can give you is to avoid putting CC functions into async functions, while many CC functions might work just fine in async, it seems that any functions that yield will have issues. So you can't use turtle functions and peripheral functions and maybe a few more in an async function.

commented

i mean that's got to be a solvable problem, i can monkey patch lualib_bundle if needed

commented

I mean, aside from passing in multiple arguments (assuming that gets fixed), is there anything else that could trip it up?

TSTL also doesn't yield, so even if it didn't mangle the event by the time user code get's it, the fact that TSTL never pulls an event is an issue.

Honestly, I'm starting to think that getting them to support CC will be more effort than it's worth for them.

i can monkey patch lualib_bundle if needed

That's probably your best bet.

commented

Well i have a loader lua wrapper that loads the user code. it runs parallel.waitforall with the user code and a lua script that pulls events and passes them into tsland