When trying to set a value to multiple objects through code, only one object gets his new value and rest are null.

Issue #680 resolved
Amit Bu created an issue

First of all, really good job on the super helpful plugin! thank you.

1. What happened?

I’ve managed to serialize the following data structure:

public enum CityType
{
    London,
}
public enum CityItemType
{
  LondonEye,
  LondonTower
}

public class CitiesManager : SerializedMonoBehaviour
{
  public enum CityType
  {
    London,
    Berlin
  }
  // this would serialize
  public Dictionary<CityType, City> cities;
}
[Serializable]
public sealed class City
{
    [NonSerialized] [JsonIgnore] [IgnoreDataMember] public bool isInitialized;

    public CityType cityType;

    // this would serialize as well
    public Dictionary<CityItemType, CityItem> cityItems;

    [JsonConstructor]
    public CapitalCity() { }

    public CapitalCity(CapitalCity city)
    {
        this.cityItems = new Dictionary<CityItemType, CityItem>(city.cityItems);
    }

    [Serializable]
    [JsonObject(MemberSerialization.OptIn)]
    public sealed class CityItem
    {
        [JsonProperty]
        [OdinSerialize]
        public CityItemProgress ItemProgress { get; set; }

        public CityItem() { }
    }

    [Serializable]
    public sealed class CityItemProgress
    {
        public double itemWeight;
        public double rewardPerComplete;

        public bool IsCompleted { get; set; }

        private double _progress;
        public double Progress
        {
            get => _progress;
            set
            {
                if (value > itemWeight)
                {
                    if (!IsCompleted)
                        IsCompleted = true;
                    return;
                }
                if (value.Equals(itemWeight))
                    IsCompleted = true;

                _progress = value;
            }
        }

        [JsonConstructor]
        public CapitalCityItemProgress() { }

        public CapitalCityItemProgress(double itemWeight, double rewardPerComplete)
        {
            this.itemWeight = itemWeight;
            this.rewardPerComplete = rewardPerComplete;
        }
    }
}

Now, I’ve written a button that will fill in the field - ItemProgress in CityItem class (Code below)

Let’s suppose I have added 1 element to the cities dictionary (City class) and added 2 Items as well to the cityItems dictionary (CityItem class), the problem is that when I press the button mentioned above, only the first item in cityItems is getting his ItemProgress field set while the other item at first gets set but after a second something sets it to null. If I press the button again, both item’s fields are getting set normally.

It’s not that bad when i’m working with small collections but as soon as these collections start to stack up, and I have 10 cities, and at least 8 items for each city, well… yeah I can’t work like that.

Here’s the code for the button - basically what it does is to give each city item a different weight so that the sum of all the items will be the levels count for this city:

[PropertySpace(8f)]
[Button("Assign weights to city items", ButtonSizes.Medium, ButtonStyle.Box)]
private void AssignWeightsToItems(CityType cityType)
{
    if (!cities.ContainsKey(cityType))
    {
        Debug.LogError($"No such city in cities ({cityType})");
        return;
    }
    var city = cities[cityType];
    var items = city.cityItems;
    int itemCount = items.Count;
    int evenDivide = GameObject.FindObjectOfType<LevelsManager>().GetLevelsCountByCity(cityType) / itemCount;
    double nextNum = -1;
    int counter = 0;
    foreach (var item in city.cityItems)
    {
        double itemWeight;
        if (!nextNum.Equals(-1))
        {
            itemWeight = nextNum;
            nextNum = -1;
        }
        else
        {
            var rand = (int)UnityEngine.Random.Range(0, evenDivide - (evenDivide * 0.5f));
            itemWeight = evenDivide - rand;
            nextNum = evenDivide + rand;
        }

        if (counter == itemCount - 1 && !nextNum.Equals(-1))
        {
            itemWeight = evenDivide;
        }

        item.Value.ItemProgress = new City.CityItemProgress(itemWeight, 1 / itemWeight);
        counter++;
        item.Value.itemType = item.Key;
        item.Value.cityType = cityType;
    }
}

How can we reproduce it?

Just copy the above code and add 1 city to the cities dictionary, and 2 items to the cityItems dictionary.

then press the button and observe.

after clicking the button:

In my game, I call the City class CapitalCity, so just know that it’s the same.

4. What version of Unity are you using?

2019.4.3f1

5. What version of Odin are you using?

2.1.12

6. Do you have Editor Only mode enabled?

No.

7. What operating system are you on?

Windows 10.

Comments (2)

  1. Log in to comment