Inventory system with unique item issue, what did I miss ?

Hello everyone,
I’m trying to create an inventory system that can store all types of items (a rock, a weapon, a bucket…) in a multiplayer game.

So I started following common tutorials on the internet, and they all work the same way. I created a datatable based on a structure S_Item (ItemID, name, description, mesh). My player has an S_Item array as an “inventory” property, and it works. Each actor in the world has an ItemID, so when I pick it up, I can retrieve all the information and store it in my inventory (S_Items array).

But now, I want my items to be specific or unique. For example, let’s consider a Bucket item. A bucket is a standard S_Item with two extra properties: MaxQuantity and CurrentQuantity of water in it. My question can also be applied to random stats for a weapon, the number of ammo in a gun, or durability on a weapon.

And now starts my endless research for a solution :slight_smile:

  1. Structure Inheritance
    There is no inheritance from structure, so I can’t create a specific structure for my bucket (and other containers) and add it to my inventory’s S_Items array. I could add my two extra properties to the S_Item base struct, but then I would need to add properties for weapons, potions, and so on. In the end, my S_Item would have 500 properties, and 95% of them would be empty.
    So, this is not the right solution.

  2. UObject
    Instead of using structures, I tried using UObjects. I can create my S_Item and my Bucket with inheritance. My inventory will be a (UObject) S_Item array and can store everything. But sadly, UObjects cannot be saved, so I can’t use the save game functionality.
    This also seems not to be the right solution.

  3. Data Assets
    I saw that data assets can inherit, so my Bucket can be a child of an S_Item data asset. I create my base item and my bucket with inheritance, and I construct an object based on my data asset and add them to my inventory. I can also modify them (change the current water quantity), so far so good. But like UObjects, these actors can’t be saved.
    Again, not the right solution.

  4. Actor
    Actors can inherit and be used for my inventory, but actors are spawned in the world, not in my inventory. Idon’t want to put all my items in the world, even hidden. While this may work, it’s definitely a bad way to do it, and it can’t be saved.
    Not a good solution either.

The last thing I have in mind, but I didn’t try it because it seems really complicated for what I think is a simple use case, is to use the data asset method (3) and, for all types of data assets, create a matching structure (so duplicate all base properties in dozens of structures). Then, when I save, I have to iterate over every item on the player (but also in all chests, items on the ground, etc.), make a struct depending on the type of the asset to match the item data asset, copy every value, and then save it. My game is a multiplayer game, so I’m going to save hundreds of items, and I wonder how long it will take and how it will affect performance.

After days of research, I’m open to any new suggestions. If you have a tutorial, a post, or something where an inventory can store dynamic items (my example was with the bucket, but it’s also the case for weapon durability, ammo, random stats, anything that makes an item unique in the game), I would love to read it.

Thanks for your help, sorry for the long post and my English :slight_smile:

Inventory Systems (IS) should be designed from the ground up considering the entire scope of items that it will contain and their customizations. Every IS is unique to the project.

Group items by Type and Same data needs.
Weapons, Ammo, Gear, Grenades, Meds, Boosters, etc.

Define the data needs of each group. If items in a group diverge create a sub type classification.

Weapons: [AR, DMR, SR, SMG, LMG, Pistol, Shotgun]
Gear: [Helmet, Vest, BackPack]

Develop a universal Item Identification structure that ALL items will use. This will ease your interaction and lookup code.

For example you can use GameplayTags as ItemID

Items
Items.Weapon
Items.Weapon.AK47

An ID of Items.Weapon.AK47 tells me the Actor is a world item (player can add it to inventory). It’s a Weapon and it’s an AK47.

Using string nodes I can split the gameplay tag into its chunks [Item, Weapon, AK47]. This can be used to tell me to use the weapons data table and the row name ak47.


Define every item type, item grouping/sub grouping, base needs of each before starting on the IS structure.

End of Day an Inventory system should be simplistic identification data and counts (int) where needed. You can use the ID’s of items to do data table lookups to get Icons, classes, meshes and any other UI elements.

