I have an inventory manager set up to start handing my character’s inventory and currently don’t call anything in the class except for the creation of the inventory slots which has a pointer to the item actors.
I am getting an error and it triggers a break point when I am in the editor running my game in the PIE.
I am using the 4.3 preview so this could be an issue with the 4.3 preview. I have had this inventory manager code in my 4.2 game and I am able to play the game for much longer at a time with no errors.
I just got through setting up a temporary day/night system in blueprints when I noticed the error. I got an error before when trying to play with the new level streaming features and thought it was due to that without actually taking a look at the error. After getting the error multiple times in a row, I knew it was not a coincidence and I am having trouble narrowing down the cause.
Below is the error.
[2014.07.15-03.51.38:890][340]LogUObjectBase:Error: 'this' pointer is invalid.
D:\BuildFarm\buildmachine_++depot+UE4-Releases+4.3\Engine\Source\Runtime\CoreUObject\Private\UObject\GarbageCollection.cpp(273): Fatal error:
Invalid object in GC: 0x0000000000000005, ReferencingObject: InventoryManager /Game/Maps/UEDPIE_0_ExileMap.ExileMap:PersistentLevel.InventoryManager_0, ReferencingProperty: ObjectProperty /Script/Exile.InventoryManager:InventorySlot.Item
Below is the code I currently have for my InventoryManager.
InventoryManager.h
#pragma once
#include "GameFramework/Actor.h"
#include "Item.h"
#include "InventoryManager.generated.h"
USTRUCT()
struct FInventorySlot
{
GENERATED_USTRUCT_BODY()
UPROPERTY()
FName SlotName;
UPROPERTY()
AItem* Item;
FInventorySlot()
{
SlotName = "";
}
FInventorySlot(FName Name)
{
SlotName = Name;
}
};
USTRUCT()
struct FInventoryRow
{
GENERATED_USTRUCT_BODY()
UPROPERTY()
TArray<FInventorySlot> Columns;
void AddNewColumn()
{
Columns.Add(FInventorySlot(""));
}
FInventoryRow()
{
}
};
USTRUCT()
struct FInventorySpace
{
GENERATED_USTRUCT_BODY()
UPROPERTY()
TArray<FInventoryRow> Rows;
void AddNewRow()
{
Rows.Add(FInventoryRow());
}
void AddUninitialized(const int32 ColCount, const int32 RowCount)
{
//Add Columns
for (int32 r = 0; r < RowCount; r++)
{
AddNewRow();
for (int32 c = 0; c < ColCount; c++)
{
Rows[r].AddNewColumn();
}
}
}
void Clear()
{
if (Rows.Num() <= 0) return;
//~~~~~~~~~~~~~~~
//Destroy any walls
const int32 RowTotal = Rows.Num();
const int32 ColTotal = Rows[0].Columns.Num();
for (int32 r = 0; r < RowTotal; r++)
{
for (int32 c = 0; c < ColTotal; c++)
{
if (Rows[r].Columns[c].Item && Rows[r].Columns[c].Item->IsValidLowLevel())
{
Rows[r].Columns[c].Item->Destroy();
}
}
}
//Empty
for (int32 r = 0; r < Rows.Num(); r++)
{
Rows[r].Columns.Empty();
}
Rows.Empty();
}
FInventorySpace()
{
}
};
/**
*
*/
UCLASS()
class EXILE_API AInventoryManager : public AActor
{
GENERATED_UCLASS_BODY()
// The main inventory space in a grid (player backpack,lootable items)
UPROPERTY()
FInventorySpace Inventory;
// Array of Item Slots for the Hotbar used by Players
UPROPERTY()
TArray<FInventorySlot> Hotbar;
// Array of Inventory Slots for the Equipment used by players and ai
UPROPERTY()
TArray<FInventorySlot> Equipment;
UFUNCTION()
void CreateInventory(int32 ColumnCount, int32 RowCount);
UFUNCTION()
void CreateHotbarSlots(int32 Count);
UFUNCTION()
void CreateEqupmentSlots();
UFUNCTION()
int32 GetInventorySize();
// Move an item from one inventory slot to another
UFUNCTION()
bool MoveItem(FInventorySlot& Origin, FInventorySlot& Destination, AItem* Item);
UFUNCTION()
bool AddItemToInventory(AItem* Item);
UFUNCTION()
bool IsInventoryFull();
// Package entire inventory (Inventory + Hotbar + Equipment) into a single Inventory.
// Used for creating a Lootable Actor from this inventory when a player or ai is killed and drops a pack of items.
UFUNCTION()
AInventoryManager* CreateDroppedInventory(int32 ColumnCount);
};
InventoryManager.cpp
#include "Exile.h"
#include "InventoryManager.h"
AInventoryManager::AInventoryManager(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
{
}
void AInventoryManager::CreateInventory(int32 ColumnCount, int32 RowCount)
{
Inventory.Clear();
Inventory.AddUninitialized(ColumnCount, RowCount);
}
void AInventoryManager::CreateHotbarSlots(int32 Count)
{
for (int32 i = 0; i < Count; i++)
{
Hotbar.Add(FInventorySlot(""));
}
}
void AInventoryManager::CreateEqupmentSlots()
{
// Add Head Item Slot
Equipment.Add(FInventorySlot("Head"));
// Add Chest Item Slot
Equipment.Add(FInventorySlot("Chest"));
// Add Legs Item Slot
Equipment.Add(FInventorySlot("Legs"));
// Add Feet Item Slot
Equipment.Add(FInventorySlot("Feet"));
}
int32 AInventoryManager::GetInventorySize()
{
if (Inventory.Rows.Num() <= 0)
{
return 0;
}
return Inventory.Rows.Num() * Inventory.Rows[0].Columns.Num();
}
bool AInventoryManager::MoveItem(FInventorySlot& Origin, FInventorySlot& Destination, AItem* Item)
{
AItem* Temp = nullptr;
// If Destination already has an item in the spot, store it into a temporary variable
if (Destination.Item && Destination.Item->IsValidLowLevel())
{
Temp = Destination.Item;
}
// Assign the item pointer to the new item for the destination inventory slot
Destination.Item = Item;
// Assign the item pointer to the temp for the origin inventory slot
Origin.Item = Temp;
return true;
}
bool AInventoryManager::AddItemToInventory(AItem* Item)
{
bool bAdded = false;
if (IsInventoryFull())
{
return false;
}
if (Inventory.Rows.Num() > 0)
{
int32 InvRowCount = Inventory.Rows.Num();
int32 InvColumnCount = Inventory.Rows[0].Columns.Num();
// Count how many filled inventory slots there are
for (int32 r = 0; r < InvRowCount; r++)
{
for (int32 c = 0; c < InvColumnCount; c++)
{
if (!Inventory.Rows[r].Columns[c].Item || !Inventory.Rows[r].Columns[c].Item->IsValidLowLevel())
{
Inventory.Rows[r].Columns[c].Item = Item;
bAdded = true;
break;
}
}
if (bAdded)
{
break;
}
}
}
return bAdded;
}
AInventoryManager* AInventoryManager::CreateDroppedInventory(int32 ColumnCount)
{
AInventoryManager* Inv;
FActorSpawnParameters SpawnParams;
SpawnParams.bNoCollisionFail = true;
Inv = GetWorld()->SpawnActor<AInventoryManager>(AInventoryManager::StaticClass(), SpawnParams);
int32 InventorySize = GetInventorySize() + Hotbar.Num() + Equipment.Num();
// Calculate number of rows needed to make sure it can hold all the items if all slots are full
int32 RowCount = FMath::Ceil(float(InventorySize) / float(ColumnCount));
Inv->CreateInventory(ColumnCount, RowCount);
// Add Hotbar items to the new inventory
for (int32 i = 0; i < Equipment.Num(); i++)
{
if (Equipment*.Item && Equipment*.Item->IsValidLowLevel())
{
Inv->AddItemToInventory(Equipment*.Item);
// Clear the item pointer so it only exists in the new inventory
Equipment*.Item = nullptr;
}
}
// Add Hotbar items to the new inventory
for (int32 i = 0; i < Hotbar.Num(); i++)
{
if (Hotbar*.Item && Hotbar*.Item->IsValidLowLevel())
{
Inv->AddItemToInventory(Hotbar*.Item);
// Clear the item pointer so it only exists in the new inventory
Hotbar*.Item = nullptr;
}
}
if (Inventory.Rows.Num() > 0)
{
int32 InvRowCount = Inventory.Rows.Num();
int32 InvColumnCount = Inventory.Rows[0].Columns.Num();
// Add Inventory items to the new inventory
for (int32 r = 0; r < InvRowCount; r++)
{
for (int32 c = 0; c < InvColumnCount; c++)
{
if (Inventory.Rows[r].Columns[c].Item && Inventory.Rows[r].Columns[c].Item->IsValidLowLevel())
{
Inv->AddItemToInventory(Inventory.Rows[r].Columns[c].Item);
// Clear the item pointer so it only exists in the new inventory
Inventory.Rows[r].Columns[c].Item = nullptr;
}
}
}
}
return Inv;
}
bool AInventoryManager::IsInventoryFull()
{
int32 InventorySize = GetInventorySize();
int32 FilledSlotCount = 0;
if (Inventory.Rows.Num() > 0)
{
int32 InvRowCount = Inventory.Rows.Num();
int32 InvColumnCount = Inventory.Rows[0].Columns.Num();
// Count how many filled inventory slots there are
for (int32 r = 0; r < InvRowCount; r++)
{
for (int32 c = 0; c < InvColumnCount; c++)
{
if (Inventory.Rows[r].Columns[c].Item && Inventory.Rows[r].Columns[c].Item->IsValidLowLevel())
{
FilledSlotCount++;
}
}
}
}
return (FilledSlotCount >= InventorySize);
}
If someone could help me figure out what is wrong in my code, that would be helpful.
If you need to see the code for how I am spawning the Inventory Manager, just let me know.
Thanks