diff options
author | skotlex <skotlex@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2006-07-07 16:28:41 +0000 |
---|---|---|
committer | skotlex <skotlex@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2006-07-07 16:28:41 +0000 |
commit | 959387743887e9a57cf31b950f23be9bd34b919f (patch) | |
tree | 8a472ad961a9d3df5dea73f84ae597735b02e52e | |
parent | ae287ef89682be736bf1281d758e5cd3bad56895 (diff) | |
download | hercules-959387743887e9a57cf31b950f23be9bd34b919f.tar.gz hercules-959387743887e9a57cf31b950f23be9bd34b919f.tar.bz2 hercules-959387743887e9a57cf31b950f23be9bd34b919f.tar.xz hercules-959387743887e9a57cf31b950f23be9bd34b919f.zip |
- Okay, added a chrif_save_ack packet to the char-server so now the map server will know once a character was "final saved", and only then the character will be removed from memory. On char-server reconnection, all chars that are in final-save state are resent to save (if they are still in memory, it's because the ack hasn't gotten here from the char-server). This should effectively block all dupe problems due to heavy inter-server lag, however as it's untested, it currently prints some debug messages when people are saved and then removed from memory. Need testers so this can be debugged and merged to stable!
git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@7568 54d463be-8e91-2dee-dedb-b68131a5f0ec
-rw-r--r-- | Changelog-Trunk.txt | 9 | ||||
-rw-r--r-- | src/char/char.c | 8 | ||||
-rw-r--r-- | src/char_sql/char.c | 8 | ||||
-rw-r--r-- | src/map/chrif.c | 25 | ||||
-rw-r--r-- | src/map/clif.c | 19 | ||||
-rw-r--r-- | src/map/map.c | 30 | ||||
-rw-r--r-- | src/map/map.h | 2 |
7 files changed, 82 insertions, 19 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index bae718cf6..9fdbe6d02 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -4,6 +4,15 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
2006/07/07
+ * Okay, added a chrif_save_ack packet to the char-server so now the map
+ server will know once a character was "final saved", and only then the
+ character will be removed from memory. On char-server reconnection, all
+ chars that are in final-save state are resent to save (if they are still in
+ memory, it's because the ack hasn't gotten here from the char-server). This
+ should effectively block all dupe problems due to heavy inter-server lag,
+ however as it's untested, it currently prints some debug messages when
+ people are saved and then removed from memory. Need testers so this can be
+ debugged and merged to stable! [Skotlex]
* Now, when the login-char connection is cut, the char-server won't set
everyone offline on reconnect, instead it will send the list of online
accounts to the login server. [Skotlex]
diff --git a/src/char/char.c b/src/char/char.c index 1556c10a3..a0d34e14e 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -2752,8 +2752,14 @@ int parse_frommap(int fd) { }
if (i != char_num)
memcpy(&char_dat[i].status, RFIFOP(fd,13), sizeof(struct mmo_charstatus));
- if (RFIFOB(fd,12)) //Flag, set character offline. [Skotlex]
+ if (RFIFOB(fd,12))
+ { //Flag, set character offline. [Skotlex]
set_char_offline(RFIFOL(fd,8),RFIFOL(fd,4));
+ WFIFOW(fd, 0) = 0x2b21; //Save ack only needed on final save.
+ WFIFOL(fd, 2) = RFIFOL(fd,4);
+ WFIFOL(fd, 6) = RFIFOL(fd,8);
+ WFIFOSET(fd, 10);
+ }
RFIFOSKIP(fd,RFIFOW(fd,2));
break;
diff --git a/src/char_sql/char.c b/src/char_sql/char.c index fb024a4ea..98b6534c3 100644 --- a/src/char_sql/char.c +++ b/src/char_sql/char.c @@ -2615,8 +2615,14 @@ int parse_frommap(int fd) { mmo_char_tosql(cid, &char_dat);
}
- if (RFIFOB(fd,12)) //Flag? Set character offline after saving [Skotlex]
+ if (RFIFOB(fd,12))
+ { //Flag? Set character offline after saving [Skotlex]
set_char_offline(cid, aid);
+ WFIFOW(fd, 0) = 0x2b21; //Save ack only needed on final save.
+ WFIFOL(fd, 2) = aid;
+ WFIFOL(fd, 6) = cid;
+ WFIFOSET(fd, 10);
+ }
RFIFOSKIP(fd,size);
break;
}
diff --git a/src/map/chrif.c b/src/map/chrif.c index 211dcb6f4..0e11c6741 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -37,7 +37,7 @@ static const int packet_len_table[0x3d] = { 6,30,-1,10,86, 7,44,34, // 2b08-2b0f: U->2b08, U->2b09, U->2b0a, U->2b0b, U->2b0c, U->2b0d, U->2b0e, U->2b0f
0,-1,10, 6,11,-1, 0, 0, // 2b10-2b17: U->2b10, U->2b11, U->2b12, U->2b13, U->2b14, U->2b15, U->2b16, U->2b17
-1,-1,-1,-1,-1,-1, 2, 7, // 2b18-2b1f: U->2b18, U->2b19, U->2b1a, U->2b1b, U->2b1c, U->2b1d, U->2b1e, U->2b1f
- -1,-1,-1,-1,-1,-1,-1,-1, // 2b20-2b27: U->2b20, F->2b21, F->2b22, F->2b23, F->2b24, F->2b25, F->2b26, F->2b27
+ -1,10,-1,-1,-1,-1,-1,-1, // 2b20-2b27: U->2b20, U->2b21, F->2b22, F->2b23, F->2b24, F->2b25, F->2b26, F->2b27
};
//Used Packets:
@@ -82,7 +82,8 @@ static const int packet_len_table[0x3d] = { //2b1e: Incoming, chrif_update_ip -> 'Reqest forwarded from char-server for interserver IP sync.' [Lance]
//2b1f: Incomming, chrif_disconnectplayer -> 'disconnects a player (aid X) with the message XY ... 0x81 ..' [Sirius]
//2b20: Incomming, chrif_removemap -> 'remove maps of a server (sample: its going offline)' [Sirius]
-//2b21-2b27: FREE
+//2b21: Incomming, chrif_save_ack. Returned after a character has been "final saved" on the char-server. [Skotlex]
+//2b22-2b27: FREE
int chrif_connected;
int char_fd = 0; //Using 0 instead of -1 is safer against crashes. [Skotlex]
@@ -183,8 +184,13 @@ int chrif_isconnect(void) int chrif_save(struct map_session_data *sd, int flag)
{
nullpo_retr(-1, sd);
- chrif_check(-1);
+
pc_makesavestatus(sd);
+ if(!chrif_isconnect())
+ {
+ if (flag) sd->state.finalsave = 1; //Will save character on reconnect.
+ return -1;
+ }
if (sd->state.finalsave)
return -1; //Refuse to save a char already tagged for final saving. [Skotlex]
@@ -193,6 +199,7 @@ int chrif_save(struct map_session_data *sd, int flag) storage_storage_save(sd->status.account_id, flag);
else if (sd->state.storage_flag == 2)
storage_guild_storagesave(sd->status.account_id, sd->status.guild_id, flag);
+ if (flag) sd->state.storage_flag = 0; //Force close it.
//Saving of registry values.
if (sd->state.reg_dirty&4)
@@ -306,6 +313,14 @@ int chrif_removemap(int fd){ return 0;
}
+int chrif_save_ack(int fd) {
+ int aid = RFIFOL(fd,2), cid = RFIFOL(fd,6);
+ struct map_session_data *sd = map_id2sd(aid);
+ if (sd && sd->status.char_id == cid)
+ map_quit_ack(sd);
+ return 0;
+}
+
/*==========================================
* マップ鯖間移動のためのデータ準備要求
*------------------------------------------
@@ -416,6 +431,7 @@ int chrif_sendmapack(int fd) send_users_tochar(-1, gettick(), 0, 0);
//Re-save any storages that were modified in the disconnection time. [Skotlex]
+ do_reconnect_map();
do_reconnect_storage();
return 0;
@@ -1493,7 +1509,8 @@ int chrif_parse(int fd) case 0x2b1d: chrif_load_scdata(fd); break;
case 0x2b1e: chrif_update_ip(fd); break;
case 0x2b1f: chrif_disconnectplayer(fd); break;
- case 0x2b20: chrif_removemap(fd); break; //Remove maps of a server [Sirius]
+ case 0x2b20: chrif_removemap(fd); break;
+ case 0x2b21: chrif_save_ack(fd); break;
default:
if (battle_config.error_log)
diff --git a/src/map/clif.c b/src/map/clif.c index 522199539..69dabc00e 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -1683,12 +1683,9 @@ int clif_move(struct block_list *bl) { static int clif_delayquit(int tid, unsigned int tick, int id, int data) {
struct map_session_data *sd = NULL;
- if (chrif_isconnect())
- { //Remove player from map server
- if ((sd = map_id2sd(id)) != NULL && sd->fd == 0) //Should be a disconnected player.
- map_quit(sd);
- } else //Save later.
- add_timer(tick + 10000, clif_delayquit, id, 0);
+ //Remove player from map server
+ if ((sd = map_id2sd(id)) != NULL && sd->fd == 0) //Should be a disconnected player.
+ map_quit(sd);
return 0;
}
@@ -1698,12 +1695,12 @@ static int clif_delayquit(int tid, unsigned int tick, int id, int data) { */
void clif_quitsave(int fd,struct map_session_data *sd)
{
- if (chrif_isconnect() && (sd->state.waitingdisconnect || //Was already waiting to be disconnected.
- !battle_config.prevent_logout || DIFF_TICK(gettick(), sd->canlog_tick) > battle_config.prevent_logout))
+ if (sd->state.waitingdisconnect || //Was already waiting to be disconnected.
+ !battle_config.prevent_logout || DIFF_TICK(gettick(), sd->canlog_tick) > battle_config.prevent_logout)
map_quit(sd);
else if (sd->fd)
{ //Disassociate session from player (session is deleted after this function was called)
- //And set a timer to delete this player later.
+ //And set a timer to make him quit later.
session[fd]->session_data = NULL;
sd->fd = 0;
add_timer(gettick() + 10000, clif_delayquit, sd->bl.id, 0);
@@ -8018,7 +8015,9 @@ void clif_parse_WantToConnection(int fd, struct map_session_data *sd) if ((old_sd = map_id2sd(account_id)) != NULL)
{ // if same account already connected, we disconnect the 2 sessions
//Check for characters with no connection (includes those that are using autotrade) [durf],[Skotlex]
- if (!old_sd->fd)
+ if (old_sd->state.finalsave)
+ ; //Ack has not arrived yet from char-server, be patient!
+ else if (!old_sd->fd)
map_quit(old_sd);
else
clif_authfail_fd(old_sd->fd, 2); // same id
diff --git a/src/map/map.c b/src/map/map.c index c5a4bb314..9c23215a2 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -1657,7 +1657,6 @@ int map_quit(struct map_session_data *sd) { //nullpo_retr(0, sd); //Utterly innecessary, all invokations to this function already have an SD non-null check. //Learn to use proper coding and stop relying on nullpo_'s for safety :P [Skotlex] - if(!sd->state.waitingdisconnect) { if (sd->npc_timer_id != -1) //Cancel the event timer. npc_timerevent_quit(sd); @@ -1680,7 +1679,6 @@ int map_quit(struct map_session_data *sd) { //Do we really need to remove the name? idb_remove(charid_db,sd->status.char_id); idb_remove(id_db,sd->bl.id); - idb_remove(pc_db,sd->bl.id); if(sd->reg) { //Double logout already freed pointer fix... [Skotlex] @@ -1694,12 +1692,38 @@ int map_quit(struct map_session_data *sd) { sd->regstr = NULL; sd->regstr_num = 0; } + if(sd->fd) + { //Player will be free'd on save-ack. [Skotlex] + if (session[sd->fd] && session[sd->fd]->session_data == sd) + session[sd->fd]->session_data = NULL; + sd->fd = 0; + } + + return 0; +} - if(!sd->fd) //There is no session connected, and as such socket.c won't free the data, we must do it. [Skotlex] +void map_quit_ack(struct map_session_data *sd) { + if (sd && sd->state.finalsave) { + idb_remove(pc_db,sd->status.account_id); aFree(sd); + ShowDebug("Final Save Ack for character %d:%d\n", sd->status.account_id, sd->status.char_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; + } return 0; } +void do_reconnect_map(void) { + pc_db->foreach(pc_db,do_reconnect_map_sub); +} + /*========================================== * id番?のPCを探す。居なければNULL *------------------------------------------ diff --git a/src/map/map.h b/src/map/map.h index d7456b742..c247d0a16 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -1304,6 +1304,7 @@ 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);
//
int map_quit(struct map_session_data *);
+void map_quit_ack(struct map_session_data *);
// npc
int map_addnpc(int,struct npc_data *);
@@ -1375,6 +1376,7 @@ int map_delmap(char *mapname); int map_addmobtolist(unsigned short m, struct spawn_data *spawn); // [Wizputer]
void map_spawnmobs(int); // [Wizputer]
void map_removemobs(int); // [Wizputer]
+void do_reconnect_map(void); //Invoked on map-char reconnection [Skotlex]
//Added for own save method
int charsql_db_init(int method);
|