Compare commits

..

48 Commits

Author SHA1 Message Date
6eca4fc94b Add editor-only floor cut to hide primitives above the MandatoryAnchor
Per-component visibility/collision toggle gated on bounds-min Z vs
(AnchorZ + Height). Snapshotted before mutation and restored on
disable, so the feature is non-destructive. Wired into the toolbars of
both Slate widgets and exposed as Blueprint methods on the UMG widget.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 12:07:28 +02:00
4a98c6402b Rename LoadScene/LoadSceneAdditive to LoadScenario/UnloadScenario
The old naming suggested UE level loading; what these calls actually do
is spawn actors described by a .pss scenario file into the already-loaded
UE level. Renamed for clarity:

  SceneLoader::LoadScene         -> LoadScenario
  SceneLoader::LoadSceneFromData -> LoadScenarioFromData
  SceneLoader::LoadSceneAdditive -> dropped (merged into LoadScenario)
  SceneLoader::UnloadSceneAdditive -> UnloadScenario
  SceneSerializer::LoadScene     -> LoadScenario
  AdditiveSpawnedActors          -> TrackedSpawnedActors

LoadScenario now branches on the filter: when Filter == PreloadOnly the
timeline subsystem is skipped entirely (no SetData, no ActorId
registration, no auto-play) so a briefing scene can drop in player
placement markers without disturbing its own timeline. All other filter
values keep the full gameplay behaviour (timeline + AI-readiness poll).

Every load tracks its actors so a follow-up UnloadScenario() can destroy
them — supports the briefing flow where the player toggles between
scenarios at runtime.

Breaking change for external BP callers: any node binding the old
LoadScene / LoadSceneAdditive / UnloadSceneAdditive functions will show
up as missing on next BP compile; replace with LoadScenario /
UnloadScenario (identical or simpler signatures).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 15:42:57 +02:00
f6efc00c73 Add LoadSceneAdditive / UnloadSceneAdditive for briefing scene preload
Lets a briefing scene materialize only the preload-tagged actors from a
scenario .pss (player placement markers, briefing props) without
clearing the current world, pushing timeline data, registering ActorIds,
or starting any auto-play. The actors spawned by each LoadSceneAdditive
call are tracked in a static TWeakObjectPtr array; UnloadSceneAdditive
destroys every still-valid one and clears the array.

Typical BP usage on scenario change:
  UnloadSceneAdditive(this) -> LoadSceneAdditive(this, NewSceneName)

No BP-side bookkeeping required. Filter defaults to PreloadOnly which
matches the intended briefing use case; the parameter stays exposed for
other niche cases (ExcludePreload, All).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 15:10:52 +02:00
34280de44a Update memory notes for UE 5.7 host project (was 5.5)
Host project migrated from PROSERVE_UE_5_5 to PROSERVE_UE_5_7 in April
2026. CLAUDE.md, memory index, project notes, and build reference now
point at the new path / target / engine version. The 5.5 host is
flagged deprecated to avoid accidental builds against it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 15:09:17 +02:00
ac91e4e8f9 Bug Fix 2026-05-06 17:53:21 +02:00
c7ec3e9653 Per-scenario type field driven by project enum (Settings dropdown + JSON peek)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 19:04:59 +02:00
d9ed016297 Reset bIsEditorModeActive on editor-PC EndPlay and SceneLoader entry
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 13:28:39 +02:00
67ac3ffab7 Demote diagnostic logs to Verbose + drop redundant ones
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 23:29:36 +02:00
8f7476d2db Mandatory actors auto-spawn + navmesh surface overlay (custom material)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 16:14:27 +02:00
b9ec67f9ff Runtime nav settings + custom debug viz (P key) + editable restore on stop
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 11:46:27 +02:00
2a53d12e68 Per-scenario dynamic nav opt-in + Settings popup + timeline restore fixes
Dynamic navigation toggle (per scenario):
- New PS_Editor_NavUtils helpers wrap UNavigationSystemV1 / RecastNavMesh
  protected APIs (RuntimeGeneration field + bEnableDrawing) via the C++
  using-trick so we can switch the level's nav mode and toggle visualization
  without engine modifications.
- FPS_Editor_SceneData gets bUseDynamicNavigation persisted in JSON.
- SpawnManager carries the live state plus a session-only bShowNavMesh
  preference (never saved).
- SceneSerializer reads/writes the flag and applies it on load (editor mode).
- SceneLoader applies it on the gameplay path before spawning actors so
  scenarios that need runtime nav rebuild get it both in editor and at
  runtime via the project's GameMode + SceneLoader::LoadScene flow.

UI:
- New "Settings" toolbar button in both Legacy and UMG widgets opens a popup
  with two checkboxes:
    * Use Dynamic Navigation - saved per scenario, live toggle
    * Show NavMesh (P) - session only, mimics editor's P key (green nav
      visualization)
- Pawn binds P to IA_ToggleNavMesh -> SpawnManager.bShowNavMesh, in sync
  with the popup checkbox.

Timeline restore correctness:
- AddOrUpdateKeyAtCurrentTime, RemoveKey, SetKeyTime, SetKeyInterpolate now
  invalidate LastAppliedValues[TrackIndex] so a key edit isn't masked by a
  stale per-track cache entry from a previous apply.
- RestoreBaseline now prefers a key at t=0 (within epsilon) over the
  captured pre-animation baseline. Updating a t=0 key + Stop now restores
  the new value instead of snapping back to the original. Tracks without a
  t=0 key still fall back to the pre-animation baseline.

Restart simulation rewind:
- Restart() used to call Stop() + Play() but Play immediately cancelled the
  pending RequestStopSimulation timer set by Stop, so transforms were never
  restored - characters stayed where they were.
- RequestStopSimulation now takes bImmediate; when true, OnEditorBeforeSimulateStop
  still fires (so BP behaviour-reset hooks run) but StopSimulation runs
  synchronously, restoring transforms before Play() recaptures them.
- Restart inlines the reset (RestoreBaseline + immediate stop + Play) so
  rewinding actually rewinds.

Build:
- Re-add NavigationSystem to PS_Editor.Build.cs (needed for ARecastNavMesh
  + ANavigationData access in NavUtils).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 10:40:18 +02:00
