#pragma once #include "CoreMinimal.h" #include "Components/ActorComponent.h" #include "DescentPlayerBodyComponent.generated.h" class USkeletalMeshComponent; class UMaterialInterface; class UDescentBodyAnimInstance; /** * The player's body: the Paragon Twinblast character (the default, red-armed mesh of the user's Fab pack) on ADescentCharacter's own * mesh component, seen in first person. Nothing in the pack is changed; everything here is set on the component at run time. * * - Body: the pack's mesh, feet on the capsule bottom, scaled so the eyes of his standing pose are at the camera (DescentTune_Body.h). * - Own view (the view target is the character): the head bone is hidden, the mesh is a first-person primitive (drawn nearer in * depth, so the hands do not enter a wall), stands a little behind the capsule axis and further back when the player looks down, * and the two upper arms are turned up and inward so the hands are in the picture. Any other view (a scenario camera, the helm's * cameras) sees the whole man in the pack's own pose. * - No guns: the pistols are one material section of the mesh, not drawn. One switch (descent.Body.Guns 1) draws them again. * - Machine legs: the lower-body material slot is overridden with our own material (Tools/ue/assets_13_twinblast.py). * - Animation: UDescentBodyAnimInstance, fed here with the real movement. * - The old cybernetic arm (Player/Arm) is one switch away: descent.Body.OldArm 1 hides the body and gives the arm back. */ UCLASS(ClassGroup = (Descent)) class THEDESCENT_API UDescentPlayerBodyComponent : public UActorComponent { GENERATED_BODY() public: UDescentPlayerBodyComponent(); /** For the character's constructor: place, turn and scale of the mesh component, no collision, not drawn until Setup gave it a mesh. */ static void ConfigureMeshDefaults(USkeletalMeshComponent* Mesh, double CapsuleHalfHeightCm); /** Gives the mesh component the Twinblast mesh, the leg material and the animation instance, and hides the guns. Idempotent; BeginPlay calls it. */ bool Setup(); bool IsSetUp() const { return bSetUp; } /** Applies visibility, the view settings, the switches, the lighting channels and the animation input from the character's state. The tick calls it. */ void Refresh(double DeltaSeconds); USkeletalMeshComponent* GetBodyMesh() const; UDescentBodyAnimInstance* GetAnim() const; // ---- the switches (console variables, so they hold for every character) ---- /** True: the old arm viewmodel is the player's view and the body is not drawn. */ static bool IsOldArmView(); static void SetOldArmView(bool bOldArm); static bool AreGunsWanted(); static void SetGunsWanted(bool bShow); // ---- what is applied right now ---- bool IsBodyShown() const { return bShown; } bool IsOwnView() const { return bOwnView; } bool AreGunsShown() const { return bGunsShown; } /** The engine's own answer for every LOD: is the pistol section drawn? */ bool IsPistolSectionShown() const; bool IsHeadHidden() const; bool IsLegMaterialApplied() const; bool IsInDryAir() const { return bInDryAir; } /** Height of the mesh's Eyes_Position socket above the feet, cm (needs evaluated bones: a running, rendered game). */ double MeasureEyeHeightCm() const; // ---- 2026-10-12 ---- /** descent.Body.ArmsUp, 0..1: how much of the "upper arms turned up into the view" of 2026-10-11 is applied (default 0). */ static double ArmsUp(); /** descent.Body.SwimArms: 1 = the swim's arm stroke is made in code with the hands in view (default), 0 = the clips' own arms. */ static double SwimArms(); /** The nutrition-port jack-in begins: the right arm reaches out, holds through the feed and comes back (retargeted set). */ void StartJack(const FVector* PortWorldUU = nullptr); // with the port's place the hand is taken to it (IK) bool IsJackPlaying() const { return JackSec >= 0.0; } /** Own view: degrees the body leans back about its feet at a down pitch, so the legs are in the picture (DescentTune_Body.h). */ static double LookDownLeanDeg(double DownDeg, double LeanMaxDeg); /** "Use" was pressed on something: the right arm pushes a button (retargeted set, upper body only). */ void NotifyUse(); /** The view bob the animation asks for AheadSec from now, -1..1 (the pelvis' up-and-down). False: the set has none measured. */ bool GetViewBobSignal(double AheadSec, double& OutSignal, double* OutFootfallHz = nullptr) const; /** Debug shots: the settings of "any other view" even while the view target is the character. */ bool bForceThirdPerson = false; protected: virtual void BeginPlay() override; virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; private: void ApplyGuns(bool bShow); void ApplyView(USkeletalMeshComponent* Mesh, bool bOwn); /** Our materials on slots of the mesh component, from the profile's material_overrides (Twinblast: the machine legs). */ UPROPERTY(Transient) TArray> OverrideMaterials; TArray OverrideIndices; TArray GunMaterialIndices; // the profile's gun_slots as material indices bool bOverridesComplete = false; bool bSetUp = false; bool bShown = false; bool bOwnView = false; bool bViewApplied = false; bool bGunsShown = true; bool bInDryAir = false; bool bLightApplied = false; bool bWasOldArm = false; bool bLoggedMissing = false; double JackSec = -1.0; double UseSec = -1.0; FVector JackPortLocal = FVector::ZeroVector; // the port in the character's frame, taken when the jack-in starts bool bJackPort = false; };