From fd665092bbcd4be32f9d8319ffbb4aad30b40d08 Mon Sep 17 00:00:00 2001 From: skotlex Date: Thu, 21 Feb 2008 00:13:56 +0000 Subject: - Fixed new guilds displaying online-connect member count at 0 rather than 1, and the guild master not knowing it is one (eg: it cannot edit the guild notice of a newly created guild until relogging). - Fixed acc_reg2 parsing screwing up the char_id and subtracting 2 from it rather than passing it as it is. - Extended the auth_node/auth_db system in chrif.c to handle log in/out and mapserver-change procedures. This way players are not in the main dbs when they are not "active", which blocks potential invalid accesses to them. - Replaced states auth, waiting_disconnect and finalsave with active. - Cleaned some the party/guild login and creation procedures, removed the party_sent/guild_sent states. - Removed a redundant guild_check_member call which is beyond not-needed and into the realm of wasting resources. - clif_parse will no longer process packets from !sd->state.active players, this also makes checking for finalsave uneccessary (since players re already removed from the maps and dbs by this point, so you can't access them in any other way) - Separated the roles of unit_free and map_quit, the former will handle cleaning structures from the player so it can be free'd safely, while the latter performs additional routines which are unique to characters logging out normally (map-server changes will invoke unit_free and bypass map_quit). - Removed pc_isplaying, quit_db, map_knowsaccount, MAPIT_PCISPLAYING among other functions/defines which are no longer needed due to the new login scheme. - Cleand up a bit some code in the clif_send(_sub) functions. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@12223 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/char/int_guild.c | 1 + src/char/inter.c | 2 +- src/char_sql/int_guild.c | 2 + src/char_sql/inter.c | 2 +- src/map/atcommand.c | 2 +- src/map/chrif.c | 317 +++++++++++++++++++++++++++++++---------------- src/map/chrif.h | 16 ++- src/map/clif.c | 183 ++++++++++++++------------- src/map/guild.c | 71 +++++++---- src/map/guild.h | 1 + src/map/intif.c | 31 ++--- src/map/mail.c | 2 +- src/map/map.c | 196 +++++++++-------------------- src/map/map.h | 12 +- src/map/party.c | 75 ++++++----- src/map/party.h | 1 + src/map/pc.c | 171 ++++++++----------------- src/map/pc.h | 5 +- src/map/status.c | 6 - src/map/storage.c | 9 -- src/map/trade.c | 3 - src/map/unit.c | 106 ++++++++-------- src/map/unit.h | 3 + 23 files changed, 592 insertions(+), 625 deletions(-) (limited to 'src') diff --git a/src/char/int_guild.c b/src/char/int_guild.c index 2e2933c14..ac15b9a0a 100644 --- a/src/char/int_guild.c +++ b/src/char/int_guild.c @@ -1004,6 +1004,7 @@ int mapif_parse_CreateGuild(int fd, int account_id, char *name, struct guild_mem // ここでギルド情報計算が必要と思われる g->max_member = 16; g->average_lv = master->lv; + g->connect_member = 1; for(i = 0; i < MAX_GUILDSKILL; i++) g->skill[i].id=i + GD_SKILLBASE; diff --git a/src/char/inter.c b/src/char/inter.c index 4e617c1e6..8472d36d1 100644 --- a/src/char/inter.c +++ b/src/char/inter.c @@ -611,7 +611,7 @@ int mapif_parse_RegistryRequest(int fd) mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6)); //Ask Login Server for Account2 values. if (RFIFOB(fd,10)) - request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6)-2); + request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6)); return 1; } diff --git a/src/char_sql/int_guild.c b/src/char_sql/int_guild.c index 5ffc96980..93b915886 100644 --- a/src/char_sql/int_guild.c +++ b/src/char_sql/int_guild.c @@ -1282,6 +1282,8 @@ int mapif_parse_CreateGuild(int fd,int account_id,char *name,struct guild_member // Initialize guild property g->max_member=16; g->average_lv=master->lv; + g->connect_member=1; + for(i=0;iskill[i].id=i + GD_SKILLBASE; g->guild_id= -1; //Request to create guild. diff --git a/src/char_sql/inter.c b/src/char_sql/inter.c index e6f955fbe..9cf89ae54 100644 --- a/src/char_sql/inter.c +++ b/src/char_sql/inter.c @@ -786,7 +786,7 @@ int mapif_parse_RegistryRequest(int fd) //Load Account Registry if (RFIFOB(fd,11)) mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),2); //Ask Login Server for Account2 values. - if (RFIFOB(fd,10)) request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6)-2); + if (RFIFOB(fd,10)) request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6)); return 1; } diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 8da0f1265..13bbb5ef0 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -3533,7 +3533,7 @@ int atcommand_doommap(const int fd, struct map_session_data* sd, const char* com *------------------------------------------*/ static void atcommand_raise_sub(struct map_session_data* sd) { - if (!sd->state.auth || !status_isdead(&sd->bl)) + if (!status_isdead(&sd->bl)) return; if(!status_revive(&sd->bl, 100, 100)) diff --git a/src/map/chrif.c b/src/map/chrif.c index e88ee3c5d..005285da5 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -8,6 +8,7 @@ #include "../common/nullpo.h" #include "../common/showmsg.h" #include "../common/strlib.h" +#include "../common/ers.h" #include "map.h" #include "battle.h" @@ -25,7 +26,8 @@ #include #include -DBMap* auth_db; // int id -> struct auth_node* +static struct eri *auth_db_ers; //For reutilizing player login structures. +static DBMap* auth_db; // int id -> struct auth_node* static const int packet_len_table[0x3d] = { // U - used, F - free 60, 3,-1,27,10,-1, 6,-1, // 2af8-2aff: U->2af8, U->2af9, U->2afa, U->2afb, U->2afc, U->2afd, U->2afe, U->2aff @@ -101,7 +103,77 @@ int other_mapserver_count=0; //Holds count of how many other map servers are onl //This define should spare writing the check in every function. [Skotlex] #define chrif_check(a) { if(!chrif_isconnected()) return a; } +struct auth_node* chrif_search(int account_id) { + return idb_get(auth_db, account_id); +} + +struct auth_node* chrif_auth_check(int account_id, int char_id, enum sd_state state) { + struct auth_node *node = chrif_search(account_id); + return (node && node->char_id == char_id && node->state == state)?node:NULL; +} + +bool chrif_auth_delete(int account_id, int char_id, enum sd_state state) { + struct auth_node *node; + if ((node=chrif_auth_check(account_id, char_id, state))) + { + if (node->fd && session[node->fd] && node->sd && + session[node->fd]->session_data == node->sd) + session[node->fd]->session_data = NULL; + if (node->char_dat) aFree(node->char_dat); + if (node->sd) aFree(node->sd); + ers_free(auth_db_ers, node); + idb_remove(auth_db,account_id); + return true; + } + return false; +} + +//Moves the sd character to the auth_db structure. +static bool chrif_sd_to_auth(TBL_PC* sd, enum sd_state state) +{ + struct auth_node *node; + if (chrif_search(sd->status.account_id)) + return false; //Already exists? + + node = ers_alloc(auth_db_ers, struct auth_node); + memset(node, 0, sizeof(struct auth_node)); + node->account_id = sd->status.account_id; + node->char_id = sd->status.char_id; + node->login_id1 = sd->login_id1; + node->login_id2 = sd->login_id2; + node->sex = sd->status.sex; + node->fd = sd->fd; + node->sd = sd; //Data from logged on char. + node->node_created = gettick(); //timestamp for node timeouts + node->state = state; + + sd->state.active = 0; + idb_put(auth_db, node->account_id, node); + return true; +} + +static bool chrif_auth_logout(TBL_PC* sd, enum sd_state state) +{ + if(sd->fd && state == ST_LOGOUT) + { //Disassociate player, and free it after saving ack returns. [Skotlex] + //fd info must not be lost for ST_MAPCHANGE as a final packet needs to be sent to the player. + if (session[sd->fd]) + session[sd->fd]->session_data = NULL; + sd->fd = 0; + } + return chrif_sd_to_auth(sd, state); +} +bool chrif_auth_finished(TBL_PC* sd) +{ + struct auth_node *node= chrif_search(sd->status.account_id); + if (node && node->sd == sd && node->state == ST_LOGIN) { + node->sd = NULL; + chrif_auth_delete(node->account_id, node->char_id, ST_LOGIN); + return true; + } + return false; +} // sets char-server's user id void chrif_setuserid(char *id) { @@ -165,15 +237,17 @@ int chrif_save(struct map_session_data *sd, int flag) if (!flag) //The flag check is needed to prevent 'nosave' taking effect when a jailed player logs out. pc_makesavestatus(sd); + + if (flag && sd->state.active) //Store player data which is quitting. + { + //FIXME: SC are lost if there's no connection at save-time because of the way its related data is cleared immediately after this function. [Skotlex] + if (chrif_isconnected()) chrif_save_scdata(sd); + chrif_auth_logout(sd, flag==1?ST_LOGOUT:ST_MAPCHANGE); + } if(!chrif_isconnected()) - { - if (flag) sd->state.finalsave = 1; //Will save character on reconnect. - return -1; - } + return -1; //Character is saved on reconnect. - if (sd->state.finalsave) - return -1; //Refuse to save a char already tagged for final saving. [Skotlex] //For data sync if (sd->state.storage_flag == 1) storage_storage_save(sd->status.account_id, flag); @@ -198,11 +272,13 @@ int chrif_save(struct map_session_data *sd, int flag) memcpy(WFIFOP(char_fd,13), &sd->status, sizeof(sd->status)); WFIFOSET(char_fd, WFIFOW(char_fd,2)); + + if(sd->status.pet_id > 0 && sd->pd) + intif_save_petdata(sd->status.account_id,&sd->pd->pet); + if (sd->hd && merc_is_hom_active(sd->hd)) merc_save(sd->hd); - if (flag) - sd->state.finalsave = 1; //Mark the last save as done. return 0; } @@ -271,40 +347,38 @@ int chrif_removemap(int fd) } // received after a character has been "final saved" on the char-server -int chrif_save_ack(int fd) +static void chrif_save_ack(int fd) { - map_quit_ack(RFIFOL(fd,2), RFIFOL(fd,6)); - return 0; + chrif_auth_delete(RFIFOL(fd,2), RFIFOL(fd,6), ST_LOGOUT); } // request to move a character between mapservers -int chrif_changemapserver(struct map_session_data* sd, short map, int x, int y, uint32 ip, uint16 port) +int chrif_changemapserver(struct map_session_data* sd, uint32 ip, uint16 port) { nullpo_retr(-1, sd); - chrif_check(-1); - if (other_mapserver_count < 1) { //No other map servers are online! clif_authfail_fd(sd->fd, 0); return -1; } + chrif_check(-1); + WFIFOHEAD(char_fd,35); WFIFOW(char_fd, 0) = 0x2b05; WFIFOL(char_fd, 2) = sd->bl.id; WFIFOL(char_fd, 6) = sd->login_id1; WFIFOL(char_fd,10) = sd->login_id2; WFIFOL(char_fd,14) = sd->status.char_id; - WFIFOW(char_fd,18) = map; - WFIFOW(char_fd,20) = x; - WFIFOW(char_fd,22) = y; + WFIFOW(char_fd,18) = sd->mapindex; + WFIFOW(char_fd,20) = sd->bl.x; + WFIFOW(char_fd,22) = sd->bl.y; WFIFOL(char_fd,24) = htonl(ip); WFIFOW(char_fd,28) = htons(port); WFIFOB(char_fd,30) = sd->status.sex; WFIFOL(char_fd,31) = 0; // sd's IP, not used anymore WFIFOSET(char_fd,35); - return 0; } @@ -312,23 +386,18 @@ int chrif_changemapserver(struct map_session_data* sd, short map, int x, int y, /// R 2b06 .L .L .L .L .W .W .W .L .W int chrif_changemapserverack(int account_id, int login_id1, int login_id2, int char_id, short map_index, short x, short y, uint32 ip, uint16 port) { - struct map_session_data *sd; - sd = map_id2sd(account_id); - - if (sd == NULL || sd->status.char_id != char_id) + struct auth_node *node; + if (!(node=chrif_auth_check(account_id, char_id, ST_MAPCHANGE))) return -1; - if (login_id1 == 1) { //FIXME: charserver says '0'! [ultramage] + if (!login_id1) { ShowError("map server change failed.\n"); - clif_authfail_fd(sd->fd, 0); - return 0; - } - - clif_changemapserver(sd, map_index, x, y, ntohl(ip), ntohs(port)); + clif_authfail_fd(node->fd, 0); + } else + clif_changemapserver(node->sd, map_index, x, y, ntohl(ip), ntohs(port)); - //Player has been saved already, remove him from memory. [Skotlex] - map_quit(sd); - map_quit_ack(sd->status.account_id, sd->status.char_id); + //Player has been saved already, remove him from memory. [Skotlex] + chrif_auth_delete(account_id, char_id, ST_MAPCHANGE); return 0; } @@ -359,6 +428,36 @@ int chrif_connectack(int fd) return 0; } +static int chrif_reconnect(DBKey key,void *data,va_list ap) +{ + struct auth_node *node=(struct auth_node*)data; + switch (node->state) { + case ST_LOGIN: + if (node->sd && node->char_dat == NULL) + { //Since there is no way to request the char auth, make it fail. + pc_authfail(node->sd); + chrif_char_offline(node->sd); + chrif_auth_delete(node->account_id, node->char_id, ST_LOGIN); + } + break; + case ST_LOGOUT: + //Re-send final save + chrif_save(node->sd, 1); + break; + case ST_MAPCHANGE: + { //Re-send map-change request. + struct map_session_data *sd = node->sd; + uint32 ip; + uint16 port; + if(map_mapname2ipport(sd->mapindex,&ip,&port)==0) + chrif_changemapserver(sd, ip, port); + else //too much lag/timeout is the closest explanation for this error. + clif_authfail_fd(sd->fd, 3); + break; + } + } + return 0; +} /*========================================== * @@ -378,7 +477,7 @@ int chrif_sendmapack(int fd) send_users_tochar(); //Re-save any storages that were modified in the disconnection time. [Skotlex] - do_reconnect_map(); + auth_db->foreach(auth_db,chrif_reconnect); do_reconnect_storage(); return 0; @@ -406,30 +505,31 @@ int chrif_scdata_request(int account_id, int char_id) *------------------------------------------*/ void chrif_authreq(struct map_session_data *sd) { - struct auth_node *auth_data; - auth_data=idb_get(auth_db, sd->bl.id); - - if(auth_data) { - if(auth_data->char_dat && - auth_data->account_id== sd->bl.id && - auth_data->login_id1 == sd->login_id1) - { //auth ok - pc_authok(sd, auth_data->login_id2, auth_data->connect_until_time, auth_data->char_dat); - } else { //auth failed - pc_authfail(sd); - chrif_char_offline(sd); //Set him offline, the char server likely has it set as online already. + struct auth_node *node= chrif_search(sd->bl.id); + + if(!node) { + //data from char server has not arrived yet. + chrif_sd_to_auth(sd, ST_LOGIN); + return; + } + + if(node->state == ST_LOGIN && + node->char_dat && + node->account_id== sd->status.account_id && + node->login_id1 == sd->login_id1) + { //auth ok + if (!pc_authok(sd, node->login_id2, node->connect_until_time, node->char_dat)) + chrif_auth_delete(sd->status.account_id, sd->status.char_id, ST_LOGIN); + else { + //char_dat no longer needed, but player auth is not completed yet. + aFree(node->char_dat); + node->char_dat = NULL; + node->sd = sd; } - if (auth_data->char_dat) - aFree(auth_data->char_dat); - idb_remove(auth_db, sd->bl.id); - } else { //data from char server has not arrived yet. - auth_data = aCalloc(1,sizeof(struct auth_node)); - auth_data->sd = sd; - auth_data->fd = sd->fd; - auth_data->account_id = sd->bl.id; - auth_data->login_id1 = sd->login_id1; - auth_data->node_created = gettick(); - idb_put(auth_db, sd->bl.id, auth_data); + } else { //auth failed + pc_authfail(sd); + chrif_char_offline(sd); //Set him offline, the char server likely has it set as online already. + chrif_auth_delete(sd->status.account_id, sd->status.char_id, ST_LOGIN); } return; } @@ -437,65 +537,69 @@ void chrif_authreq(struct map_session_data *sd) //character selected, insert into auth db void chrif_authok(int fd) { - struct auth_node *auth_data; + struct auth_node *node; + int account_id = RFIFOL(fd, 4); + struct mmo_charstatus *status = (struct mmo_charstatus *)RFIFOP(fd, 20); + int char_id = status->char_id; TBL_PC* sd; //Check if we don't already have player data in our server - //(prevents data that is to be saved from being overwritten by - //this received status data if this auth is later successful) [Skotlex] - if ((sd = map_id2sd(RFIFOL(fd, 4))) != NULL) - { - struct mmo_charstatus *status = (struct mmo_charstatus *)RFIFOP(fd, 20); - //Auth check is because this could be the very same sd that is waiting char-server authorization. - if (sd->state.auth && sd->status.char_id == status->char_id) - return; - } + //Causes problems if the currently connected player tries to quit or this data belongs to an already connected player which is trying to re-auth. + if ((sd = map_id2sd(account_id)) != NULL) + return; - if ((auth_data =idb_get(auth_db, RFIFOL(fd, 4))) != NULL) + if ((node = chrif_search(account_id))) { //Is the character already awaiting authorization? - if (auth_data->sd) + if (node->state == ST_LOGIN && node->sd) { - //First, check to see if the session data still exists (avoid dangling pointers) - if(session[auth_data->fd] && session[auth_data->fd]->session_data == auth_data->sd) - { - if (auth_data->char_dat == NULL && - auth_data->account_id == RFIFOL(fd, 4) && - auth_data->login_id1 == RFIFOL(fd, 8)) - { //Auth Ok - pc_authok(auth_data->sd, RFIFOL(fd, 16), RFIFOL(fd, 12), (struct mmo_charstatus*)RFIFOP(fd, 20)); - } else { //Auth Failed - pc_authfail(auth_data->sd); - chrif_char_offline(auth_data->sd); //Set him offline, the char server likely has it set as online already. - } - } //else: Character no longer exists, just go through. + sd = node->sd; + if(node->char_dat == NULL && + node->account_id == account_id && + node->char_id == char_id && + node->login_id1 == RFIFOL(fd, 8)) + { //Auth Ok + if (!pc_authok(sd, RFIFOL(fd, 16), RFIFOL(fd, 12), status)) + chrif_auth_delete(account_id, char_id, ST_LOGIN); + } else { //Auth Failed + pc_authfail(sd); + chrif_char_offline(sd); //Set him offline, the char server likely has it set as online already. + chrif_auth_delete(account_id, char_id, ST_LOGIN); + } } - //Delete the data of this node... - if (auth_data->char_dat) - aFree (auth_data->char_dat); - idb_remove(auth_db, RFIFOL(fd, 4)); + //Otherwise discard the entry received as we already have information. return; } - // Awaiting for client to connect. - auth_data = (struct auth_node *)aCalloc(1,sizeof(struct auth_node)); - auth_data->char_dat = (struct mmo_charstatus *) aMalloc(sizeof(struct mmo_charstatus)); - auth_data->account_id=RFIFOL(fd, 4); - auth_data->login_id1=RFIFOL(fd, 8); - auth_data->connect_until_time=RFIFOL(fd, 12); - auth_data->login_id2=RFIFOL(fd, 16); - memcpy(auth_data->char_dat,RFIFOP(fd, 20),sizeof(struct mmo_charstatus)); - auth_data->node_created=gettick(); - idb_put(auth_db, RFIFOL(fd, 4), auth_data); + // Awaiting for client to connect. + node = ers_alloc(auth_db_ers, struct auth_node); + memset(node, 0, sizeof(struct auth_node)); + node->char_dat = (struct mmo_charstatus *) aMalloc(sizeof(struct mmo_charstatus)); + + node->account_id=account_id; + node->char_id=char_id; + node->login_id1=RFIFOL(fd, 8); + node->connect_until_time=RFIFOL(fd, 12); + node->login_id2=RFIFOL(fd, 16); + memcpy(node->char_dat,status,sizeof(struct mmo_charstatus)); + node->node_created=gettick(); + idb_put(auth_db, account_id, node); } int auth_db_cleanup_sub(DBKey key,void *data,va_list ap) { struct auth_node *node=(struct auth_node*)data; - if(DIFF_TICK(gettick(),node->node_created)>30000) { - ShowNotice("Character (aid: %d) not authed within 30 seconds of character select!\n", node->account_id); - if (node->char_dat) - aFree(node->char_dat); - db_remove(auth_db, key); + if(DIFF_TICK(gettick(),node->node_created)>60000) { + switch (node->state) + { + case ST_LOGOUT: + //Re-save attempt (->sd should never be null here). + chrif_save(node->sd, 1); + break; + default: + //Clear data. any connected players should have timed out by now. + chrif_auth_delete(node->account_id, node->char_id, node->state); + break; + } return 1; } return 0; @@ -503,11 +607,11 @@ int auth_db_cleanup_sub(DBKey key,void *data,va_list ap) int auth_db_cleanup(int tid, unsigned int tick, int id, int data) { + if(!chrif_isconnected()) return 0; auth_db->foreach(auth_db, auth_db_cleanup_sub); return 0; } - /*========================================== * *------------------------------------------*/ @@ -1010,9 +1114,6 @@ int chrif_save_scdata(struct map_session_data *sd) struct status_change *sc = &sd->sc; const struct TimerData *timer; - if (sd->state.finalsave) //Character was already saved? - return -1; - chrif_check(-1); tick = gettick(); @@ -1428,6 +1529,9 @@ int auth_db_final(DBKey k,void *d,va_list ap) struct auth_node *node=(struct auth_node*)d; if (node->char_dat) aFree(node->char_dat); + if (node->sd) + aFree(node->sd); + ers_free(auth_db_ers, node); return 0; } @@ -1438,7 +1542,9 @@ int do_final_chrif(void) { if (char_fd > 0) do_close(char_fd); + auth_db->destroy(auth_db, auth_db_final); + ers_destroy(auth_db_ers); return 0; } @@ -1447,7 +1553,8 @@ int do_final_chrif(void) *------------------------------------------*/ int do_init_chrif(void) { - auth_db = idb_alloc(DB_OPT_RELEASE_DATA); + auth_db = idb_alloc(DB_OPT_BASE); + auth_db_ers = ers_new(sizeof(struct auth_node)); add_timer_func_list(check_connect_char_server, "check_connect_char_server"); add_timer_func_list(ping_char_server, "ping_char_server"); diff --git a/src/map/chrif.h b/src/map/chrif.h index b440fcac6..bf1dbb108 100644 --- a/src/map/chrif.h +++ b/src/map/chrif.h @@ -7,12 +7,15 @@ #include "../common/cbasetypes.h" #include -struct auth_node{ - int account_id, login_id1, login_id2, sex, fd; +enum sd_state { ST_LOGIN, ST_LOGOUT, ST_MAPCHANGE }; +struct auth_node { + int account_id, char_id; + int login_id1, login_id2, sex, fd; time_t connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) struct map_session_data *sd; //Data from logged on char. struct mmo_charstatus *char_dat; //Data from char server. - unsigned int node_created; //For node auto-deleting + unsigned int node_created; //timestamp for node timeouts + enum sd_state state; //To track whether player was login in/out or changing maps. }; void chrif_setuserid(char* id); @@ -26,12 +29,17 @@ int chrif_isconnected(void); extern int chrif_connected; extern int other_mapserver_count; +struct auth_node* chrif_search(int account_id); +struct auth_node* chrif_auth_check(int account_id, int char_id, enum sd_state state); +bool chrif_auth_delete(int account_id, int char_id, enum sd_state state); +bool chrif_auth_finished(struct map_session_data* sd); + void chrif_authreq(struct map_session_data* sd); void chrif_authok(int fd); int chrif_scdata_request(int account_id, int char_id); int chrif_save(struct map_session_data* sd, int flag); int chrif_charselectreq(struct map_session_data* sd, uint32 s_ip); -int chrif_changemapserver(struct map_session_data* sd, short map, int x, int y, uint32 ip, uint16 port); +int chrif_changemapserver(struct map_session_data* sd, uint32 ip, uint16 port); int chrif_searchcharid(int char_id); int chrif_changegm(int id,const char *pass,int len); diff --git a/src/map/clif.c b/src/map/clif.c index ed5e46bbd..5d6daaa26 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -175,7 +175,7 @@ int clif_countusers(void) for(i = 0; i < fd_max; i++) { if (session[i] && session[i]->func_parse == clif_parse && (sd = (struct map_session_data*)session[i]->session_data) && - sd->state.auth && !(battle_config.hide_GM_session && pc_isGM(sd))) + sd->state.active && !(battle_config.hide_GM_session && pc_isGM(sd))) users++; } return users; @@ -195,7 +195,7 @@ int clif_foreachclient(int (*func)(struct map_session_data*, va_list),...) //rec for(i = 0; i < fd_max; i++) { if ( session[i] && session[i]->func_parse == clif_parse) { sd = (struct map_session_data*)session[i]->session_data; - if ( sd && sd->state.auth && !sd->state.waitingdisconnect ) + if ( sd && sd->state.active ) func(sd, ap); } } @@ -246,20 +246,23 @@ int clif_send_sub(struct block_list *bl, va_list ap) break; } - if (session[fd] != NULL) { - WFIFOHEAD(fd, len); - if (WFIFOP(fd,0) == buf) { - ShowError("WARNING: Invalid use of clif_send function\n"); - ShowError(" Packet x%4x use a WFIFO of a player instead of to use a buffer.\n", WBUFW(buf,0)); - ShowError(" Please correct your code.\n"); - // don't send to not move the pointer of the packet for next sessions in the loop - WFIFOSET(fd,0);//## TODO is this ok? - } else { - if (packet_db[sd->packet_ver][RBUFW(buf,0)].len) { // packet must exist for the client version - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - } - } + if (session[fd] == NULL) + return 0; + + WFIFOHEAD(fd, len); + if (WFIFOP(fd,0) == buf) { + ShowError("WARNING: Invalid use of clif_send function\n"); + ShowError(" Packet x%4x use a WFIFO of a player instead of to use a buffer.\n", WBUFW(buf,0)); + ShowError(" Please correct your code.\n"); + // don't send to not move the pointer of the packet for next sessions in the loop + //WFIFOSET(fd,0);//## TODO is this ok? + //NO. It is not ok. There is the chance WFIFOSET actually sends the buffer data, and shifts elements around, which will corrupt the buffer. + return 0; + } + + if (packet_db[sd->packet_ver][RBUFW(buf,0)].len) { // packet must exist for the client version + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); } return 0; @@ -285,13 +288,13 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target case ALL_CLIENT: //All player clients. for (i = 0; i < fd_max; i++) { if (session[i] && session[i]->func_parse == clif_parse && - (sd = (struct map_session_data *)session[i]->session_data) != NULL&& - sd->state.auth) { - if (packet_db[sd->packet_ver][RBUFW(buf,0)].len) { // packet must exist for the client version - WFIFOHEAD(i, len); - memcpy(WFIFOP(i,0), buf, len); - WFIFOSET(i,len); - } + (sd = (struct map_session_data *)session[i]->session_data) != NULL && + sd->state.active && + packet_db[sd->packet_ver][RBUFW(buf,0)].len) + { // packet must exist for the client version + WFIFOHEAD(i, len); + memcpy(WFIFOP(i,0), buf, len); + WFIFOSET(i,len); } } break; @@ -299,12 +302,12 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target for(i = 0; i < fd_max; i++) { if (session[i] && session[i]->func_parse == clif_parse && (sd = (struct map_session_data*)session[i]->session_data) != NULL && - sd->state.auth && sd->bl.m == bl->m) { - if (packet_db[sd->packet_ver][RBUFW(buf,0)].len) { // packet must exist for the client version - WFIFOHEAD(i,len); - memcpy(WFIFOP(i,0), buf, len); - WFIFOSET(i,len); - } + sd->state.active && sd->bl.m == bl->m && + packet_db[sd->packet_ver][RBUFW(buf,0)].len) + { // packet must exist for the client version + WFIFOHEAD(i,len); + memcpy(WFIFOP(i,0), buf, len); + WFIFOSET(i,len); } } break; @@ -350,11 +353,11 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target for(i=1; ifunc_parse == clif_parse && (sd = (struct map_session_data*)session[i]->session_data) != NULL && - sd->state.mainchat && !sd->chatID && (fd=sd->fd)) + sd->state.active && sd->state.mainchat && !sd->chatID) { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd, len); + WFIFOHEAD(i,len); + memcpy(WFIFOP(i,0), buf, len); + WFIFOSET(i, len); } } break; @@ -376,12 +379,9 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target if( (sd = p->data[i].sd) == NULL ) continue; - if( !(fd=sd->fd) || fd <= 0 || fd >= fd_max ) + if( !(fd=sd->fd) ) continue; - if( session[fd] == NULL || sd->state.auth == 0 || session[fd]->session_data == NULL || sd->packet_ver > MAX_PACKET_VER ) - continue; - if( sd->bl.id == bl->id && (type == PARTY_WOS || type == PARTY_SAMEMAP_WOS || type == PARTY_AREA_WOS) ) continue; @@ -404,13 +404,12 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target if (session[i] && session[i]->func_parse == clif_parse && (sd = (struct map_session_data*)session[i]->session_data) != NULL && - sd->state.auth && (fd=sd->fd) && sd->partyspy == p->party.party_id) - { - if (packet_db[sd->packet_ver][RBUFW(buf,0)].len) { // packet must exist for the client version - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - } + sd->state.active && sd->partyspy == p->party.party_id && + packet_db[sd->packet_ver][RBUFW(buf,0)].len) + { // packet must exist for the client version + WFIFOHEAD(i,len); + memcpy(WFIFOP(i,0), buf, len); + WFIFOSET(i,len); } } } @@ -423,7 +422,7 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target for (i = 0; i < fd_max; i++) { if (session[i] && session[i]->func_parse == clif_parse && (sd = (struct map_session_data *)session[i]->session_data) != NULL && - sd->state.auth && sd->duel_group == x0) { + sd->state.active && sd->duel_group == x0) { if (type == DUEL_WOS && bl->id == sd->bl.id) continue; if (packet_db[sd->packet_ver][RBUFW(buf,0)].len) { @@ -460,10 +459,7 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target for(i = 0; i < g->max_member; i++) { if( (sd = g->member[i].sd) != NULL ) { - if( !(fd=sd->fd) || fd <= 0 || fd >= fd_max ) - continue; - - if( session[fd] == NULL || sd->state.auth == 0 || session[fd]->session_data == NULL || sd->packet_ver > MAX_PACKET_VER ) + if( !(fd=sd->fd) ) continue; if( sd->bl.id == bl->id && (type == GUILD_WOS || type == GUILD_SAMEMAP_WOS || type == GUILD_AREA_WOS) ) @@ -488,12 +484,12 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target for (i = 1; i < fd_max; i++){ // guildspy [Syrus22] if (session[i] && session[i]->func_parse == clif_parse && (sd = (struct map_session_data*)session[i]->session_data) != NULL && - sd->state.auth && (fd=sd->fd) && sd->guildspy == g->guild_id) { - if (packet_db[sd->packet_ver][RBUFW(buf,0)].len) { // packet must exist for the client version - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - } + sd->state.active && sd->guildspy == g->guild_id && + packet_db[sd->packet_ver][RBUFW(buf,0)].len) + { // packet must exist for the client version + WFIFOHEAD(fd,len); + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); } } } @@ -541,6 +537,7 @@ int clif_authok(struct map_session_data *sd) * 3 - timeout/too much lag -> MsgStringTable[241] * 4 - server full -> MsgStringTable[264] * 5 - underaged -> MsgStringTable[305] + * 8 - Server sill recognizes last connection -> MsgStringTable[441] * 9 - too many connections from this ip -> MsgStringTable[529] * 10 - out of available time paid for -> MsgStringTable[530] * 15 - disconnected by a GM -> if( servicetype == taiwan ) MsgStringTable[579] @@ -1038,7 +1035,7 @@ int clif_weather(int m) for(i = 0; i < fd_max; i++) { if (session[i] && session[i]->func_parse == clif_parse && (sd = session[i]->session_data) != NULL && - sd->state.auth && sd->bl.m == m) { + sd->state.active && sd->bl.m == m) { clif_weather_check(sd); } } @@ -1327,8 +1324,7 @@ static int clif_delayquit(int tid, unsigned int tick, int id, int data) *------------------------------------------*/ void clif_quitsave(int fd,struct map_session_data *sd) { - if (sd->state.waitingdisconnect || //Was already waiting to be disconnected. - !battle_config.prevent_logout || + if (!battle_config.prevent_logout || DIFF_TICK(gettick(), sd->canlog_tick) > battle_config.prevent_logout) map_quit(sd); else if (sd->fd) @@ -1356,10 +1352,9 @@ static int clif_waitclose(int tid, unsigned int tick, int id, int data) *------------------------------------------*/ void clif_setwaitclose(int fd) { - struct map_session_data *sd; // if player is not already in the game (double connection probably) - if ((sd = (struct map_session_data*)session[fd]->session_data) == NULL) { + if (session[fd]->session_data == NULL) { // limited timer, just to send information. add_timer(gettick() + 1000, clif_waitclose, fd, 0); } else @@ -3775,7 +3770,7 @@ void clif_01ac(struct block_list* bl) sd=va_arg(ap,struct map_session_data*); - if (sd == NULL || !sd->fd || session[sd->fd] == NULL) + if (sd == NULL || !sd->fd) return 0; switch(bl->type){ @@ -5614,7 +5609,7 @@ int clif_hpmeter(struct map_session_data *sd) for (i = 0; i < fd_max; i++) { if (session[i] && session[i]->func_parse == clif_parse && (sd2 = (struct map_session_data*)session[i]->session_data) && - sd != sd2 && sd2->state.auth) { + sd != sd2 && sd2->state.active) { if (sd2->bl.m != sd->bl.m || sd2->bl.x < x0 || sd2->bl.y < y0 || sd2->bl.x > x1 || sd2->bl.y > y1 || @@ -7616,12 +7611,14 @@ static int clif_guess_PacketVer(int fd, int get_previous, int *error) *------------------------------------------*/ void clif_parse_WantToConnection(int fd, TBL_PC* sd) { + struct block_list* bl; + struct auth_node* node; int cmd, account_id, char_id, login_id1, sex; unsigned int client_tick; //The client tick is a tick, therefore it needs be unsigned. [Skotlex] int packet_ver; // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 (by [Yor]) if (sd) { - ShowError("clif_parse_WantToConnection : invalid request (character already logged in)?\n"); + ShowError("clif_parse_WantToConnection : invalid request (character already logged in)\n"); return; } @@ -7646,13 +7643,12 @@ void clif_parse_WantToConnection(int fd, TBL_PC* sd) WFIFOSET(fd,packet_len(0x6a)); clif_setwaitclose(fd); return; - } else if( map_knowsaccount(account_id) ) - {// double login - sd = map_id2sd(account_id); - if( sd && sd->state.autotrade ) - map_quit(sd);// kick autotrading character - else - ShowError("clif_parse_WantToConnection: double login attempt AID/CID: %d/%d, rejecting...\n", account_id, char_id); + } + + //Check for double login. + bl = map_id2bl(account_id); + if(bl && bl->type != BL_PC) { + ShowError("clif_parse_WantToConnection: a non-player object already has id %d, please increase the starting account number\n", account_id); WFIFOHEAD(fd,packet_len(0x6a)); WFIFOW(fd,0) = 0x6a; WFIFOB(fd,2) = 3; // Rejected by server @@ -7660,19 +7656,22 @@ void clif_parse_WantToConnection(int fd, TBL_PC* sd) clif_setwaitclose(fd); return; } - else - {// packet version accepted - struct block_list* bl; - if( (bl=map_id2bl(account_id)) != NULL && bl->type != BL_PC ) - {// non-player object already has that id - ShowError("clif_parse_WantToConnection: a non-player object already has id %d, please increase the starting account number\n", account_id); - WFIFOHEAD(fd,packet_len(0x6a)); - WFIFOW(fd,0) = 0x6a; - WFIFOB(fd,2) = 3; // Rejected by server - WFIFOSET(fd,packet_len(0x6a)); - clif_setwaitclose(fd); - return; - } + + if (bl || + ((node=chrif_search(account_id)) && //An already existing node is valid only if it is for this login. + !(node->account_id == account_id && node->char_id == char_id && node->state == ST_LOGIN))) { + sd = BL_CAST(BL_PC, bl); + if (!sd) + ; //We have another char with the same account logging in/out. + else //Already connected player. + if (sd->fd) + clif_authfail_fd(sd->fd, 2); //someone else logged in + else + if(sd->state.autotrade) + map_quit(sd);// kick autotrading character + //Else do not kick character, it could be on its 10 sec penalty for Alt+F4 + clif_authfail_fd(fd, 8); //Still recognizes last connection + return; } CREATE(sd, TBL_PC, 1); @@ -7706,7 +7705,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) if(sd->bl.prev != NULL) return; - if (!sd->state.auth) + if (!sd->state.active) { //Character loading is not complete yet! //Let pc_reg_received reinvoke this when ready. sd->state.connect_new = 0; @@ -11652,12 +11651,13 @@ int clif_parse(int fd) sd->fd = 0; ShowInfo("%sCharacter '"CL_WHITE"%s"CL_RESET"' logged off (using @autotrade).\n", (pc_isGM(sd))?"GM ":"", sd->status.name); } else - if (sd->state.auth) { + if (sd->state.active) { // Player logout display [Valaris] ShowInfo("%sCharacter '"CL_WHITE"%s"CL_RESET"' logged off.\n", (pc_isGM(sd))?"GM ":"", sd->status.name); clif_quitsave(fd, sd); } else { - ShowInfo("Player AID:%d/CID:%d (not authenticated) logged off.\n", sd->bl.id, sd->status.char_id); + //Unusual logout (during log on/off/map-changer procedure) + ShowInfo("Player AID:%d/CID:%d logged off.\n", sd->status.account_id, sd->status.char_id); map_quit(sd); } } else { @@ -11723,17 +11723,14 @@ int clif_parse(int fd) if ((int)RFIFOREST(fd) < packet_len) return 0; // not enough data received to form the packet - if (sd && sd->state.waitingdisconnect == 1) { - // 切断待ちの場合パケットを処理しない - } else if (packet_db[packet_ver][cmd].func) { if (sd && sd->bl.prev == NULL && packet_db[packet_ver][cmd].func != clif_parse_LoadEndAck) ; //Only valid packet when player is not on a map is the finish-loading packet. else - if (sd + if ((sd && sd->state.active) || packet_db[packet_ver][cmd].func == clif_parse_WantToConnection || packet_db[packet_ver][cmd].func == clif_parse_debug - ) //Only execute the function when there's an sd (except for debug/wanttoconnect packets) + ) //Only execute the function when there's an active sd (except for debug/wanttoconnect packets) packet_db[packet_ver][cmd].func(fd, sd); } #if DUMP_UNKNOWN_PACKET @@ -11750,7 +11747,7 @@ int clif_parse(int fd) return 1; } else { time(&now); - if (sd && sd->state.auth) { + if (sd && sd->state.active) { fprintf(fp, "%sPlayer with account ID %d (character ID %d, player name %s) sent wrong packet:\n", asctime(localtime(&now)), sd->status.account_id, sd->status.char_id, sd->status.name); } else if (sd) // not authentified! (refused by char-server or disconnect before to be authentified) @@ -11779,7 +11776,7 @@ int clif_parse(int fd) ShowMessage("%02X ", RFIFOB(fd,i)); } ShowMessage("\n"); - if (sd && sd->state.auth) { + if (sd && sd->state.active) { if (sd->status.name != NULL) ShowMessage("\nAccount ID %d, character ID %d, player name %s.\n", sd->status.account_id, sd->status.char_id, sd->status.name); diff --git a/src/map/guild.c b/src/map/guild.c index e591fc838..5644793b2 100644 --- a/src/map/guild.c +++ b/src/map/guild.c @@ -76,7 +76,7 @@ static TBL_PC* guild_sd_check(int guild_id, int account_id, int char_id) { TBL_PC* sd = map_id2sd(account_id); - if (!(sd && sd->status.char_id == char_id && sd->state.auth && !sd->state.waitingdisconnect)) + if (!(sd && sd->status.char_id == char_id)) return NULL; if (sd->status.guild_id != guild_id) @@ -431,7 +431,6 @@ int guild_created(int account_id,int guild_id) } //struct guild *g; sd->status.guild_id=guild_id; - sd->state.guild_sent=0; clif_guild_created(sd,0); if(battle_config.guild_emperium_check) pc_delitem(sd,pc_search_inventory(sd,714),1,0); // エンペリウム消耗 @@ -485,7 +484,6 @@ int guild_check_member(struct guild *g) i = guild_getindex(g,sd->status.account_id,sd->status.char_id); if (i < 0) { sd->status.guild_id=0; - sd->state.guild_sent=0; sd->guild_emblem_id=0; ShowWarning("guild: check_member %d[%s] is not member\n",sd->status.account_id,sd->status.name); } @@ -519,10 +517,12 @@ int guild_recv_info(struct guild *sg) int i,bm,m; struct eventlist *ev,*ev2; struct map_session_data *sd; + bool guild_new = false; nullpo_retr(0, sg); if((g=idb_get(guild_db,sg->guild_id))==NULL){ + guild_new = true; g=(struct guild *)aCalloc(1,sizeof(struct guild)); idb_put(guild_db,sg->guild_id,g); before=*sg; @@ -538,7 +538,8 @@ int guild_recv_info(struct guild *sg) //Also set the guild master flag. sd->state.gmaster_flag = g; - clif_charnameupdate(sd); // [LuzZza] + clif_charnameupdate(sd); // [LuzZza] + clif_guild_masterormember(sd); } }else before=*g; @@ -579,11 +580,10 @@ int guild_recv_info(struct guild *sg) if( before.skill_point!=g->skill_point) clif_guild_skillinfo(sd); // スキル情報送信 - if( sd->state.guild_sent==0){ // 未送信なら所属情報も送る + if( guild_new ){ // 未送信なら所属情報も送る clif_guild_belonginfo(sd,g); clif_guild_notice(sd,g); sd->guild_emblem_id=g->emblem_id; - sd->state.guild_sent=1; } } @@ -702,6 +702,34 @@ int guild_reply_invite(struct map_session_data* sd, int guild_id, int flag) return 0; } + +//Invoked when a player joins. +//- If guild is not in memory, it is requested +//- Otherwise sd pointer is set up. +//- Player must be authed and must belong to a guild before invoking this method +void guild_member_joined(struct map_session_data *sd) +{ + struct guild* g; + int i; + g=guild_search(sd->status.guild_id); + if (!g) { + guild_request_info(sd->status.guild_id); + return; + } + if (strcmp(sd->status.name,g->master) == 0) + { // set the Guild Master flag + sd->state.gmaster_flag = g; + // prevent Guild Skills from being used directly after relog + if( battle_config.guild_skill_relog_delay ) + guild_block_skill(sd, 300000); + } + i = guild_getindex(g, sd->status.account_id, sd->status.char_id); + if (i == -1) + sd->status.guild_id = 0; + else + g->member[i].sd = sd; +} + // ギルドメンバが追加された int guild_member_added(int guild_id,int account_id,int char_id,int flag) { @@ -730,9 +758,12 @@ int guild_member_added(int guild_id,int account_id,int char_id,int flag) } // 成功 - sd->state.guild_sent = 0; sd->status.guild_id = g->guild_id; sd->guild_emblem_id = g->emblem_id; + //Packets which were sent in the previous 'guild_sent' implementation. + clif_guild_belonginfo(sd,g); + clif_guild_notice(sd,g); + //TODO: send new emblem info to others if( sd2!=NULL ) @@ -836,7 +867,6 @@ int guild_member_leaved(int guild_id, int account_id, int char_id, int flag, con sd->status.guild_id = 0; sd->guild_emblem_id = 0; - sd->state.guild_sent = 0; clif_charnameupdate(sd); //Update display name [Skotlex] //TODO: send emblem update to self and people around @@ -850,14 +880,10 @@ int guild_send_memberinfoshort(struct map_session_data *sd,int online) nullpo_retr(0, sd); - if(!(g = guild_search(sd->status.guild_id))) + if(sd->status.guild_id <= 0) return 0; - //Moved to place before intif_guild_memberinfoshort because - //If it's not a member, needn't send it's info to intif. [LuzZza] - guild_check_member(g); - - if(sd->status.guild_id <= 0) + if(!(g = guild_search(sd->status.guild_id))) return 0; intif_guild_memberinfoshort(g->guild_id, @@ -872,15 +898,12 @@ int guild_send_memberinfoshort(struct map_session_data *sd,int online) return 0; } - if(sd->state.guild_sent) - return 0; - - clif_guild_belonginfo(sd,g); - clif_guild_notice(sd,g); - - sd->state.guild_sent = 1; - sd->guild_emblem_id = g->emblem_id; - + if(sd->state.connect_new) + { //Note that this works because it is invoked in parse_LoadEndAck before connect_new is cleared. + clif_guild_belonginfo(sd,g); + clif_guild_notice(sd,g); + sd->guild_emblem_id = g->emblem_id; + } return 0; } @@ -915,7 +938,6 @@ int guild_recv_memberinfoshort(int guild_id,int account_id,int char_id,int onlin if(sd && sd->status.char_id == char_id) { sd->status.guild_id=0; sd->guild_emblem_id=0; - sd->state.guild_sent=0; } ShowWarning("guild: not found member %d,%d on %d[%s]\n", account_id,char_id,guild_id,g->name); return 0; @@ -1535,7 +1557,6 @@ int guild_broken(int guild_id,int flag) if(sd->state.storage_flag == 2) storage_guild_storage_quit(sd,1); sd->status.guild_id=0; - sd->state.guild_sent=0; clif_guild_broken(g->member[i].sd,0); clif_charnameupdate(sd); // [LuzZza] } diff --git a/src/map/guild.h b/src/map/guild.h index 48dcdb550..1035818d9 100644 --- a/src/map/guild.h +++ b/src/map/guild.h @@ -42,6 +42,7 @@ int guild_recv_info(struct guild *sg); int guild_npc_request_info(int guild_id,const char *ev); int guild_invite(struct map_session_data *sd,struct map_session_data *tsd); int guild_reply_invite(struct map_session_data *sd,int guild_id,int flag); +void guild_member_joined(struct map_session_data *sd); int guild_member_added(int guild_id,int account_id,int char_id,int flag); int guild_leave(struct map_session_data *sd,int guild_id, int account_id,int char_id,const char *mes); diff --git a/src/map/intif.c b/src/map/intif.c index 3566e38c4..e04710218 100644 --- a/src/map/intif.c +++ b/src/map/intif.c @@ -919,12 +919,16 @@ int intif_parse_Registers(int fd) struct map_session_data *sd; struct global_reg *reg; int *qty; - - if( (sd=map_id2sd(RFIFOL(fd,4)))==NULL) - return 1; - - if (RFIFOB(fd,12) == 3 && sd->status.char_id != RFIFOL(fd,8)) - return 1; //Character registry from another character. + int account_id = RFIFOL(fd,4), char_id = RFIFOL(fd,8); + struct auth_node *node = chrif_auth_check(account_id, char_id, ST_LOGIN); + if (node) + sd = node->sd; + else { //Normally registries should arrive for in log-in chars. + sd = map_id2sd(account_id); + if (sd && RFIFOB(fd,12) == 3 && sd->status.char_id != char_id) + sd = NULL; //Character registry from another character. + } + if (!sd) return 1; flag = (sd->save_reg.global_num == -1 || sd->save_reg.account_num == -1 || sd->save_reg.account2_num == -1); @@ -975,9 +979,6 @@ int intif_parse_LoadStorage(int fd) return 1; } - if (sd->state.finalsave) - return 1; //Player is already scheduled to leave the server. - stor = account2storage( RFIFOL(fd,4)); if (stor->storage_status == 1) { // Already open.. lets ignore this update @@ -1434,9 +1435,6 @@ int intif_parse_Mail_inboxreceived(int fd) return 1; } - if (sd->state.finalsave) - return 1; - if (RFIFOW(fd,2) - 9 != sizeof(struct mail_data)) { ShowError("intif_parse_Mail_inboxreceived: data size error %d %d\n", RFIFOW(fd,2) - 9, sizeof(struct mail_data)); @@ -1502,9 +1500,6 @@ int intif_parse_Mail_getattach(int fd) return 1; } - if (sd->state.finalsave) - return 1; - if (RFIFOW(fd,2) - 12 != sizeof(struct item)) { ShowError("intif_parse_Mail_getattach: data size error %d %d\n", RFIFOW(fd,2) - 16, sizeof(struct item)); @@ -1546,9 +1541,6 @@ int intif_parse_Mail_delete(int fd) return 1; } - if (sd->state.finalsave) - return 1; - if (!failed) { int i; @@ -1595,9 +1587,6 @@ int intif_parse_Mail_return(int fd) return 1; } - if( sd->state.finalsave ) - return 1; - if( !fail ) { int i; diff --git a/src/map/mail.c b/src/map/mail.c index 5fef604c0..0640fa521 100644 --- a/src/map/mail.c +++ b/src/map/mail.c @@ -153,7 +153,7 @@ int mail_openmail(struct map_session_data *sd) { nullpo_retr(0,sd); - if( sd->state.finalsave == 1 || sd->state.storage_flag || sd->vender_id || sd->state.trading ) + if( sd->state.storage_flag || sd->vender_id || sd->state.trading ) return 0; clif_Mail_window(sd->fd, 0); diff --git a/src/map/map.c b/src/map/map.c index c02a896a9..78e67d3d4 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -102,7 +102,6 @@ static DBMap* mobid_db=NULL; // int id -> struct mob_data* static DBMap* map_db=NULL; // unsigned int mapindex -> struct map_data* static DBMap* nick_db=NULL; // int char_id -> struct charid2nick* (requested names of offline characters) static DBMap* charid_db=NULL; // int char_id -> struct map_session_data* -static DBMap* quit_db=NULL; // int account_id -> struct map_session_data* (players that are quitting or changing map-server) static int map_users=0; static struct block_list *objects[MAX_FLOORITEM]; @@ -1540,117 +1539,76 @@ void map_deliddb(struct block_list *bl) idb_remove(id_db,bl->id); } -/// Returns true if the map server knows the account (to reject logins). -bool map_knowsaccount(int account_id) -{ - return (map_id2sd(account_id) || idb_get(quit_db,account_id) ? true : false); -} - /*========================================== - * PCのquit?理 map.c?分 - * - * quit?理の主?が違うような?もしてきた + * Standard call when a player connection is closed. *------------------------------------------*/ int map_quit(struct map_session_data *sd) { - struct map_session_data* sd2; - if(!sd->state.auth) { //Removing a player that hasn't even finished loading - TBL_PC *sd2 = map_id2sd(sd->status.account_id); - if (sd->pd) unit_free(&sd->pd->bl,-1); - if (sd->hd) unit_free(&sd->hd->bl,-1); - //Double login, let original do the cleanups below. - if (sd2 && sd2 != sd) - return 0; - map_deliddb(&sd->bl); + if(!sd->state.active) { //Removing a player that is not active. + struct auth_node *node = chrif_search(sd->status.account_id); + if (node && node->char_id == sd->status.char_id && + node->state != ST_LOGOUT) + //Except when logging out, clear the auth-connect data immediately. + chrif_auth_delete(node->account_id, node->char_id, node->state); + //Non-active players should not have loaded any data yet (or it was cleared already) so no additional cleanups are needed. return 0; } - if(!sd->state.waitingdisconnect) { - if (sd->npc_timer_id != -1) //Cancel the event timer. - npc_timerevent_quit(sd); - - npc_script_event(sd, NPCE_LOGOUT); - sd->state.waitingdisconnect = 1; - if (sd->pd) unit_free(&sd->pd->bl,0); - if (sd->hd) unit_free(&sd->hd->bl,0); - unit_free(&sd->bl,3); - chrif_save(sd,1); - } else { //Try to free some data, without saving anything (this could be invoked on map server change. [Skotlex] - if (sd->bl.prev != NULL) - unit_remove_map(&sd->bl, 0); - if (sd->pd && sd->pd->bl.prev != NULL) - unit_remove_map(&sd->pd->bl, 0); - if (sd->hd && sd->hd->bl.prev != NULL) - unit_remove_map(&sd->hd->bl, 0); - } - - map_deliddb(&sd->bl); - if( (sd2=(struct map_session_data*)idb_put(quit_db, sd->status.account_id, sd)) ) - { - ShowDebug("map_quit: Possible double login AID/CID: %d/%d AID/CID: %d/%d\n", sd2->status.account_id, sd2->status.char_id, sd->status.account_id, sd->status.char_id); - aFree(sd2); - } - if(sd->reg) - { //Double logout already freed pointer fix... [Skotlex] - aFree(sd->reg); - sd->reg = NULL; - sd->reg_num = 0; - } - if(sd->regstr) - { - int i; - for( i = 0; i < sd->regstr_num; ++i ) - if( sd->regstr[i].data ) - aFree(sd->regstr[i].data); - aFree(sd->regstr); - sd->regstr = NULL; - sd->regstr_num = 0; - } - if (sd->st) { - if (sd->st->stack) - script_free_stack (sd->st->stack); - aFree(sd->st); - sd->st = NULL; - sd->npc_id = 0; - } - if(sd->fd) - { //Player will be free'd on save-ack. [Skotlex] - if (session[sd->fd]) - session[sd->fd]->session_data = NULL; - sd->fd = 0; - } - return 0; -} - -void map_quit_ack(int account_id, int char_id) -{ - struct map_session_data* sd = (struct map_session_data*)idb_get(quit_db,account_id); - if( sd ) - { - if( sd->status.char_id != char_id ) - ShowDebug("map_quit_ack: Possible double login AID/CID: %d/%d AID/CID: %d/%d\n", account_id, char_id, sd->status.account_id, sd->status.char_id); - else - idb_remove(quit_db,account_id); - } -} - -static int do_reconnect_map_sub(DBKey key,void *data,va_list va) -{ - struct map_session_data *sd = (TBL_PC*)data; - if (sd->state.finalsave) { - sd->state.finalsave = 0; - chrif_save(sd, 1); //Resend to save! - return 1; + if (sd->npc_timer_id != -1) //Cancel the event timer. + npc_timerevent_quit(sd); + + npc_script_event(sd, NPCE_LOGOUT); + + //Unit_free handles clearing the player related data, + //map_quit handles extra specific data which is related to quitting normally + //(changing map-servers invokes unit_free but bypasses map_quit) + if(sd->sc.count) { + //Status that are not saved... + if(sd->sc.data[SC_SPURT]) + status_change_end(&sd->bl,SC_SPURT,-1); + if(sd->sc.data[SC_BERSERK]) + status_change_end(&sd->bl,SC_BERSERK,-1); + if(sd->sc.data[SC_TRICKDEAD]) + status_change_end(&sd->bl,SC_TRICKDEAD,-1); + if(sd->sc.data[SC_GUILDAURA]) + status_change_end(&sd->bl,SC_GUILDAURA,-1); + if (battle_config.debuff_on_logout&1) { + if(sd->sc.data[SC_ORCISH]) + status_change_end(&sd->bl,SC_ORCISH,-1); + if(sd->sc.data[SC_STRIPWEAPON]) + status_change_end(&sd->bl,SC_STRIPWEAPON,-1); + if(sd->sc.data[SC_STRIPARMOR]) + status_change_end(&sd->bl,SC_STRIPARMOR,-1); + if(sd->sc.data[SC_STRIPSHIELD]) + status_change_end(&sd->bl,SC_STRIPSHIELD,-1); + if(sd->sc.data[SC_STRIPHELM]) + status_change_end(&sd->bl,SC_STRIPHELM,-1); + if(sd->sc.data[SC_EXTREMITYFIST]) + status_change_end(&sd->bl,SC_EXTREMITYFIST,-1); + if(sd->sc.data[SC_EXPLOSIONSPIRITS]) + status_change_end(&sd->bl,SC_EXPLOSIONSPIRITS,-1); + if(sd->sc.data[SC_REGENERATION] && sd->sc.data[SC_REGENERATION]->val4) + status_change_end(&sd->bl,SC_REGENERATION,-1); + } + if (battle_config.debuff_on_logout&2) + { + if(sd->sc.data[SC_MAXIMIZEPOWER]) + status_change_end(&sd->bl,SC_MAXIMIZEPOWER,-1); + if(sd->sc.data[SC_MAXOVERTHRUST]) + status_change_end(&sd->bl,SC_MAXOVERTHRUST,-1); + if(sd->sc.data[SC_STEELBODY]) + status_change_end(&sd->bl,SC_STEELBODY,-1); + } } + + unit_remove_map_pc(sd,3); + pc_makesavestatus(sd); + pc_clean_skilltree(sd); + chrif_save(sd,1); + unit_free_pc(sd); return 0; } -void do_reconnect_map(void) -{ - pc_db->foreach(pc_db,do_reconnect_map_sub); - pc_db->foreach(quit_db,do_reconnect_map_sub);//## FIXME possible loss of data [FlavioJS] -} - /*========================================== * id番?のPCを探す。居なければNULL *------------------------------------------*/ @@ -1765,15 +1723,6 @@ struct block_list * map_id2bl(int id) return bl; } -static int map_getallpc_sub(DBKey key,void * data,va_list ap) -{ - struct map_session_data *sd = (struct map_session_data*) data; - if (!sd->state.auth || sd->state.waitingdisconnect || sd->state.finalsave) - return 1; //Do not count in not-yet authenticated characters or ready to disconnect ones. - - return 0; -} - /*========================================== * Returns an array of all players in the server (includes non connected ones) [Skotlex] * The int pointer given returns the count of elements in the array. @@ -1805,7 +1754,7 @@ struct map_session_data** map_getallusers(int *users) RECREATE(all_sd, struct map_session_data*, all_count); } - *users = pc_db->getall(pc_db,(void**)all_sd,all_count,map_getallpc_sub); + *users = pc_db->getall(pc_db,(void**)all_sd,all_count,NULL); if (*users > (signed int)all_count) //Which should be impossible... *users = all_count; @@ -1857,8 +1806,7 @@ struct s_mapiterator /// @return true if it matches #define MAPIT_MATCHES(_mapit_,_bl_) \ ( \ - ( (_bl_)->type & (_mapit_)->types /* type matches */ ) && \ - ( (_bl_)->type != BL_PC /* not a pc */ || !((_mapit_)->flags & MAPIT_PCISPLAYING) /* any pc state */ || pc_isplaying((TBL_PC*)(_bl_)) /* pc is playing */ ) \ + ( (_bl_)->type & (_mapit_)->types /* type matches */ ) \ ) /// Allocates a new iterator. @@ -1874,7 +1822,6 @@ struct s_mapiterator* mapit_alloc(enum e_mapitflags flags, enum bl_type types) struct s_mapiterator* mapit; CREATE(mapit, struct s_mapiterator, 1); - if( !(types & BL_PC) && (flags & MAPIT_PCISPLAYING) ) flags ^= MAPIT_PCISPLAYING;// incompatible flag mapit->flags = flags; mapit->types = types; if( types == BL_PC ) mapit->dbi = db_iterator(pc_db); @@ -3127,19 +3074,6 @@ static int cleanup_db_sub(DBKey key,void *data,va_list va) return cleanup_sub((struct block_list*)data, NULL); } -static int cleanup_db_subpc(DBKey key,void *data,va_list va) -{ - struct map_session_data *sd = (TBL_PC*)data; - if (!sd->state.finalsave) - { //Error? - ShowError("do_final: Player character in DB which was not sent to save! %d:%d\n", sd->status.account_id, sd->status.char_id); - map_quit(sd); //Attempt force-save - } - //Force remove from memory... - map_quit_ack(sd->status.account_id, sd->status.char_id); - return 1; -} - /*========================================== * map鯖終了・理 *------------------------------------------*/ @@ -3164,9 +3098,6 @@ void do_final(void) id_db->foreach(id_db,cleanup_db_sub); chrif_char_reset_offline(); chrif_flush_fifo(); - //Online players were sent to save, but the ack will not arrive on time! - //They have to be removed from memory, and assume the char-server saved them. - pc_db->foreach(pc_db,cleanup_db_subpc); do_final_atcommand(); do_final_battle(); @@ -3210,7 +3141,6 @@ void do_final(void) mobid_db->destroy(mobid_db, NULL); nick_db->destroy(nick_db, nick_db_final); charid_db->destroy(charid_db, NULL); - db_destroy(quit_db); #ifndef TXT_ONLY map_sql_close(); @@ -3222,9 +3152,6 @@ static int map_abort_sub(DBKey key,void * data,va_list ap) { struct map_session_data *sd = (TBL_PC*)data; - if (!sd->state.auth || sd->state.waitingdisconnect || sd->state.finalsave) - return 0; - chrif_save(sd,1); return 1; } @@ -3389,7 +3316,6 @@ int do_init(int argc, char *argv[]) map_db = uidb_alloc(DB_OPT_BASE); nick_db = idb_alloc(DB_OPT_BASE); charid_db = idb_alloc(DB_OPT_BASE); - quit_db = idb_alloc(DB_OPT_RELEASE_DATA); #ifndef TXT_ONLY map_sql_init(); #endif /* not TXT_ONLY */ diff --git a/src/map/map.h b/src/map/map.h index 81b55bb7a..269319ab8 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -514,10 +514,9 @@ struct map_session_data { //NOTE: When deciding to add a flag to state or special_state, take into consideration that state is preserved in //status_calc_pc, while special_state is recalculated in each call. [Skotlex] struct { - unsigned auth : 1; + unsigned active : 1; //Marks active player (not active is logging in/out, or changing map servers) unsigned menu_or_input : 1;// if a script is waiting for feedback from the player unsigned dead_sit : 2; - unsigned waitingdisconnect : 1; unsigned lr_flag : 2; unsigned connect_new : 1; unsigned arrow_atk : 1; @@ -537,12 +536,9 @@ struct map_session_data { unsigned noask :1; // [LuzZza] unsigned trading :1; //[Skotlex] is 1 only after a trade has started. unsigned deal_locked :2; //1: Clicked on OK. 2: Clicked on TRADE - unsigned party_sent :1; - unsigned guild_sent :1; unsigned monster_ignore :1; // for monsters to ignore a character [Valaris] [zzo] unsigned size :2; // for tiny/large types unsigned night :1; //Holds whether or not the player currently has the SI_NIGHT effect on. [Skotlex] - unsigned finalsave :1; //Signals whether the final save for the char was done or not yet. Meant to prevent exploits and the like. [Skotlex] unsigned blockedmove :1; unsigned using_fake_npc :1; unsigned rewarp :1; //Signals that a player should warp as soon as he is done loading a map. [Skotlex] @@ -1295,9 +1291,7 @@ int map_delobjectnofree(int id); void map_foreachobject(int (*)(struct block_list*,va_list),int,...); int map_search_freecell(struct block_list *src, int m, short *x, short *y, int rx, int ry, int flag); // -bool map_knowsaccount(int account_id); int map_quit(struct map_session_data *); -void map_quit_ack(int account_id, int char_id); // npc bool map_addnpc(int,struct npc_data *); @@ -1338,7 +1332,7 @@ struct map_session_data * map_nick2sd(const char*); enum e_mapitflags { MAPIT_NORMAL = 0, - MAPIT_PCISPLAYING = 1,// player is authed, not waiting disconnect and not in final save +// MAPIT_PCISPLAYING = 1,// Unneeded as pc_db/id_db will only hold auth'ed, active players. }; struct s_mapiterator; struct s_mapiterator* mapit_alloc(enum e_mapitflags flags, enum bl_type types); @@ -1348,7 +1342,7 @@ struct block_list* mapit_last(struct s_mapiterator* mapit); struct block_list* mapit_next(struct s_mapiterator* mapit); struct block_list* mapit_prev(struct s_mapiterator* mapit); bool mapit_exists(struct s_mapiterator* mapit); -#define mapit_getallusers() mapit_alloc(MAPIT_PCISPLAYING,BL_PC) +#define mapit_getallusers() mapit_alloc(MAPIT_NORMAL,BL_PC) #define mapit_geteachpc() mapit_alloc(MAPIT_NORMAL,BL_PC) #define mapit_geteachmob() mapit_alloc(MAPIT_NORMAL,BL_MOB) #define mapit_geteachiddb() mapit_alloc(MAPIT_NORMAL,BL_ALL) diff --git a/src/map/party.c b/src/map/party.c index 7928a3ad3..b8cd03811 100644 --- a/src/map/party.c +++ b/src/map/party.c @@ -54,7 +54,7 @@ static TBL_PC* party_sd_check(int party_id, int account_id, int char_id) { TBL_PC* sd = map_id2sd(account_id); - if (!(sd && sd->status.char_id == char_id && sd->state.auth && !sd->state.waitingdisconnect)) + if (!(sd && sd->status.char_id == char_id)) return NULL; if (sd->status.party_id != party_id) @@ -125,7 +125,6 @@ int party_create(struct map_session_data *sd,char *name,int item,int item2) int party_created(int account_id,int char_id,int fail,int party_id,char *name) { struct map_session_data *sd; - struct party_data *p; sd=map_id2sd(account_id); if (!sd || sd->status.char_id != char_id) @@ -140,16 +139,8 @@ int party_created(int account_id,int char_id,int fail,int party_id,char *name) return 0; // "party name already exists" } sd->status.party_id=party_id; - if(idb_get(party_db,party_id)!=NULL){ - ShowFatalError("party: id already exists!\n"); - exit(EXIT_FAILURE); - } - p=(struct party_data *)aCalloc(1,sizeof(struct party_data)); - p->party.party_id=party_id; - memcpy(p->party.name, name, NAME_LENGTH); - idb_put(party_db,party_id,p); clif_party_created(sd,0); //Success message - clif_charnameupdate(sd); //Update other people's display. [Skotlex] + //We don't do any further work here because the char-server sends a party info packet right after creating the party. return 1; } @@ -239,15 +230,18 @@ static void party_check_state(struct party_data *p) int party_recv_info(struct party *sp) { - struct map_session_data *sd; struct party_data *p; int i; + bool party_new = false; nullpo_retr(0, sp); p= idb_ensure(party_db, sp->party_id, create_party); if (!p->party.party_id) //party just received. + { + party_new = true; party_check_member(sp); + } memcpy(&p->party,sp,sizeof(struct party)); memset(&p->state, 0, sizeof(p->state)); memset(&p->data, 0, sizeof(p->data)); @@ -257,14 +251,17 @@ int party_recv_info(struct party *sp) p->data[i].sd = party_sd_check(p->party.party_id, p->party.member[i].account_id, p->party.member[i].char_id); } party_check_state(p); - for(i=0;idata[i].sd; - if(!sd || sd->state.party_sent) - continue; - clif_party_member_info(p,sd); - clif_party_option(p,sd,0x100); - clif_party_info(p,NULL); - sd->state.party_sent=1; + if (party_new) { + //Send party data to all players. + struct map_session_data *sd; + for(i=0;idata[i].sd; + if(!sd) continue; + clif_charnameupdate(sd); //Update other people's display. [Skotlex] + clif_party_member_info(p,sd); + clif_party_option(p,sd,0x100); + clif_party_info(p,NULL); + } } return 0; @@ -349,6 +346,26 @@ int party_reply_invite(struct map_session_data *sd,int account_id,int flag) return 1; } +//Invoked when a player joins: +//- Loads up party data if not in server +//- Sets up the pointer to him +//- Player must be authed/active and belong to a party before calling this method +void party_member_joined(struct map_session_data *sd) +{ + struct party_data* p = party_search(sd->status.party_id); + int i; + if (!p) + { + party_request_info(sd->status.party_id); + return; + } + ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == sd->status.account_id && p->party.member[i].char_id == sd->status.char_id ); + if (i < MAX_PARTY) + p->data[i].sd = sd; + else + sd->status.party_id = 0; //He does not belongs to the party really? +} + /// Invoked (from char-server) when a new member is added to the party. int party_member_added(int party_id,int account_id,int char_id, int flag) { @@ -371,9 +388,10 @@ int party_member_added(int party_id,int account_id,int char_id, int flag) } if(!flag) { - sd->state.party_sent=0; sd->status.party_id=party_id; party_check_conflict(sd); + clif_party_option(p,sd,0x100); + clif_party_info(p,sd); clif_party_member_info(p,sd); for( i = 0; i < ARRAYLENGTH(p->data); ++i ) {// hp of the other party members @@ -458,7 +476,6 @@ int party_member_leaved(int party_id, int account_id, int char_id) if( sd && sd->status.party_id == party_id && sd->status.char_id == char_id ) { sd->status.party_id = 0; - sd->state.party_sent = 0; clif_charnameupdate(sd); //Update name display [Skotlex] //TODO: hp bars should be cleared too } @@ -479,7 +496,6 @@ int party_broken(int party_id) if(p->data[i].sd!=NULL){ clif_party_leaved(p,p->data[i].sd,p->party.member[i].account_id,p->party.member[i].name,0x10); p->data[i].sd->status.party_id=0; - p->data[i].sd->state.party_sent=0; } } idb_remove(party_db,party_id); @@ -561,14 +577,11 @@ void party_send_movemap(struct map_session_data *sd) p=party_search(sd->status.party_id); if (!p) return; - if(!sd->state.party_sent) { - party_check_member(&p->party); - if(sd->status.party_id==p->party.party_id){ - clif_party_option(p,sd,0x100); - clif_party_info(p,sd); - clif_party_member_info(p,sd); - sd->state.party_sent=1; - } + if(sd->state.connect_new) { + //Note that this works because this function is invoked before connect_new is cleared. + clif_party_option(p,sd,0x100); + clif_party_info(p,sd); + clif_party_member_info(p,sd); } if (sd->fd) { // synchronize minimap positions with the rest of the party diff --git a/src/map/party.h b/src/map/party.h index 8329647b2..b04797fb1 100644 --- a/src/map/party.h +++ b/src/map/party.h @@ -24,6 +24,7 @@ int party_create(struct map_session_data *sd,char *name, int item, int item2); int party_created(int account_id,int char_id,int fail,int party_id,char *name); int party_request_info(int party_id); int party_invite(struct map_session_data *sd,struct map_session_data *tsd); +void party_member_joined(struct map_session_data *sd); int party_member_added(int party_id,int account_id,int char_id,int flag); int party_leave(struct map_session_data *sd); int party_removemember(struct map_session_data *sd,int account_id,char *name); diff --git a/src/map/pc.c b/src/map/pc.c index f76df3d0b..d1bb81c3e 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -333,9 +333,6 @@ int pc_makesavestatus(struct map_session_data *sd) { nullpo_retr(0, sd); - if (sd->state.finalsave) - return 0; //Nothing to change. - if(!battle_config.save_clothcolor) sd->status.clothes_color=0; @@ -392,10 +389,9 @@ int pc_setnewpc(struct map_session_data *sd, int account_id, int char_id, int lo sd->login_id1 = login_id1; sd->login_id2 = 0; // at this point, we can not know the value :( sd->client_tick = client_tick; - sd->state.auth = 0; + sd->state.active = 0; //to be set to 1 after player is fully authed and loaded. sd->bl.type = BL_PC; sd->canlog_tick = gettick(); - sd->state.waitingdisconnect = 0; //Required to prevent homunculus copuing a base speed of 0. sd->battle_status.speed = sd->base_status.speed = DEFAULT_WALK_SPEED; return 0; @@ -607,35 +603,17 @@ int pc_isequip(struct map_session_data *sd,int n) * session idに問題無し * char鯖から送られてきたステ?タスを設定 *------------------------------------------*/ -int pc_authok(struct map_session_data *sd, int login_id2, time_t connect_until_time, struct mmo_charstatus *st) +bool pc_authok(struct map_session_data *sd, int login_id2, time_t connect_until_time, struct mmo_charstatus *st) { - TBL_PC* old_sd; int i; unsigned long tick = gettick(); - if (sd->state.auth) //Temporary debug. [Skotlex] - { - ShowDebug("pc_authok: Received auth ok for already authorized client (account id %d)!\n", sd->bl.id); - return 1; - } - sd->login_id2 = login_id2; memcpy(&sd->status, st, sizeof(*st)); if (st->sex != sd->status.sex) { clif_authfail_fd(sd->fd, 0); - return 1; - } - - if( (old_sd=map_id2sd(st->account_id)) != NULL ){ - if (old_sd->state.finalsave || !old_sd->state.auth) - ; //Previous player is not done loading/quiting, No need to kick. - else if (old_sd->fd) - clif_authfail_fd(old_sd->fd, 2); // same id - else - map_quit(old_sd); - clif_authfail_fd(sd->fd, 8); // still recognizes last connection - return 1; + return false; } //Set the map-server used job id. [Skotlex] @@ -673,9 +651,6 @@ int pc_authok(struct map_session_data *sd, int login_id2, time_t connect_until_t if (!(battle_config.display_skill_fail&2)) sd->state.showdelay = 1; - // Request all registries. - intif_request_registry(sd,7); - // アイテムチェック pc_setinventorydata(sd); pc_checkitem(sd); @@ -709,21 +684,11 @@ int pc_authok(struct map_session_data *sd, int login_id2, time_t connect_until_t if (pc_setpos(sd, mapindex_name2id(MAP_PRONTERA), 273, 354, 0) != 0) { // if we fail again clif_authfail_fd(sd->fd, 0); - return 1; + return false; } } - // pet - if (sd->status.pet_id > 0) - intif_request_petdata(sd->status.account_id, sd->status.char_id, sd->status.pet_id); - - // Homunculus [albator] - if (sd->status.hom_id > 0) - intif_homunculus_requestload(sd->status.account_id, sd->status.hom_id); - clif_authok(sd); - map_addiddb(&sd->bl); - map_delnickdb(sd->status.char_id, sd->status.name); //Prevent S. Novices from getting the no-death bonus just yet. [Skotlex] sd->die_counter=-1; @@ -777,22 +742,18 @@ int pc_authok(struct map_session_data *sd, int login_id2, time_t connect_until_t clif_wis_message(sd->fd, wisp_server_name, tmpstr, strlen(tmpstr)+1); } - return 0; + // Request all registries (auth is considered completed whence they arrive) + intif_request_registry(sd,7); + return true; } /*========================================== * Closes a connection because it failed to be authenticated from the char server. *------------------------------------------*/ -int pc_authfail(struct map_session_data *sd) +void pc_authfail(struct map_session_data *sd) { - if (sd->state.auth) //Temporary debug. [Skotlex] - ShowDebug("pc_authfail: Received auth fail for already authentified client (account id %d)!\n", sd->bl.id); - - if (!sd->fd) - ShowDebug("pc_authfail: Received auth fail for a player with no connection (account id %d)!\n", sd->bl.id); - clif_authfail_fd(sd->fd, 0); - return 0; + return; } //Attempts to set a mob. @@ -827,7 +788,6 @@ int pc_set_hate_mob(struct map_session_data *sd, int pos, struct block_list *bl) int pc_reg_received(struct map_session_data *sd) { int i,j; - struct guild *g = NULL; sd->change_level = pc_readglobalreg(sd,"jobchange_level"); sd->die_counter = pc_readglobalreg(sd,"PC_DIE_COUNTER"); @@ -863,28 +823,33 @@ int pc_reg_received(struct map_session_data *sd) } //Weird... maybe registries were reloaded? - if (sd->state.auth) + if (sd->state.active) return 0; - sd->state.auth = 1; + sd->state.active = 1; - if (sd->status.party_id > 0 && party_search(sd->status.party_id) == NULL) - party_request_info(sd->status.party_id); - if (sd->status.guild_id > 0 && (g=guild_search(sd->status.guild_id)) == NULL) - guild_request_info(sd->status.guild_id); - else if (g && strcmp(sd->status.name,g->master) == 0) - { - // set the Guild Master flag - sd->state.gmaster_flag = g; - // prevent Guild Skills from being used directly after relog - if( battle_config.guild_skill_relog_delay ) - guild_block_skill(sd, 300000); - } + if (sd->status.party_id) + party_member_joined(sd); + if (sd->status.guild_id) + guild_member_joined(sd); + + // pet + if (sd->status.pet_id > 0) + intif_request_petdata(sd->status.account_id, sd->status.char_id, sd->status.pet_id); + + // Homunculus [albator] + if (sd->status.hom_id > 0) + intif_homunculus_requestload(sd->status.account_id, sd->status.hom_id); + + map_addiddb(&sd->bl); + map_delnickdb(sd->status.char_id, sd->status.name); + chrif_auth_finished(sd); status_calc_pc(sd,1); chrif_scdata_request(sd->status.account_id, sd->status.char_id); #ifndef TXT_ONLY intif_Mail_requestinbox(sd->status.char_id, 0); // MAIL SYSTEM - Request Mail Inbox #endif + if (!sd->state.connect_new && sd->fd) { //Character already loaded map! Gotta trigger LoadEndAck manually. sd->state.connect_new = 1; @@ -2717,9 +2682,6 @@ int pc_payzeny(struct map_session_data *sd,int zeny) { nullpo_retr(0, sd); - if( sd->state.finalsave ) - return 1; - if( zeny < 0 ) return pc_getzeny(sd, -zeny); @@ -2739,9 +2701,6 @@ int pc_getzeny(struct map_session_data *sd,int zeny) { nullpo_retr(0, sd); - if( sd->state.finalsave ) - return 1; - if( zeny < 0 ) return pc_payzeny(sd, -zeny); @@ -2785,9 +2744,6 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount) nullpo_retr(1, sd); nullpo_retr(1, item_data); - if(sd->state.finalsave) - return 1; - if(item_data->nameid <= 0 || amount <= 0) return 1; if(amount > MAX_AMOUNT) @@ -3135,9 +3091,6 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun nullpo_retr(1, sd); nullpo_retr(1, item_data); - if(sd->state.finalsave) - return 1; - if(item_data->nameid <= 0 || amount <= 0) return 1; data = itemdb_search(item_data->nameid); @@ -3191,9 +3144,6 @@ int pc_cart_delitem(struct map_session_data *sd,int n,int amount,int type) { nullpo_retr(1, sd); - if(sd->state.finalsave) - return 1; - if(sd->status.cart[n].nameid==0 || sd->status.cart[n].amountmapindex) { - uint32 ip; - uint16 port; - if(map_mapname2ipport(mapindex,&ip,&port)==0) { - unit_remove_map(&sd->bl,clrtype); - sd->mapindex = mapindex; - sd->bl.x=x; - sd->bl.y=y; - sd->state.waitingdisconnect=1; - pc_clean_skilltree(sd); - if(sd->status.pet_id > 0 && sd->pd) { - intif_save_petdata(sd->status.account_id,&sd->pd->pet); - unit_remove_map(&sd->pd->bl, clrtype); - } - if(merc_is_hom_active(sd->hd)) //Hom is auto-saved in chrif_save - unit_remove_map(&sd->hd->bl, clrtype); - - chrif_save(sd,2); - chrif_changemapserver(sd, mapindex, x, y, ip, (short)port); - return 0; - } - } - return 2; + uint32 ip; + uint16 port; + //if can't find any map-servers, just abort setting position. + if(!sd->mapindex || map_mapname2ipport(mapindex,&ip,&port)) + return 2; + + sd->mapindex = mapindex; + sd->bl.x=x; + sd->bl.y=y; + pc_clean_skilltree(sd); + unit_remove_map_pc(sd,clrtype); + chrif_save(sd,2); + chrif_changemapserver(sd, ip, (short)port); + //It is important to invoke remove_map separately from unit_free before + //saving so that the data saved corresponds to that AFTER warping. + unit_free_pc(sd); + return 0; } if(x <0 || x >= map[m].xs || y <0 || y >= map[m].ys) @@ -3500,13 +3444,9 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y } if(sd->bl.prev != NULL){ - unit_remove_map(&sd->bl, clrtype); - if(sd->status.pet_id > 0 && sd->pd) - unit_remove_map(&sd->pd->bl, clrtype); - if(merc_is_hom_active(sd->hd)) - unit_remove_map(&sd->hd->bl, clrtype); + unit_remove_map_pc(sd,clrtype); clif_changemap(sd,map[m].index,x,y); // [MouseJstr] - } else if(sd->state.auth) + } else if(sd->state.active) //Tag player for rewarping after map-loading is done. [Skotlex] sd->state.rewarp = 1; @@ -6587,7 +6527,7 @@ int pc_checkitem(struct map_session_data *sd) } pc_setequipindex(sd); - if(calc_flag && sd->state.auth) + if(calc_flag && sd->state.active) { status_calc_pc(sd,0); pc_equiplookall(sd); @@ -6881,24 +6821,11 @@ static int pc_autosave_sub(DBKey key,void * data,va_list ap) if(save_flag != 1) //Not our turn to save yet. return 0; - if (sd->state.waitingdisconnect) //Invalid char to save. - return 0; - //Save char. last_save_id = sd->bl.id; save_flag=2; - // pet - if(sd->status.pet_id > 0 && sd->pd) - intif_save_petdata(sd->status.account_id,&sd->pd->pet); - - if(sd->state.finalsave) - { //Save ack hasn't returned from char-server yet? Retry. - ShowDebug("pc_autosave: Resending to save logging out char %d:%d (save ack from char-server hasn't arrived yet)\n", sd->status.account_id, sd->status.char_id); - sd->state.finalsave = 0; - chrif_save(sd,1); - } else - chrif_save(sd,0); + chrif_save(sd,0); return 1; } diff --git a/src/map/pc.h b/src/map/pc.h index e3eb9afdb..dc55b53bd 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -126,7 +126,6 @@ extern int duel_count; #define pc_is50overweight(sd) ( (sd)->weight*100 >= (sd)->max_weight*battle_config.natural_heal_weight_rate ) #define pc_is90overweight(sd) ( (sd)->weight*10 >= (sd)->max_weight*9 ) #define pc_maxparameter(sd) ( (sd)->class_&JOBL_BABY ? battle_config.max_baby_parameter : battle_config.max_parameter ) -#define pc_isplaying(sd) ( (sd)->state.auth /* is authed */ && !(sd)->state.waitingdisconnect /* not waiting disconnect */ && !(sd)->state.finalsave /* not in final save */ ) #define pc_stop_walking(sd, type) unit_stop_walking(&(sd)->bl, type) #define pc_stop_attack(sd) unit_stop_attack(&(sd)->bl) @@ -145,8 +144,8 @@ bool pc_can_give_items(int level); int pc_setrestartvalue(struct map_session_data *sd,int type); int pc_makesavestatus(struct map_session_data *); int pc_setnewpc(struct map_session_data*,int,int,int,unsigned int,int,int); -int pc_authok(struct map_session_data*, int, time_t, struct mmo_charstatus *); -int pc_authfail(struct map_session_data *); +bool pc_authok(struct map_session_data*, int, time_t, struct mmo_charstatus *); +void pc_authfail(struct map_session_data *); int pc_reg_received(struct map_session_data *sd); int pc_isequip(struct map_session_data *sd,int n); diff --git a/src/map/status.c b/src/map/status.c index 6b6174293..10129129a 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -1616,9 +1616,6 @@ int status_calc_pc(struct map_session_data* sd,int first) int i,index; int skill,refinedef=0; - if(!sd->state.auth && !(first&1)) //Shouldn't invoke yet until player is done loading. - return -1; - if (++calculating > 10) //Too many recursive calls! return -1; @@ -4623,9 +4620,6 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val sd = BL_CAST(BL_PC, bl); - if(sd && sd->state.waitingdisconnect) - return 0; //Character logging out, all his SC were wiped already! - //Adjust tick according to status resistances if( !(flag&(1|4)) ) { diff --git a/src/map/storage.c b/src/map/storage.c index 50024fbbe..06c052d74 100644 --- a/src/map/storage.c +++ b/src/map/storage.c @@ -132,9 +132,6 @@ int storage_storageopen(struct map_session_data *sd) struct storage *stor; nullpo_retr(0, sd); - if(sd->state.finalsave) //Refuse to open storage when you had your last save done. - return 1; - if(sd->state.storage_flag) return 1; //Already open? @@ -183,9 +180,6 @@ static int storage_additem(struct map_session_data *sd,struct storage *stor,stru struct item_data *data; int i; - if (sd->state.finalsave) - return 1; - if(item_data->nameid <= 0 || amount <= 0) return 1; @@ -502,9 +496,6 @@ int storage_guild_storageopen(struct map_session_data *sd) if(sd->status.guild_id <= 0) return 2; - if(sd->state.finalsave) //Refuse to open storage when you had your last save done. - return 1; - if(sd->state.storage_flag) return 1; //Can't open both storages at a time. diff --git a/src/map/trade.c b/src/map/trade.c index 5c063621d..a9f2a2fd5 100644 --- a/src/map/trade.c +++ b/src/map/trade.c @@ -232,9 +232,6 @@ int trade_check(struct map_session_data *sd, struct map_session_data *tsd) int trade_i, i, n; short amount; - if(sd->state.finalsave || tsd->state.finalsave) - return 0; //Item transferring fails - // check zenys value against hackers (Zeny was already checked on time of adding, but you never know when you lost some zeny since then. if(sd->deal.zeny > sd->status.zeny || (tsd->status.zeny > MAX_ZENY - sd->deal.zeny)) return 0; diff --git a/src/map/unit.c b/src/map/unit.c index d0d06ff06..66f362085 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1658,13 +1658,11 @@ int unit_remove_map(struct block_list *bl, int clrtype) trade_tradecancel(sd); if(sd->vender_id) vending_closevending(sd); - if(!sd->state.waitingdisconnect) - { //when quitting, let the final chrif_save handle storage saving. - if(sd->state.storage_flag == 1) - storage_storage_quit(sd,0); - else if (sd->state.storage_flag == 2) - storage_guild_storage_quit(sd,0); - } + if(sd->state.storage_flag == 1) + storage_storage_quit(sd,0); + else if (sd->state.storage_flag == 2) + storage_guild_storage_quit(sd,0); + sd->state.storage_flag = 0; //Force close it when being warped. if(sd->party_invite>0) party_reply_invite(sd,sd->party_invite_account,0); if(sd->guild_invite>0) @@ -1708,7 +1706,7 @@ int unit_remove_map(struct block_list *bl, int clrtype) case BL_PET: { struct pet_data *pd = (struct pet_data*)bl; - if( pd->pet.intimate <= 0 && !(pd->msd && pd->msd->state.waitingdisconnect) ) + if( pd->pet.intimate <= 0 && !(pd->msd && pd->msd->state.active) ) { //If logging out, this is deleted on unit_free clif_clearunit_area(bl,clrtype); map_delblock(bl); @@ -1723,7 +1721,7 @@ int unit_remove_map(struct block_list *bl, int clrtype) { struct homun_data *hd = (struct homun_data *) bl; ud->canact_tick = ud->canmove_tick; //It appears HOM do reset the can-act tick. - if(!hd->homunculus.intimacy && !(hd->master && hd->master->state.waitingdisconnect) ) + if(!hd->homunculus.intimacy && !(hd->master && hd->master->state.active) ) { //If logging out, this is deleted on unit_free clif_emotion(bl, 28) ; //sob clif_clearunit_area(bl,clrtype); @@ -1744,6 +1742,25 @@ int unit_remove_map(struct block_list *bl, int clrtype) return 1; } +void unit_remove_map_pc(struct map_session_data *sd, int clrtype) +{ + unit_remove_map(&sd->bl,clrtype); + + if (clrtype == 3) clrtype = 0; //3 is the warp from logging out, but pets/homunc need to just 'vanish' instead of showing the warping out animation. + + if(sd->pd) + unit_remove_map(&sd->pd->bl, clrtype); + if(merc_is_hom_active(sd->hd)) + unit_remove_map(&sd->hd->bl, clrtype); +} + +void unit_free_pc(struct map_session_data *sd) +{ + if (sd->pd) unit_free(&sd->pd->bl,0); + if (sd->hd) unit_free(&sd->hd->bl,0); + unit_free(&sd->bl,3); +} + /*========================================== * Function to free all related resources to the bl * if unit is on map, it is removed using the clrtype specified @@ -1765,44 +1782,6 @@ int unit_free(struct block_list *bl, int clrtype) pc_setrestartvalue(sd,2); pc_delinvincibletimer(sd); - //Status that are not saved... - if(sd->sc.count) { - if(sd->sc.data[SC_SPURT]) - status_change_end(bl,SC_SPURT,-1); - if(sd->sc.data[SC_BERSERK]) - status_change_end(bl,SC_BERSERK,-1); - if(sd->sc.data[SC_TRICKDEAD]) - status_change_end(bl,SC_TRICKDEAD,-1); - if(sd->sc.data[SC_GUILDAURA]) - status_change_end(bl,SC_GUILDAURA,-1); - if (battle_config.debuff_on_logout&1) { - if(sd->sc.data[SC_ORCISH]) - status_change_end(bl,SC_ORCISH,-1); - if(sd->sc.data[SC_STRIPWEAPON]) - status_change_end(bl,SC_STRIPWEAPON,-1); - if(sd->sc.data[SC_STRIPARMOR]) - status_change_end(bl,SC_STRIPARMOR,-1); - if(sd->sc.data[SC_STRIPSHIELD]) - status_change_end(bl,SC_STRIPSHIELD,-1); - if(sd->sc.data[SC_STRIPHELM]) - status_change_end(bl,SC_STRIPHELM,-1); - if(sd->sc.data[SC_EXTREMITYFIST]) - status_change_end(bl,SC_EXTREMITYFIST,-1); - if(sd->sc.data[SC_EXPLOSIONSPIRITS]) - status_change_end(bl,SC_EXPLOSIONSPIRITS,-1); - if(sd->sc.data[SC_REGENERATION] && sd->sc.data[SC_REGENERATION]->val4) - status_change_end(bl,SC_REGENERATION,-1); - } - if (battle_config.debuff_on_logout&2) - { - if(sd->sc.data[SC_MAXIMIZEPOWER]) - status_change_end(bl,SC_MAXIMIZEPOWER,-1); - if(sd->sc.data[SC_MAXOVERTHRUST]) - status_change_end(bl,SC_MAXOVERTHRUST,-1); - if(sd->sc.data[SC_STEELBODY]) - status_change_end(bl,SC_STEELBODY,-1); - } - } pc_autoscript_clear(sd->autoscript, ARRAYLENGTH(sd->autoscript)); pc_autoscript_clear(sd->autoscript2, ARRAYLENGTH(sd->autoscript2)); @@ -1819,10 +1798,29 @@ int unit_free(struct block_list *bl, int clrtype) guild_send_memberinfoshort(sd,0); pc_cleareventtimer(sd); pc_delspiritball(sd,sd->spiritball,1); - if (clrtype >= 0) { - chrif_save_scdata(sd); //Save status changes, then clear'em out from memory. [Skotlex] - pc_makesavestatus(sd); - pc_clean_skilltree(sd); + + if(sd->reg) + { //Double logout already freed pointer fix... [Skotlex] + aFree(sd->reg); + sd->reg = NULL; + sd->reg_num = 0; + } + if(sd->regstr) + { + int i; + for( i = 0; i < sd->regstr_num; ++i ) + if( sd->regstr[i].data ) + aFree(sd->regstr[i].data); + aFree(sd->regstr); + sd->regstr = NULL; + sd->regstr_num = 0; + } + if (sd->st) { + if (sd->st->stack) + script_free_stack (sd->st->stack); + aFree(sd->st); + sd->st = NULL; + sd->npc_id = 0; } } else if( bl->type == BL_PET ) { struct pet_data *pd = (struct pet_data*)bl; @@ -1924,11 +1922,9 @@ int unit_free(struct block_list *bl, int clrtype) skill_clear_unitgroup(bl); status_change_clear(bl,1); - if (bl->type != BL_PC) - { //Players are handled by map_quit - map_deliddb(bl); + map_deliddb(bl); + if (bl->type != BL_PC) //Players are handled by map_quit map_freeblock(bl); - } map_freeblock_unlock(); return 0; } diff --git a/src/map/unit.h b/src/map/unit.h index 2c569607d..7575d3f5e 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -7,6 +7,7 @@ //#include "map.h" struct block_list; struct unit_data; +struct map_session_data; // PC, MOB, PET に共通する処理を1つにまとめる計画 @@ -61,6 +62,8 @@ void unit_dataset(struct block_list *bl); int unit_fixdamage(struct block_list *src,struct block_list *target,unsigned int tick,int sdelay,int ddelay,int damage,int div,int type,int damage2); // その他 struct unit_data* unit_bl2ud(struct block_list *bl); +void unit_remove_map_pc(struct map_session_data *sd, int clrtype); +void unit_free_pc(struct map_session_data *sd); int unit_remove_map(struct block_list *bl, int clrtype); int unit_free(struct block_list *bl, int clrtype); int unit_changeviewsize(struct block_list *bl,short size); -- cgit v1.2.3-70-g09d2