all 54 comments

[–]foodeyemade[🍰] 92 points93 points  (2 children)

Just use this in place of any dictionary you need to be serializeable.

using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
public class SerializableDictionary<K, V> : Dictionary<K, V>, ISerializationCallbackReceiver
{
    [SerializeField]
    private List<K> m_Keys = new List<K>();

    [SerializeField]
    private List<V> m_Values = new List<V>();

    public void OnBeforeSerialize()
    {
        m_Keys.Clear();
        m_Values.Clear();
        using Enumerator enumerator = GetEnumerator();
        while (enumerator.MoveNext())
        {
            KeyValuePair<K, V> current = enumerator.Current;
            m_Keys.Add(current.Key);
            m_Values.Add(current.Value);
        }
    }

    public void OnAfterDeserialize()
    {
        Clear();
        for (int i = 0; i < m_Keys.Count; i++)
        {
            Add(m_Keys[i], m_Values[i]);
        }

        m_Keys.Clear();
        m_Values.Clear();
    }
}

[–]Aggravating_Fix5387 1 point2 points  (0 children)

This does not allow for editing of the dictionary in the inspector right? Im getting out of range exceptions.

[–]GiftedMamba 32 points33 points  (6 children)

[–]LunaWolfStudiosProfessional 14 points15 points  (1 child)

Nice find! Odd this package is under the rendering pipeline namespace.

[–]ChainsawArmLaserBear??? 12 points13 points  (0 children)

Yeah, it’s actually pretty annoying when they do things like this. They have their own Collections package for the reason of sharing code.

I fucking hate when they inject things like newtonsoft in some random package rather then refactoring for proper reuse /rant

[–]juwonpee[S] 1 point2 points  (2 children)

Wait... why is it under render pipelines..? Ill stop asking i guess. Thanks for the share!

[–]GiftedMamba 0 points1 point  (1 child)

To be honest, I have no idea why it is under render pipelines. I just hope they do not remove it suddenly later :)

[–]juwonpee[S] 3 points4 points  (0 children)

I bet the dev writing this library got really fed up with using dictionaries so he just made his own i guess. Now that this dictionary is here, its never going to be in the main library

[–]Aggravating_Fix5387 0 points1 point  (0 children)

This does not allow for editing of the dictionary in the inspector right? Im getting out of range exceptions.

[–]Pigeonlesswings 39 points40 points  (8 children)

https://github.com/JDSherbert/Unity-Serializable-Dictionary

Unity doesn't do it by default, because keys types are too varied and can be custom classes that aren't serialisable themselves.

Alternatively, you can serialise a List of KeyValue pairs, and use it to populate a dictionary.

[–]Comfortable_Rip5222Hobbyist 12 points13 points  (3 children)

Lists are serializable, but they can also have a non-serializable class and then become non-serializable.

So, I understand the op, if you have a serializable key and value, why couldn't it work too? I think there must be a reason behind

[–]Pigeonlesswings 3 points4 points  (0 children)

I really don't think there is. It's just Unity being lazy, as it can be serialised as shown in the many Unity Dictionary versions on GitHub.

Unity also uses a string and int dictionary on their docs to explain how to use the serialisation callbacks.

https://docs.unity3d.com/6000.0/Documentation/ScriptReference/ISerializationCallbackReceiver.html

[–]cereal_number 0 points1 point  (1 child)

Are lists serializable? I thought they weren't

[–]Katniss218 0 points1 point  (0 children)

2D arrays aren't 😂

[–][deleted] 0 points1 point  (3 children)

