Check out our latest project ✨ OpenChapter.io: free ebooks the way its meant to be 📖

Luau GDExtension

An asset by fernforestgames
The page banner background of a mountain and forest
Luau GDExtension hero image

Quick Information

0 ratings
Luau GDExtension icon image
fernforestgames
Luau GDExtension

Extension providing bindings to Luau, a scripting language derived from Lua with a focus on performance and safety.

Supported Engine Version
4.5
Version String
0.4.1
License Version
MIT
Support Level
community
Modified Date
10 hours ago
Git URL
Issue URL

Luau GDExtension

Godot 4.5+ GDExtension to integrate the Luau scripting language (a high-performance Lua derivative) into Godot Engine.

📖 Documentation: Full API reference is available in Godot's built-in help system (Godot 4.3+). Search for LuaState, Luau, or LuauScript in the editor, or browse the XML files in doc_classes/.

Why Luau?

Luau is a high-performance scripting language derived from Lua 5.1, originally created by Roblox. It offers several advantages for integration into games:

  • Performance: Up to 2x faster than standard Lua 5.1 with optimized bytecode
  • Type Checking: Optional gradual typing catches errors before runtime
  • Safety: Built-in sandboxing capabilities for running untrusted code
  • Modern Features: Native vector type, improved string library, buffer API

Quick Start

Basic Usage

# Create a Lua state and load libraries
var state := LuaState.new()
state.open_libs()

# Compile and execute Luau code
var bytecode := Luau.compile("print('Hello from Luau!')")
if state.load_bytecode(bytecode, "hello"):
    state.pcall(0, 0)  # Execute with 0 arguments, 0 return values

Math Type Integration

Godot math types work seamlessly in Luau with operator support:

-- Vector3 uses Luau's native vector type for maximum performance
local pos = Vector3(10, 20, 30)
local dir = Vector3(1, 0, 0)
local new_pos = pos + dir * 5.0  -- Inline VM operations, JIT-friendly

-- Built-in vector library functions
local length = vector.magnitude(pos)
local normalized = vector.normalize(dir)

-- Other math types (Vector2, Vector4, Color, etc.)
local color = Color(1.0, 0.5, 0.0, 1.0)
local tinted = color * 0.8

Data Exchange

# Pass Godot data to Luau
var player_data := {"name": "Player", "health": 100.0, "level": 5.0}
var state := LuaState.new()
state.open_libs()
state.push_variant(player_data)
state.set_global("player")

# Execute Luau code that modifies the data
state.do_string("""
    player.health = player.health - 10
    player.level = player.level + 1
""", "modify_player")

# Retrieve modified data back to Godot
state.get_global("player")
var updated_data := state.to_dictionary(-1)
print(updated_data)  # {"name": "Player", "health": 90.0, "level": 6.0}

Callable Bridging

# Pass Godot Callables to Luau
var state := LuaState.new()
state.open_libs()
state.push_variant(func(x): return x * 2)
state.set_global("double")

state.do_string("print(double(21))", "test_callable")  # Prints: 42

# Get Lua functions as Godot Callables
state.do_string("function add(a, b) return a + b end", "define_add")
state.get_global("add")
var lua_add := state.to_callable(-1)  # Returns a Callable
print(lua_add.call(10, 32))  # Prints: 42

Sandboxing

Sandboxing protects builtin libraries and enables runtime optimizations:

var state := LuaState.new()
state.open_libs()

# Set up any globals you want to expose
state.push_variant({"max_health": 100})
state.set_global("config")

# Load untrusted code
var untrusted_code := """
    -- This code cannot modify builtin libraries
    -- string.byte = nil  -- This would fail
    print("Player max health: " .. config.max_health)
"""
var bytecode := Luau.compile(untrusted_code)
state.load_bytecode(bytecode, "untrusted")

# Apply sandbox AFTER loading code, BEFORE executing
state.sandbox()

# Now safe to execute
state.pcall(0, 0)

For threads, use sandbox_thread() after the main state is sandboxed:

# Main state already sandboxed
var thread := state.new_thread()
state.pop(1)

# Load code into thread
thread.load_bytecode(bytecode, "thread_func")

# Sandbox the thread before execution
thread.sandbox_thread()

# Now safe to execute
thread.pcall(0, 0)

Coroutines

# Create a Lua thread (coroutine)
var state := LuaState.new()
state.open_libs()
state.do_string("""
    function counter()
        for i = 1, 3 do
            coroutine.yield(i)
        end
    end
""", "define_counter")

var thread := state.new_thread()
state.pop(1)  # Clean up the thread from main stack
thread.get_global("counter")
var status := thread.resume(0)  # Call the function with 0 arguments

# Resume the coroutine multiple times
while status == Luau.LUA_YIELD:
    print(thread.to_number(-1))  # Prints: 1, 2, 3
    thread.pop(1)
    status = thread.resume(0)

Building

Prerequisites:

Build the preset appropriate for your platform—for example:

cmake --preset windows-x86_64-debug
cmake --build --preset windows-x86_64-debug -j
cmake --preset linux-x86_64-debug
cmake --build --preset linux-x86_64-debug -j
cmake --preset macos-arm64-debug
cmake --build --preset macos-arm64-debug -j

Testing

This project has comprehensive automated tests for all Godot-Luau bridging functionality:

ctest --preset windows-x86_64-debug
ctest --preset linux-x86_64-debug
ctest --preset macos-arm64-debug

📖 For detailed testing documentation, see tests/README.md

Test coverage includes:

  • ✅ Math types (Vector2/3, Color, etc.)
  • ✅ Array/Dictionary bridging
  • ✅ Variant conversions
  • ✅ Edge cases and error handling

Supported Types

Math Types

All Godot math types with full operator support:

  • Vector2, Vector2i - 2D vectors (integer and float)
  • Vector3, Vector3i - 3D vectors with native Luau vector optimization
  • Vector4, Vector4i - 4D vectors
  • Color - RGBA colors with arithmetic operations
  • Rect2, Rect2i - 2D rectangles
  • Plane, AABB - Geometric primitives
  • Quaternion, Basis, Transform2D, Transform3D, Projection - Transforms

Data Types

  • Array - Godot Arrays (bidirectional conversion to/from Lua tables)
  • Dictionary - Godot Dictionaries (bidirectional conversion to/from Lua tables)
  • String - Transparent string bridging
  • Callable - First-class functions crossing language boundaries
  • Variant - Generic type that handles all Godot types

Demo Project

Run the demo project to see Luau integration in action:

godot --editor --path demo/

The demo showcases:

  • Compiling and executing Luau scripts
  • Single-step debugging with breakpoints and step signals
  • Math type usage with operators (Vector2, Vector3, Color, etc.)
  • Array and Dictionary conversions (including nested structures)
  • Sandboxing for safe script execution
  • Vector library functions (magnitude, normalize, dot, cross, etc.)

License

This project is licensed under the MIT License. See the LICENSE file for details.

Extension providing bindings to Luau, a scripting language derived from Lua with a focus on performance and safety.

Reviews

0 ratings

Your Rating

Headline must be at least 3 characters but not more than 50
Review must be at least 5 characters but not more than 500
Please sign in to add a review

Quick Information

0 ratings
Luau GDExtension icon image
fernforestgames
Luau GDExtension

Extension providing bindings to Luau, a scripting language derived from Lua with a focus on performance and safety.

Supported Engine Version
4.5
Version String
0.4.1
License Version
MIT
Support Level
community
Modified Date
10 hours ago
Git URL
Issue URL

Open Source

Released under the AGPLv3 license

Plug and Play

Browse assets directly from Godot

Community Driven

Created by developers for developers