Savander wrote:it just saving it every x seconds :c
D: okay...
I think that one, kinda reasonable implementation of undo is to keep track of all operations using a register and just doing them backwards if needed. It could be a stack constructed of:
Code: Select all
struct Operation
{
enum OperationCode operationCode;
float value; // I guess everything in Teeworlds is described using floats, am I right?
}
Where OperationCode is:
Code: Select all
enum OperationCode
{
PARAMS_BEGIN,
PARAMS_END,
GROUP_OPERATION_BEGIN,
GROUP_OPERATION_END,
OPERATION_1,
// (...)
}
If any operation requires more than one data "value" field - like, for example, placing a block (x coordinate, y coordinate, block ID, map group, group layer, additional values of tele/switch/speedup layers, &c.), we would fill its "value" field with dummy argument and put a params block after it. Such block would begin with "PARAMS_BEGIN", end with "PARAMS_END" and would be filled with the preceding operation data.
Example:
Code: Select all
{PLACE_BLOCK, 0},
{PARAMS_BEGIN, 0},
{PLACE_BLOCK_X, 12},
{PLACE_BLOCK_Y, 45},
{PLACE_BLOCK_BLOCK_ID, 22},
// &c.
{PARAMS_END, 0}
If any operation consist of multiple operations (like copying is in fact a multiple block placement), we will fill its "value" field with a dummy argument and then wrote down all atomic operations it's constructed of, surrounding them with "GROUP_OPERATION_BEGIN" and "GROUP_OPERATION_END". Optional group operation parameters could be put between its struct and the struct of "GROUP_OPERATIONS_BEGIN".
Example:
Code: Select all
{BLOCKS_COPY, 0},
{PARAMS_BEGIN, 0},
{COPY_X_1, 10},
{COPY_Y_1, 5},
{COPY_X_2, 30},
{COPY_Y_2, 15},
{COPY_MAP_GROUP, 2},
{COPY_GROUP_LAYER, 3},
{COPY_NEW_X_1, 40},
{COPY_NEW_Y_1, 20},
{COPY_NEW_X_2, 60},
{COPY_NEW_Y_2, 30},
{COPY_NEW_MAP_GROUP, 2},
{COPY_NEW_GROUP_LAYER, 3},
{PARAMS_END, 0},
{GROUP_OPERATION_BEGIN, 0},
{PLACE_BLOCK, 0},
{PARAMS_BEGIN, 0},
{PLACE_BLOCK_X, 40},
{PLACE_BLOCK_Y, 20},
// (...)
{PARAMS_END, 0},
{PLACE_BLOCK, 0},
{PARAMS_BEGIN, 0},
{PLACE_BLOCK_X, 41},
{PLACE_BLOCK_Y, 20},
// (...)
{GROUP_OPERATION_END, 0}
When user does anything in the editor, the relevant structs are put onto the stack. If user opens the undo list, the stack is displayed (in a user-friendly form, of course :3). If the user undoes anything, we just take structs back from the stack and do them backwards until we reach the one below that chosen by him.
Of course, it will be necessary to check if all operations are represented and handled by this code after every change in the editor, but I guess it's the price to pay (I don't see any way of doing it at compile-time, so we'll have to be careful not to add any functionality without adding it to the undo handler, as the user may damage its map by assuming that everything can always be undone). ^^
[mod=Soreu]When you have more than single line of code, please use