Files
integration/CLAUDE.md

119 lines
7.7 KiB
Markdown
Raw Normal View History

# Integration Project
Unreal Engine 5.5.4 game project running on Linux (PopOS). This is **Luprex**, a game engine built on top of Unreal that uses Lua as its scripting language. The engine handles multiplayer networking automatically so scripters don't write networking code.
## 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.
- Do not edit `Integration.uproject` directly — edit `Integration.uproject.tpl.json` instead, then run `build.py`.
- Do not run builds yourself. The IDE builds automatically when the user runs the code.
## Project Structure
- `Source/Integration/` — Game module C++ source (Unreal-side driver code)
- `Content/` — Unreal assets
- `luprex/` — The Luprex DLL (driven portion of the engine)
- `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: Driver / Driven Separation
The engine is split into two halves:
- **Driven portion (Luprex DLL)** — All game logic. Deterministic, OS-independent, no I/O. Pure standard-compliant C++. Organized as a library with class `DrivenEngine` as the top-level API.
- **Driver (EXE or Unreal integration)** — Handles all I/O (sockets, files). Feeds events into the driven portion via `struct EngineWrapper`, a pure C interface of function pointers. There's a command-line driver and an Unreal driver.
The driven portion never calls into the 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.
## 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`.
## Key Documentation
- `Docs/Predictive Reexecution.md` — how the four world models stay in sync
- `Docs/The Event-Driven Structure of the Engine.md` — driver/driven separation, determinism, replay
- `Docs/Multipass Difference Transmission.md` — the algorithm for syncing Lua table graphs
- `Docs/Animation Queues and Tangible Actors.md` — how blueprints interpret animation queues
- `Docs/Our In-House Lua API.md` — the LuaStack API (LuaDefStack, LuaExtStack)
- `Docs/A Summary of our Lua Patches.md` — all modifications to the Lua runtime
- `Docs/Major Data Structures.md` — World, tangibles, threads, classes, source database
- `Docs/Displaying Widget Blueprints.md` — GUI system (invokes, probes, look-at widgets, menus)
- `Docs/Global Variables.md` — different types of global data and their transmission rules
- `Docs/Correct Implementation of Blocking Operations and NoPredict.md` — how to handle blocking ops
- `Docs/Difference Transmission with Threads.md` — why concurrent diff transmission is hard
## Blueprint Coding Conventions
- 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.)