From e8218a6e7a252c5c08b51fb584dbe2c144ba9326 Mon Sep 17 00:00:00 2001 From: Skotlex Date: Mon, 16 Aug 2010 19:16:14 +0000 Subject: - Merged Shinryo's patch to speed up map-cache loading. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@14377 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 2 + src/map/map.c | 118 +++++++++++++++++++++++++++++++++++----------------- src/map/map.h | 1 + 3 files changed, 83 insertions(+), 38 deletions(-) diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index dbb6872e1..1f551c6a6 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -3,6 +3,8 @@ 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. +2010/08/16 + * Merged Shinryo's patch which speeds up map-cache loading (with a few changes, see eA forum thread #253218 for details) [Skotlex] 2010/08/14 * Rev. 14373 Quest log kill count now updated properly. (Added from topic 253813) [L0ne_W0lf] 2010/08/11 diff --git a/src/map/map.c b/src/map/map.c index fb488cf15..909566243 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -2331,11 +2331,9 @@ int map_random_dir(struct block_list *bl, short *x, short *y) } // gatŒn -static struct mapcell map_gat2cell(int gat) +inline static struct mapcell map_gat2cell(int gat) { - struct mapcell cell; - memset(&cell, 0, sizeof(cell)); - + struct mapcell cell = {0}; switch( gat ) { case 0: cell.walkable = 1; cell.shootable = 1; cell.water = 0; break; // walkable ground @@ -2669,60 +2667,86 @@ int map_eraseipport(unsigned short mapindex, uint32 ip, uint16 port) return 0; } +/*========================================== + * [Shinryo]: Init and free the mapcache + *------------------------------------------*/ +char *map_init_mapcache(FILE *fp) +{ + size_t size = 0, read_size; + char *buffer; + + // No file open? Return.. + nullpo_ret(fp); + + // Get file size + fseek(fp, 0, SEEK_END); + size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + // Allocate enough space + CREATE(buffer, unsigned char, size); + + // No memory? Return.. + nullpo_ret(buffer); + + // Read file into buffer.. + if((read_size = fread(buffer, sizeof(char), size, fp)) != size) { + ShowError("map_init_mapcache: Could not read entire mapcache file\n"); + return NULL; + } + + return buffer; +} + /*========================================== * Map cache reading + * [Shinryo]: Optimized some behaviour to speed this up *==========================================*/ -int map_readfromcache(struct map_data *m, FILE *fp) +int map_readfromcache(struct map_data *m, char *buffer, char *decode_buffer) { - struct map_cache_main_header header; - struct map_cache_map_info info; int i; - - if( !fp ) - return 0; - - fseek(fp, 0, SEEK_SET); - fread(&header, sizeof(struct map_cache_main_header), 1, fp); + struct map_cache_main_header *header = (struct map_cache_main_header *)buffer; + struct map_cache_map_info *info; + unsigned char *p = buffer + sizeof(struct map_cache_main_header); - for( i = 0; i < header.map_count; ++i ) - { - fread(&info, sizeof(struct map_cache_map_info), 1, fp); + for(i = 0; i < header->map_count; i++) { + info = (struct map_cache_map_info *)p; - if( strcmp(m->name, info.name) == 0 ) + 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); + // Jump to next entry.. + p += sizeof(struct map_cache_map_info) + info->len; } - if( i < header.map_count ) - { - unsigned char *buf, *buf2; + if( i < header->map_count ) { unsigned long size, xy; - if( info.xs <= 0 || info.ys <= 0 ) - return 0;// invalid + if( info->xs <= 0 || info->ys <= 0 ) + return 0;// Invalid - m->xs = info.xs; - m->ys = info.ys; - size = (unsigned long)info.xs*(unsigned long)info.ys; + m->xs = info->xs; + m->ys = info->ys; + size = (unsigned long)info->xs*(unsigned long)info->ys; + + if(size > MAX_MAP_SIZE) { + ShowWarning("map_readfromcache: %s exceeded MAX_MAP_SIZE of %d\n", info->name, MAX_MAP_SIZE); + return 0; // Say not found to remove it from list.. [Shinryo] + } + + // TO-DO: Maybe handle the scenario, if the decoded buffer isn't the same size as expected? [Shinryo] + decode_zip(decode_buffer, &size, p+sizeof(struct map_cache_map_info), info->len); - buf = (unsigned char*)aMalloc(info.len); // temp buffer to read the zipped map - buf2 = (unsigned char*)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]); + m->cell[xy] = map_gat2cell(decode_buffer[xy]); - aFree(buf); - aFree(buf2); return 1; } - return 0;// not found + return 0; // Not found } int map_addmap(char* mapname) @@ -2867,6 +2891,8 @@ int map_readallmaps (void) int i; FILE* fp=NULL; int maps_removed = 0; + unsigned char *map_cache_buffer; // Has the uncompressed gat data of all maps, so just one allocation has to be made + unsigned char map_cache_decode_buffer[MAX_MAP_SIZE]; if( enable_grf ) ShowStatus("Loading maps (using GRF files)...\n"); @@ -2878,20 +2904,32 @@ int map_readallmaps (void) ShowFatalError("Unable to open map cache file "CL_WHITE"%s"CL_RESET"\n", map_cache_file); exit(EXIT_FAILURE); //No use launching server if maps can't be read. } + + // Init mapcache data.. [Shinryo] + map_cache_buffer = map_init_mapcache(fp); + if(!map_cache_buffer) { + ShowFatalError("Failed to initialize mapcache data (%s)..\n", map_cache_file); + exit(EXIT_FAILURE); + } } + // Mapcache reading is now fast enough, the progress info will just slow it down so don't use it anymore [Shinryo] + if(!enable_grf) + ShowStatus("Loading maps (%d)..\n", map_num); + for(i = 0; i < map_num; i++) { size_t size; // show progress - ShowStatus("Loading maps [%i/%i]: %s"CL_CLL"\r", i, map_num, map[i].name); + if(enable_grf) + ShowStatus("Loading maps [%i/%i]: %s"CL_CLL"\r", i, map_num, map[i].name); // try to load the map if( ! (enable_grf? map_readgat(&map[i]) - :map_readfromcache(&map[i], fp)) + :map_readfromcache(&map[i], map_cache_buffer, map_cache_decode_buffer)) ) { map_delmapid(i); maps_removed++; @@ -2934,9 +2972,13 @@ int map_readallmaps (void) map[i].block_mob = (struct block_list**)aCalloc(size, 1); } - if( !enable_grf ) + if( !enable_grf ) { fclose(fp); + // The cache isn't needed anymore, so free it.. [Shinryo] + aFree(map_cache_buffer); + } + // finished map loading ShowInfo("Successfully loaded '"CL_WHITE"%d"CL_RESET"' maps."CL_CLL"\n",map_num); instance_start = map_num; // Next Map Index will be instances diff --git a/src/map/map.h b/src/map/map.h index d76b7fabe..f5da4a437 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -44,6 +44,7 @@ struct item_data; #define MAX_DROP_PER_MAP 48 #define MAX_IGNORE_LIST 20 // official is 14 #define MAX_VENDING 12 +#define MAX_MAP_SIZE 512*512 // Wasn't there something like this already? Can't find it.. [Shinryo] #define MOBID_EMPERIUM 1288 // Added definitions for WoESE objects. [L0ne_W0lf] #define MOBID_BARRICADE1 1905 -- cgit v1.2.3-60-g2f50