Clothing system refactor

This commit is contained in:
2026-05-29 22:13:09 +03:00
parent 6e44e9d4e8
commit fbca5dd1c0
59 changed files with 417 additions and 227 deletions
@@ -5,6 +5,7 @@
#include "ItemSaveRecord.h"
#include "NakedDesire/Global/Constants.h"
#include "NakedDesire/Items/ItemInstance.h"
#include "Kismet/GameplayStatics.h"
UGlobalSaveGameData* UGlobalSaveGameData::CreateNewSaveGame()
@@ -33,100 +34,102 @@ bool UGlobalSaveGameData::SaveGame(UGlobalSaveGameData* SaveGameData, const FStr
return UGameplayStatics::SaveGameToSlot(SaveGameData, SlotName, SLOT_PLAYER);
}
FItemSaveRecord UGlobalSaveGameData::AddWardrobeItem(const UClothingItemInstance* ItemInstance)
FItemSaveRecord UGlobalSaveGameData::AddWardrobeItem(const UItemInstance* ItemInstance)
{
FItemSaveRecord NewSaveRecord;
NewSaveRecord.Init(ItemInstance);
FItemSaveRecord NewSaveRecord = ItemInstance->ToSaveRecord();
WardrobeItems.Push(NewSaveRecord);
return NewSaveRecord;
}
bool UGlobalSaveGameData::UpdateWardrobeItem(UClothingItemInstance* ItemInstance)
bool UGlobalSaveGameData::UpdateWardrobeItem(UItemInstance* ItemInstance)
{
for (auto& ItemSaveRecord : WardrobeItems)
{
if (ItemSaveRecord.InstanceId == ItemInstance->GetInstanceId())
{
ItemSaveRecord.Init(ItemInstance);
ItemSaveRecord = ItemInstance->ToSaveRecord();
return true;
}
}
return false;
}
bool UGlobalSaveGameData::RemoveWardrobeItem(UClothingItemInstance* ItemInstance)
bool UGlobalSaveGameData::RemoveWardrobeItem(UItemInstance* ItemInstance)
{
const int32 RemovedElementsCount = WardrobeItems.RemoveAll([ItemInstance](const FItemSaveRecord& Item)
{
return Item.InstanceId == ItemInstance->GetInstanceId();
});
return RemovedElementsCount > 0;
}
FItemSaveRecord UGlobalSaveGameData::AddEquippedItem(const UClothingItemInstance* ItemInstance)
FItemSaveRecord UGlobalSaveGameData::AddEquippedItem(const UItemInstance* ItemInstance)
{
FItemSaveRecord NewSaveRecord;
NewSaveRecord.Init(ItemInstance);
FItemSaveRecord NewSaveRecord = ItemInstance->ToSaveRecord();
EquippedItems.Push(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)
{
if (ItemSaveRecord.InstanceId == ItemInstance->GetInstanceId())
{
ItemSaveRecord.Init(ItemInstance);
ItemSaveRecord = ItemInstance->ToSaveRecord();
return true;
}
}
return false;
}
bool UGlobalSaveGameData::RemoveEquippedItem(UClothingItemInstance* ItemInstance)
bool UGlobalSaveGameData::RemoveEquippedItem(UItemInstance* ItemInstance)
{
const int32 RemovedElementsCount = EquippedItems.RemoveAll([ItemInstance](const FItemSaveRecord& Item)
{
return Item.InstanceId == ItemInstance->GetInstanceId();
});
return RemovedElementsCount > 0;
}
FItemSaveRecord UGlobalSaveGameData::AddWorldItem(const UClothingItemInstance* ItemInstance, FTransform Transform)
FItemSaveRecord UGlobalSaveGameData::AddWorldItem(const UItemInstance* ItemInstance, FTransform Transform)
{
FItemSaveRecord NewSaveRecord;
NewSaveRecord.Init(ItemInstance);
FItemSaveRecord NewSaveRecord = ItemInstance->ToSaveRecord();
NewSaveRecord.WorldTransform = Transform;
WorldItems.Push(NewSaveRecord);
return NewSaveRecord;
}
bool UGlobalSaveGameData::UpdateWorldItem(UClothingItemInstance* ItemInstance, FTransform Transform)
bool UGlobalSaveGameData::UpdateWorldItem(UItemInstance* ItemInstance, FTransform Transform)
{
for (auto& ItemSaveRecord : WorldItems)
{
if (ItemSaveRecord.InstanceId == ItemInstance->GetInstanceId())
{
ItemSaveRecord.Init(ItemInstance);
ItemSaveRecord = ItemInstance->ToSaveRecord();
ItemSaveRecord.WorldTransform = Transform;
return true;
}
}
return false;
}
bool UGlobalSaveGameData::RemoveWorldItem(UClothingItemInstance* ItemInstance)
bool UGlobalSaveGameData::RemoveWorldItem(UItemInstance* ItemInstance)
{
const int32 RemovedElementsCount = WorldItems.RemoveAll([ItemInstance](const FItemSaveRecord& Item)
{
return Item.InstanceId == ItemInstance->GetInstanceId();
});
return RemovedElementsCount > 0;
}
}
@@ -8,7 +8,7 @@
#include "ItemSaveRecord.h"
#include "GlobalSaveGameData.generated.h"
class UClothingItemInstance;
class UItemInstance;
UCLASS()
class NAKEDDESIRE_API UGlobalSaveGameData : public USaveGame
@@ -26,19 +26,20 @@ public:
UPROPERTY(SaveGame)
float Money = 0;
FItemSaveRecord AddWardrobeItem(const UClothingItemInstance* ItemInstance);
bool UpdateWardrobeItem(UClothingItemInstance* ItemInstance);
bool RemoveWardrobeItem(UClothingItemInstance* ItemInstance);
FItemSaveRecord AddWardrobeItem(const UItemInstance* ItemInstance);
bool UpdateWardrobeItem(UItemInstance* ItemInstance);
bool RemoveWardrobeItem(UItemInstance* ItemInstance);
TArray<FItemSaveRecord> GetWardrobeItems() const { return WardrobeItems; }
FItemSaveRecord AddEquippedItem(const UClothingItemInstance* ItemInstance);
bool UpdateEquippedItem(UClothingItemInstance* ItemInstance);
bool RemoveEquippedItem(UClothingItemInstance* ItemInstance);
FItemSaveRecord AddEquippedItem(const UItemInstance* ItemInstance);
void AddEquippedItem(const FItemSaveRecord& ItemRecord);
bool UpdateEquippedItem(UItemInstance* ItemInstance);
bool RemoveEquippedItem(UItemInstance* ItemInstance);
TArray<FItemSaveRecord> GetEquippedItems() const { return EquippedItems; }
FItemSaveRecord AddWorldItem(const UClothingItemInstance* ItemInstance, FTransform Transform);
bool UpdateWorldItem(UClothingItemInstance* ItemInstance, FTransform Transform);
bool RemoveWorldItem(UClothingItemInstance* ItemInstance);
FItemSaveRecord AddWorldItem(const UItemInstance* ItemInstance, FTransform Transform);
bool UpdateWorldItem(UItemInstance* ItemInstance, FTransform Transform);
bool RemoveWorldItem(UItemInstance* ItemInstance);
TArray<FItemSaveRecord> GetWorldItems() const { return WorldItems; }
UPROPERTY(SaveGame)
@@ -50,7 +51,7 @@ public:
private:
UPROPERTY(SaveGame)
TArray<FItemSaveRecord> WardrobeItems;
UPROPERTY(SaveGame)
TArray<FItemSaveRecord> EquippedItems;
+16 -19
View File
@@ -1,12 +1,18 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "NakedDesire/Clothing/ClothingItemInstance.h"
#include "NakedDesire/Clothing/ClothingItem.h"
#include "StructUtils/InstancedStruct.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()
struct NAKEDDESIRE_API FItemSaveRecord
{
@@ -14,25 +20,16 @@ struct NAKEDDESIRE_API FItemSaveRecord
UPROPERTY(SaveGame)
FGuid InstanceId;
UPROPERTY(SaveGame)
TSoftObjectPtr<UClothingItem> Definition;
TSoftObjectPtr<UItemDefinition> Definition;
UPROPERTY(SaveGame)
float Condition = 1.0f;
FInstancedStruct State;
UPROPERTY(SaveGame)
FGuid ParentId;
UPROPERTY(SaveGame)
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 "ItemSaveRecord.h"
#include "StartingSaveData.h"
#include "NakedDesire/Clothing/ClothingItem.h"
#include "NakedDesire/Clothing/ClothingItemInstance.h"
#include "NakedDesire/Items/ItemDefinition.h"
#include "NakedDesire/Items/ItemInstance.h"
#include "NakedDesire/Global/NakedDesireGameInstance.h"
void USaveSubsystem::LoadGame(const FString& SlotName)
@@ -62,14 +62,15 @@ void USaveSubsystem::PopulateStartingData(UGlobalSaveGameData* Save) const
if (!GameInstance || !GameInstance->StartingSaveData)
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;
// TODO: Refactor. Skip converting to ClothingItemInstance
UClothingItemInstance* Instance = NewObject<UClothingItemInstance>(Save);
Instance->Init(ClothingDef);
Save->AddEquippedItem(Instance);
}
}
@@ -6,7 +6,7 @@
#include "Engine/DataAsset.h"
#include "StartingSaveData.generated.h"
class UClothingItem;
class UItemDefinition;
UCLASS()
class NAKEDDESIRE_API UStartingSaveData : public UPrimaryDataAsset
@@ -15,5 +15,5 @@ class NAKEDDESIRE_API UStartingSaveData : public UPrimaryDataAsset
public:
UPROPERTY(EditDefaultsOnly, Category = "Starting State")
TArray<TObjectPtr<UClothingItem>> StartingClothing;
TArray<TObjectPtr<UItemDefinition>> StartingItems;
};