FChooserColumnBase::Filter

Hi,

I have a question about Filter function in FChooserColumnBase. I have noticed that for FBoolColumn (also for FFloatRangeColumn), the code is not checking whether InputValue.Get<FChooserParameterBoolBase>().GetValue(Context,Result) returns true:

void FBoolColumn::Filter(FChooserEvaluationContext& Context, const FChooserIndexArray& IndexListIn, FChooserIndexArray& IndexListOut) const { if (InputValue.IsValid()) { bool Result = false; InputValue.Get<FChooserParameterBoolBase>().GetValue(Context,Result);

However, for FEnumColumn (also for GameplayTagColumn and ObjectColumn), Filter checks whether InputValue.Get<FChooserParameterEnumBase>().GetValue(Context, Result) returns true:

void FEnumColumn::Filter(FChooserEvaluationContext& Context, const FChooserIndexArray& IndexListIn, FChooserIndexArray& IndexListOut) const { uint8 Result = 0; if (InputValue.IsValid() && InputValue.Get<FChooserParameterEnumBase>().GetValue(Context, Result)) { #if WITH_EDITOR if (Context.DebuggingInfo.bCurrentDebugTarget) { TestValue = Result; } #endif

Is this a bug? If not, what is the reasoning behind this difference?

Kind regards,

Maryam

Hi, thanks for flagging this one. It is missing functionality/a bug for the bool column, and a few other column types. The use case for that functionality is mainly that when live-editing, if you add a column, we want that column to pass through all the inputs until the underlying property has been set.

In the case of Bool columns, the lack of the GetValue check won’t actually break anything because Bool column entries default to Any so they’ll always pass anyway. But the FloatDistance and FloatRange columns will break in that live-edit example. I’m going to get a fix made for all of these.

Hi Euan,

Thanks for helping me with this!

I noticed this issue when I was trying to evaluate a chooser in code. I assumed that I had to provide context data in the same order that it appears on Chooser Table but it seems to not be the case.

Let’s say I have first added StructA to my Context Data in my Chooser Table. Let’s also say that the first Column is an Enum Column that is bound to StructA->EnumVariable. At some point later, I add StructB to my Context Data and change the first Column’s type to Bool and bind it to StructB->BoolVariable. On the code side, I create an FChooserEvaluationContext and add my StructA and StructB instances to it, and call Chooser->ChooseMulti. Now consider the following 2 scenarios:

1- In my FChooserEvaluationContext, StructA is at index 0 in Params and StructB is at index 1 in Params. Chooser->ChooseMulti behaves as I expect.

2- I go to my Chooser Table and change the order of Context Data in Settings. So now StructB is before StructA in my Chooser tables’s Context Data section. Since the order has changed, I change my FChooserEvaluationContext in code to have StructB at index 0 and StructA at index 1. To my surprise, I see the chooser evaluation is incorrect. I debug it and I notice three issues:

A) Even though their order has changed in my Chooser Table and StructB is now before StructA, the bool column’s FChooserPropertyBinding::ContextIndex is 1. So it expects StructB to be at index 1!

B) When it grabs StructA from index 1 (because StructA is at index 1 instead of StructB) and looks for the bound bool property, the search fails. However, the code doesn’t check that InputValue.Get<FChooserParameterEnumBase>().GetValue(Context, Result)) has failed and just continues assuming that the value of Result is false. When in fact Result is invalid because the code has failed to find the bound property.

C) All my other chooser table columns are enums and bound to variables from StructA. The search for them fails too because the code expects StructA to be at index 0. However when the check for InputValue.Get<FChooserParameterEnumBase>().GetValue(Context, Result) fails, this piece of code runs:

else { // passthrough fallback (behaves better during live editing) IndexListOut = IndexListIn; }So all the rows pass through, when I would have expected no rows to pass through because Result is invalid.

So I wonder if:

1) It is also a bug that when I change the order of Context Data in chooser table, FChooserPropertyBinding::ContextIndex for the columns doesn’t get updated? I tried to look a bit on the code side to understand how ChooserEvaluate custom node generates FChooserEvaluationContext and how it orders the Params but I couldn’t figure it out. I only noticed that changing the order of Context Data in chooser table, changes the order of input pins in the Evaluate Chooser node as expected.

2) It is a bug that when the Result validity check fails, all rows pass through the filter?

Kind regards,

Maryam

This is actually the expected behaviour at the moment. It’s because you have to rebind the columns properties after changing the order of the parameters in the Chooser Table. That’s because ContextIndex is set via CopyPropertyChain which is only called when the property is bound to the column. So if you re-bind your column properties after re-ordering the parameters in the table settings, you would need to update the order that you add your objects to FChooserEvaluationContext. If you didn’t re-bind your column properties after re-ordering, the indices should stay the same so you wouldn’t need to update the order.

Longer term, what we’d like to do is change this behaviour so that it’s name-based, and not dependent on the order in which the parameters, or objects in the context, are added. That should remove all of these edge cases.

In terms of the fallback behaviour when the Result validity check fails, that is intentional. Although it’s not intentional for the case that you’ve run into. The idea is about facilitating live-editing like I mentioned before. If we didn’t have the fallback behaviour, when you were live editing and you added a new column, evaluation of the Chooser would fail in most cases and so break whatever the user was live editing. So the workaround for that is this fallback behaviour where all the rows are output.

Let me know if you need any more info on this.

Thanks Euan,

This is really helpful. Regarding what you said, I have 3 further questions:

1- What does count as rebinding exactly? Is it changing the bound variable? Is it changing the column type?

2- What if you only rebind one column and not the others? Does it update the index for all of them or only for the one that is rebound?

3- What is live editing? Is it editing the chooser table during PIE?

Kind regards,

Maryam

Good to hear the previous info was useful.

What does count as rebinding exactly? Is it changing the bound variable? Is it changing the column type?

Binding/rebinding happens when the property is set on the column in the Chooser Table, so the method I mentioned runs when you do this:

[Image Removed]What if you only rebind one column and not the others? Does it update the index for all of them or only for the one that is rebound?

You would run into problems because the indices won’t match, assuming the parameters had been reordered before the rebinding. This is all quite brittle which is why doing the name matching would help a lot vs the current implementation.

What is live editing? Is it editing the chooser table during PIE?

Yeah, exactly. You can make edits to the Chooser Table while running PIE and connected to one of the active skeletal meshes. I think the Fortnite team use this live-editing workflow (in general, not just with choosers) quite extensively to make animation changes and see them update immediately in the viewport.

Thanks Euan!