So far I can think of three approaches, which are certainly not 100% distinct but which represent different ways of looking at the issue.
- Manual, by timer or event - whenever it needs to, the server can form a network message containing the entity ID and a list of all the relevant properties, or specific messages for different kinds of changes (eg. a PlayerMoved message with a new position). This can be error-prone if the coder misses an important property change, and it's not trivial to revert changes half-way through a failed operation (which sometimes is useful, especially when doing multi-stage updates based on remote server or database values). However it does allow for very efficient messages (as specific messages for different changes don't need to contain property identifiers or the like), and probably works well for shooters and other games where entities have little mutable state but need to send it often.
- Dirty flags - the server-side routine alters the entity as necessary, with changed properties having a 'dirty flag' set. Then at the end of the routine, or at regular intervals, the server inspects the entity to see which properties are dirty, gathers them into a property change message, and resets the dirty flags. One problem with this approach is that although you usually need to wrap your objects with whatever facilitates the flag, and it's usually hard to catch every single modification unless you have a very comprehensive wrapper (eg. in C++ changing a value in an std::map won't be picked up unless you have wrapped every possible way of accessing it by key or by iterator)
- Transactions - the server-side routine makes changes to a logical copy of the entity, and when the routine successfully completes, the changes can be committed to the local entity and also put into a property change message. This makes it easy to roll-back routines that don't complete properly, and makes it theoretically easy to do some distributed or concurrent updates with optimistic locking (although that's not always worked well in practice, apparently). It's apparently not well-suited to games that broadcast data at different rates for different entities (eg. you might send fewer movement updates for distant entities - but their changes are committed as soon as they happen, so when does the message get sent?). It is also awkward to code, especially if you want to allow a non-transactional interface alongside the transactional one, and you have a similar issue to dirty flags in that it's hard to ensure that all changes in a nested structure are observed correctly.