Warning: This is an Editor only feature

Undo and redo operations in the engine are implemented using the Transaction system. This system is used by all the Editor systems in order to track changes and accordingly go back and forwards in time.

Transactions operate by having a simple interface to add a Transaction, a Transaction is a simple data type with all the data needed for doing Undo/Redo operations. Base Transaction struct below:

struct Transaction
{
    std::function<void(TransactionPayload&)> undofunc;
    std::function<void(TransactionPayload&)> redofunc;
    TransactionPayload transactionPayload;
};

The TransactionPayload is used to store and access data. It contains a variety of structs and types.

struct TransactionPayload
{
    Actor affectedEntity;
    CoreComponent coreComponent;
    CoreComponent deltaCoreComponent;
    MeshComponent meshComponent;
    MeshComponentRaw meshComponentRaw;
    bool bHasComponents[2];
    bool* bChanged;
    volatile bool* vbChanged;
    std_filesystem::path* path;
};

The whole struct can be left empty if you don’t need any of the data.

The 2 function pointers correspond to their respective actions. Once this struct is passed to the StateTracker, it will manage the passed struct accordingly.

To add a transaction first create a struct with the type Transaction, fill the values in it like this

    Transaction transaction =
    {
        .undofunc = [](TransactionPayload&)
        {
            logger.consoleLog("Undo", UVK_LOG_TYPE_WARNING);
        },
        .redofunc = [](TransactionPayload&)
        {
            logger.consoleLog("Redo", UVK_LOG_TYPE_WARNING);
        }
    };

After you are done configuring the Transaction struct, you can now call push

StateTracker::push(transaction);

Now every time someone presses the undo or redo buttons/key combinations those changes and be undone and redone

Additional info for engine developers

The state tracker handles undo/redo by having 3 arrays. The first array contains all the stored transactions until it, they need to be overridden.

The 2 other arrays contain pointers to the first. These are the arrays where the undo/redo operations happen. The undo array called undoStack contains all transactions that can be undone, and the redo array called redoStack does the opposite. When a transaction is pushed via push the transaction is added to the first array and then to the undoStack, undo is called the transaction at the top of the undo array is popped and pushed to the back of the redo array. Meanwhile, the functions for their respective operations in the Transaction struct are called.