the symptom, in your words

"Heavy work without frame hitches"

✓ verified on 26.07.08e
lane Writing gameplayposted updated

▸ SYMPTOM

  • Loading a big dataset / generating geometry freezes the editor or game for seconds.
  • Loading screen hash never updates because the main thread never yields.
  • Runtime mesh creation hitch-spikes when done in one shot.

▸ CAUSE

Engine objects (GameObject, Mesh, components) must be touched on the main thread. Parsing, Clipper/earcut math, and pure number crunching do not, but if you do them on the main thread in one frame, you hitch.

▸ FIX

Background parse / math

snippet
await GameTask.RunInThreadAsync(() =>
{
    // parsing, geometry math, no engine objects
    return computedData;
});

Main thread only for creating engine objects from the result.

Time-sliced main-thread work

snippet
for (int i = 0; i < items.Count; i++)
{
    Process(items[i]);
    Progress = (i + 1) / (float)items.Count; // Razor loading screen reads this

    if (i % 32 == 0)
        await GameTask.Yield();
}

Hash Progress (and phase flags) in BuildHash() or the loading UI stays frozen (ui-frozen-buildhash).

Runtime meshes

snippet
var mesh = new Mesh(material);
mesh.CreateVertexBuffer(/* ... */);
mesh.CreateIndexBuffer(/* ... */);

var model = Model.Builder
    .AddMesh(mesh)
    .AddCollisionMesh(/* ... */)
    .Create();

If winding is ambiguous (Clipper2 + earcut), emit triangles double-sided.

GameTask.RunInThreadAsync itself is whitelisted, but code you run inside the thread is still subject to the publish whitelist: confirm your APIs are allowed before shipping.

▸ WHY IT WORKS

RunInThreadAsync moves CPU-bound work off the frame; Yield returns control so input, rendering, and Razor can run between chunks. Keeping engine allocations on the main thread avoids cross-thread ownership bugs while still spreading cost across frames.

Verified on engine 26.07.08e: seen in a real project.
s&box moves fast; an undated fix is a liability. Spot a stale detail?
changelog
  • Verified against source: RunInThreadAsync is whitelisted; removed stale needs-verification hedge.

Want to know when new guides or fixes drop? Join the community to help build this out. Report gotchas, flag outdated fixes, or just lurk.

Join the Discord