195 lines
8.0 KiB
C++
195 lines
8.0 KiB
C++
// Fill out your copyright notice in the Description page of Project Settings.
|
|
|
|
#pragma once
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "Engine/DataAsset.h"
|
|
#include "CharacterAppearanceTypes.h"
|
|
#include "CharacterPartsDataAsset.generated.h"
|
|
|
|
class UAnimInstance;
|
|
class UMaterialInterface;
|
|
class USkeletalMesh;
|
|
class UTexture2D;
|
|
|
|
/**
|
|
* Tout ce qui compose une silhouette : ses meshes de corps, son AnimBP, et les
|
|
* pieces disponibles pour chaque categorie.
|
|
*/
|
|
USTRUCT(BlueprintType)
|
|
struct FCharacterBodySet
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
/** La vignette du bouton de silhouette, meme role que celle d'une piece. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Body")
|
|
TObjectPtr<UTexture2D> Icon;
|
|
|
|
/**
|
|
* Les morceaux du corps, dans l'ordre. Le PREMIER est le porteur : c'est lui
|
|
* qui va sur le composant Mesh du Character et qui joue l'animation, les
|
|
* suivants deviennent des composants enfants en leader pose.
|
|
*
|
|
* Une LISTE alors qu'il n'y a qu'une case aujourd'hui, et ce n'est pas de la
|
|
* sur-conception : le pack livre exprès `SKM_BodyA_torso`, `_arms`,
|
|
* `_legs_01/02/03`, `_hands`, `_feet`, precisement pour qu'une armure puisse
|
|
* eteindre les segments qu'elle recouvre. Le jour venu, la case 0 deviendra
|
|
* `SKM_BodyA_empty` -- invisible, porteur d'animation -- et les huit segments
|
|
* suivront derriere, SANS que ce code change. Un TObjectPtr unique, lui,
|
|
* imposerait de tout reprendre au premier plastron.
|
|
*/
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Body")
|
|
TArray<TObjectPtr<USkeletalMesh>> BodyMeshes;
|
|
|
|
/** L'AnimBP du porteur. Il change avec la silhouette, d'ou sa place ici. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Body")
|
|
TSubclassOf<UAnimInstance> AnimClass;
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Parts")
|
|
TArray<FCharacterPartEntry> Heads;
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Parts")
|
|
TArray<FCharacterPartEntry> Hairstyles;
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Parts")
|
|
TArray<FCharacterPartEntry> Eyebrows;
|
|
|
|
/** Vide pour une silhouette qui n'en porte pas -- le pack n'en donne qu'a A. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Parts")
|
|
TArray<FCharacterPartEntry> Beards;
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Parts")
|
|
TArray<FCharacterPartEntry> Mustaches;
|
|
|
|
/**
|
|
* Fragment cherche dans le NOM des slots de materiau du mesh de tete pour y
|
|
* trouver celui des yeux.
|
|
*
|
|
* Les yeux ne sont pas un mesh : le pack les livre comme un element du mesh
|
|
* de tete. Il ne suffit donc pas de poser un parametre de couleur, il faut
|
|
* REMPLACER le materiau de ce slot -- encore faut-il savoir lequel.
|
|
*
|
|
* Un fragment de nom et pas un index, parce qu'un index est faux deux fois :
|
|
* il oblige a le verifier a la main dans l'editeur, et il suppose surtout
|
|
* que les six tetes rangent leurs slots dans le MEME ordre. Les slots du
|
|
* pack s'appellent `M_Eye_A_01`, `M_Eye`, `M_Eyes_02`... tous contiennent
|
|
* « Eye », aucun slot de peau ne le contient.
|
|
*
|
|
* Si le fragment ne trouve rien, le materiau n'est PAS pose et un
|
|
* avertissement part dans le log. C'est volontaire : poser l'oeil sur un
|
|
* slot au hasard repeindrait le visage entier, un symptome qu'on met bien
|
|
* plus longtemps a diagnostiquer qu'une ligne de log.
|
|
*/
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Parts")
|
|
FName EyeMaterialSlotHint = TEXT("Eye");
|
|
};
|
|
|
|
/**
|
|
* Le catalogue : la table de correspondance entre les index d'une
|
|
* FCharacterAppearance et les assets reels.
|
|
*
|
|
* Un seul asset a remplir, et le SEUL endroit a toucher pour ajouter une
|
|
* coiffure. C'est aussi lui qui borne ce qu'un client peut demander : une
|
|
* apparence arrivee du reseau est passee a Sanitize(), qui ramene tout index
|
|
* hors bornes a une valeur sure.
|
|
*/
|
|
UCLASS(BlueprintType)
|
|
class EMBERWILD_API UCharacterPartsDataAsset : public UPrimaryDataAsset
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
public:
|
|
/**
|
|
* Une entree par valeur d'ECharacterBodyType, dans l'ordre de l'enum.
|
|
* L'ordre EST le contrat : c'est lui qui donne son sens a BodyType.
|
|
*/
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog")
|
|
TArray<FCharacterBodySet> BodySets;
|
|
|
|
// ------------------------------------------------------------------
|
|
// Palettes : une couleur = un bouton a l'ecran, sans reglage entre les
|
|
// deux. L'ordre EST l'ordre d'affichage, et l'index qui part sur le reseau.
|
|
//
|
|
// Partagees par les deux silhouettes : deux nuanciers de peau a tenir a
|
|
// jour divergeraient au premier ajout.
|
|
// ------------------------------------------------------------------
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog|Palettes")
|
|
TArray<FLinearColor> SkinColors;
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog|Palettes")
|
|
TArray<FLinearColor> HairColors;
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog|Palettes")
|
|
TArray<FLinearColor> EyeColors;
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog|Palettes")
|
|
TArray<FLinearColor> UnderwearColors;
|
|
|
|
/** Les materiaux d'iris, un par forme d'oeil proposee. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog|Palettes")
|
|
TArray<TObjectPtr<UMaterialInterface>> EyeMaterials;
|
|
|
|
// ------------------------------------------------------------------
|
|
// Noms des parametres des materiaux du pack.
|
|
//
|
|
// Ici et pas en dur dans le C++ : ils appartiennent aux assets, pas au
|
|
// code. Changer de pack de personnages ne doit demander qu'un nouveau
|
|
// catalogue -- et ces noms contiennent des ESPACES, ce qu'on n'invente
|
|
// pas de memoire.
|
|
// ------------------------------------------------------------------
|
|
|
|
/** `M_Body_Base`. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog|Material Parameters")
|
|
FName SkinColorParameter = TEXT("Skin color");
|
|
|
|
/**
|
|
* `M_Head_Base` -- le meme role que ci-dessus, mais l'autre master, et
|
|
* surtout un NOM DIFFERENT : `Skin` cote tete, `Skin color` cote corps.
|
|
*
|
|
* Le master contient bien la chaine « Skin Base color », mais ce n'est pas
|
|
* le nom du parametre expose -- verifie dans `MI_HeadA_01_a`, ou le chercher
|
|
* ne rend aucun resultat alors que `Skin` apparait dans le groupe
|
|
* « Base colors ». Morale : un nom de parametre se lit dans l'editeur du
|
|
* Material Instance, jamais dans les chaines du binaire du master.
|
|
*/
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog|Material Parameters")
|
|
FName HeadSkinColorParameter = TEXT("Skin");
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog|Material Parameters")
|
|
FName UnderwearColorParameter = TEXT("Underware color");
|
|
|
|
/** `M_Hairstyle_Base`, parent des cheveux, barbes, moustaches ET sourcils. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog|Material Parameters")
|
|
FName HairColorParameter = TEXT("Color");
|
|
|
|
/** `M_Eyes_Base`. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Catalog|Material Parameters")
|
|
FName EyeColorParameter = TEXT("Eye color");
|
|
|
|
// ------------------------------------------------------------------
|
|
// Lecture
|
|
// ------------------------------------------------------------------
|
|
|
|
/** Le jeu de pieces d'une silhouette, ou nullptr si l'index est hors bornes. */
|
|
const FCharacterBodySet* GetBodySet(ECharacterBodyType BodyType) const;
|
|
|
|
/** La liste d'une categorie pour une silhouette, vide si rien n'est defini. */
|
|
const TArray<FCharacterPartEntry>& GetParts(ECharacterBodyType BodyType, ECharacterPartCategory Category) const;
|
|
|
|
/** Nombre d'options d'une categorie. Sert a borner l'UI comme la console. */
|
|
UFUNCTION(BlueprintPure, Category = "Catalog")
|
|
int32 GetPartCount(ECharacterBodyType BodyType, ECharacterPartCategory Category) const;
|
|
|
|
/**
|
|
* Ramene une apparence dans les bornes du catalogue.
|
|
*
|
|
* Appelee sur le SERVEUR a la reception d'une apparence client, et au
|
|
* chargement des reglages -- un catalogue ampute entre deux versions du jeu
|
|
* laisserait sinon des index qui ne designent plus rien. Les pieces
|
|
* facultatives (barbe, moustache) retombent sur NoPart, les obligatoires
|
|
* sur 0 : mieux vaut la mauvaise tete que pas de tete.
|
|
*/
|
|
void Sanitize(FCharacterAppearance& InOut) const;
|
|
};
|