49cb480e15 Add F key to frame the current selection (Maya/Blender style)
Pressing F computes the combined bounding box of every selected actor,
then animates the camera over 0.25s (smoothstep ease) to a distance that
fits the box in view while keeping the current viewing direction. The
orbit focal point and distance are synced so a subsequent Alt+drag
pivots around the new center.

No-ops cleanly when nothing is selected. Falls back to actor pivots
when no component reports valid bounds, and clamps the radius to a
minimum so point-like actors don't pull the camera onto them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 18:00:54 +02:00
7f2600f0b8 ChildMovable: rotation support + ChildMovable-aware help bar + clear previous highlight
- IPS_Editor_ChildMovable gains GetChildRotation / RotateChild and the
  GetAll/SetAll rotation pair for undo snapshots. BP impls can clamp axes
  (e.g. Yaw-only) inside RotateChild.
- Pawn captures initial rotations at gizmo drag start and applies the
  rotate gizmo's delta-quat onto the active child only (no longer
  rotating every selected actor when a child handle is active).
- FPS_Editor_SplinePointAction carries optional Old/NewRotations arrays
  applied alongside positions on Undo/Redo for ChildMovable actors.
- Pawn now calls ClearChildHighlight before HighlightChild so picking a
  new child no longer leaves the previous one stuck in highlight state.
- MainWidget + Legacy widget detect when ActivePlacementActor is a
  ChildMovable in SplinePlacement mode and swap the help bar text
  ("CHILDREN: ...") + hide the irrelevant Delete-point button.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 16:07:39 +02:00
c520f3ccd9 Group BP interface functions under "PS Editor|Editable" / "PS Editor|Child Movable"
The two BlueprintNativeEvent interfaces previously dumped every function
into a flat "PS Editor" category, so the BP class members panel listed
them all together. Use the pipe-separated category to put each interface
under its own submenu.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 13:44:25 +02:00
2f8633d23b Flatten BP categories: drop "ASTERION|" prefix and inner-struct categories
Two cleanups in one pass:

1. Replace `Category = "ASTERION|PS_Editor"` (and its sub-pipe variants like
   "...|Timeline", "...|Spline", "...|UI", "...|Child Movable") with a single
   flat `Category = "PS_Editor"` everywhere — UFUNCTIONs and class-level
   UPROPERTYs alike. The pipe-separated hierarchy was redundant (the plugin
   already lives in a "PS_Editor" namespace), and the BP right-click search
   gets a cleaner single-segment grouping.

2. Drop the `Category` attribute from struct field UPROPERTYs in
   FPS_Editor_SpawnEntry, FPS_Editor_BaseLevelEntry, and
   FPS_Editor_EditablePropertyEntry. Struct fields don't need a category —
   they inherit display from the parent property's category. Keeping a
   category on inner fields was causing the SpawnCatalog details panel to
   render the Entries array TWICE (once under the literal "ASTERION|PS Editor"
   header pulled from the inner ActorClass field, once under the proper
   "ASTERION > PS_Editor" hierarchy from the outer Entries property).

Also normalize the two `UCLASS(ClassGroup = "ASTERION|PS Editor")` declarations
on EditableComponent and SpawnableComponent to `ClassGroup = "PS Editor"` for
consistency.

Touches 13 header files; no behavior change — Categories are purely cosmetic
(Details panel grouping, BP right-click menu organization).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 15:43:34 +02:00
98de4dff6f Document PIE-only nav quirk: AI testing requires Standalone Game
Several attempts were made to fix a PIE-specific RecastNavMesh registration
failure that occurs when the editor's "Play" button calls OpenLevel(BaseLevel)
from inside a PIE session — the level's RecastNavMesh ends up pending-kill
and UE silently substitutes an empty AbstractNavData fallback, breaking AI
pathfinding. Workarounds tried (and reverted): cascading re-registrations
through RegisterNavData / OnInitializeActors / AddNavigationSystemToWorld /
Build / SpawnMissingNavigationData; intermediate transition map; duplicated
BaseLevel sublevel suffixed _default. None worked — the cause is internal
to PIE's OpenLevel handling.

Standalone Game and packaged builds initialize the nav system correctly,
so production is unaffected. Document the workflow so future contributors
don't waste time chasing this PIE-only bug.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 12:38:03 +02:00
b51f063d52 Pivot-anchor fallback for no-collision spawns + always-snap on catalog
Ground snap:
- When an actor has no colliding components at all (e.g. a VR start
  marker, placement helper, or any BP whose collision is only enabled
  on entering editor mode), SnapActorToGround now anchors the PIVOT
  directly on the ground instead of falling back to the full-bounds
  bbox bottom. The full-bounds bottom could be far below the pivot
  (helper meshes, arrows, visual markers) and was lifting objects
  hundreds of units into the air.
- Actors with collision keep the original behavior (collision-bbox
  bottom rests on the ground).

Catalog spawn:
- Always snap to ground (drop the bAutoSnapToGround gate) — a user
  clicking in the catalog expects the object to land on the ground
  every time; the flag is kept for gameplay-side spawning via
  SceneLoader.
- SpawnActor now uses AlwaysSpawn instead of
  AdjustIfPossibleButAlwaysSpawn so UE never pushes the actor
  vertically to resolve overlaps — SnapActorToGround is the
  authoritative placement step.

CLAUDE.md workflow rule:
- Document that behavior / logic changes require explaining the plan
  first and waiting for go-ahead; only diagnostic-only additions
  (temporary UE_LOG) are fine without approval.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 12:53:01 +02:00
93b9c7d927 template demo 2026-04-24 10:44:44 +02:00
050ea4eb2f Gizmo follow, cooker-friendly assets, and proper ground snapping
Gizmo usability:
- Refresh the gizmo every tick while simulation is running so it glues to
  animated / AI-driven / timeline-driven actors instead of freezing at the
  pose they had when selected
- Clear the pawn's active sub-element drag state on FinishPointPlacement /
  CancelPointPlacement — previously, after clicking Done on a spline, the
  gizmo jumped to the center cube but the internal ActiveSplinePointIndex
  stayed on the last clicked CP, so dragging the gizmo moved that CP
  instead of the whole actor
