Skip to content

SubLevelAPI functions are not on the main thread #6

Description

@lucaargolo

Every once in a while my ships were being randomly teleported to 0 0 0, turns out it was being caused by CC-Sable. The problem is that your Lua Functions are being executed in the CC Thread instead of the Server Thread, and that does some weird things to Sable.

You can reproduce this error by having a computer in a sub level doing the following:

while true do
    print(sublevel.getLogicalPose())
    sleep(0.05)
end

And then just fly around your world.

It might take a while, but a good way I found it to force it to happen is just setting the /tick rate to something big like 10000 and then throwing the ship around using the creative physics wand thingy.

You can fix it by setting the @LuaFunction annotations to @LuaFunction(mainThread = true)
Tested it on a local build and it seems to work well

Activity

  1. TechTastic commented on May 4, 2026

    @TechTastic
    Owner

    Potentially fixed in 4efdef9

  2. self-assigned this
    on May 4, 2026
  3. Felipe-Caldeira commented on May 5, 2026

    @Felipe-Caldeira

    Oh dear, now every individual function call takes a whole game tick 💀
    But I was also experiencing this teleportation issue. Hopefully we can have a solution that keeps the function calls instantaneous.

    Image
  4. Felipe-Caldeira commented on May 5, 2026

    @Felipe-Caldeira

    While testing with version 1.2.2, I observed something interesting: While I had another computer running a bunch of commands, my ship remained stable. When I stopped the command loop, suddenly my ship began losing control and glitching/teleporting to 0, 0, 0.

    Not exactly sure what about running extra work on another computer would make the ship stable and the glitches disappear. But I thought I'd bring this up in case it helps in any way.

    https://youtu.be/7qnNlvJDU88

  5. TechTastic commented on May 5, 2026

    @TechTastic
    Owner

    I think this is less a CC: Sable bug than a Sable bug that CC: Sable exposed

  6. TechTastic commented on May 5, 2026

    @TechTastic
    Owner

    While testing with version 1.2.2, I observed something interesting: While I had another computer running a bunch of commands, my ship remained stable. When I stopped the command loop, suddenly my ship began losing control and glitching/teleporting to 0, 0, 0.

    Not exactly sure what about running extra work on another computer would make the ship stable and the glitches disappear. But I thought I'd bring this up in case it helps in any way.

    https://youtu.be/7qnNlvJDU88

    Try this test without CC: Sable

  7. Felipe-Caldeira commented on May 5, 2026

    @Felipe-Caldeira

    While testing with version 1.2.2, I observed something interesting: While I had another computer running a bunch of commands, my ship remained stable. When I stopped the command loop, suddenly my ship began losing control and glitching/teleporting to 0, 0, 0.
    Not exactly sure what about running extra work on another computer would make the ship stable and the glitches disappear. But I thought I'd bring this up in case it helps in any way.
    https://youtu.be/7qnNlvJDU88

    Try this test without CC: Sable

    Can't quite test it without CC: Sable since the quadrotor is being stabilized with it lol. On every computer/game tick I call a ton of the 'sublevel' API methods to get the ship's state for the LQR controller.

  8. TechTastic commented on May 5, 2026

    @TechTastic
    Owner

    Thats fair, can I have a world download ZIP that I can test in-dev and can send along to another dev who is also looking into the issue?

  9. yoyotam3 commented on May 7, 2026

    @yoyotam3

    Could you please make it so at least the getLogicalPose function returns nil instead of erroring when used while not on a sublevel? With this change it now takes 2 ticks just to get the logical pose since you need to use isInSubGrid first to avoid erroring. pcall doesnt seem to work for it for some reason.
    EDIT: nvm pcall works fine was just using it wrong

  10. Felipe-Caldeira commented on May 18, 2026

    @Felipe-Caldeira

    I believe the issue was mainly from using getVelocity, which was using the SableCompanion to reach into the physics pipeline to get the velocity, which is likely not thread-safe. All the other methods use getSublevel().* which don't seem to have this issue.

    There's already a getLinearVelocity which uses exactly this pattern. I think getVelocity is a bit different? But getLinearVelocity does what I need, so just using it instead of getVelocity eliminates the glitches without having the methods run on the main thread.

  11. sadnesstea commented on May 20, 2026

    @sadnesstea

    I’ve tried to find the cause of this bug with llm’s help. Here’s what I could find out, maybe that would be helpful:

    AI's response

    The mainThread = true fix stops the teleportation bug, but it introduces a 1 server tick delay for every single API call, forcing the Lua script to wait for the next server tick.

    The core problem is most likely that Rapier runs in native memory (Rust) and its JNI bindings aren't thread-safe. When the main server thread updates physics via pipeline.physicsTick(), it actively mutates coordinates in memory. If a Lua computer tries to read getPose() from a background thread at the exact same millisecond, it triggers a race condition and memory tearing. This perfectly explains why Rapier suddenly returns corrupted data, resulting in those weird (0,0,0) position resets.

    A better approach to guarantee thread safety without sacrificing performance would be state snapshotting.
    Right after the physics pipeline finishes stepping on the main thread, we can extract the raw position and velocity data from Rapier and copy it into a lightweight, thread-safe Java DTO (like a volatile reference or using a fast concurrent lock). Then, we can remove mainThread = true from the @LuaFunction annotations, allowing them to run off-thread again. Instead of hitting the native Rapier JNI directly, these functions will read the data from this cached Java object.

  12. yoyotam3 commented on May 20, 2026

    @yoyotam3

    asking an AI is not generally helpful. but its response is generally how threading issues like this are solved yes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workinghelp wantedExtra attention is needed

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions