(Feat) Add Craft Systeme

This commit is contained in:
2026-07-30 23:08:33 +02:00
parent 9b5ad7c8a4
commit 3f3ae1f5fa
57 changed files with 2276 additions and 127 deletions
@@ -0,0 +1,160 @@
// 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 SURVIVAL_PROJET_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<UUniformGridPanel> RecipeGrid;
/** L'icone du resultat, dans le panneau de droite. */
UPROPERTY(meta = (BindWidget))
TObjectPtr<UImage> ResultIcon;
UPROPERTY(meta = (BindWidget))
TObjectPtr<UTextBlock> ResultNameText;
UPROPERTY(meta = (BindWidget))
TObjectPtr<UButton> CraftButton;
/** Facultatif : la description de l'objet produit. */
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UTextBlock> ResultDescriptionText;
/** Facultatif : "x2" quand la recette produit plusieurs exemplaires. Masque sinon. */
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UTextBlock> 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<UWidget> DetailsPanel;
/** Facultatif : message affiche quand aucune recette n'est disponible ici. */
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UWidget> 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<UPanelWidget> IngredientList;
/** Ton WBP_RecipeSlot. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Crafting")
TSubclassOf<UCraftingRecipeSlotWidget> RecipeSlotClass;
/** Ton WBP_IngredientRow. Sans elle, la liste de cout reste vide. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Crafting")
TSubclassOf<UCraftingIngredientRowWidget> 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<UCraftingRecipeDataAsset*>& 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<UCraftingComponent> BoundCrafting;
TWeakObjectPtr<UInventoryComponent> BoundInventory;
UPROPERTY(Transient)
TObjectPtr<UCraftingRecipeDataAsset> SelectedRecipe;
/** UPROPERTY obligatoire : sans ca le GC collecterait les cases. */
UPROPERTY(Transient)
TArray<TObjectPtr<UCraftingRecipeSlotWidget>> RecipeSlots;
UPROPERTY(Transient)
TArray<TObjectPtr<UCraftingIngredientRowWidget>> IngredientRows;
ECraftingStation StationFilter = ECraftingStation::Count;
};