Ultimate Inventory System WIP

magique

Active member
This looks really great. Is there a beta test going on yet or will there be?

[EDIT]
I asked on discord forums and was told no beta but a pre-release will go on Opsive store at some point in the near future.
 
Last edited:

Sangemdoko

Moderator
Staff member
UY4PZ1LcTkEugsLWf8TWhGcDK0rMBSi9D40M4OwwvHvDwMDVfFMlLJ4bvtisSq6OJl9TfJFAPHmWkZrxljOH-R3SDnBPmU5q0ZKTkhNjiCke4QYZBj-R-2VMjRLgljqSssOCH8LG

Part 4 : Spawning items in the scene as pickups or usable equippables

So far we saw how the items can be used from the inventory using ItemActions. I also showcased items being equipped but haven’t talked about the Equipper component. But first I want to iterate on the difference between an Item and an ItemObject. An itemObject is a MonoBehaviour which can be binded to an Item. This lets you give the item a shape in the game world. Once the item is in the game world it can be used for pickups, equipment and more.

Let’s first look at item pickups. There are many pickup components out of the box. Such as the item pickup, the item amount pickup, the inventory pickup, the currency pickup, the random inventory pickup, etc…
They are all similar in the way they need to be set up. We will look at the item pickup here. These are the components on an item pickup:
dbFA8UUZlyXS5rytZGgVYWTjLHd5esFFLAuYJmmIBwYNDKT1KiGFyZRO3is9-fr48IxNNMVCftVoN5YPIah8BqIFUX6kqbKSgfIk1EC6x0sCIueSGROhE0ClXQMmN89JT-XtW62N

The Interactable 3D uses our interaction system, It allows the player Interactor to signal the component that it is being interacted with. The item Pickup will listen to this interaction and call the pickup function so that the interactor (the player) can pick up the item.
The Item Object component will be storing a reference to the item that should be picked up. And the interesting component Item Pickup Visual Listener will listen to the ItemObject and the Item Pickup for state changes. When a new item is bound to the ItemObject the visual listener will look for a prefab in the item attributes and place it under the parent transform specified. This allows us to have a single item pickup component that is used for all item objects in the game while making them visually different since we swap out the model using the itemDefinition prefab attribute.
nTANvICkyfLRPoK_pR9JB9BzZk2olXl7hlvnjR-JW2xHrycsN1yClIptLW2l8-ZAjJ9ZPDeQfPu4WxDzENdmLJGsULAfhtENoCnjnltm56NhGAHGbOdFZlYhHIjo_TbofnL6589Z

The great thing about the attribute system inheritance is that we can have all the items inherit a generic item pickup model from the Item Category and then for some items we can specify a custom prefab. This is pretty useful if you have many items as you may not have models for all of them.
s-eT9MXInHudj6J2k3gCuUNvUOa5drfQYXfNfPmjTqvaqRn_uLc9SvsN7uogjprulWqtEdXC9JTauy459dmc2MVkx_BA21TsqpVyfiXsImeLGb_cKWIG0edNNeJCehpEkvBf9w6N

The “PickupPrefab” attribute has a visual prefab with nothing other than a mesh and mesh renderer. No need to make a special prefab for each item pickup.

Here is me dropping and picking up items from an inventory:


The ItemDrop action is very simple:
C#:
inventory.MainItemCollection.RemoveItem(item);

            m_ItemPickup = ObjectPool.Instantiate(m_PickUpItemPrefab,

                m_PlayerCharacter.transform.position +

                new Vector3(Random.value*2-1,Random.value*2,Random.value*2-1),

                Quaternion.identity).GetComponent<ItemPickup>();



            if (m_ItemPickup == null) {

                Debug.LogWarning("Item Pickup is null");

                return;

            }

            

            var itemObject = m_ItemPickup.ItemObject;

            itemObject.SetItem(item);

On the last line we set the item to the itemObject which triggers the event to signal the visual listener to swap out the pickup model. With this item pickup system we can reduce the amount of time you spend setting up prefabs so that you can spend more time on making your game better.

For equipment items we use a similar approach, but instead of having a single Equippable Item prefab where the visual prefab is swapped, we have at least one for each Equippable Item Category. And this is where the magic happens.

In the demo Usable Weapon prefabs use the Item Binder component. This video shows how the ItemBinder is used in the inspector:

