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/CharacterMovementComponent.h"
|
||||||
#include "GameFramework/PlayerController.h"
|
#include "GameFramework/PlayerController.h"
|
||||||
#include "InputAction.h"
|
#include "InputAction.h"
|
||||||
#include "GameFramework/PlayerController.h"
|
|
||||||
#include "InputMappingContext.h"
|
#include "InputMappingContext.h"
|
||||||
#include "Components/CapsuleComponent.h"
|
|
||||||
#include "Engine/World.h"
|
#include "Engine/World.h"
|
||||||
#include "TimerManager.h"
|
#include "TimerManager.h"
|
||||||
|
|
||||||
@@ -89,9 +87,9 @@ AGigLineCharacter::AGigLineCharacter()
|
|||||||
|
|
||||||
void AGigLineCharacter::LoadInputAssets()
|
void AGigLineCharacter::LoadInputAssets()
|
||||||
{
|
{
|
||||||
// The assets are hard-referenced and loaded in the constructor; this deferred
|
// The assets are hard-referenced and loaded in the constructor. This pushes
|
||||||
// call pushes the now-valid mapping context to the local player, after the
|
// the now-valid mapping context to the local player's subsystem; called from
|
||||||
// pawn has been possessed and its PlayerController exists.
|
// SetupPlayerInputComponent at possession, when the controller exists.
|
||||||
if (MappingContext)
|
if (MappingContext)
|
||||||
{
|
{
|
||||||
if (const APlayerController* PC = Cast<APlayerController>(GetController()))
|
if (const APlayerController* PC = Cast<APlayerController>(GetController()))
|
||||||
@@ -100,7 +98,17 @@ void AGigLineCharacter::LoadInputAssets()
|
|||||||
ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PC->GetLocalPlayer()))
|
ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PC->GetLocalPlayer()))
|
||||||
{
|
{
|
||||||
Subsystem->AddMappingContext(MappingContext, 0);
|
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();
|
StartLocation = GetActorLocation();
|
||||||
StartRotation = GetActorRotation();
|
StartRotation = GetActorRotation();
|
||||||
|
|
||||||
// Input assets are hard-referenced in the constructor. Defer the mapping
|
// Force game input mode + focus + mouse capture so keyboard/mouse reach the
|
||||||
// context push to just after spawn, when the PlayerController exists and a
|
// pawn regardless of window focus quirks.
|
||||||
// packaged game has finished mounting its pak IoStore.
|
if (APlayerController* PC = Cast<APlayerController>(GetController()))
|
||||||
FTimerHandle InputHandle;
|
{
|
||||||
GetWorldTimerManager().SetTimer(InputHandle, this, &AGigLineCharacter::LoadInputAssets, 1.0f, false);
|
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)
|
void AGigLineCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
|
||||||
@@ -130,6 +166,10 @@ void AGigLineCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputCo
|
|||||||
return;
|
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
|
// One action per direction keeps the sign explicit: W and S differ only by
|
||||||
// which handler runs, not by a modifier in the asset.
|
// which handler runs, not by a modifier in the asset.
|
||||||
if (MoveAction)
|
if (MoveAction)
|
||||||
@@ -165,6 +205,12 @@ void AGigLineCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputCo
|
|||||||
Input->BindAction(JumpAction, ETriggerEvent::Started, this, &AGigLineCharacter::StartJump);
|
Input->BindAction(JumpAction, ETriggerEvent::Started, this, &AGigLineCharacter::StartJump);
|
||||||
Input->BindAction(JumpAction, ETriggerEvent::Completed, this, &AGigLineCharacter::StopJump);
|
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
|
namespace
|
||||||
@@ -191,6 +237,8 @@ namespace
|
|||||||
|
|
||||||
void AGigLineCharacter::MoveForward(const FInputActionValue& Value)
|
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);
|
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)
|
void AGigLineCharacter::ApplyMove(float Forward, float Strafe)
|
||||||
{
|
{
|
||||||
const AController* Controller = GetController();
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forward/right on the controller yaw keeps the capsule upright on slopes.
|
// Forward/right on the controller yaw keeps the capsule upright on slopes.
|
||||||
const FRotator YawRotation(0.0f, Controller->GetControlRotation().Yaw, 0.0f);
|
const FRotator YawRotation(0.0f, Controller->GetControlRotation().Yaw, 0.0f);
|
||||||
const FVector ForwardDir = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
|
const FVector ForwardDir = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
|
||||||
@@ -224,6 +277,8 @@ void AGigLineCharacter::ApplyMove(float Forward, float Strafe)
|
|||||||
|
|
||||||
AddMovementInput(ForwardDir, Forward);
|
AddMovementInput(ForwardDir, Forward);
|
||||||
AddMovementInput(RightDir, Strafe);
|
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)
|
void AGigLineCharacter::Look(const FInputActionValue& Value)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "GigLineGameModeBase.h"
|
#include "GigLineGameModeBase.h"
|
||||||
|
|
||||||
|
#include "GameFramework/PlayerController.h"
|
||||||
#include "GigLineCharacter.h"
|
#include "GigLineCharacter.h"
|
||||||
#include "GigLineHUD.h"
|
#include "GigLineHUD.h"
|
||||||
|
|
||||||
@@ -9,3 +10,12 @@ AGigLineGameModeBase::AGigLineGameModeBase()
|
|||||||
// ODbL attribution must be visible in the running demo, not only in docs.
|
// ODbL attribution must be visible in the running demo, not only in docs.
|
||||||
HUDClass = AGigLineHUD::StaticClass();
|
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:
|
public:
|
||||||
AGigLineGameModeBase();
|
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
|
# 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.
|
# 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 = 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)
|
save(ia_move)
|
||||||
|
|
||||||
ia_look = fresh("IA_Look", unreal.InputAction, unreal.InputAction_Factory)
|
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
|
# 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.
|
# second action for strafe, both reporting on the value's single component.
|
||||||
ia_strafe = fresh("IA_Strafe", unreal.InputAction, unreal.InputAction_Factory)
|
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)
|
save(ia_strafe)
|
||||||
|
|
||||||
ia_back = fresh("IA_MoveBack", unreal.InputAction, unreal.InputAction_Factory)
|
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)
|
save(ia_back)
|
||||||
|
|
||||||
ia_left = fresh("IA_StrafeLeft", unreal.InputAction, unreal.InputAction_Factory)
|
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)
|
save(ia_left)
|
||||||
|
|
||||||
# Reset and pause are boolean: one press, no accumulator.
|
# Reset and pause are boolean: one press, no accumulator.
|
||||||
|
|||||||
Reference in new issue
Block a user