Hi,
first of all thank you for your help and sorry for my late answer! I actually was kind of blind and didn’t noticed that it was taking diffent code paths. It’s supposed to first call TryAddToUsedSlot
and if that fails to call TryAddToEmptySlot
, but never both.
It seems to be due to saving data beyond play sessions, because it’s predictably alternating between calling the two functions mentioned above from session to session.
I actually create the UStorageSlot
statically in the contructor and initialize its Count in BeginPlay(...)
. This is the code…
UInventoryComponent::UInventoryComponent()
{
...
ShotgunShells = CreateDefaultSubobject<USlotStorage>("ShotgunShells");
}
void UInventoryComponent::BeginPlay()
{
Super::BeginPlay();
...
ShotgunShells->Init(this, InventoryLayout.ShotgunShells);
}
void USlotStorage::Init(UInventoryComponent* AInventoryComponent, TArray<int> SlotCapacities)
{
InventoryComponent = AInventoryComponent;
for (int i = 0; i < SlotCapacities.Num(); ++i)
{
FSlot Slot;
Slot.Index = i;
Slot.Class = nullptr;
Slot.Count = 0;
Slot.Max = SlotCapacities[i];
Slots.Add(Slot);
}
}
FStorageInfo
USTRUCT(BlueprintType)
struct FStorageInfo
{
GENERATED_BODY()
FStorageInfo() {};
FStorageInfo(EStorageName StorageName, TObjectPtr<UTexture2D> Icon = nullptr, bool Consumable = true, int Count = 0);
void Update(int ACount, int AIndex, int AMax, bool ASuccess);
// When Pickup is added to an unknown Slot
UPROPERTY() EStorageName StorageName;
UPROPERTY() TObjectPtr<UTexture2D> Icon;
UPROPERTY() bool Consumable = true;
UPROPERTY() int Count = 0;
UPROPERTY() int Index = 0;
UPROPERTY() int Max = 0;
UPROPERTY() bool Success = false;
};
FSlot
USTRUCT()
struct FSlot
{
GENERATED_BODY()
int Index;
TSubclassOf<APickup> Class;
int Count;
int Max;
};
Add(…)
void USlotStorage::Add(APickup* Pickup, FStorageInfo& StorageInfo)
{
UE_LOG(LogTemp, Warning, TEXT("%s -> %d"), *FString(__FUNCTION__), StorageInfo.Count);
TryAddToUsedSlot(Pickup, StorageInfo);
if(!StorageInfo.Success)
{
TryAddToEmptySlot(Pickup, StorageInfo);
}
if(StorageInfo.Success)
{
Pickup->Destroy();
}
}
TryAddToUsedSlot(…)
void USlotStorage::TryAddToUsedSlot(APickup* Pickup, FStorageInfo& StorageInfo)
{
for (FSlot& Slot : Slots)
{
// If there is already an item of that type in a Slot that is not full: Add the item
if(Slot.Class == Pickup->GetClass())
{
if(Slot.Count < Slot.Max)
{
UE_LOG(LogTemp, Warning, TEXT("%s -> %d - %d"), *FString(__FUNCTION__), Slot.Count, StorageInfo.Count);
AddToSlot(Slot, StorageInfo);
return;
}
}
}
}
TryAddToEmptySlot(…)
void USlotStorage::TryAddToEmptySlot(APickup* Pickup, FStorageInfo& StorageInfo)
{
for (FSlot& Slot : Slots)
{
if(Slot.Count == 0)
{
Slot.Class = Pickup->GetClass();
UE_LOG(LogTemp, Warning, TEXT("%s -> %d - %d"), *FString(__FUNCTION__), Slot.Count, StorageInfo.Count);
AddToSlot(Slot, StorageInfo);
return;
}
}
}
GetStorage(…)
UStorage* UInventoryComponent::GetStorage(EStorageName StorageName)
{
switch (StorageName)
{
case EStorageName::ShotgunShells:
return ShotgunShells;
// ...
class THETHIRDPERSONGAME_API UInventoryComponent : public UActorComponent
{
...
private:
UPROPERTY() TObjectPtr<USlotStorage> ShotgunShells;