https://streamable.com/nz5vy6

The itemBinder component makes mapping attributes to properties incredibly easy. It works dynamically so you can set your item to the ItemObject at runtime and it will bind it. That’s how we set up the weapons in the demo.

YwMe_8mnnA_dn9PRApVX9fZ1P13JDbtCXisq4YiMEVPWvBMAgHeSXpZws6tdp6jiU0dJko9FY4nnz2SylrV5ZYFDyP2xeJeF65-aXXnZvqUETVsbQ7yqbklFu91yxaIxuvAcIE6q

Here we are looking at the Wand Usable Weapon. It is a prefab with a single gameObject and these are the only components we need.
Range Attack is a custom script used in the demo to shoot projectiles. It has a few public properties that we want the bound Item to set. To do that we use an ItemBinder. With the item binder you can select an ItemCategory (i.e “Wand”), this opens up the attributes that can be bound to properties. For the Wand Usable Weapon, we bind the “NumOfProjectiles” Item attribute to the “BulletsPerFire” property and we also bind the ItemDefinition attribute “Projectile Prefab” to the “Bullet Prefab” property. With that setup we can change the number and the type of projectiles being fired for each wand directly in the Inventory System Editor.
When binding an attribute to a property we have a two way bind for mutable items and a one way bind for immutable items. By a two way bind we mean that changing the value of the property which is bound to an attribute will change the item attribute value to keep things in sync. That is not the case for immutable items since they cannot change value after being spawned.
Finally we have the usable Item Object which derives from the ItemObject class. It allows you to easily map a Usable Item Action (i.e Range Attack) to an input. In the demo we do not specify any input. We may want to use the same prefab for multiple characters, not just the player. So instead of pointing out the input in the inspector we trigger the Usable Item Object action through the Character Equipper using a character Input script.

This is a good time to point out that the Ultimate Character Controller is more complete when it comes to character item equipment as it is a character controller. If you were to use the inventory integration with UCC you would still use an ItemObject and an ItemBinder but instead of using UsableItemObject and UsableItemObjectActions you would use the UCC Item component.
 

Sangemdoko

Moderator
Staff member
Now you know how to create a usable item equipment, but what about non-usable item equipment such as clothes? When equipping items we need to know where the character can equip it, which item slot is available, what items can be used in which slot, etc…

For that we use three components: An ItemSlotSet, an ItemSlotCollection (in the character Inventory) and a CharacterEquipper.
The item slot set will tell both the ItemSlotCollection and the CharacterEquipper which are the slots and what are their restrictions.
iqy7DJ0Io9SPt7kw0cJGNoSTNC6iJ3AF3c_V0TilZWAqGEppHpe2n2MIEBefxo_rBVwxkma8FBb1rx8GJ7_v5oTfCa_9229_O7rqZnnr5CPwVyEkCQi4qMRyTC5tPeGeBSlF1DIf

Each slot has a name, an ItemCategory and a size limit (usually set to one)
When adding an item to the ItemSlotCollection it will use the ItemSlotSet to know if the item can be added. When an item is added or removed from the ItemSlotCollection the equipper is notified of the change and deals with it by equipping or unequipping an item from the character.
In the Inspector when an ItemSlotSet is specified in the CharacterEquipper it will automatically create the Item object slots. The Item Object slots can be used to specify where and how the equipment should be spawned, and if some gameObject need to be hidden when something is equipped in that slot.
mHhzP-9cSInjzLIsTIqHEw3ocnCd4uwmLbUqWATYbJqJxrjkKngQan_8uZ7e78OhCuuQ4d04pLzMndL034VlblACi1IoRuHhvWY1Zq7x4N2IG6orLR-4_fNbz6sHdX-MaKdGoDtZ

For skinned meshes we can simply specify that the item object slot is a skinned
XiD1_6gOvlW-0o28J5_ARCGIW4niEtsgy50M3xFK1CQbwT7Iih7QudMaY-0mBwSxqZMQhr0rXOCqdymHdBwO3nHqq7IKXzIQkrXiejqdORI2ZXNOIKk83YYQRtmPxacX7Xv5sosF

This will automatically find the skinned mesh in the item Equippable prefab and skin it on the character. For this to work the skinned item prefab must have the same bone hierarchy as the character.

