Ultimate Inventory and Equipment Component

Documentation

Features

  • Jigsaw or slot-based container - supports jigsaw grid, found in games like Diablo or Path of Exile, where each item occupies a specific combination(rectangular) of slots in the grid. Can be also set up to act as the standard slot-based grid, found in most mmo games, where each item occupies a single slot.
  • Adjustable containers and items size - determine how big are player inventory, storage, loot chest or vendor containers. For jigsaw grid, you also determine how many slots each item occupies.
  • Items created through data table - all necessary items data is gathered in a single data table, where you can easily add new or edit existing items.
  • Inventory system - premade functionality which makes a container to act as an inventory.
  • Vendor system - premade functionality which let a user set up random shops where players can be new items or sell theirs.
  • Storage and loot chests - premade functionality which let a user create lootable chests and players storages.
  • Simple pick up and drop functions - easy to follow and extend to suit your game type.
  • Equipment system - create your own equipment slots and define which item types can be equipped to them.
  • Static and skeletal meshes - equipment system supports both static meshes (mainly weapons) and skeletal meshes (ie. armor) which needs to bend with character body.
  • Lockable equipment slots - possibility to create items that require more than one slot to be equipped (ie. two-handed sword requires left and right-hand slot and will automatically unequip items from these slots; or robe which requires torso, head and legs slots.
  • Drag&drop and single-click operations - players can drag and drop items between containers or relocate them with a single mouse click.
  • Stacking and splitting - items can be stacked up to a specific number of pieces and then stacks can be split on demand.
  • Simultaneous access to chests and vendors - multiple players can open the same chest or vendor and every action they perform (store/withdraw/buy/sell) will be seen by all these players.
  • Items tooltip and slot highlights - shows item tooltip when the mouse cursor hovers over the item slot. Additionally, when an item is dragged system highlights all affected slots to reflect possible on drop operation.
  • Items usage - add custom functionality logic to desired items.
  • Hotbar - assign items to quicks slots to ensure fast access to them.

Implementation


Now, when you have ItemsManager added to the game you can start adding containers to specific actors. AC_UIC_Container is a component responsible for storing items data assigned to the container. There are 3 basic types of container: Inventory, Stash, and Vendor. It is important to determine a type of all containers added to the game. If you want to create character's backpack functionality you will select Inventory Type. However, if you want to create some kind of chest (storage or loot), you will select Stash Type. You will also need a widget blueprint which will display items added to containers.

Steps to do :
Open your UI widget (the one which will display inventory, stash or whatever you need).
Navigate to Palette tab and find WBP_UIC_ContainerGrid. Add it to your widget. (It won't contain anything because slots will be created on the component initialization).
Click on newly added WBP_UIC_ContainerGrid and access its Details.
Under Default category select ContainerType, it will determine which container's items will be displayed there.
Open actor blueprint and navigate to its Components tab.
Click the green +Add Component button and from the dropdown list choose AC_UIC_Container.
Click on newly added AC_UIC_Container to access its Details.
In Details tab find Config category to edit container's default data.
  • ContainerSize will determine how many slots container has and how they are arranged.
  • ContainerType will determine what actions can be performed on that container.

Let's start with adding AC_UIC_ItemsManager component to the actor that will be responsible for maintaining items and containers. It is the most important component of the system because it contains whole logic and acts as a brain. My suggestion is to add it to the main Player Controller or directly to Player Pawn if you do not use custom Player Controller. Generally, add it to the actor that is easily accessible and is present in the game most of the time.

Steps to do:
Open blueprint actor that you want to add "items logic" to.
Navigate to its Components tab.
Click the green +AddComponent button and from the dropdown list choose AC_UIC_ItemsManager.
Click on newly added AC_UIC_ItemsManager and navigate to Details tab.
Find Config category and set up default data.
  • SlotDimensions determines how big are all container slots.
  • DebugEnabled will toggle printing of all debug messages from ItemsManager component.
  • NumberOfQuickSlots determines how many Quick Access Slots there will be in Quick Access Bar.
  • QuickSlotsPerRow defines how many Quick Access Slots will be in a single row.


Few important notes about containers types:
Inventory - acts as a handy bag, by default stores all picked up items, if dragging is canceled dragged items is placed there, unequipped items go there as well. Users can perform few actions when clicked while Ctrl button (by default) is held - store item in Stash type container (if a stash is opened), sell an item to a vendor (if a vendor is opened) or equip the item (if neither stash nor vendor is opened)
Stash - designed to be a storage or loot chest, dragged items can be added there as well as stored items can be retrieved. Only one action can be performed when clicked while Ctrl button is held - withdraw an item from Stash directly to Inventory.
Vendor - used to buy and sell items. Users will automatically get gold when dropping the item to Vendor container (sold items will disappear), users will also automatically pay for the item when starting to drag it. Only one action can be performed when clicked while Ctrl button is held - buy an item and place it in inventory.

Note: If you do not have your UI yet or have problems with adding ContainerGrid, you can use UI widget provided in Demo (WBP_UIC_UserInterface) or see how things are implemented there.
There is one component left - AC_UIC_Equipment. This one is responsible for handling actors equipment. It is similar to Container component because it needs to be added to the actor and only contains equipped items data. Here we can also set up how many slots equipment has and what items can be equipped. In addition to component, equipment also has its own WBP_UIC_EquipmentCanvas widget where you can adjust equipment layout.

Steps to do:
Open WBP_UIC_EquipmentCanvas.
Navigate to Palette tab and find WBP_UIC_EquipmentSlot.
Add as many of them to the EquipmentContainer canvas as you need (you can edit or remove existing slots).
Set up default data for each added EquipmentSlot widget. Under Static category, you will find following variables:
  • SlotSize - maximum size of an equipped item. All equipped items will be adjusted to the size of the slot(lesser items will be centered, so they do not stretch and larger items will be decreased to fit in the slot. to maintain optimum visual experience equipment slot should have the size equal to the largest item that can be equipped there.
  • SlotDimensions - also determines the size of the slot, but this time in pixels. So if SlotSize is 2x3 and SlotDimensions are 64x64 then equipment slot will be 128x192. I would suggest keeping SlotDimensions equal to the ones in ItemsManager.
  • SlotIndex - determines which item from equipment container will be assigned to that equipment slot. Each equipment slot must have unique SlotIndex value.
  • DefaultIcon - image that will be shown when there is no item equipped.
Open your UI widget (the one which will display equipment).
Navigate to Palette tab and find WBP_UIC_EquipmentCanvas. Add it to your widget.
Open actor blueprint to which you want to add equipment functionality.
Navigate to its Components tab.
Click the green +AddComponent button and this time from the dropdown list choose AC_UIC_Equipment.
Click on newly added AC_UIC_Equipment to access its Details.
Under Config category, you will find two variables which need to be set up:
  • EquippedItems - determines how many items can be equipped. Generally, slots should equal to the ones you set up in WBP_UIC_EquipmentCanvas.
  • AvailableEquipment - determines which item subtypes can be equipped to specific slots. Should be equal to the number of slots in EquippedItems.

Initialization

To make everything work as intended you will need to initialize ItemsManager component when all desired widgets are already present. Generally, first, you create widgets that contain inventory, equipment, stash, vendor and quick slots, then initialize proper parts of Items Manager.


Initialization process that is shown on pictures above is prepared to work in both simple and multiplayer (listen or dedicated server). You easily recreate it in your player controller blueprint or copy most of the stuff from demo player controller.

Creating new items


Items data can be edited anytime and changes will affect the game at any stage (even if you load the game from save file). However, there are few things to keep in mind.
  • Size changes should be avoided at later stages of development, especially when the game is published. Because if an item is already in a container and we change its size it is highly possible that it will overlap other items.
  • Changing MaxAmoutnInStack won't affect the current number of pieces in the stack. Eg. If you decide to decrease potion max stack amount from 20 to 10 all stacks that player already acquired and have 20 pieces will remain there unless the player decides to split them, then he won't be able to merge them back. But all new stacks will be stacked up to 10 pieces. (Of course, assuming that changes are made late in development and players already have these items).
  • Changing item subtypes won't unequip items automatically if their subtype won't match available ones, but the player won't be able to re-equip this once item is unequipped. Eg. It was made the way that player can equip 2x one-handed sword (to right and left hands). But later it was changed that the only dagger can be equipped to the left hand and only one sword can be equipped (to the right hand). So if the player had a character with 2x one-handed swords equipped it will remain this way, until the player decides to unequip that second sword.

These are small things but should help you to avoid encountering bugs later.

Of course, you could always make it put pieces that exceed MaxAmountInStack directly to inventory when changes are made and same with equipment that doesn't meet requirements after changes. However, you will also need to figure out what to do with items if there is no space in inventory and system automatically splits or unequips them. You could send them to in-game mailbox or store at special NPC (just an idea, all depends on game type).

All items added to the game are stored in DT_UIC_Items data table. You can edit existing ones or create new items there. Data table entries are basing on the S_UIC_ItemStatic structure so if you would like to extend item data you will need to edit that structure.

Below you will find explanations for all variables in item structure:
  • ID - used to identify an item during the game and in blueprints logic. All items IDs must be unique. You can use unique names or simple indexes, whatever makes it easy to distinguish them. IMPORTANT: ID must be the same as the name of the row in the data table.
  • DisplayName - the name of the item that will be displayed to the player (ie. in widgets).
  • Description - description of the item that will be displayed to the player (ie. in widgets).
  • Size - how many slots item takes in the container. TIP: Setting size of all items to 1x1 you will turn jigsaw system to standard slot-based system.
  • Value - how much item is worth (default price for buying and selling).
  • Type - to which group item belongs to (existing items types can be edited in the E_UIC_ItemType enumeration, you can also add new ones).
  • Subtype - to which subtype item belongs to (existing items types can be edited in the E_UIC_ItemSubtype enumeration, you can also add new ones). Subtypes are also used to determine which item can be equipped to specific equipment slots.
  • Usable - determines whether the item can be used or not (like potions, scrolls or other consumables).
  • RegistrableInQuickBar - determines whether the item can be registered to QuickAccessBar or not.
  • Image - icon/image that will be displayed to the player (ie. in widgets, during item dragging). Remember to maintain image proportions to avoid distortion. If item size is 2x1, then its width must two times longer than its height (256x128, 200x100, 300x150 and so on).
  • MaxAmountInStack - how many pieces of the specific item can be collected to one stack. IMPORTANT: must be higher than 0, additionally, for all equipment items must be equal to 1. Items with MaxAmountInStack higher than 1 cannot be equipped.
  • StaticQuality - determines whether item should always has static quality.
  • Quality - what quality item should have when "StaticQuality" is enabled.
  • AdditionalLockedSlots (only for equipment) - determines which slots will be locked/excluded from equipment when this specific item is equipped. Eg. If you want to create a two-handed weapon you can lock slot where a shield is equipped. One item can lock multiple slots.
  • SkeletalMeshEquip (only for equipment) - this skeletal mesh component will be added to the actor when the item is equipped. Skinned meshes can be used to create equipment parts which need to bend with the body, such as torso armor or trousers.
  • SkeletalMeshEquipSocket (only for equipment) - determines to which socket a mesh should be attached when equipped to a certain slot. Use this only if you want the mesh to be attached to socket (ie. bow or whip), leave empty and it will be attached to the main mesh (ie. armor).
  • StaticMeshEquip (only for equipment) - this static mesh component will be added to the actor when the item is equipped. Static meshes are mostly used for rigid equipment parts, such as weapons or helmets.
  • StaticMeshEquipSocket (only for equipment) - determines where static meshes are attached to (to which sockets). It requires a paired slot index and socket name. Thanks to this we can equip the same item to different slots without excessive changes. Eg. Let's assume we have two equipment slots with indexes 1 (right hand) and 2 (left hand). We also have a sword which can be equipped to right or left hand. Thanks to this paired values we can set up that when the sword is equipped to slot 1 its static mesh will be attached to the right-hand socket if the sword was equipped to slot 2 it would be attached to the left-hand socket.

Add and remove items from containers


To add an item to a specific container you can call one of two functions from ItemsManager component. These functions are: AddItemToContainer(byID) and AddItemToContainer(byStruct). IMPORTANT: If you are making a multiplayer game they should be called on the server side. These functions are very similar, they both require pinned container to which you want to add item to and you can specify amount of the item.

When to use AddItemToContainer(byID) function?
This function will read item data (by matching ID) from data table and add it to container. It is useful if you want to add some kind of random item. Let's suppose there is a sword that has random power bonus (5-15). Each time item is added from data table you could roll random power bonus value. So if you add multiple sword their power bonus would vary.

When to use AddItemToContainer(byStruct) function?
This one will require specified item structure that will be added to container. Main reason to use this function is to add item with specific data to container. Let's stick to that sword with random power bonus used in previous example. Thanks to this function you can add that sword with exact value of power bonus (eg. quest reward gives player a sword with +15 power).

There is one more function responsible for adding items to containers. It is FillContainerWithItems and it will add random items from data table to container given amount of times (It uses AddItemToContainer(byID) function). If you set up to add 100 items and container will be full after 20 rolls it will keep rolling random items up to 100 times. It does so because if it roll stackable item it will be added to existing stack if it is not full. This function can be used to fill vendor or loot chest containers with items, of course you can extend functionality by percentage based rolls, so rare items won't appear as frequently as common ones.


There is one main function in ItemsManager component responsible for removing items. IMPORTANT: As previously it should be called on the server side if it is a multiplayer game. RemoveItemFromContainer will remove an item (specified by ID) starting from the stack that is not full and then in order from the left top slot to the right bottom slot. You can specify whether it should remove items even if there are not enough pieces in a container or it should remove all of them regardless of their amount in a container.


Note: if you want to create an item that player will be able to pick up in the world, there is example BP_DemoUSC_Pickup actor in Demo/Blueprints folder. Of course, it is not the only way to implement Pickups to the game, feel free to make it the way suits your project.

Access and leave stash or vendor containers


There is powerful functionality that provides simultaneous access by multiple players to the same stash or vendor container. Thanks to this, when one player stores, withdraws, buys or sells items other players will see it immediately (of course if they are accessing the same container at this moment). How player access stash or vendor is totally up to the user and will vary depending on a game type and whether it is multiplayer or not.
However, I have added functionality that wraps up accessing containers in both single and multiplayer games. Most of the logic is spread between ItemsManager component (generic events responsible for storing references) and demo PlayerController (demo-specific data, like opening widgets). You can use it as a base to create your own functionality to access storages, chests, and vendors. I reckon in most cases there will be only little changes needed (if any at all).


Note: Simultaneous access required special interaction with the vendor. When buying an item from a vendor you will pay for it immediately when you start dragging it (click on it in vendor window) not when you drop it to inventory. It works this way because when a player starts dragging an item from a vendor other players accessing this vendor needs to know that item is no longer available. That's why it is paid instantly and treated as player's item once it is picked from a vendor.
Also to prevent from messing up vendor container sold items will disappear and won't be added to the vendor container. Of course, there are workarounds, each player could have separate independent vendors components, but it would also mean they will have different items and won't interact with each other when accessing vendor. Optionally, if there will be many requests I may try to implement this workaround and users will be able to choose the one they want to use.

Stacks splitting

To make items managing easier players can use stacks splitting functionality. It will let them take a specific amount of item from a stack (if MaxAmountInStack>1) and drag it to another slot or container. To enable or disable stack splitting call ToggleStackSplitingOperation function from ItemsManager component. In the demo, it is toggled with LeftShift (on when pressed and off when released).
Note: Items with 1 piece of item in a stack will be dragged automatically without popping Splitting Window out.


An item also will be stacked automatically if you drop it on the other item that has a matching ID.

Quick actions

Quick actions are the events that let a player to quickly perform actions in containers instead of dragging items from one container to another. With a single mouse click, players can equip, unequip, buy, sell, store and withdraw items. To enable or disable quick actions call ToggleQuickActionsOperations function from ItemsManager component. In the demo, it is toggled with LeftCtrl (on when pressed and off when released).
Which quick action is used depends on which containers are opened/accessed.
  • Quick Store and Withdraw can only be used if Stash and Inventory containers are opened and it will move items between them, relocating item to the first available valid slot.
  • Quick Buy and Sell can only be used if Vendor and Inventory containers are opened. Items will be immediately sold from inventory and bought from a vendor as long as there is free space in inventory.
  • Quick Unequip can be performed at any time and will remove an item from the equipment slot and place it in inventory as long as there is free space for it.
  • Quick Equip can only be used if neither Vendor nor Stash containers are opened. Clicked item will be equipped to the first equipment slot that meets item requirements. It means that if a one-handed sword can be equipped to right-hand equipment slot (index= 1) and left-hand equipment slot (index=2) it will always be equipped to right-hand equipment slot.

Items usage

All items that you create can be defined as usable and players will be able to use them during the game. To determine whether the item can be used or not you just need to select this option during item creation in the items data table (Usable checkbox).

To use the item you just need to call the function UseItemFromInventory_SERVER. It only requires the index of the slot where the item is. Only items that are in inventory container can be used.
By default, UseItemFromInventory_SERVER is assigned to the right mouse button clicks. If you wish to change it you can do it directly in WBP_UIC_ContainerSlot widget.

Most of the items will have different functionality. To add item effect logic to the game open AC_UIC_ItemsManager component, navigate to ItemsEffects event graph and find the SwitchOnName node. Add there pin for each item you want to be usable and connect item logic to the desired pin.

With dozens of items and all of them having less or more complex functionality event graph may get overflooded and overwhelming. To avoid this you can use CollapseNodes or CollapseToMacro options. That should give all item effects their own space.

There are few examples of items effects that may help you with setting up your custom logic.
  • Apple - executes instant effect and remove the item from inventory.
  • Scroll - timed effect that is executed after few seconds and then the item is removed.
  • Book - timed effect that is executed after few seconds but the item isn't removed (provides an infinite amount of uses).
  • PresentBox - the effect that let you receive items from another item (ie. after opening box), the system will first check if there is enough room in inventory if so it will add items to the container.

Crafting

Crafting is handled by a separate actor component. Add AC_UIC_CraftingManager to the actor that uses AC_UIC_ItemsManager component. Once it is added it doesn't require further set up.

DT_UIC_Craftables data table contains all craftable items. Modify it to add or remove craftables. Each row consists of:
  • ID - used to identify the item, should be equal to ID to one of the items in DT_UIC_Items data table because default data like name or description is read from that data table. IMPORTANT: ID must be the same as the name of the row in the data table.
  • RequiredMaterials - IDs and number of all items required to craft given item.
  • CraftingGroup - determines to which category given craftable belongs to. You can edit crafting groups in E_UIC_CraftingGroup enumeration.
  • CraftedAmount - how many items will be produced on one crafting attempt. IMPORTANT: Keep this number below crafted item maximum stack amount.
  • UnlockedByDefault - determines whether craftable is available from the beginning or has to be unlocked manually.

If an item isn't unlocked by default you can do it manually by calling UnlockCraftable function. This way you can make specific craftables obtainable by consuming other items (aka recipes), through missions etc.

Quick Access Bar

Quick Access Bar (also knows as Hotbar) allows players to use most-needed items with a single button pressing. You can define how many slots Quick Access Bar will have and how they are positioned (ie. in 2 rows). To do this open AC_UIC_ItemsManager, under Variables section, in Config category you will find two variables:
  • NumberOfQuickSlots - determines how many slots in total there will be in Quick Access Bar
  • QuickSlotsPerRow - determines up to how many slots single row can contain.

You can also define which items can be assigned to the Quick Access Bar (there is no need to assign items that do not have any effects). To do this just check RegistrableInQuickBar variable in DT_UIC_Items data table.

To add Hotbar to your game just place WBP_UIC_QuickAccessBar in one of your user interface widgets. Upon initialization, the system will automatically find it and add a defined number of slots to it.

Items cannot be dragged from inventory and dropped on quick slots because once item being dragged it no longer exists in inventory. The system wouldn't really know what item we want to assign that's why you can add items to Hotbar with a right click (by default) when Quick Access Bar registration is enabled. To toggle it just call the ToggleQuickAccessBarRegistration function (by default tied to Left Shift). Items will be added to the first quick slot without an assigned item. You can reorder items in Hotbar by simply dragging them from one slot to another.
You can also remove an item from Hotbar using Left Shift + right click (by default).

Items can be used directly from Hotbar if you use right click on the quick slot or you can tie functionality to desired buttons (example set up can be found in BP_DemoUIC_Controller blueprint.

Item Quality

You can generate random item quality using RollItemQuality function. Default function has an equal chance to roll either of qualities (mainly for demo purposes).  Swap its logic with custom one to have more complex randomization function.

Also, by default, there are 4 different qualities: Common, Rare, Epic and Legendary. They can be edited in E_UIC_ItemQuality enumeration. There is also a global ItemQualityToColor function which outputs different colors depending on quality input. This function can be edited if you want to change colors of corresponding qualities.

Save and load

All components have their own saving functionality. Container component saves inventory, stash or vendor items, Equipment component saves equipped items, Items Manager component saves Quicks Slots data and Crafting Manager component saves crafting data.

They all have similar save function respectively named SaveContainer, SaveEquipment, SaveQuickSlots, and SaveCrafting they all have the same two inputs:
  • SaveName - how a save file will be named, remember to use different names for different actors unless you want to overwrite the data.
  • SaveToGameInstance - determines whether the game should be saved to the game instance or to a separate save file on a device.

Data saved to the game instance will be stored only during a single game session and it will be wiped after the game is closed. Use it to temporarily store data, ie. when changing levels. Data saved to file (using standard SaveGame object) will be stored on a device even when the game was closed. It can be accessed each time the game is started to load stats data. Depending on your needs you may use a single method or mix them.

Components data can be loaded in an analogous way, calling one of these functions: LoadContainer, LoadEquipment, LoadQuickSlots, LoadCrafting/ They have two inputs as well:
  • SaveName - name of the save file to load stats data from or a name of a key of map variable stored in the game instance.
  • LoadFromGameInstance - determines if stats data should be loaded from a game instance or from save file stored on a device.

If you call these functions during the initialization process (ie. just after a new level was loaded) put them at the very end, so all widgets are already created and components are initialized.

To ensure smooth implementation of the saving system to your game project without overriding any of your data use BPI_UIC_SaveCommunication blueprint interface, which can be found in Blueprints>Interfaces folder. Open your custom game instance blueprints, navigate to ClassSettings and on details tab you will find the option to add interface and compile blueprint. Open BP_DemoUIC_GI_Custom blueprint located in Demo Blueprints folder and copy or recreate its functions and variables.
If you don't use the custom game instance, but you still want to use save system with game instance you can use the one which is used in demo content (or a copy of it). It has the saving system already implemented.

Important: Remember that this save functionality is created primarily for single player games because of multiplayer games rather store data externally.