Commit Graph

68 Commits

Author SHA1 Message Date
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
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
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
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
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
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
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
2b5015a9af Editor integration: editable interface, enum support, CameraStart, spawn options, crash fix
- Add IPS_Editor_EditableInterface with events: OnEditorPropertyChanged,
  OnEditorNeedsReinit, OnEditorNeedsRespawn, OnEditorModeChanged, OnEditorTick
- Add FPS_Editor_EditablePropertyEntry struct replacing separate property/display/respawn lists
  with unified Path + DisplayName + bNeedsReinit + bNeedsRespawn per entry
- Add enum property support in UI (SComboBox with display names)
- Add FVector2D property support in UI (X/Y fields)
- Add PS_Editor_CameraStart actor for initial camera position in base levels
- Add SpawnableComponent options: bAutoSnapToGround, bYawOnly, bUniformScaleOnly, GroundOffset
- Add bIsPlayMode to GameInstanceSubsystem for gameplay vs editor context
- Add PlayerController::Tick for editor tick dispatch to spawned actors
- Add SpawnManager::RespawnActorWithProperties, NotifyEditorModeChanged, TickEditorMode
- Fix recursive crash in ClearSelection/FinishPointPlacement loop
- Fix SScrollBox mouse wheel passthrough to camera
- Fix gizmo yaw-only: grey disabled arcs, block drag, preserve highlight
- Call OnEditorNeedsReinit after scene load (editor + gameplay) for property re-init

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 18:20:03 +02:00
83840d1626 Integration fixes: BaseLevelEntry with full map path, ECC_Camera traces, PP disable, thumbnails
- Replace TArray<FString> BaseLevels with TArray<FPS_Editor_BaseLevelEntry> (DisplayName + MapPath)
  so levels in subfolders (e.g. /Game/Maps/Warehouse) are found correctly
- Add BaseLevelPathMap lookup in MainWidget for Play, combo, and scene load
- Add optional MapPath parameter to LoadBaseLevelAsSublevel
- Switch all LineTrace channels from ECC_Visibility to ECC_Camera for better
  compatibility with characters that have Visibility disabled
- Add W key binding as alias for Z (translate mode) for AZERTY convenience
- Disable sublevel PostProcessVolume WeightedBlendables on load to avoid
  stencil conflicts with the plugin's selection outline
- Fix thumbnail generation: NeverStream + TEXTUREGROUP_UI + force alpha to 255

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 10:34:37 +02:00
ea20f1c279 Force opaque UI backgrounds with WhiteBrush
Default SBorder brush is semi-transparent in PIE. Using explicit
WhiteBrush (solid 1x1 texture) ensures fully opaque panels everywhere.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 18:39:24 +02:00
bc33a8f64b Make UI panel backgrounds fully opaque (alpha 1.0)
Fixes inconsistency between PIE (transparent) and packaged (opaque).
All SBorder BackgroundColor alpha changed from 0.85 to 1.0.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 18:38:07 +02:00
a91aac1192 Fix Play button: unload sublevel + use full map path for OpenLevel
OpenLevel("test") was resolving to the streamed sublevel instance
(test_LevelInstance_5) instead of the actual map. Fix:
- Unload sublevel via LoadBaseLevelAsSublevel("None") before OpenLevel
- Use full path "/Game/{BaseLevel}" to avoid ambiguity

Also: all widget lambdas now get SpawnManager/SceneSerializer fresh from
PlayerController (critical fix for packaged builds where weak ptrs are null).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 18:35:52 +02:00
7a008c7e60 Fix packaged build: weak ptr timing, factory module, hard refs, brace fix
Critical fixes for packaged builds:
- Widget weak ptrs (SpawnManager/SceneSerializer) are null in packaged due to
  HUD deferred init. All button lambdas now get references fresh from
  PlayerController via GetOwningPlayer() cast instead of cached weak ptrs.
- HUD BeginPlay deferred by one tick (SetTimerForNextTick) to ensure
  PlayerController has initialized SpawnManager before wiring.

Module split:
- Factories moved to separate PS_EditorTools module (Type: Editor)
  to fix UHT error with UFactory in packaging builds.
- PS_Editor module no longer depends on UnrealEd for factories.

Asset references:
- TSoftObjectPtr/TSoftClassPtr changed to TObjectPtr/TSubclassOf for
  MasterCatalog, SpawnCatalogs, and ActorClass entries. Hard references
  ensure assets are cooked in packaged builds.

Other fixes:
- GetActorLabel() replaced with GetClass()->GetName() (editor-only API)
- Missing brace in Browse dialog BaseLevel sync code
- BaseLevel sync only when scenario specifies a LevelName (no more clearing on empty)
- Save As dialog with native Windows file picker
- Debug info in catalog UI when empty (shows chain: Master→Catalogs→Entries)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 18:17:52 +02:00
aa4313057c Fix editor restore: init order, combo callback, scenario name
- SceneSerializer created before subsystem check (was nullptr crash)
- ComboBox OnSelectionChanged ignores ESelectInfo::Direct (programmatic)
  to prevent NativeConstruct from clearing the just-loaded scenario
