🎒Inventory
Last updated
Last updated
Due for Removal, please see Docs.
31/10/2024: MSquared will no longer be providing an inventory system as part of the core platform. We will be working out the best strategy to reduce impact to existing customers and update when we have more info.
For now we suggest using the User Collection API's directly for anything related to M2 Collections, and looking into creating your own systems in Unreal for things like typical game item management
MSquared will not be addressing cosmetic (HUD, widget etc) or non-critical issues going forwards.
Please speak to your Support Engineers for more info.
The Inventory System is how we handle “items”, including use items (devices). In-game, we currently have the following parts of the system:
The “Item”: Each item is a data asset (of the name PDA_Item_[ItemName]
). Within the data asset, we can provide various data that describes the item, such as its display name, its icon, and, if we want it to be a use item (device), additional use item details.
The “Inventory View”: This shows all the items you currently have in your possession, and which you have equipped, filtered by different item type.
Items currently equipped are displayed in a “quickbar”.
You can click and drag items between the “inventory” and the “quickbar” to equip/unequip them.
The “Device Quickbar”: This is the UI used for “devices” (use items). It shows the quickbar of equipped devices. If you select a device (using the num keys, or by clicking on it), it will display the device-specific UI for controlling that item’s behavior.
For more details on how to use the quickbar, see How to Use Devices.
For more details on how to make your own devices, see How to Make Devices.
If you are using multiple quickbar tabs, instead of the one device quickbar, see Quickbar & Inventory Tabs.
The “Place Mode”: This is our UI for selecting your equipped “Objects”, that can be placed directly into the world, e.g. MML documents.
For more details on the place mode, see Place Mode.
To use this inventory system, you need to make sure that you meet the following:
Your Morpheus Pawn has the InventoryComponent
, EquipmentComponent
etc. If you extend BPM_M2_PlayerCharacterBase
, or some child of this, all of these will be included.
Your HUD widget includes WBP_ItemManagement
. If you are using WBP_TH_HUD
, this should be handled for you.
To set up the inventory system appropriately for your project, consider the following live config values:
Inventory.ShowItemManagement
: If this is false, the entire inventory UI will be hidden
Inventory.HideInventoryView
: If this is true, the inventory view option will be hidden.
Inventory.HidePlaceMode
: If this is true, the place mode option will be hidden
(If both the above are true, you will be left only with the quickbar)
Inventory.AutoEquipItems
: If true, any time you add an item to your inventory, it will automatically be added to your quickbar (if there is space). Otherwise you will need to manually equip any granted items.
Inventory.MaxInventorySize
: The total number of 'unique' (not stacked) items you can have in your inventory. Currently set to 100.
Inventory.MaxEquipmentSlots
: The total number of quickbar slots for devices. Currently set to 8.
NOTE: Reducing the number of slots can be done easily, but there are some added steps required to add quickbar slots. Outlined in Adding/modifying Quickbar Slots.
Inventory.MaxPlacementSlots
: The total number of quickbar slots for the place mode. Currently also set to 8.
Inventory.Quickbar.HideIfEmpty
: If true, the quickbar will only be visible for players with inventory, and will be hidden for those without.
Inventory.Quickbar.HideEmptySlots
: If true, only slots that have items in already will be visible (the quickbar will "grow" up to the MaxEquipmentSlots).
Some of the additional fields within a J_ItemPrimaryAsset
(the item PDA):
bAllowsDuplicates
- this flag can be used to control whether players can be granted multiple of a given item.
(If this is false, we can guarantee that an item name is unique in your inventory, meaning that FirstKeyOfItem
can be used to find the item)
bIsStackable
- if we are allowing duplicates, this indicates whether duplicates are added to the same “slot”, or whether a unique slot is added per item of that type.
(You can control how many items can be present in a stack of a given item using OverrideMaxStackSize
- if it is <0, the live config flag Inventory.DefaultMaxStackSize
will be used)
StackConsumedPerUse
- If >0, "using" the item (e.g. activating the item's ability) will consume that number. use this to have cosnumable items/items with limited uses.
The item executor has a ConsumeUseOfItem
method, which is triggered by default in NotifyAutoUseItemResult
, but this behaviour can be overridden, or the method can be triggered manuall
J_UseItemDetails::bAutoUse
- if this is set, then clicking on a device in your quickbar/pressing the shortcut will automatically use it, instead of making it open the device specific UI. In the ItemExecutor
, this triggers the Event Execute Auto Use
The JM_InventoryComponent
is the main component that handles your inventory. It has methods for adding items and removing them, and has events that are broadcast when your inventory changes.
Items in your inventory are stored via “keys” - unique integers per item that do not change. When an item is added, it is given a key, and you can refer to this to guarantee you are considering the same item when it comes to equipping or removing it. (Using the item’s name or slot index is not reliable since there can be multiple items of the same type in your inventory, and items can move around.)
NOTE: An item key is per "stack" - depending on your item's configuration, you can have multiple items treated as a single item key, with a counter of how many there are, or have a unique entry per item.
Items can have custom properties on them. For more details, see Item Properties.
FirstKeyOfItem
: Returns the first ItemKey of the item in your inventory list. (There may be multiple)
GetKeysWithItemName
: Returns the list of all ItemKeys of items with the given name in your inventory list.
ItemKeyIsValid
: Returns true if the inventory has an item with the provided ItemKey
ItemKeyToItemName
: Returns the ItemName of the item with the provided ItemKey in your inventory list.
ItemIndexToItemKey
: Returns the ItemKey of the item at that index
ItemKeyToItemIndex
: Returns the index of the item with that ItemKey
GetInventoryList
: Returns the list of ItemNames in your inventory
GetInventoryItemKeys
: Gets all the ItemKeys in your inventory
GetItemProperty
: See Item Properties
SetItemProperty
: See Item Properties
GetItemStack
: Return the number of items stacked at the slot with the provided ItemKey
OnInventoryUpdated
: Triggered on the client and server when the inventory list is updated.
OnItemAdded
: Triggered on the client and server when an item is added to your inventory, giving the ItemName and ItemKey of the new addition.
OnItemRemoved
: Triggered on the client and server when an individual item is removed from your inventory. Provides the item's ItemName and ItemKey.
OnItemStackChanged
: Triggered on the client and server when an individual item changes its stack size (e.g. items are added/removed from the stack).
OnItemUpdated
: Triggered when an existing item in your inventory was modified, e.g. by setting its properties, or changing its stack
The following are server only:
AddInventoryItem
: Adds items with the provided ItemName to your inventory with the provided quantity
AddInventoryItemToStack
: Like the above, but allows you to add it specifically to a specific stack by providing the ItemKey
.
AddInventoryItems
: Adds a list of ItemNames to your inventory
RemoveItemByItemKey
: Removes the item with the provided ItemKey from your inventory. Allows you to remove multiple of said item.
RemoveItemsByItemKey
: Removes the items with the provided ItemKey from your inventory. Does not support removing more that one of each.
ClearInventory
: Removes all items from your inventory
OnInventoryCleared
: Triggered when the entire inventory is cleared.
An item in your inventory can store arbitrary struct data on it, which can be used to store per-item custom state. You can use this to store details that change per individual item, rather than details about the item type, for instance how many charges a device has left, or whether it is toggled on or not.
Some details on how to use it:
SetItemProperty
: Provide an arbitrary struct and an item key, and it will set that property for said item key.
NOTE: Each item can have multiple properties, but only one struct per given type. If you call SetItemProperty
again with the same struct type, it will replace the old one.
The ReplicationType
controls where the property is accessible:
LocalOnly
: Can be called on the owning client or server. The property will only be set on that machine.
OwnerOnly
: Can only be called on the server. The property will be set on the server, and replicated to the client.
Foreground
: Set on the server. It will be replicated to the client, and to other foreground clients via The Item Visuals Component.
Foreground Client Auth
: Same as above, but set on the auth client.
GetItemProperty
: Provide an item key and struct type, and it will return the property if the inventory component has a property set for that item.
NOTE: "Local Only" properties set on the server won't be seen on the client and vice versa
OnItemUpdated
: An event you can listen to, which triggers when an item's details update, e.g. its properties updated, or its stack changed.
NOTE: This triggers any time there is any update for a given item, we cannot listen to a particular property changing.
One example item property that has been hooked up to the UI is the M2_ItemToggleProperty
. This has been used e.g. by PDA_Item_LoudspeakerDevice
. If you set the item property to true, it is reflected visually in the UI.
JM_InventoryComponent
refers to your entire inventory (as seen in your inventory view). The device quickbar, controlled by the JM_EquipmentComponent
is a subset of this inventory. Similarly, the M2M_PlaceModeComponent
acts as a "quickbar" for your place mode items (showing a subset of your items that you can place in that mode, and have selected). Both of these components extend M2M_QuickbarComponent
, which has methods for controlling this subset of your inventory.
The quickbars operate by having a list of "slots" - a list of item keys that point back to the inventory component. If the slot has the INDEX_NONE
(-1) value, that means it's an "empty slot", with no item in it.
This information similarly holds for Quickbar Views. You can call the methods on the underlying quickbar component, e.g. JM_EquipmentComponent
, but this is only recommended if you are not using views on top.
SetSelectedSlot
: Selects which of your quickbar slots is the "selected"/active one.
ToggleSlot
: For the provided slot, select it if it is unselected, and vice versa
SelectItemKeyDirectly
: Allows you to select an item directly by specifying an ItemKey, without needing it to be in your quickbar.
GetSelectedItemKey
/GetSelectedItemName
: Returns the currently selected item's item key/name.
GetSelectedSlotIndex
: Similar to the above, but returns the selected item's slot. (If you selected an item that isn't in the quickbar using SelectItemKeyDirectly
, this will return -1)
IsSelectedItemInQuickbar
: Returns true if the currently selected item is in your quickbar (i.e. it was not selected directly from your inventory)
HasItemInSlot
: Returns true if there is an item in that quickbar slot.
GetItemKeyInSlot
/GetItemNameInSlot
: Returns the item key or item name of the item in the provided slot.
GetSlotByItemKey
: Returns the slot index that contains a provided ItemKey.
AddItemKeyToAssignmentSlots
/AddItemNameToAssignmentSlots
: adds the item key (either directly, or finding the item via the item name) to the provided slot in your quickbar. If no slot is provided (the index is < 0), it'll try and add the item to the first available slot.
NOTE: The device quickbar is controlled by the server, so this request is not instantaneous - it takes a round trip for the item to actually be equipped, and so for your quickbar to update
UnassignItemByKey/Slot/Id
: Unequips the provided slot, by providing the item's name, slot or item key.
ClearSelectedItem
: Deselects the currently selected item.
ClearSelectedSlot
: Same as the above, but only if you selected the item from one of your slots. It won't do anything if the item was selected directly from outside your quickbar using SelectItemKeyDirectly
.
ClearAllSlots
: Unequips all the quickbar slots.
GetEquippableItems
: Returns the list of item keys of the items your inventory that can be equipped into this quickbar component
GetSlotItemKeys
/GetAssignedItems
/GetLoadedItemAssets
: Gets the items currently in your quickbar slots, returning their item keys, item names, or their item PDAs respectively.
GetAvailableSlotInRange
: Checks the range of slots in your quickbar, and returns an empty slot (that is available for adding an item) if there is one
BindToItemsUpdated
: Triggered whenever the items in the quickbar have updated.
(Unbind with UnbindItemsUpdated
)
BindToItemsLoaded
: Same as the above, but once these items' PDAs have all been loaded. The event provides the list of item PDAs.
(Unbind with UnbindItemsLoaded
)
BindToSelectedKeyUpdated
: Triggered whenever your selected item has updated.
(Unbind with UnbindSelectedKeyUpdated
)
BindToSelectedSlotUpdated
: Similar to the above, but only when the selected item was something in your quickbar (e.g. not selected directly from outside your quickbar).
(Unbind with UnbindSelectedSlotUpdated
)
The following are specific to the JM_EquipmentQuickbar
, or equipment views on top of that:
GetActiveExecutor
: Returns the item executor for the currently selected item
BindToActiveExecutorUpdated
: Triggered when the selected item's item executor has been made, or when the selected item has been deselected, so the item executor gets cleaned up.
(Unbind with UnbindActiveExecutorUpdated
)
To add extra slots to a quickbar, you need to both increase the number of slots in live config and make sure you have defined enough shortcuts. Otherwise, it won't be able display shortcuts for all the icons.
To do this, you'll need to do the following:
In your character's MorpheusActor, e.g. the child extending BPM_M2_PlayerCharacterBase
, go to the InventoryHandlerComponent
If the InputMappingContext
doesn't have enough slots, you can make your own, e.g. by copying IMC_QuickbarSlots
.
Make sure all the inputs you need (unequip action, equip slot actions, and the same for place mode) are present in the mapping context.
Add entries to the EquipSlotActions
list, and the corresponding slots will have the right inputs.
If you're also using the place mode, add its slots to PlaceModeSlotActions
The M2M_ItemVisualsComponent
is a recent addition to the inventory system, to handle showing cosmetic details of your equipped items/devices to other players.
Items with visuals will occupy particular "slots" on the visuals component, representing what type of visual object they are (e.g. a held gadget, a piece of headgear or the like). This uses the EM2_ItemVisualsSlot
enum, which currently only contains the Selected
value - meaning the quickbar item you currently have selected.
Since the majority of the inventory system is "owner only" (only you and the server know what your inventory is), we need to choose what data we send to other nearby clients. We do this using "foreground properties". Any Foreground
properties on the selected item in the Inventory Component (set from the server) are replicated on the foreground in the Item Visuals Component. Any ForegroundClientAuth
properties do the same, but set from the authoritative client. You can then get these foreground properties for the item in a given slot through the M2M_ItemVisualsComponent
using GetVisualSlotProperty
.
In the CustomItemDetails
in your device's PDA, if it has a M2_ItemVisualsDetails
, this will be spawned for all foreground actors that have the item selected. In this details object, you can provide a class to handle the visuals, extending M2_ItemVisualsBase
The M2_ItemVisualsBase
has some implementable events to handle the visuals of the item.
Initialize
- called when the visuals object is first created (when we receive the player's item in our foreground)
TearDown
- called when the visuals object is torn down (when we receive that the item was unequipped/changed)
NotifyNetworkLevelUpdated
- called when the player whose item we're visualising changes network level (e.g. moving from the foreground to the midground/background/back). We can control what happens in this case, e.g. cleaning up the item.
NotifyRenderTargetUpdated
- called when the player's render target updates, either due to their model changing, or them changing to the animated crowd and back.
NotifyDetailsUpdated
- called when the visuals component receives a foreground (client or server auth) property update. You can use this to update
For more details on how to use the item visuals object to provide visuals for your device, see Item Visuals.
The M2M_InventoryMetadataComponent
is used to store additional information about items in your inventory, which aren't part of the core logic found in the inventory component. So far there are two things:
Favourited items are placed ahead of unfavourited items in your inventory view.
NOTE: This feature is WIP, and is missing functionality. Currently favourites only persist for the duration of one play session.
If you disable an item in your inventory, it will mean that it cannot be equipped/used. If the item is in your quickbar, it will be disabled (and deselected if you had it selected).
This can be controlled via the M2M_InventoryMetadataComponent::SetItemEnabled
method
If you are adding new keys that don't have mappings already in the DA_InputIconMap
, you will need to make your own icon map too, to add the required icons. See for details on how to do this.