- Expose UpdateGizmo() publicly on the SelectionManager so the
  PlayerController Tick can drive it

Package cooking (fix gray gizmos / missing outline in packaged builds):
- Convert every runtime LoadObject<> soft-string path into a UPROPERTY
  TObjectPtr<> filled via ConstructorHelpers::FObjectFinder at CDO
  construction time. Hard refs are picked up by the cooker so plugin
  Content assets (M_PS_Editor_Gizmo, M_PS_Editor_SelectionOutline,
  M_PS_Editor_SplineLine, and the engine basic shapes the spline actor
  uses) are reliably staged
- Touches APS_Editor_Gizmo, APS_Editor_Pawn (outline post-process
  material), APS_Editor_SplineActor (gizmo material, spline line
  material, center cube mesh, handle sphere mesh)

Ground placement (PS_Editor_GroundSnap):
- New PS_Editor_GroundSnap utility centralising placement logic for
  catalogue spawns, End-key snap-to-ground, and spline CP placement
- ProjectCameraRayToGround: aim down from a point in front of the camera
  when the camera ray misses (no more "looking at sky spawns object in
  mid-air"); classify the primary hit by normal to re-cast from below a
  ceiling / step back from a wall so the object lands on the floor
  underneath / at the foot of the surface rather than embedded in it
- SnapActorToGround: start the downward ray from INSIDE the actor's
  volume (pivot + small buffer), ignoring the actor itself — avoids the
  "raised a bit high, pressed End, teleports to upper story" bug where
  starting above the actor's bbox could cross the current room's ceiling
  and find the upper floor as the first floor-like surface
- Uses GetActorBounds(bOnlyCollidingComponents=true) with a fallback so
  characters snap from their capsule bounds rather than bbox including
  non-colliding meshes / attached weapons / child actors that used to
  lift pawns into the air
- Multi-hit trace + normal.Z >= 0.3 filter skips walls, ceilings, and
  backfaces when finding the first true floor below

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 10:43:45 +02:00
9877c1b6de Fix (missing) timeline tracks + lost editable properties on 2nd scene load
FindActorById now skips stale TWeakObjectPtr entries instead of returning
the first null match, RegisterActorId prunes stale + same-GUID entries
before adding, and Clear() resets the ActorIds map so a fresh scenario
starts with no ghost references.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 16:08:26 +02:00
721c9bb5c3 Unify simulate/timeline controls + BeforeStop event + AI auto-possess safety net
- Remove the Simulate toolbar button (both Legacy + UMG widgets). Play /
  Pause / Restart / Stop now live exclusively on the Timeline panel, and
  the panel is visible by default (no more toggle button on the toolbar).
  Keeps a global Play button on the Legacy toolbar that opens the level
  outside the editor.

- Move the grace-period / deferred-stop logic out of the TimelineSubsystem
  and into APS_Editor_PlayerController::RequestStopSimulation. This lets
  the timeline Stop button AND the UMG topbar simulate buttons share the
  same event sequence: OnEditorBeforeSimulateStop fires immediately (after
  RestoreBaseline), then a 500ms BT grace period, then StopSimulation
  fires OnEditorSimulateStop and cuts AI. New event
  OnEditorBeforeSimulateStop added to the editable interface with full
  timing docs.

- Drop the early-return in TimelineSubsystem::Play when Tracks.Num()==0 —
  the timeline Play button is now the only way to start the sim, so it
  must drive StartSimulation unconditionally.

- StartSimulation now force-calls SpawnDefaultController() on any pawn
  that enters sim without a Controller but has an AIControllerClass set,
  so AutoPossessAI=Disabled or race-lost possessions don't leave the BT
  unreachable.

- Route the UMG topbar Play / Simulate buttons and the "simulate" command
  through RequestStopSimulation too, so every path emits the full event
  sequence consistently.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 18:52:48 +02:00
e999a11349 Timeline: pre-animation baseline restore on Stop + display cache
Stop now rewinds animated properties to the value they had before the
timeline first acted on them — not "first keyframe's value" as before.

- New per-track baseline stored runtime-only in a TMap keyed by
  (ActorId, PropertyPath), so it survives track reordering and isn't
  persisted to JSON (avoids stale data in legacy scenarios).
- Captured once: at track creation (first "+" on a fresh property) or
  at SetData time for tracks loaded from a scenario. Never re-captured,
  so scrub-then-Play doesn't shift the baseline to whatever the cursor
  happened to be parked on.
- Stop writes the baselines back via ImportText, fires OnEditorPropertyChanged
  + RepNotify per track, then defers the actual StopSimulation by 100ms
  so the BehaviorTree has a grace period to see the restored values via
  OnRep / OnEditorPropertyChanged and transition to a neutral state before
  AI tick is cut.
- Play cancels any in-flight deferred StopSimulation (Restart = Stop +
  Play keeps the simulation running across the handoff).
- SetData and Clear reset the baseline map so loading a new scenario
  doesn't inherit the previous one's baselines.

Also cache GetCurrentDisplayForProperty calls in RefreshDynamicPropertyValues:
the property panel was invoking the BP interface every tick per visible
combo. Now each row stores LastExportedValue + LastDisplayToShow and
short-circuits if the property's exported text is unchanged — BP only
runs on actual value transitions (seek, timeline keyframe, manual edit).
Duplicated across MainWidget and MainWidget_Legacy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 16:13:37 +02:00
bc491b7b94 Display-vs-value custom dropdown options + UI mode parity docs
Extend the EditableInterface with two new BlueprintNativeEvents so property
combos can show human-friendly labels while storing technical values:

- GetCustomOptionsWithValuesForProperty returns TArray<FPS_Editor_PropertyOption>
  where each pair carries a DisplayName (shown in the combo) and a Value
  (written to the property via ImportText). Wins over the legacy flat-string
  variant when non-empty. Ideal for TSubclassOf / TSoftClassPtr properties
  driven by a DataTable lookup where the stored value is a class path.
- GetCurrentDisplayForProperty lets the actor authoritatively resolve the
  DisplayName from the current stored value, for cases where the automatic
  reverse lookup (normalize class path, exact-match) isn't reliable — e.g.
  several Values collapse to the same label, or the format is user-specific.

UI refresh now asks the actor first, then falls back to a normalized match
(strips the `TypeName'...'` wrapper from ExportText output so it compares
apples to apples with a plain /Game/Path.X_C string).

Same logic duplicated across both widget implementations (MainWidget and
MainWidget_Legacy) since the project can switch UI mode at runtime. The new
CLAUDE.md rule makes that requirement explicit.

Also documented in CLAUDE.md:
- Editor-vs-gameplay execution boundary: which interface methods fire where,
  including the gotcha that OnEditorPropertyChanged *does* fire in gameplay
  on the server when the timeline animates a property.
- UI modes: keep all MainWidget* implementations in lockstep to avoid the
  "I edited the file but nothing changed" class of bug.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 12:43:40 +02:00
b069c20af3 Fix character rotation in editor + defer timeline play until AI ready
- Save pawn rotation/movement settings (bUseControllerRotation*, bOrient-
  RotationToMovement, MovementMode) on SpawnableComponent when editor
  disables AI, then restore them exactly in StartSimulation
- Re-apply rotation/movement overrides on StopSimulation so the character
  doesn't auto-rotate after returning from Simulate
- Poll spawned pawns' BrainComponent on scene load (gameplay via
  SceneLoader); start timeline playback only once every AI BT is running.
  Fixes timeline keys firing before the AI-driven sequence (walk) starts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-21 18:27:42 +02:00
