Performance & @jit

-- @jit — bytecode compilation

A pragma line anywhere in the file:

-- @jit

compiles the script (and everything it requires) to JVM bytecode instead of interpreting it. Hot code gets JIT-compiled by the JVM and runs several times faster — worth it for heavy logic in tick, frame and render callbacks.

If compilation fails, the script automatically loads interpreted and chat shows @jit compilation failed, running interpreted — remove the pragma or simplify the construct the compiler choked on.

Tips

  • Read settings once. Every setting:get() crosses into Java. In a hot callback, read values into locals at the top.

    module:event("render_2d", function(render)
        local argb = color:get()      -- once
        for i = 1, #list do ... end   -- not color:get() inside the loop
    end)
    
  • Collect in tick, draw in render. world.players() / entities() build snapshot tables — too expensive per frame. Collect once per tick (20/s) and only project and draw in render_2d.

    local tracked = {}
    module:event("tick", function()
        local list = {}
        for _, e in ipairs(world.entities()) do
            if not e.is_self and e.distance < 64 then list[#list + 1] = e end
        end
        tracked = list
    end)
    module:event("render_2d", function(render)
        for i = 1, #tracked do
            local x, y, w, h = projection.entity_box(tracked[i].id)
            if x then render.outline(x, y, w, h, 0xFF4FF2A6, 0, 1) end
        end
    end)
    
  • projection.entity_box(id) instead of rebuilding tables — it projects the live entity by id with interpolation, allocating nothing on the script side.

  • Localize hot functions: local entity_box = projection.entity_box before a loop avoids repeated table lookups.

  • Don't subscribe for nothing. A frame / packet_send callback fires very often; if once per tick is enough — use tick.

  • Coroutines are expensive — don't create them in a loop.