Clothing system refactor
This commit is contained in:
@@ -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,9 +1,13 @@
|
||||
#include "ItemInstance.h"
|
||||
|
||||
#include "ItemDefinition.h"
|
||||
#include "StructUtils/InstancedStruct.h"
|
||||
#include "NakedDesire/SaveGame/ItemSaveRecord.h"
|
||||
|
||||
void UItemInstance::PostInitProperties()
|
||||
{
|
||||
Super::PostInitProperties();
|
||||
|
||||
|
||||
if (HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject | RF_NeedLoad))
|
||||
return;
|
||||
if (!InstanceId.IsValid())
|
||||
@@ -20,3 +24,37 @@ void UItemInstance::SetInstanceId(FGuid 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,19 +4,55 @@
|
||||
#include "UObject/Object.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)
|
||||
class NAKEDDESIRE_API UItemInstance : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
|
||||
public:
|
||||
virtual void PostInitProperties() override;
|
||||
virtual void PostDuplicate(EDuplicateMode::Type DuplicateMode) override;
|
||||
|
||||
FGuid GetInstanceId() const { return InstanceId; }
|
||||
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:
|
||||
/** 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"))
|
||||
FGuid InstanceId;
|
||||
};
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UItemDefinition> ItemDefinition;
|
||||
};
|
||||
@@ -1 +1,20 @@
|
||||
#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,19 +2,37 @@
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "ItemInstance.h"
|
||||
#include "SexToyItem.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()
|
||||
class NAKEDDESIRE_API USexToyInstance : public UItemInstance
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
|
||||
public:
|
||||
USexToyItem* GetSexToyItem() const { return SexToyItem; }
|
||||
|
||||
private:
|
||||
UPROPERTY()
|
||||
TObjectPtr<USexToyItem> SexToyItem;
|
||||
};
|
||||
USexToyItem* GetSexToyItem() const { return Cast<USexToyItem>(ItemDefinition); }
|
||||
|
||||
protected:
|
||||
virtual void CaptureState(FInstancedStruct& OutState) const override;
|
||||
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 "SexToyInstance.h"
|
||||
|
||||
TSubclassOf<UItemInstance> USexToyItem::GetInstanceClass() const
|
||||
{
|
||||
return USexToyInstance::StaticClass();
|
||||
}
|
||||
@@ -1,16 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Engine/DataAsset.h"
|
||||
#include "NakedDesire/Clothing/ClothingSlotType.h"
|
||||
#include "NakedDesire/Items/ItemDefinition.h"
|
||||
#include "SexToyItem.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class NAKEDDESIRE_API USexToyItem : public UPrimaryDataAsset
|
||||
class NAKEDDESIRE_API USexToyItem : public UItemDefinition
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
|
||||
public:
|
||||
virtual TSubclassOf<UItemInstance> GetInstanceClass() const override;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Sex Toy")
|
||||
float LustModifier = 0.0f;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user