[REQUEST] Automatically arrange the order of item attributes

WeiYiHua

Member
Hello, I believe that organizing item attributes in an orderly manner is essential for efficient viewing and modification. Therefore, I am trying to arrange the item attributes of "subcategories" or "item definitions" based on the order of their "parent categories" and the item attributes within each respective "parent category".

However, if an item attribute type changes, or a new item attribute is added to the "parent category," the modified item attribute will be directly placed at the bottom of the list. As the number of item categories and definitions increase, manual arranging becomes time-consuming.

It would be very convenient if there were an automated tool that could arrange item attributes in the way mentioned earlier. Please let me know if this feature is implemented in a future version. Thank you!
 
Hi WeiYiHua,

This feature has been requested once before and it is in our list of requested features.

I'll boost the priority for it. But compared to other features it is not as time sensitive.
So it could take awhile before I get to it.

In the meantime, could you give some examples on how you would like this to work? Perhaps an auto sort button at the top of a list with multiple options, by parent order, by name order, only for this object, for familly, for all database, etc...?
 
Thank you for your reply. I am currently working on implementing the ItemCategory portion of this feature. My approach is to organize all ItemCategory from the root. The ItemCategory to be organized will retrieve all ItemCategoryAttributes, ItemDefinitionAttribute, and ItemAttributes of the parent ItemCategory in sequence, and place these parent Attributes at the beginning of the list according to the order they were retrieved, before organizing the rest of the attributes for this ItemCategory.

This process involves organizing the entire database and must be manually triggered, which also allows for automatic organization starting from the root.

Later, I will do something similar for the ItemDefinition portion. Regarding ordering by name, I do not want it to interfere with the order by parent.
 
Hi, I've done some simple auto-organization and it's more than enough for me. I show the modified code below, hope it can help you.

Opsive\UltimateInventorySystem\Editor\Utility\ItemCategoryEditorUtility.cs:
Code:
/// <summary>
/// Organizes the item attributes of all item categories in the inventory system database.
/// </summary>
/// <param name="database">The inventory system database.</param>
public static void OrganizeItemAttributesOfAllItemCategory(InventorySystemDatabase database)
{
    List<ItemCategory> organizedItemCategories = new List<ItemCategory>();

    while (organizedItemCategories.Count != database.ItemCategories.Length)
    {
        foreach (var itemCategory in database.ItemCategories)
        {
            if (organizedItemCategories.Contains(itemCategory))
            {
                continue;
            }

            bool hasUnorganized = false;
            var parents = itemCategory.ParentsReadOnly;
            if (parents.Count == 0)
            {
                organizedItemCategories.Add(itemCategory);
                continue;
            }

            foreach (var itemCategoryParent in parents)
            {
                if (!organizedItemCategories.Contains(itemCategoryParent))
                {
                    hasUnorganized = true;
                    break;
                }
            }
            if (hasUnorganized)
            {
                continue;
            }

            organizedItemCategories.Add(itemCategory);
            List<AttributeBase> parentItemAttributes = new List<AttributeBase>();
            List<AttributeBase> parentItemDefinitionAttributes = new List<AttributeBase>();
            List<AttributeBase> parentItemCategoryAttributes = new List<AttributeBase>();
            foreach (var parent in parents)
            {
                foreach (var itemAttribute in parent.ItemAttributeCollection)
                {
                    bool exist = false;
                    foreach (var parentItemAttribute in parentItemAttributes)
                    {
                        if (itemAttribute.Name == parentItemAttribute.Name)
                        {
                            exist = true;
                        }
                    }
                    if (!exist)
                    {
                        parentItemAttributes.Add(itemAttribute);
                    }
                }

                foreach (var itemDefinitionAttribute in parent.ItemDefinitionAttributeCollection)
                {
                    bool exist = false;
                    foreach (var parentItemDefinitionAttribute in parentItemDefinitionAttributes)
                    {
                        if (itemDefinitionAttribute.Name == parentItemDefinitionAttribute.Name)
                        {
                            exist = true;
                        }
                    }
                    if (!exist)
                    {
                        parentItemDefinitionAttributes.Add(itemDefinitionAttribute);
                    }
                }

                foreach (var itemCategoryAttribute in parent.ItemCategoryAttributeCollection)
                {
                    bool exist = false;
                    foreach (var parentItemCategoryAttribute in parentItemCategoryAttributes)
                    {
                        if (itemCategoryAttribute.Name == parentItemCategoryAttribute.Name)
                        {
                            exist = true;
                        }
                    }
                    if (!exist)
                    {
                        parentItemCategoryAttributes.Add(itemCategoryAttribute);
                    }
                }
            }

            bool dirty = false;

            if (parentItemAttributes.Count != 0 &&
                OrganizeItemAttributes(parentItemAttributes, itemCategory.ItemAttributeCollection.Attributes))
            {
                dirty = true;
            }
            if (parentItemDefinitionAttributes.Count != 0 &&
                OrganizeItemAttributes(parentItemDefinitionAttributes, itemCategory.ItemDefinitionAttributeCollection.Attributes))
            {
                dirty = true;
            }
            if (parentItemCategoryAttributes.Count != 0 &&
                OrganizeItemAttributes(parentItemCategoryAttributes, itemCategory.ItemCategoryAttributeCollection.Attributes))
            {
                dirty = true;
            }
            if (dirty)
            {
                Debug.Log($"Organizing item attributes of item category: {itemCategory.name}.");
                //SetItemCategoryDirty(itemCategory, true);
            }
        }
    }
}