Thanks for your detailed answer :slight_smile: I understand it, and for now, this is how my inventory is defined.

But my problem is to add some random stats or values to this.

If I take your example of an AK47, I understand there is a standard definition for the AK47 in my datatable, but if I have 3 AK47 in my inventory:

  1. durability 80.3%, 21 bullets left, +3% DPS damage
  2. durability 60.7%, 19 bullets left, +8% DPS damage
  3. durability 10.0%, 5 bullets left, +5% accuracy

Does that mean each of those possibilities has to be a line in the datatable?
I can’t see how this can be implemented because I can’t create all the possibilities (it can be millions of possibilities for one item), and I don’t think I need to create a line every time a bullet is fired or the durability lost 0.1%. The datatable will be huge and always updated for every player, enemy, etc.

I took this example for one weapon, but I want to make something more like a Diablo inventory, with 8 equipment slots on the player. Each item has 5 random stats ([50-100] strength, [50-100] stamina…) + 2 random bonuses ([1-10]% DPS, [1-5]% attack speed) + durability [0-100]%. The possibilities are almost infinite.

If you can add somes details details in your AK47 example, how you can manage just the durability (float)[0.0-100.0]%, in what type of object you store the value when it’s an actor in the world, and where you keep the value when it’s in your inventory? (And how you can save this type of object).

Thanks a lot again :slight_smile:

I do it like this,

I use DataAssets for the Weapon/Item ID that doesnt change
(name, desc, icon, actorclass etc)

I create a struct for the ItemInstance (Actually i use UObjects but as you said you need a struct to save eventually)

the instance has the dynamic data like durability, currentammo etc

but the way i do that is to create an AttributeStruct
(base value, current value, additive, multipliers etc)

example: AK47 ammostruct (base ammo 30, additive 5 from extended clip)

so now all attributes are of type struct and i can store them in an array in the ItemInstance

so to expand, a weapon can have in its array, durability, ammo, DPS, accuracy
and an item may have just durability, quantity etc

Thank you for you replie :slight_smile:

So if I understand correctly, it’s some kind of key/value array to store all extra information ?
You said a weapon can have its array so item something like that at the end ?

Struct Weapon :

  • ItemID (from data asset)
  • Name (from data asset)
  • BaseDurability (from data asset)
  • BaseAmmo (from data asset)
  • Array [key,value] :
    – currentDurability : 80 (dynamic, from item instance)
    – currentAmmo : 15 (dynamic, from item instance)

Is that what you mean when you say : “so now all attributes are of type struct and i can store them in an array in the ItemInstance” ?

Thank you :slight_smile:

I use multiple data tables for weapons.

  • Base weapon config (subtype, slot options, icon, firing modes, ammo type, reticle, UI stuff etc)
  • Weapon ballistics and handling (recoil, sway, drag, range, gravity, muzzle velocity, modifiers, ads speed modifiers etc)
  • Weapon attachment modifiers
  • etc etc

Each “Type” of item (Weapons, Ammo, Gear, Grenades, Meds, Boosters, etc.) has its own base data table.

I’ll have over 150 unique items in my game with varying configs, specs etc. So it only makes sense to break them up into groups with specific tables to handle all the data.

You’d store these directly in the weapons themselves. I’m assuming said weapon would be a spawned actor and your character/inventory sys would have an actor reference to it. This is how I’m handling mine.

Server spawns and attaches the weapon to the pawn. It sets an actor reference in the Inventory for the given weapon. The weapon class does DT lookups and sets its configs [structs].

The inventory UI references the slot actor for the weapon and makes specific calls for data. This can be done via custom function/events in the weapon class or via interface.

Things like Durability, DPS bonus, Ammo would be handled directly in the weapon class and stored there.

Hi, sorry for my multiple questions but once again I’m a little bit lost :sob:

When you say “You’d store these directly in the weapons themselves. I’m assuming said weapon would be a spawned actor and your character/inventory sys would have an actor reference to it.”

