# PS_ProserveEditor - Project Guidelines ## Project Overview Unreal Engine 5.5 project with runtime editor plugin (PS_Editor). The plugin enables runtime scene editing in packaged builds: object placement, property editing, scenario definition, splines, lighting, and JSON scene save/load. ## Architecture - **Plugin**: PS_Editor (runtime plugin, must work in packaged builds) - **UI**: UMG driven by C++ (Slate) - **Gizmos**: Custom actor with BasicShapes + unlit material (InteractiveToolsFramework is editor-only) - **Serialization**: JSON via Json/JsonUtilities modules (FJsonObjectConverter) - **Input**: Enhanced Input system (AZERTY: arrows + A/Q movement, E/R/T modes) ## Editor vs. Gameplay execution boundary — CRITICAL The plugin runs in two distinct modes and it's essential never to leak editor-only code into the gameplay runtime loaded via `UPS_Editor_SceneLoader::LoadScene` (standalone). ### Editor runtime mode Activated when the `APS_Editor_PlayerController` + `APS_Editor_HUD` + `UPS_Editor_MainWidget*` stack is created (typical during authoring — the user is in the runtime editor). - `UPS_Editor_SceneLoader::bIsEditorModeActive == true` - The HUD widget drives property editing, catalogue spawn, save/load, simulate, timeline - Interface methods called **only** by the widget (never in gameplay): - `GetCustomOptionsForProperty` / `GetCustomOptionsWithValuesForProperty` / `GetCurrentDisplayForProperty` - `OnEditorModeChanged`, `OnEditorTick` - `OnEditorNeedsReinit`, `OnEditorNeedsRespawn` ### Gameplay mode The project (PROSERVE) loads a scenario via `UPS_Editor_SceneLoader::LoadScene` from a GameMode BeginPlay, without ever instantiating the editor PlayerController / HUD / widget. - `UPS_Editor_SceneLoader::bIsEditorModeActive == false` - Actors spawn, their properties are applied from JSON, `OnPropertiesLoaded` fires once - The timeline subsystem auto-plays if the scenario has tracks, driven **server-side only** ### Interface methods that fire in BOTH modes - `OnPropertiesLoaded` — after every scene load, editor or gameplay (applied once post-spawn) - `OnEditorPropertyChanged` — fires both in editor (on UI edit via `ApplyPropertyFromUI`) AND in gameplay (on server when the timeline applies a new keyframe value via `TimelineSubsystem::ApplyTrackAtTime`). Despite the name, the "Editor" refers to the PS_Editor plugin — the event is the canonical hook for "a property changed at runtime". In gameplay only the **server** invokes it; client-side reaction must go through `ReplicatedUsing=OnRep_X` RepNotify on the replicated property. ### Rule when adding new features - Anything tied to property panel UI (new interface method, new widget logic, dropdown helpers, etc.) lives in the widget only — no extra work to scope it out of gameplay - Anything added to the `SceneLoader::LoadScene` path runs in gameplay and must handle `NM_Client`, replication, and server-authority correctly (the timeline subsystem is the reference pattern) - Expensive BP implementations of editor-UI interface methods (DataTable lookups, class resolution, etc.) can stay expensive — they never run outside the authoring session ### How to guard code that could run in either mode ```cpp if (UPS_Editor_SceneLoader::IsInEditorMode()) { // editor-only behaviour } ``` or gate on `bIsCurrentlyLoading` to skip BP init during JSON restore. ## UI Modes — IMPORTANT for widget changes The runtime editor ships with **multiple widget implementations** that must all stay in sync: - `PS_Editor_MainWidget.cpp/.h` — modern UMG-based widget (primary target long-term) - `PS_Editor_MainWidget_Legacy.cpp/.h` — Slate-only legacy widget (**currently active** as of April 2026) - `PS_Editor_MainWidget_UMG.cpp/.h` — UMG variant The user can switch between them via a `UIMode` setting. At any given time only one is running, but the project keeps all three compiled. **Rule:** when changing any behavior inside a widget (new interface calls, new property row logic, new UI controls, bug fixes in RebuildDynamicProperties / ApplyPropertyFromUI / RefreshDynamicPropertyValues, etc.), **apply the change to ALL widget implementations at the same time**. Otherwise the user's current UIMode gets the fix and the others don't — the "it's like you didn't change anything" bug. Symptom that the wrong widget was edited: logs you added don't appear in the Output Log despite the build being clean and the DLL being correctly loaded. Always grep for the function name across all `PS_Editor_MainWidget*.cpp` files before assuming a single edit is sufficient. ## Naming Conventions - All plugin files and classes use the `PS_Editor_` prefix (e.g., `PS_Editor_GameMode`, `PS_Editor_Pawn`) - Code and comments in English - Standard UE5 prefixes: `A` for Actors, `U` for UObjects, `F` for structs, `E` for enums, `I` for interfaces ## Code Quality - Prefer correct, complete implementations over minimal ones. - Use appropriate data structures and algorithms — don't brute-force what has a known better solution. - When fixing a bug, fix the root cause, not the symptom. - If something requires error handling or validation to work reliably, include it without asking. ## Workflow — CRITICAL - **Do not make behavior / logic changes without first explaining the plan and waiting for the user's go-ahead.** Explain what the change will be, why it fixes the issue, and what side effects it could have. Only after the user approves (or asks to proceed), apply the edit. - Diagnostic-only additions (temporary `UE_LOG`, read-only inspections) are fine without approval because they can't regress the project. - Refactors, algorithm changes, comportement changes, new defaults, removed features — all require approval first, even when they seem obvious. - When revealing new data (e.g. logs) suggests a fix, STATE the proposed fix in plain words and wait. Don't pre-emptively write + apply the code change in the same turn. ## Build - Engine: Unreal Engine 5.5 - Plugin location: `Unreal/Plugins/PS_Editor/` - Game module: `PS_ProserveEditor` (in `Unreal/Source/PS_ProserveEditor/`) - CLI build command (Editor, Development): ``` "/Engine/Build/BatchFiles/Build.bat" PS_ProserveEditorEditor Win64 Development -Project="/Unreal/PS_ProserveEditor.uproject" -WaitMutex -FromMsBuild ``` UE install path can be found via registry: `HKLM\SOFTWARE\EpicGames\Unreal Engine\5.5` > `InstalledDirectory` ## Project Memory Shared project memory is stored in `.claude/memory/` (versioned in the repository). When starting a new session on any machine, read these files to restore context: - `MEMORY.md` — Index of all memory files with one-line summaries - `project_ps_editor.md` — Project scope, technical decisions, current phase - `feedback_naming.md` — Naming conventions and user preferences - `reference_build.md` — Full build command and UE install path details