- if(!DB->QExecute("DELETE FROM list_friend WHERE id=%i and idfriend=%i",thisclient->charid,id))
- {
- Log(MSG_INFO,"user failed to delete friend slot %i",thisclient->charname,id);
- return false;
- }
- if(!DB->QExecute("DELETE FROM list_friend WHERE id=%i and idfriend=%i",id,thisclient->charid))
- {
- Log(MSG_INFO,"user failed to delete friend slot %i",id,thisclient->charname);
- return false;
- }
So what's the bug ? Well as you all know, when you send a friend invitation, and the other player accept, there will be 2 rows created in the database. Now, there is the problem, the table list_friend as no primary keys. So what happens when you delete a friend from your friendlist ? Only 1 record is deleted. Then if you invite the same player again, there will be 2 records (rows) for him.
Pretty weird isn't it ? I discovered this when i wanted to make a limitation on the friendlist.
It count the number of friends the player already have, and if it's at the max, he can't add anymore friends (or receive invitations). But with those duplicated rows, he can have the max with only 25 real friends.
I'm not really good at sql, so i fixed this in 2 times. First we do like the code do, delete the row with ID = id of the player and friendid = id of the friend.
Then in the second time i delete the row with id = id of the friend and friendid = id of the player.
So that both rows are deleted.
I do it now like this : You can find those codes in CCharServer::pakMessengerManager in the community.cpp of the charserver
If someone knows how to do it in one single query, i would be grateful.
I also made the field id and friendid primary key. To prevent duplication of the rows.
Ok because it's a little chaotic with all the little parts, here is the code, and in color you will see what i added.
- // Messenger actions (add/remove/invite)
- bool CCharServer::pakMessengerManager ( CCharClient* thisclient, CPacket* P )
- {
- BYTE action = GETBYTE((*P),0);
- switch (action)
- {
- case 0x01://wanna be my friend?
- {
- char* nick = new (nothrow) char[P->Size-7];
- if(nick==NULL)
- {
- Log(MSG_ERROR, "Error allocing memory: pakMessengerManager 1" );
- return false;
- }
- int row;
- MYSQL_RES *result = NULL;
- result = DB->QStore("SELECT * FROM list_friend WHERE id=%i",thisclient->charid);
- row = mysql_num_rows(result);
- Log(MSG_INFO,"%s has %i friend(s)",thisclient->charname,row);
- memcpy( nick, &P->Buffer[1], P->Size-7 );
- Log(MSG_INFO,"%s Trying to invite %s",nick,thisclient->charname);
- CCharClient* otherclient = (CCharClient*) GetClientByName (nick);
- if(otherclient!=NULL)
- {//Send friend invitation (check this one)
- if(row==100){
- BEGINPACKET( pak, 0x0784 );
- ADDSTRING( pak, "Server" );
- ADDBYTE( pak, 0 );
- ADDSTRING( pak, "Your friendlist is full. Delete friends before adding new ones." );
- ADDBYTE( pak, 0 );
- thisclient->SendPacket(&pak);
- DB->QFree( );
- return false;
- }
- int row2;
- MYSQL_RES *result2 = NULL;
- result2 = DB->QStore("SELECT * FROM list_friend WHERE id=%i",otherclient->charid);
- row2 = mysql_num_rows(result2);
- Log(MSG_INFO,"%s has %i friend(s)",otherclient->charname,row2);
- if(row2==100)
- {
- BEGINPACKET( pak, 0x0784 );
- ADDSTRING( pak, "Server" );
- ADDBYTE( pak, 0 );
- ADDSTRING( pak, "Your friendlist is full. Delete friends before adding new ones." );
- ADDBYTE( pak, 0 );
- otherclient->SendPacket(&pak);
- RESETPACKET( pak, 0x0784 );
- ADDSTRING( pak, "Server" );
- ADDBYTE( pak, 0 );
- ADDSTRING( pak, "The list of your friend is full. Invitation canceled" );
- ADDBYTE( pak, 0 );
- thisclient->SendPacket(&pak);
- DB->QFree( );
- return false;
- }
- BEGINPACKET( pak, 0x7e1 );
- ADDBYTE ( pak, 0x01 );
- ADDWORD ( pak, 0x0000 );
- ADDSTRING ( pak, thisclient->charname );
- ADDBYTE ( pak, 0x00 );
- otherclient->SendPacket(&pak);
- Log(MSG_INFO,"%s exists, invite sent to %s",nick,otherclient->charname);
- }
- else
- {//This charname doesnt exist
- BEGINPACKET( pak, 0x7e1 );
- ADDBYTE ( pak, 0x04 );
- ADDSTRING ( pak, nick );
- ADDBYTE ( pak, 0x00 );
- thisclient->SendPacket(&pak);
- Log(MSG_INFO,"invite: %s doesn't exist",nick);
- }
- delete []nick;
- }
- break;
- case 0x02://yes i want
- {
- char* nick = new (nothrow) char[P->Size-9];
- if(nick==NULL)
- {
- Log(MSG_ERROR, "Error allocing memory: pakMessengerManager 2" );
- return false;
- }
- memcpy( nick, &P->Buffer[3], P->Size-9 );
- if(!CheckEscapeMySQL(nick,-1,true))
- {
- Log(MSG_WARNING,"A nick (friendlist) contains incorrect caracter (see warnings above)");
- return false;
- }
- CCharClient* otherclient = (CCharClient*) GetClientByName (nick);
- if(otherclient!=NULL)
- {
- BEGINPACKET( pak, 0x7e1 );
- ADDBYTE ( pak, 0x02 );
- /*ADDWORD ( pak, thisclient->charid );
- ADDBYTE ( pak, 0x00 );
- ADDWORD ( pak, 0x0000 );*/
- ADDDWORD ( pak, thisclient->charid );
- ADDBYTE ( pak, 0x00 );
- ADDSTRING ( pak, thisclient->charname );
- ADDBYTE ( pak, 0x00);
- otherclient->SendPacket(&pak);
- //Add friend to my friend list(sql)
- if(!DB->QExecute("INSERT INTO list_friend (id,idfriend,namefriend) VALUES (%i,%i,'%s')",otherclient->charid,thisclient->charid,thisclient->charname))
- {
- Log(MSG_WARNING,"error addind %s to %s friend list",otherclient->charname,thisclient->charname);
- return false;
- }
- CFriendList * newfriend1 = new (nothrow) CFriendList;
- if(newfriend1==NULL)
- return false;
- newfriend1->id = otherclient->charid; //friendid
- strcpy(newfriend1->name, otherclient->charname); //friend name
- thisclient->FriendList.push_back( newfriend1 );
- RESETPACKET( pak, 0x7e1 );
- ADDBYTE ( pak, 0x02 );
- /*ADDWORD ( pak, otherclient->charid );
- ADDBYTE ( pak, 0x00 );
- ADDWORD ( pak, 0x0000 );*/
- ADDDWORD ( pak, otherclient->charid );
- ADDBYTE ( pak, 0x00 );
- ADDSTRING ( pak, otherclient->charname );
- ADDBYTE ( pak, 0x00);
- thisclient->SendPacket(&pak);
- //Add me to his friend list (sql)
- if(!DB->QExecute("INSERT INTO list_friend (id,idfriend,namefriend) VALUES (%i,%i,'%s')",thisclient->charid,otherclient->charid,otherclient->charname))
- return false;
- CFriendList * newfriend2 = new (nothrow) CFriendList;
- if(newfriend2==NULL)
- return false;
- newfriend2->id = thisclient->charid; //friendid
- strcpy(newfriend2->name, thisclient->charname); //friend name
- otherclient->FriendList.push_back( newfriend2 );
- Log(MSG_INFO,"accept %s ok",nick);
- }
- else//not found
- {
- BEGINPACKET( pak, 0x7e1 );
- ADDBYTE ( pak, 0x04 );
- ADDSTRING ( pak, nick );
- ADDBYTE ( pak, 0x00 );
- thisclient->SendPacket(&pak);
- Log(MSG_INFO,"accept: %s doesn't exist",nick);
- }
- delete []nick;
- }
- break;
- case 0x03://no, i dont want
- {
- char* nick = new (nothrow) char[P->Size-9];
- if(nick==NULL)
- {
- Log(MSG_ERROR, "Error allocing memory: pakMessengerManager 3" );
- return false;
- }
- memcpy( nick, &P->Buffer[3], P->Size-9 );
- CCharClient* otherclient = (CCharClient*) GetClientByName (nick);
- if(otherclient!=NULL)
- {
- BEGINPACKET( pak, 0x7e1 );
- ADDBYTE ( pak, 0x03 );
- ADDSTRING ( pak, thisclient->charname );
- ADDBYTE ( pak, 0x00);
- otherclient->SendPacket(&pak);
- Log(MSG_INFO,"refuse: %s ok",nick);
- }
- else
- {
- BEGINPACKET( pak, 0x7e1 );
- ADDBYTE ( pak, 0x04 );
- ADDWORD ( pak, 0x0000 );
- ADDSTRING ( pak, nick );
- ADDBYTE ( pak, 0x00 );
- thisclient->SendPacket(&pak);
- Log(MSG_INFO,"refuse: %s doesn't exist",nick);
- }
- }
- break;
- case 0x05://delete user.
- {
- //WORD id = GETWORD ((*P),1);
- DWORD id = GETDWORD ((*P),1);
- if(!DB->QExecute("DELETE FROM list_friend WHERE id=%i and idfriend=%i",thisclient->charid,id))
- {
- Log(MSG_INFO,"user failed to delete friend slot %i",thisclient->charname,id);
- return false;
- }
- if(!DB->QExecute("DELETE FROM list_friend WHERE id=%i and idfriend=%i",id,thisclient->charid))
- {
- Log(MSG_INFO,"user failed to delete friend slot %i",id,thisclient->charname);
- return false;
- }
- Log(MSG_INFO,"user %s deletes friend slot %i",thisclient->charname,id);
- CCharClient* otherclient = (CCharClient*) GetClientByID(id);
- if(otherclient!=NULL)
- {
- ChangeMessengerStatus ( thisclient, otherclient, 0x08);
- }
- }
- break;
- case 0xfa://messenger logout
- [...]
I still need to do it the other way. Like a player send an invitation to an other player2 but the list of player2 is full, and so can't accept. But i didn't figure how to do it now.
EDIT: Code is not operational for now. So don't try to add this fix.
still a little problem. Charserver stops working right after deleting both rows.
EDIT 2: I putted the final code. But i still have some problems. It's not really working like it should. Some players can't send invitations. Did i something wrong somewhere ? Need little help :p