Note that we specify the attribute names for “UsableItemPrefab” and “EquipmentPrefab”. Equipment prefab will store the visual prefab or the skinned mesh prefab, while the usable item prefab will store the “Wand Usable Weapon” or “Sword Usable Weapon” for example.
WSsbTc5spRrNcdi01mxULPcBc0ayXsn5ViCAx4BF7VtxALvAWRBiy628LXrUUiqI7jOAw70CbhZE8roYWeb8IKvVrzsaid4xp27K55RzUTaOY97rvb5zVx42l4m1T4Oqxk4XC7cD


Lets see this in action!

https://streamable.com/0ovolu

Pretty cool right!

As mentioned before character stats are only part of the demo. It works by listening to the character equipper and updating the stats every time there is a change. Then the stats are used to affect damage taken or damage dealt. We added stats in the demo because a lot of people requested it but it is technically of scope for an inventory system. You can use the demo script as inspiration to create your own character stat system though.

I’m sure you noticed the enemies dropping random sets of items as they died. To do that we use a random item dropper and use the inventory as a probability table so that you can have more or less chance of getting a particular item. As mentioned before the inventory component is very usable in many different ways. In the example below we see that we have more chance of getting would than one of the runes.
For random currency droppers we pass in a currency amount from the currency holder and take a random percentage offset.

We can trigger the drops on enemy death using the unityEvent.
VhaAHEoSt8SeHQ1V7s-jIoT0uLhqyWvIewb4fxesX_mKXHFFWwQTI4ctdRB-zlPF5pBPWAbTe6eDfFIhVcqYhe5r14QpHRBEGdbm6RFzWzTVtZMgKWdR31aU87uWWccmj2wAnwAI

For fun I even added a different attack radius when the enemy equips a sword or a wand.

With that I believe that I showed pretty much everything the inventory demo has to offer. I hope you are looking forward to it being released as we do. We are doing all we can to get the asset to you in the best quality as fast as possible.

Tomorrow we will dive into the API so that you’ll know how to create items through scripts and change their attribute values, etc…
 

Sangemdoko

Moderator
Staff member
miB06a_FRCjPV6mgu-K80N4cJPWfrsLbRIv-bgeBX9CGJA6sNgwmwLiG4j80LCBxe9DTDw_bzkuL3Fo6mgYSBwnwCoTvWbdxZX8eaqSLl2_Trz4_g6KTU8FDzBNWcBDauLFuwQw8

Part 5 : First look at the API

This part will be more technical then the others but try to explain things so that non-programmers can still follow along.

When creating custom code you might want to get a reference to an ItemCategory or an ItemDefinition in a script. ItemCategories and ItemDefinitions are scriptable objects and therefore you can create a serializable field to drag and drop them in the inspector. But what if you want to get them through code? All inventory objects in the database are registered in the Inventory System Manager registers at the start of the game. Even items that are created at runtime will be registered there.

InventorySystemManager is a monobehavior singleton that you can access anywhere. You need one in the scene for the inventory components to function. There are ways to extend and/or replace the InventorySystemManager, but that’s advanced and won’t be necessary for 99.9% of people.

So using the InventorySystemManager we can get our itemCategories, ItemDefinitions and more.

C#:
    //Get an ItemCategory by name
            var category = InventorySystemManager.GetItemCategory("MyItemCategory");
            //Get an ItemCategory by id
            category = InventorySystemManager.GetItemCategory(97201);
            //Get all the Item Categories
            var allCategories = InventorySystemManager.ItemCategoryRegister.GetAll();

            //Get an ItemDefinitions by name
            var itemDef = InventorySystemManager.GetItemDefinition("MyItemDefinition");
            //Get an ItemDefinitions by id
            itemDef = InventorySystemManager.GetItemDefinition(123809);
            //Get all the ItemDefinitions
            var allItemDef = InventorySystemManager.ItemDefinitionRegister.GetAll();

You can get crafting categories, recipes and currencies in the same way.

