Inventory System by Opsive WIP

chrisk

Active member
Hi, Singemdoko, Are you still here?
I'm just checking to see how you are doing on the inventory system.
My inventory pretty much had to redesign the whole item/inventory system.
For me, it's simply impossible to workaround UCC item/inventory system.
I was wondering what kind of approach you are taking and if you are making some progress.

Cheers!
 
Hi,

Sorry for not giving an update in a while. The asset is progressing at a good pace. I am still working on the standalone inventory asset and we won't start the integration with the other Opsive assets until I am finished.
We do not have a release window, we will release this asset once it is ready.

The good news is that I am now working almost full time on the inventory asset.
I plan to post a "first draft" framework design doc once I have something that is robust and tested. I look forward to reading your comments, concerns and feedback.
 

chrisk

Active member
That's great news! Likewise, I look forward to reviewing it and hopefully I can base off of your asset instead. It will make patching UCC much easier, assuming that your inventory system will seamlessly be integrated into UCC.
Right now my inventory system has too many changes and it is very difficult to integrate UCC patches.
 

Justin

Administrator
Staff member
This is a separate asset that we don't have an ETA for yet. @Sangemdoko is making great progress on it and we should have some news soon.
 

Rastos78

New member
This is a separate asset that we don't have an ETA for yet. @Sangemdoko is making great progress on it and we should have some news soon.
Thank you and sorry for the double post.

I am integrating with Inventory and Weapon Modding (ICWM).

But I don't know if I should opt for rucksack integration instead, because I need to manage several inventories at once.

I'm a little confused but I'll probably finish what I started, and wait for your new asset.

Sorry about my English.
 
Part 1 : Introduction + Editor basics


Hello Everyone,


It took a while but I am back with an update on the progress of the inventory system. We have now pretty much locked down the core framework design. As stated before, this is a stand-alone asset, which means it will be usable on its own and will compete with the other inventory solutions on the asset store. We are bringing a solution that we believe is powerful, flexible and scalable while still being extremely easy to use, even with minimal programming knowledge. When it comes to items and their attribute values we believe that iteration time must be reduced to a minimum as it allows the creators to spend more time on the creative parts instead of tweaking values in multiple places.


Once again I would appreciate your feedback on the framework design, component namings, and on the Editor UI. Please let me know of any of your concerns on the subject and the limitations you encountered on other systems, which you would like to be addressed here.


Note that we have not started the integration with the character controllers yet. This will come after we polish the framework, write the in-game UI scripts and create the demo scenes. We will release the framework after we do all that, so you can expect it to still take a while.


If you read the first post you will see that we have made some changes to the requirements and goals. Be advised that any of the following statements can and will most likely change, but the main idea will stay the same.


There is so much content that I want to show you that it couldn’t fit in one post. It will take 4 posts.


  1. Introduction + Editor window basics
  2. Advanced concepts + Editor examples
  3. Item Action & crafting + more details on Attributes
  4. Conclusion and what’s next


With that out of the way please let me introduce the Inventory System plan V0.2:


Inventory System

The Inventory system is an asset made by Opsive that will help developers create their own inventory system for their game. Inventories can vastly change from one game to another. We do not plan on creating all possible inventory systems, instead we give a powerful modular and scalable framework that can enable anyone to make a complex inventory system in no time.

Key information
Our goal:
Make an inventory framework that is modular and scalable. We are aiming at enabling our customers to create all types of inventories with ease. The asset should be usable by non-programmers to create standard inventories you find in popular games. But the true value comes from being able to extend the framework to create your very own unique inventory system.


I believe the best way to achieve this goal is to create a powerful core framework and polish it by creating a few mini-game demos and inventory UI templates of popular game genre. This will ensure that the framework is flexible, modular and scalable. I truly believe that the only way to know that a tool is good is by using it in multiple real-world scenarios.


Target audience :
Non-programmers for people who want to create any types of items while taking advantage of the templates to create interesting inventories.
Experienced programmers and beginner programmers who are dedicated to reading our documentation and follow our tutorials to extend a template or write their own from scratch using the inventory system framework.


Unity Version :