d9d358e694 Add ui elements 2026-04-20 07:36:23 +02:00
5b9174bdcd hud 2026-04-18 20:20:57 +02:00
bc226338e0 hud 2026-04-18 20:13:33 +02:00
bdceecbe56 Add 3-way UI mode switch: Legacy / NewSlate / UMG
Introduce a switchable UI stack so the original Slate widget stays available
as a fallback while the new CodeDesign-inspired redesign and a future UMG
Widget Blueprint implementation coexist.

- PS_Editor_MainWidget_Legacy: pre-refactor Slate widget, restored from HEAD
- PS_Editor_MainWidget: refactored floating-HUD Slate widget with style asset,
  9-slice panels/buttons, rounded brushes, icon pack, Play/Pause/Stop icons,
  spec-aligned palette and radii, File dropdown, outliner per-item icons,
  command palette
- PS_Editor_MainWidget_UMG: abstract base class exposing a Blueprint-callable
  API (SetTransformMode, SaveScenario, Simulate, Selection...) and delegates
  (OnToolChanged, OnSelectionChanged...) so a WBP deriving from it can drive
  the editor end-to-end
- APS_Editor_HUD: UIMode enum + UMGWidgetClass soft ref, picks the right
  widget at BeginPlay; separate typed accessors for each flavor

Adds UI style system (UPS_Editor_UIStyleAsset DataAsset + FPS_Editor_UIStyle
helper) with runtime PNG loading for icons and 9-slice brushes from
Content/UI/icons/ and Content/UI/unreal_9slice/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 19:57:04 +02:00
4181801635 Timeline polish + simulate/timeline lockstep + default base level
Timeline behavior:
- Natural end of playback now clamps to Duration and holds values there
  (no auto-rewind, no simulation reset) — symmetric between editor and
  gameplay. New Restart button does the rewind+replay sequence explicitly.
- Pause now freezes character movement too (new SetSimulationPaused on
  the PlayerController stops AI ticks without restoring saved transforms
  the way StopSimulation does).
- Simulate toolbar button is wired through the timeline: with at least one
  track, it toggles Play/Pause; without tracks it falls back to direct
  StartSimulation/StopSimulation. Label stays "Simulate"/"Stop" so it
  doesn't duplicate the timeline panel's own Play button.
- SetKeyTime re-sorts keys; clicking a key selects the animated actor
  exclusively (ClearSelection first) so splines release their handles.
- Seek now invalidates LastAppliedValues: a manual property edit between
  two seeks used to leak onto the next key because the cache made the
  next seek skip the write.
- Keyframe colors are saturated: vivid blue / orange / green / yellow
  instead of the washed-out pastels.

Scene load robustness:
- New LoadActorClassRobust chains TryLoadClass, LoadPackage+retry,
  LoadObject, StaticLoadClass — covers cold BP post-load races that made
  actors silently fail to spawn on the first PIE of a session.
- Failed class loads and null-spawn actors now log Error with class path
  and location; a Warning/Log recap lands at the end of every load.
- Actors that end up hidden or invalid after the pipeline get their own
  Warning/Error lines for post-mortem diagnosis.

Base level handling:
- New bIsDefault flag on FPS_Editor_BaseLevelEntry. The entry marked
  default is loaded automatically at editor startup (when no pending
  scenario is queued) and as fallback when a scenario saved without a
  base level ("Unfiled" folder) is opened.
- Removed the hardcoded "None" option from the base level popup — the
  project defines its own default entry instead (e.g. renamed to "None").
- Previous behavior of LoadBaseLevelAsSublevel("Unfiled") is gone; the
  bogus sublevel load used to leave the loading screen stuck.

Spline visuals:
- SetRenderCustomDepth is now off by default and only turned on while the
  spline is selected — project outline post-process materials no longer
  highlight every loaded spline.
- ImportFromCustomProperties forces SetHandlesVisible(false) and
  SetSelected(false) after setting points (both PS_Editor and
  PS_BehaviorEditor versions) so loaded splines start in the deselected
  visual state.

AI in editor:
- Spawned pawns now get their AI disabled synchronously right after
  SpawnActor (in addition to the existing next-tick fallback) so the BT
  can't drive the character for the 1-frame gap between spawn and timer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:47:45 +02:00
75f54e27c4 Ignore .claude/settings.local.json
Per-user local Claude Code settings have no business being versioned —
remove the previously tracked file and add the path to .gitignore so
local permission changes don't show up in future diffs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 11:32:49 +02:00
4b0a182013 Add global timeline for animating editable properties
New UWorldSubsystem + FTickableGameObject drives per-property keyframe
animation in both the runtime editor and real gameplay (server-side,
replicated to clients via standard UE property replication). Tightly
coupled with Simulate: Play/Pause/Stop also start/stop AI.

