// © 2025 Naked People Team. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Subsystems/GameInstanceSubsystem.h" #include "InventorySubsystem.generated.h" class UItemInstance; class UClothingManager; class UGlobalSaveGameData; DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnWardrobeChangedSignature); /** * Runtime owner of the off-body item store (the apartment wardrobe, GDD §6.5 / §10.4). * * Holds live UItemInstance objects mirrored from UGlobalSaveGameData::WardrobeItems and is * the single entry point for moving items between the wardrobe and the body. Equipped items * stay owned by the per-character UClothingManager (it remains the body-state authority and * keeps writing the EquippedItems bucket); this subsystem orchestrates the wardrobe<->equipped * transfer so the two save buckets can never drift. Mutations broadcast OnWardrobeChanged so * the wardrobe UI can refresh without polling. */ UCLASS() class NAKEDDESIRE_API UInventorySubsystem : public UGameInstanceSubsystem { GENERATED_BODY() public: UPROPERTY(BlueprintAssignable) FOnWardrobeChangedSignature OnWardrobeChanged; /** Live wardrobe instances (off-body, mirrored from the save). */ const TArray>& GetWardrobeItems(); /** Bring an item into the wardrobe (purchase, world-return). */ void AddToWardrobe(UItemInstance* Item); /** Remove an item from the wardrobe without equipping it (discard). */ void RemoveFromWardrobe(UItemInstance* Item); /** Move a stored item onto the body; any displaced garment returns to the wardrobe. */ void EquipFromWardrobe(UItemInstance* Item); /** Take an equipped garment off the body and store it back in the wardrobe. */ void UnequipToWardrobe(UItemInstance* Item); private: void EnsureHydrated(); void StoreItem(UItemInstance* Item); // live list + save bucket, no broadcast void UnstoreItem(UItemInstance* Item); // live list + save bucket, no broadcast UClothingManager* GetPlayerClothingManager() const; UGlobalSaveGameData* GetSave() const; UPROPERTY() TArray> WardrobeItems; // The save the live list was built from; re-hydrate when this changes (e.g. load game). TWeakObjectPtr HydratedSave; };