History and interpolation
The current game logic will be mostly used in the server. Same code will probably be used on the client to predict the outcome of the commands issued by the player.
The outcomes of all commands of all of the players form a history. The history is generated by the server.
This PR starts from an in-memory representation of the history (it's not about network). The goals are:
- [x] modify attributes, so they can record changes
- [x] position is not an
Attribute, so capture changes inside the constructor and actions - [x] write out the history while the client is running (currently it has all the server code)
- [ ] write out the history of object creation
*no server-side prediction/correction for the moment
*no special format
- [ ] replay that history on the client
- [ ] output the history with server-side predictions and corrections (move away from recording every change of an attribute)
- [ ] replay the history that contains corrections
Integration is probably going to be via Unit::action_secondary, UnitContainer::new_unit and Unit::delete_unit. The idea is to create one CurveAction that will sit forever in the Unit::action_secondary and apply all curves on each graphical tick.
To extract changes, the members of Attribute<T> can be transformed into "spying" values. It's enough for point-curves, but things like MoveAction will eventually need to generate longer curves.
At the end of each logic tick (maybe I should call it a network tick) the history will be resynchronized and a segment from it will be used to show the next tick. Pipelining will be needed. The network frame rate is flexible because in theory it's inversely proportional to the amount of stuff that is coming.
Related - #530.
I tried to take a look at your code, but it's a little hard for me to understand exactly what are you doing. So I will try to list some random things in case they help you....
- There are shared and unshared attributes. For the unshared attributes you need to consider one for each unit, but for the shared you need to consider only one per unit type. This was the main purpose of my pr #683, to split all the attributes to shared and unshared in order to able to implement systems on them (= research system, nyan, your history)
- I saw some text streams in your code, in case you use them for the history, I suggest to use fixed binary streams (for speed, space and cleanness)
- Your are implementing the history in a way but If I was to do it (my approach):
- On attribute change -> Flag attribute as changed (using setters or something more advanced)
- On network tick end -> Get all flagged attributes and write on the history a copy (whole attribute not only the change, they are small enough to copy/send the whole thing)
- My pr is mainly changes the game logic side and no the technical side, so I haven't something else for you...
I don't have much xp in this kind of things but If you think I can help you, I'm here...
Okay, it's not automatically compatible with the upstream changes. Anyways, the attribute tracking that I've tried here won't be the final solution.
I'll probably have to implement the history generation in every "action" individually.
How is this going? I'm still interested in this as it relates to #652 "Headless Mode".
We've thought about it a lot, it resulted partially in #744 and the prediction project, as we don't want to keep the history only, but also the future (#740). @Tomatower and I have been thinking about it a lot and we'll try to bring in some system as fast as possible, as this will be the new gamestate foundation.
we don't want to keep the history only, but also the future
@TheJJ there is no distinction between history and future if you're talking about this PR.
@coffenbacher it's kinda hard to stitch serialization of the game events with the current game logic model that is clearly made for the lockstep RTS: serialization of the player's commands.
@ChipmunkV all I really want is some way to inject actions into the engine (like a player) and interrogate its current state (like a UI would need to) without a fat gfx stack on top of it 😄 In fact, curve generation should make the types of headless tests/simulations I want to do ridiculously simple and fast. I think it just requires waiting for the new gamestate implementation to see what it would look like however.