[Feature Request] Multistack item collection that stores an index for each item stack (for use with item view slots)

ParanoidAndroid

New member
Currently when you drag and drop an item between two different inventories, it will automatically combine the item with other stacks in that collection.

The main functionality I'm looking for is this:
If the item is dragged to an empty slot, it is moved to that slot and doesn't try and combine with any other items in that collection.
If the item is dragged to a slot that has the same item, then should it combine.
If I move the item to the inventory using a custom item action, it will try and be added to existing stacks.

This leads me to another thought about having an item index stored.
From what I saw, grid positions are only remembered by making use of the inventory grid saver component.
I haven't looked at it too closely, but it seemed a bit cumbersome to use.
For example, if I have a reusable storage menu, wouldn't that require saving the storage grid information right before I close it every time?
Otherwise, it would get lost once I get a reference to a new inventory.

I think another potential benefit of having an index would be letting different grids referencing the same inventory appear in the same order.
This would also let you be able to set item grid positions from the inspector as well.

Anyhow, I think this sort of feature would help flesh out some rather common use cases.
 
I do agree with some of the points you made.
Unfortunatly most of them require some pretty big changes which could impact existing projects, so I can't implement it quickly.

I've added this in my TODO list and I will investigate when I have more time. Hopefully I can come up with a good solution that doesn't break the way it currently works.

I am very sorry for the inconvinience.
 
That's unfortunate to hear it's not easy to implement, but I guess I'll make do for now.

In the meantime, I looked at using the grid saver component some more, and got it loading and saving when the storage grid panel is opened and closed respectively.
So I guess that was easier than I thought, although I think I have one notable issue with it currently.
It doesn't look like I can set the reference to the inventory grid in code?
I think that's something I need to be able to do, if I'm using a prefab to create a storage inventory object at runtime.
 
You mean setting the referenceof an Inventory to an Inventory Grid at runtime?

You can set the Inventory to an InventoryGrid using this:
Code:
m_InventoryGrid.SetInventory(inventory);

or if you are using an inventory panel binding you can do.
Code:
m_PanelBinding.BindInventory(inventory);


I hope that helps
 
Sorry if that was unclear, I meant setting the reference to a grid on the inventory grid saver component, not the inventory grid with the inventory.
storage_setup.PNG
This is my storage inventory prefab setup.
The storage opener script handles getting the references to later send to the storage menu script when interacted with.
The red circled variable was what I wanted to be able to set at runtime.

However, I noticed that the saver will try and set the grid to one on the same game object if it is null.
Does that mean I should only have one grid saver which is next to the grid component, instead of having a grid saver for each inventory?

Regardless of where I put the grid saver component, I think I also need to be able to set the key for the grid saver as well, since I'm having a reusable menu for different inventories that could be created at runtime.

Hopefully I've been able to explain what I'm trying to do.
 
I see what you mean now.

I added a new saver for you and made some improvements that should help.

I have a component called InventoryGridIndexData. It is a component that allows you to keep the index data of a Grid on the Inventory gameobject, instead of in the InventoryGrid. This means you can have multiple grid index data per inventory, and multiple inventory per grid index data.

All you need is add that component next to you Inventory.

In addition I added a new saver component which allows you to save the InventoryGridIndexData.
The only requirement is that you give a unique ID to your InventoryGrids (or shared the ID if you want your InventoryGrids to have the same layout).
You can define the ID of an InventoryGrid on the ItemInfoGrid component.

So now you don't have to worry about the InventoryGridSaver, you can remove that component and only use the InventoryGridIndexDataSaver

Please find the improved and new script below.

The meta file for the new saver:
fileFormatVersion: 2
guid: d9f2c548a4e64be593d1e71fd9c6c821
timeCreated: 1656663833
So that it won't break once you update. It is inside the Scripts/SaveSystem folder.

I hope that solves your issues with this.

In the next update, I will have a new feature scene showcasing this feature.
 

Attachments

  • InventoryGridIndexData.cs
    5.1 KB · Views: 3
  • InventoryGridIndexDataSaver.cs
    7.3 KB · Views: 3
This has been a great help, thank you!
The new script works almost perfectly, but I've encountered one issue using it that wasn't present before.

First, I enter play mode with some items already set in the inventory.
If I have not yet opened my inventory menu, any new items added to my inventory will be added to the first index, which pushes the index up of any prior items.
After I have opened my inventory menu, any new items acquired will be added to the first empty index, which is the expected behavior.
I guess the index data isn't getting initialized somewhere?



I also have another problem that probably won't have anything to do with the new index data, but I figure I'll ask about it here.
I have two inventory grids (one for a main menu, the other for a storage menu), both referencing my main inventory and set to the same grid ID.
The storage menu inventory grid is meant to be visually identical to the main menu inventory grid,
but having it separate lets me run different scripts and item actions with it.
I also have a mirror inventory hotbar that references the inventory grid for the main menu.

