Przeglądaj źródła

* Disabled tick cache (to enable it: define TICK_CACHE to the number of calls that should be cached).
* Added a charid2sd database for fast charid searches.
* Reworked the nick cache to only contain offline characters.

Note: The tick cache was causing _some_ of the desync problems in eA. Gameplay should be much smother, but desync problems still exist.

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@11290 54d463be-8e91-2dee-dedb-b68131a5f0ec

FlavioJS 17 lat temu
rodzic
commit
52f3681f3d
9 zmienionych plików z 182 dodań i 112 usunięć
  1. 5 0
      Changelog-Trunk.txt
  2. 24 5
      src/common/timer.c
  3. 4 0
      src/common/timer.h
  4. 1 1
      src/map/chrif.c
  5. 17 35
      src/map/clif.c
  6. 2 2
      src/map/clif.h
  7. 123 61
      src/map/map.c
  8. 5 6
      src/map/map.h
  9. 1 2
      src/map/pc.c

+ 5 - 0
Changelog-Trunk.txt

@@ -3,6 +3,11 @@ Date	Added
 AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK.
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
+2007/09/25
+	* Disabled tick cache (to enable it: define TICK_CACHE to the number of 
+	  calls that should be cached).
+	* Added a charid2sd database for fast charid searches.
+	* Reworked the nick cache to only contain offline characters. [FlavioJS]
 2007/09/24
 	* Ignore %MDef bonuses now only reduce target's base MDEF, not MDEF2.
 	* Updated the 'skills that cause no damage are blocked now if the skill

+ 24 - 5
src/common/timer.c

@@ -109,19 +109,21 @@ char* search_timer_func_list(TimerFunc func)
 /*----------------------------
  * 	Get tick time
  *----------------------------*/
-static unsigned int gettick_cache;
-static int gettick_count;
 
+//////////////////////////////////////////////////////////////////////////
+#if defined(TICK_CACHE) && TICK_CACHE > 1
+//////////////////////////////////////////////////////////////////////////
+// tick is cached for TICK_CACHE calls
 unsigned int gettick_nocache(void)
 {
-#ifdef _WIN32
-	gettick_count = 256;
+#ifdef WIN32
+	gettick_count = TICK_CACHE;
 	return gettick_cache = GetTickCount();
 #else
 	struct timeval tval;
 
 	gettimeofday(&tval, NULL);
-	gettick_count = 256;
+	gettick_count = TICK_CACHE;
 
 	return gettick_cache = tval.tv_sec * 1000 + tval.tv_usec / 1000;
 #endif
@@ -134,6 +136,23 @@ unsigned int gettick(void)
 
 	return gettick_cache;
 }
+//////////////////////////////
+#else
+//////////////////////////////
+// tick doesn't get cached
+unsigned int gettick(void)
+{
+#ifdef WIN32
+	return GetTickCount();
+#else
+	struct timeval tval;
+	gettimeofday(&tval, NULL);
+	return tval.tv_sec * 1000 + tval.tv_usec / 1000;
+#endif
+}
+//////////////////////////////////////////////////////////////////////////
+#endif
+//////////////////////////////////////////////////////////////////////////
 
 /*======================================
  * 	CORE : Timer Heap

+ 4 - 0
src/common/timer.h

@@ -41,7 +41,11 @@ struct TimerData {
 
 // Function prototype declaration
 
+#if defined(TICK_CACHE) && TICK_CACHE > 1
 unsigned int gettick_nocache(void);
+#else
+#define gettick_nocache gettick
+#endif
 unsigned int gettick(void);
 
 int add_timer(unsigned int,TimerFunc f,int,int);

+ 1 - 1
src/map/chrif.c

@@ -1302,7 +1302,7 @@ int chrif_parse(int fd)
 		case 0x2b04: chrif_recvmap(fd); break;
 		case 0x2b06: chrif_changemapserverack(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14), RFIFOW(fd,18), RFIFOW(fd,20), RFIFOW(fd,22), RFIFOL(fd,24), RFIFOW(fd,28)); break;
 		case 0x2b07: clif_updatemaxid(RFIFOL(fd,2), RFIFOL(fd,6)); break;
-		case 0x2b09: map_addchariddb(RFIFOL(fd,2), (char*)RFIFOP(fd,6)); break;
+		case 0x2b09: map_addnickdb(RFIFOL(fd,2), (char*)RFIFOP(fd,6)); break;
 		case 0x2b0b: chrif_changedgm(fd); break;
 		case 0x2b0d: chrif_changedsex(fd); break;
 		case 0x2b0f: chrif_char_ask_name_answer(fd); break;

+ 17 - 35
src/map/clif.c

@@ -5160,24 +5160,13 @@ int clif_wis_end(int fd, int flag)
 /*==========================================
  * キャラID名前引き結果を送信する
  *------------------------------------------*/