*Important* The minimum version will be 2019.1. We have decided to take advantage of the new Editor UI, UIElements, to create the editor window, it did not make sense to create the Editor UI twice just so it could be used on older Unity versions. Especially since by the time we release this tool, most developers will have moved to 2019.X-2020.X

Our Core (subject to change):
The only way to make a scalable and flexible inventory system that is coherent and rigid is by adding some rules. These rules are there to make sure the items are organized in a structured and logical way. The way we achieve that is with the following.


We have a hierarchy of three components that will shape the item. These are the ItemCategory, the ItemDefinition and the Item itself. This is all possible thanks to a system we call the Attribute system


An Attribute is simply a name and a value of any type. Think of it as a member of a class, where the class is the item. The power of the attribute is being able to inherit, override or modify another attribute value.


First, the ItemCategory is used to define the attributes that are available on all the items that will be part of that category


Second, the ItemDefinition creates a template for an item. It assigns values to the attributes that are defined by its category.


Third, the Item is created from the ItemDefinition and can override any of the attribute values to make it completely unique


A simple example of creating two potions with different values could be done this way:

  1. ItemCategory: “Consumable” category with a “healAmount” attribute
  2. ItemDefintion: “Potion” definition with “healAmount” of 5
  3. Item 1: potion with “healAmount” of 5
  4. Item 2: potion with “healAmount” of 6

Let us see how it works in the Editor

The Inventory Database Editor

The first step is to create a new Inventory System Database asset. This will store the references to all the categories and ItemDefinitions that you create in the editor. Normally you should have a single database asset per project.




Now that the database is created and selected, the next step is to create a category. Here we create a Consumable category with a “Required” Item Attribute “healAmount”. We set the default value of this attribute to 3.




Note that there are three different attribute Lists.

  1. The Category attribute List is used for attributes that are common for all items in this category. An example would be a Sprite image, a color or anything that can differentiate it from other categories of items
  2. The Required ItemDefinition Attributes are attributes that are required to exist on all the ItemDefinitions in that category. The value of the attribute can be set directly on the ItemDefinition. An example of an ItemDefinition Attribute is a fixed value for all items with that ItemDefinition, meaning a “baseDamage” or “buyPrice”
  3. The Required Item Attribute are attributes that are required on the item itself. The item attributes can be set directly in the inspector and if the Category is set to mutable to Item attributes are even allowed to change values at runtime. In our example we will use “healAmount” as an ItemAttribute

With the Category Created we can make the “Potion” ItemDefinition. We can also override the healAmount to set its default value to 5.




Note that there are two different attribute Lists.

  1. The ItemDefinitionAttributes List will have the Required ItemDefinition Attributes which are defined on the Category of the ItemDefinition. You can override the value of these attributes if you wish so, by default the attributes will inherit the value that was set in the category.
  2. The Default Item Attributes List will have the Required Item Attributes which are defined on the Category of the ItemDefinition. Note the specified “Default” that’s because any item that is created at runtime can override these “default” values. When an Item is created at runtime it will by default inherit the attribute values of the ItemDefinition Default Item.

Now that we have our potion created we can add it to an inventory default loadout. We add two potions. One with the “healAmount” overridden to a new value of 6. And the other which simply inherits its value 5 from the Default Item of the ItemDefinition.





With this we have successfully added Items in an inventory. Note that since the second potion inherits its value from the default Item, changing the DefaultItem “healAmount” value will, as you would expect, change the second potion “healAmount” value.


So with the basics out of the way lets see some cool features of this framework with some examples.
 
Part 2: Advanced concepts + Editor examples


ItemDefinition Parenting (ItemDefinition variants) & Modify Attribute
What if we wanted to make a BigPotion and its default “healAmout” should always be double the Potion Default Item “healAmount” value. Most frameworks would require you to manually change the BigPotion “healAmount” every time the Potion “healAmount” is tweaked, and if you forget to change it then you might experience unexpected results in your game. So how do we achieve this.


First we create the “BigPotion”, we then set its parent to “Potion”. As we do so the “healAmount” default value will be inherited from “Potion”. Now we can use the magic of the “Modify” attribute which let us use a string expression to compute simple things.


Note that Modify uses Regex expressions and external library called Ncalc to resolve the expression, we may change to something else before release. Please let use know What you would like to achieve with the Modify attribute variant type so that we can plan accordingly.