Highlights:
- bAnimatable flag on EditablePropertyEntry gates which properties get
  a "+" keyframe button in the runtime editor
- FGuid-based actor IDs in the timeline subsystem survive save/load
- Custom Slate widgets replace SSlider/SButton for pixel-perfect
  alignment between the scrub bar handle and keyframe dots
- Click a key = select actor + seek; drag moves it; Del removes it
- Active key highlighted green; selected key white; auto-deselect when
  the cursor leaves the key time
- Scenes loaded via the standalone SceneLoader auto-play in gameplay;
  SceneSerializer pushes timeline data into the subsystem on load
- SceneData v3 -> v4 (Timeline + per-actor ActorId); legacy scenes
  load cleanly with empty timeline + regenerated GUIDs
- "Unfiled" scenes no longer try to load a bogus sublevel (loading
  screen no longer gets stuck); LoadBaseLevelAsSublevel now has a
  safety net that hides the overlay if LoadLevelInstance fails
- TryLoadClass via FSoftClassPath fixes the intermittent "actors
  disappear on first load" bug (BP class cold-load race)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 11:28:21 +02:00
b08b17d762 Add PS_Editor user documentation (PPTX + PDF)
20-slide presentation covering:
- Plugin architecture (3 modules)
- Main features overview
- Getting started / setup
- Editor UI and workflows
- Spawn catalog, selection, properties
- Splines (generic + AI)
- Scene save/load, base level selection
- Simulate mode, Play & return
- Blueprint interface events
- Network replication
- Keyboard shortcuts & best practices

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 16:30:08 +02:00
4354b8c96e Group all BP categories/components under ASTERION|PS_Editor + fix Content Browser freeze
- All UFUNCTION/UPROPERTY Category prefix changed from "PS Editor" to "ASTERION|PS_Editor"
- Components ClassGroup changed to "ASTERION|PS Editor" (sub-hierarchy in Add Component menu)
- Create Spawnable Blueprint: defer asset loading until menu click
  (was loading all meshes on right-click, causing 30s freeze)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 16:29:41 +02:00
cd43ae6adc Fully disable AI in editor mode via SetActorTickEnabled
- Disable tick on both Pawn and AIController when not simulating
- Stops BT, perception, gaze, and all per-frame logic
- Simulate mode re-enables tick + RestartLogic on all spawned pawns

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 14:38:25 +02:00
13da8293c1 Per-level catalogs, external scenarios dir, .pss extension, BP from mesh tool
- Add per-base-level Catalogs to FPS_Editor_BaseLevelEntry, merged with global
  catalogs when the base level is loaded
- Add SpawnManager::ClearCatalogs() and rebuild on LoadBaseLevelAsSublevel
- Move scenarios storage to C:/Asterion_VR/SCENARIOS/{LevelName}/ for easy
  transfer between client PCs; avoids name conflicts via level subdirectories
- Add GetSceneFilePathForLevel and refactor GetSavedSceneNames to scan subdirs
- Change scenario file extension from .json to .pss with .json legacy fallback
- Add content browser tool: right-click StaticMesh/SkeletalMesh → PS Editor
  section → Create Spawnable Blueprint (generates BP with mesh component,
  SpawnableComponent with pre-filled DisplayName, and EditableComponent)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 12:40:39 +02:00
82e76c01ff Additional sublevels, custom property options, BaseLevel highlight, lightmap fix
- Add AdditionalSublevels to FPS_Editor_BaseLevelEntry for always-loaded
  streaming levels that aren't auto-loaded when base level is a sublevel
- Add LoadBaseLevelAsSublevel overload with ExtraSublevels parameter
- Add GetCustomOptionsForProperty to IPS_Editor_EditableInterface for
  data-driven dropdowns (e.g. weapon lists from DataTables)
- Add custom options combo in property panel (interface-driven, no CachedEnum)
- Add BaseLevel selection highlight: selected card stays highlighted until
  validate or change
- Fix deferred lightmap refresh with 0.5s timer instead of NextTick
- Fix enum detection scope error in RebuildDynamicProperties

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 18:13:38 +02:00
1a2cc87160 Add ChildMovable interface, preload filter, IsInEditorMode, lightmap init
- Add IPS_Editor_ChildMovable interface for per-child editing of sub-elements
  (VR placement spots, etc.) with full gizmo, undo, and serialization support
- Add "Edit Children" button in toolbar when a ChildMovable actor is selected
- Add bPreload tag on SpawnableComponent for briefing/placement phase actors
- Add EPS_Editor_SceneLoadFilter enum (All, PreloadOnly, ExcludePreload) to
  LoadScene for selective loading of preload vs gameplay actors
