630 lines
24 KiB
C++
630 lines
24 KiB
C++
// Fill out your copyright notice in the Description page of Project Settings.
|
|
|
|
#pragma once
|
|
|
|
#include "CoreMinimal.h"
|
|
// ESlateVisibility n'est que declare en avant par le moteur : il faut le type
|
|
// complet pour en stocker une valeur par defaut. Meme raison pour
|
|
// ECraftingStation, stocke en membre.
|
|
#include "Components/SlateWrapperTypes.h"
|
|
#include "CraftingRecipeDataAsset.h"
|
|
#include "GameFramework/PlayerController.h"
|
|
#include "FpsPlayerController.generated.h"
|
|
|
|
class AStorageContainer;
|
|
class UConfirmDialogWidget;
|
|
class UCraftingComponent;
|
|
class UHotbarWidget;
|
|
class UInputAction;
|
|
class UInventoryComponent;
|
|
class UInteractionPromptWidget;
|
|
class UInventoryScreenWidget;
|
|
class UPauseMenuWidget;
|
|
class UScreenFadeComponent;
|
|
class USettingsMenuWidget;
|
|
class USurvivalStatsWidget;
|
|
class UUserWidget;
|
|
struct FInputActionValue;
|
|
|
|
/**
|
|
* Controller du joueur. C'est ici que vit l'UI, et pas dans le personnage :
|
|
* le controller survit a la mort du pawn, alors que le personnage non.
|
|
* Si tu creais le HUD dans AFpsPlayer, il disparaitrait a chaque respawn.
|
|
*/
|
|
UCLASS()
|
|
class SURVIVAL_PROJET_API AFpsPlayerController : public APlayerController
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
public:
|
|
AFpsPlayerController();
|
|
|
|
/** Ouvre ou ferme l'ecran, toujours sur l'onglet Inventaire. */
|
|
UFUNCTION(BlueprintCallable, Category = "UI")
|
|
void ToggleInventory();
|
|
|
|
/**
|
|
* Ouvre l'ecran directement sur l'onglet Fabrication.
|
|
* Depuis l'onglet Inventaire elle bascule, depuis l'onglet Fabrication elle referme.
|
|
*/
|
|
UFUNCTION(BlueprintCallable, Category = "UI")
|
|
void ToggleCrafting();
|
|
|
|
/**
|
|
* Ouvre l'ecran de fabrication depuis un poste de travail.
|
|
*
|
|
* L'acces au poste ne dure QUE le temps de l'ecran : il est accorde ici et
|
|
* repris a la fermeture. C'est le contrat de l'interaction -- on fabrique a
|
|
* l'etabli parce qu'on est en train de s'en servir, pas parce qu'on en a
|
|
* croise un un jour.
|
|
*
|
|
* Le contrôleur s'en charge et non l'etabli : c'est lui qui sait quand
|
|
* l'ecran se referme, et lui seul peut donc rendre le poste au bon moment.
|
|
*/
|
|
UFUNCTION(BlueprintCallable, Category = "UI")
|
|
void OpenCraftingAtStation(ECraftingStation Station);
|
|
|
|
UFUNCTION(BlueprintPure, Category = "UI")
|
|
bool IsInventoryOpen() const { return bInventoryOpen; }
|
|
|
|
/**
|
|
* Ouvre l'ecran d'inventaire avec le panneau du coffre a cote : le sac a
|
|
* gauche, son contenu a droite.
|
|
*
|
|
* Ce n'est PAS un ecran a part. Le sac du joueur reste exactement au meme
|
|
* endroit qu'à l'ouverture par Tab -- c'est tout l'interet, un ecran
|
|
* distinct le ferait sauter a chaque fois qu'on ouvre un coffre.
|
|
*
|
|
* Comme pour l'etabli, c'est le controller qui pilote et non le coffre : lui
|
|
* seul sait quand l'ecran se referme, et donc quand refermer le couvercle.
|
|
*/
|
|
UFUNCTION(BlueprintCallable, Category = "UI|Storage")
|
|
void OpenStorage(AStorageContainer* Container);
|
|
|
|
/** Referme l'ecran de coffre. Sans effet s'il n'y en a pas d'ouvert. */
|
|
UFUNCTION(BlueprintCallable, Category = "UI|Storage")
|
|
void CloseStorage();
|
|
|
|
UFUNCTION(BlueprintPure, Category = "UI|Storage")
|
|
bool IsStorageOpen() const { return bStorageOpen; }
|
|
|
|
/** Ferme le menu de pause et relance le monde. */
|
|
UFUNCTION(BlueprintCallable, Category = "UI|Pause")
|
|
void ResumeGame();
|
|
|
|
/** Ouvre la demande de confirmation. Ne quitte rien par elle-meme. */
|
|
UFUNCTION(BlueprintCallable, Category = "UI|Pause")
|
|
void RequestQuitToMainMenu();
|
|
|
|
UFUNCTION(BlueprintPure, Category = "UI|Pause")
|
|
bool IsPauseMenuOpen() const { return bPauseMenuOpen; }
|
|
|
|
/** Ouvre l'ecran de reglages par-dessus le menu de pause. */
|
|
UFUNCTION(BlueprintCallable, Category = "UI|Reglages")
|
|
void OpenSettings();
|
|
|
|
/**
|
|
* Ouvre le panneau d'invitation de l'overlay Steam.
|
|
*
|
|
* Passe par le controller et non directement du widget au sous-systeme :
|
|
* inviter est une action du JOUEUR LOCAL, et le controller est justement
|
|
* l'objet qui le represente. Un widget qui irait chercher un
|
|
* GameInstanceSubsystem tout seul se brancherait sur le mauvais joueur le
|
|
* jour ou l'ecran partage existera.
|
|
*/
|
|
UFUNCTION(BlueprintCallable, Category = "Coop")
|
|
void ShowInviteFriends();
|
|
|
|
/** Faux quand Steam est absent ou qu'aucune session n'a pu etre creee. */
|
|
UFUNCTION(BlueprintPure, Category = "Coop")
|
|
bool CanInviteFriends() const;
|
|
|
|
protected:
|
|
virtual void BeginPlay() override;
|
|
|
|
/** Serveur uniquement. Chez un client, c'est AcknowledgePossession qui arrive. */
|
|
virtual void OnPossess(APawn* InPawn) override;
|
|
|
|
/**
|
|
* Le pendant CLIENT de OnPossess.
|
|
*
|
|
* OnPossess n'existe QUE sur le serveur : chez un client le pawn arrive par
|
|
* replication et cette fonction n'est jamais appelee. Comme c'est elle qui
|
|
* construisait le HUD, un joueur qui se connectait n'avait aucune interface --
|
|
* ni viseur, ni barre rapide, ni jauges. Le piege est d'autant plus fourbe
|
|
* que l'hote, lui, est bien le serveur et voit son HUD parfaitement.
|
|
*/
|
|
virtual void AcknowledgePossession(APawn* P) override;
|
|
|
|
virtual void SetupInputComponent() override;
|
|
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
|
|
|
|
// ------------------------------------------------------------------
|
|
// Fondus
|
|
//
|
|
// La mécanique elle-même vit dans UScreenFadeComponent, partagé avec le
|
|
// menu principal. Ici on ne garde que les durées propres au jeu.
|
|
// La couleur et le WBP_Fade se règlent sur le composant.
|
|
// ------------------------------------------------------------------
|
|
|
|
/** Le voile. Assigne-lui ton WBP_Fade dans BP_FpsPlayerController. */
|
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "UI|Fondu")
|
|
TObjectPtr<UScreenFadeComponent> ScreenFade;
|
|
|
|
/** Décoche pour démarrer sans fondu, pratique pendant les tests. */
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Fondu")
|
|
bool bFadeInOnStart = true;
|
|
|
|
/**
|
|
* Délai maximal d'attente du pawn avant d'éclaircir quand même.
|
|
*
|
|
* Filet de sécurité pur : si la possession n'arrivait jamais, l'écran
|
|
* resterait noir pour toujours et le joueur croirait le jeu planté. Mieux
|
|
* vaut une vue bancale qu'un écran mort.
|
|
*/
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Fondu", meta = (ClampMin = "1", Units = "s"))
|
|
float StartupFadeTimeout = 10.f;
|
|
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Fondu", meta = (ClampMin = "0.1"))
|
|
float StartupFadeDuration = 1.5f;
|
|
|
|
/** Durée du fondu au noir quand le joueur meurt. */
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Fondu", meta = (ClampMin = "0.1"))
|
|
float DeathFadeDuration = 1.f;
|
|
|
|
/**
|
|
* Temps total entre la mort et la réapparition.
|
|
* Doit rester supérieur à DeathFadeDuration, sinon le joueur réapparaît
|
|
* avant que l'écran soit entièrement noir.
|
|
*/
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Fondu", meta = (ClampMin = "0.1"))
|
|
float RespawnDelay = 3.f;
|
|
|
|
/**
|
|
* Ouverture de l'inventaire, valeur Digital (bool).
|
|
* L'input d'interface vit sur le controller et non sur le pawn : ouvrir
|
|
* son sac doit rester possible meme sans corps a piloter.
|
|
*/
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
|
TObjectPtr<UInputAction> ToggleInventoryAction;
|
|
|
|
/**
|
|
* Ouverture directe sur l'onglet Fabrication, valeur Digital (bool).
|
|
* Sur le controller comme ToggleInventoryAction : elle doit repondre alors
|
|
* meme que l'input du pawn est coupe, ecran ouvert.
|
|
*/
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
|
TObjectPtr<UInputAction> ToggleCraftingAction;
|
|
|
|
/**
|
|
* Jette l'objet survole, valeur Digital (bool). Ctrl enfonce = un seul
|
|
* exemplaire au lieu de la pile entiere.
|
|
* Sur le controller aussi : le pawn a ses inputs coupes quand l'inventaire
|
|
* est ouvert, donc un binding sur le pawn ne repondrait jamais.
|
|
*/
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
|
TObjectPtr<UInputAction> DropItemAction;
|
|
|
|
/**
|
|
* Selection directe d'un slot de la barre rapide, valeur Axis1D.
|
|
*
|
|
* Une seule action pour toutes les touches : dans IMC_Default, mappe les
|
|
* touches 1 a 6 sur cette action et donne a chacune un modificateur
|
|
* Scalar different (1, 2, 3...). Le handler lit la valeur et en deduit
|
|
* le slot. Six actions separees seraient six assets a maintenir.
|
|
*/
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
|
TObjectPtr<UInputAction> HotbarSelectAction;
|
|
|
|
/** Molette de souris pour defiler dans la barre, valeur Axis1D. */
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
|
TObjectPtr<UInputAction> HotbarScrollAction;
|
|
|
|
/**
|
|
* Echap : ferme l'inventaire s'il est ouvert, sinon bascule la pause.
|
|
*
|
|
* ATTENTION : coche "Trigger When Paused" sur l'asset IA_Pause. Un jeu en
|
|
* pause ne fait plus qu'un tick reduit ou seules les actions portant ce
|
|
* drapeau sont evaluees -- sans lui, on peut mettre en pause mais plus
|
|
* jamais en sortir au clavier.
|
|
*/
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
|
TObjectPtr<UInputAction> PauseAction;
|
|
|
|
/**
|
|
* Viseur, affiche en permanence. Widget separe du prompt : ce dernier se
|
|
* met en Collapsed des qu'on ne vise plus rien, et emporterait le viseur
|
|
* avec lui s'ils partageaient le meme widget.
|
|
*/
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI")
|
|
TSubclassOf<UUserWidget> CrosshairClass;
|
|
|
|
/** A assigner dans BP_FpsPlayerController : ton WBP_InteractionPrompt. */
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI")
|
|
TSubclassOf<UInteractionPromptWidget> InteractionPromptClass;
|
|
|
|
/**
|
|
* Ton WBP_InventoryScreen : l'ecran a onglets qui contient la grille
|
|
* d'inventaire ET la page de fabrication. Ce n'est plus WBP_Inventory
|
|
* directement, celui-ci est devenu une page a l'interieur.
|
|
*/
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI")
|
|
TSubclassOf<UInventoryScreenWidget> InventoryScreenClass;
|
|
|
|
/**
|
|
* Distance au-dela de laquelle l'ecran de coffre se referme tout seul.
|
|
*
|
|
* Sans elle, on viderait un coffre depuis l'autre bout de la carte : rien
|
|
* n'oblige le joueur a rester devant une fois l'ecran ouvert.
|
|
*/
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Storage", meta = (ClampMin = "50", Units = "cm"))
|
|
float MaxStorageDistance = 400.f;
|
|
|
|
/** Ton WBP_Hotbar, affiche en permanence. */
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI")
|
|
TSubclassOf<UHotbarWidget> HotbarClass;
|
|
|
|
/** Ton WBP_SurvivalStats : les trois jauges. */
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI")
|
|
TSubclassOf<USurvivalStatsWidget> SurvivalStatsClass;
|
|
|
|
/** Ton WBP_PauseMenu. */
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Pause")
|
|
TSubclassOf<UPauseMenuWidget> PauseMenuClass;
|
|
|
|
/**
|
|
* Ton WBP_ConfirmDialog, le meme que celui du menu principal. Laisse-le
|
|
* assigne : sans lui on retourne au menu sans rien demander, et la partie
|
|
* est perdue sur un clic.
|
|
*/
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Pause")
|
|
TSubclassOf<UConfirmDialogWidget> QuitToMenuDialogClass;
|
|
|
|
/** La question posee avant d'abandonner la partie. */
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Pause")
|
|
FText QuitToMenuMessage;
|
|
|
|
/**
|
|
* Ton WBP_Settings, le meme que celui du menu principal. C'est tout
|
|
* l'interet de son delegue OnCloseRequested : l'ecran ignore qui l'ouvre.
|
|
*/
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Reglages")
|
|
TSubclassOf<USettingsMenuWidget> SettingsMenuClass;
|
|
|
|
/**
|
|
* Ta map de menu principal.
|
|
*
|
|
* TSoftObjectPtr comme dans AMainMenuPlayerController : une reference dure
|
|
* ferait charger la map du menu en meme temps que celle du jeu.
|
|
*/
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Pause")
|
|
TSoftObjectPtr<UWorld> MainMenuLevel;
|
|
|
|
/** Fondu au noir avant de rendre la main au menu principal. */
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "UI|Fondu", meta = (ClampMin = "0.1"))
|
|
float QuitToMenuFadeDuration = 1.f;
|
|
|
|
UPROPERTY(Transient, BlueprintReadOnly, Category = "UI")
|
|
TObjectPtr<UUserWidget> Crosshair;
|
|
|
|
UPROPERTY(Transient, BlueprintReadOnly, Category = "UI")
|
|
TObjectPtr<UInteractionPromptWidget> InteractionPrompt;
|
|
|
|
UPROPERTY(Transient, BlueprintReadOnly, Category = "UI")
|
|
TObjectPtr<UInventoryScreenWidget> InventoryScreen;
|
|
|
|
UPROPERTY(Transient, BlueprintReadOnly, Category = "UI")
|
|
TObjectPtr<UHotbarWidget> Hotbar;
|
|
|
|
UPROPERTY(Transient, BlueprintReadOnly, Category = "UI")
|
|
TObjectPtr<USurvivalStatsWidget> SurvivalStatsWidget;
|
|
|
|
UPROPERTY(Transient, BlueprintReadOnly, Category = "UI|Pause")
|
|
TObjectPtr<UPauseMenuWidget> PauseMenu;
|
|
|
|
UPROPERTY(Transient, BlueprintReadOnly, Category = "UI|Pause")
|
|
TObjectPtr<UConfirmDialogWidget> QuitToMenuDialog;
|
|
|
|
UPROPERTY(Transient, BlueprintReadOnly, Category = "UI|Reglages")
|
|
TObjectPtr<USettingsMenuWidget> SettingsMenu;
|
|
|
|
private:
|
|
void CreateHudWidgets();
|
|
|
|
/**
|
|
* Tout ce qu'il faut faire quand ce controller prend un pawn, quel que soit
|
|
* le cote du reseau : creer le HUD s'il manque, rebrancher les widgets sur
|
|
* le nouveau corps, ecouter sa mort.
|
|
*
|
|
* Appelee par OnPossess (serveur) ET AcknowledgePossession (client), donc
|
|
* potentiellement deux fois chez l'hote qui est les deux a la fois. Elle
|
|
* doit rester idempotente -- d'ou AddUniqueDynamic sur OnDied, et
|
|
* CreateHudWidgets qui ne cree que ce qui n'existe pas encore.
|
|
*/
|
|
void SetupForPossessedPawn(APawn* InPawn);
|
|
|
|
/**
|
|
* Éclaircit l'écran d'arrivée, une seule fois, et seulement quand le joueur
|
|
* a réellement un corps.
|
|
*
|
|
* La condition n'est PAS « ai-je un pawn » mais « la caméra est-elle sur mon
|
|
* pawn ». Chez un client, le contrôleur commence sur un `SpectatorPawn` né
|
|
* au centre du monde -- sous le terrain -- et y reste encore un instant
|
|
* APRÈS `AcknowledgePossession`. Mesuré sur une vraie connexion : au moment
|
|
* où la possession est acquittée, `GetViewTarget()` vaut toujours
|
|
* `SpectatorPawn_0`. Éclaircir là montre le dessous de la carte.
|
|
*
|
|
* Tant que la caméra n'y est pas, on repasse toutes les `StartupFadeRetry`
|
|
* secondes. L'écran reste noir pendant ce temps -- le rendu du monde est
|
|
* suspendu par le GameInstance depuis le chargement de la map.
|
|
*/
|
|
void TryStartupFadeIn();
|
|
|
|
/**
|
|
* Éclaircit pour de bon, sans vérifier la caméra.
|
|
* Appelée par le filet de sécurité : mieux vaut une vue bancale qu'un écran
|
|
* noir définitif, qui se lit comme un plantage.
|
|
*/
|
|
void CompleteStartupFadeIn();
|
|
|
|
/** L'éclaircissement lui-même, après le temps de chauffe du monde. */
|
|
void StartStartupFade();
|
|
|
|
/**
|
|
* Echap. Une seule touche pour trois usages, d'ou une priorite explicite :
|
|
* boite de confirmation, puis inventaire, puis pause. Sans cet ordre on se
|
|
* retrouve avec l'inventaire et la pause ouverts en meme temps.
|
|
*/
|
|
void HandlePauseInput();
|
|
|
|
void OpenPauseMenu();
|
|
|
|
/** Oui : fondu au noir, puis retour au menu principal. */
|
|
UFUNCTION()
|
|
void HandleQuitToMenuConfirmed();
|
|
|
|
/**
|
|
* L'hote s'en va : ce client doit partir aussi.
|
|
*
|
|
* Une RPC explicite et non un simple abandon de connexion. Quand l'hote
|
|
* ferme sa partie, le moteur ne previent personne : les clients restent
|
|
* dans un monde mort, avec le pawn fantome de l'hote encore plante devant
|
|
* eux, jusqu'a un timeout qui peut ne jamais venir. On leur dit donc de
|
|
* partir, et ils partent avec leur propre fondu.
|
|
*/
|
|
UFUNCTION(Client, Reliable)
|
|
void Client_ReturnToMainMenu();
|
|
|
|
/**
|
|
* Lance le depart : ferme les ecrans, previent le GameInstance, fond au noir.
|
|
*
|
|
* Idempotente -- un client peut recevoir l'ordre de l'hote alors qu'il avait
|
|
* deja clique Quitter de son cote, et deux fondus simultanes se
|
|
* marcheraient dessus.
|
|
*/
|
|
void BeginQuitToMainMenu();
|
|
|
|
/**
|
|
* Envoie l'ordre de depart a tous les AUTRES joueurs. Serveur uniquement.
|
|
*
|
|
* Appele AVANT le fondu de l'hote et non apres : les clients ont ainsi
|
|
* toute la duree de ce fondu pour recevoir le message et lancer le leur.
|
|
* Prevenir a la fin donnerait un client qui decouvre la coupure sans
|
|
* explication, ecran de jeu fige.
|
|
*/
|
|
void KickRemoteClientsToMainMenu();
|
|
|
|
/** Non : on referme la boite et on rend la main au menu de pause. */
|
|
UFUNCTION()
|
|
void HandleQuitToMenuCancelled();
|
|
|
|
/** Le fondu est termine : on charge la map du menu, si c'est ce qu'on attendait. */
|
|
UFUNCTION()
|
|
void HandleFadeFinished();
|
|
|
|
/**
|
|
* Le joueur a accepte une invitation EN PLEINE PARTIE : on fond au noir
|
|
* avant que le voyage vers l'autre hote parte.
|
|
*
|
|
* bQuittingToMainMenu reste faux : ce n'est pas nous qui chargeons la map
|
|
* suivante, c'est USessionSubsystem. HandleFadeFinished doit donc laisser
|
|
* passer ce fondu-la sans rien faire.
|
|
*/
|
|
UFUNCTION()
|
|
void HandleSessionTravelPending();
|
|
|
|
/** L'ecran de reglages demande a se fermer : on rend la main au menu de pause. */
|
|
UFUNCTION()
|
|
void HandleSettingsCloseRequested();
|
|
|
|
/**
|
|
* Point d'entree unique de l'ouverture et de la fermeture de l'ecran.
|
|
*
|
|
* Tab et la touche de fabrication passent tous les deux par ici : le mode
|
|
* d'input, la souris et la barre rapide sont ainsi decides a un seul endroit.
|
|
* Deux chemins separes finiraient par diverger.
|
|
*/
|
|
void SetInventoryScreenOpen(bool bOpen, bool bShowCraftingTab);
|
|
|
|
/** Rend le poste accorde par le dernier OpenCraftingAtStation. Sans effet sinon. */
|
|
void ReleaseActiveStation();
|
|
|
|
/**
|
|
* Rend le coffre ouvert : couvercle referme, panneau masque, surveillance
|
|
* arretee. Sans effet s'il n'y en a pas.
|
|
*
|
|
* Separee de CloseStorage() pour la meme raison que ReleaseActiveStation :
|
|
* c'est la fermeture de l'ECRAN qui l'appelle, quelle qu'en soit la cause --
|
|
* Tab, Echap, la mort, un autre coffre. Un seul point de sortie, donc aucun
|
|
* chemin qui laisse un couvercle leve derriere soi.
|
|
*/
|
|
void ReleaseActiveStorage();
|
|
|
|
/**
|
|
* Mode d'input et curseur pour un ecran plein cadre.
|
|
*
|
|
* Partage par l'inventaire et le coffre : deux copies de ces huit lignes
|
|
* finiraient par diverger, et le symptome -- une camera qui ne repond plus,
|
|
* un sprint bloque -- se cherche tres longtemps.
|
|
*/
|
|
void SetUiInputMode(bool bUiOpen);
|
|
|
|
/** Le joueur s'est-il trop eloigne du coffre ouvert. Appele par un timer. */
|
|
void CheckStorageDistance();
|
|
|
|
/** Raccourci vers le composant de fabrication du pawn possede. */
|
|
UCraftingComponent* GetPawnCrafting() const;
|
|
|
|
/** L'ecran a change d'onglet : la barre rapide n'a rien a faire sous la page de craft. */
|
|
UFUNCTION()
|
|
void HandleInventoryTabChanged(bool bInventoryTabActive);
|
|
|
|
/**
|
|
* Etat unique de la barre rapide : visible partout, sauf par-dessus l'onglet
|
|
* Fabrication. Passer par une seule fonction evite les cas ou la fermeture
|
|
* de l'ecran laisserait la barre cachee.
|
|
*/
|
|
void UpdateHotbarVisibility();
|
|
|
|
/**
|
|
* Relaie le survol d'une case de la barre rapide vers le panneau de detail
|
|
* de l'ecran d'inventaire.
|
|
*
|
|
* Ignore ecran ferme : sans curseur il n'y a pas de survol, mais un widget
|
|
* masque sous la souris peut encore emettre sa sortie -- et decrire un objet
|
|
* dans un panneau invisible n'aurait aucun sens.
|
|
*/
|
|
UFUNCTION()
|
|
void HandleHotbarSlotHovered(UInventoryComponent* Inventory, int32 SlotIndex, bool bHovered);
|
|
|
|
/** Jette la pile survolee dans la grille, si l'inventaire est ouvert. */
|
|
void DropHoveredItem();
|
|
|
|
void HandleHotbarSelect(const FInputActionValue& Value);
|
|
void HandleHotbarScroll(const FInputActionValue& Value);
|
|
|
|
/** Raccourci vers l'inventaire du pawn possede. */
|
|
UInventoryComponent* GetPawnInventory() const;
|
|
|
|
/** Branche sur OnDied du pawn possede. */
|
|
UFUNCTION()
|
|
void HandlePawnDied();
|
|
|
|
/**
|
|
* Detruit le cadavre et demande un nouveau pawn au GameMode.
|
|
*
|
|
* Le GameMode n'existe QUE sur le serveur : chez un client
|
|
* GetAuthGameMode() rend nullptr, toujours. Un client route donc par
|
|
* Server_RequestRespawn, et ne garde en local que son fondu de retour --
|
|
* c'est de l'affichage, ca lui appartient.
|
|
*/
|
|
void RespawnPlayer();
|
|
|
|
UFUNCTION(Server, Reliable)
|
|
void Server_RequestRespawn();
|
|
|
|
// ------------------------------------------------------------------
|
|
// Ouverture d'ecran demandee par un acteur du monde
|
|
//
|
|
// Interact_Implementation s'execute sur le SERVEUR depuis le passage en
|
|
// coop. Or ces acteurs ouvrent une interface, qui n'existe que sur la
|
|
// machine du joueur : l'appel doit donc repartir vers le client par une
|
|
// RPC Client_. Sans elles, le serveur cree des widgets dans le vide et
|
|
// l'ecran du joueur ne s'ouvre jamais.
|
|
//
|
|
// L'etat "devant quel poste je suis" est tenu des DEUX cotes : le client en
|
|
// a besoin pour filtrer sa liste de recettes, le serveur pour valider le
|
|
// craft. Ne le tenir que d'un cote laisserait soit une liste vide, soit un
|
|
// etabli utilisable depuis la foret.
|
|
// ------------------------------------------------------------------
|
|
|
|
UFUNCTION(Client, Reliable)
|
|
void Client_OpenCraftingAtStation(ECraftingStation Station);
|
|
|
|
UFUNCTION(Client, Reliable)
|
|
void Client_OpenStorage(AStorageContainer* Container);
|
|
|
|
/** Le joueur a referme son ecran : le serveur reprend le poste accorde. */
|
|
UFUNCTION(Server, Reliable)
|
|
void Server_ReleaseStation(ECraftingStation Station);
|
|
|
|
/** Le joueur a referme le coffre : le serveur rabat le couvercle. */
|
|
UFUNCTION(Server, Reliable)
|
|
void Server_ReleaseStorage(AStorageContainer* Container);
|
|
|
|
/** Accorde le poste sur le composant du pawn et note lequel. */
|
|
void GrantStation(ECraftingStation Station);
|
|
|
|
// ------------------------------------------------------------------
|
|
// Pseudo
|
|
//
|
|
// Le serveur ne peut PAS deviner le pseudo Steam d'un client : l'API
|
|
// d'identite ne connait que l'utilisateur local de chaque machine. C'est
|
|
// donc au client de l'annoncer. Sans ca, le moteur laisse le nom par
|
|
// defaut du fichier de configuration -- on lit "Player" au-dessus des
|
|
// quatre joueurs, ce qui se remarque tout de suite.
|
|
// ------------------------------------------------------------------
|
|
|
|
/** Le pseudo de l'utilisateur Steam local, ou une chaine vide si indisponible. */
|
|
FString ResolveLocalPlayerNickname() const;
|
|
|
|
/** Ecrit le pseudo sur le PlayerState, qui le replique a tout le monde. */
|
|
UFUNCTION(Server, Reliable)
|
|
void Server_SetPlayerNickname(const FString& Nickname);
|
|
|
|
FTimerHandle RespawnTimerHandle;
|
|
|
|
/** Le fondu d'arrivée attend le pawn. */
|
|
bool bStartupFadePending = false;
|
|
|
|
FTimerHandle StartupFadeTimeoutHandle;
|
|
|
|
/** Réessai tant que la caméra n'est pas sur le pawn. */
|
|
FTimerHandle StartupFadeRetryHandle;
|
|
|
|
|
|
/** Période de réessai, en secondes. Assez court pour ne pas se voir. */
|
|
static constexpr float StartupFadeRetry = 0.05f;
|
|
|
|
/** Surveillance de l'eloignement, actif seulement pendant qu'un coffre est ouvert. */
|
|
FTimerHandle StorageDistanceTimerHandle;
|
|
|
|
/** Le coffre actuellement ouvert, pour lui refermer son couvercle. */
|
|
TWeakObjectPtr<AStorageContainer> ActiveStorage;
|
|
|
|
bool bStorageOpen = false;
|
|
|
|
bool bInventoryOpen = false;
|
|
|
|
/** Onglet Fabrication affiche. N'a de sens que si bInventoryOpen est vrai. */
|
|
bool bCraftingTabActive = false;
|
|
|
|
/**
|
|
* Poste accorde par l'ecran actuellement ouvert, a rendre a la fermeture.
|
|
* Count = aucun, l'ecran a ete ouvert au clavier et pas depuis un etabli.
|
|
*/
|
|
ECraftingStation ActiveStation = ECraftingStation::Count;
|
|
|
|
/**
|
|
* Visibilite d'origine de la barre rapide, relevee a sa creation.
|
|
* On la restaure telle quelle plutot que de forcer Visible : le Blueprint a
|
|
* peut-etre choisi SelfHitTestInvisible, et l'ecraser changerait
|
|
* silencieusement son comportement au clic.
|
|
*/
|
|
ESlateVisibility HotbarDefaultVisibility = ESlateVisibility::Visible;
|
|
|
|
bool bPauseMenuOpen = false;
|
|
|
|
/**
|
|
* La boite de confirmation avale Echap elle-meme quand elle a le focus,
|
|
* mais un clic ailleurs le lui retire : sans ce booleen, Echap refermerait
|
|
* alors le menu de pause en laissant la question affichee dans le vide.
|
|
*/
|
|
bool bQuitToMenuDialogOpen = false;
|
|
|
|
bool bSettingsOpen = false;
|
|
|
|
/** Distingue le fondu de sortie de tous les autres dans HandleFadeFinished. */
|
|
bool bQuittingToMainMenu = false;
|
|
};
|