Переглянути джерело

objects[] array removal (bugreport:2559)
- Removed the 2 MB wide static array in favor of a general-purpose DBMap (id_db for now).
- Inlined functions map_addobject, map_delobject and map_delobjectnofree into their callers' code.
- Replaced the free id lookup algorithm from ancient jathena with something more efficient.
- Moved the algorithm to map_get_new_object_id() (similar idea as r13481).

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

ultramage 16 роки тому
батько
коміт
54993d74aa
4 змінених файлів з 48 додано та 133 видалено
  1. 7 3
      src/map/chat.c
  2. 26 120
      src/map/map.c
  3. 3 5
      src/map/map.h
  4. 12 5
      src/map/skill.c

+ 7 - 3
src/map/chat.c

@@ -40,12 +40,12 @@ static struct chat_data* chat_createchat(struct block_list* bl, const char* titl
 	cd->owner = bl;
 	safestrncpy(cd->npc_event, ev, sizeof(cd->npc_event));
 
+	cd->bl.id   = map_get_new_object_id();
 	cd->bl.m    = bl->m;
 	cd->bl.x    = bl->x;
 	cd->bl.y    = bl->y;
 	cd->bl.type = BL_CHAT;
 	cd->bl.next = cd->bl.prev = NULL;
-	cd->bl.id   = map_addobject(&cd->bl);
 
 	if( cd->bl.id == 0 )
 	{
@@ -53,6 +53,8 @@ static struct chat_data* chat_createchat(struct block_list* bl, const char* titl
 		cd = NULL;
 	}
 
+	map_addiddb(&cd->bl);
+
 	return cd;
 }
 
@@ -172,7 +174,8 @@ int chat_leavechat(struct map_session_data* sd, bool kicked)
 	if( cd->users == 0 && cd->owner->type == BL_PC )
 	{	// Delete empty chatroom
 		clif_clearchat(cd, 0);
-		map_delobject(cd->bl.id);
+		map_delblock(&cd->bl);
+		map_freeblock(&cd->bl);
 		return 1;
 	}
 
@@ -323,7 +326,8 @@ int chat_deletenpcchat(struct npc_data* nd)
 	
 	chat_npckickall(cd);
 	clif_clearchat(cd, 0);
-	map_delobject(cd->bl.id);	// free‚܂łµ‚Ä‚­‚ê‚é
+	map_delblock(&cd->bl);
+	map_freeblock(&cd->bl);
 	nd->chat_id = 0;
 	
 	return 0;

+ 26 - 120
src/map/map.c

@@ -102,8 +102,6 @@ static DBMap* charid_db=NULL; // int char_id -> struct map_session_data*
 static DBMap* regen_db=NULL; // int id -> struct block_list* (status_natural_heal processing)
 
 static int map_users=0;
-static struct block_list *objects[MAX_FLOORITEM];
-static int first_free_object_id=0,last_object_id=0;
 
 #define block_free_max 1048576
 struct block_list *block_free[block_free_max];
@@ -1129,124 +1127,38 @@ int map_foreachinmap(int (*func)(struct block_list*,va_list), int m, int type,..
 	return returnCount;
 }
 
-/*==========================================
- * 床アイテムやエフェクト用の一三bj割り?て
- * object[]への保存とid_db登?まで
- *
- * bl->idもこの中で設定して問題無い?
- *------------------------------------------*/
-int map_addobject(struct block_list *bl)
+
+/// Generates a new flooritem object id from the interval [MIN_FLOORITEM, MAX_FLOORITEM).
+/// Used for floor items, skill units and chatroom objects.
+/// @return The new object id
+int map_get_new_object_id(void)
 {
+	static int last_object_id = MIN_FLOORITEM - 1;
 	int i;
-	if( bl == NULL ){
-		ShowWarning("map_addobject nullpo?\n");
-		return 0;
-	}
-	if(first_free_object_id<2 || first_free_object_id>=MAX_FLOORITEM)
-		first_free_object_id=2;
-	for(i=first_free_object_id;i<MAX_FLOORITEM && objects[i];i++);
-	if(i>=MAX_FLOORITEM){
-		ShowWarning("no free object id\n");
-		return 0;
-	}
-	first_free_object_id=i;
-	if(last_object_id<i)
-		last_object_id=i;
-	objects[i]=bl;
-	idb_put(id_db,i,bl);
-	return i;
-}
 
-/*==========================================
- * 一三bjectの解放
- *	map_delobjectのfreeしないバ?ジョン
- *------------------------------------------*/
-int map_delobjectnofree(int id)
-{
-	if( id < 0 || id >= MAX_FLOORITEM )
+	// find a free id
+	i = last_object_id + 1;
+	while( i != last_object_id )
 	{
-		ShowError("map_delobjectnofree: invalid object id '%d'!\n", id);
-		return 0;
-	}
-
-	if(objects[id]==NULL)
-		return 0;
-
-	map_delblock(objects[id]);
-	idb_remove(id_db,id);
-	objects[id]=NULL;
-
-	if(first_free_object_id>id)
-		first_free_object_id=id;
-
-	while(last_object_id>2 && objects[last_object_id]==NULL)
-		last_object_id--;
+		if( i == MAX_FLOORITEM )
+			i = MIN_FLOORITEM;
 
-	return 0;
-}
-
-/*==========================================
- * 一三bjectの解放
- * block_listからの削除、id_dbからの削除
- * object dataのfree、object[]へのNULL代入
- *
- * addとの??性が無いのが?になる
- *------------------------------------------*/
-int map_delobject(int id)
-{
-	struct block_list* bl;
+		if( idb_get(id_db, i) == NULL )
+			break;
 
-	if( id < 0 || id >= MAX_FLOORITEM )
-	{
-		ShowError("map_delobject: invalid object id '%d'!\n", id);
-		return 0;
+		++i;
 	}
 
-	if(objects[id]==NULL)
+	if( i == last_object_id )
+	{
+		ShowError("map_addobject: no free object id!\n");
 		return 0;
-
-	bl = objects[id];
-	map_delobjectnofree(id);
-	map_freeblock(bl);
-
-	return 0;
-}
-
-/*==========================================
- * 全一三bj相手にfuncを呼ぶ
- *
- *------------------------------------------*/
-void map_foreachobject(int (*func)(struct block_list*,va_list),int type,...)
-{
-	int i;
-	int blockcount=bl_list_count;
-
-	for(i=2;i<=last_object_id;i++){
-		if(objects[i]){
-			if(!(objects[i]->type==type)) // Fixed [Lance]
-				continue;
-			if(bl_list_count>=BL_LIST_MAX) {
-				ShowWarning("map_foreachobject: too many blocks !\n");
-				break;
-			}
-			bl_list[bl_list_count++]=objects[i];
-		}
 	}
 
-	map_freeblock_lock();
-
-	for(i=blockcount;i<bl_list_count;i++)
-		if( bl_list[i]->prev || bl_list[i]->next )
-		{
-			va_list ap;
-			va_start(ap, type);
-			func(bl_list[i], ap);
-			va_end(ap);
-		}
-
-	map_freeblock_unlock();
+	// update cursor
+	last_object_id = i;
 
-	bl_list_count = blockcount;
+	return i;
 }
 
 /*==========================================
@@ -1259,9 +1171,7 @@ void map_foreachobject(int (*func)(struct block_list*,va_list),int type,...)
  *------------------------------------------*/
 int map_clearflooritem_timer(int tid, unsigned int tick, int id, intptr data)
 {
-	struct flooritem_data *fitem=NULL;
-
-	fitem = (struct flooritem_data *)objects[id];
+	struct flooritem_data* fitem = idb_get(id_db, id);
 	if(fitem==NULL || fitem->bl.type!=BL_ITEM || (!data && fitem->cleartimer != tid)){
 		ShowError("map_clearflooritem_timer : error\n");
 		return 1;
@@ -1271,7 +1181,8 @@ int map_clearflooritem_timer(int tid, unsigned int tick, int id, intptr data)
 	else if(fitem->item_data.card[0] == CARD0_PET)
 		intif_delete_petdata( MakeDWord(fitem->item_data.card[1],fitem->item_data.card[2]) );
 	clif_clearflooritem(fitem,0);
-	map_delobject(fitem->bl.id);
+	map_delblock(&fitem->bl);
+	map_freeblock(&fitem->bl);
 
 	return 0;
 }
@@ -1414,7 +1325,7 @@ int map_addflooritem(struct item *item_data,int amount,int m,int x,int y,int fir
 	fitem->bl.m=m;
 	fitem->bl.x=x;
 	fitem->bl.y=y;
-	fitem->bl.id = map_addobject(&fitem->bl);
+	fitem->bl.id = map_get_new_object_id();
 	if(fitem->bl.id==0){
 		aFree(fitem);
 		return 0;
@@ -1433,6 +1344,7 @@ int map_addflooritem(struct item *item_data,int amount,int m,int x,int y,int fir
 	fitem->suby=((r>>2)&3)*3+3;
 	fitem->cleartimer=add_timer(gettick()+battle_config.flooritem_lifetime,map_clearflooritem_timer,fitem->bl.id,0);
 
+	map_addiddb(&fitem->bl);
 	map_addblock(&fitem->bl);
 	clif_dropflooritem(fitem);
 
@@ -1765,13 +1677,7 @@ struct map_session_data * map_nick2sd(const char *nick)
  *------------------------------------------*/
 struct block_list * map_id2bl(int id)
 {
-	struct block_list *bl;
-	if(id >= 0 && id < ARRAYLENGTH(objects))
-		bl = objects[id];
-	else
-		bl = (struct block_list*)idb_get(id_db,id);
-
-	return bl;
+	return (struct block_list*)idb_get(id_db,id);
 }
 
 /*==========================================

+ 3 - 5
src/map/map.h

@@ -38,7 +38,8 @@ struct item_data;
 #define MAX_EVENTQUEUE 2
 #define MAX_EVENTTIMER 32
 #define NATURAL_HEAL_INTERVAL 500
-#define MAX_FLOORITEM 500000
+#define MIN_FLOORITEM 2
+#define MAX_FLOORITEM START_ACCOUNT_NUM
 #define MAX_LEVEL 99
 #define MAX_DROP_PER_MAP 48
 #define MAX_IGNORE_LIST 20 // official is 14
@@ -535,10 +536,7 @@ int map_foreachinmap(int (*func)(struct block_list*,va_list), int m, int type, .
 int map_count_oncell(int m,int x,int y,int type);
 struct skill_unit *map_find_skill_unit_oncell(struct block_list *,int x,int y,int skill_id,struct skill_unit *);
 // ˆêŽž“IobjectŠÖ˜A
-int map_addobject(struct block_list *);
-int map_delobject(int);
-int map_delobjectnofree(int id);
-void map_foreachobject(int (*)(struct block_list*,va_list),int,...);
+int map_get_new_object_id(void);
 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 *);

+ 12 - 5
src/map/skill.c

@@ -9504,7 +9504,7 @@ struct skill_unit *skill_initunit (struct skill_unit_group *group, int idx, int
 	if(!unit->alive)
 		group->alive_count++;
 
-	unit->bl.id=map_addobject(&unit->bl);
+	unit->bl.id=map_get_new_object_id();
 	unit->bl.type=BL_SKILL;
 	unit->bl.m=group->map;
 	unit->bl.x=x;
@@ -9514,6 +9514,7 @@ struct skill_unit *skill_initunit (struct skill_unit_group *group, int idx, int
 	unit->val1=val1;
 	unit->val2=val2;
 
+	map_addiddb(&unit->bl);
 	map_addblock(&unit->bl);
 
 	// perform oninit actions
@@ -9583,7 +9584,7 @@ int skill_delunit (struct skill_unit* unit)
 
 	unit->group=NULL;
 	unit->alive=0;
-	map_delobjectnofree(unit->bl.id);
+	map_delblock(&unit->bl); // don't free yet
 	if(--group->alive_count==0)
 		skill_delunitgroup(NULL, group);
 
@@ -9851,11 +9852,17 @@ int skill_unit_timer_sub_onplace (struct block_list* bl, va_list ap)
  *------------------------------------------*/
 int skill_unit_timer_sub (struct block_list* bl, va_list ap)
 {
-	struct skill_unit* unit = (struct skill_unit *)bl;
-	struct skill_unit_group* group = unit->group;
 	unsigned int tick = va_arg(ap,unsigned int);
+	struct skill_unit* unit;
+	struct skill_unit_group* group;
   	bool dissonance;
 
+	if( bl->type != BL_SKILL )
+		return 0;
+
+	unit = (struct skill_unit *)bl;
+	group = unit->group;
+
 	if( !unit->alive )
 		return 0;
 
@@ -10011,7 +10018,7 @@ int skill_unit_timer(int tid, unsigned int tick, int id, intptr data)
 {
 	map_freeblock_lock();
 
-	map_foreachobject( skill_unit_timer_sub, BL_SKILL, tick );
+	map_foreachiddb( skill_unit_timer_sub, tick );
 
 	map_freeblock_unlock();