Files
Naked-Desire/Source/NakedDesire/Clothing/ClothingManager.cpp
T
2026-06-03 15:16:41 +03:00

234 lines
7.9 KiB
C++

// © 2025 Naked People Team. All Rights Reserved.
#include "ClothingManager.h"
#include "ClothingItemDefinition.h"
#include "ClothingItemInstance.h"
#include "GameFramework/Character.h"
#include "Kismet/GameplayStatics.h"
#include "NakedDesire/Interactables/ItemPickup.h"
#include "NakedDesire/Player/NakedDesireCharacter.h"
#include "NakedDesire/SaveGame/GlobalSaveGameData.h"
#include "NakedDesire/SaveGame/ItemSaveRecord.h"
#include "NakedDesire/SaveGame/SaveSubsystem.h"
UClothingManager::UClothingManager()
{
PrimaryComponentTick.bCanEverTick = false;
}
void UClothingManager::BeginPlay()
{
Super::BeginPlay();
HydrateClothing();
}
void UClothingManager::SetClothingSlotItem(const EClothingSlotType ClothingSlotType, UClothingItemInstance* ClothingItemInstance)
{
if (ClothingItemInstance)
EquippedClothing.Add(ClothingSlotType, ClothingItemInstance);
else
EquippedClothing.Remove(ClothingSlotType);
}
TArray<UClothingItemInstance*> UClothingManager::GetEquippedClothing() const
{
TArray<TObjectPtr<UClothingItemInstance>> Items;
EquippedClothing.GenerateValueArray(Items);
return Items;
}
UClothingItemInstance* UClothingManager::GetSlotClothing(const EClothingSlotType SlotType)
{
if (EquippedClothing.Contains(SlotType))
return EquippedClothing[SlotType];
return nullptr;
}
bool UClothingManager::IsBodyPartExposed(const EBodyPart BodyPart)
{
for (const auto& [Key, Value] : EquippedClothing)
{
if (Value->GetClothingItemDefinition()->HiddenBodyParts.Contains(BodyPart))
return false;
}
return true;
}
void UClothingManager::HydrateClothing()
{
USaveSubsystem* SaveSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem<USaveSubsystem>();
for (const FItemSaveRecord& ItemSaveRecord : SaveSubsystem->GetCurrentSave()->GetEquippedItems())
{
UClothingItemInstance* ClothingItemInstance = Cast<UClothingItemInstance>(UItemInstance::CreateFromRecord(this, ItemSaveRecord));
if (!ClothingItemInstance)
continue;
PutOnClothing(ClothingItemInstance);
}
}
float UClothingManager::GetHeelHeight()
{
if (!EquippedClothing.Contains(EClothingSlotType::Footwear))
return 0;
const UClothingItemInstance* Footwear = EquippedClothing[EClothingSlotType::Footwear];
return Footwear->GetClothingItemDefinition()->ShoesOffset;
}
USkeletalMeshComponent* UClothingManager::GetMeshComponent(const EClothingSlotType SlotType) const
{
const ANakedDesireCharacter* Player = Cast<ANakedDesireCharacter>(GetOwner());
if (!Player)
{
return nullptr;
}
switch (SlotType)
{
case EClothingSlotType::Nipples: return Player->NipplesMeshComponent;
case EClothingSlotType::Anal: return Player->AnalMeshComponent;
case EClothingSlotType::Vagina: return Player->VaginaMeshComponent;
case EClothingSlotType::Head: return Player->HeadMeshComponent;
case EClothingSlotType::Neck: return Player->NeckMeshComponent;
case EClothingSlotType::Face: return Player->FaceMeshComponent;
case EClothingSlotType::Eyes: return Player->EyesMeshComponent;
case EClothingSlotType::Bodysuit: return Player->BodySuitMeshComponent;
case EClothingSlotType::Top: return Player->TopMeshComponent;
case EClothingSlotType::Bottom: return Player->BottomMeshComponent;
case EClothingSlotType::UnderwearTop: return Player->UnderwearTopMeshComponent;
case EClothingSlotType::UnderwearBottom:return Player->UnderwearBottomMeshComponent;
case EClothingSlotType::Socks: return Player->SocksMeshComponent;
case EClothingSlotType::Footwear: return Player->FootwearMeshComponent;
case EClothingSlotType::Outerwear: return Player->OuterwearMeshComponent;
case EClothingSlotType::WristRestraint: return Player->WristRestraintMeshComponent;
case EClothingSlotType::AnkleRestraint: return Player->AnkleRestraintMeshComponent;
case EClothingSlotType::NeckRestraint: return Player->NeckRestraintMeshComponent;
default: return nullptr;
}
}
void UClothingManager::SpawnClothingPickup(UClothingItemInstance* ItemInstance)
{
if (!ItemPickupActor)
{
UE_LOG(LogTemp, Warning, TEXT("UClothingManager::SpawnClothingPickup ItemPickupActor is not set"));
return;
}
AItemPickup* NewItemPickup = GetWorld()->SpawnActor<AItemPickup>(ItemPickupActor, GetOwner()->GetActorTransform());
if (!NewItemPickup)
{
UE_LOG(LogTemp, Warning, TEXT("UClothingManager::SpawnClothingPickup NewItemPickup == nullptr"));
return;
}
USaveSubsystem* SaveSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem<USaveSubsystem>();
SaveSubsystem->GetCurrentSave()->AddWorldItem(ItemInstance, NewItemPickup->GetActorTransform());
NewItemPickup->SetItem(ItemInstance);
}
void UClothingManager::PutOnClothing(UClothingItemInstance* ClothingItemInstance)
{
if (!ClothingItemInstance)
return;
const EClothingSlotType ClothingSlotType = ClothingItemInstance->GetClothingItemDefinition()->SlotType;
USkeletalMeshComponent* MeshComponent = GetMeshComponent(ClothingSlotType);
MeshComponent->SetSkeletalMesh(ClothingItemInstance->GetClothingItemDefinition()->SkeletalMesh);
if (!ClothingItemInstance->GetClothingItemDefinition()->Materials.IsEmpty())
{
for (const TPair<FName, UMaterialInstance*>& Material : ClothingItemInstance->GetClothingItemDefinition()->Materials)
{
MeshComponent->SetMaterialByName(Material.Key, Material.Value);
}
}
SetClothingSlotItem(ClothingSlotType, ClothingItemInstance);
if (ClothingItemInstance->GetClothingItemDefinition()->UseLeaderPose)
{
MeshComponent->SetLeaderPoseComponent(Cast<ACharacter>(GetOwner())->GetMesh());
}
const UClothingItemDefinition* ClothingItem = ClothingItemInstance->GetClothingItemDefinition();
if (ClothingItem->SlotType == EClothingSlotType::Bodysuit)
{
DropClothing(EClothingSlotType::Top);
DropClothing(EClothingSlotType::Bottom);
DropClothing(EClothingSlotType::UnderwearTop);
DropClothing(EClothingSlotType::UnderwearBottom);
}
else if (ClothingItem->SlotType == EClothingSlotType::Top ||
ClothingItem->SlotType == EClothingSlotType::Bottom ||
ClothingItem->SlotType == EClothingSlotType::UnderwearTop ||
ClothingItem->SlotType == EClothingSlotType::UnderwearBottom)
{
DropClothing(EClothingSlotType::Bodysuit);
}
OnClothingEquip.Broadcast(ClothingItemInstance);
}
void UClothingManager::TakeClothing(UClothingItemInstance* ClothingItemInstance)
{
const EClothingSlotType SlotType = ClothingItemInstance->GetClothingItemDefinition()->SlotType;
if (EquippedClothing.Contains(SlotType))
{
DropClothing(SlotType);
}
SetClothingSlotItem(SlotType, ClothingItemInstance);
USaveSubsystem* SaveSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem<USaveSubsystem>();
SaveSubsystem->GetCurrentSave()->AddEquippedItem(ClothingItemInstance);
PutOnClothing(ClothingItemInstance);
}
UClothingItemInstance* UClothingManager::RemoveClothing(const EClothingSlotType ClothingSlotType)
{
if (!EquippedClothing.Contains(ClothingSlotType))
return nullptr;
UClothingItemInstance* ExistingItem = EquippedClothing[ClothingSlotType];
SetClothingSlotItem(ClothingSlotType, nullptr);
USkeletalMeshComponent* MeshComponent = GetMeshComponent(ClothingSlotType);
MeshComponent->SetSkeletalMesh(nullptr);
if (ExistingItem->GetClothingItemDefinition()->UseLeaderPose)
{
MeshComponent->SetLeaderPoseComponent(nullptr);
}
OnClothingUnequip.Broadcast(ExistingItem);
USaveSubsystem* SaveSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem<USaveSubsystem>();
SaveSubsystem->GetCurrentSave()->RemoveEquippedItem(ExistingItem);
return ExistingItem;
}
void UClothingManager::DropClothing(const EClothingSlotType ClothingType)
{
UClothingItemInstance* ClothingItemInstance = RemoveClothing(ClothingType);
if (!ClothingItemInstance)
return;
SpawnClothingPickup(ClothingItemInstance);
OnClothingDropped.Broadcast(ClothingItemInstance);
}
bool UClothingManager::IsClothingTypeOn(const EClothingSlotType ClothingType)
{
return EquippedClothing.Contains(ClothingType);
}