// © 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/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; } void UClothingManager::PutOnClothing(UClothingItemInstance* ClothingItemInstance) { if (!ClothingItemInstance) return; const EClothingSlotType ClothingSlotType = ClothingItemInstance->GetClothingItem()->SlotType; FClothingSlotData ClothingSlotData; GetClothingSlotData(ClothingSlotType, ClothingSlotData); ClothingSlotData.MeshComponent->SetSkeletalMesh(ClothingItemInstance->GetClothingItem()->SkeletalMesh); if (!ClothingItemInstance->GetClothingItem()->Materials.IsEmpty()) { for (const TPair& Material : ClothingItemInstance->GetClothingItem()->Materials) { ClothingSlotData.MeshComponent->SetMaterialByName(Material.Key, Material.Value); } } SetClothingSlotItem(ClothingSlotType, ClothingItemInstance); if (ClothingItemInstance->GetClothingItem()->UseLeaderPose) { ClothingSlotData.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 = ClothingSlotData.MeshComponent; MeshComponent->SetSkeletalMesh(nullptr); if (ClothingItemInstance->GetClothingItem()->UseLeaderPose) { ClothingSlotData.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); }