/// <summary>
/// Organizes the item attributes of the parent order according to the target order.
/// </summary>
/// <param name="parentOrder">The parent order to follow.</param>
/// <param name="target">The target order to organize.</param>
/// <returns>Returns true if the target order was modified, false otherwise.</returns>
private static bool OrganizeItemAttributes(List<AttributeBase> parentOrder, ResizableArray<AttributeBase> target)
{
    int targetCount = 0;
    bool dirty = false;
    for (int i = 0; i < parentOrder.Count; i++)
    {
        var parentAttribute = parentOrder[i];
        for (int j = 0; j < target.Count; j++)
        {
            var atribute = target[j];
            if (parentAttribute.Name == atribute.Name)
            {
                if (j != targetCount)
                {
                    target.RemoveAt(j);
                    target.Insert(targetCount, atribute);
                    dirty = true;
                }
                targetCount++;
            }
        }
    }
    return dirty;
}

Opsive\UltimateInventorySystem\Editor\Managers\ItemCategoryManager.cs
Code:
...
 private Button m_AutoOrganizeAllButton;
 private Toggle m_IsAbstract;
 private VisualElement m_MutableAndUniqueContainer;
 private Toggle m_IsMutable;
 private Toggle m_IsUnique;
...
 
 
...
 m_AutoOrganizeAllButton = new Button();
 m_AutoOrganizeAllButton.AddToClassList(InventoryManagerStyles.SubMenuButton);
 m_AutoOrganizeAllButton.text = "Auto Organize All";
 m_AutoOrganizeAllButton.clicked += () =>
 {
     ItemCategoryEditorUtility.OrganizeItemAttributesOfAllItemCategory(m_InventoryMainWindow.Database);
 };
 m_ManagerContentContainer.Add(m_AutoOrganizeAllButton);

 m_IsAbstract = new Toggle("Abstract");
 m_IsAbstract.tooltip =
...

Opsive\UltimateInventorySystem\Editor\Utility\ItemDefinitionEditorUtility.cs
Code:
/// <summary>
/// Organizes the item attributes of all item definitions in the inventory system database based on their category order.
/// </summary>
/// <param name="database">The inventory system database.</param>
public static void OrganizeItemAttributesOfAllItemDefinition(InventorySystemDatabase database)
{
    foreach (var itemDefinition in database.ItemDefinitions)
    {
        bool dirty = false;
        var itemCategory = itemDefinition.GetItemCategory() as ItemCategory;
        if (itemDefinition.ItemDefinitionAttributeCollection.Count != 0 &&
            OrganizeItemAttributes(itemCategory.ItemDefinitionAttributeCollection.Attributes, itemDefinition.ItemDefinitionAttributeCollection.Attributes))
        {
            dirty = true;
        }
        if (itemDefinition.DefaultItem.ItemAttributeCollection.Count != 0 &&
            OrganizeItemAttributes(itemCategory.ItemAttributeCollection.Attributes, itemDefinition.DefaultItem.ItemAttributeCollection.Attributes))
        {
            dirty = true;
        }
        if (dirty)
        {
            Debug.Log($"Organizing item attributes of item definition: {itemCategory.name}.");
            SetItemDefinitionDirty(itemDefinition, true);
        }
    }
}

/// <summary>
/// Reorders the attributes in the target array based on the category order array.
/// </summary>
/// <param name="categoryOrder">The category order array.</param>
/// <param name="target">The target array to be reordered.</param>
/// <returns>Returns true if any reordering is performed.</returns>
private static bool OrganizeItemAttributes(ResizableArray<AttributeBase> categoryOrder, ResizableArray<AttributeBase> target)
{
    int targetCount = 0;
    bool dirty = false;
    for (int i = 0; i < categoryOrder.Count; i++)
    {
        var parentAttribute = categoryOrder[i];
        for (int j = 0; j < target.Count; j++)
        {
            var atribute = target[j];
            if (parentAttribute.Name == atribute.Name)
            {
                if (j != targetCount)
                {
                    target.RemoveAt(j);
                    target.Insert(targetCount, atribute);
                    dirty = true;
                }
                targetCount++;
            }
        }
    }
    return dirty;
}

Opsive\UltimateInventorySystem\Editor\Managers\ItemDefinitionManager.cs
Code:
...
private Button m_AutoOrganizeAllButton;
protected ItemCategoryField m_ItemCategoryField;
protected ItemDefinitionField m_ParentField;
protected UnityObjectFieldWithPreview m_IconField;
...

...
m_AutoOrganizeAllButton = new Button();
m_AutoOrganizeAllButton.AddToClassList(InventoryManagerStyles.SubMenuButton);
m_AutoOrganizeAllButton.text = "Auto Organize All";
m_AutoOrganizeAllButton.clicked += () =>
{
    ItemDefinitionEditorUtility.OrganizeItemAttributesOfAllItemDefinition(m_InventoryMainWindow.Database);
};
m_ManagerContentContainer.Add(m_AutoOrganizeAllButton);

m_ItemCategoryField = new ItemCategoryField(
    "Item Category",
    m_InventoryMainWindow.Database,
...
 
Last edited:
Top