Post Edit delegate for an asset? (datatable)

I wish to track any modification to only a single datatable. A UDataTable has a delegate for that, but it is not accessible from an FDataTableRowHandle (const datatable).

Currently I am using:

FCoreUObjectDelegates::OnObjectModified.AddUObject(this, &UMyObject::ActOnObjectChanged);

Where I have to check if any changed UObject happens to be this datatable. Another side effect which seems to be caused by this workaround is that I don’t get the most recent data from the DataTable during ActOnObjectChanged. It lags one edit behind, which breaks the system.

You can’t bind to the table member of FDataTableRowHandle because it’s a pointer to a const table, and the event is a member of that table.

DataTables should be treated as “const” at runtime, they are meant for static data only. If you want a Key/Value pair set at runtime then just use regular TMap’s.

Assuming this for an edit-time tool, if so, you can just cast the const away. FTableRowBase also has callbacks for when the table is modified, which you can override for a specific table struct.

You can also use the Data Validation system to validate tables on save and log errors etc.

It is used within an editor module to update an object on the editor panel when I update my datatable. The datatable itself is not modified through my code, I only want to know when it is modified during editor time. The FDataTableRowHandle format is used so I can use the datatable + row “picker” on the editor panel.

Is it not undefined behavior to const_cast away the const and then write to its delegate?

const_cast conversion - cppreference.com

The issue is that UObject::Modify is always called before changes are made, you want to find some kind of post-edit change delegate. They do exist but I can’t name them currently.

RE the const_cast - probably, but I’ve always found it works fine in practice. Design decisions at the engine level sometimes make it hard to care about const-correctness when making editor tools…

that post-edit delegate sounds like the way to go, I’d rather not mess with possible UB. I found something that might just be it, but I don’t know how to use it:

FDataTableEditorUtils::FDataTableEditorManager::Get().AddListener([]( ??? ) { });

It makes use of INotifyOnChanged (ListenerManager) of which I can’t find any example in engine .cpp files.

FDataTableEditorUtils::BroadcastPostChange(DataTable, EDataTableChangeInfo::RowList);

bump

:up:

:arrow_up_small:

:up:

:wave:

Up :slight_smile:

let’s try again

Make your class inherit from public FListenerManager<UDataTable, FDataTableEditorUtils::EDataTableChangeInfo>::BaseNotifyOnChanged, and override the PreChange and PostChange functions.

You can replace UDataTable in above with a more specific class you want.

class UMyDataTableListener : public UObject, public FListenerManager<UDataTable, FDataTableEditorUtils::EDataTableChangeInfo>::BaseNotifyOnChanged
{
    virtual void PreChange(const UDataTable* Changed, FDataTableEditorUtils::EDataTableChangeInfo ChangedType) override;
    virtual void PostChange(const UDataTable* Changed, FDataTableEditorUtils::EDataTableChangeInfo ChangedType) override;
}

Then do:

FDataTableEditorUtils::FDataTableEditorManager::Get().AddListener(this); 

Don’t forget to remove the listener at some point.

1 Like