Once you have a reference to an ItemDefinition you can create an item.
C#:
//Get an ItemDefinitions by name
            var itemDef = InventorySystemManager.GetItemDefinition("MyItemDefinition");
            
            //Create an item equivalent to the default item.
            var item = InventorySystemManager.CreateItem(itemDef);
            //Create an item copy.
            var itemCopy = InventorySystemManager.CreateItem(item);
            
            //Create an item equivalent to the default item.
            var itemWithOverrideAttribute = 
                InventorySystemManager.CreateItem(itemDef, new []{new Attribute<int>("MyAttributeInt", 100) });
            //Create an item copy.
            var itemCopyWithOverrideAttribute = 
                InventorySystemManager.CreateItem(item, new []{new Attribute<bool>("MyAttributeBool", false) });

Once you create your item you can get it from anywhere using its id.
C#:
var item = InventorySystemManager.GetItem(12345);
You can’t use the name because multiple items can have the same name, by default the item name is the same as the itemDefinition, but it can be set at runtime.

Once you have a reference to a ItemCategory, itemDefinition and or item you can use their methods to get their relationships
C#:
//Get the itemCategory parents
            myItemCategory.GetDirectParents();
            //Get all the itemCategory parents, it uses a non-alloc pattern.
            ItemCategory[] allParents = new ItemCategory[0];
            var count = myItemCategory.GetAllParents(ref allParents);
            
            //Get the itemCategories children itemDefinitions
            ItemDefinition[] allChildrenItemDefinitions = new ItemDefinition[0];
            count = myItemCategory.GetAllChildrenElements(ref allChildrenItemDefinitions);
            
            //Check if a category contains an itemCategory
            myItemCategory.InherentlyContains(myOtherItemCategory);
            //Check if a category contains an itemDefinition
            myItemCategory.InherentlyContains(myItemDefinition);
            //Check if a category contains an item
            myItemCategory.InherentlyContains(myItem);
            
            //Get the itemDefinition category
            var category = myItemDefinition.Category;

            //Check if a category contains an itemDefinition
            myItemDefinition.InherentlyContains(myOtherItemDefinition);
            //Check if a category contains an item
            myItemDefinition.InherentlyContains(myItem);
            
            //Get all the itemDefinition family, includes parents and children, it uses a non-alloc pattern.
            ItemDefinition[] itemDefinitionFamily = new ItemDefinition[0];
            count = myItemDefinition.GetAllFamily(ref itemDefinitionFamily);

            //Get Item ItemCategory
            myItem.Category;
            //Get Item ItemDefinition
            myItem.ItemDefinition;

            //Get the last itemObject that was bound to this item, (there can be multiple itemObject per item)
            myItem.GetLastItemObject();
We use a non-alloc pattern for getting lists without creating garbage. We use this pattern in a lot of places. Of course in practice you wouldn’t create an array each time before getting parents, children or family of an object, it would defeat its purpose. Instead you would either cache your own array or use our extremely convenient GenericObjectPool.

C#:
var myItemCategory = InventorySystemManager.GetItemCategory("MyItemCategory");
            
            //Get all the itemCategory parents, it uses a non-alloc pattern.
            //Do it right this time!
            
            //First get the pooled array from the Generic Object Pool.
            var pooledAllParents = GenericObjectPool.Get<ItemCategory[]>();
            //Feed the array with the parents and get the count of parents.
            var count = myItemCategory.GetAllParents(ref pooledAllParents);
            
            //IMPORTANT: The array might be bigger than the amount of parents! DO NOT use pooledAllParents.Length !
            for (int i = 0; i < count; i++) {
                Debug.Log(pooledAllParents[i]);
            }
            
            //IMPORTANT: Do not forget to return the pooled array once you are done with it. 
            //This way the array can be reused somewhere else.
            GenericObjectPool.Return(pooledAllParents);

And with that you have an easy way to avoid garbage allocation for the best performance possible!

One of the most interesting features in our inventory system is the attribute system. It allows you to add any object/value type property to an object. We wanted to make sure that creating custom attributes was as seamless as possible. Creating an Attribute<MyType> manually is a solution but it becomes tedious very fast. So instead we use some reflection to create it dynamically within the editor. How do you get your types to appear in the attributes drop down then? With our unit options menu it is very simple.

First create a custom type. In the demo I use a stat class for the character. It is part of the Demo assembly. What if I wanted to make it into an attribute for some reason (can’t think of one, but imagine I did).

