/* * file central.c - communication interface for the server * * $Id: central.c,v 1.3 2004/05/14 10:00:32 alfie Exp $ * * Program XBLAST * (C) by Oliver Vogel (e-mail: m.vogel@ndh.net) * Added by Koen De Raedt for central support * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2; or (at your option) * any later version * * This program is distributed in the hope that it will be entertaining, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILTY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * Public License for more details. * * 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. * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "central.h" #include "cfg_player.h" #include "com_listen.h" #include "com_from_central.h" #include "random.h" #include #include #define RATING_WEIGTH 1.0 #define RATING_STEP 0.1 #define GJFAC 0.005 #define GJFAC2 1.005 #define SIZE 32 /* * local variables */ static XBComm *listenComm = NULL; static XBComm *centralComm = NULL; static int cPlayers; static int cGames; static int cGamesPlayed; static int cTotalGames; static int cLogins; static XBAtom adminAtom; CFGPlayerRating adminRating; /* * Start to listen for clients */ XBBool Central_StartListen (CFGGameHost *cfg) { int i,j; char tmp[256]; /* prepare database */ LoadPlayerCentral(XBTrue); cPlayers=GetNumPlayerConfigs (CT_Central)-1; // administator adminAtom=GUI_IntToAtom(0); RetrievePlayerRating (CT_Central, adminAtom, &adminRating); adminRating.timeRegister=time (NULL); StorePlayerRating (CT_Central, adminAtom, &adminRating); SavePlayerCentral(); cGames=0; cGamesPlayed=0; cTotalGames=adminRating.gamesPlayed; cLogins=0; for (i=0; i < NUM_LOCAL_PLAYER; i ++) { Network_SetPlayer (0, i, ATOM_INVALID); } for (i=1;i < MAX_PLAYER; i++) { j=sprintf(tmp,"tmpPlayer%i",i); tmp[j+1]=0; Network_SetPlayer (i, 0, GUI_StringToAtom (tmp)) ; }; /* listen on tcp-port for clients */ assert (listenComm == NULL); listenComm = CommCreateListen (cfg, XBTrue); // central if (NULL == listenComm) { return XBFalse; } /* allow client to browse for games */ assert (NULL == centralComm); centralComm = Central_CreateComm (cfg->port); if (NULL == centralComm) { Dbg_Out ("failed to open reply socket\n"); return XBFalse; } /* that'S all */ return XBTrue; } /* Central_StartListen */ /* * delete port for listening */ void Central_StopListen (void) { /* delete listen port */ assert (NULL != listenComm); CommDelete (listenComm); listenComm = NULL; /* dlete reply socket */ if (NULL != centralComm) { CommDelete (centralComm); centralComm = NULL; } /* Update administrator */ adminRating.gamesPlayed=cTotalGames; adminRating.timeUpdate=time (NULL); StorePlayerRating (CT_Central, adminAtom, &adminRating); /* save and close rating DB */ SavePlayerCentral(); FinishPlayerCentral(); } /* Central_StopListen */ /* * disconnect from clients */ void Central_SendDisconnect (unsigned clientID) { assert (clientID > 0); assert (clientID < MAX_HOSTS); /* disconnect from client */ if (C2X_Connected (clientID) ) { C2X_Disconnect (clientID); } } /* Central_SendDisconnect */ /* * disconnect from clients */ void Central_SendDisconnectAll (void) { unsigned clientID; /* disconnect from client */ for (clientID = 1 ; clientID < MAX_HOSTS; clientID ++) { Central_SendDisconnect (clientID); } } /* Central_SendDisconnectAll */ /* * central get statistics */ void Central_GetStatistics(int *nPlayers, int *nGames, int *nGamesPlayed, int *nTotalGames, int *nLogins) { *nPlayers=cPlayers; *nGames=com_GetOpenGames(); *nGamesPlayed=cGamesPlayed; *nTotalGames=cTotalGames; *nLogins=cLogins; } /* * a client has connected */ void Central_Accept (unsigned id, const char *hostName, unsigned port) { CFGGameHost cfg; assert (hostName != NULL); assert (id > 0); assert (id < MAX_HOSTS); Dbg_Out ("client adr=%s:%u id=%u connected\n", hostName, port, id); /* clear host entry in database */ DeleteGameConfig (CT_Remote, atomArrayHost0[id]); Dbg_Out("++ DEBUG 1 "); /* store in database */ memset (&cfg, 0, sizeof (cfg)); Dbg_Out(" 2 "); cfg.name = hostName; cfg.port = port; Dbg_Out(" 3 "); StoreGameHost (CT_Remote, atomArrayHost0[id], &cfg); Dbg_Out(" 4 "); /* create message */ Network_QueueEvent (XBNW_Accepted, id); cLogins++; Dbg_Out(" 5\n"); } /* Central_ClientAccepted */ /* * */ void Central_NotifyError (unsigned clientID) { assert (clientID > 0); assert (clientID < MAX_HOSTS); if (C2X_Connected (clientID) ) { C2X_Disconnect (clientID); } /* inform application */ Network_QueueEvent (XBNW_Error, clientID); } /* Central_NotifyError */ /* for little / big endian support */ int endian(int x) { char *i,*o; int y; i=(char *)&x; o=(char *)&y; o[0]=i[3]; o[1]=i[2]; o[2]=i[1]; o[3]=i[0]; return y; } /* * game config retrieved from client */ void Central_ReceiveGameStat (const char *line) { // line = numplayers, pid1, score1, pid2, score2, ... int numPlayers,i,j,k,m,endia; int PID[MAX_PLAYER]; int Score[MAX_PLAYER]; int regPl[MAX_PLAYER]; float q,plus[MAX_PLAYER],i1,j1; XBAtom pAtom[MAX_PLAYER]; CFGPlayerRating rating[MAX_PLAYER]; XBBool gamestat; char buffer[SIZE]; time_t curtime; struct tm *loctime; endia=0; memcpy(&numPlayers,line,4); Dbg_Out("Game statistics received from a %i player game\n",numPlayers); if(numPlayers > MAX_PLAYER) { i=endian(numPlayers); Dbg_Out("Possible endian problem num players = %i\n",i); if((i >= 0) && (i <= MAX_PLAYER)) { numPlayers=i; endia=1; } } if((numPlayers >= 0) && (numPlayers <= MAX_PLAYER)) { for(i=0;i0) { pAtom[i]=GUI_IntToAtom(PID[i]); if(RetrievePlayerRating (CT_Central, pAtom[i], rating+i)) { if((rating+i)->rating>0) { regPl[k]=i; k++; } } } } Dbg_Out("%i registred playes in game\n",k); m=0; gamestat=XBFalse; for(i=0;itimeUpdate=time(NULL); if(Score[j]<0) gamestat=XBTrue; m+=Score[j]; plus[j]=0.0; } if(gamestat) { m=0; cTotalGames++; cGamesPlayed++; sprintf(buffer,"game_%i",cTotalGames); StoreGameResult (CT_Central, GUI_StringToAtom(buffer), k, regPl, PID, Score); // XBST for(i=0;igamesPlayed++; if(Score[j]<0) { (rating+j)->realWins++; Score[j]=1; } else { Score[j]=0; } m+=Score[j]; } adminRating.gamesPlayed=cTotalGames; adminRating.timeUpdate=time (NULL); StorePlayerRating (CT_Central, adminAtom, &adminRating); } /* for(i=0;irating; for(j=i+1;jrating; if(Score[i0]== Score[j0]) { q=0.5; } else if(Score[i0]>Score[j0]) { q=1.0; (rating+i0)->relativeWins++; } else { q=0.0; (rating+j0)->relativeWins++; } b=1/(1+exp(RATING_WEIGTH*(j1-i1))); plus[i0]+=RATING_STEP*(q-b); plus[j0]-=RATING_STEP*(q-b); } }*/ if((m>0) && (k>1)) { q=0; j1=0; for(i=0;irating*GJFAC; plus[j]=-i1; j1+=i1; } j1*=GJFAC2; Dbg_Out("Game was worth %f points (%i bombs)\n",j1,m); for(i=0;irating; Dbg_Out("Rating for player %i = %f -> %f\n",PID[j],(rating+j)->rating,plus[j]); (rating+j)->rating=plus[j]; (rating+j)->relativeWins+=Score[j]; if(PID[j]>0) { StorePlayerRating (CT_Central, pAtom[j], rating+j); } } curtime = time (NULL); loctime = localtime (&curtime); strftime (buffer, SIZE, "%H_%d_%m_%Y", loctime); StoreTimePlayerRating (CT_Central, GUI_StringToAtom(buffer), k, regPl, PID, plus); // XBST } else { Dbg_Out("No bombs to divide\n"); } /* update administrator and save */ SavePlayerCentral(); } } /* Central_ReceiveGameConfig */ /* * player config received from client */ void Central_ReceivePlayerConfig (unsigned id, const char *line) { XBAtom atom,atomID; CFGPlayerEx tmpPlayer, idPlayer; int i; /* store player for config */ atom = Network_ReceivePlayerConfig (CT_Central, id, 0, line); /* if atom is valid, data is complete */ if (ATOM_INVALID != atom) { Dbg_Out("Player registration\n"); RetrievePlayerEx(CT_Central, atom, &tmpPlayer); i=tmpPlayer.id.PID; Dbg_Out("Player PID = %i\n",i); if(i>0) { // udpate atomID=GUI_IntToAtom(i); Dbg_Out("Got atom"); if(RetrievePlayerEx(CT_Central, atomID, &idPlayer)) { Dbg_Out("Got player"); if((tmpPlayer.id.pass!=NULL)&&(idPlayer.id.pass!=NULL)) { Dbg_Out("after null"); if(strcmp(tmpPlayer.id.pass,idPlayer.id.pass)==0) { /* copy rating stuff, do not delete big mistake */ tmpPlayer.rating.rating=idPlayer.rating.rating; tmpPlayer.rating.gamesPlayed=idPlayer.rating.gamesPlayed; tmpPlayer.rating.realWins=idPlayer.rating.realWins; tmpPlayer.rating.relativeWins=idPlayer.rating.relativeWins; tmpPlayer.rating.timeUpdate=idPlayer.rating.timeUpdate; tmpPlayer.rating.timeRegister=idPlayer.rating.timeRegister; StorePlayerEx(CT_Central, atomID, &tmpPlayer); i=tmpPlayer.id.PID; Dbg_Out("User updated\n"); } else { // bad password Dbg_Out("Bad password\n"); i=-1; } } else { Dbg_Out("Got atom"); if((tmpPlayer.id.pass==NULL)&&(idPlayer.id.pass==NULL)) { /* copy rating stuff, do not delete big mistake */ tmpPlayer.rating.rating=idPlayer.rating.rating; tmpPlayer.rating.gamesPlayed=idPlayer.rating.gamesPlayed; tmpPlayer.rating.realWins=idPlayer.rating.realWins; tmpPlayer.rating.relativeWins=idPlayer.rating.relativeWins; tmpPlayer.rating.timeUpdate=idPlayer.rating.timeUpdate; tmpPlayer.rating.timeRegister=idPlayer.rating.timeRegister; StorePlayerEx(CT_Central, atomID, &tmpPlayer); i=tmpPlayer.id.PID; Dbg_Out("User updated\n"); } else { // bad password Dbg_Out("Bad password\n"); i=-1; } } } else { // non existing Dbg_Out("Non existing PID\n"); i=-2; } } else { // new player Dbg_Out("New user\n"); i=GameRandomNumber(INT_MAX); atomID=GUI_IntToAtom(i); while(NULL != GetPlayerName(CT_Central, atomID)) { i=GameRandomNumber(INT_MAX); atomID=GUI_IntToAtom(i); } tmpPlayer.rating.rating=1000; tmpPlayer.rating.timeUpdate=0; tmpPlayer.rating.timeRegister=time(NULL); tmpPlayer.id.PID=i; StorePlayerEx(CT_Central, atomID, &tmpPlayer); cPlayers++; } /* Delete temp */ DeletePlayerConfig(CT_Central, atom); Dbg_Out("Send PID = %i\n",i); C2X_SendUserPID(id, i); SavePlayerCentral(); } } /* Central_ClientPlayerConfig */ /* * a client has connected */ void Central_ReceiveDisconnect (unsigned id) { /* create message */ Network_QueueEvent (XBNW_Disconnected, id); Dbg_Out ("User id=%u disconnected\n", id); } /* Central_ClientAccepted */ /* * received level finish from clients */ void Central_ReceiveFinish (unsigned id) { } /* Central_ReceiveFinish */ /* * end of file central.c */