diff --git a/Unreal/Plugins/PS_BehaviorEditor/PS_BehaviorEditor.uplugin b/Unreal/Plugins/PS_BehaviorEditor/PS_BehaviorEditor.uplugin index 7aa0fb8..d7de3eb 100644 --- a/Unreal/Plugins/PS_BehaviorEditor/PS_BehaviorEditor.uplugin +++ b/Unreal/Plugins/PS_BehaviorEditor/PS_BehaviorEditor.uplugin @@ -6,6 +6,7 @@ "Description": "Bridge plugin: AI Behavior splines editable via PS_Editor runtime editor.", "Category": "PS Tools", "CreatedBy": "Asterion", + "EnabledByDefault": false, "Modules": [ { "Name": "PS_BehaviorEditor", diff --git a/Unreal/Plugins/PS_BehaviorEditor/Source/PS_BehaviorEditor/PS_BehaviorEditor_AISpline.cpp b/Unreal/Plugins/PS_BehaviorEditor/Source/PS_BehaviorEditor/PS_BehaviorEditor_AISpline.cpp index ff6160b..cc1f8c1 100644 --- a/Unreal/Plugins/PS_BehaviorEditor/Source/PS_BehaviorEditor/PS_BehaviorEditor_AISpline.cpp +++ b/Unreal/Plugins/PS_BehaviorEditor/Source/PS_BehaviorEditor/PS_BehaviorEditor_AISpline.cpp @@ -6,6 +6,7 @@ #include "Components/StaticMeshComponent.h" #include "Engine/StaticMesh.h" #include "Materials/MaterialInstanceDynamic.h" +#include "PS_AI_Behavior_SplineNetwork.h" APS_BehaviorEditor_AISpline::APS_BehaviorEditor_AISpline() { @@ -82,6 +83,9 @@ void APS_BehaviorEditor_AISpline::BeginPlay() CenterCubeMat = UMaterialInstanceDynamic::Create(GizmoMat, this); CenterCubeMat->SetVectorParameterValue(TEXT("Color"), SplineColor); + + SplineMatOccluded = UMaterialInstanceDynamic::Create(GizmoMat, this); + SplineMatOccluded->SetVectorParameterValue(TEXT("Color"), FLinearColor(0.3f, 0.3f, 0.3f)); } // Center cube (selection handle) @@ -102,6 +106,18 @@ void APS_BehaviorEditor_AISpline::BeginPlay() { CenterCube->SetMaterial(0, CenterCubeMat); } + + // Rebuild SplineNetwork next tick (all splines from scene load will be ready) + GetWorld()->GetTimerManager().SetTimerForNextTick([WeakWorld = TWeakObjectPtr(GetWorld())]() + { + if (UWorld* World = WeakWorld.Get()) + { + if (UPS_AI_Behavior_SplineNetwork* Network = World->GetSubsystem()) + { + Network->RebuildNetwork(); + } + } + }); } // ---- Point manipulation ---- @@ -406,6 +422,23 @@ void APS_BehaviorEditor_AISpline::ClearHandleHighlight() } } +// ---- Visibility ---- + +void APS_BehaviorEditor_AISpline::SetVisualizationVisible(bool bVisible) +{ + if (SplineMeshComp) SplineMeshComp->SetVisibility(bVisible); + if (CenterCube) CenterCube->SetVisibility(bVisible); + if (HandleRoot) HandleRoot->SetVisibility(bVisible, true); + for (UStaticMeshComponent* Handle : PointHandles) + { + if (Handle) + { + Handle->SetVisibility(bVisible); + Handle->SetCollisionEnabled(bVisible ? ECollisionEnabled::QueryOnly : ECollisionEnabled::NoCollision); + } + } +} + // ---- Serialization ---- void APS_BehaviorEditor_AISpline::ExportToCustomProperties(TMap& OutProperties) const diff --git a/Unreal/Plugins/PS_BehaviorEditor/Source/PS_BehaviorEditor/PS_BehaviorEditor_AISpline.h b/Unreal/Plugins/PS_BehaviorEditor/Source/PS_BehaviorEditor/PS_BehaviorEditor_AISpline.h index a3cc85b..5105ae2 100644 --- a/Unreal/Plugins/PS_BehaviorEditor/Source/PS_BehaviorEditor/PS_BehaviorEditor_AISpline.h +++ b/Unreal/Plugins/PS_BehaviorEditor/Source/PS_BehaviorEditor/PS_BehaviorEditor_AISpline.h @@ -3,6 +3,7 @@ #include "CoreMinimal.h" #include "PS_AI_Behavior_SplinePath.h" #include "PS_Editor_PointPlaceable.h" +#include "PS_Editor_SplineEditable.h" #include "PS_BehaviorEditor_AISpline.generated.h" class UProceduralMeshComponent; @@ -19,7 +20,7 @@ class UPS_Editor_EditableComponent; * Includes tube visualization + handles from PS_Editor's spline system. */ UCLASS(BlueprintType, Blueprintable, meta = (DisplayName = "AI Spline (Editor)")) -class PS_BEHAVIOREDITOR_API APS_BehaviorEditor_AISpline : public APS_AI_Behavior_SplinePath, public IPS_Editor_PointPlaceable +class PS_BEHAVIOREDITOR_API APS_BehaviorEditor_AISpline : public APS_AI_Behavior_SplinePath, public IPS_Editor_PointPlaceable, public IPS_Editor_SplineEditable { GENERATED_BODY() @@ -39,40 +40,46 @@ public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spline|Visual") FLinearColor SplineSelectedColor = FLinearColor(0.4f, 0.8f, 1.0f); - // ---- Point manipulation ---- + // ---- Point manipulation (IPS_Editor_SplineEditable) ---- - void AddPoint(const FVector& WorldPosition); - void MovePoint(int32 Index, const FVector& NewWorldPosition); - void RemovePoint(int32 Index); - int32 GetNumPoints() const; - FVector GetPointLocation(int32 Index) const; - TArray GetAllPointLocations() const; - void SetAllPointLocations(const TArray& Points); - void InsertPoint(int32 Index, const FVector& WorldPosition); - int32 FindInsertIndex(const FVector& WorldLocation) const; - FVector GetCentroid() const; + virtual void AddPoint(const FVector& WorldPosition) override; + virtual void MovePoint(int32 Index, const FVector& NewWorldPosition) override; + virtual void RemovePoint(int32 Index) override; + virtual int32 GetNumPoints() const override; + virtual FVector GetPointLocation(int32 Index) const override; + virtual TArray GetAllPointLocations() const override; + virtual void SetAllPointLocations(const TArray& Points) override; + virtual void InsertPoint(int32 Index, const FVector& WorldPosition) override; + virtual int32 FindInsertIndex(const FVector& WorldLocation) const override; + virtual FVector GetCentroid() const override; - // ---- Visualization ---- + // ---- Visualization (IPS_Editor_SplineEditable) ---- - void UpdateVisualization(); + virtual void UpdateVisualization() override; UFUNCTION(BlueprintCallable, Category = "PS Editor|Spline") - void UpdateSplineMaterials(); + virtual void UpdateSplineMaterials() override; - // ---- Handle interaction ---- + // ---- Handle interaction (IPS_Editor_SplineEditable) ---- - int32 GetHandleIndexUnderCursor(const FVector& RayOrigin, const FVector& RayDirection, float SphereRadius = 15.0f) const; - void SetHandlesVisible(bool bVisible); - void SetSelected(bool bSelected); - bool IsCenterCube(const UPrimitiveComponent* Comp) const; - bool IsSplineMesh(const UPrimitiveComponent* Comp) const; - void HighlightHandle(int32 Index); - void ClearHandleHighlight(); + virtual int32 GetHandleIndexUnderCursor(const FVector& RayOrigin, const FVector& RayDirection, float SphereRadius = 15.0f) const override; + virtual void SetHandlesVisible(bool bVisible) override; + virtual void SetSelected(bool bSelected) override; + virtual bool IsCenterCube(const UPrimitiveComponent* Comp) const override; + virtual bool IsSplineMesh(const UPrimitiveComponent* Comp) const override; + virtual void HighlightHandle(int32 Index) override; + virtual void ClearHandleHighlight() override; - // ---- Serialization ---- + // ---- Visibility (IPS_Editor_SplineEditable) ---- + virtual void SetVisualizationVisible(bool bVisible) override; - void ExportToCustomProperties(TMap& OutProperties) const; - void ImportFromCustomProperties(const TMap& Properties); + // ---- Serialization (IPS_Editor_SplineEditable) ---- + + virtual void ExportToCustomProperties(TMap& OutProperties) const override; + virtual void ImportFromCustomProperties(const TMap& Properties) override; + + // ---- Access (IPS_Editor_SplineEditable) ---- + virtual USplineComponent* GetSplineComponent() const override { return SplineComp; } protected: virtual void BeginPlay() override; @@ -95,6 +102,8 @@ private: TObjectPtr HandleMat; UPROPERTY() TObjectPtr HandleHighlightMat; + UPROPERTY() + TObjectPtr SplineMatOccluded; UPROPERTY() TObjectPtr CenterCube; diff --git a/Unreal/Plugins/PS_Editor/Source/PS_Editor/GameMode/PS_Editor_Pawn.cpp b/Unreal/Plugins/PS_Editor/Source/PS_Editor/GameMode/PS_Editor_Pawn.cpp index bf61421..cfa8e2d 100644 --- a/Unreal/Plugins/PS_Editor/Source/PS_Editor/GameMode/PS_Editor_Pawn.cpp +++ b/Unreal/Plugins/PS_Editor/Source/PS_Editor/GameMode/PS_Editor_Pawn.cpp @@ -14,6 +14,7 @@ #include "PS_Editor_Gizmo.h" #include "PS_Editor_UndoManager.h" #include "PS_Editor_SplineActor.h" +#include "PS_Editor_SplineEditable.h" #include "Components/SplineComponent.h" #include "DrawDebugHelpers.h" #include "PS_Editor_ConfirmDialog.h" @@ -379,7 +380,7 @@ void APS_Editor_Pawn::HandleLook(const FInputActionValue& Value) // Spline point mode: move the single point instead of actors if (ActiveSplinePointIndex >= 0 && DraggedSplineActor.IsValid()) { - if (APS_Editor_SplineActor* SplineActor = Cast(DraggedSplineActor.Get())) + if (IPS_Editor_SplineEditable* SplineActor = Cast(DraggedSplineActor.Get())) { if (SplinePointDragInitialState.IsValidIndex(ActiveSplinePointIndex)) { @@ -472,7 +473,7 @@ void APS_Editor_Pawn::HandleLook(const FInputActionValue& Value) if (ActiveSplinePointIndex >= 0 && DraggedSplineActor.IsValid()) { // Following a single spline point - if (APS_Editor_SplineActor* SplineActor = Cast(DraggedSplineActor.Get())) + if (IPS_Editor_SplineEditable* SplineActor = Cast(DraggedSplineActor.Get())) { Gizmo->SetActorLocation(SplineActor->GetPointLocation(ActiveSplinePointIndex)); } @@ -480,7 +481,7 @@ void APS_Editor_Pawn::HandleLook(const FInputActionValue& Value) else if (Selected.Num() == 1) { // Single actor: use centroid for splines, location for others - if (APS_Editor_SplineActor* SplineActor = Cast(Selected[0].Get())) + if (IPS_Editor_SplineEditable* SplineActor = Cast(Selected[0].Get())) { Gizmo->SetActorLocation(SplineActor->GetCentroid()); } @@ -507,7 +508,7 @@ void APS_Editor_Pawn::HandleLook(const FInputActionValue& Value) else if (CameraMode == EPS_Editor_CameraMode::SplinePointDrag) { // Drag spline point along horizontal plane - APS_Editor_SplineActor* Spline = Cast(DraggedSplineActor.Get()); + IPS_Editor_SplineEditable* Spline = Cast(DraggedSplineActor.Get()); if (!Spline || ActiveSplinePointIndex < 0) return; FVector RayOrigin, RayDir; @@ -585,23 +586,23 @@ void APS_Editor_Pawn::HandleLeftClickStarted(const FInputActionValue& Value) if (Mode == EPS_Editor_EditorMode::SplinePlacement || Mode == EPS_Editor_EditorMode::SplinePlacement) { // Collect candidate splines: selected actors + active placement actor - TArray CandidateSplines; + TArray CandidateSplines; if (UPS_Editor_SelectionManager* SM = EdPC->GetSelectionManager()) { for (const TWeakObjectPtr& Weak : SM->GetSelectedActors()) { - if (APS_Editor_SplineActor* S = Cast(Weak.Get())) + if (IPS_Editor_SplineEditable* S = Cast(Weak.Get())) { CandidateSplines.AddUnique(S); } } } - if (APS_Editor_SplineActor* ActiveSpline = Cast(EdPC->GetActivePlacementActor())) + if (IPS_Editor_SplineEditable* ActiveSpline = Cast(EdPC->GetActivePlacementActor())) { CandidateSplines.AddUnique(ActiveSpline); } - for (APS_Editor_SplineActor* Spline : CandidateSplines) + for (IPS_Editor_SplineEditable* Spline : CandidateSplines) { // Center cube check (skip in SplinePlacement — no center cube interaction during creation) if (Mode == EPS_Editor_EditorMode::SplinePlacement) @@ -626,7 +627,7 @@ void APS_Editor_Pawn::HandleLeftClickStarted(const FInputActionValue& Value) if (HandleIdx >= 0) { ActiveSplinePointIndex = HandleIdx; - DraggedSplineActor = Spline; + DraggedSplineActor = Cast(Spline); Spline->HighlightHandle(HandleIdx); if (UPS_Editor_SelectionManager* SM = EdPC->GetSelectionManager()) @@ -650,16 +651,16 @@ void APS_Editor_Pawn::HandleLeftClickStarted(const FInputActionValue& Value) if (EdPC2->GetEditorMode() == EPS_Editor_EditorMode::SplinePlacement) { // Collect candidate splines: selected + active placement actor - TArray TubeCandidates; + TArray TubeCandidates; if (UPS_Editor_SelectionManager* SM2 = EdPC2->GetSelectionManager()) { for (const TWeakObjectPtr& Weak : SM2->GetSelectedActors()) { - if (APS_Editor_SplineActor* S = Cast(Weak.Get())) + if (IPS_Editor_SplineEditable* S = Cast(Weak.Get())) TubeCandidates.AddUnique(S); } } - if (APS_Editor_SplineActor* ActiveSpline = Cast(EdPC2->GetActivePlacementActor())) + if (IPS_Editor_SplineEditable* ActiveSpline = Cast(EdPC2->GetActivePlacementActor())) { TubeCandidates.AddUnique(ActiveSpline); } @@ -673,7 +674,7 @@ void APS_Editor_Pawn::HandleLeftClickStarted(const FInputActionValue& Value) if (GetWorld()->LineTraceSingleByChannel(LineHit, RayOrigin, TraceEnd, ECC_Camera, LineParams)) { - for (APS_Editor_SplineActor* Spline : TubeCandidates) + for (IPS_Editor_SplineEditable* Spline : TubeCandidates) { if (Spline->IsSplineMesh(LineHit.GetComponent())) @@ -687,7 +688,7 @@ void APS_Editor_Pawn::HandleLeftClickStarted(const FInputActionValue& Value) if (UPS_Editor_UndoManager* UM = EdPC2->GetUndoManager()) { TSharedPtr Action = MakeShared(); - Action->SplineActor = Spline; + Action->SplineActor = Cast(Spline); Action->OldPoints = OldPoints; Action->NewPoints = Spline->GetAllPointLocations(); Action->Description = TEXT("Insert spline point"); @@ -695,7 +696,7 @@ void APS_Editor_Pawn::HandleLeftClickStarted(const FInputActionValue& Value) } ActiveSplinePointIndex = InsertIdx; - DraggedSplineActor = Spline; + DraggedSplineActor = Cast(Spline); Spline->HighlightHandle(InsertIdx); if (UPS_Editor_SelectionManager* InsertSM = EdPC2->GetSelectionManager()) @@ -721,13 +722,13 @@ void APS_Editor_Pawn::HandleLeftClickStarted(const FInputActionValue& Value) { if (EdPC3->GetEditorMode() == EPS_Editor_EditorMode::SplinePlacement) { - if (APS_Editor_SplineActor* Spline = Cast(EdPC3->GetActivePlacementActor())) + if (IPS_Editor_SplineEditable* Spline = Cast(EdPC3->GetActivePlacementActor())) { // Raycast to get world click position FHitResult AddHit; FCollisionQueryParams AddParams; AddParams.AddIgnoredActor(this); - AddParams.AddIgnoredActor(Spline); + AddParams.AddIgnoredActor(Cast(Spline)); const FVector AddEnd = RayOrigin + RayDir * 100000.0f; FVector ClickPos; @@ -746,7 +747,7 @@ void APS_Editor_Pawn::HandleLeftClickStarted(const FInputActionValue& Value) if (UPS_Editor_UndoManager* UM = EdPC3->GetUndoManager()) { TSharedPtr Action = MakeShared(); - Action->SplineActor = Spline; + Action->SplineActor = Cast(Spline); Action->OldPoints = OldPoints; Action->NewPoints = Spline->GetAllPointLocations(); Action->Description = TEXT("Add spline point"); @@ -756,7 +757,7 @@ void APS_Editor_Pawn::HandleLeftClickStarted(const FInputActionValue& Value) // Select the new point const int32 NewIdx = Spline->GetNumPoints() - 1; ActiveSplinePointIndex = NewIdx; - DraggedSplineActor = Spline; + DraggedSplineActor = Cast(Spline); Spline->HighlightHandle(NewIdx); if (UPS_Editor_SelectionManager* SM3 = EdPC3->GetSelectionManager()) @@ -800,10 +801,10 @@ void APS_Editor_Pawn::HandleLeftClickCompleted(const FInputActionValue& Value) // Spline point drag: record SplinePointAction if (ActiveSplinePointIndex >= 0 && DraggedSplineActor.IsValid()) { - if (APS_Editor_SplineActor* SplineActor = Cast(DraggedSplineActor.Get())) + if (IPS_Editor_SplineEditable* SplineActor = Cast(DraggedSplineActor.Get())) { TSharedPtr Action = MakeShared(); - Action->SplineActor = SplineActor; + Action->SplineActor = Cast(SplineActor); Action->OldPoints = SplinePointDragInitialState; Action->NewPoints = SplineActor->GetAllPointLocations(); Action->Description = TEXT("Move spline point"); @@ -852,7 +853,7 @@ void APS_Editor_Pawn::HandleLeftClickCompleted(const FInputActionValue& Value) if (ActiveSplinePointIndex >= 0 && DraggedSplineActor.IsValid()) { // Keep gizmo at the active spline point - if (APS_Editor_SplineActor* SplineActor = Cast(DraggedSplineActor.Get())) + if (IPS_Editor_SplineEditable* SplineActor = Cast(DraggedSplineActor.Get())) { if (APS_Editor_Gizmo* G = SM2->GetGizmo()) { @@ -872,14 +873,14 @@ void APS_Editor_Pawn::HandleLeftClickCompleted(const FInputActionValue& Value) else if (CameraMode == EPS_Editor_CameraMode::SplinePointDrag) { // Record undo for spline point move - if (APS_Editor_SplineActor* Spline = Cast(DraggedSplineActor.Get())) + if (IPS_Editor_SplineEditable* Spline = Cast(DraggedSplineActor.Get())) { if (APS_Editor_PlayerController* EditorPC = Cast(GetController())) { if (UPS_Editor_UndoManager* UM = EditorPC->GetUndoManager()) { TSharedPtr Action = MakeShared(); - Action->SplineActor = Spline; + Action->SplineActor = Cast(Spline); Action->OldPoints = SplinePointDragInitialState; Action->NewPoints = Spline->GetAllPointLocations(); Action->Description = TEXT("Move spline point"); @@ -973,7 +974,7 @@ void APS_Editor_Pawn::HandleDelete(const FInputActionValue& Value) if (EditorPC->GetEditorMode() == EPS_Editor_EditorMode::SplinePlacement && ActiveSplinePointIndex >= 0 && DraggedSplineActor.IsValid()) { - APS_Editor_SplineActor* Spline = Cast(DraggedSplineActor.Get()); + IPS_Editor_SplineEditable* Spline = Cast(DraggedSplineActor.Get()); if (Spline && Spline->GetNumPoints() > 2) { TArray OldPoints = Spline->GetAllPointLocations(); @@ -982,7 +983,7 @@ void APS_Editor_Pawn::HandleDelete(const FInputActionValue& Value) if (UPS_Editor_UndoManager* UM = EditorPC->GetUndoManager()) { TSharedPtr Action = MakeShared(); - Action->SplineActor = Spline; + Action->SplineActor = Cast(Spline); Action->OldPoints = OldPoints; Action->NewPoints = Spline->GetAllPointLocations(); Action->Description = TEXT("Delete spline point"); @@ -1089,7 +1090,7 @@ void APS_Editor_Pawn::HandleSnapToGround(const FInputActionValue& Value) // If a spline point is selected (in edit or placement mode), snap that point to ground if (ActiveSplinePointIndex >= 0 && DraggedSplineActor.IsValid()) { - if (APS_Editor_SplineActor* Spline = Cast(DraggedSplineActor.Get())) + if (IPS_Editor_SplineEditable* Spline = Cast(DraggedSplineActor.Get())) { const FVector PointLoc = Spline->GetPointLocation(ActiveSplinePointIndex); const FVector TraceStart = PointLoc + FVector(0.0f, 0.0f, 1.0f); // Just above current position @@ -1097,7 +1098,7 @@ void APS_Editor_Pawn::HandleSnapToGround(const FInputActionValue& Value) FHitResult Hit; FCollisionQueryParams Params; - Params.AddIgnoredActor(Spline); + Params.AddIgnoredActor(Cast(Spline)); Params.AddIgnoredActor(this); if (UPS_Editor_SelectionManager* SnapSM = EditorPC->GetSelectionManager()) { @@ -1132,7 +1133,7 @@ void APS_Editor_Pawn::HandleSnapToGround(const FInputActionValue& Value) if (UPS_Editor_UndoManager* UM = EditorPC->GetUndoManager()) { TSharedPtr Action = MakeShared(); - Action->SplineActor = Spline; + Action->SplineActor = Cast(Spline); Action->OldPoints = OldPoints; Action->NewPoints = Spline->GetAllPointLocations(); Action->Description = TEXT("Snap spline point to ground"); @@ -1438,7 +1439,7 @@ void APS_Editor_Pawn::BeginGizmoDrag(EPS_Editor_GizmoAxis Axis) // Store initial spline state if editing a point if (ActiveSplinePointIndex >= 0 && DraggedSplineActor.IsValid()) { - if (APS_Editor_SplineActor* Spline = Cast(DraggedSplineActor.Get())) + if (IPS_Editor_SplineEditable* Spline = Cast(DraggedSplineActor.Get())) { SplinePointDragInitialState = Spline->GetAllPointLocations(); } diff --git a/Unreal/Plugins/PS_Editor/Source/PS_Editor/GameMode/PS_Editor_PlayerController.cpp b/Unreal/Plugins/PS_Editor/Source/PS_Editor/GameMode/PS_Editor_PlayerController.cpp index 8d3e009..7beafc3 100644 --- a/Unreal/Plugins/PS_Editor/Source/PS_Editor/GameMode/PS_Editor_PlayerController.cpp +++ b/Unreal/Plugins/PS_Editor/Source/PS_Editor/GameMode/PS_Editor_PlayerController.cpp @@ -7,6 +7,7 @@ #include "PS_Editor_Gizmo.h" #include "PS_Editor_Pawn.h" #include "PS_Editor_SplineActor.h" +#include "PS_Editor_SplineEditable.h" #include "PS_Editor_PointPlaceable.h" #include "Engine/LevelStreamingDynamic.h" #include "Engine/PostProcessVolume.h" @@ -164,9 +165,9 @@ void APS_Editor_PlayerController::OnPossess(APawn* InPawn) } } -APS_Editor_SplineActor* APS_Editor_PlayerController::GetActiveSplineActor() const +IPS_Editor_SplineEditable* APS_Editor_PlayerController::GetActiveSplineActor() const { - return Cast(ActivePlacementActor); + return Cast(ActivePlacementActor); } void APS_Editor_PlayerController::CloseEditor() @@ -223,7 +224,7 @@ void APS_Editor_PlayerController::BeginPointPlacementAppend(AActor* ExistingActo EditorMode = EPS_Editor_EditorMode::SplinePlacement; // Store initial state for undo (spline-specific) - if (APS_Editor_SplineActor* Spline = Cast(ExistingActor)) + if (IPS_Editor_SplineEditable* Spline = Cast(ExistingActor)) { AppendInitialPoints = Spline->GetAllPointLocations(); Spline->SetHandlesVisible(true); @@ -240,7 +241,7 @@ void APS_Editor_PlayerController::FinishPointPlacement() AppendInitialPoints.Empty(); EditorMode = EPS_Editor_EditorMode::Normal; - if (APS_Editor_SplineActor* Spline = Cast(PlacementActor)) + if (IPS_Editor_SplineEditable* Spline = Cast(PlacementActor)) { Spline->SetHandlesVisible(false); Spline->ClearHandleHighlight(); @@ -439,6 +440,22 @@ void APS_Editor_PlayerController::HandleEditorClick(FVector2D ScreenPos, bool bA ClickWorldPos = WorldOrigin + WorldDirection * 1000.0f; } + // Snap spline CP to ground: trace downward from click point + { + FHitResult GroundHit; + FCollisionQueryParams GroundParams; + GroundParams.AddIgnoredActor(GetPawn()); + if (ActivePlacementActor) GroundParams.AddIgnoredActor(ActivePlacementActor); + + const FVector GroundStart = ClickWorldPos + FVector(0.0f, 0.0f, 50.0f); + const FVector GroundEnd = ClickWorldPos - FVector(0.0f, 0.0f, 10000.0f); + + if (GetWorld()->LineTraceSingleByChannel(GroundHit, GroundStart, GroundEnd, ECC_Visibility, GroundParams)) + { + ClickWorldPos = GroundHit.ImpactPoint + FVector(0.0f, 0.0f, 5.0f); + } + } + if (!ActivePlacementActor) { // First click: spawn the actor, track immediately, record undo @@ -470,7 +487,7 @@ void APS_Editor_PlayerController::HandleEditorClick(FVector2D ScreenPos, bool bA } // Check if we clicked on the existing spline tube → insert instead of append - if (APS_Editor_SplineActor* Spline = Cast(ActivePlacementActor)) + if (IPS_Editor_SplineEditable* Spline = Cast(ActivePlacementActor)) { if (Spline->GetNumPoints() >= 2) { @@ -494,7 +511,7 @@ void APS_Editor_PlayerController::HandleEditorClick(FVector2D ScreenPos, bool bA } // Default: add point at end via the interface (with undo) - if (APS_Editor_SplineActor* Spline = Cast(ActivePlacementActor)) + if (IPS_Editor_SplineEditable* Spline = Cast(ActivePlacementActor)) { TArray OldPoints = Spline->GetAllPointLocations(); Spline->AddPoint(ClickWorldPos); @@ -502,7 +519,7 @@ void APS_Editor_PlayerController::HandleEditorClick(FVector2D ScreenPos, bool bA if (UndoManager) { TSharedPtr Action = MakeShared(); - Action->SplineActor = Spline; + Action->SplineActor = Cast(Spline); Action->OldPoints = OldPoints; Action->NewPoints = Spline->GetAllPointLocations(); Action->Description = TEXT("Add spline point"); diff --git a/Unreal/Plugins/PS_Editor/Source/PS_Editor/GameMode/PS_Editor_PlayerController.h b/Unreal/Plugins/PS_Editor/Source/PS_Editor/GameMode/PS_Editor_PlayerController.h index 63db99c..172ed39 100644 --- a/Unreal/Plugins/PS_Editor/Source/PS_Editor/GameMode/PS_Editor_PlayerController.h +++ b/Unreal/Plugins/PS_Editor/Source/PS_Editor/GameMode/PS_Editor_PlayerController.h @@ -12,6 +12,7 @@ class UPS_Editor_SpawnCatalog; class UPS_Editor_MasterCatalog; class UPS_Editor_SceneSerializer; class APS_Editor_SplineActor; +class IPS_Editor_SplineEditable; class IPS_Editor_PointPlaceable; class ULevelStreamingDynamic; @@ -91,7 +92,7 @@ public: bool IsAppendingToActor() const { return bAppendingToActor; } // Legacy convenience (for spline-specific code like point editing) - APS_Editor_SplineActor* GetActiveSplineActor() const; + IPS_Editor_SplineEditable* GetActiveSplineActor() const; /** Convenience: enter point placement for an existing spline. */ void BeginSplineEditing(AActor* Spline) { BeginPointPlacementAppend(Spline); } diff --git a/Unreal/Plugins/PS_Editor/Source/PS_Editor/Selection/PS_Editor_SelectionManager.cpp b/Unreal/Plugins/PS_Editor/Source/PS_Editor/Selection/PS_Editor_SelectionManager.cpp index 3a38905..55b69b4 100644 --- a/Unreal/Plugins/PS_Editor/Source/PS_Editor/Selection/PS_Editor_SelectionManager.cpp +++ b/Unreal/Plugins/PS_Editor/Source/PS_Editor/Selection/PS_Editor_SelectionManager.cpp @@ -6,6 +6,7 @@ #include "PS_Editor_EditableComponent.h" #include "PS_Editor_SpawnableComponent.h" #include "PS_Editor_SplineActor.h" +#include "PS_Editor_SplineEditable.h" #include "GameFramework/PlayerController.h" #include "Engine/World.h" #include "GameFramework/Pawn.h" @@ -188,7 +189,7 @@ void UPS_Editor_SelectionManager::SelectActor(AActor* Actor) OnSelectionChanged.Broadcast(); // Mark spline as selected (handles shown only in SplineEditing mode, not here) - if (APS_Editor_SplineActor* Spline = Cast(Actor)) + if (IPS_Editor_SplineEditable* Spline = Cast(Actor)) { Spline->SetSelected(true); } @@ -215,7 +216,7 @@ void UPS_Editor_SelectionManager::DeselectActor(AActor* Actor) OnSelectionChanged.Broadcast(); // Unmark spline - if (APS_Editor_SplineActor* Spline = Cast(Actor)) + if (IPS_Editor_SplineEditable* Spline = Cast(Actor)) { Spline->SetHandlesVisible(false); Spline->SetSelected(false); @@ -258,7 +259,7 @@ void UPS_Editor_SelectionManager::ClearSelection() SetActorHighlight(Actor, false); // Spline-specific cleanup - if (APS_Editor_SplineActor* Spline = Cast(Actor)) + if (IPS_Editor_SplineEditable* Spline = Cast(Actor)) { Spline->SetHandlesVisible(false); Spline->SetSelected(false); @@ -316,7 +317,7 @@ FVector UPS_Editor_SelectionManager::GetSelectionPivot() const if (AActor* Actor = Weak.Get()) { // For SplineActors, use the centroid of all points as pivot - if (APS_Editor_SplineActor* Spline = Cast(Actor)) + if (IPS_Editor_SplineEditable* Spline = Cast(Actor)) { Sum += Spline->GetCentroid(); } @@ -523,7 +524,7 @@ void UPS_Editor_SelectionManager::UpdateGizmo() // Override pivot for SplineActors: use centroid so gizmo aligns with center cube if (SelectedActors.Num() == 1) { - if (APS_Editor_SplineActor* Spline = Cast(SelectedActors[0].Get())) + if (IPS_Editor_SplineEditable* Spline = Cast(SelectedActors[0].Get())) { Pivot = Spline->GetCentroid(); } diff --git a/Unreal/Plugins/PS_Editor/Source/PS_Editor/Selection/PS_Editor_UndoManager.cpp b/Unreal/Plugins/PS_Editor/Source/PS_Editor/Selection/PS_Editor_UndoManager.cpp index e43f919..4d5220d 100644 --- a/Unreal/Plugins/PS_Editor/Source/PS_Editor/Selection/PS_Editor_UndoManager.cpp +++ b/Unreal/Plugins/PS_Editor/Source/PS_Editor/Selection/PS_Editor_UndoManager.cpp @@ -1,11 +1,11 @@ #include "PS_Editor_UndoManager.h" -#include "PS_Editor_SplineActor.h" +#include "PS_Editor_SplineEditable.h" #include "UObject/UnrealType.h" #include "Components/ActorComponent.h" void FPS_Editor_SplinePointAction::Execute() { - if (APS_Editor_SplineActor* Spline = SplineActor.Get()) + if (IPS_Editor_SplineEditable* Spline = Cast(SplineActor.Get())) { Spline->SetAllPointLocations(NewPoints); } @@ -13,7 +13,7 @@ void FPS_Editor_SplinePointAction::Execute() void FPS_Editor_SplinePointAction::Undo() { - if (APS_Editor_SplineActor* Spline = SplineActor.Get()) + if (IPS_Editor_SplineEditable* Spline = Cast(SplineActor.Get())) { Spline->SetAllPointLocations(OldPoints); } diff --git a/Unreal/Plugins/PS_Editor/Source/PS_Editor/Selection/PS_Editor_UndoManager.h b/Unreal/Plugins/PS_Editor/Source/PS_Editor/Selection/PS_Editor_UndoManager.h index 1e970e5..42a8154 100644 --- a/Unreal/Plugins/PS_Editor/Source/PS_Editor/Selection/PS_Editor_UndoManager.h +++ b/Unreal/Plugins/PS_Editor/Source/PS_Editor/Selection/PS_Editor_UndoManager.h @@ -158,17 +158,16 @@ struct FPS_Editor_SpawnAction : public FPS_Editor_Action } }; -class APS_Editor_SplineActor; - /** * Records a spline point state change (move, add, remove). * Stores full state snapshots (all points before/after) for simplicity. + * SplineActor must implement IPS_Editor_SplineEditable. */ struct FPS_Editor_SplinePointAction : public FPS_Editor_Action { FPS_Editor_SplinePointAction() : FPS_Editor_Action(EPS_Editor_ActionType::SplinePointChange) {} - TWeakObjectPtr SplineActor; + TWeakObjectPtr SplineActor; TArray OldPoints; TArray NewPoints; FString Description; diff --git a/Unreal/Plugins/PS_Editor/Source/PS_Editor/Serialization/PS_Editor_SceneLoader.cpp b/Unreal/Plugins/PS_Editor/Source/PS_Editor/Serialization/PS_Editor_SceneLoader.cpp index 69908d9..53f1cad 100644 --- a/Unreal/Plugins/PS_Editor/Source/PS_Editor/Serialization/PS_Editor_SceneLoader.cpp +++ b/Unreal/Plugins/PS_Editor/Source/PS_Editor/Serialization/PS_Editor_SceneLoader.cpp @@ -4,6 +4,7 @@ #include "PS_Editor_EditableInterface.h" #include "PS_Editor_SpawnableComponent.h" #include "PS_Editor_SplineActor.h" +#include "PS_Editor_SplineEditable.h" #include "PS_Editor_PointPlaceable.h" #include "JsonObjectConverter.h" #include "Misc/FileHelper.h" @@ -74,6 +75,12 @@ bool UPS_Editor_SceneLoader::LoadScene(const UObject* WorldContextObject, const { Comp->DestroyComponent(); } + + // Hide spline visualization in gameplay (tube, handles) — data stays for AI + if (IPS_Editor_SplineEditable* Spline = Cast(Actor)) + { + Spline->SetVisualizationVisible(false); + } } } @@ -144,7 +151,7 @@ AActor* UPS_Editor_SceneLoader::SpawnActorFromData(UWorld* World, const FPS_Edit } // Import spline data if applicable - if (APS_Editor_SplineActor* Spline = Cast(SpawnedActor)) + if (IPS_Editor_SplineEditable* Spline = Cast(SpawnedActor)) { Spline->ImportFromCustomProperties(ActorData.CustomProperties); } diff --git a/Unreal/Plugins/PS_Editor/Source/PS_Editor/Serialization/PS_Editor_SceneSerializer.cpp b/Unreal/Plugins/PS_Editor/Source/PS_Editor/Serialization/PS_Editor_SceneSerializer.cpp index 489c5bf..6550edf 100644 --- a/Unreal/Plugins/PS_Editor/Source/PS_Editor/Serialization/PS_Editor_SceneSerializer.cpp +++ b/Unreal/Plugins/PS_Editor/Source/PS_Editor/Serialization/PS_Editor_SceneSerializer.cpp @@ -6,6 +6,7 @@ #include "PS_Editor_PlayerController.h" #include "PS_Editor_SceneLoader.h" #include "PS_Editor_SplineActor.h" +#include "PS_Editor_SplineEditable.h" #include "JsonObjectConverter.h" #include "Misc/FileHelper.h" #include "Misc/Paths.h" @@ -47,7 +48,7 @@ bool UPS_Editor_SceneSerializer::SaveScene(const FString& SceneName, UPS_Editor_ ActorData.Scale = Actor->GetActorScale3D(); // Export spline data - if (APS_Editor_SplineActor* Spline = Cast(Actor)) + if (IPS_Editor_SplineEditable* Spline = Cast(Actor)) { Spline->ExportToCustomProperties(ActorData.CustomProperties); UE_LOG(LogTemp, Log, TEXT("PS_Editor: Exported spline with %d points, class=%s"), @@ -214,7 +215,7 @@ bool UPS_Editor_SceneSerializer::LoadScene(const FString& SceneName, UPS_Editor_ } // Import spline data - if (APS_Editor_SplineActor* Spline = Cast(SpawnedActor)) + if (IPS_Editor_SplineEditable* Spline = Cast(SpawnedActor)) { Spline->ImportFromCustomProperties(ActorData.CustomProperties); } diff --git a/Unreal/Plugins/PS_Editor/Source/PS_Editor/Spline/PS_Editor_SplineActor.cpp b/Unreal/Plugins/PS_Editor/Source/PS_Editor/Spline/PS_Editor_SplineActor.cpp index cf4c658..0f12044 100644 --- a/Unreal/Plugins/PS_Editor/Source/PS_Editor/Spline/PS_Editor_SplineActor.cpp +++ b/Unreal/Plugins/PS_Editor/Source/PS_Editor/Spline/PS_Editor_SplineActor.cpp @@ -87,6 +87,10 @@ void APS_Editor_SplineActor::BeginPlay() CenterCubeMat = UMaterialInstanceDynamic::Create(GizmoMat, this); CenterCubeMat->SetVectorParameterValue(TEXT("Color"), SplineColor); + + // Occluded pass: gray, no depth test — visible through walls + SplineMatOccluded = UMaterialInstanceDynamic::Create(GizmoMat, this); + SplineMatOccluded->SetVectorParameterValue(TEXT("Color"), FLinearColor(0.3f, 0.3f, 0.3f)); } // Create center cube (selection handle for whole spline) @@ -255,14 +259,12 @@ void APS_Editor_SplineActor::UpdateVisualization() } SplineMeshComp->ClearAllMeshSections(); + SplineMeshComp->CreateMeshSection(0, Vertices, Triangles, Normals, UVs, TArray(), TArray(), true); - // Force collision and bounds update immediately SplineMeshComp->UpdateBounds(); SplineMeshComp->MarkRenderStateDirty(); - // Apply the current material (normal or selected) - // Check if handles are visible as a proxy for "selected" state const bool bCurrentlySelected = (PointHandles.Num() > 0 && PointHandles[0] && PointHandles[0]->IsVisible()); UMaterialInstanceDynamic* LineMat = (bCurrentlySelected && SplineMatSelected) ? SplineMatSelected : SplineMat; if (LineMat) @@ -458,6 +460,21 @@ void APS_Editor_SplineActor::UpdateSplineMaterials() } } +void APS_Editor_SplineActor::SetVisualizationVisible(bool bVisible) +{ + if (SplineMeshComp) SplineMeshComp->SetVisibility(bVisible); + if (CenterCube) CenterCube->SetVisibility(bVisible); + if (HandleRoot) HandleRoot->SetVisibility(bVisible, true); + for (UStaticMeshComponent* Handle : PointHandles) + { + if (Handle) + { + Handle->SetVisibility(bVisible); + Handle->SetCollisionEnabled(bVisible ? ECollisionEnabled::QueryOnly : ECollisionEnabled::NoCollision); + } + } +} + bool APS_Editor_SplineActor::IsSplineMesh(const UPrimitiveComponent* Comp) const { return Comp && Comp == SplineMeshComp; diff --git a/Unreal/Plugins/PS_Editor/Source/PS_Editor/Spline/PS_Editor_SplineActor.h b/Unreal/Plugins/PS_Editor/Source/PS_Editor/Spline/PS_Editor_SplineActor.h index 3928c99..c944d56 100644 --- a/Unreal/Plugins/PS_Editor/Source/PS_Editor/Spline/PS_Editor_SplineActor.h +++ b/Unreal/Plugins/PS_Editor/Source/PS_Editor/Spline/PS_Editor_SplineActor.h @@ -3,6 +3,7 @@ #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "PS_Editor_PointPlaceable.h" +#include "PS_Editor_SplineEditable.h" #include "PS_Editor_SplineActor.generated.h" class USplineComponent; @@ -15,7 +16,7 @@ class UPS_Editor_EditableComponent; * Renders as a visible quad strip with clickable point handles. */ UCLASS() -class PS_EDITOR_API APS_Editor_SplineActor : public AActor, public IPS_Editor_PointPlaceable +class PS_EDITOR_API APS_Editor_SplineActor : public AActor, public IPS_Editor_PointPlaceable, public IPS_Editor_SplineEditable { GENERATED_BODY() @@ -46,74 +47,77 @@ public: // ---- Point manipulation ---- /** Add a point at the end of the spline (world space). */ - void AddPoint(const FVector& WorldPosition); + virtual void AddPoint(const FVector& WorldPosition) override; /** Move an existing point to a new world position. */ - void MovePoint(int32 Index, const FVector& NewWorldPosition); + virtual void MovePoint(int32 Index, const FVector& NewWorldPosition) override; /** Remove a point by index. */ - void RemovePoint(int32 Index); + virtual void RemovePoint(int32 Index) override; /** Get the number of spline points. */ - int32 GetNumPoints() const; + virtual int32 GetNumPoints() const override; /** Get the world position of a spline point. */ - FVector GetPointLocation(int32 Index) const; + virtual FVector GetPointLocation(int32 Index) const override; /** Get all point world positions (for undo snapshots). */ - TArray GetAllPointLocations() const; + virtual TArray GetAllPointLocations() const override; /** Set all point positions at once (for undo restore). Rebuilds handles and visualization. */ - void SetAllPointLocations(const TArray& Points); + virtual void SetAllPointLocations(const TArray& Points) override; // ---- Visualization ---- /** Regenerate the line mesh and reposition all handles. */ - void UpdateVisualization(); + virtual void UpdateVisualization() override; /** Re-apply SplineColor to materials (call after changing SplineColor at runtime). */ UFUNCTION(BlueprintCallable, Category = "PS Editor|Spline") - void UpdateSplineMaterials(); + virtual void UpdateSplineMaterials() override; // ---- Handle interaction ---- /** Find which point handle is under the cursor ray. Returns -1 if none. */ - int32 GetHandleIndexUnderCursor(const FVector& RayOrigin, const FVector& RayDirection, float SphereRadius = 15.0f) const; + virtual int32 GetHandleIndexUnderCursor(const FVector& RayOrigin, const FVector& RayDirection, float SphereRadius = 15.0f) const override; /** Show or hide all point handles and center cube. */ - void SetHandlesVisible(bool bVisible); + virtual void SetHandlesVisible(bool bVisible) override; /** Set the spline's selected state (changes line + cube color). */ - void SetSelected(bool bSelected); + virtual void SetSelected(bool bSelected) override; /** Returns true if the given component is the center cube. */ - bool IsCenterCube(const UPrimitiveComponent* Comp) const; + virtual bool IsCenterCube(const UPrimitiveComponent* Comp) const override; /** Highlight a specific handle (yellow), others go back to normal (white). */ - void HighlightHandle(int32 Index); + virtual void HighlightHandle(int32 Index) override; /** Clear all handle highlights. */ - void ClearHandleHighlight(); + virtual void ClearHandleHighlight() override; // ---- Serialization ---- /** Returns true if the given component is the spline line mesh. */ - bool IsSplineMesh(const UPrimitiveComponent* Comp) const; + virtual bool IsSplineMesh(const UPrimitiveComponent* Comp) const override; /** Find the best insertion index for a new point at the given world location. */ - int32 FindInsertIndex(const FVector& WorldLocation) const; + virtual int32 FindInsertIndex(const FVector& WorldLocation) const override; /** Insert a point at a specific index. */ - void InsertPoint(int32 Index, const FVector& WorldPosition); + virtual void InsertPoint(int32 Index, const FVector& WorldPosition) override; /** Get the centroid of all spline points (world space). Used as pivot for gizmo. */ - FVector GetCentroid() const; + virtual FVector GetCentroid() const override; + + /** Hide/show the spline visualization. */ + virtual void SetVisualizationVisible(bool bVisible) override; /** Export spline data to a key-value map (for JSON serialization). */ - void ExportToCustomProperties(TMap& OutProperties) const; + virtual void ExportToCustomProperties(TMap& OutProperties) const override; /** Import spline data from a key-value map (for scene loading). */ - void ImportFromCustomProperties(const TMap& Properties); + virtual void ImportFromCustomProperties(const TMap& Properties) override; protected: virtual void BeginPlay() override; @@ -144,6 +148,9 @@ private: UPROPERTY() TObjectPtr HandleHighlightMat; + UPROPERTY() + TObjectPtr SplineMatOccluded; // Gray, no depth test — visible through walls + UPROPERTY() TObjectPtr CenterCube; diff --git a/Unreal/Plugins/PS_Editor/Source/PS_Editor/Spline/PS_Editor_SplineEditable.h b/Unreal/Plugins/PS_Editor/Source/PS_Editor/Spline/PS_Editor_SplineEditable.h new file mode 100644 index 0000000..e71fe49 --- /dev/null +++ b/Unreal/Plugins/PS_Editor/Source/PS_Editor/Spline/PS_Editor_SplineEditable.h @@ -0,0 +1,63 @@ +#pragma once + +#include "CoreMinimal.h" +#include "UObject/Interface.h" +#include "PS_Editor_SplineEditable.generated.h" + +class USplineComponent; + +UINTERFACE(BlueprintType, meta = (DisplayName = "PS Editor Spline Editable")) +class PS_EDITOR_API UPS_Editor_SplineEditable : public UInterface +{ + GENERATED_BODY() +}; + +/** + * Interface for any actor that provides spline editing in PS_Editor. + * Implemented by APS_Editor_SplineActor and APS_BehaviorEditor_AISpline. + * + * The editor (Pawn, SelectionManager, Serializer, etc.) casts to this interface + * instead of a concrete class, so any spline-like actor works with the full + * editing flow: point placement, handle drag, insert, delete, undo, serialization. + */ +class PS_EDITOR_API IPS_Editor_SplineEditable +{ + GENERATED_BODY() + +public: + // ---- Point manipulation ---- + virtual void AddPoint(const FVector& WorldPosition) = 0; + virtual void MovePoint(int32 Index, const FVector& NewWorldPosition) = 0; + virtual void RemovePoint(int32 Index) = 0; + virtual int32 GetNumPoints() const = 0; + virtual FVector GetPointLocation(int32 Index) const = 0; + virtual TArray GetAllPointLocations() const = 0; + virtual void SetAllPointLocations(const TArray& Points) = 0; + virtual void InsertPoint(int32 Index, const FVector& WorldPosition) = 0; + virtual int32 FindInsertIndex(const FVector& WorldLocation) const = 0; + virtual FVector GetCentroid() const = 0; + + // ---- Visualization ---- + virtual void UpdateVisualization() = 0; + virtual void UpdateSplineMaterials() = 0; + + // ---- Handle interaction ---- + virtual int32 GetHandleIndexUnderCursor(const FVector& RayOrigin, const FVector& RayDirection, float SphereRadius = 15.0f) const = 0; + virtual void SetHandlesVisible(bool bVisible) = 0; + virtual void SetSelected(bool bSelected) = 0; + virtual bool IsCenterCube(const UPrimitiveComponent* Comp) const = 0; + virtual bool IsSplineMesh(const UPrimitiveComponent* Comp) const = 0; + virtual void HighlightHandle(int32 Index) = 0; + virtual void ClearHandleHighlight() = 0; + + // ---- Serialization ---- + virtual void ExportToCustomProperties(TMap& OutProperties) const = 0; + virtual void ImportFromCustomProperties(const TMap& Properties) = 0; + + // ---- Visibility ---- + /** Hide/show the spline visualization (tube, handles, center cube). Data remains for AI. */ + virtual void SetVisualizationVisible(bool bVisible) = 0; + + // ---- Access ---- + virtual USplineComponent* GetSplineComponent() const = 0; +}; diff --git a/Unreal/Plugins/PS_Editor/Source/PS_Editor/UI/Widgets/PS_Editor_MainWidget.cpp b/Unreal/Plugins/PS_Editor/Source/PS_Editor/UI/Widgets/PS_Editor_MainWidget.cpp index 180cea2..884b4b9 100644 --- a/Unreal/Plugins/PS_Editor/Source/PS_Editor/UI/Widgets/PS_Editor_MainWidget.cpp +++ b/Unreal/Plugins/PS_Editor/Source/PS_Editor/UI/Widgets/PS_Editor_MainWidget.cpp @@ -9,6 +9,7 @@ #include "PS_Editor_EditableInterface.h" #include "PS_Editor_SpawnableComponent.h" #include "PS_Editor_SplineActor.h" +#include "PS_Editor_SplineEditable.h" #include "PS_Editor_Pawn.h" #include "PS_Editor_PointPlaceable.h" #include "Widgets/SBoxPanel.h" @@ -204,9 +205,9 @@ TSharedRef UPS_Editor_MainWidget::RebuildWidget() { for (const TWeakObjectPtr& Weak : SelMgr->GetSelectedActors()) { - if (APS_Editor_SplineActor* Spline = Cast(Weak.Get())) + if (Cast(Weak.Get())) { - EditorPC->BeginSplineEditing(Spline); + EditorPC->BeginSplineEditing(Weak.Get()); break; } } @@ -713,26 +714,42 @@ TSharedRef UPS_Editor_MainWidget::BuildSceneButtons() // Store scene name in GameInstance subsystem (survives OpenLevel) FString BaseLevel = EditorPC->CurrentBaseLevel; - UE_LOG(LogTemp, Warning, TEXT("PS_Editor Play: BaseLevel='%s'"), *BaseLevel); - if (BaseLevel.IsEmpty()) + FString SceneName = SaveNameField.IsValid() ? SaveNameField->GetText().ToString() : TEXT(""); + + // Resolve map path: BaseLevel from catalog, or current map if none selected + FString MapPath; + if (!BaseLevel.IsEmpty()) { - UE_LOG(LogTemp, Warning, TEXT("PS_Editor: No BaseLevel set, cannot Play.")); - return FReply::Handled(); + if (FString* Found = BaseLevelPathMap.Find(BaseLevel)) + { + MapPath = *Found; + } + else + { + MapPath = FString::Printf(TEXT("/Game/%s"), *BaseLevel); + } + } + else + { + // No BaseLevel = play on the current editor map + MapPath = EditorPC->GetWorld()->GetMapName(); + MapPath.RemoveFromStart(EditorPC->GetWorld()->StreamingLevelsPrefix); + BaseLevel = MapPath; } - FString SceneName = SaveNameField.IsValid() ? SaveNameField->GetText().ToString() : TEXT(""); + UE_LOG(LogTemp, Log, TEXT("PS_Editor Play: BaseLevel='%s', Map='%s', Scenario='%s'"), *BaseLevel, *MapPath, *SceneName); + if (UGameInstance* GI = EditorPC->GetGameInstance()) { if (UPS_Editor_GameInstanceSubsystem* Sub = GI->GetSubsystem()) { Sub->SetPendingScenario(SceneName, BaseLevel); Sub->bIsPlayMode = true; - // Remember editor map for ReturnToEditor if (Sub->EditorMapName.IsEmpty()) { - FString MapName = EditorPC->GetWorld()->GetMapName(); - MapName.RemoveFromStart(EditorPC->GetWorld()->StreamingLevelsPrefix); - Sub->EditorMapName = MapName; + FString EdMapName = EditorPC->GetWorld()->GetMapName(); + EdMapName.RemoveFromStart(EditorPC->GetWorld()->StreamingLevelsPrefix); + Sub->EditorMapName = EdMapName; } } } @@ -750,16 +767,6 @@ TSharedRef UPS_Editor_MainWidget::BuildSceneButtons() EditorPC->bShowMouseCursor = false; EditorPC->SetInputMode(FInputModeGameOnly()); - // Use full path from MasterCatalog, fallback to /Game/{name} - FString MapPath; - if (FString* Found = BaseLevelPathMap.Find(BaseLevel)) - { - MapPath = *Found; - } - else - { - MapPath = FString::Printf(TEXT("/Game/%s"), *BaseLevel); - } UGameplayStatics::OpenLevel(EditorPC, FName(*MapPath), true, TEXT("")); return FReply::Handled(); }) @@ -1353,7 +1360,7 @@ void UPS_Editor_MainWidget::RefreshPropertiesFromSelection() { for (const TWeakObjectPtr& Weak : SM->GetSelectedActors()) { - if (Cast(Weak.Get())) + if (Cast(Weak.Get())) { bSplineSelected = true; break; @@ -1598,11 +1605,7 @@ void UPS_Editor_MainWidget::RefreshOutliner() // Build display name FString DisplayName; - if (Cast(Actor)) - { - DisplayName = TEXT("Spline"); - } - else if (UPS_Editor_SpawnableComponent* SC = Actor->FindComponentByClass()) + if (UPS_Editor_SpawnableComponent* SC = Actor->FindComponentByClass()) { if (!SC->DisplayName.IsEmpty()) {