summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changelog-Trunk.txt2
-rw-r--r--src/map/map.c118
-rw-r--r--src/map/map.h1
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
@@ -2670,59 +2668,85 @@ int map_eraseipport(unsigned short mapindex, uint32 ip, uint16 port)
}
/*==========================================
+ * [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