qa: walkable demo fixed — terrain collision root cause, spawn, and a scripted QA pass #7
No files matched your search
@@ -7,6 +7,15 @@ CopyrightNotice=
|
||||
BuildConfiguration=PPBC_Development
|
||||
FullRebuild=False
|
||||
UsePakFile=True
|
||||
; Runtime-loaded content must ship even when nothing statically references it.
|
||||
; The Enhanced Input assets are only soft-loaded by AGigLineCharacter at
|
||||
; BeginPlay; without this the cooker prunes them from the pak (observed: the
|
||||
; cook ReferencedSet had zero /Game/Input entries, so inputs were all nil and
|
||||
; no keys worked). Always cook the demo map + input. Keep both maps listed so
|
||||
; EditorStartupMap/GameDefaultMap selection stays flexible.
|
||||
+DirectoriesToAlwaysCook=/Game/Input
|
||||
+DirectoriesToAlwaysCook=/Game/Hollywood
|
||||
+DirectoriesToAlwaysCook=/Game/Test
|
||||
|
||||
[/Script/EngineSettings.GameMapsSettings]
|
||||
; Temporary default while the demo map is being built; GameMapsSettings in
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
#include "InputAction.h"
|
||||
#include "GameFramework/PlayerController.h"
|
||||
#include "InputMappingContext.h"
|
||||
#include "Components/CapsuleComponent.h"
|
||||
#include "Engine/World.h"
|
||||
#include "TimerManager.h"
|
||||
|
||||
AGigLineCharacter::AGigLineCharacter()
|
||||
{
|
||||
@@ -39,51 +42,56 @@ AGigLineCharacter::AGigLineCharacter()
|
||||
GetMesh()->SetHiddenInGame(true);
|
||||
GetMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
|
||||
|
||||
// Input assets are created by Tools/ue_create_input_assets.py. They are loaded in
|
||||
// BeginPlay rather than the constructor: the constructor runs during CDO
|
||||
// construction where asset loads are unreliable, and a missing asset should be
|
||||
// a loud warning, not a silent no-op.
|
||||
}
|
||||
// Hard-reference the Enhanced Input assets with ConstructorHelpers so the
|
||||
// cooker always includes them and they load during CDO construction. Runtime
|
||||
// soft-loading them at BeginPlay was fragile: the assets were pruned from the
|
||||
// pak unless /Game/Input was force-cooked, and a soft path can miss while the
|
||||
// IoStore registry is still mounting. A constructor FObjectFinder is a hard
|
||||
// reference (followed by the cooker) and loads deterministically.
|
||||
// Assets are created by Tools/ue_create_input_assets.py.
|
||||
static ConstructorHelpers::FObjectFinder<UInputMappingContext> CtxFinder(
|
||||
TEXT("/Game/Input/IMC_Default.IMC_Default"));
|
||||
static ConstructorHelpers::FObjectFinder<UInputAction> MoveF(
|
||||
TEXT("/Game/Input/IA_Move.IA_Move"));
|
||||
static ConstructorHelpers::FObjectFinder<UInputAction> StrafeF(
|
||||
TEXT("/Game/Input/IA_Strafe.IA_Strafe"));
|
||||
static ConstructorHelpers::FObjectFinder<UInputAction> BackF(
|
||||
TEXT("/Game/Input/IA_MoveBack.IA_MoveBack"));
|
||||
static ConstructorHelpers::FObjectFinder<UInputAction> LeftF(
|
||||
TEXT("/Game/Input/IA_StrafeLeft.IA_StrafeLeft"));
|
||||
static ConstructorHelpers::FObjectFinder<UInputAction> LookF(
|
||||
TEXT("/Game/Input/IA_Look.IA_Look"));
|
||||
static ConstructorHelpers::FObjectFinder<UInputAction> JumpF(
|
||||
TEXT("/Game/Input/IA_Jump.IA_Jump"));
|
||||
static ConstructorHelpers::FObjectFinder<UInputAction> ResetF(
|
||||
TEXT("/Game/Input/IA_Reset.IA_Reset"));
|
||||
static ConstructorHelpers::FObjectFinder<UInputAction> PauseF(
|
||||
TEXT("/Game/Input/IA_Pause.IA_Pause"));
|
||||
|
||||
void AGigLineCharacter::LoadInputAssets()
|
||||
{
|
||||
auto LoadSoft = [](const TCHAR* Path) -> TObjectPtr<UObject>
|
||||
{
|
||||
return LoadObject<UObject>(nullptr, Path);
|
||||
};
|
||||
MappingContext = Cast<UInputMappingContext>(LoadSoft(TEXT("/Game/Input/IMC_Default.IMC_Default")));
|
||||
MoveAction = Cast<UInputAction>(LoadSoft(TEXT("/Game/Input/IA_Move.IA_Move")));
|
||||
StrafeAction = Cast<UInputAction>(LoadSoft(TEXT("/Game/Input/IA_Strafe.IA_Strafe")));
|
||||
MoveBackAction = Cast<UInputAction>(LoadSoft(TEXT("/Game/Input/IA_MoveBack.IA_MoveBack")));
|
||||
StrafeLeftAction = Cast<UInputAction>(LoadSoft(TEXT("/Game/Input/IA_StrafeLeft.IA_StrafeLeft")));
|
||||
LookAction = Cast<UInputAction>(LoadSoft(TEXT("/Game/Input/IA_Look.IA_Look")));
|
||||
JumpAction = Cast<UInputAction>(LoadSoft(TEXT("/Game/Input/IA_Jump.IA_Jump")));
|
||||
ResetAction = Cast<UInputAction>(LoadSoft(TEXT("/Game/Input/IA_Reset.IA_Reset")));
|
||||
PauseAction = Cast<UInputAction>(LoadSoft(TEXT("/Game/Input/IA_Pause.IA_Pause")));
|
||||
MappingContext = CtxFinder.Object;
|
||||
MoveAction = MoveF.Object;
|
||||
StrafeAction = StrafeF.Object;
|
||||
MoveBackAction = BackF.Object;
|
||||
StrafeLeftAction = LeftF.Object;
|
||||
LookAction = LookF.Object;
|
||||
JumpAction = JumpF.Object;
|
||||
ResetAction = ResetF.Object;
|
||||
PauseAction = PauseF.Object;
|
||||
|
||||
if (!MappingContext || !MoveAction || !MoveBackAction || !StrafeAction || !StrafeLeftAction
|
||||
|| !LookAction)
|
||||
{
|
||||
UE_LOG(LogTemp, Warning,
|
||||
TEXT("GigLine: input assets missing (context=%s move=%s look=%s). ")
|
||||
TEXT("Run Tools/ue_create_input_assets.py to build /Game/Input."),
|
||||
MappingContext ? TEXT("ok") : TEXT("missing"),
|
||||
(MoveAction && MoveBackAction && StrafeAction && StrafeLeftAction) ? TEXT("ok")
|
||||
: TEXT("missing"),
|
||||
LookAction ? TEXT("ok") : TEXT("missing"));
|
||||
TEXT("GigLine: input assets failed to load at construction. ")
|
||||
TEXT("Run Tools/ue_create_input_assets.py to build /Game/Input."));
|
||||
}
|
||||
}
|
||||
|
||||
void AGigLineCharacter::BeginPlay()
|
||||
void AGigLineCharacter::LoadInputAssets()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
LoadInputAssets();
|
||||
|
||||
StartLocation = GetActorLocation();
|
||||
StartRotation = GetActorRotation();
|
||||
|
||||
// Push the mapping context for this local player.
|
||||
// The assets are hard-referenced and loaded in the constructor; this deferred
|
||||
// call pushes the now-valid mapping context to the local player, after the
|
||||
// pawn has been possessed and its PlayerController exists.
|
||||
if (MappingContext)
|
||||
{
|
||||
if (const APlayerController* PC = Cast<APlayerController>(GetController()))
|
||||
@@ -97,6 +105,20 @@ void AGigLineCharacter::BeginPlay()
|
||||
}
|
||||
}
|
||||
|
||||
void AGigLineCharacter::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
StartLocation = GetActorLocation();
|
||||
StartRotation = GetActorRotation();
|
||||
|
||||
// Input assets are hard-referenced in the constructor. Defer the mapping
|
||||
// context push to just after spawn, when the PlayerController exists and a
|
||||
// packaged game has finished mounting its pak IoStore.
|
||||
FTimerHandle InputHandle;
|
||||
GetWorldTimerManager().SetTimer(InputHandle, this, &AGigLineCharacter::LoadInputAssets, 1.0f, false);
|
||||
}
|
||||
|
||||
void AGigLineCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
|
||||
{
|
||||
Super::SetupPlayerInputComponent(PlayerInputComponent);
|
||||
|
||||
+18
-10
@@ -146,7 +146,7 @@ def build():
|
||||
log(f"could not create {MAP}")
|
||||
return
|
||||
|
||||
removed = clear(("Demo_", "PlayerStart", "Hero_Facade", "Frontage_"))
|
||||
removed = clear(("Demo_", "PlayerStart", "Hero_Facade", "Frontage_", "ShotSequencer"))
|
||||
log(f"cleared {removed} previous demo actors")
|
||||
|
||||
# --- lighting: fixed daytime ------------------------------------------
|
||||
@@ -256,7 +256,7 @@ def build():
|
||||
actor = spawn(unreal.StaticMeshActor, unreal.Vector(-13336.0, 1307.0, 0.0), "Hero_Facade")
|
||||
if actor:
|
||||
actor.static_mesh_component.set_static_mesh(hero)
|
||||
actor.static_mesh_component.set_mobility(unreal.ComponentMobility.MOVABLE)
|
||||
actor.static_mesh_component.set_mobility(unreal.ComponentMobility.STATIC)
|
||||
log("staged: Hero_Facade at the building line")
|
||||
else:
|
||||
log("MISSING: SM_HeroFacade — run Tools/ue_hero_facade_import.py")
|
||||
@@ -303,11 +303,18 @@ def build():
|
||||
continue
|
||||
actor = spawn(unreal.StaticMeshActor, unreal.Vector(0, 0, 0), f"Demo_{name}")
|
||||
if actor:
|
||||
actor.static_mesh_component.set_static_mesh(mesh)
|
||||
actor.static_mesh_component.set_mobility(unreal.ComponentMobility.MOVABLE)
|
||||
comp = actor.static_mesh_component
|
||||
comp.set_static_mesh(mesh)
|
||||
# Immutable level geometry must be STATIC to reliably expose its
|
||||
# complex-as-simple collision body to CharacterMovement; staging
|
||||
# these MOVABLE let the player fall through the world.
|
||||
comp.set_mobility(unreal.ComponentMobility.STATIC)
|
||||
comp.set_collision_enabled(unreal.CollisionEnabled.QUERY_AND_PHYSICS)
|
||||
comp.set_collision_object_type(unreal.CollisionChannel.ECC_WORLD_STATIC)
|
||||
comp.set_collision_profile_name("BlockAll")
|
||||
mat = built.get(mat_name)
|
||||
if mat:
|
||||
actor.static_mesh_component.set_material(0, mat)
|
||||
comp.set_material(0, mat)
|
||||
imported += 1
|
||||
log(f"staged {imported} site meshes with explicit surface materials")
|
||||
|
||||
@@ -362,11 +369,12 @@ def build():
|
||||
# --- player start: north sidewalk, facing the hero frontage -------------
|
||||
# Signs were measured from the imported meshes rather than assumed: the FBX
|
||||
# preset flips north, so in Unreal the road spans Y -1382..+1047, the NORTH
|
||||
# sidewalk is at Y -1912..-1053 and the SOUTH sidewalk at Y +718..+1447. The
|
||||
# facade stands at Y -1450. Stand on the north sidewalk and look north (-Y).
|
||||
# North sidewalk (Y -1912..-1053), facing south (+Y) across the road at the
|
||||
# hero on the south side. Yaw 90 looks along +Y.
|
||||
spawn(unreal.PlayerStart, unreal.Vector(-13336.0, -1700.0, 120.0), "Demo_PlayerStart",
|
||||
# sidewalk is at Y -1912..-1053 and the SOUTH sidewalk at Y +718..+1447.
|
||||
# The hero facade is on the SOUTH side at Y +1307. Stand on the north
|
||||
# sidewalk and face south (+Y, yaw 90) across the road at it.
|
||||
# Z 200 is clear air so the capsule settles onto the pavement instead of
|
||||
# spawning embedded or below grade (the fall-through QA finding).
|
||||
spawn(unreal.PlayerStart, unreal.Vector(-13336.0, -1700.0, 200.0), "Demo_PlayerStart",
|
||||
unreal.Rotator(pitch=0.0, yaw=90.0, roll=0.0))
|
||||
log("staged: Demo_PlayerStart on the north sidewalk facing south (+Y)")
|
||||
|
||||
|
||||
Reference in new issue
Block a user