Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e6a4fc7e06 | |||
| 5ecbf24998 | |||
| a61d4e2bd0 | |||
| 0cccb12b72 | |||
| 1c8ee03083 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
@@ -42,6 +42,10 @@
|
|||||||
"Win64"
|
"Win64"
|
||||||
],
|
],
|
||||||
"MarketplaceURL": "com.epicgames.launcher://ue/marketplace/product/362651520df94e4fa65492dbcba44ae2"
|
"MarketplaceURL": "com.epicgames.launcher://ue/marketplace/product/362651520df94e4fa65492dbcba44ae2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "StructUtils",
|
||||||
|
"Enabled": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
// © 2025 Naked People Team. All Rights Reserved.
|
||||||
|
|
||||||
|
|
||||||
|
#include "CensorshipComponent.h"
|
||||||
|
|
||||||
|
#include "Components/StaticMeshComponent.h"
|
||||||
|
#include "NakedDesire/Clothing/BodyPart.h"
|
||||||
|
#include "NakedDesire/Clothing/ClothingManager.h"
|
||||||
|
#include "NakedDesire/Global/Constants.h"
|
||||||
|
#include "NakedDesire/Global/NakedDesireUserSettings.h"
|
||||||
|
|
||||||
|
UCensorshipComponent::UCensorshipComponent()
|
||||||
|
{
|
||||||
|
PrimaryComponentTick.bCanEverTick = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UCensorshipComponent::Initialize(UClothingManager* InClothingManager,
|
||||||
|
UStaticMeshComponent* InBoobL, UStaticMeshComponent* InBoobR,
|
||||||
|
UStaticMeshComponent* InVagina, UStaticMeshComponent* InAnal)
|
||||||
|
{
|
||||||
|
ClothingManager = InClothingManager;
|
||||||
|
BoobLCensorship = InBoobL;
|
||||||
|
BoobRCensorship = InBoobR;
|
||||||
|
VaginaCensorship = InVagina;
|
||||||
|
AnalCensorship = InAnal;
|
||||||
|
|
||||||
|
if (ClothingManager)
|
||||||
|
{
|
||||||
|
ClothingManager->OnClothingEquip.AddUniqueDynamic(this, &UCensorshipComponent::HandleClothingChanged);
|
||||||
|
ClothingManager->OnClothingUnequip.AddUniqueDynamic(this, &UCensorshipComponent::HandleClothingChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UNakedDesireUserSettings* Settings = UNakedDesireUserSettings::GetNakedDesireUserSettings())
|
||||||
|
{
|
||||||
|
Settings->OnSettingsChanged.AddUniqueDynamic(this, &UCensorshipComponent::HandleSettingsChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
RefreshCensorship();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UCensorshipComponent::RefreshCensorship()
|
||||||
|
{
|
||||||
|
if (!ClothingManager)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const bool bCensor = ShouldCensor();
|
||||||
|
|
||||||
|
SetBodyPartCensored(EBodyPart::Boobs, bCensor && ClothingManager->IsBodyPartExposed(EBodyPart::Boobs));
|
||||||
|
SetBodyPartCensored(EBodyPart::Genitals, bCensor && ClothingManager->IsBodyPartExposed(EBodyPart::Genitals));
|
||||||
|
SetBodyPartCensored(EBodyPart::Ass, bCensor && ClothingManager->IsBodyPartExposed(EBodyPart::Ass));
|
||||||
|
}
|
||||||
|
|
||||||
|
void UCensorshipComponent::HandleClothingChanged(UClothingItemInstance* ClothingItemInstance)
|
||||||
|
{
|
||||||
|
RefreshCensorship();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UCensorshipComponent::HandleSettingsChanged(UNakedDesireUserSettings* Settings)
|
||||||
|
{
|
||||||
|
RefreshCensorship();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UCensorshipComponent::ShouldCensor() const
|
||||||
|
{
|
||||||
|
if (IS_DEMO)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const UNakedDesireUserSettings* Settings = UNakedDesireUserSettings::GetNakedDesireUserSettings();
|
||||||
|
return Settings && Settings->GetIsCensorshipEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UCensorshipComponent::SetBodyPartCensored(EBodyPart BodyPart, bool bCensored)
|
||||||
|
{
|
||||||
|
switch (BodyPart)
|
||||||
|
{
|
||||||
|
case EBodyPart::Boobs:
|
||||||
|
if (BoobLCensorship)
|
||||||
|
BoobLCensorship->SetVisibility(bCensored);
|
||||||
|
if (BoobRCensorship)
|
||||||
|
BoobRCensorship->SetVisibility(bCensored);
|
||||||
|
break;
|
||||||
|
case EBodyPart::Genitals:
|
||||||
|
if (VaginaCensorship)
|
||||||
|
VaginaCensorship->SetVisibility(bCensored);
|
||||||
|
break;
|
||||||
|
case EBodyPart::Ass:
|
||||||
|
if (AnalCensorship)
|
||||||
|
AnalCensorship->SetVisibility(bCensored);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
// © 2025 Naked People Team. All Rights Reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "Components/ActorComponent.h"
|
||||||
|
#include "CensorshipComponent.generated.h"
|
||||||
|
|
||||||
|
class UClothingManager;
|
||||||
|
class UClothingItemInstance;
|
||||||
|
class UNakedDesireUserSettings;
|
||||||
|
class UStaticMeshComponent;
|
||||||
|
enum class EBodyPart : uint8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Owns the show/hide logic for the body-part censorship meshes. The meshes
|
||||||
|
* themselves stay on the character (BP-authored assets + fitted transforms);
|
||||||
|
* this component just drives their visibility from the equipped set + setting.
|
||||||
|
*/
|
||||||
|
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
|
||||||
|
class NAKEDDESIRE_API UCensorshipComponent : public UActorComponent
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UCensorshipComponent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wire dependencies and apply the initial censorship state. Call from the
|
||||||
|
* owning character's BeginPlay *after* Super::BeginPlay, so clothing
|
||||||
|
* hydration has already populated the equipped set.
|
||||||
|
*/
|
||||||
|
void Initialize(UClothingManager* InClothingManager,
|
||||||
|
UStaticMeshComponent* InBoobL, UStaticMeshComponent* InBoobR,
|
||||||
|
UStaticMeshComponent* InVagina, UStaticMeshComponent* InAnal);
|
||||||
|
|
||||||
|
/** Recompute every censor mesh from the current equipped set + setting. Idempotent. */
|
||||||
|
void RefreshCensorship();
|
||||||
|
|
||||||
|
private:
|
||||||
|
UFUNCTION()
|
||||||
|
void HandleClothingChanged(UClothingItemInstance* ClothingItemInstance);
|
||||||
|
|
||||||
|
UFUNCTION()
|
||||||
|
void HandleSettingsChanged(UNakedDesireUserSettings* Settings);
|
||||||
|
|
||||||
|
/** Censorship is forced on in the demo build regardless of the user setting. */
|
||||||
|
bool ShouldCensor() const;
|
||||||
|
|
||||||
|
void SetBodyPartCensored(EBodyPart BodyPart, bool bCensored);
|
||||||
|
|
||||||
|
UPROPERTY()
|
||||||
|
TObjectPtr<UClothingManager> ClothingManager;
|
||||||
|
|
||||||
|
UPROPERTY()
|
||||||
|
TObjectPtr<UStaticMeshComponent> BoobLCensorship;
|
||||||
|
|
||||||
|
UPROPERTY()
|
||||||
|
TObjectPtr<UStaticMeshComponent> BoobRCensorship;
|
||||||
|
|
||||||
|
UPROPERTY()
|
||||||
|
TObjectPtr<UStaticMeshComponent> VaginaCensorship;
|
||||||
|
|
||||||
|
UPROPERTY()
|
||||||
|
TObjectPtr<UStaticMeshComponent> AnalCensorship;
|
||||||
|
};
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
// © 2025 Naked People Team. All Rights Reserved.
|
|
||||||
|
|
||||||
|
|
||||||
#include "ClothingItem.h"
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// © 2025 Naked People Team. All Rights Reserved.
|
||||||
|
|
||||||
|
|
||||||
|
#include "ClothingItemDefinition.h"
|
||||||
|
|
||||||
|
#include "ClothingItemInstance.h"
|
||||||
|
|
||||||
|
TSubclassOf<UItemInstance> UClothingItemDefinition::GetInstanceClass() const
|
||||||
|
{
|
||||||
|
return UClothingItemInstance::StaticClass();
|
||||||
|
}
|
||||||
+4
-13
@@ -6,8 +6,9 @@
|
|||||||
#include "BodyPart.h"
|
#include "BodyPart.h"
|
||||||
#include "ClothingSlotType.h"
|
#include "ClothingSlotType.h"
|
||||||
#include "Engine/DataAsset.h"
|
#include "Engine/DataAsset.h"
|
||||||
|
#include "NakedDesire/Items/ItemDefinition.h"
|
||||||
#include "NakedDesire/Progression/ProgressionPath.h"
|
#include "NakedDesire/Progression/ProgressionPath.h"
|
||||||
#include "ClothingItem.generated.h"
|
#include "ClothingItemDefinition.generated.h"
|
||||||
|
|
||||||
USTRUCT(BlueprintType)
|
USTRUCT(BlueprintType)
|
||||||
struct NAKEDDESIRE_API FBodyPartCoverage
|
struct NAKEDDESIRE_API FBodyPartCoverage
|
||||||
@@ -68,16 +69,12 @@ struct NAKEDDESIRE_API FGarmentContainerSlot
|
|||||||
};
|
};
|
||||||
|
|
||||||
UCLASS(BlueprintType)
|
UCLASS(BlueprintType)
|
||||||
class NAKEDDESIRE_API UClothingItem : public UPrimaryDataAsset
|
class NAKEDDESIRE_API UClothingItemDefinition : public UItemDefinition
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
virtual TSubclassOf<UItemInstance> GetInstanceClass() const override;
|
||||||
FText Name;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
|
||||||
TObjectPtr<UTexture2D> Icon;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
||||||
EClothingSlotType SlotType;
|
EClothingSlotType SlotType;
|
||||||
@@ -88,9 +85,6 @@ public:
|
|||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
||||||
TMap<FName, UMaterialInstance*> Materials;
|
TMap<FName, UMaterialInstance*> Materials;
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
|
||||||
UStaticMesh* StaticMesh;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
||||||
int BasePrice;
|
int BasePrice;
|
||||||
|
|
||||||
@@ -109,9 +103,6 @@ public:
|
|||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
||||||
TArray<EBodyPart> CanExpose;
|
TArray<EBodyPart> CanExpose;
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
|
||||||
float Coverage = 1.0f;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
||||||
TArray<FGarmentContainerSlot> ContainerSlots;
|
TArray<FGarmentContainerSlot> ContainerSlots;
|
||||||
|
|
||||||
@@ -1,27 +1,24 @@
|
|||||||
#include "ClothingItemInstance.h"
|
#include "ClothingItemInstance.h"
|
||||||
|
|
||||||
#include "ClothingItem.h"
|
#include "ClothingItemDefinition.h"
|
||||||
#include "NakedDesire/SaveGame/ItemSaveRecord.h"
|
#include "StructUtils/InstancedStruct.h"
|
||||||
|
|
||||||
void UClothingItemInstance::Init(UClothingItem* InClothingItem)
|
void UClothingItemInstance::Init(UClothingItemDefinition* InClothingItem)
|
||||||
{
|
{
|
||||||
ClothingItem = InClothingItem;
|
ItemDefinition = InClothingItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UClothingItemInstance::Setup(UClothingItem* InClothingItem, const TArray<UItemInstance*>& InStoredItems,
|
void UClothingItemInstance::CaptureState(FInstancedStruct& OutState) const
|
||||||
const float InCondition, const FGuid InInstanceId)
|
|
||||||
{
|
{
|
||||||
this->ClothingItem = InClothingItem;
|
FClothingInstanceState ClothingState;
|
||||||
this->StoredItems = InStoredItems;
|
ClothingState.Condition = Condition;
|
||||||
this->Condition = InCondition;
|
OutState.InitializeAs<FClothingInstanceState>(ClothingState);
|
||||||
this->InstanceId = InInstanceId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UClothingItemInstance* UClothingItemInstance::CreateFromSave(UObject* Outer, const FItemSaveRecord& ItemSaveRecord)
|
void UClothingItemInstance::ApplyState(const FInstancedStruct& InState)
|
||||||
{
|
{
|
||||||
UClothingItemInstance* NewItemInstance = NewObject<UClothingItemInstance>(Outer);
|
if (const FClothingInstanceState* ClothingState = InState.GetPtr<FClothingInstanceState>())
|
||||||
|
{
|
||||||
NewItemInstance->Setup(ItemSaveRecord.Definition.Get(), {}, ItemSaveRecord.Condition, ItemSaveRecord.InstanceId);
|
Condition = ClothingState->Condition;
|
||||||
|
}
|
||||||
return NewItemInstance;
|
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,21 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
|
#include "ClothingItemDefinition.h"
|
||||||
#include "NakedDesire/Items/ItemInstance.h"
|
#include "NakedDesire/Items/ItemInstance.h"
|
||||||
#include "ClothingItemInstance.generated.h"
|
#include "ClothingItemInstance.generated.h"
|
||||||
|
|
||||||
struct FItemSaveRecord;
|
class UClothingItemDefinition;
|
||||||
class UClothingItem;
|
|
||||||
|
/** Per-instance mutable state for clothing. */
|
||||||
|
USTRUCT()
|
||||||
|
struct FClothingInstanceState : public FItemInstanceState
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
UPROPERTY(SaveGame)
|
||||||
|
float Condition = 1.0f;
|
||||||
|
};
|
||||||
|
|
||||||
UCLASS(BlueprintType)
|
UCLASS(BlueprintType)
|
||||||
class NAKEDDESIRE_API UClothingItemInstance : public UItemInstance
|
class NAKEDDESIRE_API UClothingItemInstance : public UItemInstance
|
||||||
@@ -16,16 +26,13 @@ public:
|
|||||||
UPROPERTY(BlueprintReadOnly, Category = "Clothing Item")
|
UPROPERTY(BlueprintReadOnly, Category = "Clothing Item")
|
||||||
float Condition = 1.0f;
|
float Condition = 1.0f;
|
||||||
|
|
||||||
UClothingItem* GetClothingItem() const { return ClothingItem; }
|
UClothingItemDefinition* GetClothingItemDefinition() const { return Cast<UClothingItemDefinition>(ItemDefinition); }
|
||||||
|
|
||||||
void Init(UClothingItem* InClothingItem);
|
void Init(UClothingItemDefinition* InClothingItem);
|
||||||
void Setup(UClothingItem* InClothingItem, const TArray<UItemInstance*>& InStoredItems, float InCondition, FGuid InInstanceId);
|
|
||||||
|
|
||||||
static UClothingItemInstance* CreateFromSave(UObject* Outer, const FItemSaveRecord& ItemSaveRecord);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
UPROPERTY(BlueprintReadOnly, Category = "Clothing Item")
|
virtual void CaptureState(FInstancedStruct& OutState) const override;
|
||||||
TObjectPtr<UClothingItem> ClothingItem;
|
virtual void ApplyState(const FInstancedStruct& InState) override;
|
||||||
|
|
||||||
UPROPERTY(BlueprintReadOnly, Category = "Clothing Item")
|
UPROPERTY(BlueprintReadOnly, Category = "Clothing Item")
|
||||||
TArray<TObjectPtr<UItemInstance>> StoredItems;
|
TArray<TObjectPtr<UItemInstance>> StoredItems;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "ClothingManager.h"
|
#include "ClothingManager.h"
|
||||||
#include "ClothingItem.h"
|
#include "ClothingItemDefinition.h"
|
||||||
#include "ClothingItemInstance.h"
|
#include "ClothingItemInstance.h"
|
||||||
#include "GameFramework/Character.h"
|
#include "GameFramework/Character.h"
|
||||||
#include "Kismet/GameplayStatics.h"
|
#include "Kismet/GameplayStatics.h"
|
||||||
@@ -51,7 +51,7 @@ bool UClothingManager::IsBodyPartExposed(const EBodyPart BodyPart)
|
|||||||
{
|
{
|
||||||
for (const auto& [Key, Value] : EquippedClothing)
|
for (const auto& [Key, Value] : EquippedClothing)
|
||||||
{
|
{
|
||||||
if (Value->GetClothingItem()->HiddenBodyParts.Contains(BodyPart))
|
if (Value->GetClothingItemDefinition()->HiddenBodyParts.Contains(BodyPart))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +63,10 @@ void UClothingManager::HydrateClothing()
|
|||||||
USaveSubsystem* SaveSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem<USaveSubsystem>();
|
USaveSubsystem* SaveSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem<USaveSubsystem>();
|
||||||
for (const FItemSaveRecord& ItemSaveRecord : SaveSubsystem->GetCurrentSave()->GetEquippedItems())
|
for (const FItemSaveRecord& ItemSaveRecord : SaveSubsystem->GetCurrentSave()->GetEquippedItems())
|
||||||
{
|
{
|
||||||
UClothingItemInstance* ClothingItemInstance = UClothingItemInstance::CreateFromSave(this, ItemSaveRecord);
|
UClothingItemInstance* ClothingItemInstance = Cast<UClothingItemInstance>(UItemInstance::CreateFromRecord(this, ItemSaveRecord));
|
||||||
|
if (!ClothingItemInstance)
|
||||||
|
continue;
|
||||||
|
|
||||||
PutOnClothing(ClothingItemInstance);
|
PutOnClothing(ClothingItemInstance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,38 +78,7 @@ float UClothingManager::GetHeelHeight()
|
|||||||
|
|
||||||
const UClothingItemInstance* Footwear = EquippedClothing[EClothingSlotType::Footwear];
|
const UClothingItemInstance* Footwear = EquippedClothing[EClothingSlotType::Footwear];
|
||||||
|
|
||||||
return Footwear->GetClothingItem()->ShoesOffset;
|
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)
|
void UClothingManager::SpawnClothingPickup(UClothingItemInstance* ItemInstance)
|
||||||
@@ -135,25 +107,11 @@ void UClothingManager::PutOnClothing(UClothingItemInstance* ClothingItemInstance
|
|||||||
if (!ClothingItemInstance)
|
if (!ClothingItemInstance)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const EClothingSlotType ClothingSlotType = ClothingItemInstance->GetClothingItem()->SlotType;
|
const EClothingSlotType ClothingSlotType = ClothingItemInstance->GetClothingItemDefinition()->SlotType;
|
||||||
|
|
||||||
USkeletalMeshComponent* MeshComponent = GetMeshComponent(ClothingSlotType);
|
|
||||||
MeshComponent->SetSkeletalMesh(ClothingItemInstance->GetClothingItem()->SkeletalMesh);
|
|
||||||
if (!ClothingItemInstance->GetClothingItem()->Materials.IsEmpty())
|
|
||||||
{
|
|
||||||
for (const TPair<FName, UMaterialInstance*>& Material : ClothingItemInstance->GetClothingItem()->Materials)
|
|
||||||
{
|
|
||||||
MeshComponent->SetMaterialByName(Material.Key, Material.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SetClothingSlotItem(ClothingSlotType, ClothingItemInstance);
|
SetClothingSlotItem(ClothingSlotType, ClothingItemInstance);
|
||||||
if (ClothingItemInstance->GetClothingItem()->UseLeaderPose)
|
|
||||||
{
|
|
||||||
MeshComponent->SetLeaderPoseComponent(Cast<ACharacter>(GetOwner())->GetMesh());
|
|
||||||
}
|
|
||||||
|
|
||||||
const UClothingItem* ClothingItem = ClothingItemInstance->GetClothingItem();
|
const UClothingItemDefinition* ClothingItem = ClothingItemInstance->GetClothingItemDefinition();
|
||||||
if (ClothingItem->SlotType == EClothingSlotType::Bodysuit)
|
if (ClothingItem->SlotType == EClothingSlotType::Bodysuit)
|
||||||
{
|
{
|
||||||
DropClothing(EClothingSlotType::Top);
|
DropClothing(EClothingSlotType::Top);
|
||||||
@@ -174,7 +132,7 @@ void UClothingManager::PutOnClothing(UClothingItemInstance* ClothingItemInstance
|
|||||||
|
|
||||||
void UClothingManager::TakeClothing(UClothingItemInstance* ClothingItemInstance)
|
void UClothingManager::TakeClothing(UClothingItemInstance* ClothingItemInstance)
|
||||||
{
|
{
|
||||||
const EClothingSlotType SlotType = ClothingItemInstance->GetClothingItem()->SlotType;
|
const EClothingSlotType SlotType = ClothingItemInstance->GetClothingItemDefinition()->SlotType;
|
||||||
if (EquippedClothing.Contains(SlotType))
|
if (EquippedClothing.Contains(SlotType))
|
||||||
{
|
{
|
||||||
DropClothing(SlotType);
|
DropClothing(SlotType);
|
||||||
@@ -197,14 +155,6 @@ UClothingItemInstance* UClothingManager::RemoveClothing(const EClothingSlotType
|
|||||||
|
|
||||||
SetClothingSlotItem(ClothingSlotType, nullptr);
|
SetClothingSlotItem(ClothingSlotType, nullptr);
|
||||||
|
|
||||||
USkeletalMeshComponent* MeshComponent = GetMeshComponent(ClothingSlotType);
|
|
||||||
MeshComponent->SetSkeletalMesh(nullptr);
|
|
||||||
|
|
||||||
if (ExistingItem->GetClothingItem()->UseLeaderPose)
|
|
||||||
{
|
|
||||||
MeshComponent->SetLeaderPoseComponent(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
OnClothingUnequip.Broadcast(ExistingItem);
|
OnClothingUnequip.Broadcast(ExistingItem);
|
||||||
|
|
||||||
USaveSubsystem* SaveSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem<USaveSubsystem>();
|
USaveSubsystem* SaveSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem<USaveSubsystem>();
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ public:
|
|||||||
float GetHeelHeight();
|
float GetHeelHeight();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
USkeletalMeshComponent* GetMeshComponent(EClothingSlotType SlotType) const;
|
|
||||||
void SpawnClothingPickup(UClothingItemInstance* ItemInstance);
|
void SpawnClothingPickup(UClothingItemInstance* ItemInstance);
|
||||||
|
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
// © 2025 Naked People Team. All Rights Reserved.
|
||||||
|
|
||||||
|
|
||||||
|
#include "ClothingVisualsComponent.h"
|
||||||
|
|
||||||
|
#include "ClothingItemDefinition.h"
|
||||||
|
#include "ClothingItemInstance.h"
|
||||||
|
#include "ClothingManager.h"
|
||||||
|
#include "Components/SkeletalMeshComponent.h"
|
||||||
|
#include "Materials/MaterialInstance.h"
|
||||||
|
|
||||||
|
UClothingVisualsComponent::UClothingVisualsComponent()
|
||||||
|
{
|
||||||
|
PrimaryComponentTick.bCanEverTick = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UClothingVisualsComponent::Initialize(USkeletalMeshComponent* InBodyMesh, UClothingManager* InClothingManager)
|
||||||
|
{
|
||||||
|
BodyMesh = InBodyMesh;
|
||||||
|
ClothingManager = InClothingManager;
|
||||||
|
|
||||||
|
if (!ClothingManager)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ClothingManager->OnClothingEquip.AddUniqueDynamic(this, &UClothingVisualsComponent::HandleClothingEquip);
|
||||||
|
ClothingManager->OnClothingUnequip.AddUniqueDynamic(this, &UClothingVisualsComponent::HandleClothingUnequip);
|
||||||
|
|
||||||
|
for (const UClothingItemInstance* Equipped : ClothingManager->GetEquippedClothing())
|
||||||
|
{
|
||||||
|
Apply(Equipped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UClothingVisualsComponent::Apply(const UClothingItemInstance* ClothingItemInstance)
|
||||||
|
{
|
||||||
|
if (!ClothingItemInstance)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const UClothingItemDefinition* Definition = ClothingItemInstance->GetClothingItemDefinition();
|
||||||
|
if (!Definition)
|
||||||
|
return;
|
||||||
|
|
||||||
|
USkeletalMeshComponent* SlotMesh = GetOrCreateSlotMesh(Definition->SlotType);
|
||||||
|
if (!SlotMesh)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SlotMesh->SetSkeletalMesh(Definition->SkeletalMesh);
|
||||||
|
|
||||||
|
if (Definition->UseLeaderPose)
|
||||||
|
{
|
||||||
|
SlotMesh->SetLeaderPoseComponent(BodyMesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const TPair<FName, UMaterialInstance*>& Material : Definition->Materials)
|
||||||
|
{
|
||||||
|
SlotMesh->SetMaterialByName(Material.Key, Material.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UClothingVisualsComponent::ClearSlot(EClothingSlotType SlotType)
|
||||||
|
{
|
||||||
|
if (const TObjectPtr<USkeletalMeshComponent>* Found = SlotMeshes.Find(SlotType))
|
||||||
|
{
|
||||||
|
(*Found)->SetLeaderPoseComponent(nullptr);
|
||||||
|
(*Found)->SetSkeletalMesh(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UClothingVisualsComponent::HandleClothingEquip(UClothingItemInstance* ClothingItemInstance)
|
||||||
|
{
|
||||||
|
Apply(ClothingItemInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UClothingVisualsComponent::HandleClothingUnequip(UClothingItemInstance* ClothingItemInstance)
|
||||||
|
{
|
||||||
|
if (ClothingItemInstance && ClothingItemInstance->GetClothingItemDefinition())
|
||||||
|
{
|
||||||
|
ClearSlot(ClothingItemInstance->GetClothingItemDefinition()->SlotType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
USkeletalMeshComponent* UClothingVisualsComponent::GetOrCreateSlotMesh(EClothingSlotType SlotType)
|
||||||
|
{
|
||||||
|
if (const TObjectPtr<USkeletalMeshComponent>* Found = SlotMeshes.Find(SlotType))
|
||||||
|
{
|
||||||
|
return *Found;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!BodyMesh)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
const FName ComponentName = *FString::Printf(TEXT("ClothingSlotMesh_%d"), static_cast<int32>(SlotType));
|
||||||
|
USkeletalMeshComponent* SlotMesh = NewObject<USkeletalMeshComponent>(GetOwner(), ComponentName);
|
||||||
|
SlotMesh->SetupAttachment(BodyMesh);
|
||||||
|
SlotMesh->RegisterComponent();
|
||||||
|
SlotMeshes.Add(SlotType, SlotMesh);
|
||||||
|
return SlotMesh;
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
// © 2025 Naked People Team. All Rights Reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "Components/ActorComponent.h"
|
||||||
|
#include "ClothingSlotType.h"
|
||||||
|
#include "ClothingVisualsComponent.generated.h"
|
||||||
|
|
||||||
|
class UClothingManager;
|
||||||
|
class UClothingItemInstance;
|
||||||
|
class USkeletalMeshComponent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders equipped clothing by lazily spawning one skeletal mesh component per
|
||||||
|
* occupied slot, parented to a target body mesh. Reacts to a UClothingManager's
|
||||||
|
* equip/unequip events, so the character, mirror impostor, and cinematic double
|
||||||
|
* share one implementation instead of hand-maintained per-slot components.
|
||||||
|
*/
|
||||||
|
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
|
||||||
|
class NAKEDDESIRE_API UClothingVisualsComponent : public UActorComponent
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UClothingVisualsComponent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind to a clothing manager and a body mesh (the leader-pose source and
|
||||||
|
* attach parent for spawned slot meshes), then apply the current equipped set.
|
||||||
|
* Call after the manager has hydrated (e.g. owning actor's BeginPlay).
|
||||||
|
*/
|
||||||
|
void Initialize(USkeletalMeshComponent* InBodyMesh, UClothingManager* InClothingManager);
|
||||||
|
|
||||||
|
void Apply(const UClothingItemInstance* ClothingItemInstance);
|
||||||
|
void ClearSlot(EClothingSlotType SlotType);
|
||||||
|
|
||||||
|
private:
|
||||||
|
UFUNCTION()
|
||||||
|
void HandleClothingEquip(UClothingItemInstance* ClothingItemInstance);
|
||||||
|
|
||||||
|
UFUNCTION()
|
||||||
|
void HandleClothingUnequip(UClothingItemInstance* ClothingItemInstance);
|
||||||
|
|
||||||
|
/** Returns the slot's mesh component, creating + attaching it on first use. */
|
||||||
|
USkeletalMeshComponent* GetOrCreateSlotMesh(EClothingSlotType SlotType);
|
||||||
|
|
||||||
|
UPROPERTY()
|
||||||
|
TObjectPtr<USkeletalMeshComponent> BodyMesh;
|
||||||
|
|
||||||
|
UPROPERTY()
|
||||||
|
TObjectPtr<UClothingManager> ClothingManager;
|
||||||
|
|
||||||
|
UPROPERTY()
|
||||||
|
TMap<EClothingSlotType, TObjectPtr<USkeletalMeshComponent>> SlotMeshes;
|
||||||
|
};
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "NakedDesireGameMode.h"
|
#include "NakedDesireGameMode.h"
|
||||||
#include "Kismet/GameplayStatics.h"
|
#include "Kismet/GameplayStatics.h"
|
||||||
#include "NakedDesire/Clothing/ClothingItem.h"
|
#include "NakedDesire/Clothing/ClothingItemDefinition.h"
|
||||||
#include "NakedDesire/Clothing/ClothingItemInstance.h"
|
#include "NakedDesire/Clothing/ClothingItemInstance.h"
|
||||||
#include "NakedDesire/Interactables/ItemPickup.h"
|
#include "NakedDesire/Interactables/ItemPickup.h"
|
||||||
#include "UObject/ConstructorHelpers.h"
|
#include "UObject/ConstructorHelpers.h"
|
||||||
@@ -34,10 +34,10 @@ void ANakedDesireGameMode::BuyItem(UClothingItemInstance* ClothingItemInstance)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SaveGame->Money < ClothingItemInstance->GetClothingItem()->BasePrice)
|
if (SaveGame->Money < ClothingItemInstance->GetClothingItemDefinition()->BasePrice)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SaveGame->Money -= ClothingItemInstance->GetClothingItem()->BasePrice;
|
SaveGame->Money -= ClothingItemInstance->GetClothingItemDefinition()->BasePrice;
|
||||||
Wardrobe->AddItem(ClothingItemInstance);
|
Wardrobe->AddItem(ClothingItemInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,12 +71,12 @@ void ANakedDesireGameMode::BeginPlay()
|
|||||||
}
|
}
|
||||||
|
|
||||||
USaveSubsystem* SaveSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem<USaveSubsystem>();
|
USaveSubsystem* SaveSubsystem = UGameplayStatics::GetGameInstance(GetWorld())->GetSubsystem<USaveSubsystem>();
|
||||||
for (const auto& Item : SaveSubsystem->GetCurrentSave()->GetWorldItems())
|
for (const FItemSaveRecord& Item : SaveSubsystem->GetCurrentSave()->GetWorldItems())
|
||||||
{
|
{
|
||||||
UClothingItemInstance* NewItemInstance = NewObject<UClothingItemInstance>(this);
|
UClothingItemInstance* NewItemInstance = Cast<UClothingItemInstance>(UItemInstance::CreateFromRecord(this, Item));
|
||||||
NewItemInstance->Init(Item.Definition.Get());
|
if (!NewItemInstance)
|
||||||
NewItemInstance->Condition = Item.Condition;
|
continue;
|
||||||
NewItemInstance->SetInstanceId(Item.InstanceId);
|
|
||||||
AItemPickup* NewItemPickup = GetWorld()->SpawnActor<AItemPickup>(ItemPickupClass, Item.WorldTransform);
|
AItemPickup* NewItemPickup = GetWorld()->SpawnActor<AItemPickup>(ItemPickupClass, Item.WorldTransform);
|
||||||
NewItemPickup->SetItem(NewItemInstance);
|
NewItemPickup->SetItem(NewItemInstance);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#include "Components/BoxComponent.h"
|
#include "Components/BoxComponent.h"
|
||||||
#include "Components/WidgetComponent.h"
|
#include "Components/WidgetComponent.h"
|
||||||
#include "Kismet/GameplayStatics.h"
|
#include "Kismet/GameplayStatics.h"
|
||||||
#include "NakedDesire/Clothing/ClothingItem.h"
|
#include "NakedDesire/Clothing/ClothingItemDefinition.h"
|
||||||
#include "NakedDesire/Clothing/ClothingItemInstance.h"
|
#include "NakedDesire/Clothing/ClothingItemInstance.h"
|
||||||
#include "NakedDesire/Clothing/ClothingManager.h"
|
#include "NakedDesire/Clothing/ClothingManager.h"
|
||||||
#include "NakedDesire/Player/NakedDesireCharacter.h"
|
#include "NakedDesire/Player/NakedDesireCharacter.h"
|
||||||
@@ -71,7 +71,14 @@ void AItemPickup::SetItem(UClothingItemInstance* InItem)
|
|||||||
{
|
{
|
||||||
ClothingItemInstance = InItem;
|
ClothingItemInstance = InItem;
|
||||||
|
|
||||||
Mesh->SetStaticMesh(InItem->GetClothingItem()->StaticMesh);
|
Mesh->SetStaticMesh(InItem->GetClothingItemDefinition()->StaticMesh);
|
||||||
|
if (!InItem->GetClothingItemDefinition()->Materials.IsEmpty())
|
||||||
|
{
|
||||||
|
for (const TPair<FName, UMaterialInstance*>& Material : InItem->GetClothingItemDefinition()->Materials)
|
||||||
|
{
|
||||||
|
Mesh->SetMaterialByName(Material.Key, Material.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AItemPickup::ApplyOutline(UStaticMeshComponent* InMesh, bool bEnabled, int32 StencilValue)
|
void AItemPickup::ApplyOutline(UStaticMeshComponent* InMesh, bool bEnabled, int32 StencilValue)
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ public:
|
|||||||
virtual void ShowInteractionFocusHint_Implementation() override;
|
virtual void ShowInteractionFocusHint_Implementation() override;
|
||||||
virtual void ShowInteractionProximityHint_Implementation() override;
|
virtual void ShowInteractionProximityHint_Implementation() override;
|
||||||
|
|
||||||
|
|
||||||
void SetItem(UClothingItemInstance* InItem);
|
void SetItem(UClothingItemInstance* InItem);
|
||||||
UClothingItemInstance* GetItem() const { return ClothingItemInstance; }
|
UClothingItemInstance* GetItem() const { return ClothingItemInstance; }
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "Wardrobe.h"
|
#include "Wardrobe.h"
|
||||||
#include "Kismet/GameplayStatics.h"
|
#include "Kismet/GameplayStatics.h"
|
||||||
|
#include "NakedDesire/Clothing/ClothingItemInstance.h"
|
||||||
#include "NakedDesire/SaveGame/GlobalSaveGameData.h"
|
#include "NakedDesire/SaveGame/GlobalSaveGameData.h"
|
||||||
#include "NakedDesire/SaveGame/ItemSaveRecord.h"
|
#include "NakedDesire/SaveGame/ItemSaveRecord.h"
|
||||||
#include "NakedDesire/SaveGame/SaveSubsystem.h"
|
#include "NakedDesire/SaveGame/SaveSubsystem.h"
|
||||||
@@ -29,7 +30,10 @@ void AWardrobe::BeginPlay()
|
|||||||
|
|
||||||
for (const FItemSaveRecord& ItemSaveRecord : SaveGame->GetWardrobeItems())
|
for (const FItemSaveRecord& ItemSaveRecord : SaveGame->GetWardrobeItems())
|
||||||
{
|
{
|
||||||
UClothingItemInstance* NewItemInstance = UClothingItemInstance::CreateFromSave(this, ItemSaveRecord);
|
UClothingItemInstance* NewItemInstance = Cast<UClothingItemInstance>(UItemInstance::CreateFromRecord(this, ItemSaveRecord));
|
||||||
|
if (!NewItemInstance)
|
||||||
|
continue;
|
||||||
|
|
||||||
ClothingItems.Push(NewItemInstance);
|
ClothingItems.Push(NewItemInstance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// © 2025 Naked People Team. All Rights Reserved.
|
||||||
|
|
||||||
|
|
||||||
|
#include "ItemDefinition.h"
|
||||||
|
|
||||||
|
#include "ItemInstance.h"
|
||||||
|
|
||||||
|
UItemInstance* UItemDefinition::CreateInstance(UObject* Outer) const
|
||||||
|
{
|
||||||
|
const TSubclassOf<UItemInstance> InstanceClass = GetInstanceClass();
|
||||||
|
if (!InstanceClass)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
UItemInstance* Instance = NewObject<UItemInstance>(Outer, InstanceClass);
|
||||||
|
Instance->SetItemDefinition(const_cast<UItemDefinition*>(this));
|
||||||
|
return Instance;
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
// © 2025 Naked People Team. All Rights Reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "Engine/DataAsset.h"
|
||||||
|
#include "Templates/SubclassOf.h"
|
||||||
|
#include "ItemDefinition.generated.h"
|
||||||
|
|
||||||
|
class UItemInstance;
|
||||||
|
|
||||||
|
UCLASS(Abstract)
|
||||||
|
class NAKEDDESIRE_API UItemDefinition : public UPrimaryDataAsset
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** The UItemInstance subclass that runtime instances of this definition use. */
|
||||||
|
virtual TSubclassOf<UItemInstance> GetInstanceClass() const PURE_VIRTUAL(UItemDefinition::GetInstanceClass, return nullptr;);
|
||||||
|
|
||||||
|
/** Mint a fresh runtime instance of this definition (new GUID, default per-type state). */
|
||||||
|
UItemInstance* CreateInstance(UObject* Outer) const;
|
||||||
|
|
||||||
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
||||||
|
FText Name;
|
||||||
|
|
||||||
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
||||||
|
TObjectPtr<UTexture2D> Icon;
|
||||||
|
|
||||||
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
|
||||||
|
UStaticMesh* StaticMesh;
|
||||||
|
};
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
#include "ItemInstance.h"
|
#include "ItemInstance.h"
|
||||||
|
|
||||||
|
#include "ItemDefinition.h"
|
||||||
|
#include "StructUtils/InstancedStruct.h"
|
||||||
|
#include "NakedDesire/SaveGame/ItemSaveRecord.h"
|
||||||
|
|
||||||
void UItemInstance::PostInitProperties()
|
void UItemInstance::PostInitProperties()
|
||||||
{
|
{
|
||||||
Super::PostInitProperties();
|
Super::PostInitProperties();
|
||||||
@@ -20,3 +24,37 @@ void UItemInstance::SetInstanceId(FGuid InId)
|
|||||||
{
|
{
|
||||||
InstanceId = InId;
|
InstanceId = InId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FItemSaveRecord UItemInstance::ToSaveRecord() const
|
||||||
|
{
|
||||||
|
FItemSaveRecord Record;
|
||||||
|
Record.InstanceId = InstanceId;
|
||||||
|
Record.Definition = ItemDefinition;
|
||||||
|
CaptureState(Record.State);
|
||||||
|
return Record;
|
||||||
|
}
|
||||||
|
|
||||||
|
UItemInstance* UItemInstance::CreateFromRecord(UObject* Outer, const FItemSaveRecord& Record)
|
||||||
|
{
|
||||||
|
UItemDefinition* Definition = Record.Definition.LoadSynchronous();
|
||||||
|
if (!Definition)
|
||||||
|
{
|
||||||
|
UE_LOG(LogTemp, Warning, TEXT("UItemInstance::CreateFromRecord: failed to load definition for instance %s"),
|
||||||
|
*Record.InstanceId.ToString());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TSubclassOf<UItemInstance> InstanceClass = Definition->GetInstanceClass();
|
||||||
|
if (!InstanceClass)
|
||||||
|
{
|
||||||
|
UE_LOG(LogTemp, Warning, TEXT("UItemInstance::CreateFromRecord: %s returned no instance class"),
|
||||||
|
*Definition->GetName());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
UItemInstance* Instance = NewObject<UItemInstance>(Outer, InstanceClass);
|
||||||
|
Instance->ItemDefinition = Definition;
|
||||||
|
Instance->InstanceId = Record.InstanceId.IsValid() ? Record.InstanceId : FGuid::NewGuid();
|
||||||
|
Instance->ApplyState(Record.State);
|
||||||
|
return Instance;
|
||||||
|
}
|
||||||
@@ -4,6 +4,20 @@
|
|||||||
#include "UObject/Object.h"
|
#include "UObject/Object.h"
|
||||||
#include "ItemInstance.generated.h"
|
#include "ItemInstance.generated.h"
|
||||||
|
|
||||||
|
class UItemDefinition;
|
||||||
|
struct FItemSaveRecord;
|
||||||
|
struct FInstancedStruct;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base for per-instance mutable state carried inside FItemSaveRecord::State.
|
||||||
|
* Subclass per item type (see FClothingInstanceState, FSexToyInstanceState).
|
||||||
|
*/
|
||||||
|
USTRUCT()
|
||||||
|
struct NAKEDDESIRE_API FItemInstanceState
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
};
|
||||||
|
|
||||||
UCLASS(Abstract)
|
UCLASS(Abstract)
|
||||||
class NAKEDDESIRE_API UItemInstance : public UObject
|
class NAKEDDESIRE_API UItemInstance : public UObject
|
||||||
{
|
{
|
||||||
@@ -16,7 +30,29 @@ public:
|
|||||||
FGuid GetInstanceId() const { return InstanceId; }
|
FGuid GetInstanceId() const { return InstanceId; }
|
||||||
void SetInstanceId(FGuid InId);
|
void SetInstanceId(FGuid InId);
|
||||||
|
|
||||||
|
UItemDefinition* GetItemDefinition() const { return ItemDefinition; }
|
||||||
|
void SetItemDefinition(UItemDefinition* InDefinition) { ItemDefinition = InDefinition; }
|
||||||
|
|
||||||
|
/** Serialize identity + definition + per-type state into a record. */
|
||||||
|
FItemSaveRecord ToSaveRecord() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reconstruct the correct UItemInstance subclass from a saved record,
|
||||||
|
* driven by the definition's GetInstanceClass(). Returns nullptr if the
|
||||||
|
* definition fails to load.
|
||||||
|
*/
|
||||||
|
static UItemInstance* CreateFromRecord(UObject* Outer, const FItemSaveRecord& Record);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
/** Override to pack this type's mutable state into OutState. */
|
||||||
|
virtual void CaptureState(FInstancedStruct& OutState) const {}
|
||||||
|
|
||||||
|
/** Override to restore this type's mutable state from InState. */
|
||||||
|
virtual void ApplyState(const FInstancedStruct& InState) {}
|
||||||
|
|
||||||
UPROPERTY(VisibleAnywhere, SaveGame, BlueprintReadOnly, Category = "Item", meta = (AllowPrivateAccess = "true"))
|
UPROPERTY(VisibleAnywhere, SaveGame, BlueprintReadOnly, Category = "Item", meta = (AllowPrivateAccess = "true"))
|
||||||
FGuid InstanceId;
|
FGuid InstanceId;
|
||||||
|
|
||||||
|
UPROPERTY()
|
||||||
|
TObjectPtr<UItemDefinition> ItemDefinition;
|
||||||
};
|
};
|
||||||
@@ -1 +1,20 @@
|
|||||||
#include "SexToyInstance.h"
|
#include "SexToyInstance.h"
|
||||||
|
|
||||||
|
#include "StructUtils/InstancedStruct.h"
|
||||||
|
|
||||||
|
void USexToyInstance::CaptureState(FInstancedStruct& OutState) const
|
||||||
|
{
|
||||||
|
FSexToyInstanceState State;
|
||||||
|
State.bActive = bActive;
|
||||||
|
State.Battery = Battery;
|
||||||
|
OutState.InitializeAs<FSexToyInstanceState>(State);
|
||||||
|
}
|
||||||
|
|
||||||
|
void USexToyInstance::ApplyState(const FInstancedStruct& InState)
|
||||||
|
{
|
||||||
|
if (const FSexToyInstanceState* State = InState.GetPtr<FSexToyInstanceState>())
|
||||||
|
{
|
||||||
|
bActive = State->bActive;
|
||||||
|
Battery = State->Battery;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,9 +2,21 @@
|
|||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "ItemInstance.h"
|
#include "ItemInstance.h"
|
||||||
|
#include "SexToyItem.h"
|
||||||
#include "SexToyInstance.generated.h"
|
#include "SexToyInstance.generated.h"
|
||||||
|
|
||||||
class USexToyItem;
|
/** Per-instance mutable state for sex toys. */
|
||||||
|
USTRUCT()
|
||||||
|
struct FSexToyInstanceState : public FItemInstanceState
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
UPROPERTY(SaveGame)
|
||||||
|
bool bActive = false;
|
||||||
|
|
||||||
|
UPROPERTY(SaveGame)
|
||||||
|
float Battery = 1.0f;
|
||||||
|
};
|
||||||
|
|
||||||
UCLASS()
|
UCLASS()
|
||||||
class NAKEDDESIRE_API USexToyInstance : public UItemInstance
|
class NAKEDDESIRE_API USexToyInstance : public UItemInstance
|
||||||
@@ -12,9 +24,15 @@ class NAKEDDESIRE_API USexToyInstance : public UItemInstance
|
|||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
USexToyItem* GetSexToyItem() const { return SexToyItem; }
|
USexToyItem* GetSexToyItem() const { return Cast<USexToyItem>(ItemDefinition); }
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
UPROPERTY()
|
virtual void CaptureState(FInstancedStruct& OutState) const override;
|
||||||
TObjectPtr<USexToyItem> SexToyItem;
|
virtual void ApplyState(const FInstancedStruct& InState) override;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadOnly, Category = "Sex Toy")
|
||||||
|
bool bActive = false;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadOnly, Category = "Sex Toy")
|
||||||
|
float Battery = 1.0f;
|
||||||
};
|
};
|
||||||
@@ -1 +1,8 @@
|
|||||||
#include "SexToyItem.h"
|
#include "SexToyItem.h"
|
||||||
|
|
||||||
|
#include "SexToyInstance.h"
|
||||||
|
|
||||||
|
TSubclassOf<UItemInstance> USexToyItem::GetInstanceClass() const
|
||||||
|
{
|
||||||
|
return USexToyInstance::StaticClass();
|
||||||
|
}
|
||||||
@@ -1,16 +1,18 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "Engine/DataAsset.h"
|
|
||||||
#include "NakedDesire/Clothing/ClothingSlotType.h"
|
#include "NakedDesire/Clothing/ClothingSlotType.h"
|
||||||
|
#include "NakedDesire/Items/ItemDefinition.h"
|
||||||
#include "SexToyItem.generated.h"
|
#include "SexToyItem.generated.h"
|
||||||
|
|
||||||
UCLASS()
|
UCLASS()
|
||||||
class NAKEDDESIRE_API USexToyItem : public UPrimaryDataAsset
|
class NAKEDDESIRE_API USexToyItem : public UItemDefinition
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
virtual TSubclassOf<UItemInstance> GetInstanceClass() const override;
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Sex Toy")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Sex Toy")
|
||||||
float LustModifier = 0.0f;
|
float LustModifier = 0.0f;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "EquipClothingRestriction.h"
|
#include "EquipClothingRestriction.h"
|
||||||
#include "NakedDesire/Clothing/ClothingItem.h"
|
#include "NakedDesire/Clothing/ClothingItemDefinition.h"
|
||||||
#include "NakedDesire/Clothing/ClothingItemInstance.h"
|
#include "NakedDesire/Clothing/ClothingItemInstance.h"
|
||||||
#include "NakedDesire/Clothing/ClothingManager.h"
|
#include "NakedDesire/Clothing/ClothingManager.h"
|
||||||
#include "NakedDesire/Player/NakedDesireCharacter.h"
|
#include "NakedDesire/Player/NakedDesireCharacter.h"
|
||||||
@@ -65,9 +65,9 @@ FText UEquipClothingRestriction::GetDescription() const
|
|||||||
|
|
||||||
void UEquipClothingRestriction::OnClothingEquipped(UClothingItemInstance* ClothingItemInstance)
|
void UEquipClothingRestriction::OnClothingEquipped(UClothingItemInstance* ClothingItemInstance)
|
||||||
{
|
{
|
||||||
const bool IsTargetClothing = ClothingItems.FindByPredicate([&ClothingItemInstance](const UClothingItem* Item)
|
const bool IsTargetClothing = ClothingItems.FindByPredicate([&ClothingItemInstance](const UClothingItemDefinition* Item)
|
||||||
{
|
{
|
||||||
return Item && Item->Name.EqualTo(ClothingItemInstance->GetClothingItem()->Name);
|
return Item && Item->Name.EqualTo(ClothingItemInstance->GetClothingItemDefinition()->Name);
|
||||||
}) != nullptr;
|
}) != nullptr;
|
||||||
if (IsTargetClothing)
|
if (IsTargetClothing)
|
||||||
{
|
{
|
||||||
@@ -77,9 +77,9 @@ void UEquipClothingRestriction::OnClothingEquipped(UClothingItemInstance* Clothi
|
|||||||
|
|
||||||
void UEquipClothingRestriction::OnClothingUnequipped(UClothingItemInstance* ClothingItemInstance)
|
void UEquipClothingRestriction::OnClothingUnequipped(UClothingItemInstance* ClothingItemInstance)
|
||||||
{
|
{
|
||||||
const bool IsTargetClothing = ClothingItems.FindByPredicate([&ClothingItemInstance](const UClothingItem* Item)
|
const bool IsTargetClothing = ClothingItems.FindByPredicate([&ClothingItemInstance](const UClothingItemDefinition* Item)
|
||||||
{
|
{
|
||||||
return Item && Item->Name.EqualTo(ClothingItemInstance->GetClothingItem()->Name);
|
return Item && Item->Name.EqualTo(ClothingItemInstance->GetClothingItemDefinition()->Name);
|
||||||
}) != nullptr;
|
}) != nullptr;
|
||||||
if (IsTargetClothing)
|
if (IsTargetClothing)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include "EquipClothingRestriction.generated.h"
|
#include "EquipClothingRestriction.generated.h"
|
||||||
|
|
||||||
class UClothingItemInstance;
|
class UClothingItemInstance;
|
||||||
class UClothingItem;
|
class UClothingItemDefinition;
|
||||||
|
|
||||||
UCLASS(EditInlineNew)
|
UCLASS(EditInlineNew)
|
||||||
class NAKEDDESIRE_API UEquipClothingRestriction : public UGoalRestriction
|
class NAKEDDESIRE_API UEquipClothingRestriction : public UGoalRestriction
|
||||||
@@ -16,7 +16,7 @@ class NAKEDDESIRE_API UEquipClothingRestriction : public UGoalRestriction
|
|||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, meta = (ToolTip =
|
UPROPERTY(EditDefaultsOnly, meta = (ToolTip =
|
||||||
"One of provided clothing items should be equipped by player. If multiple clothing items required provide multiple restrictions"))
|
"One of provided clothing items should be equipped by player. If multiple clothing items required provide multiple restrictions"))
|
||||||
TArray<UClothingItem*> ClothingItems;
|
TArray<UClothingItemDefinition*> ClothingItems;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void Init(ANakedDesireCharacter* PlayerCharacter) override;
|
virtual void Init(ANakedDesireCharacter* PlayerCharacter) override;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "ExposeBodyPartRestriction.h"
|
#include "ExposeBodyPartRestriction.h"
|
||||||
|
|
||||||
#include "NakedDesire/Clothing/ClothingItem.h"
|
#include "NakedDesire/Clothing/ClothingItemDefinition.h"
|
||||||
#include "NakedDesire/Clothing/ClothingItemInstance.h"
|
#include "NakedDesire/Clothing/ClothingItemInstance.h"
|
||||||
#include "NakedDesire/Player/NakedDesireCharacter.h"
|
#include "NakedDesire/Player/NakedDesireCharacter.h"
|
||||||
#include "NakedDesire/Clothing/ClothingManager.h"
|
#include "NakedDesire/Clothing/ClothingManager.h"
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public class NakedDesire : ModuleRules
|
|||||||
PublicDependencyModuleNames.AddRange(new string[]
|
PublicDependencyModuleNames.AddRange(new string[]
|
||||||
{
|
{
|
||||||
"Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput", "UMG", "CommonUI", "NavigationSystem",
|
"Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput", "UMG", "CommonUI", "NavigationSystem",
|
||||||
"AIModule", "GameplayTags", "Slate", "SlateCore"
|
"AIModule", "GameplayTags", "Slate", "SlateCore", "StructUtils"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,8 +9,10 @@
|
|||||||
#include "EnhancedInputSubsystems.h"
|
#include "EnhancedInputSubsystems.h"
|
||||||
#include "Kismet/GameplayStatics.h"
|
#include "Kismet/GameplayStatics.h"
|
||||||
#include "Internationalization/Text.h"
|
#include "Internationalization/Text.h"
|
||||||
#include "NakedDesire/Clothing/ClothingItem.h"
|
#include "NakedDesire/Censorship/CensorshipComponent.h"
|
||||||
|
#include "NakedDesire/Clothing/ClothingItemDefinition.h"
|
||||||
#include "NakedDesire/Clothing/ClothingItemInstance.h"
|
#include "NakedDesire/Clothing/ClothingItemInstance.h"
|
||||||
|
#include "NakedDesire/Clothing/ClothingVisualsComponent.h"
|
||||||
#include "NakedDesire/Global/Constants.h"
|
#include "NakedDesire/Global/Constants.h"
|
||||||
#include "NakedDesire/Global/NakedDesireHUD.h"
|
#include "NakedDesire/Global/NakedDesireHUD.h"
|
||||||
#include "NakedDesire/Global/NakedDesireUserSettings.h"
|
#include "NakedDesire/Global/NakedDesireUserSettings.h"
|
||||||
@@ -32,42 +34,7 @@ ANakedDesireCharacter::ANakedDesireCharacter()
|
|||||||
StatsManager = CreateDefaultSubobject<UStatsManager>("Stats Manager");
|
StatsManager = CreateDefaultSubobject<UStatsManager>("Stats Manager");
|
||||||
MissionsManager = CreateDefaultSubobject<UMissionsManager>("Missions Manager");
|
MissionsManager = CreateDefaultSubobject<UMissionsManager>("Missions Manager");
|
||||||
|
|
||||||
NipplesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Nipples");
|
ClothingVisualsComponent = CreateDefaultSubobject<UClothingVisualsComponent>(TEXT("Clothing Visuals Component"));
|
||||||
NipplesMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
AnalMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Anal");
|
|
||||||
AnalMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
VaginaMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Vagina");
|
|
||||||
VaginaMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
HeadMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Head");
|
|
||||||
HeadMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
NeckMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Neck");
|
|
||||||
NeckMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
FaceMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Face");
|
|
||||||
FaceMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
EyesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Eyes");
|
|
||||||
EyesMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
BodySuitMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Body Suit");
|
|
||||||
BodySuitMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
TopMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Top");
|
|
||||||
TopMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
BottomMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Bottom");
|
|
||||||
BottomMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
UnderwearTopMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Underwear Top");
|
|
||||||
UnderwearTopMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
UnderwearBottomMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Underwear Bottom");
|
|
||||||
UnderwearBottomMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
SocksMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Socks");
|
|
||||||
SocksMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
FootwearMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Footwear");
|
|
||||||
FootwearMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
OuterwearMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Outerwear");
|
|
||||||
OuterwearMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
WristRestraintMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Wrist Restraint");
|
|
||||||
WristRestraintMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
AnkleRestraintMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Ankle Restraint");
|
|
||||||
AnkleRestraintMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
NeckRestraintMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>("Neck Restraint");
|
|
||||||
NeckRestraintMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
|
|
||||||
BoobLCensorship = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Boob L Censorship"));
|
BoobLCensorship = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Boob L Censorship"));
|
||||||
BoobLCensorship->SetupAttachment(GetMesh(), FName(TEXT("boob_l")));
|
BoobLCensorship->SetupAttachment(GetMesh(), FName(TEXT("boob_l")));
|
||||||
@@ -78,6 +45,8 @@ ANakedDesireCharacter::ANakedDesireCharacter()
|
|||||||
AnalCensorship = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Anal Censorship"));
|
AnalCensorship = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Anal Censorship"));
|
||||||
AnalCensorship->SetupAttachment(GetMesh(), FName(TEXT("pelvis")));
|
AnalCensorship->SetupAttachment(GetMesh(), FName(TEXT("pelvis")));
|
||||||
|
|
||||||
|
CensorshipComponent = CreateDefaultSubobject<UCensorshipComponent>(TEXT("Censorship Component"));
|
||||||
|
|
||||||
StimuliSourceComponent = CreateDefaultSubobject<UAIPerceptionStimuliSourceComponent>(TEXT("Stimuli Source Component"));
|
StimuliSourceComponent = CreateDefaultSubobject<UAIPerceptionStimuliSourceComponent>(TEXT("Stimuli Source Component"));
|
||||||
InteractionComponent = CreateDefaultSubobject<UInteractionComponent>(TEXT("Interaction Component"));
|
InteractionComponent = CreateDefaultSubobject<UInteractionComponent>(TEXT("Interaction Component"));
|
||||||
}
|
}
|
||||||
@@ -153,12 +122,12 @@ void ANakedDesireCharacter::BeginPlay()
|
|||||||
StimuliSourceComponent->RegisterForSense(TSubclassOf<UAISense_Sight>());
|
StimuliSourceComponent->RegisterForSense(TSubclassOf<UAISense_Sight>());
|
||||||
StimuliSourceComponent->RegisterWithPerceptionSystem();
|
StimuliSourceComponent->RegisterWithPerceptionSystem();
|
||||||
|
|
||||||
ClothingManager->OnClothingEquip.AddUniqueDynamic(this, &ANakedDesireCharacter::OnClothingEquip);
|
// Initialize after Super::BeginPlay so clothing hydration has populated the
|
||||||
ClothingManager->OnClothingUnequip.AddUniqueDynamic(this, &ANakedDesireCharacter::OnClothingUnequip);
|
// equipped set; both components sync from that final state.
|
||||||
|
ClothingVisualsComponent->Initialize(GetMesh(), ClothingManager);
|
||||||
|
CensorshipComponent->Initialize(ClothingManager, BoobLCensorship, BoobRCensorship, VaginaCensorship, AnalCensorship);
|
||||||
|
|
||||||
HUD = Cast<ANakedDesireHUD>(UGameplayStatics::GetPlayerController(GetWorld(), 0)->GetHUD());
|
HUD = Cast<ANakedDesireHUD>(UGameplayStatics::GetPlayerController(GetWorld(), 0)->GetHUD());
|
||||||
|
|
||||||
UNakedDesireUserSettings::GetNakedDesireUserSettings()->OnSettingsChanged.AddUniqueDynamic(this, &ANakedDesireCharacter::OnSettingsChanged);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UAISense_Sight::EVisibilityResult ANakedDesireCharacter::CanBeSeenFrom(const FCanBeSeenFromContext& Context,
|
UAISense_Sight::EVisibilityResult ANakedDesireCharacter::CanBeSeenFrom(const FCanBeSeenFromContext& Context,
|
||||||
@@ -225,70 +194,6 @@ void ANakedDesireCharacter::LogTest()
|
|||||||
UE_LOG(LogTemp, Warning, TEXT("ANakedDesireCharacter::LogTest %s"), *ClothingItemInstance->GetInstanceId().ToString());
|
UE_LOG(LogTemp, Warning, TEXT("ANakedDesireCharacter::LogTest %s"), *ClothingItemInstance->GetInstanceId().ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ANakedDesireCharacter::OnClothingEquip(UClothingItemInstance* ClothingItemInstance)
|
|
||||||
{
|
|
||||||
if (ClothingItemInstance->GetClothingItem()->HiddenBodyParts.Contains(EBodyPart::Ass))
|
|
||||||
{
|
|
||||||
AnalCensorship->SetVisibility(false);
|
|
||||||
}
|
|
||||||
if (ClothingItemInstance->GetClothingItem()->HiddenBodyParts.Contains(EBodyPart::Genitals))
|
|
||||||
{
|
|
||||||
VaginaCensorship->SetVisibility(false);
|
|
||||||
}
|
|
||||||
if (ClothingItemInstance->GetClothingItem()->HiddenBodyParts.Contains(EBodyPart::Boobs))
|
|
||||||
{
|
|
||||||
BoobLCensorship->SetVisibility(false);
|
|
||||||
BoobRCensorship->SetVisibility(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ANakedDesireCharacter::OnClothingUnequip(UClothingItemInstance* ClothingItemInstance)
|
|
||||||
{
|
|
||||||
if (!UNakedDesireUserSettings::GetNakedDesireUserSettings()->GetIsCensorshipEnabled() && !IS_DEMO)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (ClothingManager->IsBodyPartExposed(EBodyPart::Ass))
|
|
||||||
{
|
|
||||||
AnalCensorship->SetVisibility(true);
|
|
||||||
}
|
|
||||||
if (ClothingManager->IsBodyPartExposed(EBodyPart::Genitals))
|
|
||||||
{
|
|
||||||
VaginaCensorship->SetVisibility(true);
|
|
||||||
}
|
|
||||||
if (ClothingManager->IsBodyPartExposed(EBodyPart::Boobs))
|
|
||||||
{
|
|
||||||
BoobLCensorship->SetVisibility(true);
|
|
||||||
BoobRCensorship->SetVisibility(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ANakedDesireCharacter::OnSettingsChanged(UNakedDesireUserSettings* Settings)
|
|
||||||
{
|
|
||||||
if (Settings->GetIsCensorshipEnabled())
|
|
||||||
{
|
|
||||||
if (ClothingManager->IsBodyPartExposed(EBodyPart::Ass))
|
|
||||||
{
|
|
||||||
AnalCensorship->SetVisibility(true);
|
|
||||||
}
|
|
||||||
if (ClothingManager->IsBodyPartExposed(EBodyPart::Genitals))
|
|
||||||
{
|
|
||||||
VaginaCensorship->SetVisibility(true);
|
|
||||||
}
|
|
||||||
if (ClothingManager->IsBodyPartExposed(EBodyPart::Boobs))
|
|
||||||
{
|
|
||||||
BoobLCensorship->SetVisibility(true);
|
|
||||||
BoobRCensorship->SetVisibility(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!IS_DEMO)
|
|
||||||
{
|
|
||||||
AnalCensorship->SetVisibility(false);
|
|
||||||
VaginaCensorship->SetVisibility(false);
|
|
||||||
BoobLCensorship->SetVisibility(false);
|
|
||||||
BoobRCensorship->SetVisibility(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ANakedDesireCharacter::OnLook(const FInputActionValue& Value)
|
void ANakedDesireCharacter::OnLook(const FInputActionValue& Value)
|
||||||
{
|
{
|
||||||
const FVector2D MouseValue = Value.Get<FVector2D>();
|
const FVector2D MouseValue = Value.Get<FVector2D>();
|
||||||
|
|||||||
@@ -14,11 +14,13 @@
|
|||||||
|
|
||||||
class UInteractionComponent;
|
class UInteractionComponent;
|
||||||
class ANakedDesireHUD;
|
class ANakedDesireHUD;
|
||||||
class UClothingItem;
|
class UClothingItemDefinition;
|
||||||
class UClothingItemInstance;
|
class UClothingItemInstance;
|
||||||
class UClothingSlotsData;
|
class UClothingSlotsData;
|
||||||
class UAIPerceptionStimuliSourceComponent;
|
class UAIPerceptionStimuliSourceComponent;
|
||||||
class UClothingManager;
|
class UClothingManager;
|
||||||
|
class UClothingVisualsComponent;
|
||||||
|
class UCensorshipComponent;
|
||||||
class UStatsManager;
|
class UStatsManager;
|
||||||
class UMissionsManager;
|
class UMissionsManager;
|
||||||
class ANPCAIController;
|
class ANPCAIController;
|
||||||
@@ -56,60 +58,9 @@ public:
|
|||||||
UPROPERTY(EditDefaultsOnly, Category = "Input")
|
UPROPERTY(EditDefaultsOnly, Category = "Input")
|
||||||
UInputAction* InteractAction;
|
UInputAction* InteractAction;
|
||||||
|
|
||||||
// Clothing
|
// Clothing slot meshes are spawned per equipped slot at runtime by ClothingVisualsComponent.
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
|
||||||
USkeletalMeshComponent* NipplesMeshComponent;
|
UClothingVisualsComponent* ClothingVisualsComponent;
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* AnalMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* VaginaMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* HeadMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* NeckMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* FaceMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* EyesMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* BodySuitMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* TopMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* BottomMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* UnderwearTopMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* UnderwearBottomMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* SocksMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* FootwearMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* OuterwearMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* WristRestraintMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* AnkleRestraintMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* NeckRestraintMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Censorship")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Censorship")
|
||||||
UStaticMeshComponent* BoobLCensorship;
|
UStaticMeshComponent* BoobLCensorship;
|
||||||
@@ -123,6 +74,9 @@ public:
|
|||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Censorship")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Censorship")
|
||||||
UStaticMeshComponent* AnalCensorship;
|
UStaticMeshComponent* AnalCensorship;
|
||||||
|
|
||||||
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Censorship")
|
||||||
|
UCensorshipComponent* CensorshipComponent;
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, Category = "Clothing")
|
UPROPERTY(EditDefaultsOnly, Category = "Clothing")
|
||||||
TObjectPtr<UClothingSlotsData> SlotsData;
|
TObjectPtr<UClothingSlotsData> SlotsData;
|
||||||
|
|
||||||
@@ -172,15 +126,6 @@ private:
|
|||||||
EGait Gait = EGait::Walk;
|
EGait Gait = EGait::Walk;
|
||||||
EStance Stance = EStance::Stand;
|
EStance Stance = EStance::Stand;
|
||||||
|
|
||||||
UFUNCTION()
|
|
||||||
void OnClothingEquip(UClothingItemInstance* ClothingItemInstance);
|
|
||||||
|
|
||||||
UFUNCTION()
|
|
||||||
void OnClothingUnequip(UClothingItemInstance* ClothingItemInstance);
|
|
||||||
|
|
||||||
UFUNCTION()
|
|
||||||
void OnSettingsChanged(UNakedDesireUserSettings* Settings);
|
|
||||||
|
|
||||||
void OnLook(const FInputActionValue& Value);
|
void OnLook(const FInputActionValue& Value);
|
||||||
void OnMove(const FInputActionValue& Value);
|
void OnMove(const FInputActionValue& Value);
|
||||||
void OnRunPress(const FInputActionValue& Value);
|
void OnRunPress(const FInputActionValue& Value);
|
||||||
|
|||||||
@@ -1,44 +1,28 @@
|
|||||||
#include "PlayerCinematic.h"
|
#include "PlayerCinematic.h"
|
||||||
|
|
||||||
#include "NakedDesireCharacter.h"
|
#include "NakedDesireCharacter.h"
|
||||||
#include "Kismet/GameplayStatics.h"
|
#include "Kismet/GameplayStatics.h"
|
||||||
#include "NakedDesire/Clothing/ClothingItem.h"
|
#include "NakedDesire/Censorship/CensorshipComponent.h"
|
||||||
#include "NakedDesire/Clothing/ClothingItemInstance.h"
|
|
||||||
#include "NakedDesire/Clothing/ClothingManager.h"
|
#include "NakedDesire/Clothing/ClothingManager.h"
|
||||||
|
#include "NakedDesire/Clothing/ClothingVisualsComponent.h"
|
||||||
|
|
||||||
|
|
||||||
// Sets default values
|
|
||||||
APlayerCinematic::APlayerCinematic()
|
APlayerCinematic::APlayerCinematic()
|
||||||
{
|
{
|
||||||
PrimaryActorTick.bCanEverTick = false;
|
PrimaryActorTick.bCanEverTick = false;
|
||||||
|
|
||||||
NipplesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Nipples"));
|
ClothingVisualsComponent = CreateDefaultSubobject<UClothingVisualsComponent>(TEXT("Clothing Visuals Component"));
|
||||||
NipplesMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
AnalMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Anal"));
|
BoobLCensorship = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Boob L Censorship"));
|
||||||
AnalMeshComponent->SetupAttachment(GetMesh());
|
BoobLCensorship->SetupAttachment(GetMesh(), FName(TEXT("boob_l")));
|
||||||
VaginaMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Vagina"));
|
BoobRCensorship = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Boob R Censorship"));
|
||||||
VaginaMeshComponent->SetupAttachment(GetMesh());
|
BoobRCensorship->SetupAttachment(GetMesh(), FName(TEXT("boob_r")));
|
||||||
HeadMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Head"));
|
VaginaCensorship = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Vagina Censorship"));
|
||||||
HeadMeshComponent->SetupAttachment(GetMesh());
|
VaginaCensorship->SetupAttachment(GetMesh(), FName(TEXT("pelvis")));
|
||||||
NeckMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Neck"));
|
AnalCensorship = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Anal Censorship"));
|
||||||
NeckMeshComponent->SetupAttachment(GetMesh());
|
AnalCensorship->SetupAttachment(GetMesh(), FName(TEXT("pelvis")));
|
||||||
FaceMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Face"));
|
|
||||||
FaceMeshComponent->SetupAttachment(GetMesh());
|
CensorshipComponent = CreateDefaultSubobject<UCensorshipComponent>(TEXT("Censorship Component"));
|
||||||
EyesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Eyes"));
|
|
||||||
EyesMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
BodyMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Body"));
|
|
||||||
BodyMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
TopMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Top"));
|
|
||||||
TopMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
BottomMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Bottom"));
|
|
||||||
BottomMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
BraMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Bra"));
|
|
||||||
BraMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
PantiesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Panties"));
|
|
||||||
PantiesMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
SocksMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Socks"));
|
|
||||||
SocksMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
ShoesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Shoes"));
|
|
||||||
ShoesMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void APlayerCinematic::BeginPlay()
|
void APlayerCinematic::BeginPlay()
|
||||||
@@ -51,83 +35,6 @@ void APlayerCinematic::BeginPlay()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player->ClothingManager->OnClothingEquip.AddUniqueDynamic(this, &APlayerCinematic::OnClothingEquip);
|
ClothingVisualsComponent->Initialize(GetMesh(), Player->ClothingManager);
|
||||||
Player->ClothingManager->OnClothingUnequip.AddUniqueDynamic(this, &APlayerCinematic::OnClothingUnequip);
|
CensorshipComponent->Initialize(Player->ClothingManager, BoobLCensorship, BoobRCensorship, VaginaCensorship, AnalCensorship);
|
||||||
|
|
||||||
for (const UClothingItemInstance* ClothingItemInstance : Player->ClothingManager->GetEquippedClothing())
|
|
||||||
{
|
|
||||||
EquipClothing(ClothingItemInstance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void APlayerCinematic::OnClothingEquip(UClothingItemInstance* ClothingItemInstance)
|
|
||||||
{
|
|
||||||
EquipClothing(ClothingItemInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
void APlayerCinematic::OnClothingUnequip(UClothingItemInstance* ClothingItemInstance)
|
|
||||||
{
|
|
||||||
UnequipClothing(ClothingItemInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
USkeletalMeshComponent* APlayerCinematic::GetMeshByType(const EClothingSlotType SlotType) const
|
|
||||||
{
|
|
||||||
switch (SlotType)
|
|
||||||
{
|
|
||||||
case EClothingSlotType::Nipples:
|
|
||||||
return NipplesMeshComponent;
|
|
||||||
case EClothingSlotType::Anal:
|
|
||||||
return AnalMeshComponent;
|
|
||||||
case EClothingSlotType::Vagina:
|
|
||||||
return VaginaMeshComponent;
|
|
||||||
case EClothingSlotType::Head:
|
|
||||||
return HeadMeshComponent;
|
|
||||||
case EClothingSlotType::Neck:
|
|
||||||
return NeckMeshComponent;
|
|
||||||
case EClothingSlotType::Face:
|
|
||||||
return FaceMeshComponent;
|
|
||||||
case EClothingSlotType::Eyes:
|
|
||||||
return EyesMeshComponent;
|
|
||||||
case EClothingSlotType::Bodysuit:
|
|
||||||
return BodyMeshComponent;
|
|
||||||
case EClothingSlotType::Top:
|
|
||||||
return TopMeshComponent;
|
|
||||||
case EClothingSlotType::Bottom:
|
|
||||||
return BottomMeshComponent;
|
|
||||||
case EClothingSlotType::UnderwearTop:
|
|
||||||
return BraMeshComponent;
|
|
||||||
case EClothingSlotType::UnderwearBottom:
|
|
||||||
return PantiesMeshComponent;
|
|
||||||
case EClothingSlotType::Socks:
|
|
||||||
return SocksMeshComponent;
|
|
||||||
case EClothingSlotType::Footwear:
|
|
||||||
return ShoesMeshComponent;
|
|
||||||
default:
|
|
||||||
return NipplesMeshComponent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void APlayerCinematic::EquipClothing(const UClothingItemInstance* ClothingItemInstance)
|
|
||||||
{
|
|
||||||
USkeletalMeshComponent* MeshComponent = GetMeshByType(ClothingItemInstance->GetClothingItem()->SlotType);
|
|
||||||
MeshComponent->SetSkeletalMesh(ClothingItemInstance->GetClothingItem()->SkeletalMesh);
|
|
||||||
if (ClothingItemInstance->GetClothingItem()->UseLeaderPose)
|
|
||||||
{
|
|
||||||
MeshComponent->SetLeaderPoseComponent(GetMesh());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ClothingItemInstance->GetClothingItem()->Materials.IsEmpty())
|
|
||||||
{
|
|
||||||
for (const TPair<FName, UMaterialInstance*>& Material : ClothingItemInstance->GetClothingItem()->Materials)
|
|
||||||
{
|
|
||||||
MeshComponent->SetMaterialByName(Material.Key, Material.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void APlayerCinematic::UnequipClothing(const UClothingItemInstance* ClothingItemInstance)
|
|
||||||
{
|
|
||||||
USkeletalMeshComponent* MeshComponent = GetMeshByType(ClothingItemInstance->GetClothingItem()->SlotType);
|
|
||||||
MeshComponent->SetSkeletalMesh(nullptr);
|
|
||||||
MeshComponent->SetLeaderPoseComponent(nullptr);
|
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "GameFramework/Character.h"
|
#include "GameFramework/Character.h"
|
||||||
#include "NakedDesire/Clothing/ClothingSlotType.h"
|
|
||||||
#include "PlayerCinematic.generated.h"
|
#include "PlayerCinematic.generated.h"
|
||||||
|
|
||||||
class UClothingItemInstance;
|
|
||||||
class ANakedDesireCharacter;
|
class ANakedDesireCharacter;
|
||||||
|
class UClothingVisualsComponent;
|
||||||
|
class UCensorshipComponent;
|
||||||
|
class UStaticMeshComponent;
|
||||||
|
|
||||||
UCLASS()
|
UCLASS()
|
||||||
class NAKEDDESIRE_API APlayerCinematic : public ACharacter
|
class NAKEDDESIRE_API APlayerCinematic : public ACharacter
|
||||||
@@ -14,46 +15,22 @@ class NAKEDDESIRE_API APlayerCinematic : public ACharacter
|
|||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
||||||
USkeletalMeshComponent* NipplesMeshComponent;
|
UClothingVisualsComponent* ClothingVisualsComponent;
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Censorship")
|
||||||
USkeletalMeshComponent* AnalMeshComponent;
|
UStaticMeshComponent* BoobLCensorship;
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Censorship")
|
||||||
USkeletalMeshComponent* VaginaMeshComponent;
|
UStaticMeshComponent* BoobRCensorship;
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Censorship")
|
||||||
USkeletalMeshComponent* HeadMeshComponent;
|
UStaticMeshComponent* VaginaCensorship;
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Censorship")
|
||||||
USkeletalMeshComponent* NeckMeshComponent;
|
UStaticMeshComponent* AnalCensorship;
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Censorship")
|
||||||
USkeletalMeshComponent* FaceMeshComponent;
|
UCensorshipComponent* CensorshipComponent;
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* EyesMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* BodyMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* TopMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* BottomMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* BraMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* PantiesMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* SocksMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* ShoesMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
ANakedDesireCharacter* Player;
|
ANakedDesireCharacter* Player;
|
||||||
@@ -62,15 +39,4 @@ public:
|
|||||||
APlayerCinematic();
|
APlayerCinematic();
|
||||||
|
|
||||||
virtual void BeginPlay() override;
|
virtual void BeginPlay() override;
|
||||||
|
|
||||||
private:
|
|
||||||
UFUNCTION()
|
|
||||||
void OnClothingEquip(UClothingItemInstance* ClothingItemInstance);
|
|
||||||
|
|
||||||
UFUNCTION()
|
|
||||||
void OnClothingUnequip(UClothingItemInstance* ClothingItemInstance);
|
|
||||||
|
|
||||||
USkeletalMeshComponent* GetMeshByType(const EClothingSlotType SlotType) const;
|
|
||||||
void EquipClothing(const UClothingItemInstance* ClothingItemInstance);
|
|
||||||
void UnequipClothing(const UClothingItemInstance* ClothingItemInstance);
|
|
||||||
};
|
};
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
#include "PlayerImpostor.h"
|
#include "PlayerImpostor.h"
|
||||||
|
|
||||||
#include "NakedDesireCharacter.h"
|
#include "NakedDesireCharacter.h"
|
||||||
#include "Kismet/GameplayStatics.h"
|
#include "Kismet/GameplayStatics.h"
|
||||||
#include "NakedDesire/Clothing/ClothingItem.h"
|
#include "NakedDesire/Censorship/CensorshipComponent.h"
|
||||||
#include "NakedDesire/Clothing/ClothingItemInstance.h"
|
|
||||||
#include "NakedDesire/Clothing/ClothingManager.h"
|
#include "NakedDesire/Clothing/ClothingManager.h"
|
||||||
|
#include "NakedDesire/Clothing/ClothingVisualsComponent.h"
|
||||||
|
|
||||||
|
|
||||||
APlayerImpostor::APlayerImpostor()
|
APlayerImpostor::APlayerImpostor()
|
||||||
@@ -16,44 +17,18 @@ APlayerImpostor::APlayerImpostor()
|
|||||||
Mesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("RootMesh"));
|
Mesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("RootMesh"));
|
||||||
Mesh->SetupAttachment(RootComponent);
|
Mesh->SetupAttachment(RootComponent);
|
||||||
|
|
||||||
NipplesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Nipples"));
|
ClothingVisualsComponent = CreateDefaultSubobject<UClothingVisualsComponent>(TEXT("Clothing Visuals Component"));
|
||||||
NipplesMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
AnalMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Anal"));
|
|
||||||
AnalMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
VaginaMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Vagina"));
|
|
||||||
VaginaMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
HeadMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Head"));
|
|
||||||
HeadMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
NeckMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Neck"));
|
|
||||||
NeckMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
FaceMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Face"));
|
|
||||||
FaceMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
EyesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Eyes"));
|
|
||||||
EyesMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
BodyMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Body"));
|
|
||||||
BodyMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
TopMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Top"));
|
|
||||||
TopMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
BottomMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Bottom"));
|
|
||||||
BottomMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
BraMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Bra"));
|
|
||||||
BraMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
PantiesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Panties"));
|
|
||||||
PantiesMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
SocksMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Socks"));
|
|
||||||
SocksMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
ShoesMeshComponent = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Shoes"));
|
|
||||||
ShoesMeshComponent->SetupAttachment(GetMesh());
|
|
||||||
}
|
|
||||||
|
|
||||||
void APlayerImpostor::OnClothingEquip(UClothingItemInstance* ClothingItemInstance)
|
BoobLCensorship = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Boob L Censorship"));
|
||||||
{
|
BoobLCensorship->SetupAttachment(GetMesh(), FName(TEXT("boob_l")));
|
||||||
EquipClothing(ClothingItemInstance);
|
BoobRCensorship = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Boob R Censorship"));
|
||||||
}
|
BoobRCensorship->SetupAttachment(GetMesh(), FName(TEXT("boob_r")));
|
||||||
|
VaginaCensorship = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Vagina Censorship"));
|
||||||
|
VaginaCensorship->SetupAttachment(GetMesh(), FName(TEXT("pelvis")));
|
||||||
|
AnalCensorship = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Anal Censorship"));
|
||||||
|
AnalCensorship->SetupAttachment(GetMesh(), FName(TEXT("pelvis")));
|
||||||
|
|
||||||
void APlayerImpostor::OnClothingUnequip(UClothingItemInstance* ClothingItemInstance)
|
CensorshipComponent = CreateDefaultSubobject<UCensorshipComponent>(TEXT("Censorship Component"));
|
||||||
{
|
|
||||||
UnequipClothing(ClothingItemInstance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void APlayerImpostor::BeginPlay()
|
void APlayerImpostor::BeginPlay()
|
||||||
@@ -66,73 +41,6 @@ void APlayerImpostor::BeginPlay()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player->ClothingManager->OnClothingEquip.AddUniqueDynamic(this, &APlayerImpostor::OnClothingEquip);
|
ClothingVisualsComponent->Initialize(GetMesh(), Player->ClothingManager);
|
||||||
Player->ClothingManager->OnClothingUnequip.AddUniqueDynamic(this, &APlayerImpostor::OnClothingUnequip);
|
CensorshipComponent->Initialize(Player->ClothingManager, BoobLCensorship, BoobRCensorship, VaginaCensorship, AnalCensorship);
|
||||||
|
|
||||||
for (const UClothingItemInstance* ClothingItemInstance : Player->ClothingManager->GetEquippedClothing())
|
|
||||||
{
|
|
||||||
EquipClothing(ClothingItemInstance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
USkeletalMeshComponent* APlayerImpostor::GetMeshByType(const EClothingSlotType SlotType) const
|
|
||||||
{
|
|
||||||
switch (SlotType)
|
|
||||||
{
|
|
||||||
case EClothingSlotType::Nipples:
|
|
||||||
return NipplesMeshComponent;
|
|
||||||
case EClothingSlotType::Anal:
|
|
||||||
return AnalMeshComponent;
|
|
||||||
case EClothingSlotType::Vagina:
|
|
||||||
return VaginaMeshComponent;
|
|
||||||
case EClothingSlotType::Head:
|
|
||||||
return HeadMeshComponent;
|
|
||||||
case EClothingSlotType::Neck:
|
|
||||||
return NeckMeshComponent;
|
|
||||||
case EClothingSlotType::Face:
|
|
||||||
return FaceMeshComponent;
|
|
||||||
case EClothingSlotType::Eyes:
|
|
||||||
return EyesMeshComponent;
|
|
||||||
case EClothingSlotType::Bodysuit:
|
|
||||||
return BodyMeshComponent;
|
|
||||||
case EClothingSlotType::Top:
|
|
||||||
return TopMeshComponent;
|
|
||||||
case EClothingSlotType::Bottom:
|
|
||||||
return BottomMeshComponent;
|
|
||||||
case EClothingSlotType::UnderwearTop:
|
|
||||||
return BraMeshComponent;
|
|
||||||
case EClothingSlotType::UnderwearBottom:
|
|
||||||
return PantiesMeshComponent;
|
|
||||||
case EClothingSlotType::Socks:
|
|
||||||
return SocksMeshComponent;
|
|
||||||
case EClothingSlotType::Footwear:
|
|
||||||
return ShoesMeshComponent;
|
|
||||||
default:
|
|
||||||
return NipplesMeshComponent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void APlayerImpostor::EquipClothing(const UClothingItemInstance* ClothingItemInstance)
|
|
||||||
{
|
|
||||||
USkeletalMeshComponent* MeshComponent = GetMeshByType(ClothingItemInstance->GetClothingItem()->SlotType);
|
|
||||||
MeshComponent->SetSkeletalMesh(ClothingItemInstance->GetClothingItem()->SkeletalMesh);
|
|
||||||
if (ClothingItemInstance->GetClothingItem()->UseLeaderPose)
|
|
||||||
{
|
|
||||||
MeshComponent->SetLeaderPoseComponent(GetMesh());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ClothingItemInstance->GetClothingItem()->Materials.IsEmpty())
|
|
||||||
{
|
|
||||||
for (const TPair<FName, UMaterialInstance*>& Material : ClothingItemInstance->GetClothingItem()->Materials)
|
|
||||||
{
|
|
||||||
MeshComponent->SetMaterialByName(Material.Key, Material.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void APlayerImpostor::UnequipClothing(const UClothingItemInstance* ClothingItemInstance)
|
|
||||||
{
|
|
||||||
USkeletalMeshComponent* MeshComponent = GetMeshByType(ClothingItemInstance->GetClothingItem()->SlotType);
|
|
||||||
MeshComponent->SetSkeletalMesh(nullptr);
|
|
||||||
MeshComponent->SetLeaderPoseComponent(nullptr);
|
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "GameFramework/Actor.h"
|
#include "GameFramework/Pawn.h"
|
||||||
#include "NakedDesire/Clothing/ClothingSlotType.h"
|
|
||||||
#include "PlayerImpostor.generated.h"
|
#include "PlayerImpostor.generated.h"
|
||||||
|
|
||||||
class UClothingItemInstance;
|
|
||||||
class ANakedDesireCharacter;
|
class ANakedDesireCharacter;
|
||||||
|
class UClothingVisualsComponent;
|
||||||
|
class UCensorshipComponent;
|
||||||
|
class UStaticMeshComponent;
|
||||||
|
|
||||||
UCLASS()
|
UCLASS()
|
||||||
class NAKEDDESIRE_API APlayerImpostor : public APawn
|
class NAKEDDESIRE_API APlayerImpostor : public APawn
|
||||||
@@ -20,46 +21,22 @@ class NAKEDDESIRE_API APlayerImpostor : public APawn
|
|||||||
USkeletalMeshComponent* Mesh;
|
USkeletalMeshComponent* Mesh;
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
||||||
USkeletalMeshComponent* NipplesMeshComponent;
|
UClothingVisualsComponent* ClothingVisualsComponent;
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Censorship")
|
||||||
USkeletalMeshComponent* AnalMeshComponent;
|
UStaticMeshComponent* BoobLCensorship;
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Censorship")
|
||||||
USkeletalMeshComponent* VaginaMeshComponent;
|
UStaticMeshComponent* BoobRCensorship;
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Censorship")
|
||||||
USkeletalMeshComponent* HeadMeshComponent;
|
UStaticMeshComponent* VaginaCensorship;
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Censorship")
|
||||||
USkeletalMeshComponent* NeckMeshComponent;
|
UStaticMeshComponent* AnalCensorship;
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Censorship")
|
||||||
USkeletalMeshComponent* FaceMeshComponent;
|
UCensorshipComponent* CensorshipComponent;
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* EyesMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* BodyMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* TopMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* BottomMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* BraMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* PantiesMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* SocksMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = true), Category = "Clothing")
|
|
||||||
USkeletalMeshComponent* ShoesMeshComponent;
|
|
||||||
|
|
||||||
UPROPERTY()
|
UPROPERTY()
|
||||||
ANakedDesireCharacter* Player;
|
ANakedDesireCharacter* Player;
|
||||||
@@ -70,14 +47,5 @@ public:
|
|||||||
virtual void BeginPlay() override;
|
virtual void BeginPlay() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UFUNCTION()
|
USkeletalMeshComponent* GetMesh() const { return Mesh; }
|
||||||
void OnClothingEquip(UClothingItemInstance* ClothingItemInstance);
|
|
||||||
|
|
||||||
UFUNCTION()
|
|
||||||
void OnClothingUnequip(UClothingItemInstance* ClothingItemInstance);
|
|
||||||
|
|
||||||
USkeletalMeshComponent* GetMesh() const { return Mesh; };
|
|
||||||
USkeletalMeshComponent* GetMeshByType(const EClothingSlotType SlotType) const;
|
|
||||||
void EquipClothing(const UClothingItemInstance* ClothingItemInstance);
|
|
||||||
void UnequipClothing(const UClothingItemInstance* ClothingItemInstance);
|
|
||||||
};
|
};
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "ItemSaveRecord.h"
|
#include "ItemSaveRecord.h"
|
||||||
#include "NakedDesire/Global/Constants.h"
|
#include "NakedDesire/Global/Constants.h"
|
||||||
|
#include "NakedDesire/Items/ItemInstance.h"
|
||||||
#include "Kismet/GameplayStatics.h"
|
#include "Kismet/GameplayStatics.h"
|
||||||
|
|
||||||
UGlobalSaveGameData* UGlobalSaveGameData::CreateNewSaveGame()
|
UGlobalSaveGameData* UGlobalSaveGameData::CreateNewSaveGame()
|
||||||
@@ -33,21 +34,20 @@ bool UGlobalSaveGameData::SaveGame(UGlobalSaveGameData* SaveGameData, const FStr
|
|||||||
return UGameplayStatics::SaveGameToSlot(SaveGameData, SlotName, SLOT_PLAYER);
|
return UGameplayStatics::SaveGameToSlot(SaveGameData, SlotName, SLOT_PLAYER);
|
||||||
}
|
}
|
||||||
|
|
||||||
FItemSaveRecord UGlobalSaveGameData::AddWardrobeItem(const UClothingItemInstance* ItemInstance)
|
FItemSaveRecord UGlobalSaveGameData::AddWardrobeItem(const UItemInstance* ItemInstance)
|
||||||
{
|
{
|
||||||
FItemSaveRecord NewSaveRecord;
|
FItemSaveRecord NewSaveRecord = ItemInstance->ToSaveRecord();
|
||||||
NewSaveRecord.Init(ItemInstance);
|
|
||||||
WardrobeItems.Push(NewSaveRecord);
|
WardrobeItems.Push(NewSaveRecord);
|
||||||
return NewSaveRecord;
|
return NewSaveRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UGlobalSaveGameData::UpdateWardrobeItem(UClothingItemInstance* ItemInstance)
|
bool UGlobalSaveGameData::UpdateWardrobeItem(UItemInstance* ItemInstance)
|
||||||
{
|
{
|
||||||
for (auto& ItemSaveRecord : WardrobeItems)
|
for (auto& ItemSaveRecord : WardrobeItems)
|
||||||
{
|
{
|
||||||
if (ItemSaveRecord.InstanceId == ItemInstance->GetInstanceId())
|
if (ItemSaveRecord.InstanceId == ItemInstance->GetInstanceId())
|
||||||
{
|
{
|
||||||
ItemSaveRecord.Init(ItemInstance);
|
ItemSaveRecord = ItemInstance->ToSaveRecord();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,7 +55,7 @@ bool UGlobalSaveGameData::UpdateWardrobeItem(UClothingItemInstance* ItemInstance
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UGlobalSaveGameData::RemoveWardrobeItem(UClothingItemInstance* ItemInstance)
|
bool UGlobalSaveGameData::RemoveWardrobeItem(UItemInstance* ItemInstance)
|
||||||
{
|
{
|
||||||
const int32 RemovedElementsCount = WardrobeItems.RemoveAll([ItemInstance](const FItemSaveRecord& Item)
|
const int32 RemovedElementsCount = WardrobeItems.RemoveAll([ItemInstance](const FItemSaveRecord& Item)
|
||||||
{
|
{
|
||||||
@@ -65,21 +65,25 @@ bool UGlobalSaveGameData::RemoveWardrobeItem(UClothingItemInstance* ItemInstance
|
|||||||
return RemovedElementsCount > 0;
|
return RemovedElementsCount > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FItemSaveRecord UGlobalSaveGameData::AddEquippedItem(const UClothingItemInstance* ItemInstance)
|
FItemSaveRecord UGlobalSaveGameData::AddEquippedItem(const UItemInstance* ItemInstance)
|
||||||
{
|
{
|
||||||
FItemSaveRecord NewSaveRecord;
|
FItemSaveRecord NewSaveRecord = ItemInstance->ToSaveRecord();
|
||||||
NewSaveRecord.Init(ItemInstance);
|
|
||||||
EquippedItems.Push(NewSaveRecord);
|
EquippedItems.Push(NewSaveRecord);
|
||||||
return NewSaveRecord;
|
return NewSaveRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UGlobalSaveGameData::UpdateEquippedItem(UClothingItemInstance* ItemInstance)
|
void UGlobalSaveGameData::AddEquippedItem(const FItemSaveRecord& ItemRecord)
|
||||||
|
{
|
||||||
|
EquippedItems.Push(ItemRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UGlobalSaveGameData::UpdateEquippedItem(UItemInstance* ItemInstance)
|
||||||
{
|
{
|
||||||
for (auto& ItemSaveRecord : EquippedItems)
|
for (auto& ItemSaveRecord : EquippedItems)
|
||||||
{
|
{
|
||||||
if (ItemSaveRecord.InstanceId == ItemInstance->GetInstanceId())
|
if (ItemSaveRecord.InstanceId == ItemInstance->GetInstanceId())
|
||||||
{
|
{
|
||||||
ItemSaveRecord.Init(ItemInstance);
|
ItemSaveRecord = ItemInstance->ToSaveRecord();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,7 +91,7 @@ bool UGlobalSaveGameData::UpdateEquippedItem(UClothingItemInstance* ItemInstance
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UGlobalSaveGameData::RemoveEquippedItem(UClothingItemInstance* ItemInstance)
|
bool UGlobalSaveGameData::RemoveEquippedItem(UItemInstance* ItemInstance)
|
||||||
{
|
{
|
||||||
const int32 RemovedElementsCount = EquippedItems.RemoveAll([ItemInstance](const FItemSaveRecord& Item)
|
const int32 RemovedElementsCount = EquippedItems.RemoveAll([ItemInstance](const FItemSaveRecord& Item)
|
||||||
{
|
{
|
||||||
@@ -97,22 +101,21 @@ bool UGlobalSaveGameData::RemoveEquippedItem(UClothingItemInstance* ItemInstance
|
|||||||
return RemovedElementsCount > 0;
|
return RemovedElementsCount > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FItemSaveRecord UGlobalSaveGameData::AddWorldItem(const UClothingItemInstance* ItemInstance, FTransform Transform)
|
FItemSaveRecord UGlobalSaveGameData::AddWorldItem(const UItemInstance* ItemInstance, FTransform Transform)
|
||||||
{
|
{
|
||||||
FItemSaveRecord NewSaveRecord;
|
FItemSaveRecord NewSaveRecord = ItemInstance->ToSaveRecord();
|
||||||
NewSaveRecord.Init(ItemInstance);
|
|
||||||
NewSaveRecord.WorldTransform = Transform;
|
NewSaveRecord.WorldTransform = Transform;
|
||||||
WorldItems.Push(NewSaveRecord);
|
WorldItems.Push(NewSaveRecord);
|
||||||
return NewSaveRecord;
|
return NewSaveRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UGlobalSaveGameData::UpdateWorldItem(UClothingItemInstance* ItemInstance, FTransform Transform)
|
bool UGlobalSaveGameData::UpdateWorldItem(UItemInstance* ItemInstance, FTransform Transform)
|
||||||
{
|
{
|
||||||
for (auto& ItemSaveRecord : WorldItems)
|
for (auto& ItemSaveRecord : WorldItems)
|
||||||
{
|
{
|
||||||
if (ItemSaveRecord.InstanceId == ItemInstance->GetInstanceId())
|
if (ItemSaveRecord.InstanceId == ItemInstance->GetInstanceId())
|
||||||
{
|
{
|
||||||
ItemSaveRecord.Init(ItemInstance);
|
ItemSaveRecord = ItemInstance->ToSaveRecord();
|
||||||
ItemSaveRecord.WorldTransform = Transform;
|
ItemSaveRecord.WorldTransform = Transform;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -121,7 +124,7 @@ bool UGlobalSaveGameData::UpdateWorldItem(UClothingItemInstance* ItemInstance, F
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UGlobalSaveGameData::RemoveWorldItem(UClothingItemInstance* ItemInstance)
|
bool UGlobalSaveGameData::RemoveWorldItem(UItemInstance* ItemInstance)
|
||||||
{
|
{
|
||||||
const int32 RemovedElementsCount = WorldItems.RemoveAll([ItemInstance](const FItemSaveRecord& Item)
|
const int32 RemovedElementsCount = WorldItems.RemoveAll([ItemInstance](const FItemSaveRecord& Item)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#include "ItemSaveRecord.h"
|
#include "ItemSaveRecord.h"
|
||||||
#include "GlobalSaveGameData.generated.h"
|
#include "GlobalSaveGameData.generated.h"
|
||||||
|
|
||||||
class UClothingItemInstance;
|
class UItemInstance;
|
||||||
|
|
||||||
UCLASS()
|
UCLASS()
|
||||||
class NAKEDDESIRE_API UGlobalSaveGameData : public USaveGame
|
class NAKEDDESIRE_API UGlobalSaveGameData : public USaveGame
|
||||||
@@ -26,19 +26,20 @@ public:
|
|||||||
UPROPERTY(SaveGame)
|
UPROPERTY(SaveGame)
|
||||||
float Money = 0;
|
float Money = 0;
|
||||||
|
|
||||||
FItemSaveRecord AddWardrobeItem(const UClothingItemInstance* ItemInstance);
|
FItemSaveRecord AddWardrobeItem(const UItemInstance* ItemInstance);
|
||||||
bool UpdateWardrobeItem(UClothingItemInstance* ItemInstance);
|
bool UpdateWardrobeItem(UItemInstance* ItemInstance);
|
||||||
bool RemoveWardrobeItem(UClothingItemInstance* ItemInstance);
|
bool RemoveWardrobeItem(UItemInstance* ItemInstance);
|
||||||
TArray<FItemSaveRecord> GetWardrobeItems() const { return WardrobeItems; }
|
TArray<FItemSaveRecord> GetWardrobeItems() const { return WardrobeItems; }
|
||||||
|
|
||||||
FItemSaveRecord AddEquippedItem(const UClothingItemInstance* ItemInstance);
|
FItemSaveRecord AddEquippedItem(const UItemInstance* ItemInstance);
|
||||||
bool UpdateEquippedItem(UClothingItemInstance* ItemInstance);
|
void AddEquippedItem(const FItemSaveRecord& ItemRecord);
|
||||||
bool RemoveEquippedItem(UClothingItemInstance* ItemInstance);
|
bool UpdateEquippedItem(UItemInstance* ItemInstance);
|
||||||
|
bool RemoveEquippedItem(UItemInstance* ItemInstance);
|
||||||
TArray<FItemSaveRecord> GetEquippedItems() const { return EquippedItems; }
|
TArray<FItemSaveRecord> GetEquippedItems() const { return EquippedItems; }
|
||||||
|
|
||||||
FItemSaveRecord AddWorldItem(const UClothingItemInstance* ItemInstance, FTransform Transform);
|
FItemSaveRecord AddWorldItem(const UItemInstance* ItemInstance, FTransform Transform);
|
||||||
bool UpdateWorldItem(UClothingItemInstance* ItemInstance, FTransform Transform);
|
bool UpdateWorldItem(UItemInstance* ItemInstance, FTransform Transform);
|
||||||
bool RemoveWorldItem(UClothingItemInstance* ItemInstance);
|
bool RemoveWorldItem(UItemInstance* ItemInstance);
|
||||||
TArray<FItemSaveRecord> GetWorldItems() const { return WorldItems; }
|
TArray<FItemSaveRecord> GetWorldItems() const { return WorldItems; }
|
||||||
|
|
||||||
UPROPERTY(SaveGame)
|
UPROPERTY(SaveGame)
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
|
// © 2025 Naked People Team. All Rights Reserved.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "CoreMinimal.h"
|
#include "CoreMinimal.h"
|
||||||
#include "NakedDesire/Clothing/ClothingItemInstance.h"
|
#include "StructUtils/InstancedStruct.h"
|
||||||
#include "NakedDesire/Clothing/ClothingItem.h"
|
|
||||||
#include "ItemSaveRecord.generated.h"
|
#include "ItemSaveRecord.generated.h"
|
||||||
|
|
||||||
class UClothingItemInstance;
|
class UItemDefinition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type-agnostic save record for any UItemInstance.
|
||||||
|
* Per-type mutable state lives in State as an FItemInstanceState subclass
|
||||||
|
* (e.g. FClothingInstanceState), so new item types add no fields here.
|
||||||
|
*/
|
||||||
USTRUCT()
|
USTRUCT()
|
||||||
struct NAKEDDESIRE_API FItemSaveRecord
|
struct NAKEDDESIRE_API FItemSaveRecord
|
||||||
{
|
{
|
||||||
@@ -16,23 +22,14 @@ struct NAKEDDESIRE_API FItemSaveRecord
|
|||||||
FGuid InstanceId;
|
FGuid InstanceId;
|
||||||
|
|
||||||
UPROPERTY(SaveGame)
|
UPROPERTY(SaveGame)
|
||||||
TSoftObjectPtr<UClothingItem> Definition;
|
TSoftObjectPtr<UItemDefinition> Definition;
|
||||||
|
|
||||||
UPROPERTY(SaveGame)
|
UPROPERTY(SaveGame)
|
||||||
float Condition = 1.0f;
|
FInstancedStruct State;
|
||||||
|
|
||||||
UPROPERTY(SaveGame)
|
UPROPERTY(SaveGame)
|
||||||
FGuid ParentId;
|
FGuid ParentId;
|
||||||
|
|
||||||
UPROPERTY(SaveGame)
|
UPROPERTY(SaveGame)
|
||||||
FTransform WorldTransform;
|
FTransform WorldTransform;
|
||||||
|
|
||||||
void Init(const UClothingItemInstance* ClothingItemInstance);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void FItemSaveRecord::Init(const UClothingItemInstance* ClothingItemInstance)
|
|
||||||
{
|
|
||||||
InstanceId = ClothingItemInstance->GetInstanceId();
|
|
||||||
Definition = ClothingItemInstance->GetClothingItem();
|
|
||||||
Condition = ClothingItemInstance->Condition;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
#include "GlobalSaveGameData.h"
|
#include "GlobalSaveGameData.h"
|
||||||
#include "ItemSaveRecord.h"
|
#include "ItemSaveRecord.h"
|
||||||
#include "StartingSaveData.h"
|
#include "StartingSaveData.h"
|
||||||
#include "NakedDesire/Clothing/ClothingItem.h"
|
#include "NakedDesire/Items/ItemDefinition.h"
|
||||||
#include "NakedDesire/Clothing/ClothingItemInstance.h"
|
#include "NakedDesire/Items/ItemInstance.h"
|
||||||
#include "NakedDesire/Global/NakedDesireGameInstance.h"
|
#include "NakedDesire/Global/NakedDesireGameInstance.h"
|
||||||
|
|
||||||
void USaveSubsystem::LoadGame(const FString& SlotName)
|
void USaveSubsystem::LoadGame(const FString& SlotName)
|
||||||
@@ -62,14 +62,15 @@ void USaveSubsystem::PopulateStartingData(UGlobalSaveGameData* Save) const
|
|||||||
if (!GameInstance || !GameInstance->StartingSaveData)
|
if (!GameInstance || !GameInstance->StartingSaveData)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (UClothingItem* ClothingDef : GameInstance->StartingSaveData->StartingClothing)
|
for (UItemDefinition* Definition : GameInstance->StartingSaveData->StartingItems)
|
||||||
{
|
{
|
||||||
if (!ClothingDef)
|
if (!Definition)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
UItemInstance* Instance = Definition->CreateInstance(Save);
|
||||||
|
if (!Instance)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// TODO: Refactor. Skip converting to ClothingItemInstance
|
|
||||||
UClothingItemInstance* Instance = NewObject<UClothingItemInstance>(Save);
|
|
||||||
Instance->Init(ClothingDef);
|
|
||||||
Save->AddEquippedItem(Instance);
|
Save->AddEquippedItem(Instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#include "Engine/DataAsset.h"
|
#include "Engine/DataAsset.h"
|
||||||
#include "StartingSaveData.generated.h"
|
#include "StartingSaveData.generated.h"
|
||||||
|
|
||||||
class UClothingItem;
|
class UItemDefinition;
|
||||||
|
|
||||||
UCLASS()
|
UCLASS()
|
||||||
class NAKEDDESIRE_API UStartingSaveData : public UPrimaryDataAsset
|
class NAKEDDESIRE_API UStartingSaveData : public UPrimaryDataAsset
|
||||||
@@ -15,5 +15,5 @@ class NAKEDDESIRE_API UStartingSaveData : public UPrimaryDataAsset
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
UPROPERTY(EditDefaultsOnly, Category = "Starting State")
|
UPROPERTY(EditDefaultsOnly, Category = "Starting State")
|
||||||
TArray<TObjectPtr<UClothingItem>> StartingClothing;
|
TArray<TObjectPtr<UItemDefinition>> StartingItems;
|
||||||
};
|
};
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "EquipmentSlotWidget.h"
|
#include "EquipmentSlotWidget.h"
|
||||||
#include "Kismet/GameplayStatics.h"
|
#include "Kismet/GameplayStatics.h"
|
||||||
#include "NakedDesire/Clothing/ClothingItem.h"
|
#include "NakedDesire/Clothing/ClothingItemDefinition.h"
|
||||||
#include "NakedDesire/Clothing/ClothingItemInstance.h"
|
#include "NakedDesire/Clothing/ClothingItemInstance.h"
|
||||||
#include "NakedDesire/Clothing/ClothingManager.h"
|
#include "NakedDesire/Clothing/ClothingManager.h"
|
||||||
#include "NakedDesire/Clothing/ClothingSlotsData.h"
|
#include "NakedDesire/Clothing/ClothingSlotsData.h"
|
||||||
@@ -13,7 +13,7 @@ void UEquipmentSlotWidget::SetItem(UClothingItemInstance* InItem)
|
|||||||
{
|
{
|
||||||
ClothingItemInstance = InItem;
|
ClothingItemInstance = InItem;
|
||||||
|
|
||||||
IconImage->SetBrushFromTexture(InItem->GetClothingItem()->Icon);
|
IconImage->SetBrushFromTexture(InItem->GetClothingItemDefinition()->Icon);
|
||||||
IconImage->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
|
IconImage->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
|
||||||
PlaceholderImage->SetVisibility(ESlateVisibility::Hidden);
|
PlaceholderImage->SetVisibility(ESlateVisibility::Hidden);
|
||||||
SetIsEnabled(true);
|
SetIsEnabled(true);
|
||||||
@@ -45,7 +45,7 @@ void UEquipmentSlotWidget::NativePreConstruct()
|
|||||||
|
|
||||||
void UEquipmentSlotWidget::OnClothingEquip(UClothingItemInstance* InClothingItemInstance)
|
void UEquipmentSlotWidget::OnClothingEquip(UClothingItemInstance* InClothingItemInstance)
|
||||||
{
|
{
|
||||||
if (InClothingItemInstance->GetClothingItem()->SlotType != SlotType)
|
if (InClothingItemInstance->GetClothingItemDefinition()->SlotType != SlotType)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SetItem(InClothingItemInstance);
|
SetItem(InClothingItemInstance);
|
||||||
@@ -53,7 +53,7 @@ void UEquipmentSlotWidget::OnClothingEquip(UClothingItemInstance* InClothingItem
|
|||||||
|
|
||||||
void UEquipmentSlotWidget::OnClothingUnequip(UClothingItemInstance* InClothingItemInstance)
|
void UEquipmentSlotWidget::OnClothingUnequip(UClothingItemInstance* InClothingItemInstance)
|
||||||
{
|
{
|
||||||
if (InClothingItemInstance->GetClothingItem()->SlotType != SlotType)
|
if (InClothingItemInstance->GetClothingItemDefinition()->SlotType != SlotType)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ClearItem();
|
ClearItem();
|
||||||
|
|||||||
Reference in New Issue
Block a user