The first byte of your structs should be an identification byte, f.i. as follows:

struct _DATA {
int type; // or short or char
};

struct _DATA_CHAT {
int type;
short player_id;
char msg[128];
};

struct _DATA_MOVE {
int type;
short player_id;
var input; // f.i holds the key inputs from the player
};

typedef struct _DATA DATA;
typedef struct _DATA_CHAT DATA_CHAT;
typedef struct _DATA_MOVE DATA_MOVE;

#define TYPE_CHAT 1
#define TYPE_MOVE 2

DATA_MOVE dm_player[16];

The first struct is not really necessary but IMO makes it nicer to handle.
Now you can proceed as follows:

received data/ buffer?
DATA* mydata = (DATA*)buffer;
if(mydata->type == TYPE_MOVE)
{
DATA_MOVE* move = (DATA_MOVE*)buffer;
dm_player[move->player_id].input = move->input;
}
if(mydata->type == TYPE_CHAT) ...


I hope this gives you an idea how to handle this situation (only programmed something like this once, so it may not be the best method, I don't know).
Additionally, I would suggest that you do not use synchronized global entities (and thus their handles) but only create local entities. If you know have let's say 20 players you simply create 20 player models on each machine locally and move and handle them using your data structs. This gives you full control over your simulation and you do not have to rely on or wait for the entity synchronization and so on.


"Falls das Resultat nicht einfach nur dermassen gut aussieht, sollten Sie nochmal von vorn anfangen..." - Manual

Check out my new game: Pogostuck: Rage With Your Friends