- Add bPreload field to FPS_Editor_ActorData for JSON persistence
- Add static IsInEditorMode() getter on SceneLoader (BlueprintPure)
- Add Level::InitializeRenderingResources() call on sublevel load for lightmaps
- Update Pawn, PlayerController, UndoManager, SceneSerializer, SceneLoader,
  MainWidget to support ChildMovable alongside existing SplineEditable

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 18:02:17 +02:00
5859d3bf6a BaseLevel selection popup with thumbnail grid
- Add Thumbnail field to FPS_Editor_BaseLevelEntry (UTexture2D)
- Replace BaseLevel combo box with button that opens a selection popup
- Popup displays base levels in a 3-column grid with thumbnails (2:1 ratio)
- Validate/Cancel buttons to confirm or dismiss selection
- Gray placeholder shown for entries without thumbnail

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 08:42:03 +02:00
27ff2e8d8f temp for later 2026-04-14 20:40:06 +02:00
fb95d3b821 Simulate mode: AI start/stop, save lock, position restore
- Simulate button (orange) toggles AI on/off in editor
- StartSimulation: saves all actor transforms, RestartLogic on all BrainComponents
- StopSimulation: StopLogic on all BrainComponents, restores saved transforms
- Save blocked during simulation with help bar message
- AI auto-stopped per-pawn on spawn in editor (deferred next tick for AIController)
- SceneSerializer also stops AI on loaded pawns
- AIModule added to Build.cs dependencies

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 20:29:45 +02:00
16fdcb55da Debounced SplineNetwork rebuild on spline point changes
- ScheduleNetworkRebuild() called after AddPoint, RemovePoint, SetAllPointLocations
- 0.5s debounce timer avoids redundant rebuilds during rapid editing
- AI NPCs now detect and follow splines placed in the editor immediately

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 20:07:22 +02:00
1f11b79222 Auto-call OnRep on server after editor property change + ForceNetUpdate
- After ImportText, automatically call the property's RepNotifyFunc via reflection
- ForceNetUpdate ensures replication to clients (OnRep fires on both server and client)
- No BP changes needed — fully transparent for replicated properties

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 19:50:20 +02:00
6c39b5888f CustomDepth stencil 2 on spline meshes, SplineNetwork rebuild, PP occluded (disabled)
- Enable RenderCustomDepth + stencil value 2 on spline tube mesh
- Restore stencil 2 on deselect (selection sets stencil 1 for outline)
- Auto-generated M_PS_Editor_SplineOccluded PP material (stencil + depth compare)
- PP occluded effect disabled for now (depth comparison unreliable)
- AISpline triggers SplineNetwork::RebuildNetwork on BeginPlay (next tick)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 19:18:41 +02:00
24e50ab919 IPS_Editor_SplineEditable interface, spline visibility, snap-to-ground, Play without BaseLevel
Refactor spline system to use IPS_Editor_SplineEditable interface:
- New interface in Spline/PS_Editor_SplineEditable.h with all editing methods
- APS_Editor_SplineActor and APS_BehaviorEditor_AISpline both implement it
- All ~40 Cast<APS_Editor_SplineActor> replaced with Cast<IPS_Editor_SplineEditable>
- UndoManager SplinePointAction uses TWeakObjectPtr<AActor> + interface cast
- Any actor implementing the interface works with full editor spline editing

Spline visibility:
- SetVisualizationVisible() hides tube/handles/cube in gameplay (data stays for AI)
- SceneLoader calls it when stripping editor components
- SplineMatOccluded material added (unused for now, PP occlusion planned)

Other improvements:
- Snap spline CP to ground on placement (downward raytrace)
- Play button works without BaseLevel (uses current editor map)
- AISpline triggers SplineNetwork::RebuildNetwork on BeginPlay (next tick)
- PS_BehaviorEditor marked EnabledByDefault: false (only active in PROSERVE)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 18:05:53 +02:00
21e39ad3fa Add PS_BehaviorEditor bridge plugin with AI Spline actor
New plugin that bridges PS_Editor and PS_AI_Behavior:
- APS_BehaviorEditor_AISpline inherits from APS_AI_Behavior_SplinePath
  (detected by SplineNetwork, usable by BT tasks)
- Implements IPS_Editor_PointPlaceable (click-to-place flow)
- Full tube visualization + handles (adapted from PS_Editor_SplineActor)
- SpawnableComponent (catalogue category "AI") + EditableComponent
- Editable AI properties: SplineCategory, bBidirectional, SplineWalkSpeed, Priority
- Custom serialization for spline points + AI properties
- No modifications to PS_Editor or PS_AI_Behavior plugins

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 15:00:19 +02:00
c04bc2149b Loading screen overlay + camera fade on sublevel load
- Add loading overlay (black background + "Loading..." text) behind UI panels
- Overlay starts visible by default, hidden in NativeConstruct if no sublevel
- CameraFade to black before sublevel load, with deferred fallback for BeginPlay
- 2s delay after OnLevelShown before starting 2s fade-in from black
- ShowLoadingScreen helper on PlayerController via HUD->MainWidget

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 14:26:43 +02:00
5affbc7d0d IsLoadingFromScene via static flag, revert network replication on SpawnableComponent
- IsLoadingFromScene uses a simple static bool flag active during spawn loop
- Works server-side only (client relies on its own property replication)
- Removed replicated bLoadedFromScene/bPropertiesReady from SpawnableComponent
- Removed Multicast RPC and SetIsReplicatedByDefault (unnecessary complexity)
- SceneSerializer sets bIsCurrentlyLoading during load for consistent behavior

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 13:36:12 +02:00
1d5d448bf1 Close button, OnPropertiesLoaded event, spawn raytrace, IsLoadingFromScene
- Add close button (X) in title bar with save confirmation overlay
- Add OnEditorClosed delegate on PlayerController (BP-bindable)
- Add OnPropertiesLoaded event to EditableInterface (fires after scene load)
- Add IsLoadingFromScene() helper for BP BeginPlay skip pattern
- ComputeSpawnLocation now raycasts to avoid spawning through floors
- Track dirty state for save confirmation on close
- Scene load uses PS_Editor_Loading tag via CustomPreSpawnInitalization

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 09:26:41 +02:00
551 changed files with 16074 additions and 846 deletions

View File

@@ -1,4 +1,4 @@
- [PS_Editor plugin project](project_ps_editor.md) — Runtime editor plugin for UE 5.5, Phases 1-4 done, outline material pending
- [PS_Editor plugin project](project_ps_editor.md) — Runtime editor plugin for UE 5.7 (migrated from 5.5 in April 2026), Phases 1-4 done, outline material pending
- [Underscore naming](feedback_naming.md) — Always use PS_Editor_ prefix with underscores in file/class names
- [UE5 build process](reference_build.md) — CLI build command for the project (Build.bat path, target name, flags)
- [UE5 build process](reference_build.md) — CLI build command for PROSERVE_UE_5_7 (5.5 host deprecated), Build.bat path, target name, junction check
- [Build workflow](feedback_build_workflow.md) — Prefer Live Coding (Ctrl+Alt+F11) when UE is open, CLI build only when UE is closed

View File

@@ -1,10 +1,10 @@
---
name: PS_Editor plugin project
description: Runtime editor plugin for UE 5.5 - object placement, scene editing, JSON save/load in packaged builds
description: Runtime editor plugin for UE 5.7 - object placement, scene editing, JSON save/load in packaged builds
type: project
---
PS_Editor is a runtime editor plugin for Unreal Engine 5.5 for the PROSERVE project.
PS_Editor is a runtime editor plugin for Unreal Engine 5.7 for the PROSERVE project. The plugin was started on UE 5.5; the host project migrated to UE 5.7 in April 2026 and the plugin follows. Build details in reference_build.md.
Key decisions:
- UI: UMG driven by C++ (Slate)