C#:
 [Serializable]
    public class Stats
    {
        [SerializeField] protected int m_MaxHp;
        [SerializeField] protected int m_Attack;
        [SerializeField] protected int m_Defence;

        public int MaxHp => m_MaxHp;
        public int Attack => m_Attack;
        public int Defence => m_Defence;
    }

So in the editor I could try to use it as an attribute… but it won’t appear in the dropDown type list:
2RzCAv_NqXl9vG0xtAZ6Ttn4ezGzSxjSxXMSmiCk0VLiq0h4YzgLdE9nOxTAMIjEj6XB1EY0TlQbQFm4X0MmapK4vn22YCcns9NQhVsMeAOeUNla0AzgZ2Mlk5HWd31VJONPv9gD

If we added all the types the list would be too crowded with useless types. To add the type to the dropDown list you simply need to open the Unit Options window and set it there:

https://streamable.com/kx022t

Note that you’ll need to add your assembly to the assemblies list for your type to appear in the choices. The toggle next to the type name lets you set it as a common or uncommon type. A common type will appear at the top of the type list the more it is used.
You can even make an Array or a List of your custom type by selecting that option before selecting the type.
 

Sangemdoko

Moderator
Staff member
Once the attributes are added to an ItemCategory, ItemDefinition and Item you can get/set their values. It is recommended not to change the values of any immutable items, including ItemCategories and ItemDefinitions and our system may prevent you from doing so.

To get or set attributes of an item you will need to know its name.

C#:
//Get an attribute from an item. This includes itemCategory and ItemDefinition attributes.
            var attributeInt = myItem.GetAttribute<Attribute<int>>("MyAttributeInt");
            //Returns the attribute value.
            attributeInt.GetValue();
            //Get the inherited value.
            attributeInt.GetInheritedValue();
            //Set the override value (automatically sets the variant type to Override).
            attributeInt.SetOverrideValue(100);
            //Set a modify expression (automatically sets the variant type to Modify).
            attributeInt.SetModifyExpression("42 + 42",true);
            //Change the variant type to inherit.
            attributeInt.SetVariantType(VariantType.Inherit);
       
            //If you are only interested in the attribute Value you can use TryGetAttributeValue.
            if (myItem.TryGetAttributeValue("MyAttributeInt", out int attributeValue)) {
                Debug.Log(attributeValue);
            }

            //List of item attributes (does not include itemCategory or itemDefinition attributes.)
            var itemAttributes = myItem.GetAttributeList();
            for (int i = 0; i < itemAttributes.Count; i++) {
                //Attribute base class does not know the attribute type, this can cause boxing.
                itemAttributes[i].GetValueAsObject();
            }

            //Iterate through all the item attributes including the itemCategory and ItemDefinition attributes.
            var attributeCount = myItem.GetAttributeCount(true,true);
            for (int i = 0; i < attributeCount; i++) {
                myItem.GetAttributeAt(i,true,true);
            }

To get attributes on ItemCategories and itemDefinitions is very similar.

As you see we use strings quite a bit to get objects and attributes. That can make it a bit of a pain if you are the type to make typos or forget how you named things. That’s why I made a script generator that extracts all the names of the objects in the database and auto generates them in hierarchy. All you have to do is press “Generate Name Script” in the editor Setup menu to get it.
C#:
//This File is Auto-Generated by the editor window
//Date of creation: 04/03/2020 16:59:02

public static class DemoInventoryDatabaseNames
{
  //ItemCategories

  public static class Viewable
  {
   public const string name = "Viewable"; //ItemCategory

//Attributes
   public const string categoryIcon = "CategoryIcon"; //Sprite
   public const string description = "Description"; //String
   public const string icon = "Icon"; //Sprite

//Item Definitions
  }

  public static class Pickupable
  {
   public const string name = "Pickupable"; //ItemCategory

//Attributes
   public const string pickupPrefab = "PickupPrefab"; //GameObject

//Item Definitions
  }

//….etc….

In practice this is how your code may look like
C#:
            //Get the viewable Item category from the database names.
            var viewableCategory = InventorySystemManager.GetItemCategory(DemoInventoryDatabaseNames.Viewable.name);
            var potionItemDefinition = InventorySystemManager.GetItemDefinition(DemoInventoryDatabaseNames.potion);
            var potionItem = InventorySystemManager.CreateItem(potionItemDefinition);
       