In our case we want to double the value that we are inheriting. So the expression looks like this:

<Inherited>*2





The modify variant type does not only allow us to evaluate an expression with the inherited value we can also get values of other attributes!


What about making the potions have a “healAmount” value in between a max and min?


To do this, first I would create a “minHealAmount” and a “maxHealAmount” Required ItemDefinition attribute on the category. I would change “healAmount” to make a float. The healAmount can be set to modify in the category with this expression: “([maxHealAmount]-[minHealAmount])*<Override>+[minHealAmount]”. The override value of “healAmount” can be set from 0-1 which will return a value between the min and max. When this attribute is inherited, the values of the attributes inside the expression are relative the attribute where the value is retrieved. Meaning that even though BigPotion and Potion will both be set to inherit the “healAmount” attribute value they can have different resulting values. This will make sense when you see it in action.


Note In the case that you do not want to use the relative attribute value in the expression but instead use the value of the attribute where the expression is defined, you can use the ‘$’ symbol. So imagine we had $<healAmount> in the expression above and that the Category Required Item Attribute “healAmount” override value was 0, the “healAmount” would always return the same value as “minHealAmount” for all the Items in the category no matter the override value of “healAmount”.




As you can see in the example above I set the Potion max:10, min:3 and the healAmount override to 0.5, which gives me a final result for healAmount of 6.5

For BigPotion I have a max: 15, min: 5 and an override of 0.3, which result in a default “healAmount” value of 8.


The trick here is that the “healAmount” attribute is set to modify in the Category and it is set on inherit on the default Item. You can imagine now that I could create a script that spawns potions with a random “healAmount” override value between 0-1 and that I would result in spawning potions with “healAmouts” with random values between the max and min set by the itemDefinition.
Of course if that was your use case you could also simply do the calculation in your random potion spawn script and set the “healAmount” to variantType: override with an override value between min and max.
There is a lot of flexibility and plenty of solutions for a single problem, so it is up to you to decide what suits you best..


ItemCategoryParenting

So far we’ve seen that we can parent ItemDefinitions and inherit, override or modify the attributes of the parent. That is great but in most games we have more than one Item type or rather category. You can have Weapons, KeyItems, Consumables, etc.. And sometimes the items in those categories have properties that overlap. For example you could view, buy and sell both a weapon and a consumable item. You could also view a key item but maybe you can only find keyItems and therefore you wouldn’t allow to sell or buy them.


To make this structure I would create multiple categories

  • Buyable: has a “buyPriceAttribute”
  • Sellable: has a “sellPriceAttribute”
  • BuyableSellable: inherits Buyable and Sellable
  • Viewable: has a “description”, “categoryIcon”, “ItemIcon” attribute
  • Weapon: inherits from BuyableSellable and Viewable has “damage”
  • Consumable: inherits BuyableSellable and Viewable has “healAmount”
  • KeyItem: inherits Viewable
You might be wondering why I have Buyable and Sellable separate. We can imagine that we might change our requirements and think that we may want to buy keyItems even though we can’t sell them. In that case why have BuyableSellable? Simply to keep things organized because most categories will be both Buyable and Sellable at the same time. It is up to you to decide how to organize your items in a way that makes sense to you and your team.


Also note that buyPrice and sellPrice could really be anything. In this case we will use ints, but we could use a currency system instead. This could be done by creating a new “Currency” category with a “gold”, “gem”, etc.. as ItemDefinitions. Then we could set the price attributes to lists of ItemDefinitions amounts. Another option could be to create a custom attribute type from a struct of hard coded currencies. It really depends on your game and what you want to achieve.


Here is how parenting works for categories (It looks like I forgot to set some attributes to override):





Note that the little color boxes next of the attribute Names show which category is the source of the attribute and where the attribute is inherited from. Hovering over those little boxes gives you the name of these objects. The characters meanings are:

  • “N”: does not inherit anything the inherit value is set to default(T)
  • “C”: inherits from a category
  • “D”: inherits from a definition
  • “I”: inherits from a default Item

