summaryrefslogtreecommitdiff
path: root/src/map/map.c
diff options
context:
space:
mode:
authorhemagx <ibrahem.h.basyone@gmail.com>2017-01-16 19:02:15 +0200
committerHaru <haru@dotalux.com>2018-02-17 15:10:12 +0100
commit400076f4e26a121746545cf9f6483ca8e93896b5 (patch)
treea962db573b5483965bcc5e74c127aec08ff350f7 /src/map/map.c
parent59f02f1d406a1238f90d072949ac07279a90e9ea (diff)
downloadhercules-400076f4e26a121746545cf9f6483ca8e93896b5.tar.gz
hercules-400076f4e26a121746545cf9f6483ca8e93896b5.tar.bz2
hercules-400076f4e26a121746545cf9f6483ca8e93896b5.tar.xz
hercules-400076f4e26a121746545cf9f6483ca8e93896b5.zip
New mapcache system
* Now each map is in separated file so now it will be easier to know which map got updated or delete on updates * Now there's md5 checksum check for each map * Now the map cache is platform safe, the old format was not packed which may result in undefined behavior * The map cache tool got converted into hercules plugin Signed-off-by: hemagx <ibrahem.h.basyone@gmail.com>
Diffstat (limited to 'src/map/map.c')
-rw-r--r--src/map/map.c221
1 files changed, 119 insertions, 102 deletions
diff --git a/src/map/map.c b/src/map/map.c
index bb367a08d..780e6f535 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -66,6 +66,7 @@
#include "common/core.h"
#include "common/ers.h"
#include "common/grfio.h"
+#include "common/md5calc.h"
#include "common/memmgr.h"
#include "common/nullpo.h"
#include "common/random.h"
@@ -2899,21 +2900,26 @@ int map_cell2gat(struct mapcell cell) {
ShowWarning("map_cell2gat: cell has no matching gat type\n");
return 1; // default to 'wall'
}
-void map_cellfromcache(struct map_data *m) {
- struct map_cache_map_info *info;
+/**
+ * Extracts a map's cell data from its compressed mapcache.
+ *
+ * @param[in, out] m The target map.
+ */
+void map_cellfromcache(struct map_data *m)
+{
nullpo_retv(m);
- info = (struct map_cache_map_info *)m->cellPos;
- if (info) {
+ if (m->cell_buf.data != NULL) {
char decode_buffer[MAX_MAP_SIZE];
unsigned long size, xy;
int i;
- size = (unsigned long)info->xs*(unsigned long)info->ys;
+ size = (unsigned long)m->xs * (unsigned long)m->ys;
// TO-DO: Maybe handle the scenario, if the decoded buffer isn't the same size as expected? [Shinryo]
- grfio->decode_zip(decode_buffer, &size, m->cellPos+sizeof(struct map_cache_map_info), info->len);
+ grfio->decode_zip(decode_buffer, &size, m->cell_buf.data, m->cell_buf.len);
+
CREATE(m->cell, struct mapcell, size);
// Set cell properties
@@ -3253,97 +3259,125 @@ int map_eraseipport(unsigned short map_index, uint32 ip, uint16 port) {
return 0;
}
-/*==========================================
- * [Shinryo]: Init the mapcache
- *------------------------------------------*/
-char *map_init_mapcache(FILE *fp) {
- struct map_cache_main_header header;
- size_t size = 0;
- char *buffer;
-
- // No file open? Return..
- nullpo_ret(fp);
+/**
+ * Reads a map's compressed cell data from its mapcache file.
+ *
+ * @param[in,out] m The target map.
+ * @return The loading success state.
+ * @retval false in case of errors.
+ */
+bool map_readfromcache(struct map_data *m)
+{
+ unsigned int file_size;
+ char file_path[256];
+ FILE *fp = NULL;
+ bool retval = false;
+ int16 version;
- // Get file size
- fseek(fp, 0, SEEK_END);
- size = ftell(fp);
- fseek(fp, 0, SEEK_SET);
+ nullpo_retr(false, m);
- // Allocate enough space
- CREATE(buffer, char, size);
+ snprintf(file_path, sizeof(file_path), "%s%s%s.%s", "maps/", DBPATH, m->name, "mcache");
+ fp = fopen(file_path, "rb");
- // No memory? Return..
- nullpo_ret(buffer);
+ if (fp == NULL) {
+ ShowWarning("map_readfromcache: Could not open the mapcache file for map '%s' at path '%s'.\n", m->name, file_path);
+ return false;
+ }
- // Read file into buffer..
- if(fread(buffer, sizeof(char), size, fp) != size) {
- ShowError("map_init_mapcache: Could not read entire mapcache file\n");
- aFree(buffer);
- return NULL;
+ if (fread(&version, sizeof(version), 1, fp) < 1) {
+ ShowError("map_readfromcache: Could not read file version for map '%s'.\n", m->name);
+ fclose(fp);
+ return false;
}
- rewind(fp);
+ fseek(fp, 0, SEEK_END);
+ file_size = (unsigned int)ftell(fp);
+ fseek(fp, 0, SEEK_SET); // Rewind file pointer before passing it to the read function.
- // Get main header to verify if data is corrupted
- if( fread(&header, sizeof(header), 1, fp) != 1 ) {
- ShowError("map_init_mapcache: Error obtaining main header!\n");
- aFree(buffer);
- return NULL;
- }
- if( GetULong((unsigned char *)&(header.file_size)) != size ) {
- ShowError("map_init_mapcache: Map cache is corrupted!\n");
- aFree(buffer);
- return NULL;
+ switch(version) {
+ case 1:
+ retval = map->readfromcache_v1(fp, m, file_size);
+ break;
+ default:
+ ShowError("map_readfromcache: Mapcache file has unknown version '%d' for map '%s'.\n", version, m->name);
+ break;
}
- return buffer;
+ fclose(fp);
+ return retval;
}
-/*==========================================
- * Map cache reading
- * [Shinryo]: Optimized some behaviour to speed this up
- *==========================================*/
-int map_readfromcache(struct map_data *m, char *buffer) {
- int i;
- struct map_cache_main_header *header = (struct map_cache_main_header *)buffer;
- struct map_cache_map_info *info = NULL;
- char *p = buffer + sizeof(struct map_cache_main_header);
-
- nullpo_ret(m);
- nullpo_ret(buffer);
-
- for(i = 0; i < header->map_count; i++) {
- info = (struct map_cache_map_info *)p;
+/**
+ * Reads a map's compressed cell data from its mapcache file (file format
+ * version 1).
+ *
+ * @param[in] fp The file pointer to read from (opened and closed by
+ * the caller).
+ * @param[in,out] m The target map.
+ * @param[in] file_size The size of the file to load from.
+ * @return The loading success state.
+ * @retval false in case of errors.
+ */
+bool map_readfromcache_v1(FILE *fp, struct map_data *m, unsigned int file_size)
+{
+ struct map_cache_header mheader = { 0 };
+ uint8 md5buf[16] = { 0 };
+ int map_size;
+ nullpo_retr(false, fp);
+ nullpo_retr(false, m);
+
+ if (file_size <= sizeof(mheader) || fread(&mheader, sizeof(mheader), 1, fp) < 1) {
+ ShowError("map_readfromcache: Failed to read cache header for map '%s'.\n", m->name);
+ return false;
+ }
- if( strcmp(m->name, info->name) == 0 )
- break; // Map found
+ if (mheader.len <= 0) {
+ ShowError("map_readfromcache: A file with negative or zero compressed length passed '%d'.\n", mheader.len);
+ return false;
+ }
- // Jump to next entry..
- p += sizeof(struct map_cache_map_info) + info->len;
+ if (file_size < sizeof(mheader) + mheader.len) {
+ ShowError("map_readfromcache: An incomplete file passed for map '%s'.\n", m->name);
+ return false;
}
- if( info && i < header->map_count ) {
- unsigned long size;
+ if (mheader.ys <= 0 || mheader.xs <= 0) {
+ ShowError("map_readfromcache: A map with invalid size passed '%s' xs: '%d' ys: '%d'.\n", m->name, mheader.xs, mheader.ys);
+ return false;
+ }
- if( info->xs <= 0 || info->ys <= 0 )
- return 0;// Invalid
+ m->xs = mheader.xs;
+ m->ys = mheader.ys;
+ map_size = (int)mheader.xs * (int)mheader.ys;
- m->xs = info->xs;
- m->ys = info->ys;
- size = (unsigned long)info->xs*(unsigned long)info->ys;
+ if (map_size > MAX_MAP_SIZE) {
+ ShowWarning("map_readfromcache: %s exceeded MAX_MAP_SIZE of %d.\n", m->name, MAX_MAP_SIZE);
+ return false;
+ }
- 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]
- }
+ CREATE(m->cell_buf.data, uint8, mheader.len);
+ m->cell_buf.len = mheader.len;
+ if (fread(m->cell_buf.data, mheader.len, 1, fp) < 1) {
+ ShowError("mapreadfromcache: Could not load the compressed cell data for map '%s'.\n", m->name);
+ aFree(m->cell_buf.data);
+ m->cell_buf.data = NULL;
+ m->cell_buf.len = 0;
+ return false;
+ }
- m->cellPos = p;
- m->cell = (struct mapcell *)0xdeadbeaf;
+ md5->binary(m->cell_buf.data, m->cell_buf.len, md5buf);
- return 1;
+ if (memcmp(md5buf, mheader.md5_checksum, sizeof(md5buf)) != 0) {
+ ShowError("mapreadfromcache: md5 checksum check failed for map '%s'\n", m->name);
+ aFree(m->cell_buf.data);
+ m->cell_buf.data = NULL;
+ m->cell_buf.len = 0;
+ return false;
}
- return 0; // Not found
+ m->cell = (struct mapcell *)0xdeadbeaf;
+
+ return true;
}
/**
@@ -3747,26 +3781,12 @@ void map_removemapdb(struct map_data *m) {
*--------------------------------------*/
int map_readallmaps (void) {
int i;
- FILE* fp=NULL;
int maps_removed = 0;
- if( map->enable_grf )
+ if (map->enable_grf) {
ShowStatus("Loading maps (using GRF files)...\n");
- else {
- char mapcachefilepath[256];
- safesnprintf(mapcachefilepath, 256, "%s/%s%s", map->db_path, DBPATH, "map_cache.dat");
- ShowStatus("Loading maps (using %s as map cache)...\n", mapcachefilepath);
- if( (fp = fopen(mapcachefilepath, "rb")) == NULL ) {
- ShowFatalError("Unable to open map cache file "CL_WHITE"%s"CL_RESET"\n", mapcachefilepath);
- 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", mapcachefilepath);
- exit(EXIT_FAILURE);
- }
+ } else {
+ ShowStatus("Loading maps using map cache files...\n");
}
for(i = 0; i < map->count; i++) {
@@ -3780,7 +3800,7 @@ int map_readallmaps (void) {
if( !
(map->enable_grf?
map->readgat(&map->list[i])
- :map->readfromcache(&map->list[i], map->cache_buffer))
+ :map->readfromcache(&map->list[i]))
) {
map->delmapid(i);
maps_removed++;
@@ -3822,10 +3842,6 @@ int map_readallmaps (void) {
// intialization and configuration-dependent adjustments of mapflags
map->flags_init();
- if( !map->enable_grf ) {
- fclose(fp);
- }
-
// finished map loading
ShowInfo("Successfully loaded '"CL_WHITE"%d"CL_RESET"' maps."CL_CLL"\n",map->count);
instance->start_id = map->count; // Next Map Index will be instances
@@ -6062,6 +6078,11 @@ int do_final(void) {
ers_destroy(map->iterator_ers);
ers_destroy(map->flooritem_ers);
+ for (i = 0; i < map->count; ++i) {
+ if (map->list[i].cell_buf.data != NULL)
+ aFree(map->list[i].cell_buf.data);
+ map->list[i].cell_buf.len = 0;
+ }
aFree(map->list);
if( map->block_free )
@@ -6069,9 +6090,6 @@ int do_final(void) {
if( map->bl_list )
aFree(map->bl_list);
- if( !map->enable_grf )
- aFree(map->cache_buffer);
-
aFree(map->MAP_CONF_NAME);
aFree(map->BATTLE_CONF_FILENAME);
aFree(map->ATCOMMAND_CONF_FILENAME);
@@ -6687,7 +6705,6 @@ void map_defaults(void) {
map->list = NULL;
map->iterator_ers = NULL;
- map->cache_buffer = NULL;
map->flooritem_ers = NULL;
/* */
@@ -6834,8 +6851,8 @@ void map_defaults(void) {
map->iwall_nextxy = map_iwall_nextxy;
map->create_map_data_other_server = create_map_data_other_server;
map->eraseallipport_sub = map_eraseallipport_sub;
- map->init_mapcache = map_init_mapcache;
map->readfromcache = map_readfromcache;
+ map->readfromcache_v1 = map_readfromcache_v1;
map->addmap = map_addmap;
map->delmapid = map_delmapid;
map->zone_db_clear = map_zone_db_clear;