-int clif_solved_charname(struct map_session_data *sd,int char_id)
+int clif_solved_charname(int fd, int charid, const char* name)
 {
-	char *p= map_charid2nick(char_id);
-	int fd;
-
-	nullpo_retr(0, sd);
-
-	fd=sd->fd;
-	if(p!=NULL){
-		WFIFOHEAD(fd,packet_len(0x194));
-		WFIFOW(fd,0)=0x194;
-		WFIFOL(fd,2)=char_id;
-		memcpy(WFIFOP(fd,6), p, NAME_LENGTH);
-		WFIFOSET(fd,packet_len(0x194));
-	}else{
-		map_reqchariddb(sd,char_id);
-		chrif_searchcharid(char_id);
-	}
+	WFIFOHEAD(fd,packet_len(0x194));
+	WFIFOW(fd,0)=0x194;
+	WFIFOL(fd,2)=charid;
+	safestrncpy(WFIFOP(fd,6), name, NAME_LENGTH);
+	WFIFOSET(fd,packet_len(0x194));
 	return 0;
 }
 
@@ -6039,25 +6028,18 @@ int clif_movetoattack(struct map_session_data *sd,struct block_list *bl)
 /*==========================================
  * 製造エフェクト
  *------------------------------------------*/
-int clif_produceeffect(struct map_session_data *sd,int flag,int nameid)
+int clif_produceeffect(struct map_session_data* sd,int flag,int nameid)
 {
-	int view,fd;
+	int fd;
 
 	nullpo_retr(0, sd);
 
-	fd=sd->fd;
-	// 名前の登録と送信を先にしておく
-	if( map_charid2nick(sd->status.char_id)==NULL )
-		map_addchariddb(sd->status.char_id,sd->status.name);
-	clif_solved_charname(sd,sd->status.char_id);
-
+	fd = sd->fd;
+	clif_solved_charname(fd, sd->status.char_id, sd->status.name);
 	WFIFOHEAD(fd,packet_len(0x18f));
 	WFIFOW(fd, 0)=0x18f;
 	WFIFOW(fd, 2)=flag;
-	if((view = itemdb_viewid(nameid)) > 0)
-		WFIFOW(fd, 4)=view;
-	else
-		WFIFOW(fd, 4)=nameid;
+	WFIFOW(fd, 4)=(itemdb_viewid(nameid)||nameid);
 	WFIFOSET(fd,packet_len(0x18f));
 	return 0;
 }
