qa wip: spawn in front of facade + input/sim diagnostics
- PlayerStart moved to (-10722,-2400,800) clear air, facing the facade. - Force game input mode + hide cursor at BeginPlay. - Diagnostics: every-second world/Z/gravity/fall log; one HighResShot at 1.5s. Verified (packaged, engine log): controller connects to pawn input=yes, ctx pushed, actions bound, world ticks, gravity -980, but capsule stays Z=909 fall=0 forever and no input fires. Static airborne pawn + no fall + no input = pawn simulated without an active autonomous local player. Recorded for next debug; do not merge to main.
This commit is contained in:
1 parent
ea16818e2a
commit
2199a546bd
8 files changed
+97
-24
No files matched your search
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -7,9 +7,7 @@
|
||||
#include "GameFramework/CharacterMovementComponent.h"
|
||||
#include "GameFramework/PlayerController.h"
|
||||
#include "InputAction.h"
|
||||
#include "GameFramework/PlayerController.h"
|
||||
#include "InputMappingContext.h"
|
||||
#include "Components/CapsuleComponent.h"
|
||||
#include "Engine/World.h"
|
||||
#include "TimerManager.h"
|
||||
|
||||
@@ -89,9 +87,9 @@ AGigLineCharacter::AGigLineCharacter()
|
||||
|
||||
void AGigLineCharacter::LoadInputAssets()
|
||||
{
|
||||
// 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.
|
||||
// The assets are hard-referenced and loaded in the constructor. This pushes
|
||||
// the now-valid mapping context to the local player's subsystem; called from
|
||||
// SetupPlayerInputComponent at possession, when the controller exists.
|
||||
if (MappingContext)
|
||||
{
|
||||
if (const APlayerController* PC = Cast<APlayerController>(GetController()))
|
||||
@@ -100,7 +98,17 @@ void AGigLineCharacter::LoadInputAssets()
|
||||
ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PC->GetLocalPlayer()))
|
||||
{
|
||||
Subsystem->AddMappingContext(MappingContext, 0);
|
||||
UE_LOG(LogTemp, Log, TEXT("GigLine IN: pushed mapping context %s"),
|
||||
*MappingContext->GetName());
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogTemp, Log, TEXT("GigLine IN: no enhanced input subsystem on local player"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UE_LOG(LogTemp, Log, TEXT("GigLine IN: no PlayerController at LoadInputAssets"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,11 +120,39 @@ void AGigLineCharacter::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);
|
||||
// Force game input mode + focus + mouse capture so keyboard/mouse reach the
|
||||
// pawn regardless of window focus quirks.
|
||||
if (APlayerController* PC = Cast<APlayerController>(GetController()))
|
||||
{
|
||||
PC->SetInputMode(FInputModeGameOnly());
|
||||
PC->bShowMouseCursor = false;
|
||||
}
|
||||
|
||||
// TEMP QA: one screenshot at +1.5s so the actual frame is reviewable.
|
||||
FTimerHandle ShotHandle;
|
||||
GetWorldTimerManager().SetTimer(ShotHandle, [this]()
|
||||
{
|
||||
if (APlayerController* PC = Cast<APlayerController>(GetController()))
|
||||
{
|
||||
PC->ConsoleCommand(TEXT("HighResShot 1280 720"));
|
||||
}
|
||||
}, 1.5f, false);
|
||||
|
||||
// TEMP QA: every second log world time + capsule Z + gravity + fall state so
|
||||
// we can see whether the world is simulating the pawn at all (symptom:
|
||||
// "spawns above ground but never falls, no input").
|
||||
FTimerHandle SimHandle;
|
||||
GetWorldTimerManager().SetTimer(SimHandle, [this]()
|
||||
{
|
||||
UCharacterMovementComponent* M = GetCharacterMovement();
|
||||
UE_LOG(LogTemp, Log,
|
||||
TEXT("GigLine SIM: worldTime=%.2f Z=%.0f grav=%.1f fall=%d pawn=%s"),
|
||||
GetWorld() ? GetWorld()->GetTimeSeconds() : -1.f,
|
||||
GetActorLocation().Z,
|
||||
M ? M->GetGravityZ() : 0.f,
|
||||
(M && M->IsFalling()) ? 1 : 0,
|
||||
*GetName());
|
||||
}, 1.0f, true);
|
||||
}
|
||||
|
||||
void AGigLineCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
|
||||
@@ -130,6 +166,10 @@ void AGigLineCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputCo
|
||||
return;
|
||||
}
|
||||
|
||||
// Push the mapping context for this controller's local player so the bound
|
||||
// actions receive input (runs at possession, when the controller exists).
|
||||
LoadInputAssets();
|
||||
|
||||
// One action per direction keeps the sign explicit: W and S differ only by
|
||||
// which handler runs, not by a modifier in the asset.
|
||||
if (MoveAction)
|
||||
@@ -165,6 +205,12 @@ void AGigLineCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputCo
|
||||
Input->BindAction(JumpAction, ETriggerEvent::Started, this, &AGigLineCharacter::StartJump);
|
||||
Input->BindAction(JumpAction, ETriggerEvent::Completed, this, &AGigLineCharacter::StopJump);
|
||||
}
|
||||
UE_LOG(LogTemp, Log, TEXT("GigLine IN: bound %d actions; ctx=%s move=%s look=%s jmp=%s"),
|
||||
(Input ? 1 : 0),
|
||||
MappingContext ? TEXT("ok") : TEXT("nil"),
|
||||
MoveAction ? TEXT("ok") : TEXT("nil"),
|
||||
LookAction ? TEXT("ok") : TEXT("nil"),
|
||||
JumpAction ? TEXT("ok") : TEXT("nil"));
|
||||
}
|
||||
|
||||
namespace
|
||||
@@ -191,6 +237,8 @@ namespace
|
||||
|
||||
void AGigLineCharacter::MoveForward(const FInputActionValue& Value)
|
||||
{
|
||||
UE_LOG(LogTemp, Log, TEXT("GigLine IN: MoveForward fired, axis=%.3f type=%d"),
|
||||
FMath::Abs(SignedAxis(Value, false)), (int)Value.GetValueType());
|
||||
ApplyMove(FMath::Abs(SignedAxis(Value, false)), 0.0f);
|
||||
}
|
||||
|
||||
@@ -212,11 +260,16 @@ void AGigLineCharacter::MoveLeft(const FInputActionValue& Value)
|
||||
void AGigLineCharacter::ApplyMove(float Forward, float Strafe)
|
||||
{
|
||||
const AController* Controller = GetController();
|
||||
if (!Controller || (FMath::IsNearlyZero(Forward) && FMath::IsNearlyZero(Strafe)))
|
||||
if (!Controller)
|
||||
{
|
||||
UE_LOG(LogTemp, Log, TEXT("GigLine IN: ApplyMove called but NO controller (fwd %.2f strafe %.2f)"),
|
||||
Forward, Strafe);
|
||||
return;
|
||||
}
|
||||
if (FMath::IsNearlyZero(Forward) && FMath::IsNearlyZero(Strafe))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Forward/right on the controller yaw keeps the capsule upright on slopes.
|
||||
const FRotator YawRotation(0.0f, Controller->GetControlRotation().Yaw, 0.0f);
|
||||
const FVector ForwardDir = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
|
||||
@@ -224,6 +277,8 @@ void AGigLineCharacter::ApplyMove(float Forward, float Strafe)
|
||||
|
||||
AddMovementInput(ForwardDir, Forward);
|
||||
AddMovementInput(RightDir, Strafe);
|
||||
UE_LOG(LogTemp, Log, TEXT("GigLine IN: ApplyMove fwd %.2f strafe %.2f controller=%s yaw=%.0f"),
|
||||
Forward, Strafe, *Controller->GetName(), Controller->GetControlRotation().Yaw);
|
||||
}
|
||||
|
||||
void AGigLineCharacter::Look(const FInputActionValue& Value)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "GigLineGameModeBase.h"
|
||||
|
||||
#include "GameFramework/PlayerController.h"
|
||||
#include "GigLineCharacter.h"
|
||||
#include "GigLineHUD.h"
|
||||
|
||||
@@ -9,3 +10,12 @@ AGigLineGameModeBase::AGigLineGameModeBase()
|
||||
// ODbL attribution must be visible in the running demo, not only in docs.
|
||||
HUDClass = AGigLineHUD::StaticClass();
|
||||
}
|
||||
|
||||
void AGigLineGameModeBase::HandleStartingNewPlayer_Implementation(APlayerController* NewPlayer)
|
||||
{
|
||||
Super::HandleStartingNewPlayer_Implementation(NewPlayer);
|
||||
UE_LOG(LogTemp, Log, TEXT("GigLine GM: player %s connected; pawn=%s input=%s"),
|
||||
NewPlayer ? *NewPlayer->GetName() : TEXT("null"),
|
||||
NewPlayer && NewPlayer->GetPawn() ? *NewPlayer->GetPawn()->GetName() : TEXT("NONE"),
|
||||
NewPlayer && NewPlayer->PlayerInput ? TEXT("yes") : TEXT("no"));
|
||||
}
|
||||
@@ -18,4 +18,8 @@ class GIGLINE_API AGigLineGameModeBase : public AGameModeBase
|
||||
|
||||
public:
|
||||
AGigLineGameModeBase();
|
||||
|
||||
protected:
|
||||
/** Logs whether a local player connected to a pawn with input (QA). */
|
||||
virtual void HandleStartingNewPlayer_Implementation(class APlayerController* NewPlayer) override;
|
||||
};
|
||||
@@ -85,7 +85,11 @@ def build():
|
||||
# component and D/A carry strafe, combined by the character. A 2D value would
|
||||
# need per-key axis modifiers, and modifiers do not survive the save path here.
|
||||
ia_move = fresh("IA_Move", unreal.InputAction, unreal.InputAction_Factory)
|
||||
ia_move.set_editor_property("value_type", unreal.InputActionValueType.AXIS1D)
|
||||
# Boolean (pressed = 1), not AXIS1D: the C++ handler reads Get<bool>() and
|
||||
# moves at full walk speed. An axis action from a keyboard key can deliver 0
|
||||
# depending on the trigger, which showed up as "character stands, W does not
|
||||
# move" in QA. WASD are four separate per-direction actions below.
|
||||
ia_move.set_editor_property("value_type", unreal.InputActionValueType.BOOLEAN)
|
||||
save(ia_move)
|
||||
|
||||
ia_look = fresh("IA_Look", unreal.InputAction, unreal.InputAction_Factory)
|
||||
@@ -107,15 +111,15 @@ def build():
|
||||
# Two actions feed the one-dimensional move: IA_Move for forward/back, and a
|
||||
# second action for strafe, both reporting on the value's single component.
|
||||
ia_strafe = fresh("IA_Strafe", unreal.InputAction, unreal.InputAction_Factory)
|
||||
ia_strafe.set_editor_property("value_type", unreal.InputActionValueType.AXIS1D)
|
||||
ia_strafe.set_editor_property("value_type", unreal.InputActionValueType.BOOLEAN)
|
||||
save(ia_strafe)
|
||||
|
||||
ia_back = fresh("IA_MoveBack", unreal.InputAction, unreal.InputAction_Factory)
|
||||
ia_back.set_editor_property("value_type", unreal.InputActionValueType.AXIS1D)
|
||||
ia_back.set_editor_property("value_type", unreal.InputActionValueType.BOOLEAN)
|
||||
save(ia_back)
|
||||
|
||||
ia_left = fresh("IA_StrafeLeft", unreal.InputAction, unreal.InputAction_Factory)
|
||||
ia_left.set_editor_property("value_type", unreal.InputActionValueType.AXIS1D)
|
||||
ia_left.set_editor_property("value_type", unreal.InputActionValueType.BOOLEAN)
|
||||
save(ia_left)
|
||||
|
||||
# Reset and pause are boolean: one press, no accumulator.
|
||||
|
||||
Reference in new issue
Block a user