TylerTemp / SaintsField

A Unity Inspector extension tool focusing on script fields inspector enhancement
MIT License
184 stars 10 forks source link

Expandable doesn't update the SO value when nested in Unity 2020 #60

Open laurentopia opened 3 months ago

laurentopia commented 3 months ago

with this setup changing expanded team within the editor doesn't update the SO and colored progressbars don't follow color coding set by FillColor(): image image

[Expandable, Required]
public MCTeam team;

and that

public enum ALIANCETYPE { FRIEND, NEUTRAL, ENEMY }
[CreateAssetMenu]
public class MCTeam : ScriptableObject
{
    [Tooltip("for physics raycast, <everything> is fine but setting it can help optimize")]
    public LayerMask layers;
    public List<TeamCounter> aliances;
    [MinMaxSlider(-10, 10)]
    public Vector2 neutralRange = new Vector2(-1, 1);
#if UNITY_EDITOR
    void OnValidate()
    {
        for (var i = aliances.Count - 1; i >= 0; i--) {
            var a = aliances[i];
            a.neutralRange = neutralRange;
            if (a.team == this) aliances.RemoveAt(i);
            if (aliances.FindAll(tt => tt.team == a.team).Count > 1) a.team = null;
        }
    }
#endif
    public ALIANCETYPE GetAliance(MCTeam t) => aliances.Find(a => a.team == t).aliance;

    public ALIANCETYPE AddliancePoints(MCTeam t, int points)
    {
        TeamCounter teamCounter = aliances.Find(a => a.team == t);
        teamCounter.affinity += points;
        return teamCounter.aliance;
    }

    [Serializable]
    public class TeamCounter
    {
        [Layout("ream counter", ELayout.Horizontal)]
        [Required]
        public MCTeam team;
        [ProgressBar(-20, 20, step: 0.1f, colorCallback: nameof(FillColor))]
        public int affinity;
        public ALIANCETYPE aliance
        {
            get {
                if (affinity > neutralRange.y) return ALIANCETYPE.FRIEND;
                else if (affinity < neutralRange.x) return ALIANCETYPE.ENEMY;
                else return ALIANCETYPE.NEUTRAL;
            }
        }
        [HideInInspector]
        public Vector2 neutralRange;
    #if UNITY_EDITOR
        private EColor FillColor() => aliance == ALIANCETYPE.ENEMY ? EColor.Red : (aliance == ALIANCETYPE.FRIEND ? EColor.Green : EColor.Gray);
    #endif
    }
}
laurentopia commented 3 months ago

but changing neutralrange gets stores in the SO, perhaps it's failing within a list

laurentopia commented 3 months ago

and i'm thinking, maybe it's conflicting with the drag and drop reordering of the list... yeah when dragging the progressbar the list element gets dragged, this is the wrong behavior as it contrasts with dragging the reference field which doesn't drag the element.

laurentopia commented 3 months ago

confirmation that it also happens at runtime: that's the SO asset before event image after event image that's the thing referencing the SO after event image the color changed but not the value I had to select the SO then back the user to get value change. and these are the values all changing at the same time. image and that is also happening on the SO so my guess is we're seeing 2 bugs:

  1. ref of SO with expandable that contains a list don't update properly
  2. list of class containing progressbar update funky
laurentopia commented 3 months ago

oops attached the wrong thing, this is all the sliders changing at the same time (list of class with progressbar in it) https://github.com/user-attachments/assets/9996d277-7461-4099-a2c1-15701fc31a2e

TylerTemp commented 3 months ago

There is some weird issue with struct + progressbar. Im looking into it

TylerTemp commented 3 months ago

Hi, please try this script if it's a bit better. (not actually solves everything but should make it more aligned with serialized data)

#if UNITY_EDITOR
using UnityEditor;
#endif

#if UNITY_EDITOR
void OnValidate()
{
    for (var i = aliances.Count - 1; i >= 0; i--)
    {
        var a = aliances[i];
        a.neutralRange = neutralRange;
        if (a.team == this)
        {
            Undo.RecordObject(this, name);  // add this
            aliances.RemoveAt(i);
        }
        if (aliances.FindAll(tt => tt.team == a.team).Count > 1)
        {
            Undo.RecordObject(this, name);  // add this
            a.team = null;
        }
    }
}
#endif
laurentopia commented 3 months ago

Thanks, still doesn't work. I even boxed the onvalidate code in Application.isPlayer==false and removed it altogether. Could it be a 2020 special?

TylerTemp commented 3 months ago

Can you give Unity's full version (2020.x.f1 etc) so I can try re-produce it?

TylerTemp commented 3 months ago

OK I managed to re-produce it in 2020.1.0f1. It's a IMGUI issue. I'm looking into it

TylerTemp commented 3 months ago

https://github.com/user-attachments/assets/886c36ee-42ff-465b-8d7f-ad3db9cc35c9

Fixed. The fix will be released soon

TylerTemp commented 3 months ago

Hi, please check if it's been fixed in 3.2.3

laurentopia commented 3 months ago

image even with the onvalidate removed. edit and play time

TylerTemp commented 3 months ago

Hi, to be clear, does the issue now is:

  1. Now, the ProgressBar can be dragged independently
  2. The ProgressBar works fine in the ScriptableObject itself
  3. But in Expandable, the ProgressBar does not change color correctly, and the value is lost after editing in Expandable
TylerTemp commented 3 months ago

3.2.4 now will apply the changed value by Expandable in IMGUI, please have a try

laurentopia commented 3 months ago

Almost there: it works fine from the [Expandable] scriptableobject reference but now it doesn't work from the SO to the reference. Also the reference's inspector doesn't update when the SO is changed at runtime. That said, damn it's nice already!

TylerTemp commented 3 months ago

Almost there: it works fine from the [Expandable] scriptableobject reference but now it doesn't work from the SO to the reference. Also the reference's inspector doesn't update when the SO is changed at runtime. That said, damn it's nice already!

Hi, I'm a bit confused here.

it doesn't work from the SO to the reference what's the operation here? For what I think, I did:

  1. Click Play to get into play mode
  2. Find the SO, let's say it's named "Main", change the alliaces[0].affinity using inspector to some other value
  3. Click the gameObject, the affinity is correct.
  4. Exit Play mode, the new value is applied

So, what's your operation here so I can re-produce it?

the reference's inspector doesn't update when the SO is changed at runtime.

Do you mean the script changed the So's value like this

[Expandable, Required]
public MCTeam team;

private void Start()
{
    team.alliances[0].affinity = 0;
}

For what I'm testing under IMGUI, it will update the display in the inspector during runtime.

So, any information that helps re-producing it is welcome :)

laurentopia commented 3 months ago

If you reference the SO in a scene gameobject and change the SO, the GO's expanded inspector doesn't update.