// © 2025 Naked People Team. All Rights Reserved. #include "ClothingManager.h" #include "ClothingItem.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 UClothingManager::GetEquippedClothing() const { TArray> 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->GetClothingItem()->HiddenBodyParts.Contains(BodyPart)) return false; } return true; } void UClothingManager::HydrateClothing() { USaveSubsystem* SaveSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem(); for (const FItemSaveRecord& ItemSaveRecord : SaveSubsystem->GetCurrentSave()->EquippedItems) { UClothingItemInstance* ClothingItemInstance = UClothingItemInstance::CreateFromSave(this, ItemSaveRecord); PutOnClothing(ClothingItemInstance); } } float UClothingManager::GetHeelHeight() { if (!EquippedClothing.Contains(EClothingSlotType::Footwear)) return 0; const UClothingItemInstance* Footwear = EquippedClothing[EClothingSlotType::Footwear]; return Footwear->GetClothingItem()->ShoesOffset; } USkeletalMeshComponent* UClothingManager::GetMeshComponent(const EClothingSlotType SlotType) const { const ANakedDesireCharacter* Player = Cast(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(ItemPickupActor, GetOwner()->GetActorTransform()); if (!NewItemPickup) { UE_LOG(LogTemp, Warning, TEXT("UClothingManager::SpawnClothingPickup NewItemPickup == nullptr")); return; } USaveSubsystem* SaveSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem(); FItemSaveRecord ItemSaveRecord; ItemSaveRecord.Init(ItemInstance); ItemSaveRecord.WorldTransform = NewItemPickup->GetActorTransform(); SaveSubsystem->GetCurrentSave()->WorldItems.Push(ItemSaveRecord); NewItemPickup->SetItem(ItemInstance); } void UClothingManager::PutOnClothing(UClothingItemInstance* ClothingItemInstance) { if (!ClothingItemInstance) return; const EClothingSlotType ClothingSlotType = ClothingItemInstance->GetClothingItem()->SlotType; USkeletalMeshComponent* MeshComponent = GetMeshComponent(ClothingSlotType); MeshComponent->SetSkeletalMesh(ClothingItemInstance->GetClothingItem()->SkeletalMesh); if (!ClothingItemInstance->GetClothingItem()->Materials.IsEmpty()) { for (const TPair& Material : ClothingItemInstance->GetClothingItem()->Materials) { MeshComponent->SetMaterialByName(Material.Key, Material.Value); } } SetClothingSlotItem(ClothingSlotType, ClothingItemInstance); if (ClothingItemInstance->GetClothingItem()->UseLeaderPose) { MeshComponent->SetLeaderPoseComponent(Cast(GetOwner())->GetMesh()); } const UClothingItem* ClothingItem = ClothingItemInstance->GetClothingItem(); 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->GetClothingItem()->SlotType; if (EquippedClothing.Contains(SlotType)) { DropClothing(SlotType); } SetClothingSlotItem(SlotType, ClothingItemInstance); USaveSubsystem* SaveSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem(); FItemSaveRecord ItemSaveRecord; ItemSaveRecord.Init(ClothingItemInstance); SaveSubsystem->GetCurrentSave()->EquippedItems.Push(ItemSaveRecord); PutOnClothing(ClothingItemInstance); } UClothingItemInstance* UClothingManager::RemoveClothing(const EClothingSlotType ClothingSlotType) { TObjectPtr* ExistingItemRef = EquippedClothing.Find(ClothingSlotType); if (!ExistingItemRef) { UE_LOG(LogTemp, Warning, TEXT("UClothingManager::RemoveClothing ExistingItemRef == nullptr")); return nullptr; } UClothingItemInstance* ExistingItem = *ExistingItemRef; if (!ExistingItem) { UE_LOG(LogTemp, Warning, TEXT("UClothingManager::RemoveClothing ExistingItem == nullptr")); return nullptr; } SetClothingSlotItem(ClothingSlotType, nullptr); USkeletalMeshComponent* MeshComponent = GetMeshComponent(ClothingSlotType); MeshComponent->SetSkeletalMesh(nullptr); if (ExistingItem->GetClothingItem()->UseLeaderPose) { MeshComponent->SetLeaderPoseComponent(nullptr); } OnClothingUnequip.Broadcast(ExistingItem); USaveSubsystem* SaveSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem(); SaveSubsystem->GetCurrentSave()->EquippedItems.RemoveAll([ExistingItem](const FItemSaveRecord& Item) { return Item.InstanceId == ExistingItem->GetInstanceId(); }); 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); }