From 0cccb12b7229e5101d7a5a3012b9faf780583230 Mon Sep 17 00:00:00 2001 From: olehhapuk Date: Fri, 29 May 2026 22:27:32 +0300 Subject: [PATCH] Refactor censorship --- .../Censorship/CensorshipComponent.cpp | 93 +++++++++++++++++++ .../Censorship/CensorshipComponent.h | 66 +++++++++++++ .../Player/NakedDesireCharacter.cpp | 76 ++------------- .../NakedDesire/Player/NakedDesireCharacter.h | 13 +-- 4 files changed, 170 insertions(+), 78 deletions(-) create mode 100644 Source/NakedDesire/Censorship/CensorshipComponent.cpp create mode 100644 Source/NakedDesire/Censorship/CensorshipComponent.h diff --git a/Source/NakedDesire/Censorship/CensorshipComponent.cpp b/Source/NakedDesire/Censorship/CensorshipComponent.cpp new file mode 100644 index 00000000..3ea0afb5 --- /dev/null +++ b/Source/NakedDesire/Censorship/CensorshipComponent.cpp @@ -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; + } +} \ No newline at end of file diff --git a/Source/NakedDesire/Censorship/CensorshipComponent.h b/Source/NakedDesire/Censorship/CensorshipComponent.h new file mode 100644 index 00000000..c2ada8ad --- /dev/null +++ b/Source/NakedDesire/Censorship/CensorshipComponent.h @@ -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 ClothingManager; + + UPROPERTY() + TObjectPtr BoobLCensorship; + + UPROPERTY() + TObjectPtr BoobRCensorship; + + UPROPERTY() + TObjectPtr VaginaCensorship; + + UPROPERTY() + TObjectPtr AnalCensorship; +}; \ No newline at end of file diff --git a/Source/NakedDesire/Player/NakedDesireCharacter.cpp b/Source/NakedDesire/Player/NakedDesireCharacter.cpp index 75c2dbd7..6d368d11 100644 --- a/Source/NakedDesire/Player/NakedDesireCharacter.cpp +++ b/Source/NakedDesire/Player/NakedDesireCharacter.cpp @@ -9,6 +9,7 @@ #include "EnhancedInputSubsystems.h" #include "Kismet/GameplayStatics.h" #include "Internationalization/Text.h" +#include "NakedDesire/Censorship/CensorshipComponent.h" #include "NakedDesire/Clothing/ClothingItemDefinition.h" #include "NakedDesire/Clothing/ClothingItemInstance.h" #include "NakedDesire/Global/Constants.h" @@ -78,6 +79,8 @@ ANakedDesireCharacter::ANakedDesireCharacter() AnalCensorship = CreateDefaultSubobject(TEXT("Anal Censorship")); AnalCensorship->SetupAttachment(GetMesh(), FName(TEXT("pelvis"))); + CensorshipComponent = CreateDefaultSubobject(TEXT("Censorship Component")); + StimuliSourceComponent = CreateDefaultSubobject(TEXT("Stimuli Source Component")); InteractionComponent = CreateDefaultSubobject(TEXT("Interaction Component")); } @@ -153,12 +156,11 @@ void ANakedDesireCharacter::BeginPlay() StimuliSourceComponent->RegisterForSense(TSubclassOf()); StimuliSourceComponent->RegisterWithPerceptionSystem(); - ClothingManager->OnClothingEquip.AddUniqueDynamic(this, &ANakedDesireCharacter::OnClothingEquip); - ClothingManager->OnClothingUnequip.AddUniqueDynamic(this, &ANakedDesireCharacter::OnClothingUnequip); - - HUD = Cast(UGameplayStatics::GetPlayerController(GetWorld(), 0)->GetHUD()); + // Initialize after Super::BeginPlay so clothing hydration has populated the + // equipped set; the component recomputes censorship from that final state. + CensorshipComponent->Initialize(ClothingManager, BoobLCensorship, BoobRCensorship, VaginaCensorship, AnalCensorship); - UNakedDesireUserSettings::GetNakedDesireUserSettings()->OnSettingsChanged.AddUniqueDynamic(this, &ANakedDesireCharacter::OnSettingsChanged); + HUD = Cast(UGameplayStatics::GetPlayerController(GetWorld(), 0)->GetHUD()); } UAISense_Sight::EVisibilityResult ANakedDesireCharacter::CanBeSeenFrom(const FCanBeSeenFromContext& Context, @@ -225,70 +227,6 @@ void ANakedDesireCharacter::LogTest() UE_LOG(LogTemp, Warning, TEXT("ANakedDesireCharacter::LogTest %s"), *ClothingItemInstance->GetInstanceId().ToString()); } -void ANakedDesireCharacter::OnClothingEquip(UClothingItemInstance* ClothingItemInstance) -{ - if (ClothingItemInstance->GetClothingItemDefinition()->HiddenBodyParts.Contains(EBodyPart::Ass)) - { - AnalCensorship->SetVisibility(false); - } - if (ClothingItemInstance->GetClothingItemDefinition()->HiddenBodyParts.Contains(EBodyPart::Genitals)) - { - VaginaCensorship->SetVisibility(false); - } - if (ClothingItemInstance->GetClothingItemDefinition()->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) { const FVector2D MouseValue = Value.Get(); diff --git a/Source/NakedDesire/Player/NakedDesireCharacter.h b/Source/NakedDesire/Player/NakedDesireCharacter.h index 2412beb1..6524a239 100644 --- a/Source/NakedDesire/Player/NakedDesireCharacter.h +++ b/Source/NakedDesire/Player/NakedDesireCharacter.h @@ -19,6 +19,7 @@ class UClothingItemInstance; class UClothingSlotsData; class UAIPerceptionStimuliSourceComponent; class UClothingManager; +class UCensorshipComponent; class UStatsManager; class UMissionsManager; class ANPCAIController; @@ -123,6 +124,9 @@ public: UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Censorship") UStaticMeshComponent* AnalCensorship; + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Censorship") + UCensorshipComponent* CensorshipComponent; + UPROPERTY(EditDefaultsOnly, Category = "Clothing") TObjectPtr SlotsData; @@ -172,15 +176,6 @@ private: EGait Gait = EGait::Walk; 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 OnMove(const FInputActionValue& Value); void OnRunPress(const FInputActionValue& Value);