            //Check if potion is part of the viewable category.
            if (viewableCategory.InherentlyContains(potionItem)) {
                //If potion is part of viewable category it must have all the attributes of viewable
                //Get the description.
                potionItem.GetAttribute<Attribute<string>>(DemoInventoryDatabaseNames.Viewable.description).GetValue();
                //Get the item Icon.
                potionItem.GetAttribute<Attribute<string>>(DemoInventoryDatabaseNames.Viewable.icon).GetValue();
                //Of course you can also get the category attribute from the item directly.
                potionItem.GetAttribute<Attribute<string>>(DemoInventoryDatabaseNames.Viewable.categoryIcon).GetValue();
            }

This should help you avoid silly mistakes and will also help you refactor your when you decide to rename an object or an attribute.


A component you will use very often is the Inventory and ItemCollections. And most likely you will want to filter and sort the inventory items. That is extremely simple.
C#:
//Get a collection by ID.
            var myItemCollection = myInventory.GetItemCollection(0);
            //Or get it by name.
            myInventory.GetItemCollection("My Item Collection");

            //Check if itemCollection has the item.
            myItemCollection.HasItem(myItem);
       
            //Add an item amount to a collection.
            myItemCollection.AddItem(myItem, 5);
            //Remove an item amount to a collection
            myItemCollection.RemoveItem(myItem, 2);

            //Get the amount of an item
            myItemCollection.GetItemAmount(myItem);
            //Get the amount of an item with itemDefinition
            myItemCollection.GetItemDefinitionAmount(myItemDefinition);
            //Get the amount of an item with ItemCategory
            myItemCollection.GetItemCategoryAmount(myItemCategory);

            //Get all the itemAmounts in the collection
            var allItemsAmounts = myItemCollection.GetAllItemsAmounts();
            for (int i = 0; i < allItemsAmounts.Count; i++) {
                allItemsAmounts[i].Item;
                allItemsAmounts[i].Amount;
            }
       
            var pooledItemAmount = GenericObjectPool.Get<ItemAmount[]>();
       
            //Get all item amounts with definition (the 'true' parameter is used to check inherit relation)
            var count = myItemCollection.GetItemAmountsWithDefinition(myItemDefinition, ref pooledItemAmount,true);
            for (int i = 0; i < count; i++) {
                pooledItemAmount[i];
            }
       
            //Get all item amounts with category (the 'true' parameter is used to check inherit relation)
            count = myItemCollection.GetItemAmountsWithCategory(myItemCategory, ref pooledItemAmount, true);
            for (int i = 0; i < count; i++) {
                pooledItemAmount[i];
            }
       
       
            //Get item amounts wil a custom filter and sort function.
            //Get all items with an amount bigger than 10 and sorts by name.
            //Note: Create the comparer before as to not create garbage like in this example.
            //If you are unfamiliar with this syntax learn about Lambda functions.
            myItemCollection.GetItemAmounts(
                ref pooledItemAmount,
                (itemAmount) =>
                {
                    return itemAmount.Amount == 10;
                },
                Comparer<ItemAmount>.Create(
                    (i1, i2) =>
                    {
                        return i1.Item.name.CompareTo(i2.Item.name);
                    }));
            for (int i = 0; i < count; i++) {
                pooledItemAmount[i];
            }

            //If you need items from all the itemCollection in the inventory
            //You can use the same function on the inventory instead of the itemCollection.
            myInventory.GetItemAmounts(
                ref pooledItemAmount,
                (itemAmount) =>
                {
                    return itemAmount.Amount == 10;
                },
                Comparer<ItemAmount>.Create(
                    (i1, i2) =>
                    {
                        return i1.Item.name.CompareTo(i2.Item.name);
                    }));
            for (int i = 0; i < count; i++) {
                pooledItemAmount[i];
            }

