diff --git a/docs/DEFERRED.md b/docs/DEFERRED.md index a309f22..5548f6d 100644 --- a/docs/DEFERRED.md +++ b/docs/DEFERRED.md @@ -62,6 +62,14 @@ - **raycast_all (다중 hit)** — 가장 가까운 hit만 반환. - **BVH 조기 종료 최적화** — 모든 리프 검사 후 최소 t 선택. front-to-back 순회 미구현. +## Phase 8-3 + +- **핫 리로드** — 파일 변경 감지 + Lua state 재로드 미구현. +- **엔진 API 노출** — ECS, 물리, 오디오 등 Lua에서 접근 불가. +- **Lua 테이블 ↔ Rust 구조체** — 복잡한 데이터 변환 미구현. +- **코루틴** — Lua 코루틴 래핑 미구현. +- **샌드박싱** — Lua 보안 제한 미구현. + ## Phase 8-2 - **상태 동기화 (스냅샷)** — 미구현. 서버→클라이언트 월드 상태 전송. diff --git a/docs/STATUS.md b/docs/STATUS.md index 6ea6f99..da23c30 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -125,6 +125,12 @@ - voltex_ai: A* pathfinding on triangle graph (center-point path) - voltex_ai: Steering behaviors (seek, flee, arrive, wander, follow_path) +### Phase 8-3: Lua Scripting +- voltex_script: Lua 5.4 내장 빌드 (cc crate) +- voltex_script: Lua C API FFI 바인딩 +- voltex_script: LuaState 안전 래퍼 (exec, exec_file, register_fn, globals) +- voltex_script: 기본 바인딩 (voltex_print) + ### Phase 8-2: Networking Foundation - voltex_net: Packet protocol (Connect, Accept, Disconnect, Ping, Pong, UserData) - voltex_net: Binary serialization/deserialization @@ -144,10 +150,11 @@ crates/ ├── voltex_physics — Collider, ContactPoint, BvhTree, RigidBody, detect_collisions, physics_step, raycast ├── voltex_audio — AudioClip, WAV parser, mixing, WASAPI backend, AudioSystem, MixGroup, spatial ├── voltex_ai — NavMesh, A* pathfinding, steering behaviors -└── voltex_net — UDP packets, NetServer, NetClient +├── voltex_net — UDP packets, NetServer, NetClient +└── voltex_script — Lua 5.4 FFI, LuaState, scripting bindings ``` -## 테스트: 236개 전부 통과 +## 테스트: 245개 전부 통과 - voltex_asset: 14 - voltex_audio: 35 (audio_clip 2 + wav 5 + mixing 11 + audio_system 2 + spatial 8 + mix_group 7) @@ -157,6 +164,7 @@ crates/ - voltex_platform: 3 - voltex_ai: 15 (navmesh 4 + pathfinding 5 + steering 6) - voltex_net: 8 (packet 7 + integration 1) +- voltex_script: 9 (state 8 + bindings 1) - voltex_renderer: 33 (20 + SSGI 3 + RT 3 + bloom 3 + tonemap 4) ## Examples (11개) @@ -173,7 +181,7 @@ crates/ - audio_demo — 사인파 오디오 재생 - deferred_demo — 디퍼드 렌더링 + 다중 포인트 라이트 -## 다음: Phase 8-3 (스크립팅) / 8-4 (에디터) — Stretch Goal +## 다음: Phase 8-4 (에디터) — Stretch Goal 스펙 참조: `docs/superpowers/specs/2026-03-24-voltex-engine-design.md` diff --git a/docs/superpowers/specs/2026-03-25-phase8-3-scripting.md b/docs/superpowers/specs/2026-03-25-phase8-3-scripting.md new file mode 100644 index 0000000..74abb1f --- /dev/null +++ b/docs/superpowers/specs/2026-03-25-phase8-3-scripting.md @@ -0,0 +1,133 @@ +# Phase 8-3: Lua Scripting — Design Spec + +## Overview + +`voltex_script` crate를 신규 생성한다. Lua 5.4 소스를 내장 빌드하고, FFI로 Lua C API를 호출하는 안전한 래퍼를 구현한다. + +## Scope + +- Lua 5.4 소스 내장 (cc crate로 빌드) +- Lua C API FFI 선언 +- LuaState 안전한 래퍼 (exec, exec_file, 글로벌 변수 읽기/쓰기) +- Rust 함수를 Lua에 등록 (register_fn) +- 기본 바인딩 (voltex_print) + +## Out of Scope + +- 핫 리로드 (파일 변경 감지) +- 엔진 API 노출 (ECS, 물리 등) +- Lua 테이블 ↔ Rust 구조체 변환 +- 코루틴 지원 +- 에러 핸들링 고도화 + +## Module Structure + +``` +crates/voltex_script/ +├── Cargo.toml +├── build.rs — cc::Build로 Lua 5.4 컴파일 +├── lua/ — Lua 5.4 소스코드 (.c, .h) +└── src/ + ├── lib.rs + ├── ffi.rs — Lua C API extern 선언 + ├── state.rs — LuaState 래퍼 + └── bindings.rs — 기본 Rust→Lua 바인딩 +``` + +## Dependencies + +- `cc` (build dependency) — C 소스 컴파일 + +## Lua 5.4 소스 내장 + +lua/ 디렉토리에 Lua 5.4.7 소스코드를 배치. build.rs에서 cc::Build로 컴파일. + +제외 파일: lua.c (standalone interpreter), luac.c (standalone compiler) — main() 충돌 방지. + +Windows: `LUA_USE_WINDOWS` 또는 기본값 사용. + +## Types + +### ffi.rs + +```rust +pub enum lua_State {} +pub type lua_CFunction = unsafe extern "C" fn(*mut lua_State) -> c_int; +pub type lua_Number = f64; +pub type lua_Integer = i64; +``` + +핵심 함수들: +- luaL_newstate, luaL_openlibs, lua_close +- luaL_dostring, luaL_loadfilex +- lua_pcallk (lua_pcall 매크로 대체) +- lua_pushnumber, lua_pushstring, lua_pushcclosure +- lua_tonumberx, lua_tolstring +- lua_setglobal, lua_getglobal +- lua_gettop, lua_settop +- lua_type, lua_typename + +### LuaState + +```rust +pub struct LuaState { + state: *mut ffi::lua_State, +} +``` + +- `new() -> Self` — luaL_newstate + luaL_openlibs +- `exec(code: &str) -> Result<(), String>` — luaL_dostring, 에러 시 스택 메시지 반환 +- `exec_file(path: &str) -> Result<(), String>` — luaL_loadfilex + lua_pcall +- `register_fn(name: &str, f: ffi::lua_CFunction)` — lua_pushcclosure + lua_setglobal +- `get_global_number(name: &str) -> Option` — lua_getglobal + lua_tonumberx +- `get_global_string(name: &str) -> Option` — lua_getglobal + lua_tolstring +- `set_global_number(name: &str, value: f64)` — lua_pushnumber + lua_setglobal +- `set_global_string(name: &str, value: &str)` — lua_pushstring + lua_setglobal +- `Drop` — lua_close + +unsafe impl Send for LuaState {} (Lua state는 단일 스레드에서만 사용) + +### bindings.rs + +```rust +pub fn register_default_bindings(lua: &LuaState) +``` + +기본 바인딩: +- `voltex_print(msg)` — Rust println!으로 출력 +- `voltex_log(msg)` — 로그 + +## build.rs + +```rust +fn main() { + let mut build = cc::Build::new(); + build.include("lua"); + + for entry in std::fs::read_dir("lua").unwrap() { + let path = entry.unwrap().path(); + if path.extension().map_or(false, |e| e == "c") { + let name = path.file_name().unwrap().to_str().unwrap(); + if name != "lua.c" && name != "luac.c" { + build.file(&path); + } + } + } + + build.compile("lua54"); +} +``` + +## Test Plan + +### state.rs +- LuaState 생성/삭제 (new + drop) +- exec 간단한 코드 ("x = 1 + 2") +- exec 에러 코드 → Err +- get_global_number: Lua에서 설정한 변수 읽기 +- set_global_number + get: 라운드트립 +- get_global_string: 문자열 변수 +- register_fn: Rust 함수 등록 후 Lua에서 호출 + +### bindings.rs +- voltex_print 호출 (크래시 없이 실행)