People like to argue about the respective merits of client/server versus peer-to-peer network topologies, but personally I think this is the wrong debate. Who says you have to pick just one? I'm a big fan of hybrids that combine the best of both worlds.
Network programming is all about compromise. It is impossible to have everything be both 100% accurate and 100% lag free, so we have to make tradeoffs. Sometimes we can put up with a bit more lag in order to increase accuracy, while other times it makes more sense to sacrifice accuracy in the interest of a snappy response.
The million dollar question: which machines control what data?
For every piece of data in your game, you can do a cost/benefit analysis by considering these questions:
The answers will suggest how the data should be controlled:
Note how the choice of what machine controls the data (questions 1 and 2) is independent of whether to apply prediction algorithms (questions 3 and 4).
For example:
Moving spaceships around the screen
Conclusion: each spaceship should be controlled by their local player machine. Prediction algorithms should be applied.
Winning a race
Conclusion: a single authority machine should decide the race results. Prediction should not be used.
Being killed
Conclusion: each machine should be responsible for deciding when their local player is dead. Other machines should not attempt to predict this.
Enhancement: you could get clever and apply some visual-only prediction here. For instance if my machine thinks I got a headshot, but isn't 100% sure yet because it doesn't know exactly where the target player was, it could start playing an "I'm wounded" animation. This gives some immediate visual feedback, while still keeping its options open. If a later network packet confirms the kill, it can transition from the wounded animation into the final death crumple, while if the kill prediction turns out to have been a mistake, it can just cancel the wounded animation and go back to the normal state with no harm done.
Getting into a vehicle
I once worked on a prototype for a game where you could run around on foot and get in or out of many different vehicles. While you were in a vehicle, this was exactly the same scenario I previously described as "moving spaceships around the screen", but getting into vehicles was different. You can't have more than one player driving a vehicle at the same time!
To handle this, we implemented dynamic object ownership. This gave us a new piece of metadata: in addition to deciding which machine controlled each vehicle, we now also had to decide which machine controlled which machines controlled each vehicle.
The vehicle state (steering, physics, collision, etc) was controlled by whatever machine was currently driving it, but we put a single authority machine in charge of deciding who that driver should be. When vehicles were empty, the coordinator allocated them to whatever machine was currently controlling the fewest.
When you ran up next to a vehicle and pressed the "get in" button, here is what happened:
When you were in a vehicle, this was a peer-to-peer architecture, but the more important decisions of getting in and out were handled in a client/server fashion.
The idea of giving some important decisions to a single authority machine does not require a single machine to be the authority for all data. You could have machine A be the authority for getting in and out of vehicles, while B is in charge of coordinating powerups, and C takes care of deciding when to end the session and tracking who has won.
And that is all I have to say about networking.
THE END