The problem is there, if a weapon is in my inventory it’s not spawn in the world and this is my main issue, how to keep those dynamic information in something that is not an actor (because it’s not in the world) and not a struct (because I can’t mix different struct in the same inventory array on my character).

If you have some screenshot of blueprint or a video maybe I will understand easily ?

Thanks again :slight_smile:

Keep the information stored as a struct in an inventory component and put that component on your pawn. Anything dynamic goes in that struct. anything constant goes in a datatable. spawned “items” such as weapons don’t hold state relevant to the inventory.

I don’t think you need to mix structs for anything in the inventory. If you have a rifle that requires 3 bullets to shoot you just let the rifle check the inventory component for the rifle and reserve 3 bullets?

I got very far by using a generic sounding attribute like “durability” for cases such as water in a bucket and durability on a rifle. Anything non generic would bloat the entire system but can probably be avoided.

  • Edit

What about using JSON? This is one of those very rare cases I’d just like the flexibility of javascript to build structures / objects from scratch without being bound to a certain format. You will want it when you want the possibility for 9999 item types without pre programming them into a framework bloating it just in case.

I must say I haven’t tried this in c++ but why not :slight_smile: . I’m making the assumption this does not require you to convert between struct and json.

https://www.youtube.com/watch?v=4wJ45mrzrkM

How to retrieve single text field from Json? - #3 by GraeChan

What I did was linking datatables. If an item’s datatable entry contains a pointer to another datatable “weapon datatable” containing the weapon specs, it is a weapon. The downside is this assumes there will be weapons in the game it is used in, making it less fit as a generic framework. Upside is you have all the data linked, bit like expanding data on the original struct into sub categories of an item.

My weapons (3) are spawned and attached to the character. If unequipped (not in hand, using) they are attached to the pawns back (sockets).

My inventory has an Actor Obj reference variable for each weapon since they are “dynamic” items. All of the Weapons “special” data that’s used for inventory is stored in the class itself.

Most games do this. They don’t spawn and destroy actors when you switch weapons. They hide and unhide them. Spawning and Destroying are performance hitters. Imagine hot swapping a weapon in game, back and forth and how much spawn/destroy load you’re adding.

Definitely can’t do this with multiplayer. Server has to spawn weapons. Clients have to RPC and request the spawn. So every time you want to switch a weapon you RPC the server, it spawns it, destroys old, attaches new, updates inventory. Madness.

I thought about going that route, but decided against it. Eventually I’ll be using Run-time data tables. All my DT data will be in an MySQL or Oracle DB. Servers will have a C++ API that will request the latest DT’s if changes are pushed.

This allows me to make on the fly changes to specs, and multiple people can work on the data as needed. Essentially a Team can update items on the fly and I don’t have to push a patch to clients.

1 Like

Interesting approach, I suppose for an online game? I’ve not yet dived into networking but don’t you risk clients having a DT mismatch (and the server flagging them) if you don’t take them offline for a patch and enforce versioning? Or did you have a specific reason for this choice?

Maybe what I think is complete nonsense but my immediate thought is “what if” one DT is outdated because it did not download, does the server handle client mismatches, etc. I like control.

yes, Online game MMOFPS w/on-demand cloud VM servers.

Server and clients will use ACK system and other checks to validate DT’s.
Server will be notified of changes from a central hub (probably the MM server that’ll handle spin ups).
Clients will be notified on game boot. If the changes happen after that point a server join… OnPostLogin event or other could push the changes. They’ll download them during the level loading process.

Jared already has a base model runtime DT plugin on the marketplace.
https://www.unrealengine.com/marketplace/en-US/product/runtime-datatable

1 Like

yep thats how i do it,

you can save DataAssets so you only need the ItemID in the struct then you can access that to get the Name, Icon etc

otherwise if i want a value like durability i search the Array if it exists, if it doesnt its 0 otherwise i retrieve the current value

Thanks all of you for your answer I think it’s clearer now :slight_smile: