X-Git-Url: http://git.shiar.nl/netris.git/blobdiff_plain/e3d58186949bfcdb149cc2a545ce6c14a8689268..HEAD:/server.c diff --git a/server.c b/server.c index 7e0aca1..70406a3 100644 --- a/server.c +++ b/server.c @@ -15,13 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: game.c,v 1.39 1999/05/16 06:56:27 mhw Exp $ */ #define NOEXT #include "netris.h" + #include +#include #include #include #include @@ -32,160 +32,102 @@ #include #include -#define HEADER_SIZE sizeof(netint4[3]) -#define MAX_CONNECTIONS 3 +#include "util.h" +#include "msg.h" -char *version_string = "0.5.89"; +#define HEADER_SIZE sizeof(netint4[3]) static struct option options[] = { - { "wait", 0, 0, 'w' }, - { "port", 1, 0, 'p' }, - { "speed", 1, 0, 'i' }, - { "seed", 1, 0, 's' }, - { "info", 0, 0, 'H' }, - { "help", 0, 0, 'h' }, - { 0, 0, 0, 0 } + { "wait", 0, 0, 'w' }, + { "port", 1, 0, 'p' }, + { "quadra", 1, 0, 'q' }, + { "min-players", 1, 0, 'm' }, + { "max-players", 1, 0, 'x' }, + { "continuous", 1, 0, 'c' }, + { "speed", 1, 0, 'i' }, + { "seed", 1, 0, 's' }, + { "verbose", 0, 0, 'v' }, + { "info", 0, 0, 'H' }, + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } }; -static char *gameNames[GT_len] = { "OnePlayer", "ClassicTwo" }; +static char minplayers = 2; +static char maxplayers = 8; +static char playercount; +static char verbose = 0; -ExtFunc MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event); +struct sockaddr_in addr; -EventGenRec netGen[MAX_SCREENS] = { - { NULL, 0, FT_read, -1, NetGenFunc, EM_net, 0, "\0", 0, HEADER_SIZE } }; +static MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event); +static EventGenRec netGen[MAX_SCREENS] = { + { NULL, 0, FT_read, -1, NetGenFunc, EM_net, 0, "\0", 0, HEADER_SIZE } +}; static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event); -static EventGenRec alarmGen = - { &alarmGen, 0, FT_read, -1, AlarmGenFunc, EM_alarm }; +static EventGenRec alarmGen = { + &alarmGen, 0, FT_read, -1, AlarmGenFunc, EM_alarm +}; + +static MyEventType ConnGenFunc(EventGenRec *gen, MyEvent *event); +static EventGenRec connGen = { + NULL, 0, FT_read, -1, ConnGenFunc, EM_connect +}; + static EventGenRec *nextGen = &alarmGen; static sigjmp_buf close_env; -ExtFunc volatile void die(char *msg) -{ - perror(msg); - exit(1); -} //die -ExtFunc int MyRead(int fd, void *data, int len) -{ - int result, left; - - left = len; - while (left > 0) { - result = read(fd, data, left); - if (result > 0) { - data = ((char *)data) + result; - left -= result; - } - else if (errno != EINTR) - return result; - } - return len; -} //MyRead +static void SendPacketTo(short player, short uid, NetPacketType type, int size, void *data) +{ //send to someone + netint4 header[3]; -ExtFunc int MyWrite(int fd, void *data, int len) -{ - int result, left; - - left = len; - while (left > 0) { - result = write(fd, data, left); - if (result > 0) { - data = ((char *)data) + result; - left -= result; - } - else if (errno != EINTR) - return result; + if (netGen[player].fd >= 0) { + if (verbose) + fprintf(stderr, MSG_SERVER_DBG_SEND "\n", type, uid, player); + header[0] = hton4(uid); + header[1] = hton4(type); + header[2] = hton4(size + HEADER_SIZE); + if (MyWrite(netGen[player].fd, header, HEADER_SIZE) != HEADER_SIZE) + die("write (header)"); + if (size > 0 && data && MyWrite(netGen[player].fd, data, size) != size) + die("write"); } - return len; -} //MyWrite +} static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event) { return E_alarm; } -ExtFunc void AddEventGen(EventGenRec *gen) -{ - assert(gen->next == NULL); - assert(nextGen->next != (void*)0xffffffff); - gen->next = nextGen->next; - nextGen->next = gen; -} //AddEventGen +static void SCloseNet(short player) +{ //kick some connection's ass! + MyEvent event; -ExtFunc void RemoveEventGen(EventGenRec *gen) -{ - // assert(gen->next != NULL); /* Be more forgiving, for SIGINTs */ - if (gen->next) { - while (nextGen->next != gen) - nextGen = nextGen->next; - nextGen->next = gen->next; - gen->next = NULL; + if (netGen[player].fd >= 0) { + if (Players[player].alive >= 0) { + SendPacketTo(player, 0, NP_endConn, 0, NULL); + do {} while (WaitMyEvent(&event, EM_net) != E_lostConn); + } //say bye to player + close(netGen[player].fd); + netGen[player].fd = -1; } -} //RemoveEventGen - -ExtFunc MyEventType WaitMyEvent(MyEvent *event, int mask) -{ //poll - int i, retry = 0; - fd_set fds[FT_len]; - EventGenRec *gen; - int result, anyReady, anySet; - struct timeval tv; - - for (;;) { - for (i = 0; i < FT_len; ++i) - FD_ZERO(&fds[i]); - anyReady = anySet = 0; - gen = nextGen; - do { - if (gen->mask & mask) { - if (gen->ready) - anyReady = 1; - if (gen->fd >= 0) { - FD_SET(gen->fd, &fds[gen->fdType]); - anySet = 1; - } - } - gen = gen->next; - } while (gen != nextGen); - if (anySet) { - tv.tv_sec = 0; - tv.tv_usec = (retry && !anyReady) ? 500000 : 0; - result = select(FD_SETSIZE, &fds[FT_read], &fds[FT_write], - &fds[FT_except], anyReady ? &tv : NULL); - } - else { - if (retry && !anyReady) - sleep(1); - result = 0; - } - gen = nextGen; - do { - if ((gen->mask & mask) - && (gen->ready || (result > 0 && gen->fd >= 0 - && FD_ISSET(gen->fd, &fds[gen->fdType])))) { - gen->ready = 0; - event->type = gen->func(gen, event); - if (event->type != E_none) { - nextGen = gen->next; - return event->type; - } - } - gen = gen->next; - } while (gen != nextGen); - retry = 1; - } -} //WaitMyEvent + if (netGen[player].next) + RemoveEventGen(&netGen[player]); +} -ExtFunc void ByeClient(int playa) -{ //client went away - fprintf(stderr, "Close connection #%d\n", playa); - close(netGen[playa].fd); - netGen[playa].fd = -1; -} //ByeClient +static void CloseNets(void) +{ //nou oogjes dicht en snaveltjes toe + int i; -ExtFunc MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event) + fprintf(stderr, MSG_SERVER_CLOSE_ALL "\n"); + for (i = 1; i < MAX_SCREENS; i++) + SCloseNet(i); // bye everybuddy + fprintf(stderr, MSG_SERVER_CLOSE_ALL_DONE "\n\n"); +} + +static MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event) { //receive int result; short uid, type, size; @@ -194,15 +136,14 @@ ExtFunc MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event) result = MyRead(gen->fd, gen->buf + gen->bufSize, gen->bufGoal - gen->bufSize); if (result < 0) { - ByeClient(gen->player); - type = NP_endConn; - return E_net; + fprintf(stderr, MSG_SERVER_PLAYER_CLOSED "\n", gen->player); + return E_lostConn; } gen->bufSize += result; if (gen->bufSize < gen->bufGoal) return E_none; // *ugly* memcpy(data, gen->buf, sizeof(data)); - uid = ntoh4(data[0]); + uid = ntoh4(data[0]); type = ntoh4(data[1]); size = ntoh4(data[2]); gen->bufGoal = size; @@ -215,287 +156,341 @@ ExtFunc MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event) event->u.net.type = type; event->u.net.size = size - HEADER_SIZE; event->u.net.data = gen->buf + HEADER_SIZE; - if (type == NP_endConn) - ByeClient(gen->player); + if (type == NP_endConn) { + fprintf(stderr, MSG_SERVER_PLAYER_QUIT "\n", gen->player); + return E_lostConn; + } //client sent quit signal return E_net; -} //NetGenFunc - -ExtFunc void SendPacketTo(short playa, short uid, NetPacketType type, int size, void *data) -{ //send to someone - netint4 header[3]; - - if (netGen[playa].fd >= 0) { - header[0] = hton4(uid); - header[1] = hton4(type); - header[2] = hton4(size + HEADER_SIZE); - if (MyWrite(netGen[playa].fd, header, HEADER_SIZE) != HEADER_SIZE) - die("write (header)"); - if (size > 0 && data && MyWrite(netGen[playa].fd, data, size) != size) - die("write"); - } -} //SendPacketTo - - -ExtFunc void AtExit(void (*handler)(void)) -{ -#ifdef HAS_ON_EXIT - on_exit((void *)handler, NULL); -#else - atexit(handler); -#endif } -ExtFunc void SCloseNet(short playa) -{ //kick some connection's ass! - MyEvent event; - - if (netGen[playa].fd >= 0) { - SendPacketTo(playa, 0, NP_endConn, 0, NULL); - do{} while (WaitMyEvent(&event, EM_net) != E_lostConn); - close(netGen[playa].fd); - netGen[playa].fd = -1; - } - if (netGen[playa].next) - RemoveEventGen(&netGen[playa]); -} //SCloseNet - -ExtFunc void CloseNets(void) -{ //nou oogjes dicht en snaveltjes toe - int i; - - for (i = 1; i <= totalPlayers; i++) - SCloseNet(i); -} //CloseNets -ExtFunc int WaitForConnection(short port) +static MyEventType ConnGenFunc(EventGenRec *gen, MyEvent *event) { - struct sockaddr_in addr; - struct hostent *host; - int sockListen; int addrLen; - int val1; struct linger val2; - int i; - - AtExit(CloseNets); - for (i = 1; i < MAX_SCREENS; i++) - memcpy(&netGen[i], &netGen[0], sizeof(EventGenRec)); - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_ANY); - if ((sockListen = socket(AF_INET, SOCK_STREAM, 0)) < 0) - die("socket"); - val1 = 1; - setsockopt(sockListen, SOL_SOCKET, SO_REUSEADDR, - (void *)&val1, sizeof(val1)); - if (bind(sockListen, (struct sockaddr *)&addr, sizeof(addr)) < 0) - die("bind"); - if (listen(sockListen, 1) < 0) - die("listen"); + int new; addrLen = sizeof(addr); - for (i = 1; i <= MAX_CONNECTIONS; i++) { - if ((netGen[i].fd = accept(sockListen, (struct sockaddr *)&addr, &addrLen)) < 0) - die("accept"); - fprintf(stderr, "Connection: %s\n", inet_ntoa(addr.sin_addr)); - val2.l_onoff = 1; - val2.l_linger = 0; - setsockopt(netGen[i].fd, SOL_SOCKET, SO_LINGER, (void *)&val2, sizeof(val2)); - sprintf(Players[i].host, "%s", inet_ntoa(addr.sin_addr)); + for (new = 1; new <= MAX_SCREENS; new++) + if (netGen[new].fd < 0) break; + if (new > maxplayers) return; + + if (( + netGen[new].fd = accept(gen->fd, (struct sockaddr *)&addr, &addrLen) + ) < 0) + die("accept"); + fprintf(stderr, MSG_SERVER_CONNECT "\n", inet_ntoa(addr.sin_addr)); + val2.l_onoff = 1; + val2.l_linger = 0; + setsockopt(netGen[new].fd, SOL_SOCKET, SO_LINGER,(void *)&val2, + sizeof(val2)); + AddEventGen(&netGen[new]); + netGen[new].player = event->u.net.uid = new; + { //new connection; netGen already initialized in GenFunc + struct hostent *host; + + sprintf(Players[new].host, "%s", inet_ntoa(addr.sin_addr)); if (addr.sin_family == AF_INET) { - host = gethostbyaddr((void *)&addr.sin_addr, - sizeof(struct in_addr), AF_INET); + host = gethostbyaddr( + (void *)&addr.sin_addr, sizeof(struct in_addr), AF_INET + ); if (host) { - strncpy(Players[i].host, host->h_name, sizeof(Players[i].host) - 1); - Players[i].host[sizeof(Players[i].host) - 1] = 0; - } + strncpy(Players[new].host, host->h_name, + sizeof(Players[new].host) - 1); + Players[new].host[sizeof(Players[new].host) - 1] = 0; + } //set player's hostname } - AddEventGen(&netGen[i]); - netGen[i].player = i; - totalPlayers++; - { - MyEvent event; - - do {} while ((WaitMyEvent(&event, EM_net) != E_net) || - (event.u.net.sender != i)); - if (event.u.net.type != NP_hello) ByeClient(i); - else { - netint4 versiondata[2]; - char data[255]; - int major; - memcpy(versiondata, event.u.net.data, sizeof(versiondata)); - major = ntoh4(versiondata[0]); - protocolVersion = ntoh4(versiondata[1]); - if (major != MAJOR_VERSION || protocolVersion != PROTOCOL_VERSION) { - snprintf(data, sizeof(data), "Version mismatch: received %d.%d", - major, protocolVersion); - fprintf(stderr, "Byebye client #%d (%s)\n", - event.u.net.sender, data); - SendPacketTo(event.u.net.sender, 0, NP_error, strlen(data)+1, data); - SCloseNet(event.u.net.sender); - } //version mismatch - fprintf(stderr, "Accepted #%d\n", event.u.net.sender); - } //NP_hello + } //E_connect + return E_connect; +} + +static void CountPlayers(void) +{ //count number of players/teams + int i, j; + playercount = 0; + for (i = 1; i < MAX_SCREENS; i++) if (Players[i].alive > 0) { + if (Players[i].team < 128) for (j = 1; j < i; j++) { + if (Players[j].alive > 0 && Players[j].team == Players[i].team) { + playercount--; // player of same team counted before + break; + } } - } - close(sockListen); - return 0; -} //WaitForConnection + playercount++; + } //player alive +} -ExtFunc int StartServer(char *portStr) +static int StartServer(void) { MyEvent event; - char serverdata[255]; - int playercount; + netint2 currentpiece[MAX_SCREENS]; + int playersReady = 0; + bool paused = 1; int i; - { - short port; - - if (portStr) - port = atoi(portStr); /* XXX Error checking */ - else - port = DEFAULT_PORT; - WaitForConnection(port); - } - - playercount = MAX_CONNECTIONS; - - for (i = 1; i <= playercount; i++) { - sprintf(serverdata, "Netris server %s", version_string); - SendPacketTo(i, i, NP_hello, strlen(serverdata)+1, serverdata); - } - - while(1) { - if (WaitMyEvent(&event, EM_net) == E_net) { -// fprintf(stderr, "in %d: %d\n", -// netGen[event.u.net.sender].fd, event.u.net.type); - switch(event.u.net.type) { - case NP_endConn: - { //client went away :( - //tell the others! :) - break; - } //NP_endConn + do { + switch (WaitMyEvent(&event, EM_any)) { + case E_lostConn: //client went away :( + Players[event.u.net.sender].alive = -1; + for (i = 1; i < MAX_SCREENS; i++) + if (Players[i].alive >= 0) + SendPacketTo(i, event.u.net.sender, + NP_part, sizeof(Players[0].alive), + &Players[event.u.net.sender].alive); + SCloseNet(event.u.net.sender); + break; //NP_endConn + case E_net: + if (verbose) fprintf(stderr, MSG_SERVER_DBG_RECV "\n", + netGen[event.u.net.sender].fd, event.u.net.type); + switch(event.u.net.type) { case NP_hello: +// if (event.u.net.type != NP_hello) ByeClient(new); + { + netint4 versiondata[2]; + char data[255]; + int major; + int protocolVersion; + + memcpy(versiondata, event.u.net.data, sizeof(versiondata)); + major = ntoh4(versiondata[0]); + protocolVersion = ntoh4(versiondata[1]); + if (major != MAJOR_VERSION + || protocolVersion != PROTOCOL_VERSION) { + snprintf(data, sizeof(data), + "Version mismatch: received %d.%d", + major, protocolVersion); + fprintf(stderr, MSG_SERVER_PLAYER_EVERSION "\n", + event.u.net.sender, data); + SendPacketTo(event.u.net.sender, 0, NP_error, + strlen(data)+1, data); + SCloseNet(event.u.net.sender); + } //version mismatch + fprintf(stderr, MSG_SERVER_PLAYER_ACCEPT "\n", + event.u.net.sender); break; + } //NP_hello case NP_newPlayer: - { //receive player details and return other players + //receive player details and return other players memcpy(&Players[event.u.net.sender], event.u.net.data, event.u.net.size); - fprintf(stderr, "player %d: %s <%s>\n", event.u.net.sender, - event.u.net.data, //Players[event.u.net.sender].name - Players[event.u.net.sender].host); - for (i = 1; i <= totalPlayers; i++) - if (i != event.u.net.sender) - SendPacketTo(i, event.u.net.sender, event.u.net.type, - sizeof(Player) - sizeof(Players[0].spy), - &Players[event.u.net.sender]); - if (--playercount == 0) { - fprintf(stderr, "Starting game\n"); - for (i = 1; i <= totalPlayers; i++) - SendPacketTo(i, 0, NP_goAhead, 0, NULL); - playercount++; + if (Players[event.u.net.sender].team < 1 + || Players[event.u.net.sender].team > 7) { + int team; + + for (team = 1; team < 7; team++) { + for (i = 1; i < MAX_SCREENS; i++) + if (Players[i].alive > 0 && Players[i].team == team) + break; //team in use + if (i == MAX_SCREENS) break; + } //find unused team + Players[event.u.net.sender].team = team; + SendPacketTo(event.u.net.sender, event.u.net.sender, NP_team, + sizeof(Players[event.u.net.sender].team), + &Players[event.u.net.sender].team); + } //invalid team + if (Game.started < 2) + Players[event.u.net.sender].flags |= SCF_paused; + if (!Game.continuous && Game.started >= 2) { + char data[40]; + strcpy(data, "Can't join: Game has already started"); + fprintf(stderr, MSG_SERVER_PLAYER_JOIN_ESTARTED, + event.u.net.sender); + SendPacketTo(event.u.net.sender, 0, NP_error, + strlen(data)+1, data); +// SCloseNet(event.u.net.sender, 0); + break; + } //can't join started game + { + static struct { + int playerflags; + int gravity; //1 + int started; //2 + int continuous; //3 + long seed; //4 + float shapes[7]; + int initspeed; //5 + } data; + + memcpy(&data, &Players[event.u.net.sender].flags, + sizeof(data.playerflags)); + memcpy(&data.gravity, &Game.gravity, + sizeof(data) - sizeof(data.playerflags)); + SendPacketTo(event.u.net.sender, 0, NP_gamedata, + sizeof(data), &data); + } //send game options + for (i = 1; i < MAX_SCREENS; i++) + if (netGen[i].fd >= 0 && i != event.u.net.sender) { + SendPacketTo(event.u.net.sender, i, NP_newPlayer, + sizeof(player_t), &Players[i]); + SendPacketTo(event.u.net.sender, i, NP_newPiece, + sizeof(Players[i].curShape), &Players[i].curShape); + SendPacketTo(i, event.u.net.sender, NP_newPlayer, + sizeof(player_t), &Players[event.u.net.sender]); + } //send (to) players + fprintf(stderr, MSG_SERVER_PLAYER_JOIN "\n", + event.u.net.sender, + Players[event.u.net.sender].name, + Players[event.u.net.sender].host, + teamname[Players[event.u.net.sender].team]); + if (++playersReady >= minplayers) { + if (Game.started > 1) + SendPacketTo(event.u.net.sender, 0, + NP_start, 0, NULL); +/* else { + fprintf(stderr, "* Starting game (%010d)\n", + Game.seed); + for (i = 1; i < MAX_SCREENS; i++) + SendPacketTo(i, 0, NP_start, 0, NULL); + Game.started++; + } //first goahead (to all)*/ } //give go ahead - break; - } //NP_playerdata - default: - { //relay data to all players - // if (event.u.net.type >= NP_pause) - for (i = 1; i <= totalPlayers; i++) + break; //NP_playerdata + case NP_newPiece: + memcpy(&Players[event.u.net.sender].curShape, + event.u.net.data, sizeof(Players[0].curShape)); + goto sendtoall; + case NP_argghhh: + Players[event.u.net.sender].alive = 0; + fprintf(stderr, MSG_SERVER_PLAYER_DIE "\n", + event.u.net.sender); + //check for unpaused game + case NP_pause: + { + Players[event.u.net.sender].flags ^= SCF_paused; + paused = Game.started < 1; + for (i = 1; i < MAX_SCREENS; i++) + if (Players[i].alive > 0) + paused |= (Players[i].flags & SCF_paused) != 0; + fprintf(stderr, MSG_SERVER_PLAYER_PAUSE "\n", + event.u.net.sender, paused); + goto sendtoall; + } //NP_pause + default: //relay data to all players + sendtoall: +// if (event.u.net.type >= NP_pause) + if (event.u.net.type >= NP_rotright + && Game.started < 2) + break; + for (i = 1; i < MAX_SCREENS; i++) if (i != event.u.net.sender) - SendPacketTo(i, event.u.net.sender, event.u.net.type, - event.u.net.size, event.u.net.data); - break; + if (event.u.net.type != NP_giveJunk + || Players[i].team != Players[event.u.net.sender].team) + SendPacketTo(i, event.u.net.sender, + event.u.net.type, event.u.net.size, + event.u.net.data); + break; //>=NP_paused } - } //E_net - } - } //loop -} //StartServer + break; //E_net + case E_connect: + { //new connection; netGen already initialized in GenFunc + char serverdata[255]; + + sprintf(serverdata, "Netris server %s", version_string); + SendPacketTo(event.u.net.uid, event.u.net.uid, NP_hello, + strlen(serverdata)+1, serverdata); + break; + } //E_connect + } //event + CountPlayers(); + if (Game.started < 1) { + if (playercount >= 2) { + fprintf(stderr, MSG_SERVER_GAME_READY "\n", Game.seed); + Game.started++; + } //give goahead + } //game not yet started + else { + if (playercount < 2) { + fprintf(stderr, MSG_SERVER_GAME_STOP "\n"); + if (Game.seed) Game.seed++; + if (Game.started > 1) for (i = 1; i < MAX_SCREENS; i++) { + if (Players[i].alive >= 0) { + Players[i].alive = 1; + Players[i].flags |= SCF_paused; + SendPacketTo(i, 0, NP_stop, + sizeof(Game.seed), &Game.seed); + } //transmit game stop and set players not ready + } + paused = 1; + Game.started = 0; + } //too few players for game + if (Game.started == 1 && !paused) { + Game.started++; + fprintf(stderr, MSG_SERVER_GAME_START "\n"); + for (i = 1; i < MAX_SCREENS; i++) + if (Players[i].alive > 0) + SendPacketTo(i, 0, NP_start, 0, NULL); + } //everybody ready to start + } //game (ready to) start(ed) + } while (1); + fprintf(stderr, "* Exiting server\n"); +} -ExtFunc void Header(void) +static void SHeader(void) { - fprintf(stderr, - "NETRIS Server %s\t(c) 2002 Shiar \n\n", - version_string); -} //Header - -ExtFunc void Usage(void) -{ - Header(); - fprintf(stderr, - "Usage: netris \n" - "\n" - " -h, --help\t\tPrint this usage information\n" - " -H, --info\t\tShow distribution and warranty information\n" - "\n" - " -p, --port \tSet port number (default is %d)\n" - "\n" - " -s, --seed \tStart with given random seed\n" - " -i, --speed \tSet the initial step-down interval, in seconds\n" - "\n", DEFAULT_PORT); + fprintf(stderr, MSG_SERVER_TITLE "\n\n", version_string); } -ExtFunc void DistInfo(void) +static void SUsage(void) { - Header(); + SHeader(); fprintf(stderr, - "This program is free software; you can redistribute it and/or modify\n" - "it under the terms of the GNU General Public License as published by\n" - "the Free Software Foundation; either version 2 of the License, or\n" - "(at your option) any later version.\n" - "\n" - "This program is distributed in the hope that it will be useful,\n" - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" - "GNU General Public License for more details.\n" - "\n" - "You should have received a copy of the GNU General Public License\n" - "along with this program; if not, write to the Free Software\n" - "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n" - "\n"); -} //DistInfo - -ExtFunc void WriteConf(void) -{ - FILE *file_out; - - file_out = fopen(CONFIG_FILE, "w"); - if (file_out == NULL) { - perror("Error writing config file"); - exit(1); - } - - fprintf(file_out, "### NETRIS %s Config file ###\n\n", version_string); - - fclose(file_out); - fprintf(stderr, "Wrote new game configuration to %s\n", CONFIG_FILE); -} //WriteConf + "Usage: netris \n" + "\n" + " -h, --help\t\tPrint this usage information\n" + " -H, --info\t\tShow distribution and warranty information\n" + "\n" + " -p, --port %d\tSet port number\n" + "\n" + " -s, --seed \tStart with given random seed\n" + " -i, --speed %.2f\tSet the initial step-down interval, in seconds\n" + " -m, --min-players %d\tNumber of players required before starting the game\n" + " -x, --max-players %d\tMaximum number of players allowed in the game\n" + " -c, --continuous\tDon'n quit the game\n" + "\n", + DEFAULT_PORT, DEFAULT_INTERVAL/1e6, minplayers, maxplayers + ); +} -ExtFunc void HandleOption(char tag, char *value) +static void HandleOption(char tag, char *value) { switch (tag) { - case 'p': //port - portStr = value; break; - case 'i': //speed (of level 1) - Game.initspeed = atof(value) * 1e6; - break; - case 's': //seed - Game.seed = atoi(value); - Players[0].flags |= SCF_setSeed; - break; - case 'H': //info - DistInfo(); exit(0); - case 'h': //help - Usage(); exit(0); - default: - break; + case 'v': //verbose + verbose = 1; + break; + case 'p': //port + port = atoi(value); + break; + case 'c': //min-players + Game.continuous = atoi(value); + break; + case 'm': //min-players + minplayers = atoi(value); + break; + case 'x': //max-players + maxplayers = MIN(atoi(value), MAX_SCREENS); + break; + case 'q': //quadra-style gravity + Game.gravity ^= 1; + break; + case 'i': //speed (of level 1) + Game.initspeed = atof(value) * 1e6; + break; + case 's': //seed + Game.seed = atoi(value); + break; + case 'H': //info + SHeader(); + DistInfo(); + exit(0); + case 'h': //help + SUsage(); + exit(0); + default: + break; } -} //HandleParam +} -ExtFunc void ReadConf(char *filename) +static void ReadConf(char *filename) { FILE *file_in; char buf[513]; @@ -509,7 +504,8 @@ ExtFunc void ReadConf(char *filename) if ((ch = strchr(buf, '#'))) *ch = '\0'; // truncate string from # char for (i = strlen(buf)-1; i >= 0; i--) - if (buf[i] == ' ' || buf[i] == '\n' || buf[i] == '\t' || buf[i] == 13) + if (buf[i] == ' ' || buf[i] == '\t' + || buf[i] == '\n' || buf[i] == 13) buf[i] = '\0'; else break; @@ -527,41 +523,81 @@ ExtFunc void ReadConf(char *filename) fprintf(stderr, "Unable to open config file %s.\n", filename); } //defaults -} //ReadConf +} -ExtFunc void CatchInt(int sig) +static void CatchInt(int sig) { siglongjmp(close_env, 1); } -ExtFunc int main(int argc, char **argv) +int main(int argc, char **argv) { + int i; char ch; if (sigsetjmp(close_env, 1)) exit(0); signal(SIGINT, CatchInt); - Game.standout = Game.color = 1; + port = DEFAULT_PORT; + maxplayers = 8; Game.initspeed = DEFAULT_INTERVAL; + Game.seed = time(0); + for (i = 0; i < sizeof(Game.shapes) / sizeof(Game.shapes[0]); i++) + Game.shapes[i] = 1; + Game.gravity = 0; + { + int i; + + for (i = 1; i < MAX_SCREENS; i++) + Players[i].alive = -1; + } // if (getopt(argc, argv, "f:") == 'f') // ReadConf(optarg); // else ReadConf(CONFIG_FILE); - while ((ch = getopt_long(argc, argv, - "hHp:i:s:", options, NULL)) != -1) + while ((ch = getopt_long( + argc, argv, "hHvqp:i:s:c:m:x:", options, NULL + )) != -1) HandleOption(ch, optarg); if (optind < argc) { - Usage(); + SUsage(); exit(1); } // WriteConf(); - Header(); - StartServer(portStr); + SHeader(); + + { + int i; + + for (i = 1; i < MAX_SCREENS; i++) + memcpy(&netGen[i], &netGen[0], sizeof(EventGenRec)); + } //setup netGen var + + AtExit(CloseNets); + + { + int val1; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + if ((connGen.fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + die("socket"); + val1 = 1; + setsockopt(connGen.fd, SOL_SOCKET, SO_REUSEADDR, + (void *)&val1, sizeof(val1)); + if (bind(connGen.fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) + die("bind"); + if (listen(connGen.fd, 1) < 0) + die("listen"); + + AddEventGen(&connGen); + } //setup listening sock + + StartServer(); //server loop + return 0; } -/* - * vi: ts=4 ai - * vim: noai si - */