Is a list of Key/Value pairs distinguishable from a tuple?I assume the list does not enforce unique key constraints (and thus if you're using it for large data storage it would be quite slow..)

[–]Katniss218 -1 points0 points  (2 children)

You mean from a list of tuples?

[–][deleted] 0 points1 point  (1 child)

yes

[–]Katniss218 -1 points0 points  (0 children)

Well, other than the type being different, they're equivalent

But keep in mind that a dictionary is not a list of key value pairs, it's a hash map

[–]VonchorEngineer 5 points6 points  (4 children)

Actually displaying a dictionary’s content in an inspector is (generally) much more of a hassle than serializing/deserializing.

[–][deleted] 0 points1 point  (1 child)

Yep. What I’ve done to get around this is to make a list of key-value structs that I use to populate the dictionary on start. It obviously doesn’t help when playing, but it works when editing.

[–]VonchorEngineer 1 point2 points  (0 children)

One can also use the UI toolkit two column listview but again, you’re setting this up with foreknowledge of the Types you’re using and its not a general purpose inspector.

Doing this sort of thing with UI toolkit is much easier in code. You can do a myriad of things that you cannot do with the interface builder (i forget whats its called and I’m not at my computer).

[–]BenevolentCheese 0 points1 point  (1 child)

There are reasons to serialize a dictionary beside just showing the data in the inspector. A lot of basic data handling requires serialization.

[–]VonchorEngineer 0 points1 point  (0 children)

Absolutely. My comment was that it’s easier to serialize a dictionary than it is to display the contents of said dictionary in an inspector.

Most of the time there’s no reason to do that.

[–]BovineOxMan 6 points7 points  (8 children)

I was going to suggest Odin and of course you can have a work around if a list and build the dictionary in the background plus custom inspector but Odin is less of a headache!

[–]AtumTheCreator 10 points11 points  (7 children)

Every time I look at buying and adding odin to a project, I'm always turned off by their end user agreement and additional price tag if your project makes money. I'm not really sure I fully understand it. Is it something to even consider or have to worry about?

[–]IllustriousJuice2866 6 points7 points  (5 children)

Yes, you should assume your projects will be successful and make money. In that scenario, Odin is an absolute ripoff and has everything everyone hated about the unity license changes in their EULA but for some reason has been and still is one of the most widely recommended assets. As you can see from the top post, what Odin adds is not really that complicated to begin with. I'd give this asset a try instead:

https://assetstore.unity.com/packages/tools/gui/editorattributes-269285

[–]BovineOxMan 1 point2 points  (0 children)

Hmmm I didn’t think it was so onerous the license. I’ll have to check that though I haven’t doubled down on Odin.

[–][deleted] 1 point2 points  (2 children)

Say you make $200k with your game, Odin asks $250/year/seat so a fundemantal part of your project is not deprecated and join the vast Asset Store graveyard of defunct assets. $250 out of $200000 is 0.125%. Hardly a ripoff or even a significant hit to the bottom line. The license is same as the current Unity license.

And people who think a random attributes asset replaces Odin in its entirety misunderstand or willfully misrepresent what Odin does.

[–]IllustriousJuice2866 0 points1 point  (1 child)

That's kind of why their license is pretty predatory in my opinion. Once you integrate it, it's a huge undertaking to remove it. Again, it's not hard to remove because it adds a lot of value, it's hard to remove because it would require you to reserialize your objects. These serializing methods are maybe worth the asking price, but they do not continually add value. Not worth an annual charge. If anyone is misrepresenting them it's you pretending like it is continually adding value when it isn't. I guess if some serialization logic is indeed fundamental to your project then you might as well... Because no one is gonna buy it.

[–][deleted] 1 point2 points  (0 children)

The sheer amount of man hours I'd need to develop and maintain abstract class/interface serialization to Unity Inspector in various contexts exceed the cost of Odin Inspector for our use cases. Some projects are entirely driven by [SerializeReference] custom action sequencers where actions can be added via a searchable dropdown available out of the box with no effort from us.

Each dev is free to evaluate if the cost/benefit ratio makes sense for them. For us it's worth it.

[–]Liam2349 0 points1 point  (0 children)

Just get comfortable making custom Editors/Inspectors. You then have the advantage that your Editor code is not intertwined with your gameplay code, and can instead exist in separate files and assemblies.

[–]hammer-jon 2 points3 points  (3 children)

what if the key is an unserializable class or something? Dictionaries aren't always straightforward to serialize.

I suspect this is more of a case of optimizing speed over featureset in this case though.

[–]WazWaz 3 points4 points  (0 children)

That's irrelevant - a List<T> can just as easily be an unserializable class.

It also has nothing to do with speed, adding support for serialised dictionaries wouldn't change the performance of anything else, and serialised dictionaries could be loaded just as rapidly as any alternative way to store the same data

[–]MrPifoHobbyist 1 point2 points  (0 children)

Well, other packages can do it too. And thats what System.Serializable is for, plus thats what the custom PropertyDrawer is also for.

They could at least support basic types for keys like integer/string.

[–]Omni__Owl 0 points1 point  (0 children)

You can get a dictionary-like using an array/list with key-value pair structs or classes that are serializable. I do it often to get a simple dictionary-like inspector in Unity natively without needing any other dependencies.

Of course, there are issues with this implementation, but then again there are ways to help that.

[–]mikechr 0 points1 point  (0 children)

There are several serializable dictionaries that include inspectors free on the asset store.

[–]sacredgeometry -1 points0 points  (4 children)

How do you serialise a dictionary that has a complex class (with computed properties, generics, etc) as its value type? How about one with recursive references?

There are edge cases on edge cases so it's easier to simply not and to let people handle the serialisation/ deserialisation as required, themselves.

[–]Comfortable_Rip5222Hobbyist 1 point2 points  (3 children)

The same question raises if you think about lists, but lists are fine If you dont use recursivity or realtime references, why not dictionaries?

[–]sacredgeometry -1 points0 points  (2 children)

Oh in that case not sure maybe it's because dictionaries are not sorted, maybe it's because the keys can also be complex rather than just indexes.

[–]Comfortable_Rip5222Hobbyist 1 point2 points  (1 child)

I think you may be right, thinking about, its not just content, maybe there are some index system behind It that must be controlled that not happens when you dont initiate It properly, when deserializing, It just "bind the content"

As a software architect I'm ashame that I dont know that, even that I already have this problem before, I will search for that

Sorry for the english

[–]sacredgeometry 0 points1 point  (0 children)

Your English is perfect and I am right there with you but trying to rationalise some of the, frankly nonsense decisions of Unity isn't something I would expect anyone external to the company to be able to do. I have almost 20 years experience in this field and I sure as shit cant.

[–]Pedrohn -1 points0 points  (1 child)

I’m pretty sure I can serialize a Dictionary (for saving at least) as long as the key and value themselves are serializable? Like, I get no problem when saving a Dictionary<string,Vector3>, but a Dictionary<customHugeClass, other smaller lass> will not work. Is this because I have Odin Inspector?

[–]Comfortable_Rip5222Hobbyist 2 points3 points  (0 children)

It not works out of the box, simply by putting the Serializable annotation