We wanted particles to be rewound as well, because that effect is nifty and all, except when you have 500+ particles on the screen, storing all of these every frame becomes really time consuming and memory intensive. So, I figured I'd simplify things a bit by putting a cap on the number of recorded frames and only store critical information: position, rotation, animation frame, and other things that only really needed to be preserved. Then, when you rewound, it would modify the original object to have the stored values. Of course, then I ran into another problem: some objects would get permanently deleted in the present, and when you rewound, it would casually modify the freed memory, corrupting the heap and jacking up the whole game.
In retrospect, this problem would have been incredibly easy to solve: if we had used handles to our game objects, we could have removed the handle from the master game object list so that it would no longer get updated, and when we rewound, it could have freely updated the game object without any problems. The object would still have been freed when the recorded frame was eventually deleted thanks to the cap, and everything would have been good. Instead, I chose to attempt to find every special case that broke rewind and fix it. It cost me at least three weeks of debugging time when I could have been implementing new gameplay features.
Of course, hindsight is 20/20 and now I see I approached the problem from the wrong angle entirely. I did not design our architecture with rewind in mind; while it was dynamic and composition-based, implementing rewind in a robust, flexible, extensible way would have been to add a messaging system that recorded inverse transforms of each gameobject-transforming message. For example, if a change velocity message containing a vector increment was sent to the player, a new message with the negative vector could be automatically stored. All of these messages could be stored in a queue associated with the game object, and when the game object was permanently deleted, all the messages could have been deleted as well. This type of system would have been much more robust and error-proof, as well as extensible with our architecture.
There are many other things I would change if we were to make Tim-E again, but that is the nature of learning though practice. Perhaps if I could just keep all the knowledge I have now and just rewind...?
