That pesky Duplicate Bug... (InventoryItem)

Notice: Since Unity 2021, this check will result in Unity throwing an error, do not use this

So I discovered a potential “bug” in the code for randomly generating the UUIDs in InventoryItem… If you Duplicate an InventoryItem in the inspector, the UUID for both items will be the same. When you go to retrieve an item, the GetFromID() method will complain about two (or possibly many more) items with the same UUID, and you’ll only be able to retrieve one of the items… even if all three items were saved somewhere…
Fortunately, there’s a solution, though it will require the help of Linq

Add this to your usings clause: using System.Linq;

Then in the ISerializationCallbackReceiver.OnBeforeSerialization() change your method to look like this:

void ISerializationCallbackReceiver.OnBeforeSerialize()
        {
            // Generate and save a new UUID if this is blank.
            if (string.IsNullOrWhiteSpace(itemId))
            {
                itemID = Guid.NewGuid().ToString();
            }
            // Test for multiple objects with the same UUID
            var items = Resources.LoadAll<InventoryItem>(""). //continues below
                       Where(p => p.GetItemID() == itemID).ToList();
            if (items.Count > 1)
            {
                itemID = Guid.NewGuid().ToString();
            }
        }

What this does, in a nutshell, is query the Resources, basically “give me a list of every InventoryItem with this itemID and put it in a List for me”. It’s a magical Query device that System.Linq provides.
The object you’re editing is one of those objects. If there is a duplicate object, then items.Count will be greater than 1. If this is the case, then we change the UUID. If the count is 1, then there is no need to change the UUID of the item.

6 Likes

I love how often you use LINQ, it really helps connect the dots with my day job SQL query brain.

This would be an excellent 'Brian’s tips and tricks" candidate I think.

Takes again!

1 Like

I’m definitely a big fan of LINQ. As long as you’re not doing big sorts every frame (like in an update loop), it’s a very powerful tool.

1 Like

I know I’m late to the party, but as I wait for your upcoming 3rd person <-> RPG tutorial, I decided to see how I can improve my project to make it more robust. This is definitely going to save me from a truck load of headaches down the line (because this bug absolutely bothered me once). Thank you again Brian :slight_smile:

Hi again, sorry if I’m being annoying, but… There’s a bug coming out of this code, in my main project:

Objects are trying to be loaded during a domain backup. This is not allowed as it will lead to undefined behaviour!

UnityEngine.Resources:LoadAll<GameDevTV.Inventories.InventoryItem> (string)
GameDevTV.Inventories.InventoryItem:UnityEngine.ISerializationCallbackReceiver.OnBeforeSerialize () (at Assets/GameDev.tv Assets/Scripts/Inventories/InventoryItem.cs:139)

This is line 139 it’s referring to:

var items = Resources.LoadAll<InventoryItem>("").Where(p => p.GetItemID() == itemID).ToList();

Do I ignore this?

I started getting these messages when the jobs system came out. This check is now obsolete.

2 Likes

No clue what the jobs system is, but okay I guess… :slight_smile:

To make the Editor more performant, it now uses true multitasking under the hood when dealing with serialization, object loading and saving, etc. The long and short of it is that the right hand doesn’t know what the left hand is doing and while the Linq expression is busy trying to sort and test for duplicates, another thread is actually saving the asset, and the two things create a merge conflict.

So one is searching duplicates, and the other is saving them… is Unity trying to destroy itself by accident? :stuck_out_tongue_winking_eye:

1 Like

Privacy & Terms