Here is a very preliminary patch against xmame 0.56.1 to enable network multiplayer. Only the basics are implemented (see TODO in doc/multiplayer-readme.txt) but it should be enough to play most games on a LAN. I doubt you'd have much luck over the internet, and playing over anything slower than a cable modem is definitely not going to be pleasant. Still, it's a start. I would've given it some more work but I'm sending it in now in case some of you want to play around with it over the weekend -- I probably won't get back to it before Monday. Enjoy, and good luck...
-- Steve 'Nephtes' Freeland | For Christmas this year I'd like to see Martha [EMAIL PROTECTED] | Stewart compete on an episode of Junkyard Wars. diff -cr xmame-0.56.1/doc/multiplayer-readme.txt xmame-0.56.1-net/doc/multiplayer-readme.txt *** xmame-0.56.1/doc/multiplayer-readme.txt Fri Nov 2 20:22:54 2001 --- xmame-0.56.1-net/doc/multiplayer-readme.txt Fri Dec 7 14:07:35 2001 *************** *** 1,3 **** --- 1,90 ---- + Multiplayer Network XMame N0.1 (Rewrite by Steve Freeland, [EMAIL PROTECTED]) + ------------------------------ + mame version 0.56.1 + + Usage (for an n-player game): + ----- + Start a master: + xmame.<display method> -master n <other options> <game name> + Start n - 1 slaves: + xmame.<display method> -slave <master hostname> <other options> <game name> + Currently there can only be one slave per machine, although a slave + can share a machine with the master. + + Message format + -------------- + Each UDP packet has a 4-byte header followed by a body. + The header has a 3-byte magic string "XNM" followed by a 1-byte message type. + The contents of the message body depends on the message type, and there may in fact + not be a body. + + Message types: See enum net_msg_type in src/unix/network.c in case + ------------- this doc is out of date + JOIN: This is the first message the slaves send to the master for + handshaking. The body contains a string identifying the slave + (<hostname>/<pid>), the slave's MAME build version and net protocol + version, and the name of the game being played. If any of the latter + 3 do not match the master's information, the master will refuse the + join. The slave id string is currently only used for logging. + + ACCEPT: This is the master's reply to the slave if the protocol + versions and game name match. The 1-byte body is the player number + assigned to the slave. + + REFUSE: This is the master's reply to the slave if the protocol + versions and game name do not match. There is no body. + + LOCAL_STATE: This message is sent by the slave to the master and + contains a sequence number (see Protocol below) and a byte + order-adjusted copy of the slave's current input_port_values[] array. + It is used by the master to compute the global state. + + GLOBAL_STATE: Sent by the master to each of the slaves and contains, + like LOCAL_STATE, a sequence number and a byte order-adjusted copy of the + input_port_values[] array. The slave uses this to overwrite its own + local copy of input_port_values[]. + + QUIT: Sent when a client or the master exits and allows the remaining + participants to handle the exit gracefully without having wait for a timeout. + + Protocol + -------- + For frame n: + . Slaves all send input state for frame sequence number n to master. + . Master waits indefinitely for all slave inputs for frame n to + arrive. + . If the master receives a slave input for frame n - 1, that + slave may not have received the global state for frame n - 1 + and the master must resend it. + . If the master receives a slave input for frame < n - 1, that + can only be due to out-of-order delivery (I think) and it + can be ignored. + . Master eventually receives all slave input state, merges them and + sends the global state back to slaves, then processes (eg, + proceeds with emulation until the next frame) the merged + input and goes back to waiting for local inputs for frame n + 1. + . Slaves wait a certain amount of time for the global input state + from the master. + . If the wait times out then the local input state for frame n + is resent. + . Slave may receive an old response (frame < n) due to out-of- + order delivery, which it ignores. If frame is n - 1 is + received that could be due to a premature resend. + . Slaves eventually all get the global state for frame n, then + process the merged input and proceed to the next frame. + . Lather, rinse, repeat. + + TODO + ---- + . Handle user interface invocation? + . More flexible port config? + . Adjust for high latency -- coarser sync frequency? + . Player n to player 1 input port remapping + . Talk to the core team about integrating the protocol-level stuff + into the platform-independant network.c + + Old readme: + ----------- Multiplayer Network XMame 0.02 ------------------------------ mame version 0.34b5 diff -cr xmame-0.56.1/src/driver.h xmame-0.56.1-net/src/driver.h *** xmame-0.56.1/src/driver.h Fri Nov 2 20:22:51 2001 --- xmame-0.56.1-net/src/driver.h Wed Dec 5 19:56:42 2001 *************** *** 19,28 **** #include "tilemap.h" #include "profiler.h" - #ifdef MAME_NET - #include "network.h" - #endif /* MAME_NET */ - #define MAX_CPU 8 /* MAX_CPU is the maximum number of CPUs which cpuintrf.c */ /* can run at the same time. Currently, 8 is enough. */ --- 19,24 ---- diff -cr xmame-0.56.1/src/inptport.c xmame-0.56.1-net/src/inptport.c *** xmame-0.56.1/src/inptport.c Fri Nov 2 20:22:53 2001 --- xmame-0.56.1-net/src/inptport.c Wed Dec 5 21:17:56 2001 *************** *** 595,601 **** int load_input_port_settings(void) { void *f; ! #ifdef MAME_NET struct InputPort *in; int port, player; #endif /* MAME_NET */ --- 595,601 ---- int load_input_port_settings(void) { void *f; ! #ifdef OLD_MAME_NET struct InputPort *in; int port, player; #endif /* MAME_NET */ *************** *** 605,611 **** if ((f = osd_fopen(Machine->gamedrv->name,0,OSD_FILETYPE_CONFIG,0)) != 0) { ! #ifndef MAME_NET struct InputPort *in; #endif unsigned int total,savedtotal; --- 605,611 ---- if ((f = osd_fopen(Machine->gamedrv->name,0,OSD_FILETYPE_CONFIG,0)) != 0) { ! #ifndef OLD_MAME_NET struct InputPort *in; #endif unsigned int total,savedtotal; *************** *** 697,703 **** for (i = 0; i < MAX_INPUT_PORTS; i++) input_analog_init[i] = 1; } ! #ifdef MAME_NET /* Find out what port is used by what player and swap regular inputs */ in = Machine->input_ports; --- 697,703 ---- for (i = 0; i < MAX_INPUT_PORTS; i++) input_analog_init[i] = 1; } ! #ifdef OLD_MAME_NET /* Find out what port is used by what player and swap regular inputs */ in = Machine->input_ports; *************** *** 813,819 **** /* TODO: at this point the games should initialize peers to same as server */ ! #endif /* MAME_NET */ update_input_ports(); --- 813,819 ---- /* TODO: at this point the games should initialize peers to same as server */ ! #endif /* OLD_MAME_NET */ update_input_ports(); *************** *** 829,835 **** void save_input_port_settings(void) { void *f; ! #ifdef MAME_NET struct InputPort *in; int port, player; --- 829,835 ---- void save_input_port_settings(void) { void *f; ! #ifdef OLD_MAME_NET struct InputPort *in; int port, player; *************** *** 946,960 **** port++; if (in->type == IPT_PORT) in++; } ! #endif /* MAME_NET */ save_default_keys(); if ((f = osd_fopen(Machine->gamedrv->name,0,OSD_FILETYPE_CONFIG,1)) != 0) { ! #ifndef MAME_NET struct InputPort *in; ! #endif /* MAME_NET */ int total; int i; --- 946,960 ---- port++; if (in->type == IPT_PORT) in++; } ! #endif /* OLD_MAME_NET */ save_default_keys(); if ((f = osd_fopen(Machine->gamedrv->name,0,OSD_FILETYPE_CONFIG,1)) != 0) { ! #ifndef OLD_MAME_NET struct InputPort *in; ! #endif /* OLD_MAME_NET */ int total; int i; *************** *** 1305,1314 **** readword(playback,&input_port_value[port]); if (record) writeword(record,input_port_value[port]); ! #ifdef MAME_NET if ( net_active() && (default_player != NET_SPECTATOR) ) net_analog_sync((unsigned char *) input_port_value, port, analog_player_port, default_player); ! #endif /* MAME_NET */ profiler_mark(PROFILER_END); } --- 1305,1314 ---- readword(playback,&input_port_value[port]); if (record) writeword(record,input_port_value[port]); ! #ifdef OLD_MAME_NET if ( net_active() && (default_player != NET_SPECTATOR) ) net_analog_sync((unsigned char *) input_port_value, port, analog_player_port, default_player); ! #endif /* OLD_MAME_NET */ profiler_mark(PROFILER_END); } *************** *** 1330,1338 **** int joystick[MAX_JOYSTICKS*MAX_PLAYERS][4]; #endif ! #ifdef MAME_NET int player; ! #endif /* MAME_NET */ profiler_mark(PROFILER_INPUT); --- 1330,1338 ---- int joystick[MAX_JOYSTICKS*MAX_PLAYERS][4]; #endif ! #ifdef OLD_MAME_NET int player; ! #endif /* OLD_MAME_NET */ profiler_mark(PROFILER_INPUT); *************** *** 1438,1444 **** input_port_value[port] = (input_port_value[port] & ~in->mask) | (in->default_value & in->mask); #ifdef MAME_NET ! if ( net_active() ) input_port_defaults[port] = input_port_value[port]; #endif /* MAME_NET */ } --- 1438,1444 ---- input_port_value[port] = (input_port_value[port] & ~in->mask) | (in->default_value & in->mask); #ifdef MAME_NET ! if ( osd_net_active() ) input_port_defaults[port] = input_port_value[port]; #endif /* MAME_NET */ } *************** *** 1451,1462 **** in->type != IPT_END && in->type != IPT_PORT; in++, ib++) { ! #ifdef MAME_NET player = 0; if ((in->type & IPF_PLAYERMASK) == IPF_PLAYER2) player = 1; else if ((in->type & IPF_PLAYERMASK) == IPF_PLAYER3) player = 2; else if ((in->type & IPF_PLAYERMASK) == IPF_PLAYER4) player = 3; ! #endif /* MAME_NET */ if ((in->type & ~IPF_MASK) != IPT_DIPSWITCH_SETTING && /* skip dipswitch definitions */ (in->type & ~IPF_MASK) != IPT_EXTENSION) /* skip analog extension fields */ { --- 1451,1462 ---- in->type != IPT_END && in->type != IPT_PORT; in++, ib++) { ! #ifdef OLD_MAME_NET player = 0; if ((in->type & IPF_PLAYERMASK) == IPF_PLAYER2) player = 1; else if ((in->type & IPF_PLAYERMASK) == IPF_PLAYER3) player = 2; else if ((in->type & IPF_PLAYERMASK) == IPF_PLAYER4) player = 3; ! #endif /* OLD_MAME_NET */ if ((in->type & ~IPF_MASK) != IPT_DIPSWITCH_SETTING && /* skip dipswitch definitions */ (in->type & ~IPF_MASK) != IPT_EXTENSION) /* skip analog extension fields */ { *************** *** 1519,1525 **** else if ((in->type & ~IPF_MASK) >= IPT_JOYSTICK_UP && (in->type & ~IPF_MASK) <= IPT_JOYSTICKLEFT_RIGHT) { ! #ifndef MAME_NET int joynum,joydir,mask,player; --- 1519,1525 ---- else if ((in->type & ~IPF_MASK) >= IPT_JOYSTICK_UP && (in->type & ~IPF_MASK) <= IPT_JOYSTICKLEFT_RIGHT) { ! #ifndef OLD_MAME_NET int joynum,joydir,mask,player; *************** *** 1529,1535 **** else if ((in->type & IPF_PLAYERMASK) == IPF_PLAYER4) player = 3; #else int joynum,joydir,mask; ! #endif /* !MAME_NET */ joynum = player * MAX_JOYSTICKS + ((in->type & ~IPF_MASK) - IPT_JOYSTICK_UP) / 4; joydir = ((in->type & ~IPF_MASK) - IPT_JOYSTICK_UP) % 4; --- 1529,1535 ---- else if ((in->type & IPF_PLAYERMASK) == IPF_PLAYER4) player = 3; #else int joynum,joydir,mask; ! #endif /* ! OLD_MAME_NET */ joynum = player * MAX_JOYSTICKS + ((in->type & ~IPF_MASK) - IPT_JOYSTICK_UP) / 4; joydir = ((in->type & ~IPF_MASK) - IPT_JOYSTICK_UP) % 4; *************** *** 1648,1655 **** writeword(record,input_port_value[i]); } #ifdef MAME_NET ! if ( net_active() && (default_player != NET_SPECTATOR) ) ! net_input_sync((unsigned char *) input_port_value, (unsigned char *) input_port_defaults, MAX_INPUT_PORTS); #endif /* MAME_NET */ profiler_mark(PROFILER_END); --- 1648,1655 ---- writeword(record,input_port_value[i]); } #ifdef MAME_NET ! if ( osd_net_active() ) ! osd_net_sync(input_port_value, input_port_defaults); #endif /* MAME_NET */ profiler_mark(PROFILER_END); *************** *** 1758,1764 **** READ16_HANDLER( input_port_18_word_r ) { return readinputport(18); } READ16_HANDLER( input_port_19_word_r ) { return readinputport(19); } ! #ifdef MAME_NET void set_default_player_controls(int player) { if (player == NET_SPECTATOR) --- 1758,1764 ---- READ16_HANDLER( input_port_18_word_r ) { return readinputport(18); } READ16_HANDLER( input_port_19_word_r ) { return readinputport(19); } ! #ifdef OLD_MAME_NET void set_default_player_controls(int player) { if (player == NET_SPECTATOR) *************** *** 1766,1772 **** else default_player = player - 1; } ! #endif /* MAME_NET */ /***************************************************************************/ /* InputPort conversion */ --- 1766,1772 ---- else default_player = player - 1; } ! #endif /* OLD_MAME_NET */ /***************************************************************************/ /* InputPort conversion */ diff -cr xmame-0.56.1/src/mame.c xmame-0.56.1-net/src/mame.c *** xmame-0.56.1/src/mame.c Fri Nov 2 20:22:51 2001 --- xmame-0.56.1-net/src/mame.c Wed Dec 5 19:57:18 2001 *************** *** 1253,1259 **** #ifdef MAME_NET /* disable high score when playing network game */ /* (this forces all networked machines to start from the same state!) */ ! if (net_active()) return 0; #endif /* MAME_NET */ return 1; --- 1253,1259 ---- #ifdef MAME_NET /* disable high score when playing network game */ /* (this forces all networked machines to start from the same state!) */ ! if (osd_net_active()) return 0; #endif /* MAME_NET */ return 1; diff -cr xmame-0.56.1/src/network.h xmame-0.56.1-net/src/network.h *** xmame-0.56.1/src/network.h Fri Nov 2 20:22:51 2001 --- xmame-0.56.1-net/src/network.h Wed Dec 5 20:10:26 2001 *************** *** 3,9 **** network.h ***************************************************************************/ ! #ifdef MAME_NET #ifndef __NETWORK_H__ #define __NETWORK_H__ --- 3,9 ---- network.h ***************************************************************************/ ! #ifdef OLD_MAME_NET #ifndef __NETWORK_H__ #define __NETWORK_H__ *************** *** 201,204 **** #endif /* __NETWORK_H__ */ ! #endif /* MAME_NET */ --- 201,204 ---- #endif /* __NETWORK_H__ */ ! #endif /* OLD_MAME_NET */ diff -cr xmame-0.56.1/src/osdepend.h xmame-0.56.1-net/src/osdepend.h *** xmame-0.56.1/src/osdepend.h Fri Nov 2 20:22:53 2001 --- xmame-0.56.1-net/src/osdepend.h Thu Dec 6 15:41:21 2001 *************** *** 387,395 **** #ifdef MAME_NET /* network */ int osd_net_init(void); int osd_net_send(int player, unsigned char buf[], int *size); int osd_net_recv(int player, unsigned char buf[], int *size); ! int osd_net_sync(void); int osd_net_input_sync(void); int osd_net_exit(void); int osd_net_add_player(void); --- 387,397 ---- #ifdef MAME_NET /* network */ int osd_net_init(void); + int osd_net_active(void); int osd_net_send(int player, unsigned char buf[], int *size); int osd_net_recv(int player, unsigned char buf[], int *size); ! void osd_net_sync(unsigned short input_port_values[MAX_INPUT_PORTS], ! unsigned short input_port_defaults[MAX_INPUT_PORTS]); int osd_net_input_sync(void); int osd_net_exit(void); int osd_net_add_player(void); diff -cr xmame-0.56.1/src/unix/network.c xmame-0.56.1-net/src/unix/network.c *** xmame-0.56.1/src/unix/network.c Fri Nov 2 20:22:57 2001 --- xmame-0.56.1-net/src/unix/network.c Fri Dec 7 14:00:37 2001 *************** *** 1,14 **** #include "xmame.h" #ifdef MAME_NET ! enum {MASTER=1,SLAVE}; ! enum {IDENTIFY, SYNC}; ! #define NAME_LENGTH 256 ! #define PORT_DATA 9000 ! ! static int netkeymap = 0; ! static int players = 0; ! static char *mastername = NULL; #endif struct rc_option network_opts[] = { --- 1,71 ---- #include "xmame.h" + #undef PROTOCOL_DEBUG + #ifdef MAME_NET ! ! #include <sys/types.h> ! #include <sys/socket.h> ! #include <netinet/in.h> ! #include <arpa/inet.h> ! #include <netdb.h> ! #ifdef svgalib ! #include <vgakeyboard.h> ! #endif ! #include "driver.h" ! ! enum net_role { ! NONE, ! MASTER, ! SLAVE ! }; ! ! static enum net_role current_net_role = NONE; ! ! #define NET_MAX_PLAYERS 4 ! #define MASTER_INPUT_PORT 9000 ! #define SLAVE_INPUT_PORT 9001 ! #define MAX_MSG_LEN 100 ! ! enum net_msg_type { ! JOIN, ! ACCEPT, ! REFUSE, ! LOCAL_STATE, ! GLOBAL_STATE, ! QUIT ! }; ! ! #define MSG_MAGIC_HEADER "XNM" ! #define PROTOCOL_VERSION "N0.1.0" ! ! struct net_msg_info { ! enum net_msg_type msg_type; ! unsigned sequence; ! unsigned char msg[MAX_MSG_LEN]; ! unsigned char *data_start; ! int data_len; ! } scratch_msg_info, output_state_msg_info; ! ! static int input_remap = 0; ! ! /* For master only */ ! static int original_player_count = 0; ! static int current_player_count = 0; ! struct net_slave_info { ! char name[MAX_MSG_LEN]; ! unsigned active; ! struct sockaddr_in addr; ! unsigned expected_sequence; ! } slave_info[NET_MAX_PLAYERS - 1]; ! ! /* For slave only */ ! const char *master_hostname = NULL; ! static struct sockaddr_in output_addr; ! static struct sockaddr_in input_addr; ! static unsigned char player_number; ! static int input_map[MAX_INPUT_PORTS * 16]; ! #endif struct rc_option network_opts[] = { *************** *** 17,29 **** { "Network Related", NULL, rc_seperator, NULL, NULL, 0, 0, NULL, NULL }, ! { "master", NULL, rc_int, &players, NULL, 1, 4, NULL, "Enable master mode. Set number of players" }, ! { "slave", NULL, rc_string, &mastername, NULL, 0, 0, NULL, "Enable slave mode. Set master hostname" }, ! { "netmapkey", NULL, rc_bool, &netkeymap, "0", 0, 0, NULL, "When enabled all players use the player 1 keys. For use with *real* multiplayer games" }, #endif --- 74,86 ---- { "Network Related", NULL, rc_seperator, NULL, NULL, 0, 0, NULL, NULL }, ! { "master", NULL, rc_int, &original_player_count, NULL, 1, 4, NULL, "Enable master mode. Set number of players" }, ! { "slave", NULL, rc_string, &master_hostname, NULL, 0, 0, NULL, "Enable slave mode. Set master hostname" }, ! { "netmapkey", NULL, rc_bool, &input_remap, "0", 0, 0, NULL, "When enabled all players use the player 1 keys. For use with *real* multiplayer games" }, #endif *************** *** 33,87 **** }; #ifdef MAME_NET - #include <sys/types.h> - #include <sys/socket.h> - #include <netinet/in.h> - #include <arpa/inet.h> - #include <netdb.h> - #ifdef svgalib - #include <vgakeyboard.h> - #endif - #include "driver.h" ! static int socks[4]; ! static struct sockaddr_in names[4]; ! static int player; ! static unsigned char keymap[128]; /* table to map network keys to player 1 */ ! static int timeout = 60; ! static int init_master_socket(void) { ! struct hostent *hp; ! char hname[NAME_LENGTH]; ! fprintf(stderr_file, "XMame in network Master Mode\nWaiting for %d players.\n", players-1); ! gethostname(hname, 256); /* socket creation */ ! if ((socks[0] = socket(AF_INET, SOCK_DGRAM, 0)) < 0) ! { ! fprintf(stderr_file, "init master : Can't initialise socket\n"); return(OSD_NOT_OK); } ! /* Assign domain and port number */ ! memset(&names[0], 0, sizeof(names[0])); ! names[0].sin_family = AF_INET; ! names[0].sin_port = PORT_DATA; ! ! /* Assign IP address */ ! if ((hp = gethostbyname(hname)) == NULL) { ! fprintf(stderr_file, "init master : gethostbyname error\n"); return(OSD_NOT_OK); } - memcpy(&(names[0].sin_addr.s_addr), hp->h_addr, hp->h_length); ! /* bind socket */ ! if (bind(socks[0], (struct sockaddr *)&names[0], sizeof(names[0])) == -1) ! { ! fprintf(stderr_file, "init master : Bind failure.\n"); ! return(OSD_NOT_OK); } return(OSD_OK); --- 90,135 ---- }; #ifdef MAME_NET ! static int output_socket; ! static int input_socket; ! ! unsigned current_frame_sequence = 0; ! static int init_master_sockets(void) { ! struct sockaddr_in input_socket_addr; ! fprintf(stderr_file, ! "XMame in network Master Mode\n" ! "Waiting for %d more players.\n", ! original_player_count - 1); /* socket creation */ ! if ((input_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { ! fprintf(stderr_file, ! "init master : Can't initialise socket (%s)\n", ! strerror(errno)); return(OSD_NOT_OK); } ! /* bind socket */ ! input_socket_addr.sin_family = AF_INET; ! input_socket_addr.sin_port = htons(MASTER_INPUT_PORT); ! input_socket_addr.sin_addr.s_addr = INADDR_ANY; ! if (bind(input_socket, ! (struct sockaddr *)&input_socket_addr, ! sizeof(input_socket_addr)) == -1) { ! fprintf(stderr_file, "init master : Bind failure (%s)\n", strerror(errno)); return(OSD_NOT_OK); } ! if ((output_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { ! fprintf(stderr_file, ! "Error: can't initialise output socket\n (%s)", ! strerror(errno)); ! return(OSD_NOT_OK); } return(OSD_OK); *************** *** 89,438 **** static int init_slave_sockets(void) { ! struct hostent *hp; ! char hname[NAME_LENGTH]; - fprintf(stderr_file, "Slave Mode; Registering to Master %s\n", mastername); - /* socket creation */ ! if ((socks[1] = socket(AF_INET, SOCK_DGRAM, 0)) < 0) ! { ! fprintf(stderr_file, "init slave : Can't initialise socket\n"); return(OSD_NOT_OK); } /* Assign domain and port number */ ! memset(&names[1], 0, sizeof(names[1])); ! names[1].sin_family = AF_INET; ! names[1].sin_port = PORT_DATA; /* Assign IP address */ ! if ((hp = gethostbyname(mastername)) == NULL) ! { fprintf(stderr_file, "init slave : gethostbyname error\n"); return(OSD_NOT_OK); } ! memcpy(&(names[1].sin_addr.s_addr), hp->h_addr, hp->h_length); ! ! gethostname(hname, 256); /* socket creation */ ! if ((socks[0] = socket(AF_INET, SOCK_DGRAM, 0)) < 0) ! { ! fprintf(stderr_file, "init slave : Can't initialise socket\n"); return(OSD_NOT_OK); } /* Assign domain and port number */ ! memset(&names[0], 0, sizeof(names[0])); ! names[0].sin_family = AF_INET; ! names[0].sin_port = PORT_DATA+1; ! ! /* Assign IP address */ ! if ((hp = gethostbyname(hname)) == NULL) ! { ! fprintf(stderr_file, "init slave : gethostbyname error\n"); ! return(OSD_NOT_OK); ! } ! memcpy(&(names[0].sin_addr.s_addr), hp->h_addr, hp->h_length); /* bind socket */ ! if (bind(socks[0], (struct sockaddr *)&names[0], sizeof(names[0])) == -1) ! { ! fprintf(stderr_file, "init slave : Bind failure.\n"); return(OSD_NOT_OK); } return(OSD_OK); } ! static int receive_msg(void *msg, int size) ! { ! unsigned int lg = 0; ! fd_set rfds; ! struct timeval tv; ! ! /* watch socks[0] to see if it has any input */ ! FD_ZERO(&rfds); ! FD_SET(socks[0], &rfds); ! ! /* Wait up to timeout seconds. */ ! tv.tv_sec = timeout; ! tv.tv_usec = 0; ! if (select(socks[0] + 1, &rfds, NULL, NULL, &tv)==0) ! { ! fprintf(stderr_file, "Error: timeout (%d secs) while receiving message.\n", timeout); ! return OSD_NOT_OK; ! } ! if (recvfrom(socks[0], msg, size, 0, NULL, &lg) == -1) ! { ! fprintf(stderr_file, "Error: socket error receiving message.\n"); return OSD_NOT_OK; ! } return OSD_OK; } ! static int send_msg(void *msg, int size) { ! int i; ! ! switch(netstate) ! { ! case MASTER: ! for(i=1;i<players;i++) ! { ! if (sendto(socks[i], msg, size, 0, (struct sockaddr *)&names[i], sizeof(names[i])) == -1) ! { ! fprintf(stderr_file, "Error: socket error sending message.\n"); ! return OSD_NOT_OK; ! } ! } ! break; ! case SLAVE: ! if (sendto(socks[1], msg, size, 0, (struct sockaddr *)&names[1], sizeof(names[1])) == -1) ! { ! fprintf(stderr_file, "Error: socket error sending message.\n"); ! return OSD_NOT_OK; ! } ! break; ! } ! return OSD_OK; } ! static int add_slave(char *host, int *sock, struct sockaddr_in *name) { ! struct hostent *hp; ! ! /* socket creation */ ! if ((*sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) ! { ! fprintf(stderr_file, "Error: can't initialise socket\n"); ! return(OSD_NOT_OK); ! } ! ! /* Assign domain and port number */ ! memset(name, 0, sizeof(struct sockaddr_in)); ! name->sin_family = AF_INET; ! name->sin_port = PORT_DATA+1; ! ! /* Assign IP address */ ! if ((hp = gethostbyname(host)) == NULL) ! { ! fprintf(stderr_file, "Error: gethostbyname error\n"); ! return(OSD_NOT_OK); ! } ! memcpy(&name->sin_addr.s_addr, hp->h_addr, hp->h_length); ! return(OSD_OK); } static int register_to_master(void) { ! char hname[NAME_LENGTH]; ! gethostname(hname, NAME_LENGTH); ! if (sendto(socks[1], hname, NAME_LENGTH, 0, (struct sockaddr *)&names[1], sizeof(names[1])) == -1) ! { ! fprintf(stderr_file, "Error: socket error sending registration to master"); ! return OSD_NOT_OK; } ! if (receive_msg(&player, sizeof(player)) != OSD_OK) return OSD_NOT_OK; ! fprintf(stderr_file, "Registered as player %d\n", player); return OSD_OK; } ! static int wait_registration(void) { ! char hname[NAME_LENGTH]; /* slave host name */ ! int i; ! for(i=1;i<players;i++) ! { ! player=i+1; ! if (receive_msg(hname, NAME_LENGTH) != OSD_OK) ! { ! fprintf(stderr_file, "Error: Can't receive registration from player %d\n", player); ! return OSD_NOT_OK; ! } ! if (add_slave(hname, &socks[i], &names[i])!=OSD_OK) return OSD_NOT_OK; ! if (sendto(socks[i], &player, sizeof(player), 0, (struct sockaddr *)&names[i], sizeof(names[i]))==-1) ! { ! fprintf(stderr_file, "Error: socket error sending registration to player %d\n", player); ! return OSD_NOT_OK; ! } ! fprintf(stderr_file, "%s registered successfully as player %d.\n", hname, player); } ! player = 1; return OSD_OK; } ! int default_key(const struct InputPort *in); ! ! static int net_map_key(int keycode, int playermask) { ! struct InputPort *in = Machine->input_ports, *start = Machine->input_ports; ! int port, found, event = 0; ! if (in->type == IPT_END) return keycode; /* nothing to do */ ! /* make sure the InputPort definition is correct */ ! if (in->type != IPT_PORT) ! { ! if (errorlog) fprintf(errorlog,"Error in InputPort definition: expecting PORT_START\n"); ! return keycode; } ! else start = ++in; ! ! found = 0; ! port = 0; ! while ((found ==0) && (in->type != IPT_END) && (port < MAX_INPUT_PORTS)) ! { ! while (in->type != IPT_END && in->type != IPT_PORT) ! { ! if (default_key(in)==keycode) ! { ! event = in->type; ! found = 1; ! break; ! } ! in++; ! } ! if (found == 0) ! { ! port++; ! if (in->type == IPT_PORT) in++; ! } } ! if (found == 0) return keycode; ! ! in = start; ! port = 0; ! while (in->type != IPT_END && port < MAX_INPUT_PORTS) { ! while (in->type != IPT_END && in->type != IPT_PORT) { ! if ((in->type & IPF_PLAYERMASK)== playermask) ! if ((in->type & (~IPF_MASK)) == (event & (~IPF_MASK))) ! { ! return default_key(in); ! } ! in++; } ! port++; ! if (in->type == IPT_PORT) in++; } ! ! return keycode; } static void build_keymap(void) { ! int i, keycode, playermask = 0; ! switch(player) ! { case 1: ! playermask = IPF_PLAYER1; ! break; case 2: ! playermask = IPF_PLAYER2; ! break; case 3: ! playermask = IPF_PLAYER3; ! break; case 4: ! playermask = IPF_PLAYER4; ! break; ! } ! ! memset(keymap,0,128*sizeof(unsigned char)); ! for(i=0;i<128;i++) ! { ! keymap[net_map_key(i, playermask)] = i; ! } } - /* ! * get key tables from slaves */ ! void osd_net_sync(void) { ! int i,j; ! static char net_key[128]; ! ! if (!key) return; ! ! if (netkeymap) ! { ! for(i=0; i<128; i++) ! { ! global_key[i] = local_key[keymap[i]]; ! } } ! ! switch(netstate) ! { ! case MASTER: ! if(!netkeymap) memcpy(global_key, local_key, 128*sizeof(unsigned char)); ! for(i=1;i<players;i++) ! { ! if (receive_msg(net_key, 128*sizeof(unsigned char)) != OSD_OK) ! goto drop_to_single_player; ! for(j=0;j<=OSD_MAX_KEY;j++) ! global_key[j] |= net_key[j]; ! } ! if (send_msg(global_key, 128*sizeof(unsigned char)) != OSD_OK) ! goto drop_to_single_player; ! break; ! case SLAVE: ! if (netkeymap) ! { ! if (send_msg(global_key, 128*sizeof(unsigned char)) != OSD_OK) ! goto drop_to_single_player; } ! else ! { ! if (send_msg(local_key, 128*sizeof(unsigned char)) != OSD_OK) ! goto drop_to_single_player; } - if (receive_msg(global_key, 128*sizeof(unsigned char))!=OSD_OK) - goto drop_to_single_player; - break; } ! /* after the first successfull sync it should be safe to lower the ! timeout to 5 seconds */ ! timeout = 5; ! return; ! drop_to_single_player: ! fprintf(stderr_file, "Lost network connection, continuing in single player mode\n"); ! osd_net_close(); ! netstate=0; ! key=local_key; } /* * Close all opened sockets */ void osd_net_close(void) { ! int i; ! ! switch(netstate) { ! case MASTER: ! for(i=0;i<(players-1);i++) close(socks[i]); ! break; ! case SLAVE: ! close(socks[0]); ! close(socks[1]); ! break; } } --- 137,750 ---- static int init_slave_sockets(void) { ! struct hostent *master_hostent; /* socket creation */ ! if ((output_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { ! fprintf(stderr_file, ! "init slave : Can't initialise output socket (%s)\n", ! strerror(errno)); return(OSD_NOT_OK); } /* Assign domain and port number */ ! output_addr.sin_family = AF_INET; ! output_addr.sin_port = htons(MASTER_INPUT_PORT); /* Assign IP address */ ! if ((master_hostent = gethostbyname(master_hostname)) == NULL) { fprintf(stderr_file, "init slave : gethostbyname error\n"); return(OSD_NOT_OK); } ! memcpy(&(output_addr.sin_addr.s_addr), ! master_hostent->h_addr, ! master_hostent->h_length); /* socket creation */ ! if ((input_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { ! fprintf(stderr_file, ! "init slave : Can't initialise input socket (%s)\n", ! strerror(errno)); return(OSD_NOT_OK); } /* Assign domain and port number */ ! input_addr.sin_family = AF_INET; ! input_addr.sin_port = htons(SLAVE_INPUT_PORT); ! input_addr.sin_addr.s_addr = INADDR_ANY; /* bind socket */ ! if (bind(input_socket, (struct sockaddr *)&input_addr, sizeof(input_addr)) == -1) { ! fprintf(stderr_file, ! "init slave : Input socket bind failure (%s).\n", ! strerror(errno)); return(OSD_NOT_OK); } return(OSD_OK); } ! static int rcv_msg(int fd, ! struct net_msg_info *msg_info, ! struct sockaddr_in *source_addr, ! unsigned timeout) ! { ! socklen_t socklen = 0; ! fd_set scratch_fds; ! struct timeval timeout_tv = { timeout / 1000000, (timeout % 1000000) * 1000 }; ! struct timeval *timeout_tv_p = NULL; ! int msg_len; ! ! if (timeout > 0) { ! timeout_tv_p = &timeout_tv; ! } ! ! if (source_addr != 0) { ! socklen = sizeof(*source_addr); ! } ! ! do { ! FD_ZERO(&scratch_fds); ! FD_SET(fd, &scratch_fds); ! ! if (select(fd + 1, &scratch_fds, NULL, NULL, timeout_tv_p) == 0) { ! fprintf(stderr_file, ! "Error: timeout (%d ms) while receiving message.\n", ! timeout); ! return OSD_NOT_OK; ! } ! msg_len = recvfrom(fd, ! msg_info->msg, ! sizeof(msg_info->msg), ! 0, ! source_addr, ! &socklen); ! if (msg_len < 0) { ! fprintf(stderr_file, ! "Error: socket error receiving message (%s).\n", ! strerror(errno)); return OSD_NOT_OK; ! } ! /* Packets without the magic header are discarded without error; they are ! assumed to be unrelated traffic */ ! } while (msg_len < 4 || memcmp(msg_info->msg, MSG_MAGIC_HEADER, 3) != 0); ! ! msg_info->msg_type = msg_info->msg[3]; ! switch (msg_info->msg_type) { ! case JOIN: ! case ACCEPT: ! case REFUSE: ! case QUIT: ! msg_info->data_start = msg_info->msg + 4; ! msg_info->data_len = msg_len - 4; ! break; ! case LOCAL_STATE: ! case GLOBAL_STATE: ! if (msg_len <= 8) { ! fprintf(stderr_file, ! "Error: received truncated state packet (size %i).\n", ! msg_len); ! return OSD_NOT_OK; ! } ! msg_info->sequence = (unsigned)ntohl(*((long int *)(msg_info->msg + 4))); ! msg_info->data_start = msg_info->msg + 8; ! msg_info->data_len = msg_len - 8; ! break; ! } return OSD_OK; } ! void prime_msg(struct net_msg_info *msg_info) { ! memcpy(msg_info->msg, MSG_MAGIC_HEADER, 3); ! msg_info->msg[3] = (unsigned char)msg_info->msg_type; ! switch (msg_info->msg_type) { ! case JOIN: ! case ACCEPT: ! case REFUSE: ! case QUIT: ! msg_info->data_start = msg_info->msg + 4; ! break; ! case LOCAL_STATE: ! case GLOBAL_STATE: ! (*(long int *)(msg_info->msg + 4)) = ntohl(msg_info->sequence); ! msg_info->data_start = msg_info->msg + 8; ! break; ! } ! msg_info->data_len = 0; } ! int write_to_msg(struct net_msg_info *msg_info, const void *new_data, unsigned new_data_len) { ! if ((msg_info->data_start - msg_info->msg) + msg_info->data_len + new_data_len > MAX_MSG_LEN) ! { ! fprintf(stderr_file, "Error: message overflow\n"); ! return OSD_NOT_OK; ! } ! memcpy(msg_info->data_start + msg_info->data_len, new_data, new_data_len); ! msg_info->data_len += new_data_len; ! return OSD_OK; ! } ! static int send_msg(int sock_fd, struct net_msg_info *msg_info, struct sockaddr_in *dest) ! { ! if (sendto(sock_fd, ! msg_info->msg, ! (msg_info->data_start - msg_info->msg) + msg_info->data_len, ! 0, ! (struct sockaddr *)dest, ! sizeof(*dest)) < 0) ! { ! fprintf(stderr_file, "Error: socket error sending message (%s).\n", strerror(errno)); ! return OSD_NOT_OK; ! } ! return OSD_OK; } static int register_to_master(void) { ! char scratch[MAX_MSG_LEN]; ! fprintf(stderr_file, "Slave Mode; Registering to Master %s\n", master_hostname); ! ! gethostname(scratch, MAX_MSG_LEN); ! ! scratch_msg_info.msg_type = JOIN; ! prime_msg(&scratch_msg_info); ! write_to_msg(&scratch_msg_info, scratch, strlen(scratch)); ! sprintf(scratch, "/%d", getpid()); ! write_to_msg(&scratch_msg_info, scratch, strlen(scratch) + 1); ! write_to_msg(&scratch_msg_info, build_version, strlen(build_version) + 1); ! write_to_msg(&scratch_msg_info, PROTOCOL_VERSION, strlen(PROTOCOL_VERSION) + 1); ! write_to_msg(&scratch_msg_info, ! Machine->gamedrv->name, ! strlen(Machine->gamedrv->name) + 1); ! ! do { ! send_msg(output_socket, &scratch_msg_info, &output_addr); ! } while (rcv_msg(input_socket, &scratch_msg_info, NULL, 1000) != OSD_OK); ! ! if (scratch_msg_info.msg_type == REFUSE) { ! fprintf(stderr_file, "Master %s refused registration\n", master_hostname); ! if (scratch_msg_info.data_len > 0) { ! fprintf(stderr_file, "Reason given: %.50s\n", scratch_msg_info.data_start); ! } else { ! fprintf(stderr_file, "No reason given\n"); ! } ! return OSD_NOT_OK; ! } ! else if (scratch_msg_info.msg_type != ACCEPT) { ! fprintf(stderr_file, ! "Master %s returned bogus message type %d\n", ! master_hostname, ! scratch_msg_info.msg_type); ! return OSD_NOT_OK; } ! ! player_number = scratch_msg_info.data_start[0]; ! ! fprintf(stderr_file, "Registeration as player %d confirmed\n", (unsigned)player_number); return OSD_OK; } ! static int await_slave_registrations(void) { ! unsigned char i = 0; ! struct sockaddr_in source_addr; ! while (i < original_player_count - 1) { ! unsigned msg_data_left; ! unsigned char *msg_read_pointer; ! unsigned char scratch_msg_data[MAX_MSG_LEN]; ! ! if (rcv_msg(input_socket, &scratch_msg_info, &source_addr, 0)) { ! fprintf(stderr_file, ! "Error: Registration from slave failed (%s)\n", ! strerror(errno)); ! continue; ! } ! if (scratch_msg_info.msg_type != JOIN) { ! fprintf(stderr_file, ! "Error: Unexpected message type (%d) while awaiting registrations\n", ! scratch_msg_info.msg_type); ! continue; ! } ! ! msg_data_left = scratch_msg_info.data_len; ! msg_read_pointer = scratch_msg_info.data_start; ! ! slave_info[i].addr.sin_family = AF_INET; ! slave_info[i].addr.sin_port = htons(SLAVE_INPUT_PORT); ! memcpy(&(slave_info[i].addr.sin_addr), ! &(source_addr.sin_addr), ! sizeof(slave_info[i].addr.sin_addr)); ! ! strncpy(slave_info[i].name, msg_read_pointer, msg_data_left); ! msg_data_left -= (strlen(slave_info[i].name) + 1); ! msg_read_pointer += (strlen(slave_info[i].name) + 1); ! ! if (strncmp(msg_read_pointer, build_version, msg_data_left) != 0) { ! scratch_msg_info.msg_type = REFUSE; ! prime_msg(&scratch_msg_info); ! sprintf(scratch_msg_data, ! "Wrong build version; need %s not %.10s", ! build_version, ! msg_read_pointer); ! write_to_msg(&scratch_msg_info, scratch_msg_data, strlen(scratch_msg_data)); ! send_msg(output_socket, &scratch_msg_info, &(slave_info[i].addr)); ! continue; ! } ! msg_data_left -= strlen(build_version) + 1; ! msg_read_pointer += strlen(build_version) + 1; ! ! if (strncmp(msg_read_pointer, PROTOCOL_VERSION, msg_data_left) != 0) { ! scratch_msg_info.msg_type = REFUSE; ! prime_msg(&scratch_msg_info); ! sprintf(scratch_msg_data, ! "Wrong protocol version; need %s not %.10s", ! PROTOCOL_VERSION, ! msg_read_pointer); ! write_to_msg(&scratch_msg_info, scratch_msg_data, strlen(scratch_msg_data)); ! send_msg(output_socket, &scratch_msg_info, &(slave_info[i].addr)); ! continue; ! } ! msg_data_left -= strlen(PROTOCOL_VERSION) + 1; ! msg_read_pointer += strlen(PROTOCOL_VERSION) + 1; ! ! if (strncmp(msg_read_pointer, Machine->gamedrv->name, msg_data_left) != 0) { ! scratch_msg_info.msg_type = REFUSE; ! prime_msg(&scratch_msg_info); ! sprintf(scratch_msg_data, ! "Wrong game; need %s not %.10s", ! Machine->gamedrv->name, ! msg_read_pointer); ! write_to_msg(&scratch_msg_info, scratch_msg_data, strlen(scratch_msg_data)); ! send_msg(output_socket, &scratch_msg_info, &(slave_info[i].addr)); ! continue; ! } ! ! slave_info[i].active = 1; ! slave_info[i].expected_sequence = 0; ! ! scratch_msg_info.msg_type = ACCEPT; ! prime_msg(&scratch_msg_info); ! scratch_msg_data[0] = i + 2; ! write_to_msg(&scratch_msg_info, scratch_msg_data, 1); ! ! if (send_msg(output_socket, ! &scratch_msg_info, ! &(slave_info[i].addr)) != OSD_OK) ! { ! fprintf(stderr_file, ! "Error: socket error sending registration to slave %d (%s)\n", ! i, ! strerror(errno)); ! return OSD_NOT_OK; ! } ! fprintf(stderr_file, ! "%s registeration accepted as player %d.\n", ! slave_info[i].name, ! i + 2); ! i += 1; } ! current_player_count = original_player_count; return OSD_OK; } ! #if 0 ! static int mapped_port_bit_for_port(int unmapped_port_index, int playermask) { ! int candidate_port_group, candidate_port_index; ! int target_type; ! if (playermask == IPF_PLAYER1) return unmapped_port_index; ! if (Machine->input_ports[unmapped_port_index] & IPF_PLAYERMASK = playermask) { ! /* Map player n ports to player 1 */ ! target_type = ! (Machine->input_ports[unmapped_port_index] & ~IPF_PLAYERMASK) & IPF_PLAYER1; } ! else if (Machine->input_ports[unmapped_port_index] & IPF_PLAYERMASK = IPF_PLAYER1) ! /* Map player 1 ports to player n */ ! target_type = ! (Machine->input_ports[unmapped_port_index] & ~IPF_PLAYERMASK) & playermask; ! } else { ! /* Other keys remain unchanged */ ! return unmapped_port_index; } + + /* make sure the InputPort definition is correct */ + if (in->type != IPT_PORT) { + if (errorlog) fprintf(errorlog,"Error in InputPort definition: expecting +PORT_START\n"); + return keycode; + } + else start = ++in; ! candidate_port_element = 0; ! candidate_port_group = 0; ! while (Machine->input_ports[candidate_port_index].type != IPT_END && ! candidate_port_group < MAX_INPUT_PORTS) { ! while (Machine->input_ports[candidate_port_index].type != IPT_END && ! Machine->input_ports[candidate_port_index].type != IPT_PORT) { ! if (Machine->input_ports[candidate_port_index].type == target_type) { ! return candidate_port_index; ! } ! candidate_port_index++; } ! candidate_port_group++; ! if (Machine->input_ports[candidate_port_index].type == IPT_PORT) candidate_port_index++; } ! ! return unmapped_port_index; } + #endif static void build_keymap(void) { ! int playermask; ! switch(player_number) ! { case 1: ! playermask = IPF_PLAYER1; ! break; case 2: ! playermask = IPF_PLAYER2; ! break; case 3: ! playermask = IPF_PLAYER3; ! break; case 4: ! playermask = IPF_PLAYER4; ! break; ! } ! /* for(unmapped_port_index = 0; unmapped_port_index < port_count; unmapped_port_index++) { ! input_map[unmapped_port_index] = mapped_port_for_port(unmapped_port_index); ! } */ } /* ! * get port state tables from slaves */ ! static unsigned short scratch_slave_input_state[MAX_INPUT_PORTS]; ! ! void osd_master_sync(unsigned short input_port_values[MAX_INPUT_PORTS], ! unsigned short input_port_defaults[MAX_INPUT_PORTS]) { ! unsigned i; ! unsigned slaves_reported = 0; ! unsigned char slave_index = (unsigned char)-1; ! ! struct sockaddr_in source_addr; ! ! /* Change the values into deviations from default values */ ! for (i = 0; i < MAX_INPUT_PORTS; i++) { ! input_port_values[i] ^= input_port_defaults[i]; } ! ! while (slaves_reported < current_player_count - 1) { ! if (rcv_msg(input_socket, &scratch_msg_info, &source_addr, 0) != OSD_OK) ! continue; ! ! for (i = 0; i < original_player_count - 1; i++) { ! if (slave_info[i].active && ! memcmp(&(source_addr.sin_addr), ! &(slave_info[i].addr.sin_addr), ! sizeof(source_addr.sin_addr)) == 0) ! { ! slave_index = i; ! break; ! } } ! if (slave_index == (unsigned char)-1) { ! fprintf(stderr_file, "Error : Received packet from unknown slave\n"); ! continue; ! } ! if (scratch_msg_info.msg_type == QUIT) { ! fprintf(stderr_file, "Slave \"%s\" quit\n", slave_info[slave_index].name); ! current_player_count -= 1; ! if (current_player_count == 1) { ! current_net_role = NONE; ! break; ! } ! } ! if (scratch_msg_info.msg_type != LOCAL_STATE) { ! fprintf(stderr_file, ! "Error : Received unexpected message type (%d) from slave \"%s\"\n", ! scratch_msg_info.msg_type, ! slave_info[slave_index].name); ! continue; ! } ! ! #ifdef PROTOCOL_DEBUG ! fprintf(stderr_file, ! "master : received state %d from slave \"%s\" (expecting %d)\n", ! scratch_msg_info.sequence, ! slave_info[slave_index].name, ! slave_info[slave_index].expected_sequence); ! #endif ! if (scratch_msg_info.sequence == slave_info[slave_index].expected_sequence) { ! slaves_reported += 1; ! memcpy(scratch_slave_input_state, ! scratch_msg_info.data_start, ! scratch_msg_info.data_len); ! for (i = 0; i < MAX_INPUT_PORTS; i++) { ! input_port_values[i] |= ! (ntohs(scratch_slave_input_state[i]) ^ input_port_defaults[i]); ! } ! slave_info[slave_index].expected_sequence += 1; ! } ! else if (scratch_msg_info.sequence == slave_info[slave_index].expected_sequence - 1) { ! if (scratch_msg_info.sequence == current_frame_sequence) { ! /* Slave is sending states too fast? Ignore */ ! } else { ! /* Slave missed previous state */ ! #ifdef PROTOCOL_DEBUG ! fprintf(stderr_file, ! "master : Re-sending global state %d to slave \"%s\"\n", ! output_state_msg_info.sequence, ! slave_info[slave_index].name); ! #endif ! send_msg(output_socket, ! &output_state_msg_info, ! &slave_info[slave_index].addr); ! } ! } else { ! /* Lost packet? Ignore */ ! } ! } ! ! /* At this point all slaves have reported their states */ ! output_state_msg_info.msg_type = GLOBAL_STATE; ! output_state_msg_info.sequence = current_frame_sequence; ! prime_msg(&output_state_msg_info); ! for (i = 0; i < MAX_INPUT_PORTS; i++) { ! unsigned short scratch; ! /* Change the input port default deviations back into real values */ ! input_port_values[i] ^= input_port_defaults[i]; ! scratch = htons(input_port_values[i]); ! write_to_msg(&output_state_msg_info, &scratch, sizeof(scratch)); ! } ! /* Send global state to all slaves */ ! #ifdef PROTOCOL_DEBUG ! fprintf(stderr_file, "master : Sending global state %d\n", current_frame_sequence); ! #endif ! for (i = 0; i < original_player_count - 1; i++) { ! if (slave_info[i].active) { ! send_msg(output_socket, &output_state_msg_info, &slave_info[i].addr); } } ! current_frame_sequence += 1; ! } ! ! void osd_slave_sync(unsigned short input_port_values[MAX_INPUT_PORTS], ! unsigned short input_port_defaults[MAX_INPUT_PORTS]) ! { ! unsigned i; ! ! output_state_msg_info.msg_type = LOCAL_STATE; ! output_state_msg_info.sequence = current_frame_sequence; ! prime_msg(&output_state_msg_info); ! for (i = 0; i < MAX_INPUT_PORTS; i++) { ! unsigned short scratch = htons(input_port_values[i]); ! write_to_msg(&output_state_msg_info, &scratch, sizeof(scratch)); ! } ! while (1) { ! #ifdef PROTOCOL_DEBUG ! fprintf(stderr_file, ! "slave : sending state %d to master\n", ! output_state_msg_info.sequence); ! #endif ! send_msg(output_socket, &output_state_msg_info, &output_addr); ! /* Try a 12 ms timeout for now */ ! if (rcv_msg(input_socket, &scratch_msg_info, NULL, 30) != OSD_OK) ! continue; ! ! if (scratch_msg_info.msg_type == QUIT) { ! fprintf(stderr_file, "Master disconnected! No more network input\n"); ! current_net_role = NONE; ! return; ! } ! if (scratch_msg_info.msg_type != GLOBAL_STATE) { ! fprintf(stderr_file, ! "Error : Received wrong packet type (%d) from master\n", ! scratch_msg_info.msg_type); ! continue; ! } ! ! #ifdef PROTOCOL_DEBUG ! fprintf(stderr_file, ! "slave : received state %d from master (awaiting %d)\n", ! scratch_msg_info.sequence, ! current_frame_sequence); ! #endif ! if (scratch_msg_info.sequence == current_frame_sequence) ! break; ! } ! ! for (i = 0; i < MAX_INPUT_PORTS; i++) { ! input_port_values[i] = ntohs(((unsigned short *)(scratch_msg_info.data_start))[i]); ! } ! current_frame_sequence += 1; } + void osd_net_sync(unsigned short input_port_values[MAX_INPUT_PORTS], + unsigned short input_port_defaults[MAX_INPUT_PORTS]) + { + switch(current_net_role) { + case MASTER: + osd_master_sync(input_port_values, input_port_defaults); + break; + case SLAVE: + osd_slave_sync(input_port_values, input_port_defaults); + break; + default: + /* wtf? */ + break; + } + } + /* * Close all opened sockets */ void osd_net_close(void) { ! unsigned i, j; ! switch(current_net_role) { ! case SLAVE: ! scratch_msg_info.msg_type = QUIT; ! prime_msg(&scratch_msg_info); ! for (i = 0; i < 4; i++) { ! send_msg(output_socket, &scratch_msg_info, &output_addr); ! usleep(50); ! } ! close(input_socket); ! close(output_socket); ! break; ! case MASTER: ! scratch_msg_info.msg_type = QUIT; ! prime_msg(&scratch_msg_info); ! for (i = 0; i < 4; i++) { ! for (j = 0; j < original_player_count - 1; j++) { ! if (slave_info[j].active) { ! send_msg(output_socket, &scratch_msg_info, &(slave_info[j].addr)); ! } ! } ! usleep(50); ! } ! close(input_socket); ! close(output_socket); ! break; ! case NONE: ! break; } } *************** *** 443,469 **** */ int osd_net_init(void) { ! netstate = 0; ! ! if (players) netstate = MASTER; ! if (mastername) ! { ! if(netstate==MASTER) ! { fprintf(stderr_file, "error: can't be Slave and Master\n"); return OSD_NOT_OK; } ! netstate = SLAVE; } ! switch(netstate) { ! case 0: return OSD_OK; case MASTER: ! if (init_master_socket() != OSD_OK) return OSD_NOT_OK; ! if (wait_registration() != OSD_OK) return OSD_NOT_OK; break; case SLAVE: --- 755,780 ---- */ int osd_net_init(void) { ! if (original_player_count > 0) { ! current_net_role = MASTER; ! } ! ! if (master_hostname) { ! if (current_net_role == MASTER) { fprintf(stderr_file, "error: can't be Slave and Master\n"); return OSD_NOT_OK; } ! current_net_role = SLAVE; } ! switch(current_net_role) { ! case NONE: return OSD_OK; case MASTER: ! if (init_master_sockets() != OSD_OK) return OSD_NOT_OK; ! if (await_slave_registrations() != OSD_OK) return OSD_NOT_OK; break; case SLAVE: *************** *** 471,482 **** return OSD_NOT_OK; if (register_to_master() != OSD_OK) return OSD_NOT_OK; break; } - if (netkeymap) build_keymap(); - /* mouse is not supported in network mode */ - use_mouse = FALSE; return OSD_OK; } #endif /* MAME_NET */ --- 782,797 ---- return OSD_NOT_OK; if (register_to_master() != OSD_OK) return OSD_NOT_OK; + /* if (input_remap) + build_net_keymap(); */ break; } return OSD_OK; + } + + int osd_net_active(void) + { + return (current_net_role != NONE); } #endif /* MAME_NET */ diff -cr xmame-0.56.1/src/usrintrf.c xmame-0.56.1-net/src/usrintrf.c *** xmame-0.56.1/src/usrintrf.c Fri Nov 2 20:22:51 2001 --- xmame-0.56.1-net/src/usrintrf.c Wed Dec 5 19:56:22 2001 *************** *** 3575,3583 **** while (!input_ui_pressed(IPT_UI_PAUSE)) { - #ifdef MAME_NET - osd_net_sync(); - #endif /* MAME_NET */ profiler_mark(PROFILER_VIDEO); if (osd_skip_this_frame() == 0) { --- 3575,3580 ---- _______________________________________________ Xmame mailing list [EMAIL PROTECTED] http://toybox.twisted.org.uk/mailman/listinfo/xmame