            GenericObjectPool.Return(pooledItemAmount);

We haven’t seen the shop, currency, crafting, etc… There is simply too much content to explain in a single post. We use the same patterns everywhere and try to be as consistent as possible so all the other scripts should be easy to use once you understand the logic behind the system.

This is the end of the week of showcases. From now on it will be the final stretch before the release. There is still a lot to polish in the code, documentation, editor and demo. But I think we are ready to share a release window.

We plan to pre-release the Ultimate Inventory System (UIS) on the Opsive store in May. The Unity store version will be released as soon as the pre-release version is stable.

We have a lot of features planned for after release and I am sure the community will come up with more as time goes on. Our goal is to make this asset the best inventory system on the asset store and we will do everything possible to make that happen.

If you have any questions feel free to ask, I’ll try to answer the best I can.
 
Last edited:

Justin

Administrator
Staff member
@Sangemdoko mentioned it in his last post, but to give more detail the name of the asset will be the Ultimate Inventory System. We plan on releasing in May on the Opsive Store, and as soon as things are stable we'll release it on the Asset Store. I'm imagining that there will be a few weeks in between the two releases but we'll see how things go.

Also, we are going to set a price of $75 for this asset. @Sangemdoko has been working on this asset for more than a year and it is turning out to be an extremely flexible and complete inventory system. After we release version 2.2 of the character controller I will be helping @Sangemdoko polish the asset for release. We can't wait to see what everyone thinks once they get their hands on it.
 

chrisk

Active member
@Sangemdoko, Wow! I just went through the updates! There is quite a lot to swallow but it looks really good and everything seems logical. I'm really excited! At this point, I just have two questions.

1. UCC integration. UCC uses ItemType, ItemSet, ItemCollections (it's own naming conventions and concept) I'm wondering if they will be unified with the new Inventory system so that we don't have to use two different systems. I really think UCC and the new Inventory system should shares the same base codes. I guess you don't mind sharing parts of your code with UCC, right?

2. Attachment/Socket system. Shooter games and RPG game requires Attachments/Sockets and I hope you give some provisions on how an Item can contain other Items, like Children and Parent. I guess adding Children/Parent API to Item is not that hard but it will require some Editor support. I hope there is still some room to work on before May release.

Please keep the good work. Cheers!
 

Sangemdoko

Moderator
Staff member
Hi @chrisk, I'm glad you are excited

I'm wondering if they will be unified with the new Inventory system so that we don't have to use two different systems.

We are still working on the UCC integration so things may change. Essentially both UIS and UCC will use use a basic shared set of interfaces and classes. Things like ItemIdentifier, ItemParent, etc...
This should allow us to use the UIS items within the UCC equipment inventory. We'll share more about the integration once it works with all the UCC equippable items.

Attachment/Socket system.
For attachments and or sockets you should be able to use the demo item upgrade as an example to create your own system. There are better ways to add this functionality than to modify the existing API. If a lot of people request a more advanced attachements/socket system then what is available in the demo I'll look into adding a feature for it. Using attributes as slot and making a component that lets you set the attahcments in the inspector should do the trick.

I hope that answers your questions
 

chrisk

Active member
Thanks for the answer. please understand that I'm a bit worried but I'll patiently wait for the release. ^^
 

Duffer123

Member
@Sangemdoko ,

Hi, just reviewing all the amazing stuff above and considering.

(a) In relation to the item binding (binding item attributes to fields or(?) properties in monobehaviour components on the same(?) GameObject, what if my component script has within it a class and within that class is a public float field? Is there a way to bind through the component => class => public float field?

(b) In relation to calculated Item Attribute fields (rather than inherited or overridden) - although I see an excellent example of returning a combined $"{attribute} {attributeB}" string, can the the calculation formula cope with adding strings together?

(c) Another question. In terms of naming and naming conventions for Item Categories, Item Definitions and Item Attributes (etc) in setting them up in the Editor, can I name an Item Attribute say "Base Name" or is it that I should not use spaces ie. "BaseName"?

[EDIT]

A suggested feature for after first release - being able to recolour sprite or mesh/gameobject at runtime. That would allow a huge reduction in the need for assets, potentially?
 
Last edited:

Sangemdoko

Moderator
Staff member
Hi @Duffer123

(a) In relation to the item binding (binding item attributes to fields or(?) properties in monobehaviour components on the same(?) GameObject, what if my component script has within it a class and within that class is a public float field? Is there a way to bind through the component => class => public float field?

ItemBinder only binds properties, not fields. Example:
C#:
public int myProperty {get;set;}
public int myProperty2 {get => m_MyField; set => m_MyField = value;}
public int myProperty3 {get => m_MyClass.Field; set => m_MyClass.Field = value;}
The third example shows how to bind a property within a class. You'll need to add a public property on the Monobehavior component for it to appear in the custom editor property dropdown.

(b) In relation to calculated Item Attribute fields (rather than inherited or overridden) - although I see an excellent example of returning a combined $"{attribute} {attributeB}" string, can the the calculation formula cope with adding strings together?
Yes that should work

(c) Another question. In terms of naming and naming conventions for Item Categories, Item Definitions and Item Attributes (etc) in setting them up in the Editor, can I name an Item Attribute say "Base Name" or is it that I should not use spaces ie. "BaseName"?
You can use spaces if you want. For the ItemCategory and ItemDefinitions names I suggest putting the name as you want it to appear in game. For attributes I usually suggest Pascal case but you can do whatever you want, as long as you use only letters, numbers, spaces and underscores.

A suggested feature for after first release - being able to recolour sprite or mesh/gameobject at runtime. That would allow a huge reduction in the need for assets, potentially?

Recoloring sprites is quite limited as you would need to specify a color to replace by another, it would only really work for duo colored sprites... Not sure if that's worth it. So is changing color of a material, It can be done but it only work well if you have black and white textures or for very specific use cases. If you believe these are features that could be useful to you, I can give you some pointers on how to implement it yourself, but I do not think they should be part of the Inventory system.
 

Duffer123

Member
@Sangemdoko ,

Excellent - thanks for the replies. The stuff on turning sub-class fields in to Properties that Ultimate Inventory System (UIS?) can grab was really useful too.

Perhaps with the recolouring thing, just shifting the hue - which I think can easily be done to Sprites, Materials, Mesh Materials?

So if you had say a nice silver/grey sword, shifting the hue to yellow could make it 'gold' or similar? Dunno. Just thought doing something on that which was simple and accessible would allow people to forget about complex coding on it and it would really leverage the inherited feature best? (he says still trying to sell the idea... ;) )
 

Sangemdoko

Moderator
Staff member
@Duffer123

So if you had say a nice silver/grey sword, shifting the hue to yellow could make it 'gold' or similar?

Although the idea seems good at first glance, it's not as good as you'd think in practice. Changing the hue of a sprite means the entire image changes color. Your sword will have a handle, a blade, etc... adding yellow to all of item won't look nice. If you were to use a mask to only color part of the sprite it could work... but at that point you might as well create a new sprite, if you have 3-4 variants. If you want players to customize the items color though that's were such a feature could prove useful.
Personally I think that such a feature is out of scope since it is not related to the inventory system, it is more related to an art workflow. There may already be assets that dedicate themselves purely to do such things. You can also try to implement such a feature by yourself, I'll answer any questions related to the inventory system when it comes up.
 

Duffer123

Member
Ok, fair enough.

Here's another one for you - a simple API method to sort items in any Category-based (as they all are) Inventory by their sub-Categories, whatever they are? (unless you've made that method already!).
 

Sangemdoko

Moderator
Staff member
Here's another one for you - a simple API method to sort items in any Category-based (as they all are) Inventory by their sub-Categories, whatever they are? (unless you've made that method already!).

Yes that is already part of the asset. By default you can sort by item name or itemCategory name, I may add some other default sort options. It's very easy to add your own sort/filter functions too for full control.
 

BrandonDeVITO

New member
I think that 75$ is an extremely fair price for what I would consider a core system. Though there are a myriad of cobbled ways around it, I've discovered that using UCC as the core of my single player and VR creations is essential. That it's integrated with Playmaker, my Weather System, my Quest and Dialogue system, and doesn't effect my Sound Spatializer plugins means the only core system we've been missing is an integrated, and comprehensive Inventory System.

We wasted a lot of money on lost systems over the years. And what remains is either system specific (Like the ORK Framework, or GameCreator) and therefore locked as to what is compatible with it, and how far it can be expanded; or it's something that's been depreciated.

When I start a project by installing UCC and Behavior designer, then form what Assets I add based on that core, it creates something stable. Having Inventory, Drops, Equips, and associated GUI tie-ins come from another Opsive Core plugin will be something that will solve a great deal of my creative limitations.

For out team, it will be a day one purchase. And is something we've been eagerly awaiting for the length of time it's been being worked on. Thank you for all of the effort; I can't wait to get our hands on it. We need it desperately.

Kudos.
 
Top