In the example above you see that I am changing the IsMutable and IsAbstract toggles

  • IsMutable enables the item to change attribute values at runtime. When it is Immutable the system can save some memory because it merges items that are identical.
  • IsAbstract simply tells that the Category cannot have itemDefinitions directly of that category. Example we should not have an itemDefinition directly under Buyable because it does not make sense. This helps keeping things clean and organized.

For those who are wondering what is the RelationShip foldout, here is what it looks like when it is opened:





You can see the descendants, ancestors and ItemDefinition of the category. The GX shows the generation of the ancestor G1 being direct child or parent.
You can click on the names to open up its object view.


And with that we pretty much wrap up the editor. As you might expect the editor is in its early stages so some things may look a bit off. If you have any comments on the editor please let me know.



Now that we have some categories, definitions and some items in our inventory default loadout we can focus on adding functionality. For example, how would we go about adding hp to a character when consuming an item? To do that, we recommend using ItemActions.
 
Part 3: Item Action & crafting + more details on Attributes


Item Actions

ItemAction is an abstract scriptable object which has three functions:


  1. Abstract bool CanApply( Item, Inventory ) : returns true if the action can be applied
  2. Virtual void ApplyAction( Item, Inventory ) : checks if CanApply is true and then calls ApplyActionInternal.
  3. Abstract void ApplyActionInternal( Item, Inventory) : applies the actions

So for example for a ConsumeAction we could do :

  1. CanApply: returns true if the Item is a “Consumable” item && if the inventory contains the item
  2. ApplyActionInternal: Finds the character from the inventory and increase its hp by “healAmount”



Take Note of the m_RestoredAmount property. Instead of returning the restore value with the function Apply function (which would create boxing) we simply set a property to that value. If for some reason that value is needed we can simply retrieve it each time after calling ApplyAction. You can imagine that we can have plenty of properties which we could set before and/or retrieve after calling the ApplyAction.



In this case we need to add the consumable object in the inspector, which some people may dislike since the only ItemCategory which should be specified here is the Consumable category since it is the only one that has a “healAmount” attribute. For that exact reason we can auto-generate a script with all the names of ItemDefinition, Categories and attributes so that you can retrieve them directly in code without being scared of refactoring names or of making spelling mistakes.


So the code would look like this:








You can imagine that with the ItemActions you can do pretty much whatever you want. We will make a few general ones and some specific ones for the Demo scenes. The goal here is that we want to easily map an ItemAction to a in-game UI Button.



Another thing we’ve looked into is crafting. Crafting can be very simple as it can be extremely complex. For that we have a class CratingBase which uses two structs CraftingIngredients and CraftingResult:





As the ItemAction we first check if the operation is valid before acting on it. This time we pass a list of items instead of a single one. And we return a result of the operation


You can imagine that we could make something really simple by setting some ItemDefinitions as ingredients and having an Item as result. Example 1 stick + 1 coal = 1 torch.

But you can also imagine something more complex where the attribute values of the ingredient items can affect the result of the craft, or where the character stats can decide the quality of the crafted item. This can be done by knowing the categories or directly the attribute names of the items being crafted and using the attributes of the ingredient item to compute the resulting item(s).


The attribute system helps making complex crafting systems were attribute values and external influences can affect the resulting crafted item. These complex crafting systems require more thought on the part of the creator. We will provide some examples of what can be done to give you a push in the right direction.




More Details on Attributes

For those who are interested here is a UML of the classes connected to the AttributeBase class






Attributes
attributes are used by Category, ItemDefinition and Item. It consists of a name and a value of any type. When an attribute is added to one of the aforementioned classes it can be set to Inherit , Override or Modify the value of its parent.


  • Override: The value returned is the “OverrideValue”, which is set on the attribute
  • Inherit: The value returned is taken from another attribute which this attribute inherits from
  • Modify: The “modifyExpression” is evaluated to compute a value for the attribute. The modifyExpression can take other attribute values from the same collection or family
If there is no parent the inherited value is the next value in the echelon.

  • Item inherits from ItemDefinition DefaultItem
  • Default Item inherits from parent or Category
  • ItemDefinition inherits from parent or Category
  • Category inherits from parent or attribute type default value.

