For simple coop! games played in a friendly cooperative context (eg only friends)
-> Do whatever you want wherever, do everything that makes sense on the server, to prevent issues with multiple incoherent worldstates. (eg the classical desync in WC3 where all players differ so greatly in state, that noone knows who is winning.
-> Especially physics is a case here that can be highly simplified for the server and run mostly on clients, as they can trust each other
Great example is older Arma games, played in coop missions, were the Game could simulate up to several hundred NPC's , by assingin each client a few squads an do the AI there.
Great counter example is Arma in a Team vs Team context, that gives cheaters a real upper hand, as the server trusts those. https://www.youtube.com/watch?v=AmtZNnc-QPA (Leading to kinda funny hacks as this (dayz uses same engine) ro just assholes crashing your server/instakillin everyone.
For games with random persons (eg say counterstrike) where a cheater might exist
-> Validate everything on the server, no shortcuts anywhere.
-> Client is only for rendering, and might so stuff the server does as well, to give a lagfree feeling, by approximating what the server might say, but the server is the truth here.
Good example here would be Counterstrike, that (tries) actualy even simulates the physic on the server, and additionally, tries to not send to much information to clients. E.g if a client is behind a corner for some other client, do not send the actual position to the client, to reduce the benefit of wall hacks.
An bad example would be: https://www.youtube.com/watch?v=YK0gFUuoNEE There was an overly simplified calculation used in older UT engines, that basically assumed as long as you move slower than the maximum possible speed you are fine. Problem was, that maximum speed is pretty high without cheating, if a explosion just pushed you with high speed into some direction.