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>
This commit is contained in:
2026-04-18 13:47:45 +02:00
parent 75f54e27c4
commit 4181801635
11 changed files with 422 additions and 110 deletions

View File

@@ -28,7 +28,9 @@ APS_BehaviorEditor_AISpline::APS_BehaviorEditor_AISpline()
SplineMeshComp->SetCollisionResponseToChannel(ECC_Camera, ECR_Block);
SplineMeshComp->bUseComplexAsSimpleCollision = true;
SplineMeshComp->SetCastShadow(false);
SplineMeshComp->SetRenderCustomDepth(true);
// Custom depth off by default; SetSelected enables it while selected so the outline PP
// only catches the currently-selected spline.
SplineMeshComp->SetRenderCustomDepth(false);
SplineMeshComp->SetCustomDepthStencilValue(2);
// Handle parent
@@ -409,6 +411,8 @@ void APS_BehaviorEditor_AISpline::SetSelected(bool bSelected)
{
UMaterialInstanceDynamic* Mat = bSelected ? SplineMatSelected : SplineMat;
if (Mat) SplineMeshComp->SetMaterial(0, Mat);
// Only participate in the custom-depth pass while selected (see SplineActor).
SplineMeshComp->SetRenderCustomDepth(bSelected);
SplineMeshComp->SetCustomDepthStencilValue(bSelected ? 1 : 2);
}
if (CenterCubeMat)
@@ -528,4 +532,10 @@ void APS_BehaviorEditor_AISpline::ImportFromCustomProperties(const TMap<FString,
Priority = FCString::Atoi(**PriStr);
UpdateSplineMaterials();
// Force deselected state on load: handles default to visible on creation and
// UpdateVisualization uses handle visibility to pick the "selected" material.
SetHandlesVisible(false);
SetSelected(false);
UpdateVisualization();
}