### Example Build Command Source: https://github.com/libriscv/godot-sandbox/blob/main/program/cpp/project/README.md An example of executing the build script with the --strip option. The output shows the CMake configuration and build progress. ```sh $ ./build.sh --strip ~/github/godot-riscv/program/cpp/project/.build ~/github/godot-riscv/program/cpp/project -- The C compiler identification is Clang 19.1.0 -- The CXX compiler identification is Clang 19.1.0 -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working C compiler: /home/gonzo/zig/zig - skipped -- Detecting C compile features -- Detecting C compile features - done -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: /home/gonzo/zig/zig - skipped -- Detecting CXX compile features -- Detecting CXX compile features - done -- Building using zig c++ -- Configuring done -- Generating done -- Build files have been written to: /home/gonzo/github/godot-riscv/program/cpp/project/.build [ 4%] Building C object CMakeFiles/atomic.dir/src/atomic.c.o [ 9%] Building CXX object cmake/CMakeFiles/sandbox_api.dir/api/array.cpp.o [ 18%] Building CXX object cmake/CMakeFiles/sandbox_api.dir/api/api.cpp.o [ 18%] Building CXX object cmake/CMakeFiles/sandbox_api.dir/api/native.cpp.o [ 22%] Building CXX object cmake/CMakeFiles/sandbox_api.dir/api/basis.cpp.o [ 27%] Building CXX object cmake/CMakeFiles/sandbox_api.dir/api/node2d.cpp.o [ 36%] Building CXX object cmake/CMakeFiles/sandbox_api.dir/api/node.cpp.o [ 36%] Building CXX object cmake/CMakeFiles/sandbox_api.dir/api/dictionary.cpp.o [ 40%] Linking C static library libatomic.a [ 40%] Built target atomic [ 45%] Building CXX object cmake/CMakeFiles/sandbox_api.dir/api/node3d.cpp.o [ 50%] Building CXX object cmake/CMakeFiles/sandbox_api.dir/api/object.cpp.o [ 54%] Building CXX object cmake/CMakeFiles/sandbox_api.dir/api/packed_array.cpp.o [ 59%] Building CXX object cmake/CMakeFiles/sandbox_api.dir/api/quaternion.cpp.o [ 63%] Building CXX object cmake/CMakeFiles/sandbox_api.dir/api/string.cpp.o [ 68%] Building CXX object cmake/CMakeFiles/sandbox_api.dir/api/timer.cpp.o [ 72%] Building CXX object cmake/CMakeFiles/sandbox_api.dir/api/transform2d.cpp.o [ 77%] Building CXX object cmake/CMakeFiles/sandbox_api.dir/api/transform3d.cpp.o [ 81%] Building CXX object cmake/CMakeFiles/sandbox_api.dir/api/variant.cpp.o [ 86%] Building CXX object cmake/CMakeFiles/sandbox_api.dir/api/vector.cpp.o [ 90%] Linking CXX static library libsandbox_api.a [ 90%] Built target sandbox_api [ 95%] Building CXX object CMakeFiles/sandbox_program.dir/src/program.cpp.o [100%] Linking CXX executable sandbox_program [100%] Built target sandbox_program ~/github/godot-riscv/program/cpp/project ``` -------------------------------- ### Build godot-sandbox with SCons Source: https://github.com/libriscv/godot-sandbox/blob/main/README.md Alternative build command using SCons, similar to how godot-cpp addons are built. Requires SCons and python3 to be installed. ```shell scons ``` -------------------------------- ### Branch Simplification Example Source: https://github.com/libriscv/godot-sandbox/blob/main/src/gdscript/compiler/OPTIMIZATIONS.md Simplifies redundant branch patterns by removing unnecessary conditional logic. The example shows how a comparison followed by a conditional branch can be simplified when the comparison itself already produces a boolean result. ```assembly CMP_LT r0, r1, r2 BRANCH_ZERO r0, @skip LOAD_BOOL r0, 1 JUMP @cont LABEL @skip LOAD_BOOL r0, 0 LABEL @cont → CMP_LT r0, r1, r2 # Already produces bool ``` -------------------------------- ### Create Example ELF Program with CMake Source: https://github.com/libriscv/godot-sandbox/blob/main/bin/cmake/CMakeLists.txt This snippet defines a CMake target named 'example.elf' that compiles the provided C++ source files. It utilizes the custom CMake command 'add_sandbox_program_at' to specify the output executable name and its source files, including the main C++ file and any necessary headers or resources located in the '../src' directory. ```cmake # Create example.elf in the src folder add_sandbox_program_at(example.elf ../src ../src/example.cpp ) ``` -------------------------------- ### Type-Hint Propagation Example Source: https://github.com/libriscv/godot-sandbox/blob/main/src/gdscript/compiler/OPTIMIZATIONS.md Tracks and propagates type hints through the Intermediate Representation (IR). This enables other optimizations like strength reduction and allows for specialized code generation. ```assembly LOAD_IMM r0, 5 # Mark as INT LOAD_IMM r1, 10 # Mark as INT ADD r2, r0, r1 # Propagate INT type hint ``` -------------------------------- ### Common Subexpression Elimination (CSE) Example Source: https://github.com/libriscv/godot-sandbox/blob/main/src/gdscript/compiler/OPTIMIZATIONS.md Planned optimization to detect and reuse previously computed values, improving performance by avoiding redundant calculations. ```ir ADD r1, r0, r2 ... ADD r3, r0, r2 # Same computation → ADD r1, r0, r2 ... MOVE r3, r1 # Reuse ``` -------------------------------- ### RISC-V Codegen Stack-Based Example Source: https://github.com/libriscv/godot-sandbox/blob/main/src/gdscript/compiler/OPTIMIZATIONS.md Demonstrates the current stack-based approach in the RISC-V code generation, where all operations involve loading from and storing back to the stack, using only `t0` as a scratch register. ```assembly ld t0, 24(sp) # Load from stack sd t0, 48(sp) # Store to stack ld t0, 32(sp) # Load from stack sd t0, 56(sp) # Store to stack # ... only t0 is used! ``` -------------------------------- ### Redundant Store Elimination Example Source: https://github.com/libriscv/godot-sandbox/blob/main/src/gdscript/compiler/OPTIMIZATIONS.md Removes dead stores and consecutive identical stores to registers. ```ir LOAD_IMM r0, 10 LOAD_IMM r0, 20 # First store is dead → LOAD_IMM r0, 20 ``` -------------------------------- ### Sandbox.generate_api: Use Generated API in Guest C++ Source: https://context7.com/libriscv/godot-sandbox/llms.txt Example of how to use the generated Godot API header in a guest C++ program. It shows accessing engine classes like SceneTree after including the generated header. ```cpp // In guest C++ — after generated_api.hpp is present: #include "api.hpp" // includes generated_api.hpp automatically static Variant use_generated_api() { // SceneTree is now available from generated_api.hpp SceneTree tree = get_tree(); Node root = tree.get_edited_scene_root(); print("Scene root: ", root.get_name()); return Nil; } ``` -------------------------------- ### Strength Reduction Examples Source: https://github.com/libriscv/godot-sandbox/blob/main/src/gdscript/compiler/OPTIMIZATIONS.md Replaces expensive arithmetic operations with cheaper equivalents. This optimization is safe for type-hinted integers. ```assembly MUL r0, r1, 2 → ADD r0, r1, r1 (for type-hinted ints) ``` ```assembly DIV r0, r1, 4 → SRA r0, r1, 2 (for type-hinted ints) ``` ```assembly MUL r0, r1, 0 → LOAD_IMM r0, 0 ``` -------------------------------- ### Enhanced Copy Propagation Example Source: https://github.com/libriscv/godot-sandbox/blob/main/src/gdscript/compiler/OPTIMIZATIONS.md Advanced copy propagation that tracks copy chains to propagate sources through multiple moves. Verifies the source register hasn't been modified. ```gdscript var a = x var b = a return b # Can use x directly ``` ```ir Before: MOVE r1, r0 CMP_LT r3, r1, r2 # Uses r1 After: MOVE r1, r0 CMP_LT r3, r0, r2 # Uses r0 directly ``` -------------------------------- ### Algebraic Simplification Examples Source: https://github.com/libriscv/godot-sandbox/blob/main/src/gdscript/compiler/OPTIMIZATIONS.md Applies algebraic identities to simplify expressions. These are very safe for integers but require care with floating-point values like NaN and infinity. ```assembly ADD r0, r1, 0 → MOVE r0, r1 ``` ```assembly MUL r0, r1, 1 → MOVE r0, r1 ``` ```assembly MUL r0, r1, 0 → LOAD_IMM r0, 0 ``` ```assembly SUB r0, r1, 0 → MOVE r0, r1 ``` -------------------------------- ### Define Sandbox API Library Source: https://github.com/libriscv/godot-sandbox/blob/main/program/cpp/cmake/CMakeLists.txt Defines the static library for the sandbox API, setting version, compile definitions, options, and include directories. It also includes conditional linking for different compiler setups and linker wrappers. ```cmake add_library(sandbox_api STATIC ${API_SOURCES}) target_compile_definitions(sandbox_api PUBLIC VERSION=${VERSION} ) target_compile_options(sandbox_api PUBLIC ${RISCV_ARCH} ${RISCV_ABI} $<$:${CXXFLAGS}> $<$:${CFLAGS}> ) target_include_directories(sandbox_api PUBLIC ${API_DIR} ) ``` ```cmake if (NOT ZIG_COMPILER) target_link_libraries(sandbox_api PUBLIC -Wl,--wrap=memcpy,--wrap=memset,--wrap=memcmp,--wrap=memmove -Wl,--wrap=strlen,--wrap=strcmp,--wrap=strncmp -Wl,--wrap=malloc,--wrap=calloc,--wrap=realloc,--wrap=free ) else() target_compile_definitions(sandbox_api PUBLIC ZIG_COMPILER=1 ) target_link_libraries(sandbox_api PUBLIC -Wl,--image-base=0x100000 ) endif() ``` ```cmake if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") # If the GCC version is 14.0 or higher, we can use the -fuse-ld=mold flag if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 14.0) find_program(MOLD_LINKER "mold") if (MOLD_LINKER) message(STATUS "Using MOLD linker") target_link_libraries(sandbox_api PUBLIC -fuse-ld=mold) endif() endif() endif() ``` -------------------------------- ### CMakeLists.txt Configuration Source: https://github.com/libriscv/godot-sandbox/blob/main/program/cpp/cmake/example/CMakeLists.txt Sets up the minimum CMake version, project name, and language. Includes a subdirectory and fetches an external dependency. ```cmake cmake_minimum_required(VERSION 3.10) project(example LANGUAGES CXX) add_subdirectory(../ cmake) # Fetch fmt from GitHub include(FetchContent) FetchContent_Declare(libfmt GIT_REPOSITORY https://github.com/fmtlib/fmt GIT_TAG master ) FetchContent_MakeAvailable(libfmt) add_sandbox_program(example "example.cpp" ) target_link_libraries(example PRIVATE fmt::fmt) ``` -------------------------------- ### Get Sandbox for Node or Objects with `ELFScript` Source: https://context7.com/libriscv/godot-sandbox/llms.txt Retrieves the shared Sandbox instance associated with an `ELFScript` resource. Use `get_sandbox_for` to get the sandbox for a specific node, or `get_sandbox_objects` to enumerate all objects sharing the sandbox. ```gdscript # Load the ELF resource var elf: ELFScript = preload("res://scripts/enemy.elf") # Get the shared Sandbox for a specific node instance var enemy_node := $EnemyA var sb: Sandbox = elf.get_sandbox_for(enemy_node) if sb: sb.vmcall("force_die") # Enumerate all objects sharing this ELF script's sandbox var objects: Array = elf.get_sandbox_objects() for obj in objects: print("Shared sandbox owner: ", obj) ``` -------------------------------- ### Guest C++ API: Math, loadv, ClassDB::instantiate Source: https://context7.com/libriscv/godot-sandbox/llms.txt Shows how to use the sandboxed Math struct for operations, load resources with `loadv`, and instantiate Godot objects using `ClassDB::instantiate`. ```cpp #include "api.hpp" static Variant spawn_projectile(Vector2 origin, float angle) { // Math operations float vx = Math::cosf(angle) * 400.0f; float vy = Math::sinf(angle) * 400.0f; float clamped = Math::clampf(vx, -500.0f, 500.0f); float smooth = Math::smoothstepf(0.0f, 1.0f, 0.5f); // Instantiate a new Node2D for the bullet Node2D bullet = ClassDB::instantiate("Node2D", "Bullet"); bullet.set_position(origin); // Load a texture resource (may be denied by sandbox restrictions) Variant tex = loadv("res://assets/bullet.png"); if (!tex.is_nil()) { // tex is a Texture2D resource object bullet.call("set_texture", tex); // generic method_call on Variant } // Attach bullet to scene root get_node().add_child(bullet); return Nil; } int main() { ADD_API_FUNCTION(spawn_projectile, "void", "Vector2 origin, float angle"); } ``` -------------------------------- ### Guest C++ API - Math, loadv, ClassDB::instantiate Source: https://context7.com/libriscv/godot-sandbox/llms.txt Shows how to use the Math struct for calculations, load resources using `loadv`, and instantiate Godot objects via `ClassDB::instantiate`. ```APIDOC ## spawn_projectile(origin: Vector2, angle: float) -> void ### Description Calculates projectile velocity using math functions, instantiates a Node2D for the bullet, attempts to load and set its texture, and adds it as a child to the scene. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **origin** (Vector2) - The starting position of the projectile. - **angle** (float) - The angle at which the projectile is fired. ### Request Example ```cpp spawn_projectile(Vector2(100, 200), PI / 4.0); ``` ### Response #### Success Response (200) - **return value** (void) - This function does not return a meaningful value. #### Response Example ```cpp // No response body ``` ``` -------------------------------- ### Verify Built ELF Binary Source: https://github.com/libriscv/godot-sandbox/blob/main/program/cpp/project/README.md After building, the `sandbox_program.elf` will be located in the `.build` directory. Use the `file` command to inspect its properties. ```shell $ file .build/sandbox_program.elf ``` -------------------------------- ### Guest C++ API: Variant, Array, Dictionary, Callable Source: https://context7.com/libriscv/godot-sandbox/llms.txt Demonstrates type inspection, conversion, and manipulation of Godot's Variant, Array, and Dictionary types in C++. Shows how to create and use Callables for callbacks. ```cpp #include "api.hpp" static Variant compute(Variant input) { // Variant type inspection if (input.get_type() == Variant::ARRAY) { Array arr = input.as_array(); double sum = 0.0; for (int i = 0; i < arr.size(); i++) { sum += (double)arr[i]; } return sum; } if (input.get_type() == Variant::DICTIONARY) { Dictionary d = input.as_dictionary(); d["processed"] = true; d["count"] = d.size(); return d; } // Build an Array with Array::make Array result = Array::make(1, 2.5, "three", true); result.push_back(input); result.sort(); return result; } static Variant use_callable() { // Create a guest Callable from a C++ function pointer Callable cb = Callable::Create(+[](Variant arg) -> Variant { print("Callback received: ", arg); return Nil; }); // Pass it to a host signal connection via vmcall from GDScript, or call directly cb(42); // Dictionary construction and method_call Dictionary d = Dictionary::Create(); d["hello"] = "world"; d["pi"] = 3.14159; print("Keys: ", d.keys()); return d; } int main() { ADD_API_FUNCTION(compute, "Variant", "Variant input"); ADD_API_FUNCTION(use_callable, "Dictionary"); } ``` -------------------------------- ### Sandbox profiling — `profiling`, `get_hotspots`, `clear_hotspots` Source: https://context7.com/libriscv/godot-sandbox/llms.txt Enable instruction-level profiling to identify performance bottlenecks in guest programs. `get_hotspots` retrieves the most frequently executed addresses. ```APIDOC ## Sandbox profiling — `profiling`, `get_hotspots`, `clear_hotspots` Enable instruction-level profiling to identify hot functions in guest programs. `get_hotspots` returns the top-N most-executed addresses globally across all sandbox instances. ```gdscript var sb: Sandbox = Sandbox.FromProgram(preload("res://scripts/game_logic.elf")) add_child(sb) sb.profiling = true # Run some workload for i in 1000: sb.vmcall("tick", get_process_delta_time()) # Print top 5 hotspots var hotspots: Array = Sandbox.get_hotspots(5) for h in hotspots: print(h) # e.g.: { "name": "_process", "hits": 8420, "address": 0x10234 } Sandbox.clear_hotspots() sb.profiling = false ``` ``` -------------------------------- ### Load Sandbox Program Source: https://context7.com/libriscv/godot-sandbox/llms.txt Create a Sandbox node from a preloaded ELFScript resource or a raw byte array. These are the primary methods for initializing sandbox instances at runtime. The 'program' property can also be used to set the ELF script on an existing Sandbox node. ```gdscript var sb: Sandbox = Sandbox.FromProgram(preload("res://mods/my_mod.elf")) add_child(sb) var bytes: PackedByteArray = Sandbox.download_program("hello_world") var sb2: Sandbox = Sandbox.FromBuffer(bytes) add_child(sb2) var sb3 := Sandbox.new() sb3.set_program(preload("res://scripts/enemy_ai.elf")) add_child(sb3) ``` -------------------------------- ### Induction Variable Optimization Example Source: https://github.com/libriscv/godot-sandbox/blob/main/src/gdscript/compiler/OPTIMIZATIONS.md Optimizes loop counter variables, such as replacing multiplication within a loop with an increment operation. This is particularly effective for counted loops. ```gdscript for i in range(10): array[i] = i * 2 ``` -------------------------------- ### Constant Folding Example Source: https://github.com/libriscv/godot-sandbox/blob/main/src/gdscript/compiler/OPTIMIZATIONS.md Evaluates constant expressions at compile time. Handles integer and float arithmetic, comparisons, and GDScript type promotion. Avoids division by zero. ```gdscript var x = 5 + 10 # Compiled as: x = 15 var y = 2.0 * 3.0 # Compiled as: y = 6.0 ``` ```ir Before: LOAD_IMM r1, 5 LOAD_IMM r2, 10 ADD r0, r1, r2 After: LOAD_IMM r0, 15 ``` -------------------------------- ### Reset and Dynamically Load Sandbox Programs Source: https://context7.com/libriscv/godot-sandbox/llms.txt Re-initializes the sandbox from its current program using `reset()` or replaces the loaded program at runtime with a new ELF byte array using `load_buffer()`. This enables live mod updates or hot-swapping. ```gdscript var sb: Sandbox = Sandbox.FromProgram(preload("res://scripts/base.elf")) add_child(sb) # Hot-swap the program with a freshly downloaded mod var new_bytes: PackedByteArray = await download_mod_from_server("mod_v2") sb.load_buffer(new_bytes) # After a crash or timeout, reset without unloading if sb.monitor_exceptions > 0 or sb.monitor_execution_timeouts > 0: sb.reset() # reloads and re-runs main() # sb.reset(true) # also unloads the program entirely ``` -------------------------------- ### Sandbox reset and dynamic loading — reset / load_buffer Source: https://context7.com/libriscv/godot-sandbox/llms.txt `reset()` re-initializes the sandbox from its current program. `load_buffer()` replaces the loaded program at runtime with a new ELF byte array. ```APIDOC ## Sandbox reset and dynamic loading — reset / load_buffer `reset()` re-initializes the sandbox from its current program (useful after an exception or timeout). `load_buffer()` replaces the loaded program at runtime with a new ELF byte array — enabling live mod updates or hot-swapping. ### Methods ```gdscript func reset(unload_program: bool = false) -> void func load_buffer(elf_bytes: PackedByteArray) -> void ``` ### Parameters #### reset - **unload_program** (bool) - Optional. If true, the program is unloaded entirely. Defaults to false. #### load_buffer - **elf_bytes** (PackedByteArray) - The new ELF program as a byte array. ### Request Example ```gdscript var sb: Sandbox = Sandbox.FromProgram(preload("res://scripts/base.elf")) add_child(sb) # Hot-swap the program with a freshly downloaded mod var new_bytes: PackedByteArray = await download_mod_from_server("mod_v2") sb.load_buffer(new_bytes) # After a crash or timeout, reset without unloading if sb.monitor_exceptions > 0 or sb.monitor_execution_timeouts > 0: sb.reset() # reloads and re-runs main() # sb.reset(true) # also unloads the program entirely ``` ``` -------------------------------- ### Guest Rust API - Registering Public Functions Source: https://context7.com/libriscv/godot-sandbox/llms.txt Explains how to expose Rust functions to GDScript using `register_public_api_funcN` and interact with Godot nodes and variants. ```APIDOC ## _physics_process(delta: f64) -> Variant ### Description Processes physics updates for a node. If not in the editor, it moves the node horizontally based on speed and delta time. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **delta** (f64) - The time elapsed since the last physics frame. ### Request Example ```rust // Called automatically by Godot's physics loop ``` ### Response #### Success Response (200) - **return value** (Variant) - Returns Nil. #### Response Example ```rust Variant::new_nil() ``` ``` ```APIDOC ## add_numbers(a: i32, b: i32) -> Variant ### Description Adds two 32-bit integers and returns the result as a Godot Variant. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **a** (i32) - The first integer. - **b** (i32) - The second integer. ### Request Example ```rust let result = add_numbers(5, 10); ``` ### Response #### Success Response (200) - **return value** (Variant) - A Variant containing the integer sum of 'a' and 'b'. #### Response Example ```rust Variant::new_integer(15) ``` ``` -------------------------------- ### Add Sandbox Program with Output Directory Source: https://github.com/libriscv/godot-sandbox/blob/main/program/cpp/cmake/CMakeLists.txt Extends `add_sandbox_program` to specify the runtime output directory for the executable. Handles both absolute and relative paths for the output directory. ```cmake function (add_sandbox_program_at name path) add_sandbox_program(${name} ${ARGN}) # if the path is relative, make it relative to # the CMake source directory if (NOT IS_ABSOLUTE "${path}") set(path "${CMAKE_SOURCE_DIR}/${path}") endif() set_target_properties(${name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${path} RUNTIME_OUTPUT_NAME ${name} ) endfunction() ``` -------------------------------- ### Add Sandbox Program Build Rule Source: https://github.com/libriscv/godot-sandbox/blob/main/program/cpp/project/README.md Use the `add_sandbox_program` function to define a new sandbox executable. Specify the desired ELF binary name followed by the source files. ```cmake add_sandbox_program(sandbox_program.elf "src/program.cpp" ) ``` -------------------------------- ### Build Script Usage Source: https://github.com/libriscv/godot-sandbox/blob/main/program/cpp/project/README.md Use this script to build the C++ project. Options control debugging, stripping, precision, and RISC-V extensions. ```sh Usage: ./build.sh [options] Options: -h, --help Display this help and exit --runtime-api Download a run-time generated Godot API header --no-runtime-api Do not download a run-time generated Godot API header --debug Build with debug symbols --debinfo Build with debug info --strip Strip the binary --no-strip Do not strip the binary --single Build with single precision vectors --double Build with double precision vectors --C Enable RISC-V C extension (default) --no-C Disable RISC-V C extension --toolchain Specify a custom toolchain file --verbose Enable verbose build ``` -------------------------------- ### Enable Sandbox Instruction-Level Profiling Source: https://context7.com/libriscv/godot-sandbox/llms.txt Activate instruction-level profiling to identify performance bottlenecks ('hotspots') within guest programs. `Sandbox.get_hotspots` retrieves the most executed addresses across all sandbox instances. ```gdscript var sb: Sandbox = Sandbox.FromProgram(preload("res://scripts/game_logic.elf")) add_child(sb) sb.profiling = true # Run some workload for i in 1000: sb.vmcall("tick", get_process_delta_time()) # Print top 5 hotspots var hotspots: Array = Sandbox.get_hotspots(5) for h in hotspots: print(h) # e.g.: { "name": "_process", "hits": 8420, "address": 0x10234 } Sandbox.clear_hotspots() sb.profiling = false ``` -------------------------------- ### Guest Rust API: Registering Public Functions Source: https://context7.com/libriscv/godot-sandbox/llms.txt Demonstrates how to expose Rust functions to GDScript using `register_public_api_funcN`. Accesses Godot nodes and variants through the `godot::` module. ```rust mod godot; use godot::api::*; use godot::node::*; use godot::variant::*; const SPEED: f32 = 120.0; extern "C" fn _physics_process(delta: f64) -> Variant { if Engine::is_editor_hint() { return Variant::new_nil(); } let node = get_node(); let mut pos = node.call("get_position", &[]).to_vec2(); pos.x += SPEED * delta as f32; node.call("set_position", &[Variant::new_vec2(pos)]); Variant::new_nil() } extern "C" fn add_numbers(a: i32, b: i32) -> Variant { Variant::new_integer((a + b).into()) } pub fn main() { register_public_api_func1("_physics_process", _physics_process, "Variant", "f64 delta"); register_public_api_func2("add_numbers", add_numbers, "int", "int a, int b"); } ``` -------------------------------- ### Sandbox.vmcallv Source: https://context7.com/libriscv/godot-sandbox/llms.txt Variant-only function call into the guest ELF program. All arguments are passed as `Variant`s, and the guest function must also accept `Variant` parameters. Recommended for unknown argument types or GDScript-compiled ELFs. ```APIDOC ## `Sandbox.vmcallv` — Variant-only function call into the sandbox Same as `vmcall` but passes all arguments as `Variant`s. The guest function must also accept `Variant` parameters. More permissive and error-tolerant than `vmcall`; recommended when argument types are not known at call time or when using GDScript-compiled ELFs. ```gdscript var sb: Sandbox = Sandbox.FromProgram(preload("res://mods/player_mod.elf")) add_child(sb) # Guest function signature (C++): # Variant handle_event(Variant event_name, Variant payload) { ... } var result = sb.vmcallv("handle_event", "on_coin_collected", {"player": "Alice", "coins": 10}) print(result) # Whatever the mod returns ``` ``` -------------------------------- ### Apply Minimal Build Flags Source: https://github.com/libriscv/godot-sandbox/blob/main/program/cpp/cmake/CMakeLists.txt Enables -Oz optimization flag for both CXX and C compilers if the MINIMAL option is set. ```cmake if (MINIMAL) set(CXXFLAGS ${CXXFLAGS} -Oz) set(CFLAGS ${CFLAGS} -Oz) endif() ``` -------------------------------- ### Define Build Options Source: https://github.com/libriscv/godot-sandbox/blob/main/program/cpp/cmake/CMakeLists.txt Sets boolean options for various build configurations, such as downloading the runtime API, enabling RISC-V extensions, controlling precision, stripping binaries, enabling link-time optimization, and building minimal programs. ```cmake option(DOWNLOAD_RUNTIME_API "Download the run-time generated API" ON) option(SANDBOX_RISCV_EXT_C "Enable RISC-V C extension" ON) option(DOUBLE_PRECISION "Enable double precision real_t" OFF) option(STRIPPED "Strip executables" OFF) option(FLTO "Enable link-time optimization" OFF) option(MINIMAL "Build minimal programs using -Oz" OFF) ``` -------------------------------- ### Guest C++ API - Variant, Array, Dictionary, Callable Source: https://context7.com/libriscv/godot-sandbox/llms.txt Demonstrates the usage of Variant, Array, Dictionary, and Callable types in C++ for data manipulation and function callbacks within the sandbox. ```APIDOC ## compute(input: Variant) -> Variant ### Description Processes a Variant input. If it's an Array, it calculates the sum of its elements. If it's a Dictionary, it adds 'processed' and 'count' fields. Otherwise, it creates and returns a sorted Array containing the input and other elements. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **input** (Variant) - The input variant to process. ### Request Example ```cpp Variant input_array = Array::make(1.0, 2.0, 3.0); Variant result = compute(input_array); ``` ### Response #### Success Response (200) - **return value** (Variant) - The processed Variant, which could be a double (sum), a Dictionary, or an Array. #### Response Example ```cpp // If input was an array [1.0, 2.0, 3.0] 6.0 // If input was a dictionary {"key": "value", "processed": true, "count": 1} // If input was neither [1, 2.5, "three", true, ].sorted() ``` ``` ```APIDOC ## use_callable() -> Dictionary ### Description Creates a Callable from a C++ lambda function, invokes it, and demonstrates Dictionary construction and method calls. ### Parameters None ### Request Example ```cpp Dictionary result = use_callable(); ``` ### Response #### Success Response (200) - **return value** (Dictionary) - A dictionary containing "hello": "world" and "pi": 3.14159. #### Response Example ```cpp {"hello": "world", "pi": 3.14159} ``` ``` -------------------------------- ### Configure Sandbox Resource Limits Source: https://context7.com/libriscv/godot-sandbox/llms.txt Set limits on memory usage, execution time (instructions per call), and heap allocations to prevent resource exhaustion by guest programs. Also includes monitoring of runtime statistics. ```gdscript var sb: Sandbox = Sandbox.FromProgram(preload("res://mods/mod.elf")) add_child(sb) sb.memory_max = 8 # 8 MB max virtual memory sb.execution_timeout = 2000 # 2 000 M instructions per vmcall (default 8 000) sb.allocations_max = 500 # max 500 heap allocs per call (default 4 000) sb.references_max = 50 # max 50 object references (default 100) # Monitor runtime stats print("Calls made: ", sb.monitor_calls_made) print("Exceptions: ", sb.monitor_exceptions) print("Timeouts: ", sb.monitor_execution_timeouts) print("Heap usage: ", sb.monitor_heap_usage, " bytes") ``` -------------------------------- ### Build godot-sandbox Locally Source: https://github.com/libriscv/godot-sandbox/blob/main/README.md Shell script to build the godot-sandbox project locally. This is a prerequisite for contributing to the repository. ```shell ./build.sh ``` -------------------------------- ### Compile and Load Binary Translation Source: https://context7.com/libriscv/godot-sandbox/llms.txt Optimize RISC-V programs for significant performance gains (5–50×) by compiling them into native shared libraries. This involves emitting C source, compiling it, and then loading the resulting library at game startup. ```gdscript # Step 1: Compile translation at editor time or first run var sb: Sandbox = Sandbox.FromProgram(preload("res://scripts/heavy.elf")) add_child(sb) var ok = sb.try_compile_binary_translation( "res://bintr", # output path (without extension) "cc", # C compiler "-O3", # extra C flags true, # ignore instruction limit inside translation false # automatic n-bit address space (experimental) ) print("Compiled: ", ok) # true if cc is available # Step 2: At game startup, BEFORE adding any Sandbox nodes: func _init(): Sandbox.load_binary_translation("res://bintr.so") # or .dll on Windows # Check if a sandbox is using binary translation var sb2: Sandbox = Sandbox.FromProgram(preload("res://scripts/heavy.elf")) add_child(sb2) print("Binary translated: ", sb2.is_binary_translated()) # true after loading ``` -------------------------------- ### Define API Source Files Source: https://github.com/libriscv/godot-sandbox/blob/main/program/cpp/cmake/CMakeLists.txt Lists the C++ source files that constitute the API for the Godot Sandbox project. ```cmake set(API_DIR "${CMAKE_CURRENT_LIST_DIR}/../docker/api") set(API_SOURCES "${API_DIR}/api.cpp" "${API_DIR}/array.cpp" "${API_DIR}/basis.cpp" "${API_DIR}/dictionary.cpp" "${API_DIR}/native.cpp" "${API_DIR}/node.cpp" "${API_DIR}/node2d.cpp" "${API_DIR}/node3d.cpp" "${API_DIR}/object.cpp" "${API_DIR}/packed_array.cpp" "${API_DIR}/quaternion.cpp" "${API_DIR}/string.cpp" "${API_DIR}/timer.cpp" "${API_DIR}/transform2d.cpp" "${API_DIR}/transform3d.cpp" "${API_DIR}/variant.cpp" "${API_DIR}/vector.cpp" ) ``` -------------------------------- ### Sandbox Node Constructors Source: https://context7.com/libriscv/godot-sandbox/llms.txt Static constructors to create a Sandbox node from an ELFScript resource or a raw byte array. These are the primary methods for initializing sandbox instances. ```APIDOC ## Sandbox Node — `Sandbox.FromProgram` / `Sandbox.FromBuffer` Static constructors that create a `Sandbox` node from an `ELFScript` resource or raw byte array. These are the main entry points for creating sandbox instances at runtime. ```gdscript # From a preloaded ELFScript resource (typical workflow) var sb: Sandbox = Sandbox.FromProgram(preload("res://mods/my_mod.elf")) add_child(sb) # From a byte array downloaded at runtime var bytes: PackedByteArray = Sandbox.download_program("hello_world") var sb2: Sandbox = Sandbox.FromBuffer(bytes) add_child(sb2) # Or assign via the 'program' property on an existing Sandbox node var sb3 := Sandbox.new() sb3.set_program(preload("res://scripts/enemy_ai.elf")) add_child(sb3) ``` ``` -------------------------------- ### Create Callable from Guest Address Source: https://context7.com/libriscv/godot-sandbox/llms.txt Use `vmcallable_address` to create a Callable from a raw memory address within the sandbox. This is useful when you have an integer address, such as one obtained from `Sandbox.address_of`. ```gdscript var sb: Sandbox = Sandbox.FromProgram(preload("res://scripts/compute.elf")) add_child(sb) var fn_addr: int = sb.address_of("heavy_computation") if fn_addr != 0: var cb = sb.vmcallable_address(fn_addr, [42]) # Call immediately var result = cb.call() print("Result: ", result) ``` -------------------------------- ### Fetch godot-sandbox C++ API with CMake Source: https://github.com/libriscv/godot-sandbox/blob/main/bin/cmake/CMakeLists.txt This snippet configures CMake to fetch the godot-sandbox C++ API from its GitHub repository. It uses FetchContent to download the repository, specifying the Git URL, tag, and shallow clone option. It also sets SOURCE_SUBDIR to point to the correct directory within the repository. ```cmake cmake_minimum_required(VERSION 3.10) project(example LANGUAGES CXX) # Fetch godot-sandbox C++ API include(FetchContent) FetchContent_Declare( godot-sandbox GIT_REPOSITORY https://github.com/libriscv/godot-sandbox.git GIT_TAG main GIT_SHALLOW TRUE GIT_SUBMODULES "" SOURCE_SUBDIR "program/cpp/cmake" ) FetchContent_MakeAvailable(godot-sandbox) ``` -------------------------------- ### Sandbox.vmcall Source: https://context7.com/libriscv/godot-sandbox/llms.txt Typed function call into the guest ELF program. Arguments are passed as their native Godot types (unboxed), making it faster than `vmcallv` when `unboxed_arguments` is enabled. ```APIDOC ## `Sandbox.vmcall` — Typed function call into the sandbox Calls a named function in the guest ELF program. Arguments are passed as their native Godot types (unboxed). The first variadic argument is the function name string; the remaining arguments are forwarded to the guest. Faster than `vmcallv` because types do not need to be wrapped into Variants when `unboxed_arguments` is enabled. ```gdscript # C++ guest function (in the ELF): # Variant my_function(int a, String b, Array c) { # return c[0].operator double() + c[1].operator double() + c[2].operator double(); # } var sb: Sandbox = Sandbox.FromProgram(preload("res://scripts/math.elf")) add_child(sb) if sb.has_function("my_function"): var result = sb.vmcall("my_function", 123, "hello", [4.0, 5.0, 6.0]) print(result) # Output: 15.0 # Calling a Godot lifecycle callback registered by the guest sb.vmcall("_ready") sb.vmcall("_process", get_process_delta_time()) ``` ``` -------------------------------- ### Binary translation — `emit_binary_translation` / `try_compile_binary_translation` / `load_binary_translation` Source: https://context7.com/libriscv/godot-sandbox/llms.txt Convert interpreted RISC-V programs into native shared libraries for significant performance improvements. The process involves emitting C source, compiling it, and then loading the resulting library. ```APIDOC ## Binary translation — `emit_binary_translation` / `try_compile_binary_translation` / `load_binary_translation` Convert an interpreted RISC-V program to a native shared library for 5–50× performance. The workflow is: emit C source → compile to `.so`/`.dll` → load on next startup (before any Sandbox is created). ```gdscript # Step 1: Compile translation at editor time or first run var sb: Sandbox = Sandbox.FromProgram(preload("res://scripts/heavy.elf")) add_child(sb) var ok = sb.try_compile_binary_translation( "res://bintr", # output path (without extension) "cc", # C compiler "-O3", # extra C flags true, # ignore instruction limit inside translation false # automatic n-bit address space (experimental) ) print("Compiled: ", ok) # true if cc is available # Step 2: At game startup, BEFORE adding any Sandbox nodes: func _init(): Sandbox.load_binary_translation("res://bintr.so") # or .dll on Windows # Check if a sandbox is using binary translation var sb2: Sandbox = Sandbox.FromProgram(preload("res://scripts/heavy.elf")) add_child(sb2) print("Binary translated: ", sb2.is_binary_translated()) # true after loading ``` ``` -------------------------------- ### Add Sandbox Library Source: https://github.com/libriscv/godot-sandbox/blob/main/program/cpp/cmake/CMakeLists.txt Defines a static library target for the sandbox, linking it against the main sandbox API library. ```cmake function (add_sandbox_library name) add_library(${name} STATIC ${ARGN}) target_link_libraries(${name} INTERFACE sandbox_api ) endfunction() ``` -------------------------------- ### Enable Link-Time Optimization Source: https://github.com/libriscv/godot-sandbox/blob/main/program/cpp/cmake/CMakeLists.txt Applies the -flto flag to CXX and C compilers if the FLTO option is enabled. ```cmake if (FLTO) set(CXXFLAGS ${CXXFLAGS} -flto) set(CFLAGS ${CFLAGS} -flto) endif() ``` -------------------------------- ### Sandbox resource limits — `memory_max`, `execution_timeout`, `allocations_max` Source: https://context7.com/libriscv/godot-sandbox/llms.txt Set limits on guest memory usage, maximum instructions per call, and the number of heap allocations to control resource consumption. ```APIDOC ## Sandbox resource limits — `memory_max`, `execution_timeout`, `allocations_max` Configure how many megabytes of memory the guest may use, the maximum number of (millions of) instructions per call, and the maximum number of heap allocations. ```gdscript var sb: Sandbox = Sandbox.FromProgram(preload("res://mods/mod.elf")) add_child(sb) sb.memory_max = 8 # 8 MB max virtual memory sb.execution_timeout = 2000 # 2 000 M instructions per vmcall (default 8 000) sb.allocations_max = 500 # max 500 heap allocs per call (default 4 000) sb.references_max = 50 # max 50 object references (default 100) # Monitor runtime stats print("Calls made: ", sb.monitor_calls_made) print("Exceptions: ", sb.monitor_exceptions) print("Timeouts: ", sb.monitor_execution_timeouts) print("Heap usage: ", sb.monitor_heap_usage, " bytes") ``` ``` -------------------------------- ### Sandbox.vmcallable_address — Create a Callable from a raw guest address Source: https://context7.com/libriscv/godot-sandbox/llms.txt Creates a Callable that invokes a function at a specific memory address within the sandbox. This is useful when you have a raw memory address, for instance, after using `Sandbox.address_of`. ```APIDOC ## `Sandbox.vmcallable_address` — Create a Callable from a raw guest address Creates a `Callable` that calls a function at a specific memory address inside the sandbox. Works like `vmcallable` but uses an integer address instead of a symbol name. Useful after calling `Sandbox.address_of`. ```gdscript var sb: Sandbox = Sandbox.FromProgram(preload("res://scripts/compute.elf")) add_child(sb) var fn_addr: int = sb.address_of("heavy_computation") if fn_addr != 0: var cb = sb.vmcallable_address(fn_addr, [42]) # Call immediately var result = cb.call() print("Result: ", result) ``` ``` -------------------------------- ### Sandbox.generate_api - Generate Godot API Header Source: https://context7.com/libriscv/godot-sandbox/llms.txt Details how to use `Sandbox.generate_api` in GDScript to create a C++ header file containing Godot class bindings for guest programs. ```APIDOC ## Sandbox.generate_api(language: String, module_filter: String, include_hidden: bool) -> String ### Description Generates a language-specific header file (e.g., C++ header) containing Godot class bindings that can be used in guest programs for auto-completion and type-safe access. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **language** (String) - The target language for the generated API header (e.g., "cpp"). - **module_filter** (String) - A filter for modules to include (can be empty). - **include_hidden** (bool) - Whether to include hidden classes and members. ### Request Example ```gdscript var api_code: String = Sandbox.generate_api("cpp", "", true) ``` ### Response #### Success Response (200) - **return value** (String) - A string containing the generated API header code. #### Response Example ```cpp // Content of generated_api.hpp #include // ... other Godot class bindings ... ``` ``` ```APIDOC ## use_generated_api() -> Variant ### Description An example function within a guest C++ program that utilizes the generated API header to access Godot classes like `SceneTree`. ### Parameters None ### Request Example ```cpp // Assuming generated_api.hpp is included Variant result = use_generated_api(); ``` ### Response #### Success Response (200) - **return value** (Variant) - Returns Nil. #### Response Example ```cpp // No response body, prints to console ``` ``` -------------------------------- ### Sandbox.generate_api: Generate Godot API Header (GDScript) Source: https://context7.com/libriscv/godot-sandbox/llms.txt Generates a C++ header file containing Godot class bindings for use in guest programs. This enables auto-completion and type-safe access to the Godot API. ```gdscript # Generate the C++ API header and save it for use in guest programs var api_code: String = Sandbox.generate_api("cpp", "", true) var f := FileAccess.open("res://program/cpp/docker/api/generated_api.hpp", FileAccess.WRITE) f.store_string(api_code) f.close() print("Generated ", api_code.length(), " bytes of API") ``` -------------------------------- ### Registering API Functions and Properties in C++ Source: https://context7.com/libriscv/godot-sandbox/llms.txt Use `ADD_PROPERTY` to expose variables to the Godot Inspector and `ADD_API_FUNCTION` to register C++ functions callable from Godot. Ensure correct type and parameter signatures are provided. ```cpp #include "api.hpp" // Per-instance state using the PER_OBJECT macro struct EnemyState { int health = 100; float speed = 60.0f; }; PER_OBJECT(EnemyState); // Exposed inspector property static float patrol_speed = 60.0f; static Variant _ready() { if (is_editor_hint()) return Nil; print("Enemy ready! Node: ", get_node().get_name()); return Nil; } static Variant _physics_process(double delta) { Node2D self = get_node(); auto& state = GetEnemyState(self); Vector2 pos = self.get_position(); pos.x += patrol_speed * (float)delta; self.set_position(pos); return Nil; } static Variant take_damage(int amount) { Node self = get_node(); auto& state = GetEnemyState(self); state.health -= amount; print("Health: ", state.health); if (state.health <= 0) { self.queue_free(); } return state.health; } int main() { ADD_PROPERTY(patrol_speed, Variant::FLOAT); // visible in the Godot Inspector ADD_API_FUNCTION(_ready, "void"); ADD_API_FUNCTION(_physics_process, "void", "double delta"); ADD_API_FUNCTION(take_damage, "int", "int amount"); } ```