// © 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/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(); } bool UClothingManager::IsBodyTypeExposed(const EBodyPart BodyPart) { for (const auto& ClothingSlot : ClothingSlots) { if (ClothingSlot.ClothingItemInstance) // TODO: Add covered body part resolution { return false; } } return true; } bool UClothingManager::GetClothingSlotData(const EClothingSlotType ClothingSlotType, FClothingSlotData& OutClothingSlotData) { for (const auto& ClothingSlot : ClothingSlots) { if (ClothingSlot.ClothingSlotType == ClothingSlotType) { OutClothingSlotData = ClothingSlot; return true; } } return false; } void UClothingManager::SetClothingSlotItem(const EClothingSlotType ClothingSlotType, UClothingItemInstance* ClothingItemInstance) { for (FClothingSlotData& ClothingSlot : ClothingSlots) { if (ClothingSlot.ClothingSlotType == ClothingSlotType) { ClothingSlot.ClothingItemInstance = ClothingItemInstance; } } } TArray UClothingManager::GetEquippedClothing() { TArray EquippedClothingItems; for (FClothingSlotData ClothingSlot : ClothingSlots) { if (ClothingSlot.ClothingItemInstance) { EquippedClothingItems.Add(ClothingSlot.ClothingItemInstance); } } return EquippedClothingItems; } 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 (FClothingSlotData ClothingSlotData; GetClothingSlotData(EClothingSlotType::Footwear, ClothingSlotData)) { if (ClothingSlotData.ClothingItemInstance) { return ClothingSlotData.ClothingItemInstance->GetClothingItem()->ShoesOffset; } } return 0; } 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::PutOnClothing(UClothingItemInstance* ClothingItemInstance) { if (!ClothingItemInstance) return; const EClothingSlotType ClothingSlotType = ClothingItemInstance->GetClothingItem()->SlotType; FClothingSlotData ClothingSlotData; GetClothingSlotData(ClothingSlotType, ClothingSlotData); 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()); } 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) { FClothingSlotData ClothingSlotData; GetClothingSlotData(ClothingItemInstance->GetClothingItem()->SlotType, ClothingSlotData); if (ClothingSlotData.ClothingItemInstance->GetClothingItem()) { DropClothing(ClothingItemInstance->GetClothingItem()->SlotType); } ClothingSlotData.ClothingItemInstance = ClothingItemInstance; USaveSubsystem* SaveSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem(); FItemSaveRecord ItemSaveRecord; ItemSaveRecord.Init(ClothingItemInstance); SaveSubsystem->GetCurrentSave()->EquippedItems.Push(ItemSaveRecord); SaveSubsystem->GetCurrentSave()->DroppedItems.RemoveAll([ClothingItemInstance](const FItemSaveRecord& Item) { return Item.InstanceId == ClothingItemInstance->GetInstanceId(); }); PutOnClothing(ClothingItemInstance); } UClothingItemInstance* UClothingManager::RemoveClothing(const EClothingSlotType ClothingSlotType) { FClothingSlotData ClothingSlotData; if (!GetClothingSlotData(ClothingSlotType, ClothingSlotData) || !ClothingSlotData.ClothingItemInstance) { UE_LOG(LogTemp, Error, TEXT("Couldn't find clothing slot")); return nullptr; } UClothingItemInstance* ClothingItemInstance = ClothingSlotData.ClothingItemInstance; SetClothingSlotItem(ClothingSlotType, nullptr); USkeletalMeshComponent* MeshComponent = GetMeshComponent(ClothingSlotType); MeshComponent->SetSkeletalMesh(nullptr); if (ClothingItemInstance->GetClothingItem()->UseLeaderPose) { MeshComponent->SetLeaderPoseComponent(nullptr); } OnClothingUnequip.Broadcast(ClothingItemInstance); USaveSubsystem* SaveSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem(); SaveSubsystem->GetCurrentSave()->EquippedItems.RemoveAll([ClothingItemInstance](const FItemSaveRecord& Item) { return Item.InstanceId == ClothingItemInstance->GetInstanceId(); }); return ClothingItemInstance; } void UClothingManager::DropClothing(const EClothingSlotType ClothingType) { const UClothingItemInstance* ClothingItemInstance = RemoveClothing(ClothingType); if (!ClothingItemInstance) return; USaveSubsystem* SaveSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem(); FItemSaveRecord ItemSaveRecord; ItemSaveRecord.Init(ClothingItemInstance); SaveSubsystem->GetCurrentSave()->DroppedItems.Push(ItemSaveRecord); OnClothingDropped.Broadcast(ClothingItemInstance); } bool UClothingManager::IsClothingTypeOn(const EClothingSlotType ClothingType) { FClothingSlotData ClothingSlotData; GetClothingSlotData(ClothingType, ClothingSlotData); const bool IsTypeOn = ClothingSlotData.ClothingItemInstance != nullptr; return IsTypeOn; } bool UClothingManager::IsPartiallyNaked() { return IsBodyTypeExposed(EBodyPart::Ass) || IsBodyTypeExposed(EBodyPart::Genitals) || IsBodyTypeExposed(EBodyPart::Boobs); }