Categories can have multiple parents, meaning that it will try to get its attribute inherit value from one of its parents. Starting with parent at element 0 and going up, the first attribute match will be chosen to be the inherited value. Therefore the order of the Category parents can in fact affect the attribute values.


Most common types are available out of the box. But some people might want to add their own value types. To do so one must extend the generic class Attribute<T> where T is the attribute value type.


Modify is the most interesting of the attribute functions. It enables you to write an expression as a string, which can then be evaluated to give a new value. The expression can be evaluated in any way you want. The great thing about the expression is that it can grab other attribute values, the inherited value, the override value, the type default value and any other parameters you which to create.


As it is impossible to make a modify expression evaluator that works for all types it is recommended to create your own modify evaluator logic for each VariantAttribute type. For consistency we recommend to have a common syntax for all of them.

Modify expression syntax
The modify expression is very powerful as it lets you grab values of other attributes as well as perform some logic on them.


Important: If an attribute “A1” inherits from another attribute “A2”, which is set to “modify”, the attributes that are part of the expression will be picked from the perspective of the attribute that first requested the value, in this case “A1”. If the values should be picked from the perspective of the attribute holding the expression, in this case “A2”, one can add the ‘$’ character in front of the attribute name.


As the expression is a string you can create your very own syntax by writing your own parser. But for consistency it is recommended to use the syntax below to get other attribute values.

  • [myOtherAttribute] : gets the value of an attribute named “myOtherAttribute”
  • <Override> : gets the override value
  • <Inherited> : gets the inherited value
  • $ : the $ sign can be added in front of any “get value”. It will get the value of the attribute from the perspective of the attribute holding the expression.
    Example: “$[myOtherAttribute]” or “$<Inherited>”

It is encouraged to write additional or specific functions to the parser for any of the custom created VariantAttributes as it will help the item database creator to have more freedom.



There is still a lot of work to do but with this sneak peek I hope you see the simplicity, power and flexibility of our framework.
 
Part 4 : Conclusion and what’s next


The next step will be to increase performance and reduce garbage allocations to a minimum. This will take quite a bit of time. Once I have done a primary stage optimization of the core I will work on the in game UI and the Demo/template scenes, which I am sure will allow me to find some areas of the framework and Editor UI which need a bit more polish.


The first Demo I will work on is a jrpg like inventory with one inventory shared among 4 characters.The goal will be to showcase

  • Change stats on equip/unequip
  • Different actions (Consume equip) for the same item
  • Buy/Sell/Craft Single currency & simple crafting
  • Pickup/drop items 2D
  • Having 4 characters with one shared inventory will test the itemCollection restrictions, example two characters should not be able to equip the same item
  • Classic retro JRPG UI


The second Demo will be a first person shooter like Inventory

  • Item pickup/drop 3D
  • Item using another item (gun using bullets) changing resulting damage
  • Shooter inventory UI


The final Demo will be an action rpg like Inventory

  • Inventory where item size & weight matters
  • UI with drag and drop
  • Item with more Items inside (bag)
  • Sell/Buy/Craft multi currency and complex crafting system

As I will come closer to implementing the last template, Justin and I will work on integrating the Inventory asset with the character controller family. And we will be making a demo scene with a template UI for a 3rd person shooter. People have showed interest for a Template similar to a “Last Of Us” Inventory UI. So we might go in that direction.


If there is anything you would like to be part of the templates, please let me know. Please keep your request reasonable. The features I will focus on are the ones that are useful for a great majority, we want to keep things game agnostic with some simple examples.


So as a recap:

Main features (subject to change) :
  • Inventory system Database Editor window (started)
  • Attribute system (started)
  • Inventory and ItemCollections (started)
  • Shops/Vendors/Buyers (started)
  • Crafting system (started)
  • Item interactions/actions (started)
  • Modular UI system (Mouse&Keyboard, Joystick/gamepad and touch support) (not started)
  • Templates for popular inventory systems and UI (not started)
Other Additional features (subject to change) (not started):
  • Save/Load system (for scene transitions)
  • Event system shared with UCC
  • Object Pool shared with UCC
Other Features Coming After release (subject to change) :
  • Import/export database
  • Multi-language support
  • Multiplayer support