However, the mirror hotbar doesn't get updated when changes are made using the storage menu grid.
Furthermore, adding items from this storage menu will place them on the first empty slot of the hotbar, if any,
regardless of where I place the item on the grid.
Once I open my main inventory, my hotbar updates to the correct indexes.
Is it possible for the mirror hotbar to account for multiple grids? Or for grids tied to the same ID to better sync up index data somehow?

I don't know how much this sounds like its own feature request, so my apologies if this deviates too much from the original topic area.
 
For your first issue, I think it was a problem with the InventoryGridIndexer which inversed the items that had to be added.

The items in the Inventory are not added to the InventoryGrid each time an item is added. They are only added when the InventoryGridIndexer is told to refresh, which happens when the InventoryGrid is drawn.

So I fixed the order on line 286 of the InventoryGridIndexer script:
Code:
for (int i = 0; i < m_TempUnsetItemInfos.Count; i++) {


For your second issue

The InventoryGridIndexData is only refreshed when the InventoryGrid is drawn. That's because the InventoryGrid has the Filters and Sorters. So its the only way to know what the index should be.

And the problem of having multiple InventoryGrid using the same ID is that they might have different Filters and sorters.
This is a bad design from my part, I should have split the Visual part from the filters and sorters. But unfortunatly I can't split them now since it would break many projects. I will need to wait for a Version 2 of the Inventory System which won't be anytime soon.

Comming back to your issue with the Hotbar mirror. I changed the Hotbar to fix your particular issue.
It's not very elegant and it won't work if you have all the inventory grids opened at the same time. But its the best I can do without a major refactor.

As you suggested I now use the GridID to know when to refesh the hotbar. and the InventoryGrid reference within the hotbar is autmatically updated to the latest drawn inventoryGrid with the matching id.

Please find attached the new InventoryMirrorHotbar script.

It requires the following changes:

In the EventNames.cs file in line 62 add this new event name:
Code:
//The Inventory Grid has filtered and sorted the item infos
public const string c_InventoryGameObject_OnInventoryGridUpdate_InventoryGrid_ListSliceOfItemInfos_GridID = "c_InventoryGameObject_OnInventoryGridUpdate_InventoryGrid_ListSliceOfItemInfos_GridID";

And in the InventoryGrid script you can replace the FilterAndSortItemInfos function on lin 194:
Code:
/// <summary>
/// Filter and sort the item infos to be drawn.
/// </summary>
/// <param name="notify">Notify that the items have been filtered and sorted?</param>
/// <returns>The list of item infos filtered and sorted.</returns>
public ListSlice<ItemInfo> FilterAndSortItemInfos(bool notify = true)
{
    var listSlice = new ListSlice<ItemInfo>(m_Inventory.AllItemInfos);
    var filterSorter = m_Grid.FilterSorter;
    if (filterSorter != null) {
        var pooledArray = GenericObjectPool.Get<ItemInfo[]>();
        listSlice = filterSorter.Filter(listSlice, ref pooledArray);
        if (m_UseGridIndex) { listSlice = m_InventoryGridIndexer.GetOrderedItems(listSlice); }
        GenericObjectPool.Return(pooledArray);
    } else {
        if (m_UseGridIndex) { listSlice = m_InventoryGridIndexer.GetOrderedItems(listSlice); }
    }
    if (notify) {
        Shared.Events.EventHandler.ExecuteEvent<InventoryGrid, ListSlice<ItemInfo>, int>(m_Inventory.gameObject,
            EventNames.c_InventoryGameObject_OnInventoryGridUpdate_InventoryGrid_ListSliceOfItemInfos_GridID,
            this, listSlice, GridID);
    }
    return listSlice;
}

I hope that will work out for you
 

Attachments

  • InventoryMirrorHotbar.cs
    8.3 KB · Views: 2
+1 for improving flexibility of how stackable items are handled. Being able to split stacks is a fairly standard feature in most game inventories. UIS currently forces you to fill up one stack before you can create a second stack
 
Unfortunatly that won't make the upcoming update. And after that I will be extremely busy working on UCC V3.
This feaute is quite high in priority of UIS, but it will take awhile before I can implement it.

If I find some time to implement it, I will share my solution here asap so you won't have to wait for the next update.

I am very sorry for the inconvinience.
 
The fix on line 286 for the InventoryGridIndexer is working as expected, thanks!

As for the mirror hotbar, I think I'm missing another thing for the new script to work, as I'm getting this error.
new_mirror_hotbar_error.PNG

Anyhow, it sounds like the new mirror hotbar will work for my use case, so I greatly appreciate the support on this matter.
Looking forward to testing it soon.
 
We released UIS v1.2.10 yesterday it includes the HotbarMirror change.
RegisterUnregisterEvent is a function that exist in the updated version of the shared folder
it does the same as if you did
if(regsiter){ register} else { unregister }
but in one line
 
I've updated to UIS v1.2.10.

To test the mirror hotbar, I made an empty test scene with a barebones classic schema UI.
I have two inventory grids set to an ID of 1, on separate menu display panels, and they reflect the changes in each other.
The hotbar is also set to an ID of 1, has a default reference to my first grid, and is located on the GamePlay panel (So it gets deactivated when my other menus are open)

It seems the new mirror hotbar doesn't ever update its grid reference when I use my second grid.
I'm assuming that new event is supposed to be used to automatically update that, but it doesn't seem to be working.
Now, if I manually set the grid reference, such as using the display panel OnPanelOpen events, then the hotbar works as expected, reflecting changes made in the second grid.

Something else I noticed is that the new mirror hotbar doesn't seem to take into account the Item View Slots Container Panel Binding settings.
When I close my inventory and the hotbar is opened, it doesn't update with any changes. (It will update once I click on it.)
If I set "Draw on enable" to true, the hotbar updates when my inventory menu is closed (and the hotbar is set active.)

Functionally, the hotbar is working the way I need it to!
But it looks like there's a couple of fixes it still needs.
 
Last edited:
Alright so I've been messing around with setting up item actions for my mirror hotbar,
and unfortunately I'm getting some serious issues involving removing and dropping items.
Figured I'll keep posting here instead of making a new thread.

My current testing setup uses an ItemViewSlotsContainer Item Action Binding that uses the item on click.
I have been testing two item actions separately, the default RemoveItemAction and DropItemAction.

RemoveItemAction:
Start with some items in your inventory.
Open your inventory and then close it.
Click on any hotbar slot as long as it isn't the last item in the inventory.
The item will be removed as expected. The inventory component will reflect this.
Open your inventory menu, and you will still see the item, and be spammed with an error.
The error will stop once you try and move the ghost item to another slot, in which it will disappear.
RemoveItemAction.PNG
Something to note, this error doesn't happen if the item you remove is the last item in the collection.
Another thing to note, if the inventory menu is not yet opened, you can remove items,
and the error won't popup when you first open the inventory.
Also note that the items won't account for any empty spaces made in the hotbar.
I'm guessing that's because the item indexes haven't been set yet, but I don't know what can be done about that.


DropItemAction:
Using the drop item action will produce the same error when you have it remove the item and then open your inventory menu.
There are a few more unusual things to note from being able to pick up the item again.
If you drop the item, and then pick it up again, you won't be spammed with the error when you open your inventory.
If you drop the item, pick it up, then try and drop it again, you'll be spammed with a new error similar to the remove error.
Checking the inventory component shows the item has been removed, but the hotbar doesn't reflect this.
If you keep clicking the not-updated slot, the item will continue to drop and duplicate itself.
Picking up the item or opening your inventory will stop the errors.
DropItemAction.PNG

I must say I appreciate all the support so far, and for accommodating my use case with the mirror hotbar.
Hopefully the errors make it clear where exactly these issues are coming from, and that they won't be too hard to fix.
 
I created a new Feature scene to test your exact use case.
Two Inventory Grids with the same Grid ID and monitoring the same Inventory.
And a InventoryMirrorHotbar monitor the same Inventory.

I added and removed items (using the adjust button) while openeing, and closing the Grids. But everything worked as expected without any errors.

So I'm wondering what could have gone wrong in your scene.

Please find the new feature scene below. Tell me if you are able to replicate your error in there. and If not try comparing your scene with this one to see what could be the issue.

For the error I'm adding a warning, which perhaps will give us more information as to what is going wrong:
Code:
if (m_RemovedDirtyIndexedItems.TryGetValue(itemStack, out var previousValue)) {
    //This itemStack was already set to be removed, something isn't right.
    Debug.LogWarning($"The item Stack {itemStack} to be removed with index {index} and itemInfo {m_CachedItemInfos[index]} already had a previous value {previousValue}");
} else {
    m_RemovedDirtyIndexedItems.Add(itemStack, (index, m_CachedItemInfos[index]));
}
You can change the line that is giving you the error by the code above.

I hope that helps
 

Attachments

  • Feature scene 6_2.unitypackage
    47.5 KB · Views: 1
I wasn't getting any errors with the demo scene you provided.
Then I noticed that the changes made in one grid weren't being reflected in the other.
It looks like you forgot to add the "inventory grid index data" script to the "Player Inventory" game object.
As soon as I added that, I started getting my error again, so it definitely has something to do with the previously mentioned script.

Also, here's an example of the debug message.
debug_message.PNG

One extra little thing I noticed, the inventory grids had an ID of 1, but the hotbar had it set to 0?
That didn't seem to have an effect on anything though.
 
Please find the updated InventoryGrid below.

Now InventoryGrid will listen to other grids updating. When they match grid id and tab id it will copy the indexes and redraw itself.

This is not a very elegant solution but it seems to work.
 

Attachments

  • InventoryGrid.cs
    13.5 KB · Views: 5
Top