- SaveNameField restored from LastEditedScenarioName on return
- Added ReturnToEditor/OpenEditor to GameInstanceSubsystem
- EditorMapName auto-saved on Play for return navigation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 16:23:32 +02:00
9c43fd523a Standalone editor: scenario workflow, BaseLevel combo, ReturnToEditor
Editor workflow:
- Removed auto-detection of BaseLevel (strip _Editor). Editor is standalone.
- User selects BaseLevel from ComboBox (populated from MasterCatalog.BaseLevels)
- "None" option for editing without a base level
- Selecting BaseLevel: clears current scenario, hides persistent level actors,
  loads sublevel. Selecting "None" restores persistent level actors.

UI terminology: Scene → Scenario (save field, buttons, notifications)

GameInstanceSubsystem:
- Renamed PendingSceneName → PendingScenarioName
- Added LastEditedScenarioName/LastEditedBaseLevel (persist after Consume)
- SetPendingScenario() stores in both Pending and LastEdited
- ReturnToEditor() restores Pending from LastEdited, opens editor map
- EditorMapName auto-saved on first Play, used by ReturnToEditor
- OpenEditor() / ReturnToEditor() callable from gameplay BP

Play button: resets input mode before OpenLevel (fixes cursor in FirstPerson GM)

Test assets: FirstPerson template for testing Play/ReturnToEditor flow

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 16:12:10 +02:00
472811b858 Add PROSERVE integration: sublevel loading, Play button, GameInstance subsystem
Architecture for single editor map workflow:
- MasterCatalog.BaseLevels lists available base levels
- BaseLevel selector in UI (cycle button) loads selected level as sublevel
- Sublevel provides visual context only — save/load only touches PS_Editor objects
- No auto-load at startup: user picks via UI or PROSERVE sets via subsystem

GameInstanceSubsystem (survives OpenLevel):
- PendingSceneName + PendingBaseLevel set by PROSERVE before opening editor
- Editor reads them at BeginPlay: loads sublevel + scene automatically
- ConsumePendingScene() for gameplay side to read and clear

Play button:
- Auto-saves current scene
- Stores scene name in GameInstanceSubsystem
- Opens the BaseLevel via OpenLevel

SceneLoader:
- bStripEditorComponents parameter (default true) removes Spawnable/Editable
  components after load for clean gameplay actors

SceneData v3: LevelName field associates scenes with base levels.
Scene list filtered by selected BaseLevel.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 15:32:43 +02:00
aafcbbb7f9 Add BaseLevelNameOverride for dedicated editor maps
PlayerController gets a BaseLevelNameOverride property. When set (e.g. "Warehouse"),
scenes are tagged with that level name instead of the auto-detected map name.

Use case: editing on "Warehouse_Editor" map but scenes should be associated
with the "Warehouse" base level for PROSERVE runtime loading.

Save, load list, and scene filtering all respect this override.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 12:01:43 +02:00
4dc0f400b4 Add level-based scene organization and filtering
SceneData now includes LevelName field (auto-detected from current map on save).
Version bumped to 3. Backward compatible (empty LevelName for old files).

SceneLoader:
- GetSavedSceneNames(LevelFilter) filters by associated level
- GetSceneLevelName() reads level association without full parse
- GetSavedSceneNamesForCurrentLevel() convenience for game code

Editor UI:
- Scene list grouped: "This level" (highlighted) + "Other levels" (dimmed)
- Shows current level name above the list

PROSERVE integration pattern:
  // List scenarios for current level
  auto Scenes = UPS_Editor_SceneLoader::GetSavedSceneNamesForCurrentLevel(this);
  // Load a specific scenario
  UPS_Editor_SceneLoader::LoadScene(this, "Scenario_A", OutActors);

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 11:43:00 +02:00
77f2da027e Add standalone SceneLoader for game runtime initialization
UPS_Editor_SceneLoader is a BlueprintFunctionLibrary that loads PS_Editor
JSON scenes without any editor infrastructure (no PlayerController, Gizmo,
SelectionManager, or UI required).

Usage from any GameMode:
  TArray<AActor*> Actors;
  UPS_Editor_SceneLoader::LoadScene(this, "MyScene", Actors);

Handles: class loading (BP + C++), transforms, custom editable properties
via reflection (ImportText), and spline point data. All functions are
BlueprintCallable for BP GameMode usage.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 11:32:09 +02:00
861c15c193 Unify spline creation/editing into single seamless mode
Major UX simplification:
- Removed SplineEditing mode — single SplinePlacement mode handles both
  creation and editing with identical behavior
- Actor spawned and tracked on first click (no "finish" step needed)
- Each point add/insert/move has individual undo
- Right-click always = camera fly (no special handling during creation)
- Escape/Done just exits edit mode, nothing to "finish"

Catalog system:
- MasterCatalog DataAsset groups multiple SpawnCatalogs (Tools, Characters, Props)
- PlayerController references one MasterCatalog instead of single catalog
- SpawnManager.AddCatalog() loads sub-catalogs incrementally
- Factory for MasterCatalog creation in Content Browser

Spline polish:
- SplineActor has built-in SpawnableComponent + EditableComponent
- SplineColor/SplineSelectedColor/SplineTag as UPROPERTY for BP variants
- All spline point operations use World coordinate space (fixes snap-to-ground)
- Snap-to-ground ignores gizmo actor (was hitting gizmo guide lines)
- Tube mesh collision forced with UpdateBounds after CreateMeshSection
- Tube insert and handle selection include active placement actor (not just selected)
- Notification bar shows contextual Delete Point button when CP selected

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 11:06:04 +02:00