@@ -9915,10 +9897,10 @@ void clif_parse_InsertCard(int fd,struct map_session_data *sd)
  *------------------------------------------*/
 void clif_parse_SolveCharName(int fd, struct map_session_data *sd)
 {
-	int char_id;
+	int charid;
 
-	char_id = RFIFOL(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
-	clif_solved_charname(sd, char_id);
+	charid = RFIFOL(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
+	map_reqnickdb(sd, charid);
 }
 
 /*==========================================
@@ -11263,7 +11245,7 @@ void clif_parse_PVPInfo(int fd,struct map_session_data *sd)
 void clif_parse_Blacksmith(int fd,struct map_session_data *sd)
 {
 	int i;
-	char *name;
+	const char* name;
 
 	WFIFOHEAD(fd,packet_len(0x219));
 	WFIFOW(fd,0) = 0x219;
@@ -11306,7 +11288,7 @@ int clif_fame_blacksmith(struct map_session_data *sd, int points)
 void clif_parse_Alchemist(int fd,struct map_session_data *sd)
 {
 	int i;
-	char *name;
+	const char* name;
 
 	WFIFOHEAD(fd,packet_len(0x21a));
 	WFIFOW(fd,0) = 0x21a;
@@ -11349,7 +11331,7 @@ int clif_fame_alchemist(struct map_session_data *sd, int points)
 void clif_parse_Taekwon(int fd,struct map_session_data *sd)
 {
 	int i;
-	char *name;
+	const char* name;
 
 	WFIFOHEAD(fd,packet_len(0x226));
 	WFIFOW(fd,0) = 0x226;

+ 2 - 2
src/map/clif.h

@@ -216,7 +216,7 @@ int clif_skill_memo(struct map_session_data *sd,int flag);
 int clif_skill_teleportmessage(struct map_session_data *sd,int flag);
 int clif_skill_produce_mix_list(struct map_session_data *sd, int trigger);
 
-int clif_produceeffect(struct map_session_data *sd,int flag,int nameid);
+int clif_produceeffect(struct map_session_data* sd,int flag,int nameid);
 
 int clif_skill_setunit(struct skill_unit *unit);
 int clif_skill_delunit(struct skill_unit *unit);
@@ -237,7 +237,7 @@ int clif_status_change(struct block_list *bl,int type,int flag);
 int clif_wis_message(int fd, const char* nick, const char* mes, int mes_len);
 int clif_wis_end(int fd,int flag);
 
-int clif_solved_charname(struct map_session_data *sd,int char_id);
+int clif_solved_charname(int fd, int charid, const char* name);
 int clif_charnameack(int fd, struct block_list *bl);
 int clif_charnameupdate(struct map_session_data *ssd);
 

+ 123 - 61
src/map/map.c

@@ -115,10 +115,11 @@ char *SCRIPT_CONF_NAME;
 char *MSG_CONF_NAME;
 
 // 極力 staticでロ?カルに?める
-static struct dbt * id_db=NULL;
-static struct dbt * pc_db=NULL;
+static struct dbt * id_db=NULL;// id -> struct block_list
+static struct dbt * pc_db=NULL;// id -> struct map_session_data
 static struct dbt * map_db=NULL;
-static struct dbt * charid_db=NULL;
+static struct dbt * nick_db=NULL;// charid -> struct charid2nick (requested names of offline characters)
+static struct dbt * charid_db=NULL;// charid -> struct map_session_data
 
 static int map_users=0;
 static struct block_list *objects[MAX_FLOORITEM];
@@ -143,9 +144,13 @@ int save_settings = 0xFFFF;
 int agit_flag = 0;
 int night_flag = 0; // 0=day, 1=night [Yor]
 
+struct charid_request {
+	struct charid_request* next;
+	int charid;// who want to be notified of the nick
+};
 struct charid2nick {
 	char nick[NAME_LENGTH];
-	int req_id;
+	struct charid_request* requests;// requests of notification on this nick
 };
 
 // This is the main header found at the very beginning of the map cache
@@ -1589,45 +1594,88 @@ int map_addflooritem(struct item *item_data,int amount,int m,int x,int y,int fir
 static void* create_charid2nick(DBKey key, va_list args)
 {
 	struct charid2nick *p;
-	p = (struct charid2nick *)aCallocA(1, sizeof (struct charid2nick));
+	CREATE(p, struct charid2nick, 1);
 	return p;
 }
 
-/*==========================================
- * charid_dbへ追加(返信待ちがあれば返信)
- *------------------------------------------*/
-void map_addchariddb(int charid, char* name)
+/// Adds(or replaces) the nick of charid to nick_db and fullfils pending requests.
+/// Does nothing if the character is online.
+void map_addnickdb(int charid, const char* nick)
 {
 	struct charid2nick* p;
-	int req = 0;
+	struct charid_request* req;
+	struct map_session_data* sd;
+
+	if( map_charid2sd(charid) )
+		return;// already online
 
-	p = idb_ensure(charid_db, charid, create_charid2nick);
-	req = p->req_id;
-	p->req_id = 0;
-	//We overwrite the nick anyway in case a different one arrived.
-	memcpy(p->nick, name, NAME_LENGTH);
+	p = idb_ensure(nick_db, charid, create_charid2nick);
+	safestrncpy(p->nick, nick, sizeof(p->nick));
 
-	if (req) {
-		struct map_session_data* sd = map_id2sd(req);
-		if (sd) clif_solved_charname(sd,charid);
+	while( p->requests )
+	{
+		req = p->requests;
+		p->requests = req->next;
+		sd = map_charid2sd(req->charid);
+		if( sd )
+			clif_solved_charname(sd->fd, charid, p->nick);
+		aFree(req);
 	}
 }
 
-/*==========================================
- * charid_dbへ追加(返信要求のみ)
- *------------------------------------------*/
-int map_reqchariddb(struct map_session_data * sd,int charid)
+/// Removes the nick of charid from nick_db.
+/// Sends name to all pending requests on charid.
+void map_delnickdb(int charid, const char* name)
 {
-	struct charid2nick *p=NULL;
+	struct charid2nick* p;
+	struct charid_request* req;
+	struct map_session_data* sd;
 
-	nullpo_retr(0, sd);
+	p = idb_remove(nick_db, charid);
+	if( p == NULL )
+		return;
 
-	p = (struct charid2nick*)idb_get(charid_db,charid);
-	if(p) return 0; //Nothing to request, we already have the name!
-	p = (struct charid2nick *)aCalloc(1,sizeof(struct charid2nick));
-	p->req_id=sd->bl.id;
-	idb_put(charid_db,charid,p);
-	return 0;
+	while( p->requests )
+	{
+		req = p->requests;
+		p->requests = req->next;
+		sd = map_charid2sd(req->charid);
+		if( sd )
+			clif_solved_charname(sd->fd, charid, name);
+		aFree(req);
+	}
+	aFree(p);
+}
+
+/// Notifies sd of the nick of charid.
+/// Uses the name in the character if online.
+/// Uses the name in nick_db if offline.
+void map_reqnickdb(struct map_session_data * sd, int charid)
+{
+	struct charid2nick* p;
+	struct charid_request* req;
+	struct map_session_data* tsd;
+
+	nullpo_retv(sd);
+
+	tsd = map_charid2sd(charid);
+	if( tsd )
+	{
+		clif_solved_charname(sd->fd, charid, tsd->status.name);
+		return;
+	}
+
+	p = (struct charid2nick*)idb_ensure(nick_db, charid, create_charid2nick);
+	if( *p->nick )
+	{
+		clif_solved_charname(sd->fd, charid, p->nick);
+		return;
+	}
+	// not in cache, request it
+	CREATE(req, struct charid_request, 1);
+	req->next = p->requests;
+	p->requests = req;
+	chrif_searchcharid(charid);
 }
 
 /*==========================================
@@ -1638,7 +1686,11 @@ void map_addiddb(struct block_list *bl)
 	nullpo_retv(bl);
 
 	if (bl->type == BL_PC)
-		idb_put(pc_db,bl->id,bl);
+	{
+		TBL_PC* sd = (TBL_PC*)bl;
+		idb_put(pc_db,sd->bl.id,sd);
+		idb_put(charid_db,sd->status.char_id,sd);
+	}
 	idb_put(id_db,bl->id,bl);
 }
 
@@ -1650,7 +1702,11 @@ void map_deliddb(struct block_list *bl)
 	nullpo_retv(bl);
 
 	if (bl->type == BL_PC)
-		idb_remove(pc_db,bl->id);
+	{
+		TBL_PC* sd = (TBL_PC*)bl;
+		idb_remove(pc_db,sd->bl.id);
+		idb_remove(charid_db,sd->status.char_id);
+	}
 	idb_remove(id_db,bl->id);
 }
 
@@ -1668,9 +1724,7 @@ int map_quit(struct map_session_data *sd)
 		//Double login, let original do the cleanups below.
 		if (sd2 && sd2 != sd)
 			return 0;
-		idb_remove(id_db,sd->bl.id);
-		idb_remove(pc_db,sd->status.account_id);
-		idb_remove(charid_db,sd->status.char_id);
+		map_deliddb(&sd->bl);
 		return 0;
 	}
 	if(!sd->state.waitingdisconnect) {
@@ -1693,8 +1747,6 @@ int map_quit(struct map_session_data *sd)
 			unit_remove_map(&sd->hd->bl, 0);
 	}
 
-	//Do we really need to remove the name?
-	idb_remove(charid_db,sd->status.char_id);
 	idb_remove(id_db,sd->bl.id);
 
 	if(sd->reg)
@@ -1729,6 +1781,7 @@ void map_quit_ack(struct map_session_data *sd)
 {
 	if (sd && sd->state.finalsave) {
 		idb_remove(pc_db,sd->status.account_id);
+		idb_remove(charid_db,sd->status.char_id);
 		aFree(sd);
 	}
 }
@@ -1758,33 +1811,30 @@ struct map_session_data * map_id2sd(int id)
 	return (struct map_session_data*)idb_get(pc_db,id);
 }
 
-/*==========================================
- * char_id番?の名前を探す
- *------------------------------------------*/
-char * map_charid2nick(int id)
-{
-	struct charid2nick *p = (struct charid2nick*)idb_get(charid_db,id);
-
-	if(p==NULL)
-		return NULL;
-	return p->nick;
-}
-
-struct map_session_data * map_charid2sd(int id)
+/// Returns the nick of the target charid or NULL if unknown (requests the nick to the char server).
+const char* map_charid2nick(int charid)
 {
-	int i, users;
-	struct map_session_data **all_sd;
+	struct charid2nick *p;
+	struct map_session_data* sd;
 
-	if (id <= 0) return 0;
+	sd = map_charid2sd(charid);
+	if( sd )
+		return sd->status.name;// character is online, return it's name
 
-	all_sd = map_getallusers(&users);
-	for(i = 0; i < users; i++)
-		if (all_sd[i] && all_sd[i]->status.char_id == id)
-			return all_sd[i];
+	p = (struct charid2nick*)idb_ensure(nick_db, charid, create_charid2nick);
+	if( *p->nick )
+		return p->nick;// name in nick_db
 
+	chrif_searchcharid(charid);// request the name
 	return NULL;
 }
 
+/// Returns the struct map_session_data of the charid or NULL if the char is not online.
+struct map_session_data* map_charid2sd(int charid)
+{
+	return (struct map_session_data*)idb_get(charid_db, charid);
+}
+
 /*==========================================
  * Search session data from a nick name
  * (without sensitive case if necessary)
@@ -3040,10 +3090,20 @@ int map_db_final(DBKey k,void *d,va_list ap)
 	return 0;
 }
 
-int nick_db_final(void *k,void *d,va_list ap)
+int nick_db_final(DBKey key, void *data, va_list args)
 {
-	char *p = (char *) d;
-	if (p) aFree(p);
+	struct charid2nick* p = (struct charid2nick*)data;
+	struct charid_request* req;
+
+	if( p == NULL )
+		return 0;
+	while( p->requests )
+	{
+		req = p->requests;
+		p->requests = req->next;
+		aFree(req);
+	}
+	aFree(p);
 	return 0;
 }
 
@@ -3161,6 +3221,7 @@ void do_final(void)
 
 	id_db->destroy(id_db, NULL);
 	pc_db->destroy(pc_db, NULL);
+	nick_db->destroy(nick_db, nick_db_final);
 	charid_db->destroy(charid_db, NULL);
 
 #ifndef TXT_ONLY
@@ -3197,7 +3258,7 @@ void do_abort(void)
 	if (!chrif_isconnected())
 	{
 		if (pc_db->size(pc_db))
-			ShowFatalError("Server has crashed without a connection to the char-server, character data can't be saved!\n");
+			ShowFatalError("Server has crashed without a connection to the char-server, %u characters can't be saved!\n", pc_db->size(pc_db));
 		return;
 	}
 	ShowError("Server received crash signal! Attempting to save all online characters!\n");
@@ -3339,6 +3400,7 @@ int do_init(int argc, char *argv[])
 	id_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_BASE,sizeof(int));
 	pc_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_BASE,sizeof(int));	//Added for reliable map_id2sd() use. [Skotlex]
 	map_db = db_alloc(__FILE__,__LINE__,DB_UINT,DB_OPT_BASE,sizeof(int));
+	nick_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));
 	charid_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));
 #ifndef TXT_ONLY
 	map_sql_init();

+ 5 - 6
src/map/map.h

@@ -1327,11 +1327,11 @@ int map_removemobs_timer(int,unsigned int,int,int);
 int map_addflooritem(struct item *item_data,int amount,int m,int x,int y,int first_id,int second_id,int third_id,int flags);
 
 // キャラid=>キャラ名 変換関連
-void map_addchariddb(int charid,char *name);
-void map_delchariddb(int charid);
-int map_reqchariddb(struct map_session_data * sd,int charid);
-char * map_charid2nick(int);
-struct map_session_data * map_charid2sd(int);
+void map_addnickdb(int charid, const char* nick);
+void map_delnickdb(int charid, const char* nick);
+void map_reqnickdb(struct map_session_data* sd,int charid);
+const char* map_charid2nick(int charid);
+struct map_session_data* map_charid2sd(int charid);
 
 struct map_session_data * map_id2sd(int);
 struct block_list * map_id2bl(int);
@@ -1346,7 +1346,6 @@ void map_deliddb(struct block_list *bl);
 struct map_session_data** map_getallusers(int *users);
 void map_foreachpc(int (*func)(DBKey,void*,va_list),...);
 int map_foreachiddb(int (*)(DBKey,void*,va_list),...);
-void map_addnickdb(struct map_session_data *);
 struct map_session_data * map_nick2sd(const char*);
 
 // その他

+ 1 - 2
src/map/pc.c

@@ -696,8 +696,7 @@ int pc_authok(struct map_session_data *sd, int login_id2, time_t connect_until_t
 
 	clif_authok(sd);
 	map_addiddb(&sd->bl);
-	if (map_charid2nick(sd->status.char_id) == NULL)
-		map_addchariddb(sd->status.char_id, sd->status.name);
+	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;