// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "Blueprint/UserWidget.h" #include "CraftingRecipeDataAsset.h" #include "CraftingWidget.generated.h" class UButton; class UCraftingComponent; class UCraftingIngredientRowWidget; class UCraftingRecipeSlotWidget; class UImage; class UInventoryComponent; class UPanelWidget; class UTextBlock; class UUniformGridPanel; /** * La page de fabrication : la grille de recettes a gauche, le detail de la * recette choisie a droite. * * Elle ne calcule rien. UCraftingComponent lui dit quelles recettes afficher, * lesquelles sont realisables, et fabrique quand on clique. Elle s'abonne a * l'inventaire et aux postes accessibles pour se rafraichir -- jamais de Tick * pour relire un etat. */ UCLASS(Abstract) class EMBERWILD_API UCraftingWidget : public UUserWidget { GENERATED_BODY() public: virtual void NativeConstruct() override; virtual void NativeDestruct() override; /** * (Re)branche la page sur le pawn actuellement possede. * Indispensable apres un respawn : le nouveau pawn a de nouveaux composants, * et les anciens abonnements pointeraient vers des objets detruits. */ void BindToOwningPawn(); /** Relit la liste, l'etat de chaque case et le panneau de detail. */ UFUNCTION(BlueprintCallable, Category = "Crafting") void Refresh(); /** Appele par une case quand on clique dessus. */ void NotifyRecipeClicked(UCraftingRecipeDataAsset* InRecipe); /** * Restreint l'affichage a un seul poste. Count = tout ce qui est accessible. * Purement visuel : ce filtre ne peut jamais rendre une recette realisable. */ UFUNCTION(BlueprintCallable, Category = "Crafting") void SetStationFilter(ECraftingStation InFilter); protected: /** A nommer exactement "RecipeGrid" dans le Widget Blueprint. */ UPROPERTY(meta = (BindWidget)) TObjectPtr RecipeGrid; /** L'icone du resultat, dans le panneau de droite. */ UPROPERTY(meta = (BindWidget)) TObjectPtr ResultIcon; UPROPERTY(meta = (BindWidget)) TObjectPtr ResultNameText; UPROPERTY(meta = (BindWidget)) TObjectPtr CraftButton; /** Facultatif : la description de l'objet produit. */ UPROPERTY(meta = (BindWidgetOptional)) TObjectPtr ResultDescriptionText; /** Facultatif : "x2" quand la recette produit plusieurs exemplaires. Masque sinon. */ UPROPERTY(meta = (BindWidgetOptional)) TObjectPtr ResultQuantityText; /** * Facultatif : le panneau de droite dans son ensemble. Masque tant qu'aucune * recette n'est choisie, pour ne pas afficher un cadre vide au premier * affichage. */ UPROPERTY(meta = (BindWidgetOptional)) TObjectPtr DetailsPanel; /** Facultatif : message affiche quand aucune recette n'est disponible ici. */ UPROPERTY(meta = (BindWidgetOptional)) TObjectPtr EmptyGridMessage; /** * Le conteneur des lignes de cout. Declare en UPanelWidget et non en * UVerticalBox : ca laisse le choix d'un Wrap Box ou d'un Grid Panel dans le * Blueprint sans toucher au C++, puisqu'on ne fait qu'y ajouter des enfants. */ UPROPERTY(meta = (BindWidgetOptional)) TObjectPtr IngredientList; /** Ton WBP_RecipeSlot. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Crafting") TSubclassOf RecipeSlotClass; /** Ton WBP_IngredientRow. Sans elle, la liste de cout reste vide. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Crafting") TSubclassOf IngredientRowClass; UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Crafting", meta = (ClampMin = "1")) int32 ColumnCount = 5; private: UFUNCTION() void HandleInventoryChanged(); UFUNCTION() void HandleStationsChanged(); UFUNCTION() void HandleCraftClicked(); /** Recree les cases uniquement si la liste affichee a change. */ void RebuildGrid(const TArray& NewRecipes); /** Pousse l'etat realisable/non a chaque case et met a jour le panneau. */ void RefreshStates(); void RefreshDetails(); /** * Remplit la liste de cout de la recette choisie. * * Les lignes sont RECYCLEES et non recreees : cette fonction repasse a * chaque changement d'inventaire, donc a chaque ramassage. Detruire puis * reconstruire trois widgets par branche ramassee serait du gaspillage. */ void RefreshIngredients(); UCraftingComponent* ResolveCrafting() const; /** Detache les deux abonnements. Appele avant de rebrancher, et a la destruction. */ void UnbindDelegates(); TWeakObjectPtr BoundCrafting; TWeakObjectPtr BoundInventory; UPROPERTY(Transient) TObjectPtr SelectedRecipe; /** UPROPERTY obligatoire : sans ca le GC collecterait les cases. */ UPROPERTY(Transient) TArray> RecipeSlots; UPROPERTY(Transient) TArray> IngredientRows; ECraftingStation StationFilter = ECraftingStation::Count; };