View File

@@ -1,18 +1,30 @@
---
name: UE5 build process
description: How to build the PS_ProserveEditor UE 5.5 project from command line on Windows
description: How to build the PROSERVE host project (currently UE 5.7) from command line on Windows
type: reference
---
UE 5.5 is installed at `C:\Program Files\Epic Games\UE_5.5` (found via registry key `HKLM\SOFTWARE\EpicGames\Unreal Engine\5.5`).
The PS_Editor plugin is developed in `E:\ASTERION\GIT\PS_Editor\Unreal\Plugins\PS_Editor` and consumed by the PROSERVE host project via an NTFS junction. Always build the host project, not the plugin in isolation.
**Current host project (April 2026):** `E:\ASTERION\SVN\DEV\PROSERVE_UE_5_7\PROSERVE_UE_5_7.uproject` (Unreal Engine 5.7)
The previous 5.5 host (`PROSERVE_UE_5_5`) is deprecated — do not use unless explicitly asked.
UE 5.7 is installed at `C:\Program Files\Epic Games\UE_5.7` (found via registry key `HKLM\SOFTWARE\EpicGames\Unreal Engine\5.7`).
Build command (Editor target, Development):
```
"C:/Program Files/Epic Games/UE_5.5/Engine/Build/BatchFiles/Build.bat" PS_ProserveEditorEditor Win64 Development -Project="C:/ASTERION/GIT/PS_ProserveEditor/Unreal/PS_ProserveEditor.uproject" -WaitMutex -FromMsBuild
"C:/Program Files/Epic Games/UE_5.7/Engine/Build/BatchFiles/Build.bat" PROSERVE_UE_5_7Editor Win64 Development -Project="E:/ASTERION/SVN/DEV/PROSERVE_UE_5_7/PROSERVE_UE_5_7.uproject" -WaitMutex -FromMsBuild
```
**How to apply:** Use this command to compile after code changes. Timeout should be set to 600000ms (10 min) for safety. The target name is `PS_ProserveEditorEditor` (Editor suffix) for editor builds.
**How to apply:** Use this command to compile after code changes. Timeout should be set to 600000ms (10 min) for safety. The target name is `PROSERVE_UE_5_7Editor` (Editor suffix) for editor builds.
**When to use CLI vs Live Coding:**
- Live Coding (Ctrl+Alt+F11): .cpp only changes (no new UCLASS, USTRUCT, UENUM, UPROPERTY in headers)
- Full CLI build (UE must be closed): new files, header changes with new reflected types, Build.cs changes
**Plugin junction verification:**
```
ls -la E:/ASTERION/SVN/DEV/PROSERVE_UE_5_7/Plugins/ | grep PS_Editor
```
Should show a symlink pointing to `/e/ASTERION/GIT/PS_Editor/Unreal/Plugins/PS_Editor`. If broken, the host project will build against a stale or missing plugin copy.

View File

@@ -1,16 +0,0 @@
{
"permissions": {
"allow": [
"Bash(reg query:*)",
"Bash(\"C:/Program Files/Epic Games/UE_5.5/Engine/Build/BatchFiles/Build.bat\" PS_ProserveEditorEditor Win64 Development -Project=\"C:/ASTERION/GIT/PS_ProserveEditor/Unreal/PS_ProserveEditor.uproject\" -WaitMutex -FromMsBuild)",
"Bash(cp \"C:/Users/j_foucher/.claude/projects/C--ASTERION-GIT-PS-ProserveEditor/memory/MEMORY.md\" \"C:/ASTERION/GIT/PS_ProserveEditor/.claude/memory/MEMORY.md\")",
"Bash(cp \"C:/Users/j_foucher/.claude/projects/C--ASTERION-GIT-PS-ProserveEditor/memory/project_ps_editor.md\" \"C:/ASTERION/GIT/PS_ProserveEditor/.claude/memory/project_ps_editor.md\")",
"Bash(cp \"C:/Users/j_foucher/.claude/projects/C--ASTERION-GIT-PS-ProserveEditor/memory/feedback_naming.md\" \"C:/ASTERION/GIT/PS_ProserveEditor/.claude/memory/feedback_naming.md\")",
"Bash(cp \"C:/Users/j_foucher/.claude/projects/C--ASTERION-GIT-PS-ProserveEditor/memory/reference_build.md\" \"C:/ASTERION/GIT/PS_ProserveEditor/.claude/memory/reference_build.md\")",
"Bash(cp \"C:/Users/j_foucher/.claude/projects/C--ASTERION-GIT-PS-ProserveEditor/memory/feedback_build_workflow.md\" \"C:/ASTERION/GIT/PS_ProserveEditor/.claude/memory/feedback_build_workflow.md\")",
"Bash(powershell -Command \"\\(Get-ItemProperty 'HKLM:\\\\SOFTWARE\\\\EpicGames\\\\Unreal Engine\\\\5.5' -Name 'InstalledDirectory'\\).InstalledDirectory\")",
"Bash(\"C:\\\\Program Files\\\\Epic Games\\\\UE_5.5\\\\Engine\\\\Build\\\\BatchFiles\\\\Build.bat\" PS_ProserveEditorEditor Win64 Development -Project=\"C:\\\\ASTERION\\\\GIT\\\\PS_ProserveEditor\\\\Unreal\\\\PS_ProserveEditor.uproject\" -WaitMutex -FromMsBuild)",
"Bash(tasklist)"
]
}
}

3
.gitignore vendored
View File

