Files
integration/CLAUDE.md
2026-03-08 21:28:47 -04:00

121 lines
7.5 KiB
Markdown

# Integration Project
This is **Luprex**, a game engine built on top of Unreal that uses Lua as its scripting language.
The system consists of two parts:
1. The Luprex DLL. Stores the state of the world. Handles networking and lua scripting. The networking is automatic, scripters don't write networking code. The luprex DLL is event-driven, deterministic, OS-independent, no I/O. Pure standard-compliant C++. Organized as a library with struct `EngineWrapper` as the top-level API.
2. The Unreal-based Driver. Its job is to peer into the luprex DLL and render whatever it sees. It is also responsible for sending OS events (like TCP/IP events) into the Luprex DLL. Uses struct EngineWrapper access the Luprex DLL. There's also a command-line driver for the game's server.
The luprex DLL never calls into the Unreal driver. Output goes through polled buffers. This separation enables deterministic replay for debugging: the driver logs all events, and can replay them to reproduce crashes.
## Build System
- Use `build.py` for all builds. Do NOT follow Epic's standard build instructions.
- `build.py all` — full rebuild (engine, game, intellisense, project files)
- `build.py c++` — lightweight rebuild (only if you've only edited C++ files in this repo)
- Lua and Blueprint edits don't require a rebuild.
## Directory Structure
- `luprex/` — The Luprex DLL.
- `Source/Integration/` — Game module C++ source (Unreal-side driver code)
- `Content/` — Unreal assets
- `Docs/` — Documentation. When trying to understand this system, start with the markdown files in the Docs directory.
- `Config/` — Unreal config files
- `EnginePatches/` — Custom engine modifications
## Architecture: World Models and Predictive Reexecution
There are four types of world models, each a separate `World` instance with its own Lua interpreter:
- **Master** (server, one) — authoritative state, executes commands immediately when they arrive.
- **Server-synchronous** (server, one per client) — executes commands when the acknowledgement is issued.
- **Client-synchronous** (client, one) — executes commands when the same acknowledgement arrives; determinism keeps it in perfect sync with its server-synchronous counterpart.
- **Asynchronous** (client, one) — snapshot of client-synchronous with predictions applied for responsive rendering; rolled back when server confirms.
The synchronous models lag behind the master but stay in lockstep with each other. The asynchronous model fills the latency gap for the player.
Two update channels flow into the synchronous models:
1. **Command acknowledgements** — for the client's own actions, keeping the two synchronous models in lockstep.
2. **Difference transmission** — for everything else (other players' actions, server-side events, tangibles entering/leaving visibility).
See `Docs/Predictive-Reexecution.md` for the full explanation.
## Architecture: Lua / Unreal Separation
Lua scripts have no access to the Unreal API whatsoever. The scripter works with plain Lua tables, animation queues of key-value tuples, and coroutines. There are no "unreal bindings." The Luprex DLL is engine-agnostic — Unreal (or any other front end) interprets the animation queues and renders accordingly.
Small concessions to reality exist in animation step tuples:
- `bp` — names which Tangible Actor blueprint to use for rendering
- `mat_color` — a persistent value that hints at material color
These are still just key-value data; the script never touches the Unreal API directly.
## Architecture: Tangibles
Tangibles are game objects. Each has:
- A **Lua table** — the scripter stores arbitrary game data here.
- An **animation queue** — a fixed-length sequence of key-value animation steps.
- A **C++ tangible** — holds the ID, animation queue, positional tracker, etc.
- A **metatable** — engine-reserved; contains __id, __index (class), __threads.
Animation steps contain **transient** values (like `action`) that don't propagate, and **persistent** values (like `xyz`, `facing`, `plane`) that carry forward automatically.
On the Unreal side, **Tangible Actor blueprints** (TangibleStaticMesh, TangibleSkeletalMesh, TangibleCharacter) monitor the animation queue and perform the visual animations. Custom blueprints can interpret the queue in any way they want.
## Architecture: Lua Environment
- **Patched Lua runtime** — deterministic table iteration, deterministic table length, flag bits on tables, generalized less-than, C++ exceptions instead of longjmp, and more. See `Docs/A-Summary-of-our-Lua-Patches.md`.
- **LuaStack API** — custom C++ API replacing the standard Lua C API. Uses `LuaDefStack`/`LuaExtStack` with `LuaArg`/`LuaVar`/`LuaRet` slots mapped to stack positions. See `Docs/Our-In-House-Lua-API.md`.
- **LuaDefine macro** — declares Lua-callable C++ functions and auto-registers them in a global registry for automatic insertion into the Lua environment.
- **eng::malloc heap** — custom deterministic memory allocator for the driven portion, ensuring reproducible addresses during replay.
## Architecture: Determinism
The driven portion must be fully deterministic so that synchronous models stay in lockstep and event replay works. Rules: no true random numbers, no iterating unordered maps, no real-time clocks, no threads (with carefully sandboxed exceptions). See `Docs/The-Event-Driven-Structure-of-the-Engine.md`.
## Architecture: GUI System
Blueprints call into Lua via two mechanisms:
- **Invokes** — change world state, forwarded to server, executed in order per predictive reexecution rules.
- **Probes** — read-only, return data to blueprints, run locally on client.
Look-at widgets, hotkeys, and menus are built on top of this. The menu system is implemented entirely in "user space" Lua and blueprint code. See `Docs/Displaying-Widget-Blueprints.md`.
## Blueprint Text Export
Blueprints are automatically exported to readable text files in `Saved/BlueprintExports/` whenever they are saved in the editor. This lets Claude Code read blueprint logic. See `Docs/Blueprint Text Export.md` for format details. Source: `Source/Integration/BlueprintExporter.h/.cpp` and `Source/Integration/Integration.cpp`.
## Key Documentation
Look in the Docs directory for important documentation.
## Git
Do not use git to make changes (commit, push, branch, etc.). Read-only git commands (status, log, diff, etc.) are fine.
## Workflow
- When the user gives a direct command, execute it. But when proposing changes on your own initiative, describe the plan and get approval before editing files.
- If an instruction ends with an ellipsis (`...`), the user has more to say. Wait for the next message before acting.
## Coding Conventions
- Prefer early returns and `continue` to reduce nesting (never-nester style).
- Do not use static functions in Unreal code. Use class methods or namespace-scoped functions instead.
- Use `LogLuprexIntegration` for log messages, not `LogTemp`.
- When writing UFUNCTIONs that take an `AActor*`, `UObject*`, or similar "self" parameter, add `DefaultToSelf` meta to that pin. Most functions should have this on the obvious pin so the user doesn't have to manually wire it in blueprints.
## Session Startup
At the beginning of every session, do a directory listing of these three directories so you know what files are available:
- `Docs/` — documentation
- `Source/Integration/` — Unreal-side C++ code
- `luprex/cpp/core/` — Luprex DLL core C++ code
These two code directories contain 99% of the code we'll be working on together.
## Current Status
(Use this section to track what we're working on across sessions.)