// Fill out your copyright notice in the Description page of Project Settings. #include "ItemDataAsset.h" #include "Components/StaticMeshComponent.h" #if WITH_EDITOR #include "Misc/DataValidation.h" #endif #define LOCTEXT_NAMESPACE "ItemData" namespace { /** * Pose un mesh et son eventuel materiau de surcharge sur un composant. * * Prefixe du fichier oblige : le build unity concatene les .cpp du module, * un namespace anonyme n'isole rien. */ void ItemDataApplyMeshAndMaterial(UStaticMeshComponent* Component, UStaticMesh* Mesh, UMaterialInterface* Material) { // OverrideMaterials appartient au COMPOSANT, pas au mesh : il survit donc // a un changement d'asset. Sans ce vidage, un objet sans surcharge monte // apres un objet qui en avait une garderait le materiau du precedent -- // le meme piege que les meshes de corps de la customisation. Il ne se // voit que sur un composant REUTILISE, donc jamais sur un pickup fraichement // engendre, et systematiquement sur l'objet en main ou sur un grill. Component->EmptyOverrideMaterials(); Component->SetStaticMesh(Mesh); // SetMaterial(0, nullptr) ne "retire" pas le materiau, il pose un slot vide // et le mesh devient gris damier. Sans override, on ne touche a rien et le // mesh garde le sien. if (Material) { Component->SetMaterial(0, Material); } } } void UItemDataAsset::ApplyWorldVisualsTo(UStaticMeshComponent* Component) const { if (!Component) { return; } ItemDataApplyMeshAndMaterial(Component, WorldMesh, WorldMeshMaterial); } void UItemDataAsset::ApplyHeldVisualsTo(UStaticMeshComponent* Component) const { if (!Component) { return; } // Le materiau de surcharge est celui du monde, sans equivalent "en main" : // il sert a distinguer un cru d'un cuit, et cette distinction vaut aussi // dans la main. Un second champ n'aurait fait que se desynchroniser. ItemDataApplyMeshAndMaterial(Component, GetHeldMesh(), WorldMeshMaterial); } #if WITH_EDITOR EDataValidationResult UItemDataAsset::IsDataValid(FDataValidationContext& Context) const { EDataValidationResult Result = Super::IsDataValid(Context); if (bCanBeCooked && !CookedResult) { Context.AddError(LOCTEXT("CookNoResult", "'Can Be Cooked' is checked but no 'Cooked Result' is assigned: this item would sit on the fire forever without ever changing.")); Result = EDataValidationResult::Invalid; } if (bCanBurn && !BurntResult) { Context.AddError(LOCTEXT("BurnNoResult", "'Can Burn' is checked but no 'Burnt Result' is assigned.")); Result = EDataValidationResult::Invalid; } // Une chaine qui reboucle sur elle-meme ne plante pas, elle tourne : la // station re-arme un timer identique a chaque etape et le joueur voit un // objet qui ne finit jamais de cuire. Impossible a diagnostiquer en jeu. if (CookedResult == this) { Context.AddError(LOCTEXT("CookSelfResult", "'Cooked Result' points back to this asset: the item would cook into itself, endlessly.")); Result = EDataValidationResult::Invalid; } if (BurntResult == this) { Context.AddError(LOCTEXT("BurnSelfResult", "'Burnt Result' points back to this asset: the item would burn into itself, endlessly.")); Result = EDataValidationResult::Invalid; } // Un objet a charges ne s'empile pas (voir GetEffectiveMaxStack). Le poser // sur le feu reste possible, mais la charge entamee suit l'exemplaire et le // resultat en herite : autant que ce soit un choix, pas une surprise. if (MaxUses > 1 && bCanBeCooked) { Context.AddWarning(LOCTEXT("CookableWithCharges", "This item has multiple uses AND can be cooked. The remaining charges follow the item through cooking, which is rarely what you want for food.")); } // Le symptome serait une main vide sans le moindre message : le composant // aurait bien monte son mesh, avec un asset nul. if (bShowInHand && !GetHeldMesh()) { Context.AddError(LOCTEXT("HeldNoMesh", "'Show In Hand' is checked but neither 'Held Mesh' nor 'World Mesh' is assigned: nothing would appear in the player's hand.")); Result = EDataValidationResult::Invalid; } // Un outil invisible se remarque tout de suite en jeu, mais on cherche la // cause du mauvais cote -- dans le composant, dans le socket, dans le rig -- // avant de penser a une case a cocher. if (IsTool() && !bShowInHand) { Context.AddWarning(LOCTEXT("ToolNotShownInHand", "This item is a tool but 'Show In Hand' is unchecked: the player will harvest with an empty hand.")); } return Result; } #endif #undef LOCTEXT_NAMESPACE