This series of posts was pretty long but I hope it makes you excited for the result. I look forward to all your feedback and I’ll answer any questions the best I can. Remember nothing is completely set into stone so feel free to let me know anything you would like to change/improve. I will continue to work very hard on this asset to make it the best it can be. I’ll give you the next update in a few months once I complete the first demo/template.
 

chrisk

Active member
@Sangemdoko , Wow! very long posts with very detailed explanation. I really like the design and everything seems very logical, including the naming, I can't wait till I try it.

If I were to add one thing, there is one piece missing, that is the Attachment System where you can define attachment items and it can be attached to other items(where applicable) to enhance ability(add/remove attribute values) or provide extra action functionality.

In shooter type of games, attachments can be like scope, muzzle, magazine, and etc.
In RPG type of game, attachments can be like gem-stones or extra ornaments to blades and such.

In my game, I implemented the Attachment System using Socket System. Each item can have one Bolt Socket and list of Nut Sockets. A socket is basically a structure with a name and a location (position/rotation). To attach an item, for example, if you find a nut socket from list of nut sockets on the parent item and it matches the bolt socket from self, it can be attached.


Other than that, everything should be minor stuff like, stackability, Active slots(left/right hands), weight limit system that does not require structural changes.

With given enough time, I have confidence that you will have very nice Inventory system with compelling examples, however, I have a very big concern that how tight it will integrate into UCC. It will require a major rewrite of UCC inventory system. I guess it depends on Jason if he will replace UCC inventory runtime with yours. In my opinion, the Inventory system in UCC is probably the worst system(it's hard to understand, has many misnomers, hard to extend, won't scale up for many items) and I hope you are in close contact with him and let us know if the tight integration is a possibility.

Cheers!
 
Hi @chrisk I'm glad you like the design and find everything logical.

The attachment system is something I haven't really thought about, I'm glad you brought it up. My top of the head implementation would be to create an attribute with a "Attachment" Type array. Where the Attachment could be a struct of an Item reference and a position. The attribute would be defined as an Item attribute so that I could swap out the attachments of my weapons/armors at runtime.

I'll definitely add it to my todo list for the second and third demo/template scene as it will go well for FPS and RPG games.

The default stackability goes hand in hand with mutability and the demos will show how that works. I also plan to add an abstraction layer in one of the demos to show how to have a custom stackability and have bags (items containing other items in the inventory). That will most likely be in the third demo

Weight limit will be simple to implement and will be part of the RPG demo

Active slots are not part of the inventory system. The inventory only structures and organizes the items. There will be actions to equip items that can check if an item is already equipped ect... But whether a slot is active or not should be on the character controller in my opinion.

You shouldn't be concerned about the integration with UCC. I chat with Justin pretty much every single day about the inventory system. We plan to make a completely seamless integration with the inventory system. That will require some changes in the UCC side to add a layer of abstraction so that it can either use its default inventory system, the inventory system I'm working on or even other custom solutions.

As mentioned before we will work on that integration once I am almost done with development on this asset. So I can't say anything in detail just yet.
 

chrisk

Active member
Awesome!! Everything sounds really good! However, having an extra layer on top of existing UCC inventory system will not work because UCC inventory system is not designed with extensions (it can just add new items monolith ways). For instance, ItemType should really be the ItemDefinition but ItemType is too deeply rooted in UCC. If we have to work with both, having the two different systems will confuse the many. I believe the best is to replace the UCC inventory system with your base classes and UCC to extend them separately if necessary. I don't any other better way to do it. I believe it will save many headaches and also save time in the long run. Have great day~ ^^
 
Hi @chrisk, sorry for not being clear. By abstraction layer I meant a layer under the current implementation instead of above. This will require some refactoring and a few changes to the UCC framework but it should allow us to integrate this inventory, and for other people to create custom inventory systems if they wish to, with less problems. I hope that makes sense. Anyways we are far from that point, we'll have more thought on the actual integration once we get near the deadline
 
Hi @David3D,
I'm sorry I can't give you a release date window because there is still so much to do. There are still features that we haven't started implementing yet. In the next post update I'll make a list of features we have planned and ask the community what features people want at launch and which ones can wait after launch. The release date will greatly depend on that.
 
Top