From 1b241817a93f892a24379866a06e046e7e6c5e86 Mon Sep 17 00:00:00 2001 From: ultramage Date: Thu, 3 Jan 2008 21:36:40 +0000 Subject: Map cell mechanism rewrite - defined a data structure for map cells (replaces 3 various cell arrays) - both terrain (gat) and dynamic (cell) information is now stored as C-style bit flags instead of #defines and bitmasks - added map_gat2cell() and map_cell2gat() for terrain type conversions - changing terrain information via 'setcell' is temporarily disabled - mapserver startup now takes longer, as it needs to adapt mapcache data to internal representation, cell by cell (new mapcache format anyone?) git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@12003 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/map/map.c | 248 +++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 150 insertions(+), 98 deletions(-) (limited to 'src/map/map.c') diff --git a/src/map/map.c b/src/map/map.c index 0115bb02b..04ff50e23 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -178,6 +178,10 @@ int map_getusers(void) return map_users; } +// +// block削除の安全性確保?理 +// + /*========================================== * blockをfreeするときfreeの?わりに呼ぶ * ロックされているときはバッファにためる @@ -1977,7 +1981,7 @@ int map_mapindex2mapid(unsigned short mapindex) return -1; md = (struct map_data*)uidb_get(map_db,(unsigned int)mapindex); - if(md==NULL || md->gat==NULL) + if(md==NULL || md->cell==NULL) return -1; return md->m; } @@ -1990,7 +1994,7 @@ int map_mapname2ipport(unsigned short name, uint32* ip, uint16* port) struct map_data_other_server *mdos=NULL; mdos = (struct map_data_other_server*)uidb_get(map_db,(unsigned int)name); - if(mdos==NULL || mdos->gat) //If gat isn't null, this is a local map. + if(mdos==NULL || mdos->cell) //If gat isn't null, this is a local map. return -1; *ip=mdos->ip; *port=mdos->port; @@ -2094,7 +2098,41 @@ int map_random_dir(struct block_list *bl, short *x, short *y) } return 0; } + // gat系 +static struct mapcell map_gat2cell(int gat) +{ + struct mapcell cell; + memset(&cell, 0, sizeof(cell)); + + switch( gat ) + { + case 0: cell.walkable = 1; cell.shootable = 1; cell.water = 0; break; // walkable ground + case 1: cell.walkable = 0; cell.shootable = 0; cell.water = 0; break; // non-walkable ground + case 2: cell.walkable = 1; cell.shootable = 1; cell.water = 0; break; // ??? + case 3: cell.walkable = 1; cell.shootable = 1; cell.water = 1; break; // walkable water + case 4: cell.walkable = 1; cell.shootable = 1; cell.water = 0; break; // ??? + case 5: cell.walkable = 0; cell.shootable = 1; cell.water = 0; break; // gap (snipable) + case 6: cell.walkable = 1; cell.shootable = 1; cell.water = 0; break; // ??? + default: + ShowWarning("map_gat2cell: unrecognized gat type '%d'\n", gat); + break; + } + + return cell; +} + +static int map_cell2gat(struct mapcell cell) +{ + if( cell.walkable == 1 && cell.shootable == 1 && cell.water == 0 ) return 0; + if( cell.walkable == 0 && cell.shootable == 0 && cell.water == 0 ) return 1; + if( cell.walkable == 1 && cell.shootable == 1 && cell.water == 1 ) return 3; + if( cell.walkable == 0 && cell.shootable == 1 && cell.water == 0 ) return 5; + + ShowWarning("map_cell2gat: cell has no matching gat type\n"); + return 1; // default to 'wall' +} + /*========================================== * (m,x,y)の状態を調べる *------------------------------------------*/ @@ -2105,70 +2143,76 @@ int map_getcell(int m,int x,int y,cell_t cellchk) int map_getcellp(struct map_data* m,int x,int y,cell_t cellchk) { - int type, type2; -#ifdef CELL_NOSTACK - int type3; -#endif + struct mapcell cell; nullpo_ret(m); + //NOTE: this intentionally overrides the last row and column if(x<0 || x>=m->xs-1 || y<0 || y>=m->ys-1) { if(cellchk==CELL_CHKNOPASS) return 1; return 0; } - type = m->gat[x+y*m->xs]; - type2 = m->cell[x+y*m->xs]; -#ifdef CELL_NOSTACK - type3 = m->cell_bl[x+y*m->xs]; -#endif + + cell = m->cell[x + y*m->xs]; switch(cellchk) { + // gat type retrieval + case CELL_GETTYPE: + return map_cell2gat(cell); + + // base gat type checks + case CELL_CHKWALL: + return (!cell.walkable && !cell.shootable); + //return (map_cell2gat(cell) == 1); + case CELL_CHKWATER: + return (cell.water); + //return (map_cell2gat(cell) == 3); + case CELL_CHKCLIFF: + return (!cell.walkable && cell.shootable); + //return (map_cell2gat(cell) == 5); + + // base cell type checks + case CELL_CHKNPC: + return (cell.npc); + case CELL_CHKPNEUMA: + return (cell.pneuma); + case CELL_CHKSAFETYWALL: + return (cell.safetywall); + case CELL_CHKBASILICA: + return (cell.basilica); + case CELL_CHKLANDPROTECTOR: + return (cell.landprotector); + case CELL_CHKREGEN: + return (cell.regen); + case CELL_CHKICEWALL: + return (cell.icewall); + case CELL_CHKNOVENDING: + return (cell.novending); + + // special checks case CELL_CHKPASS: #ifdef CELL_NOSTACK - if (type3 >= battle_config.cell_stack_limit) return 0; + if (cell.cell_bl >= battle_config.cell_stack_limit) return 0; #endif case CELL_CHKREACH: - return (type!=1 && type!=5 && !(type2&CELL_ICEWALL)); + return (cell.walkable && !cell.icewall); + case CELL_CHKNOPASS: #ifdef CELL_NOSTACK - if (type3 >= battle_config.cell_stack_limit) return 1; + if (cell.cell_bl >= battle_config.cell_stack_limit) return 1; #endif case CELL_CHKNOREACH: - return (type==1 || type==5 || type2&CELL_ICEWALL); + return (!cell.walkable || cell.icewall); + case CELL_CHKSTACK: #ifdef CELL_NOSTACK - return (type3 >= battle_config.cell_stack_limit); + return (cell.cell_bl >= battle_config.cell_stack_limit); #else return 0; #endif - case CELL_CHKWALL: - return (type==1/* || type2&CELL_ICEWALL*/); //Uncomment to prevent sniping/casting through the icewall. [Skotlex] - case CELL_CHKWATER: - return (type==3); - case CELL_CHKGROUND: - return (type==5 || type2&CELL_ICEWALL); - case CELL_GETTYPE: - return type; - case CELL_GETCELLTYPE: - return type2; - case CELL_CHKNPC: - return (type2&CELL_NPC); - case CELL_CHKPNEUMA: - return (type2&CELL_PNEUMA); - case CELL_CHKSAFETYWALL: - return (type2&CELL_SAFETYWALL); - case CELL_CHKBASILICA: - return (type2&CELL_BASILICA); - case CELL_CHKLANDPROTECTOR: - return (type2&CELL_LANDPROTECTOR); - case CELL_CHKREGEN: - return (type2&CELL_REGEN); - case CELL_CHKICEWALL: - return (type2&CELL_ICEWALL); - case CELL_CHKNOVENDING: - return (type2&CELL_NOVENDING); + default: return 0; } @@ -2185,26 +2229,27 @@ void map_setcell(int m,int x,int y,int cell) j=x+y*map[m].xs; switch (cell) { - case CELL_SETNPC: map[m].cell[j] |= CELL_NPC; break; - case CELL_CLRNPC: map[m].cell[j] &= ~CELL_NPC; break; - case CELL_SETICEWALL: map[m].cell[j] |= CELL_ICEWALL; break; - case CELL_CLRICEWALL: map[m].cell[j] &= ~CELL_ICEWALL; break; - case CELL_SETBASILICA: map[m].cell[j] |= CELL_BASILICA; break; - case CELL_CLRBASILICA: map[m].cell[j] &= ~CELL_BASILICA; break; - case CELL_SETPNEUMA: map[m].cell[j] |= CELL_PNEUMA; break; - case CELL_CLRPNEUMA: map[m].cell[j] &= ~CELL_PNEUMA; break; - case CELL_SETSAFETYWALL: map[m].cell[j] |= CELL_SAFETYWALL; break; - case CELL_CLRSAFETYWALL: map[m].cell[j] &= ~CELL_SAFETYWALL; break; - case CELL_SETLANDPROTECTOR: map[m].cell[j] |= CELL_LANDPROTECTOR; break; - case CELL_CLRLANDPROTECTOR: map[m].cell[j] &= ~CELL_LANDPROTECTOR; break; - case CELL_SETREGEN: map[m].cell[j] |= CELL_REGEN; break; - case CELL_SETNOVENDING: map[m].cell[j] |= CELL_NOVENDING; break; - case CELL_CLRNOVENDING: map[m].cell[j] &= ~CELL_NOVENDING; break; + case CELL_SETNPC: map[m].cell[j].npc = 1; break; + case CELL_CLRNPC: map[m].cell[j].npc = 0; break; + case CELL_SETICEWALL: map[m].cell[j].icewall = 1; break; + case CELL_CLRICEWALL: map[m].cell[j].icewall = 0; break; + case CELL_SETBASILICA: map[m].cell[j].basilica = 1; break; + case CELL_CLRBASILICA: map[m].cell[j].basilica = 0; break; + case CELL_SETPNEUMA: map[m].cell[j].pneuma = 1; break; + case CELL_CLRPNEUMA: map[m].cell[j].pneuma = 0; break; + case CELL_SETSAFETYWALL: map[m].cell[j].safetywall = 1; break; + case CELL_CLRSAFETYWALL: map[m].cell[j].safetywall = 0; break; + case CELL_SETLANDPROTECTOR: map[m].cell[j].landprotector = 1; break; + case CELL_CLRLANDPROTECTOR: map[m].cell[j].landprotector = 0; break; + case CELL_SETREGEN: map[m].cell[j].regen = 1; break; + case CELL_SETNOVENDING: map[m].cell[j].novending = 1; break; + case CELL_CLRNOVENDING: map[m].cell[j].novending = 0; break; default: - map[m].gat[j] = cell; + //map[m].gat[j] = cell; FIXME break; } } + static void* create_map_data_other_server(DBKey key, va_list args) { struct map_data_other_server *mdos; @@ -2224,7 +2269,7 @@ int map_setipport(unsigned short mapindex, uint32 ip, uint16 port) mdos=(struct map_data_other_server *)uidb_ensure(map_db,(unsigned int)mapindex, create_map_data_other_server); - if(mdos->gat) //Local map,Do nothing. Give priority to our own local maps over ones from another server. [Skotlex] + if(mdos->cell) //Local map,Do nothing. Give priority to our own local maps over ones from another server. [Skotlex] return 0; if(ip == clif_getip() && port == clif_getport()) { //That's odd, we received info that we are the ones with this map, but... we don't have it. @@ -2242,7 +2287,7 @@ int map_setipport(unsigned short mapindex, uint32 ip, uint16 port) int map_eraseallipport_sub(DBKey key,void *data,va_list va) { struct map_data_other_server *mdos = (struct map_data_other_server*)data; - if(mdos->gat == NULL) { + if(mdos->cell == NULL) { db_remove(map_db,key); aFree(mdos); } @@ -2263,7 +2308,7 @@ int map_eraseipport(unsigned short mapindex, uint32 ip, uint16 port) struct map_data_other_server *mdos; mdos = uidb_get(map_db,(unsigned int)mapindex); - if(!mdos || mdos->gat) //Map either does not exists or is a local map. + if(!mdos || mdos->cell) //Map either does not exists or is a local map. return 0; if(mdos->ip==ip && mdos->port == port) { @@ -2279,32 +2324,49 @@ int map_eraseipport(unsigned short mapindex, uint32 ip, uint16 port) *===========================================*/ int map_readfromcache(struct map_data *m, FILE *fp) { - int i; struct map_cache_main_header header; struct map_cache_map_info info; - unsigned long size; - unsigned char *buf; - - if(!fp) + int i; + + if( !fp ) return 0; fseek(fp, 0, SEEK_SET); fread(&header, sizeof(struct map_cache_main_header), 1, fp); - for(i = 0; i < header.map_count; i++) { + for( i = 0; i < header.map_count; ++i ) + { fread(&info, sizeof(struct map_cache_map_info), 1, fp); - if(strcmp(m->name, info.name) == 0) { // Map found - m->xs = info.xs; - m->ys = info.ys; - m->gat = (unsigned char *)aMalloc(m->xs*m->ys); // Allocate room for map cells data - buf = aMalloc(info.len); // Allocate a temp buffer to read the zipped map - fread(buf, info.len, 1, fp); - size = m->xs*m->ys; - decode_zip(m->gat, &size, buf, info.len); // Unzip the map from the buffer - aFree(buf); - return 1; - } else // Map not found, jump to the beginning of the next map info header - fseek(fp, info.len, SEEK_CUR); + + if( strcmp(m->name, info.name) == 0 ) + break; // Map found + + // Map not found, jump to the beginning of the next map info header + fseek(fp, info.len, SEEK_CUR); + } + + if( i < header.map_count ) + { + unsigned char *buf, *buf2; + unsigned int size, xy; + + m->xs = info.xs; + m->ys = info.ys; + size = info.xs*info.ys; + + buf = aMalloc(info.len); // temp buffer to read the zipped map + buf2 = aMalloc(size); // temp buffer to unpack the data + CREATE(m->cell, struct mapcell, size); + + fread(buf, info.len, 1, fp); + decode_zip(buf2, &size, buf, info.len); // Unzip the map from the buffer + + for( xy = 0; xy < size; ++xy ) + m->cell[xy] = map_gat2cell(buf2[xy]); + + aFree(buf); + aFree(buf2); + return 1; } return 0; @@ -2329,7 +2391,7 @@ int map_addmap(char* mapname) static void map_delmapid(int id) { - ShowNotice("Removing map [ %s ] from maplist\n"CL_CLL,map[id].name); + ShowNotice("Removing map [ %s ] from maplist"CL_CLL"\n",map[id].name); memmove(map+id, map+id+1, sizeof(map[0])*(map_num-id-1)); map_num--; } @@ -2404,7 +2466,7 @@ int map_readgat (struct map_data* m) m->xs = *(int32*)(gat+6); m->ys = *(int32*)(gat+10); num_cells = m->xs * m->ys; - CREATE(m->gat, uint8, num_cells); + CREATE(m->cell, struct mapcell, num_cells); water_height = map_waterheight(m->name); @@ -2420,10 +2482,9 @@ int map_readgat (struct map_data* m) if( type == 0 && water_height != NO_WATER && height > water_height ) type = 3; // Cell is 0 (walkable) but under water level, set to 3 (walkable water) - m->gat[xy] = (uint8)type; - + m->cell[xy] = map_gat2cell(type); } - + aFree(gat); return 1; @@ -2473,10 +2534,10 @@ int map_readallmaps (void) if (uidb_get(map_db,(unsigned int)map[i].index) != NULL) { - ShowWarning("Map %s already loaded!\n"CL_CLL, map[i].name); - if (map[i].gat) { - aFree(map[i].gat); - map[i].gat = NULL; + ShowWarning("Map %s already loaded!"CL_CLL"\n", map[i].name); + if (map[i].cell) { + aFree(map[i].cell); + map[i].cell = NULL; } map_delmapid(i); maps_removed++; @@ -2492,11 +2553,6 @@ int map_readallmaps (void) if(battle_config.pk_mode) map[i].flag.pvp = 1; // make all maps pvp for pk_mode [Valaris] - map[i].cell = (unsigned char *)aCalloc(map[i].xs * map[i].ys, sizeof(unsigned char)); -#ifdef CELL_NOSTACK - map[i].cell_bl = (unsigned char *)aCalloc(map[i].xs * map[i].ys, sizeof(unsigned char)); -#endif - map[i].bxs = (map[i].xs + BLOCK_SIZE - 1) / BLOCK_SIZE; map[i].bys = (map[i].ys + BLOCK_SIZE - 1) / BLOCK_SIZE; @@ -2859,7 +2915,7 @@ int sql_ping_init(void) int map_db_final(DBKey k,void *d,va_list ap) { struct map_data_other_server *mdos = (struct map_data_other_server*)d; - if(mdos && mdos->gat == NULL) + if(mdos && mdos->cell == NULL) aFree(mdos); return 0; } @@ -2977,11 +3033,7 @@ void do_final(void) map_db->destroy(map_db, map_db_final); for (i=0; i