From 89815bcd13514a475af7dd3ccacb6a5207444537 Mon Sep 17 00:00:00 2001 From: jyelon Date: Tue, 31 Mar 2026 17:38:52 -0400 Subject: [PATCH] Config files for claude and codex --- AGENTS.md | 120 +++++++++++++++++ CLAUDE.md | 121 +----------------- .../Source/UEWingman/Handlers/UserManual.h | 2 +- .../Source/UEWingman/Private/WingManual.cpp | 61 ++++----- .../Source/UEWingman/Public/WingManual.h | 4 +- 5 files changed, 151 insertions(+), 157 deletions(-) create mode 100644 AGENTS.md mode change 100644 => 120000 CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..e90ded11 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,120 @@ +# 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.) diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index e90ded11..00000000 --- a/CLAUDE.md +++ /dev/null @@ -1,120 +0,0 @@ -# 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.) diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 00000000..47dc3e3d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/UserManual.h b/Plugins/UEWingman/Source/UEWingman/Handlers/UserManual.h index 675671a8..0ab772dd 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/UserManual.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/UserManual.h @@ -18,6 +18,6 @@ public: virtual void Handle() override { - WingManual::PrintManual(WingManual::AllSections(), nullptr, false); + WingManual::PrintManual({WingManual::Section::All}, nullptr, false); } }; diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingManual.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingManual.cpp index 7926eb18..2c3e0e11 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingManual.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingManual.cpp @@ -3,19 +3,6 @@ #include "WingHandler.h" #include "WingTypes.h" -TSet WingManual::AllSections() -{ - return { - Section::Paths, - Section::Types, - Section::ParameterLists, - Section::EscapeSequences, - Section::Whitespace, - Section::MaterialEditing, - Section::ImportantCommands, - }; -} - void WingManual::PrintHandlerPrototype(UClass *HandlerClass) { UWingServer::Print(WingUtils::GetHandlerName(HandlerClass)); @@ -80,17 +67,19 @@ void WingManual::PrintManual(TSet
Sections, UClass *Handler, bool Abrid if (Sections.IsEmpty()) return; + const bool bPrintAll = Sections.Contains(Section::All); + if (Abridged) { UWingServer::Printf(TEXT("\n--- AUTOMATIC DOCUMENTATION ---\n")); } - if (Sections.Contains(Section::HandlerHelp)) + if (Sections.Contains(Section::HandlerHelp) || bPrintAll) { PrintHandlerHelp(Handler); } - if (Sections.Contains(Section::Paths)) + if (Sections.Contains(Section::Paths) || bPrintAll) { if (Abridged) { @@ -136,7 +125,7 @@ void WingManual::PrintManual(TSet
Sections, UClass *Handler, bool Abrid } } - if (Sections.Contains(Section::Types)) + if (Sections.Contains(Section::Types) || bPrintAll) { if (Abridged) { @@ -170,38 +159,42 @@ void WingManual::PrintManual(TSet
Sections, UClass *Handler, bool Abrid } } - if (Sections.Contains(Section::ParameterLists)) + if (Sections.Contains(Section::VariableDeclarations) || bPrintAll) { if (Abridged) { UWingServer::Print(TEXT( - "\n PARAMETER LISTS: Here is an example parameter list:" - "\n double D,PlayerController P,Array A" - "\n" + "\n VARIABLE DECLARATIONS: example variable declarations:" + "\n Array Actors" + "\n Float F (InstanceEditable)" + "\n String S = This is the default value" )); } else { UWingServer::Print(TEXT( - "\n PARAMETER LISTS:" + "\n VARIABLE DECLARATIONS:" "\n" - "\n Parameter lists (including function arguments and function return" - "\n values) are expressed as comma-separated lists of type-name pairs:" + "\n We have our own syntax for variable declarations: a type," + "\n a name, optional flags, and an optional default value," + "\n always on one line:" "\n" - "\n Double D,PlayerController P,Array A" + "\n Array Actors" + "\n Float F (InstanceEditable)" + "\n String S = This is the default value" "\n" - "\n To change the arguments or return values of a function, edit the" - "\n entry or exit node of the graph using GraphNode_SetArgs." - "\n You can view the arguments using GraphNode_Dump. If a return " - "\n node doesn't exist, you may have to create it using GraphNode_Create" - "\n before you can set return values. Custom event nodes also have" - "\n editable arguments." + "\n The commands Variables_Create, Variables_Modify," + "\n and Variables_Remove can be used to edit: " + "\n blueprint variables, graph local variables, graph input" + "\n variables, graph output variables, and custom" + "\n event node input variables. Event dispatchers are" + "\n also graphs, so they too can be edited." "\n" )); } } - if (Sections.Contains(Section::EscapeSequences)) + if (Sections.Contains(Section::EscapeSequences) || bPrintAll) { if (Abridged) { @@ -245,7 +238,7 @@ void WingManual::PrintManual(TSet
Sections, UClass *Handler, bool Abrid } } - if (Sections.Contains(Section::Whitespace)) + if (Sections.Contains(Section::Whitespace) || bPrintAll) { UWingServer::Print(TEXT( "\n ABOUT WHITESPACE:" @@ -256,7 +249,7 @@ void WingManual::PrintManual(TSet
Sections, UClass *Handler, bool Abrid )); } - if (Sections.Contains(Section::MaterialEditing)) + if (Sections.Contains(Section::MaterialEditing) || bPrintAll) { if (Abridged) { @@ -283,7 +276,7 @@ void WingManual::PrintManual(TSet
Sections, UClass *Handler, bool Abrid } } - if (Sections.Contains(Section::ImportantCommands)) + if (Sections.Contains(Section::ImportantCommands) || bPrintAll) { UWingServer::Print(TEXT( "\n COMMANDS YOU SHOULD KNOW ABOUT AND REMEMBER:" diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingManual.h b/Plugins/UEWingman/Source/UEWingman/Public/WingManual.h index f941e95d..eea7a7ab 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingManual.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingManual.h @@ -6,17 +6,17 @@ class WingManual public: enum class Section { + All, HandlerHelp, Paths, Types, - ParameterLists, + VariableDeclarations, EscapeSequences, Whitespace, MaterialEditing, ImportantCommands, }; - static TSet
AllSections(); static void PrintHandlerPrototype(UClass *Handler); static void PrintHandlerArguments(UClass *Handler); static void PrintHandlerDescription(UClass *Handler);