@@ -16,3 +16,6 @@ Unreal/Plugins/*/Intermediate/
Thumbs.db
Desktop.ini
.DS_Store
# Claude Code per-user local settings
.claude/settings.local.json

110
CLAUDE.md
View File

@@ -1,7 +1,7 @@
# 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.
Unreal Engine 5.7 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. The plugin was started on UE 5.5; the host project migrated to UE 5.7 in April 2026.
## Architecture
- **Plugin**: PS_Editor (runtime plugin, must work in packaged builds)
@@ -10,6 +10,91 @@ Unreal Engine 5.5 project with runtime editor plugin (PS_Editor). The plugin ena
- **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
}
```
### Known PIE-only AI quirk — use Standalone for AI testing
When the editor's "Play" button calls `UGameplayStatics::OpenLevel(BaseLevel)` from a PIE
session, the BaseLevel's `RecastNavMesh` actor ends up pending-kill at registration time
(UE logs `RegistrationFailed_DataPendingKill` ×2 and silently spawns an empty
`AbstractNavData-Default` as fallback). All `FindPathAsync` / `ProjectPointToNavigation`
queries return empty after that — pathfinding looks broken with no error.
This is **PIE-specific**:
- Standalone Game (Window → Standalone) — works correctly
- Packaged builds — work correctly
- PIE direct on BaseLevel (no editor map / OpenLevel involved) — works correctly
- PIE on editor map → click Play (OpenLevel transition inside PIE) — broken
Multiple workaround attempts have all failed (cascading re-registrations through
`RegisterNavData` / `OnInitializeActors` / `AddNavigationSystemToWorld` / `Build` /
`SpawnMissingNavigationData`; transition map; duplicated sublevel suffixed `_default`).
The cause is internal to PIE's OpenLevel handling and cannot be fixed from the plugin
side without engine modifications.
**Workflow:** for AI iteration, run **Standalone Game** instead of PIE. It exercises the
exact same code path as packaged builds.
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
@@ -21,15 +106,28 @@ Unreal Engine 5.5 project with runtime editor plugin (PS_Editor). The plugin ena
- 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/`)
- Engine: Unreal Engine 5.7 (host project migrated from 5.5 in April 2026)
- Plugin location: `Unreal/Plugins/PS_Editor/` (consumed via NTFS junction from the PROSERVE host project's `Plugins/` directory)
- Host project: `E:\ASTERION\SVN\DEV\PROSERVE_UE_5_7\PROSERVE_UE_5_7.uproject` — always build this, not the plugin in isolation
- Game module: `PROSERVE_UE_5_7` (in the host project's `Source/`)
- CLI build command (Editor, Development):
```
"<UE_INSTALL>/Engine/Build/BatchFiles/Build.bat" PS_ProserveEditorEditor Win64 Development -Project="<REPO>/Unreal/PS_ProserveEditor.uproject" -WaitMutex -FromMsBuild
"C:/Program Files/Epic Games/UE_5.7/Engine/Build/BatchFiles/Build.bat" PROSERVE_UE_5_7Editor Win64 Development -Project="E:/ASTERION/SVN/DEV/PROSERVE_UE_5_7/PROSERVE_UE_5_7.uproject" -WaitMutex -FromMsBuild
```
UE install path can be found via registry: `HKLM\SOFTWARE\EpicGames\Unreal Engine\5.5` > `InstalledDirectory`
UE install path can be found via registry: `HKLM\SOFTWARE\EpicGames\Unreal Engine\5.7` > `InstalledDirectory`
- The 5.5 host (`PROSERVE_UE_5_5`) is deprecated — do not build against it unless explicitly asked.
## 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:

BIN
UI/BP_PS_Editor_HUD.uasset Normal file

Binary file not shown.

BIN
UI/assets/gizmo_rotate.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

BIN
UI/assets/gizmo_scale.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
UI/assets/thumb_fx.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
UI/assets/thumb_npc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
UI/assets/thumb_prop.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
UI/assets/thumb_spline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

BIN
UI/assets/thumb_weapon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
UI/icons/Bell.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
UI/icons/Box.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

BIN
UI/icons/Camera.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

BIN
UI/icons/Check.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
UI/icons/ChevronDown.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
UI/icons/ChevronLeft.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
UI/icons/ChevronRight.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
UI/icons/Command.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
UI/icons/Diamond.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
UI/icons/Download.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
UI/icons/Eye.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

BIN
UI/icons/EyeOff.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

BIN
UI/icons/Film.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
UI/icons/Flag.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
UI/icons/Folder.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
UI/icons/Globe.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
UI/icons/Grid.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
UI/icons/Help.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
UI/icons/Layers.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
UI/icons/Lightbulb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

BIN
UI/icons/Lock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
UI/icons/Map.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
UI/icons/Minus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
UI/icons/More.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
UI/icons/Move.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
UI/icons/PanelBottom.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
UI/icons/PanelRight.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
UI/icons/Pause.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
UI/icons/Play.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
UI/icons/Plus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
UI/icons/Record.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
UI/icons/Rotate.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

BIN
UI/icons/Save.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
UI/icons/Scale.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
UI/icons/Search.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

BIN
UI/icons/Settings.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
UI/icons/Sidebar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
UI/icons/SkipBack.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
UI/icons/SkipFwd.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
UI/icons/Snap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
UI/icons/Spline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

BIN
UI/icons/Stop.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
UI/icons/Target.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
UI/icons/Unlock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

BIN
UI/icons/User.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

BIN
UI/icons/Zap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
UI/icons/icons_16/Bell.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

BIN
UI/icons/icons_16/Box.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 B

BIN
UI/icons/icons_16/Check.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

BIN
UI/icons/icons_16/Eye.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

BIN
UI/icons/icons_16/Film.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 B

BIN
UI/icons/icons_16/Flag.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

BIN
UI/icons/icons_16/Globe.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 461 B

BIN
UI/icons/icons_16/Grid.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 B

BIN
UI/icons/icons_16/Help.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 B

BIN
UI/icons/icons_16/Lock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 B

BIN
UI/icons/icons_16/Map.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 B

BIN
UI/icons/icons_16/Minus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 B

BIN
UI/icons/icons_16/More.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

BIN
UI/icons/icons_16/Move.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

BIN
UI/icons/icons_16/Pause.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

BIN
UI/icons/icons_16/Play.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

BIN
UI/icons/icons_16/Plus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 B

BIN
UI/icons/icons_16/Save.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 B

BIN
UI/icons/icons_16/Scale.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Some files were not shown because too many files have changed in this diff Show More