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>
This commit is contained in:
@@ -163,6 +163,7 @@ void APS_Editor_Pawn::CreateInputActions()
|
|||||||
IA_TranslateMode = NewObject<UInputAction>(this, TEXT("IA_TranslateMode"));
|
IA_TranslateMode = NewObject<UInputAction>(this, TEXT("IA_TranslateMode"));
|
||||||
IA_TranslateMode->ValueType = EInputActionValueType::Boolean;
|
IA_TranslateMode->ValueType = EInputActionValueType::Boolean;
|
||||||
EditorMappingContext->MapKey(IA_TranslateMode, EKeys::Z);
|
EditorMappingContext->MapKey(IA_TranslateMode, EKeys::Z);
|
||||||
|
EditorMappingContext->MapKey(IA_TranslateMode, EKeys::W);
|
||||||
|
|
||||||
IA_RotateMode = NewObject<UInputAction>(this, TEXT("IA_RotateMode"));
|
IA_RotateMode = NewObject<UInputAction>(this, TEXT("IA_RotateMode"));
|
||||||
IA_RotateMode->ValueType = EInputActionValueType::Boolean;
|
IA_RotateMode->ValueType = EInputActionValueType::Boolean;
|
||||||
@@ -609,7 +610,7 @@ void APS_Editor_Pawn::HandleLeftClickStarted(const FInputActionValue& Value)
|
|||||||
FCollisionQueryParams SplineParams;
|
FCollisionQueryParams SplineParams;
|
||||||
SplineParams.AddIgnoredActor(this);
|
SplineParams.AddIgnoredActor(this);
|
||||||
const FVector TraceEnd = RayOrigin + RayDir * 100000.0f;
|
const FVector TraceEnd = RayOrigin + RayDir * 100000.0f;
|
||||||
if (GetWorld()->LineTraceSingleByChannel(SplineHit, RayOrigin, TraceEnd, ECC_Visibility, SplineParams))
|
if (GetWorld()->LineTraceSingleByChannel(SplineHit, RayOrigin, TraceEnd, ECC_Camera, SplineParams))
|
||||||
{
|
{
|
||||||
if (Spline->IsCenterCube(SplineHit.GetComponent()))
|
if (Spline->IsCenterCube(SplineHit.GetComponent()))
|
||||||
{
|
{
|
||||||
@@ -670,7 +671,7 @@ void APS_Editor_Pawn::HandleLeftClickStarted(const FInputActionValue& Value)
|
|||||||
LineParams.AddIgnoredActor(this);
|
LineParams.AddIgnoredActor(this);
|
||||||
const FVector TraceEnd = RayOrigin + RayDir * 100000.0f;
|
const FVector TraceEnd = RayOrigin + RayDir * 100000.0f;
|
||||||
|
|
||||||
if (GetWorld()->LineTraceSingleByChannel(LineHit, RayOrigin, TraceEnd, ECC_Visibility, LineParams))
|
if (GetWorld()->LineTraceSingleByChannel(LineHit, RayOrigin, TraceEnd, ECC_Camera, LineParams))
|
||||||
{
|
{
|
||||||
for (APS_Editor_SplineActor* Spline : TubeCandidates)
|
for (APS_Editor_SplineActor* Spline : TubeCandidates)
|
||||||
{
|
{
|
||||||
@@ -730,7 +731,7 @@ void APS_Editor_Pawn::HandleLeftClickStarted(const FInputActionValue& Value)
|
|||||||
const FVector AddEnd = RayOrigin + RayDir * 100000.0f;
|
const FVector AddEnd = RayOrigin + RayDir * 100000.0f;
|
||||||
|
|
||||||
FVector ClickPos;
|
FVector ClickPos;
|
||||||
if (GetWorld()->LineTraceSingleByChannel(AddHit, RayOrigin, AddEnd, ECC_Visibility, AddParams))
|
if (GetWorld()->LineTraceSingleByChannel(AddHit, RayOrigin, AddEnd, ECC_Camera, AddParams))
|
||||||
{
|
{
|
||||||
ClickPos = AddHit.ImpactPoint + FVector(0.0f, 0.0f, 5.0f);
|
ClickPos = AddHit.ImpactPoint + FVector(0.0f, 0.0f, 5.0f);
|
||||||
}
|
}
|
||||||
@@ -1106,7 +1107,7 @@ void APS_Editor_Pawn::HandleSnapToGround(const FInputActionValue& Value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetWorld()->LineTraceSingleByChannel(Hit, TraceStart, TraceEnd, ECC_Visibility, Params))
|
if (GetWorld()->LineTraceSingleByChannel(Hit, TraceStart, TraceEnd, ECC_Camera, Params))
|
||||||
{
|
{
|
||||||
UE_LOG(LogTemp, Log, TEXT("PS_Editor: SnapToGround - PointLoc=%s, HitZ=%.2f, HitActor=%s, HitComp=%s"),
|
UE_LOG(LogTemp, Log, TEXT("PS_Editor: SnapToGround - PointLoc=%s, HitZ=%.2f, HitActor=%s, HitComp=%s"),
|
||||||
*PointLoc.ToString(), Hit.ImpactPoint.Z,
|
*PointLoc.ToString(), Hit.ImpactPoint.Z,
|
||||||
@@ -1291,7 +1292,7 @@ void APS_Editor_Pawn::ComputeOrbitFocalPoint()
|
|||||||
FCollisionQueryParams Params;
|
FCollisionQueryParams Params;
|
||||||
Params.AddIgnoredActor(this);
|
Params.AddIgnoredActor(this);
|
||||||
|
|
||||||
if (GetWorld()->LineTraceSingleByChannel(Hit, Start, End, ECC_Visibility, Params))
|
if (GetWorld()->LineTraceSingleByChannel(Hit, Start, End, ECC_Camera, Params))
|
||||||
{
|
{
|
||||||
OrbitFocalPoint = Hit.ImpactPoint;
|
OrbitFocalPoint = Hit.ImpactPoint;
|
||||||
OrbitDistance = FVector::Dist(Start, OrbitFocalPoint);
|
OrbitDistance = FVector::Dist(Start, OrbitFocalPoint);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "PS_Editor_SplineActor.h"
|
#include "PS_Editor_SplineActor.h"
|
||||||
#include "PS_Editor_PointPlaceable.h"
|
#include "PS_Editor_PointPlaceable.h"
|
||||||
#include "Engine/LevelStreamingDynamic.h"
|
#include "Engine/LevelStreamingDynamic.h"
|
||||||
|
#include "Engine/PostProcessVolume.h"
|
||||||
#include "PS_Editor_GameInstanceSubsystem.h"
|
#include "PS_Editor_GameInstanceSubsystem.h"
|
||||||
#include "GameFramework/GameModeBase.h"
|
#include "GameFramework/GameModeBase.h"
|
||||||
#include "GameFramework/GameStateBase.h"
|
#include "GameFramework/GameStateBase.h"
|
||||||
@@ -61,7 +62,17 @@ void APS_Editor_PlayerController::BeginPlay()
|
|||||||
UE_LOG(LogTemp, Log, TEXT("PS_Editor: Restoring from subsystem - BaseLevel='%s', Scenario='%s'"),
|
UE_LOG(LogTemp, Log, TEXT("PS_Editor: Restoring from subsystem - BaseLevel='%s', Scenario='%s'"),
|
||||||
*Sub->PendingBaseLevel, *Sub->PendingScenarioName);
|
*Sub->PendingBaseLevel, *Sub->PendingScenarioName);
|
||||||
|
|
||||||
LoadBaseLevelAsSublevel(Sub->PendingBaseLevel);
|
// Resolve full map path from MasterCatalog
|
||||||
|
FString ResolvedMapPath;
|
||||||
|
for (const FPS_Editor_BaseLevelEntry& Entry : Master->BaseLevels)
|
||||||
|
{
|
||||||
|
if (Entry.DisplayName == Sub->PendingBaseLevel)
|
||||||
|
{
|
||||||
|
ResolvedMapPath = Entry.MapPath;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LoadBaseLevelAsSublevel(Sub->PendingBaseLevel, ResolvedMapPath);
|
||||||
|
|
||||||
if (!Sub->PendingScenarioName.IsEmpty() && SpawnManager && SceneSerializer)
|
if (!Sub->PendingScenarioName.IsEmpty() && SpawnManager && SceneSerializer)
|
||||||
{
|
{
|
||||||
@@ -197,7 +208,7 @@ void APS_Editor_PlayerController::CancelPointPlacement()
|
|||||||
FinishPointPlacement();
|
FinishPointPlacement();
|
||||||
}
|
}
|
||||||
|
|
||||||
void APS_Editor_PlayerController::LoadBaseLevelAsSublevel(const FString& LevelName)
|
void APS_Editor_PlayerController::LoadBaseLevelAsSublevel(const FString& LevelName, const FString& MapPath)
|
||||||
{
|
{
|
||||||
// Unload previous sublevel first
|
// Unload previous sublevel first
|
||||||
if (CurrentSublevel)
|
if (CurrentSublevel)
|
||||||
@@ -238,11 +249,14 @@ void APS_Editor_PlayerController::LoadBaseLevelAsSublevel(const FString& LevelNa
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use MapPath if provided, otherwise fall back to LevelName (legacy behavior)
|
||||||
|
const FString& LevelToLoad = MapPath.IsEmpty() ? LevelName : MapPath;
|
||||||
|
|
||||||
// Load new sublevel
|
// Load new sublevel
|
||||||
bool bSuccess = false;
|
bool bSuccess = false;
|
||||||
CurrentSublevel = ULevelStreamingDynamic::LoadLevelInstance(
|
CurrentSublevel = ULevelStreamingDynamic::LoadLevelInstance(
|
||||||
GetWorld(),
|
GetWorld(),
|
||||||
LevelName,
|
LevelToLoad,
|
||||||
FVector::ZeroVector,
|
FVector::ZeroVector,
|
||||||
FRotator::ZeroRotator,
|
FRotator::ZeroRotator,
|
||||||
bSuccess);
|
bSuccess);
|
||||||
@@ -252,11 +266,33 @@ void APS_Editor_PlayerController::LoadBaseLevelAsSublevel(const FString& LevelNa
|
|||||||
CurrentSublevel->SetShouldBeLoaded(true);
|
CurrentSublevel->SetShouldBeLoaded(true);
|
||||||
CurrentSublevel->SetShouldBeVisible(true);
|
CurrentSublevel->SetShouldBeVisible(true);
|
||||||
CurrentBaseLevel = LevelName;
|
CurrentBaseLevel = LevelName;
|
||||||
UE_LOG(LogTemp, Log, TEXT("PS_Editor: Loaded sublevel '%s'"), *LevelName);
|
|
||||||
|
// Disable custom PP materials once sublevel actors are available
|
||||||
|
CurrentSublevel->OnLevelShown.AddUniqueDynamic(this, &APS_Editor_PlayerController::DisableSublevelPostProcessMaterials);
|
||||||
|
|
||||||
|
UE_LOG(LogTemp, Log, TEXT("PS_Editor: Loaded sublevel '%s' (path: '%s')"), *LevelName, *LevelToLoad);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UE_LOG(LogTemp, Warning, TEXT("PS_Editor: Failed to load sublevel '%s'"), *LevelName);
|
UE_LOG(LogTemp, Warning, TEXT("PS_Editor: Failed to load sublevel '%s' (path: '%s')"), *LevelName, *LevelToLoad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void APS_Editor_PlayerController::DisableSublevelPostProcessMaterials()
|
||||||
|
{
|
||||||
|
if (!CurrentSublevel) return;
|
||||||
|
|
||||||
|
ULevel* Level = CurrentSublevel->GetLoadedLevel();
|
||||||
|
if (!Level) return;
|
||||||
|
|
||||||
|
for (AActor* Actor : Level->Actors)
|
||||||
|
{
|
||||||
|
if (!Actor) continue;
|
||||||
|
APostProcessVolume* PPVolume = Cast<APostProcessVolume>(Actor);
|
||||||
|
if (!PPVolume) continue;
|
||||||
|
|
||||||
|
PPVolume->Settings.WeightedBlendables.Array.Empty();
|
||||||
|
UE_LOG(LogTemp, Log, TEXT("PS_Editor: Disabled PP materials on '%s'"), *PPVolume->GetName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,7 +312,7 @@ void APS_Editor_PlayerController::HandleEditorClick(FVector2D ScreenPos, bool bA
|
|||||||
|
|
||||||
const FVector End = WorldOrigin + WorldDirection * 100000.0f;
|
const FVector End = WorldOrigin + WorldDirection * 100000.0f;
|
||||||
FVector ClickWorldPos;
|
FVector ClickWorldPos;
|
||||||
if (GetWorld()->LineTraceSingleByChannel(Hit, WorldOrigin, End, ECC_Visibility, Params))
|
if (GetWorld()->LineTraceSingleByChannel(Hit, WorldOrigin, End, ECC_Camera, Params))
|
||||||
{
|
{
|
||||||
ClickWorldPos = Hit.ImpactPoint + FVector(0.0f, 0.0f, 5.0f);
|
ClickWorldPos = Hit.ImpactPoint + FVector(0.0f, 0.0f, 5.0f);
|
||||||
}
|
}
|
||||||
@@ -326,7 +362,7 @@ void APS_Editor_PlayerController::HandleEditorClick(FVector2D ScreenPos, bool bA
|
|||||||
TubeParams.AddIgnoredActor(GetPawn());
|
TubeParams.AddIgnoredActor(GetPawn());
|
||||||
const FVector TubeEnd = WorldOrigin + WorldDirection * 100000.0f;
|
const FVector TubeEnd = WorldOrigin + WorldDirection * 100000.0f;
|
||||||
|
|
||||||
if (GetWorld()->LineTraceSingleByChannel(TubeHit, WorldOrigin, TubeEnd, ECC_Visibility, TubeParams))
|
if (GetWorld()->LineTraceSingleByChannel(TubeHit, WorldOrigin, TubeEnd, ECC_Camera, TubeParams))
|
||||||
{
|
{
|
||||||
if (Spline->IsSplineMesh(TubeHit.GetComponent()))
|
if (Spline->IsSplineMesh(TubeHit.GetComponent()))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -47,9 +47,13 @@ public:
|
|||||||
UPROPERTY(BlueprintReadWrite, Category = "PS Editor")
|
UPROPERTY(BlueprintReadWrite, Category = "PS Editor")
|
||||||
FString CurrentBaseLevel;
|
FString CurrentBaseLevel;
|
||||||
|
|
||||||
/** Load a base level as sublevel for visual context. Unloads previous sublevel. */
|
/** Load a base level as sublevel for visual context. Unloads previous sublevel.
|
||||||
|
* @param LevelName Display name stored in CurrentBaseLevel (used for scene filtering).
|
||||||
|
* @param MapPath Full package path for LoadLevelInstance (e.g. "/Game/Maps/Warehouse").
|
||||||
|
* If empty, LevelName is used as-is (legacy behavior).
|
||||||
|
*/
|
||||||
UFUNCTION(BlueprintCallable, Category = "PS Editor")
|
UFUNCTION(BlueprintCallable, Category = "PS Editor")
|
||||||
void LoadBaseLevelAsSublevel(const FString& LevelName);
|
void LoadBaseLevelAsSublevel(const FString& LevelName, const FString& MapPath = TEXT(""));
|
||||||
|
|
||||||
// ---- Editor Mode (Normal / SplinePlacement) ----
|
// ---- Editor Mode (Normal / SplinePlacement) ----
|
||||||
|
|
||||||
@@ -119,5 +123,9 @@ private:
|
|||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
TObjectPtr<ULevelStreamingDynamic> CurrentSublevel;
|
TObjectPtr<ULevelStreamingDynamic> CurrentSublevel;
|
||||||
|
|
||||||
|
/** Disable custom post-process materials in the loaded sublevel to avoid stencil conflicts. */
|
||||||
|
UFUNCTION()
|
||||||
|
void DisableSublevelPostProcessMaterials();
|
||||||
|
|
||||||
void HandleEditorClick(FVector2D ScreenPos, bool bAdditive);
|
void HandleEditorClick(FVector2D ScreenPos, bool bAdditive);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ static void ConfigureGizmoComponent(UPrimitiveComponent* Comp)
|
|||||||
{
|
{
|
||||||
Comp->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
|
Comp->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
|
||||||
Comp->SetCollisionResponseToAllChannels(ECR_Ignore);
|
Comp->SetCollisionResponseToAllChannels(ECR_Ignore);
|
||||||
Comp->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block);
|
Comp->SetCollisionResponseToChannel(ECC_Camera, ECR_Block);
|
||||||
Comp->SetCollisionObjectType(ECC_WorldDynamic);
|
Comp->SetCollisionObjectType(ECC_WorldDynamic);
|
||||||
Comp->SetCastShadow(false);
|
Comp->SetCastShadow(false);
|
||||||
Comp->SetRenderCustomDepth(false);
|
Comp->SetRenderCustomDepth(false);
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ void UPS_Editor_SelectionManager::HandleClickAtScreenPosition(FVector2D ScreenPo
|
|||||||
}
|
}
|
||||||
|
|
||||||
const FVector End = WorldOrigin + WorldDirection * 100000.0f;
|
const FVector End = WorldOrigin + WorldDirection * 100000.0f;
|
||||||
const bool bHit = PC->GetWorld()->LineTraceSingleByChannel(Hit, WorldOrigin, End, ECC_Visibility, Params);
|
const bool bHit = PC->GetWorld()->LineTraceSingleByChannel(Hit, WorldOrigin, End, ECC_Camera, Params);
|
||||||
|
|
||||||
if (bHit && Hit.GetActor())
|
if (bHit && Hit.GetActor())
|
||||||
{
|
{
|
||||||
@@ -467,7 +467,7 @@ void UPS_Editor_SelectionManager::SnapSelectionToGround()
|
|||||||
Params.AddIgnoredActor(PC->GetPawn());
|
Params.AddIgnoredActor(PC->GetPawn());
|
||||||
if (Gizmo) Params.AddIgnoredActor(Gizmo);
|
if (Gizmo) Params.AddIgnoredActor(Gizmo);
|
||||||
|
|
||||||
if (Actor->GetWorld()->LineTraceSingleByChannel(Hit, Start, End, ECC_Visibility, Params))
|
if (Actor->GetWorld()->LineTraceSingleByChannel(Hit, Start, End, ECC_Camera, Params))
|
||||||
{
|
{
|
||||||
FVector NewLocation = Hit.ImpactPoint;
|
FVector NewLocation = Hit.ImpactPoint;
|
||||||
NewLocation.Z += BottomOffset;
|
NewLocation.Z += BottomOffset;
|
||||||
|
|||||||
@@ -85,11 +85,18 @@ void UPS_Editor_SpawnCatalog::CaptureAllThumbnails()
|
|||||||
|
|
||||||
uint8* MipData = Texture->Source.LockMip(0);
|
uint8* MipData = Texture->Source.LockMip(0);
|
||||||
FMemory::Memcpy(MipData, PixelData.GetData(), PixelData.Num());
|
FMemory::Memcpy(MipData, PixelData.GetData(), PixelData.Num());
|
||||||
|
// Force alpha to 255 — UE thumbnails may have zeroed alpha
|
||||||
|
for (int32 Px = 0; Px < Width * Height; ++Px)
|
||||||
|
{
|
||||||
|
MipData[Px * 4 + 3] = 255;
|
||||||
|
}
|
||||||
Texture->Source.UnlockMip(0);
|
Texture->Source.UnlockMip(0);
|
||||||
|
|
||||||
Texture->SRGB = true;
|
Texture->SRGB = true;
|
||||||
Texture->CompressionSettings = TC_Default;
|
Texture->CompressionSettings = TC_Default;
|
||||||
Texture->MipGenSettings = TMGS_NoMipmaps;
|
Texture->MipGenSettings = TMGS_NoMipmaps;
|
||||||
|
Texture->NeverStream = true;
|
||||||
|
Texture->LODGroup = TEXTUREGROUP_UI;
|
||||||
Texture->PostEditChange();
|
Texture->PostEditChange();
|
||||||
Texture->UpdateResource();
|
Texture->UpdateResource();
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,28 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A base level entry: display name + full map path.
|
||||||
|
* The MapPath is used for OpenLevel and sublevel loading.
|
||||||
|
* Example: DisplayName="Warehouse", MapPath="/Game/Maps/Warehouse"
|
||||||
|
*/
|
||||||
|
USTRUCT(BlueprintType)
|
||||||
|
struct FPS_Editor_BaseLevelEntry
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
/** Display name shown in the editor combo box and used for scene filtering. */
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS Editor")
|
||||||
|
FString DisplayName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Full map path used for OpenLevel and sublevel loading.
|
||||||
|
* Example: "/Game/Maps/Warehouse"
|
||||||
|
*/
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS Editor")
|
||||||
|
FString MapPath;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Master catalog that groups multiple SpawnCatalogs.
|
* Master catalog that groups multiple SpawnCatalogs.
|
||||||
* Assign this to the PlayerController. Each sub-catalog can represent a domain
|
* Assign this to the PlayerController. Each sub-catalog can represent a domain
|
||||||
@@ -60,10 +82,10 @@ public:
|
|||||||
TArray<TObjectPtr<UPS_Editor_SpawnCatalog>> Catalogs;
|
TArray<TObjectPtr<UPS_Editor_SpawnCatalog>> Catalogs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of base level names available for scene editing.
|
* List of base levels available for scene editing.
|
||||||
* Used to filter saved scenes by level. Auto-matched by stripping "_Editor" from the current map name.
|
* DisplayName is used for UI display and scene filtering.
|
||||||
* Example: "Warehouse", "Office", "Parking"
|
* MapPath is the full package path for OpenLevel (e.g. "/Game/Maps/Warehouse").
|
||||||
*/
|
*/
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS Editor")
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS Editor")
|
||||||
TArray<FString> BaseLevels;
|
TArray<FPS_Editor_BaseLevelEntry> BaseLevels;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -67,6 +67,11 @@ void UPS_Editor_SpawnManager::AddCatalog(UPS_Editor_SpawnCatalog* InCatalog)
|
|||||||
Resolved.Category = SpawnComp ? SpawnComp->Category : TEXT("Default");
|
Resolved.Category = SpawnComp ? SpawnComp->Category : TEXT("Default");
|
||||||
Resolved.Thumbnail = SpawnComp ? SpawnComp->Thumbnail : nullptr;
|
Resolved.Thumbnail = SpawnComp ? SpawnComp->Thumbnail : nullptr;
|
||||||
|
|
||||||
|
UE_LOG(LogTemp, Log, TEXT("PS_Editor: Resolved '%s' - SpawnComp=%s, Thumbnail=%s"),
|
||||||
|
*Resolved.DisplayName,
|
||||||
|
SpawnComp ? TEXT("found") : TEXT("null"),
|
||||||
|
Resolved.Thumbnail ? *Resolved.Thumbnail->GetPathName() : TEXT("null"));
|
||||||
|
|
||||||
ResolvedEntries.Add(Resolved);
|
ResolvedEntries.Add(Resolved);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -111,11 +111,18 @@ FReply FPS_Editor_SpawnableComponentCustomization::OnCaptureThumbnailClicked()
|
|||||||
|
|
||||||
uint8* MipData = Texture->Source.LockMip(0);
|
uint8* MipData = Texture->Source.LockMip(0);
|
||||||
FMemory::Memcpy(MipData, PixelData.GetData(), PixelData.Num());
|
FMemory::Memcpy(MipData, PixelData.GetData(), PixelData.Num());
|
||||||
|
// Force alpha to 255 — UE thumbnails may have zeroed alpha
|
||||||
|
for (int32 Px = 0; Px < Width * Height; ++Px)
|
||||||
|
{
|
||||||
|
MipData[Px * 4 + 3] = 255;
|
||||||
|
}
|
||||||
Texture->Source.UnlockMip(0);
|
Texture->Source.UnlockMip(0);
|
||||||
|
|
||||||
Texture->SRGB = true;
|
Texture->SRGB = true;
|
||||||
Texture->CompressionSettings = TC_Default;
|
Texture->CompressionSettings = TC_Default;
|
||||||
Texture->MipGenSettings = TMGS_NoMipmaps;
|
Texture->MipGenSettings = TMGS_NoMipmaps;
|
||||||
|
Texture->NeverStream = true;
|
||||||
|
Texture->LODGroup = TEXTUREGROUP_UI;
|
||||||
Texture->PostEditChange();
|
Texture->PostEditChange();
|
||||||
Texture->UpdateResource();
|
Texture->UpdateResource();
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ APS_Editor_SplineActor::APS_Editor_SplineActor()
|
|||||||
SplineMeshComp->SetupAttachment(Root);
|
SplineMeshComp->SetupAttachment(Root);
|
||||||
SplineMeshComp->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
|
SplineMeshComp->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
|
||||||
SplineMeshComp->SetCollisionResponseToAllChannels(ECR_Ignore);
|
SplineMeshComp->SetCollisionResponseToAllChannels(ECR_Ignore);
|
||||||
SplineMeshComp->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block);
|
SplineMeshComp->SetCollisionResponseToChannel(ECC_Camera, ECR_Block);
|
||||||
SplineMeshComp->bUseComplexAsSimpleCollision = true;
|
SplineMeshComp->bUseComplexAsSimpleCollision = true;
|
||||||
SplineMeshComp->SetCastShadow(false);
|
SplineMeshComp->SetCastShadow(false);
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ void APS_Editor_SplineActor::BeginPlay()
|
|||||||
CenterCube->SetWorldScale3D(FVector(CenterCubeScale));
|
CenterCube->SetWorldScale3D(FVector(CenterCubeScale));
|
||||||
CenterCube->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
|
CenterCube->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
|
||||||
CenterCube->SetCollisionResponseToAllChannels(ECR_Ignore);
|
CenterCube->SetCollisionResponseToAllChannels(ECR_Ignore);
|
||||||
CenterCube->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block);
|
CenterCube->SetCollisionResponseToChannel(ECC_Camera, ECR_Block);
|
||||||
CenterCube->SetCastShadow(false);
|
CenterCube->SetCastShadow(false);
|
||||||
if (CenterCubeMat)
|
if (CenterCubeMat)
|
||||||
{
|
{
|
||||||
@@ -316,7 +316,7 @@ UStaticMeshComponent* APS_Editor_SplineActor::CreatePointHandle(const FVector& W
|
|||||||
// Collision for raycast
|
// Collision for raycast
|
||||||
Handle->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
|
Handle->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
|
||||||
Handle->SetCollisionResponseToAllChannels(ECR_Ignore);
|
Handle->SetCollisionResponseToAllChannels(ECR_Ignore);
|
||||||
Handle->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block);
|
Handle->SetCollisionResponseToChannel(ECC_Camera, ECR_Block);
|
||||||
|
|
||||||
Handle->SetCastShadow(false);
|
Handle->SetCastShadow(false);
|
||||||
Handle->SetRenderInDepthPass(false);
|
Handle->SetRenderInDepthPass(false);
|
||||||
|
|||||||
@@ -624,8 +624,16 @@ TSharedRef<SWidget> UPS_Editor_MainWidget::BuildSceneButtons()
|
|||||||
EditorPC->bShowMouseCursor = false;
|
EditorPC->bShowMouseCursor = false;
|
||||||
EditorPC->SetInputMode(FInputModeGameOnly());
|
EditorPC->SetInputMode(FInputModeGameOnly());
|
||||||
|
|
||||||
// Use full path to avoid confusion with sublevel instances
|
// Use full path from MasterCatalog, fallback to /Game/{name}
|
||||||
FString MapPath = FString::Printf(TEXT("/Game/%s"), *BaseLevel);
|
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(""));
|
UGameplayStatics::OpenLevel(EditorPC, FName(*MapPath), true, TEXT(""));
|
||||||
return FReply::Handled();
|
return FReply::Handled();
|
||||||
})
|
})
|
||||||
@@ -676,7 +684,12 @@ TSharedRef<SWidget> UPS_Editor_MainWidget::BuildSceneButtons()
|
|||||||
{
|
{
|
||||||
if (EditorPC->CurrentBaseLevel != SceneLevelName)
|
if (EditorPC->CurrentBaseLevel != SceneLevelName)
|
||||||
{
|
{
|
||||||
EditorPC->LoadBaseLevelAsSublevel(SceneLevelName);
|
FString SceneMapPath = SceneLevelName;
|
||||||
|
if (FString* Found = BaseLevelPathMap.Find(SceneLevelName))
|
||||||
|
{
|
||||||
|
SceneMapPath = *Found;
|
||||||
|
}
|
||||||
|
EditorPC->LoadBaseLevelAsSublevel(SceneLevelName, SceneMapPath);
|
||||||
CurrentLevelFilter = EditorPC->CurrentBaseLevel;
|
CurrentLevelFilter = EditorPC->CurrentBaseLevel;
|
||||||
for (const TSharedPtr<FString>& Opt : BaseLevelOptions)
|
for (const TSharedPtr<FString>& Opt : BaseLevelOptions)
|
||||||
{
|
{
|
||||||
@@ -748,7 +761,12 @@ TSharedRef<SWidget> UPS_Editor_MainWidget::BuildSceneButtons()
|
|||||||
SaveNameField->SetText(FText::GetEmpty());
|
SaveNameField->SetText(FText::GetEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorPC->LoadBaseLevelAsSublevel(*Selected);
|
FString SublevelPath = *Selected;
|
||||||
|
if (FString* Found = BaseLevelPathMap.Find(*Selected))
|
||||||
|
{
|
||||||
|
SublevelPath = *Found;
|
||||||
|
}
|
||||||
|
EditorPC->LoadBaseLevelAsSublevel(*Selected, SublevelPath);
|
||||||
CurrentLevelFilter = EditorPC->CurrentBaseLevel;
|
CurrentLevelFilter = EditorPC->CurrentBaseLevel;
|
||||||
|
|
||||||
if (BaseLevelComboText.IsValid())
|
if (BaseLevelComboText.IsValid())
|
||||||
@@ -834,9 +852,13 @@ void UPS_Editor_MainWidget::NativeConstruct()
|
|||||||
BaseLevelOptions.Add(MakeShared<FString>(TEXT("None")));
|
BaseLevelOptions.Add(MakeShared<FString>(TEXT("None")));
|
||||||
if (UPS_Editor_MasterCatalog* Master = EditorPC->MasterCatalogAsset)
|
if (UPS_Editor_MasterCatalog* Master = EditorPC->MasterCatalogAsset)
|
||||||
{
|
{
|
||||||
for (const FString& Level : Master->BaseLevels)
|
for (const FPS_Editor_BaseLevelEntry& Entry : Master->BaseLevels)
|
||||||
{
|
{
|
||||||
BaseLevelOptions.Add(MakeShared<FString>(Level));
|
BaseLevelOptions.Add(MakeShared<FString>(Entry.DisplayName));
|
||||||
|
if (!Entry.MapPath.IsEmpty())
|
||||||
|
{
|
||||||
|
BaseLevelPathMap.Add(Entry.DisplayName, Entry.MapPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -915,7 +937,12 @@ void UPS_Editor_MainWidget::PopulateSceneList()
|
|||||||
{
|
{
|
||||||
if (EditorPC->CurrentBaseLevel != SceneLevelName)
|
if (EditorPC->CurrentBaseLevel != SceneLevelName)
|
||||||
{
|
{
|
||||||
EditorPC->LoadBaseLevelAsSublevel(SceneLevelName);
|
FString SceneMapPath = SceneLevelName;
|
||||||
|
if (FString* Found = BaseLevelPathMap.Find(SceneLevelName))
|
||||||
|
{
|
||||||
|
SceneMapPath = *Found;
|
||||||
|
}
|
||||||
|
EditorPC->LoadBaseLevelAsSublevel(SceneLevelName, SceneMapPath);
|
||||||
CurrentLevelFilter = EditorPC->CurrentBaseLevel;
|
CurrentLevelFilter = EditorPC->CurrentBaseLevel;
|
||||||
|
|
||||||
for (const TSharedPtr<FString>& Opt : BaseLevelOptions)
|
for (const TSharedPtr<FString>& Opt : BaseLevelOptions)
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ private:
|
|||||||
TArray<TSharedPtr<FString>> BaseLevelOptions;
|
TArray<TSharedPtr<FString>> BaseLevelOptions;
|
||||||
TSharedPtr<STextBlock> BaseLevelComboText;
|
TSharedPtr<STextBlock> BaseLevelComboText;
|
||||||
FString CurrentLevelFilter;
|
FString CurrentLevelFilter;
|
||||||
|
/** Maps DisplayName → full MapPath for base levels (from MasterCatalog). */
|
||||||
|
TMap<FString, FString> BaseLevelPathMap;
|
||||||
TArray<TSharedPtr<FSlateBrush>> CachedBrushes;
|
TArray<TSharedPtr<FSlateBrush>> CachedBrushes;
|
||||||
|
|
||||||
// Transform fields
|
// Transform fields
|
||||||
|
|||||||
Reference in New Issue
Block a user