diff options
Diffstat (limited to 'src/map')
-rw-r--r-- | src/map/atcommand.c | 2 | ||||
-rw-r--r-- | src/map/chrif.c | 317 | ||||
-rw-r--r-- | src/map/chrif.h | 16 | ||||
-rw-r--r-- | src/map/clif.c | 183 | ||||
-rw-r--r-- | src/map/guild.c | 71 | ||||
-rw-r--r-- | src/map/guild.h | 1 | ||||
-rw-r--r-- | src/map/intif.c | 31 | ||||
-rw-r--r-- | src/map/mail.c | 2 | ||||
-rw-r--r-- | src/map/map.c | 196 | ||||
-rw-r--r-- | src/map/map.h | 12 | ||||
-rw-r--r-- | src/map/party.c | 75 | ||||
-rw-r--r-- | src/map/party.h | 1 | ||||
-rw-r--r-- | src/map/pc.c | 171 | ||||
-rw-r--r-- | src/map/pc.h | 5 | ||||
-rw-r--r-- | src/map/status.c | 6 | ||||
-rw-r--r-- | src/map/storage.c | 9 | ||||
-rw-r--r-- | src/map/trade.c | 3 | ||||
-rw-r--r-- | src/map/unit.c | 106 | ||||
-rw-r--r-- | src/map/unit.h | 3 |
19 files changed, 587 insertions, 623 deletions
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 <sys/types.h> #include <time.h> -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 <account_id>.L <login_id1>.L <login_id2>.L <char_id>.L <map_index>.W <x>.W <y>.W <ip>.L <port>.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 <time.h> -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; 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.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;i<MAX_PARTY;i++){ - sd = p->data[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;i<MAX_PARTY;i++){ + sd = p->data[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].amount<amount) return 1; @@ -3456,29 +3406,23 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y } if(m<0) { - if(sd->mapindex) { - 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); |