Refactor censorship

This commit is contained in:
2026-05-29 22:27:32 +03:00
parent cfecd1f4c6
commit 4405324095
4 changed files with 170 additions and 78 deletions
@@ -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;
};
@@ -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<UStaticMeshComponent>(TEXT("Anal Censorship"));
AnalCensorship->SetupAttachment(GetMesh(), FName(TEXT("pelvis")));
CensorshipComponent = CreateDefaultSubobject<UCensorshipComponent>(TEXT("Censorship Component"));
StimuliSourceComponent = CreateDefaultSubobject<UAIPerceptionStimuliSourceComponent>(TEXT("Stimuli Source Component"));
InteractionComponent = CreateDefaultSubobject<UInteractionComponent>(TEXT("Interaction Component"));
}
@@ -153,12 +156,11 @@ void ANakedDesireCharacter::BeginPlay()
StimuliSourceComponent->RegisterForSense(TSubclassOf<UAISense_Sight>());
StimuliSourceComponent->RegisterWithPerceptionSystem();
ClothingManager->OnClothingEquip.AddUniqueDynamic(this, &ANakedDesireCharacter::OnClothingEquip);
ClothingManager->OnClothingUnequip.AddUniqueDynamic(this, &ANakedDesireCharacter::OnClothingUnequip);
HUD = Cast<ANakedDesireHUD>(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<ANakedDesireHUD>(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<FVector2D>();
@@ -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<UClothingSlotsData> 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);