summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/HPMDataCheck.h3
-rw-r--r--src/map/map.c221
-rw-r--r--src/map/map.h32
-rw-r--r--src/plugins/HPMHooking/HPMHooking.Defs.inc8
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc8
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc2
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.Hooks.inc52
-rw-r--r--src/plugins/mapcache.c384
-rw-r--r--src/tool/Makefile.in23
-rw-r--r--src/tool/mapcache.c377
10 files changed, 561 insertions, 549 deletions
diff --git a/src/common/HPMDataCheck.h b/src/common/HPMDataCheck.h
index fe4745e79..4bcb33e23 100644
--- a/src/common/HPMDataCheck.h
+++ b/src/common/HPMDataCheck.h
@@ -524,8 +524,7 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
{ "charid_request", sizeof(struct charid_request), SERVER_TYPE_MAP },
{ "flooritem_data", sizeof(struct flooritem_data), SERVER_TYPE_MAP },
{ "iwall_data", sizeof(struct iwall_data), SERVER_TYPE_MAP },
- { "map_cache_main_header", sizeof(struct map_cache_main_header), SERVER_TYPE_MAP },
- { "map_cache_map_info", sizeof(struct map_cache_map_info), SERVER_TYPE_MAP },
+ { "map_cache_header", sizeof(struct map_cache_header), SERVER_TYPE_MAP },
{ "map_data", sizeof(struct map_data), SERVER_TYPE_MAP },
{ "map_data_other_server", sizeof(struct map_data_other_server), SERVER_TYPE_MAP },
{ "map_drop_list", sizeof(struct map_drop_list), SERVER_TYPE_MAP },
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;
diff --git a/src/map/map.h b/src/map/map.h
index facf1d921..5c4c6d59d 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -909,7 +909,10 @@ struct map_data {
/* */
int (*getcellp)(struct map_data* m, const struct block_list *bl, int16 x, int16 y, cell_chk cellchk);
void (*setcell) (int16 m, int16 x, int16 y, cell_t cell, bool flag);
- char *cellPos;
+ struct {
+ uint8 *data;
+ int len;
+ } cell_buf;
/* ShowEvent Data Cache */
struct questinfo *qi_data;
@@ -1064,20 +1067,20 @@ struct charid2nick {
struct charid_request* requests;// requests of notification on this nick
};
-// This is the main header found at the very beginning of the map cache
-struct map_cache_main_header {
- uint32 file_size;
- uint16 map_count;
-};
-
-// This is the header appended before every compressed map cells info in the map cache
-struct map_cache_map_info {
- char name[MAP_NAME_LENGTH];
+// New mcache file format header
+#if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute
+#pragma pack(push, 1)
+#endif // not NetBSD < 6 / Solaris
+struct map_cache_header {
+ int16 version;
+ uint8 md5_checksum[16];
int16 xs;
int16 ys;
int32 len;
-};
-
+} __attribute__((packed));
+#if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute
+#pragma pack(pop)
+#endif // not NetBSD < 6 / Solaris
/*=====================================
* Interface : map.h
@@ -1167,7 +1170,6 @@ END_ZEROED_BLOCK;
struct map_data *list;
/* [Ind/Hercules] */
struct eri *iterator_ers;
- char *cache_buffer; // Has the uncompressed gat data of all maps, so just one allocation has to be made
/* */
struct eri *flooritem_ers;
/* */
@@ -1317,8 +1319,8 @@ END_ZEROED_BLOCK;
void (*iwall_nextxy) (int16 x, int16 y, int8 dir, int pos, int16 *x1, int16 *y1);
struct DBData (*create_map_data_other_server) (union DBKey key, va_list args);
int (*eraseallipport_sub) (union DBKey key, struct DBData *data, va_list va);
- char* (*init_mapcache) (FILE *fp);
- int (*readfromcache) (struct map_data *m, char *buffer);
+ bool (*readfromcache) (struct map_data *m);
+ bool (*readfromcache_v1) (FILE *fp, struct map_data *m, unsigned int file_size);
int (*addmap) (const char *mapname);
void (*delmapid) (int id);
void (*zone_db_clear) (void);
diff --git a/src/plugins/HPMHooking/HPMHooking.Defs.inc b/src/plugins/HPMHooking/HPMHooking.Defs.inc
index daa6f0a9f..822faa0cd 100644
--- a/src/plugins/HPMHooking/HPMHooking.Defs.inc
+++ b/src/plugins/HPMHooking/HPMHooking.Defs.inc
@@ -4304,10 +4304,10 @@ typedef struct DBData (*HPMHOOK_pre_map_create_map_data_other_server) (union DBK
typedef struct DBData (*HPMHOOK_post_map_create_map_data_other_server) (struct DBData retVal___, union DBKey key, va_list args);
typedef int (*HPMHOOK_pre_map_eraseallipport_sub) (union DBKey *key, struct DBData **data, va_list va);
typedef int (*HPMHOOK_post_map_eraseallipport_sub) (int retVal___, union DBKey key, struct DBData *data, va_list va);
-typedef char* (*HPMHOOK_pre_map_init_mapcache) (FILE **fp);
-typedef char* (*HPMHOOK_post_map_init_mapcache) (char* retVal___, FILE *fp);
-typedef int (*HPMHOOK_pre_map_readfromcache) (struct map_data **m, char **buffer);
-typedef int (*HPMHOOK_post_map_readfromcache) (int retVal___, struct map_data *m, char *buffer);
+typedef bool (*HPMHOOK_pre_map_readfromcache) (struct map_data **m);
+typedef bool (*HPMHOOK_post_map_readfromcache) (bool retVal___, struct map_data *m);
+typedef bool (*HPMHOOK_pre_map_readfromcache_v1) (FILE **fp, struct map_data **m, unsigned int *file_size);
+typedef bool (*HPMHOOK_post_map_readfromcache_v1) (bool retVal___, FILE *fp, struct map_data *m, unsigned int file_size);
typedef int (*HPMHOOK_pre_map_addmap) (const char **mapname);
typedef int (*HPMHOOK_post_map_addmap) (int retVal___, const char *mapname);
typedef void (*HPMHOOK_pre_map_delmapid) (int *id);
diff --git a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc
index a06c1f1bd..9d531e370 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc
@@ -3356,10 +3356,10 @@ struct {
struct HPMHookPoint *HP_map_create_map_data_other_server_post;
struct HPMHookPoint *HP_map_eraseallipport_sub_pre;
struct HPMHookPoint *HP_map_eraseallipport_sub_post;
- struct HPMHookPoint *HP_map_init_mapcache_pre;
- struct HPMHookPoint *HP_map_init_mapcache_post;
struct HPMHookPoint *HP_map_readfromcache_pre;
struct HPMHookPoint *HP_map_readfromcache_post;
+ struct HPMHookPoint *HP_map_readfromcache_v1_pre;
+ struct HPMHookPoint *HP_map_readfromcache_v1_post;
struct HPMHookPoint *HP_map_addmap_pre;
struct HPMHookPoint *HP_map_addmap_post;
struct HPMHookPoint *HP_map_delmapid_pre;
@@ -9637,10 +9637,10 @@ struct {
int HP_map_create_map_data_other_server_post;
int HP_map_eraseallipport_sub_pre;
int HP_map_eraseallipport_sub_post;
- int HP_map_init_mapcache_pre;
- int HP_map_init_mapcache_post;
int HP_map_readfromcache_pre;
int HP_map_readfromcache_post;
+ int HP_map_readfromcache_v1_pre;
+ int HP_map_readfromcache_v1_post;
int HP_map_addmap_pre;
int HP_map_addmap_post;
int HP_map_delmapid_pre;
diff --git a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc
index a0d8e452a..5551668d2 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc
@@ -1720,8 +1720,8 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(map->iwall_nextxy, HP_map_iwall_nextxy) },
{ HP_POP(map->create_map_data_other_server, HP_map_create_map_data_other_server) },
{ HP_POP(map->eraseallipport_sub, HP_map_eraseallipport_sub) },
- { HP_POP(map->init_mapcache, HP_map_init_mapcache) },
{ HP_POP(map->readfromcache, HP_map_readfromcache) },
+ { HP_POP(map->readfromcache_v1, HP_map_readfromcache_v1) },
{ HP_POP(map->addmap, HP_map_addmap) },
{ HP_POP(map->delmapid, HP_map_delmapid) },
{ HP_POP(map->zone_db_clear, HP_map_zone_db_clear) },
diff --git a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
index 7e4b7c293..f42f8fc1c 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
@@ -44370,15 +44370,15 @@ int HP_map_eraseallipport_sub(union DBKey key, struct DBData *data, va_list va)
}
return retVal___;
}
-char* HP_map_init_mapcache(FILE *fp) {
+bool HP_map_readfromcache(struct map_data *m) {
int hIndex = 0;
- char* retVal___ = NULL;
- if (HPMHooks.count.HP_map_init_mapcache_pre > 0) {
- char* (*preHookFunc) (FILE **fp);
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_map_readfromcache_pre > 0) {
+ bool (*preHookFunc) (struct map_data **m);
*HPMforce_return = false;
- for (hIndex = 0; hIndex < HPMHooks.count.HP_map_init_mapcache_pre; hIndex++) {
- preHookFunc = HPMHooks.list.HP_map_init_mapcache_pre[hIndex].func;
- retVal___ = preHookFunc(&fp);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_map_readfromcache_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_map_readfromcache_pre[hIndex].func;
+ retVal___ = preHookFunc(&m);
}
if (*HPMforce_return) {
*HPMforce_return = false;
@@ -44386,26 +44386,26 @@ char* HP_map_init_mapcache(FILE *fp) {
}
}
{
- retVal___ = HPMHooks.source.map.init_mapcache(fp);
+ retVal___ = HPMHooks.source.map.readfromcache(m);
}
- if (HPMHooks.count.HP_map_init_mapcache_post > 0) {
- char* (*postHookFunc) (char* retVal___, FILE *fp);
- for (hIndex = 0; hIndex < HPMHooks.count.HP_map_init_mapcache_post; hIndex++) {
- postHookFunc = HPMHooks.list.HP_map_init_mapcache_post[hIndex].func;
- retVal___ = postHookFunc(retVal___, fp);
+ if (HPMHooks.count.HP_map_readfromcache_post > 0) {
+ bool (*postHookFunc) (bool retVal___, struct map_data *m);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_map_readfromcache_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_map_readfromcache_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, m);
}
}
return retVal___;
}
-int HP_map_readfromcache(struct map_data *m, char *buffer) {
+bool HP_map_readfromcache_v1(FILE *fp, struct map_data *m, unsigned int file_size) {
int hIndex = 0;
- int retVal___ = 0;
- if (HPMHooks.count.HP_map_readfromcache_pre > 0) {
- int (*preHookFunc) (struct map_data **m, char **buffer);
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_map_readfromcache_v1_pre > 0) {
+ bool (*preHookFunc) (FILE **fp, struct map_data **m, unsigned int *file_size);
*HPMforce_return = false;
- for (hIndex = 0; hIndex < HPMHooks.count.HP_map_readfromcache_pre; hIndex++) {
- preHookFunc = HPMHooks.list.HP_map_readfromcache_pre[hIndex].func;
- retVal___ = preHookFunc(&m, &buffer);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_map_readfromcache_v1_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_map_readfromcache_v1_pre[hIndex].func;
+ retVal___ = preHookFunc(&fp, &m, &file_size);
}
if (*HPMforce_return) {
*HPMforce_return = false;
@@ -44413,13 +44413,13 @@ int HP_map_readfromcache(struct map_data *m, char *buffer) {
}
}
{
- retVal___ = HPMHooks.source.map.readfromcache(m, buffer);
+ retVal___ = HPMHooks.source.map.readfromcache_v1(fp, m, file_size);
}
- if (HPMHooks.count.HP_map_readfromcache_post > 0) {
- int (*postHookFunc) (int retVal___, struct map_data *m, char *buffer);
- for (hIndex = 0; hIndex < HPMHooks.count.HP_map_readfromcache_post; hIndex++) {
- postHookFunc = HPMHooks.list.HP_map_readfromcache_post[hIndex].func;
- retVal___ = postHookFunc(retVal___, m, buffer);
+ if (HPMHooks.count.HP_map_readfromcache_v1_post > 0) {
+ bool (*postHookFunc) (bool retVal___, FILE *fp, struct map_data *m, unsigned int file_size);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_map_readfromcache_v1_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_map_readfromcache_v1_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, fp, m, file_size);
}
}
return retVal___;
diff --git a/src/plugins/mapcache.c b/src/plugins/mapcache.c
new file mode 100644
index 000000000..f1dab97c1
--- /dev/null
+++ b/src/plugins/mapcache.c
@@ -0,0 +1,384 @@
+/**
+* This file is part of Hercules.
+* http://herc.ws - http://github.com/HerculesWS/Hercules
+*
+* Copyright (C) 2013-2015 Hercules Dev Team
+*
+* Hercules is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * Mapcache Plugin
+ * This Plugin is made to handle the creation and update the new format of mapcache
+ * it also handles the convertion from the old to the new mapcache format
+ **/
+
+#include "common/hercules.h" /* Should always be the first Hercules file included! (if you don't make it first, you won't be able to use interfaces) */
+
+#include "common/memmgr.h"
+#include "common/md5calc.h"
+#include "common/nullpo.h"
+#include "common/grfio.h"
+#include "common/utils.h"
+#include "map/map.h"
+
+#include "common/HPMDataCheck.h" /* should always be the last Hercules file included! (if you don't make it last, it'll intentionally break compile time) */
+
+#include <stdio.h>
+#include <string.h>
+
+HPExport struct hplugin_info pinfo = {
+ "Mapcache", ///< Plugin name
+ SERVER_TYPE_MAP, ///< Which server types this plugin works with?
+ "1.0.0", ///< Plugin version
+ HPM_VERSION, ///< HPM Version (don't change, macro is automatically updated)
+};
+
+/**
+ * Yes.. old mapcache was never packed, and we loaded and wrote a compiler paded structs
+ * DON'T BLAME IF SOMETHING EXPLODED [hemagx]
+ **/
+// This is the main header found at the very beginning of the map cache
+struct old_mapcache_main_header {
+ uint32 file_size;
+ uint16 map_count;
+};
+
+// This is the header appended before every compressed map cells info in the map cache
+struct old_mapcache_map_info {
+ char name[MAP_NAME_LENGTH];
+ int16 xs;
+ int16 ys;
+ int32 len;
+};
+
+/**
+ *
+ */
+
+#define NO_WATER 1000000
+
+VECTOR_DECL(char *) maplist;
+bool needs_grfio;
+
+
+/**
+ * code from utlis.c until it's interfaced
+ **/
+
+#ifdef WIN32
+# ifndef F_OK
+# define F_OK 0x0
+# endif /* F_OK */
+#else
+# include <unistd.h>
+#endif
+
+
+// Reads an uint32 in little-endian from the buffer
+uint32 GetULong(const unsigned char* buf)
+{
+ return (((uint32)(buf[0])))
+ | (((uint32)(buf[1])) << 0x08)
+ | (((uint32)(buf[2])) << 0x10)
+ | (((uint32)(buf[3])) << 0x18);
+}
+
+// Reads a float (32 bits) from the buffer
+float GetFloat(const unsigned char* buf)
+{
+ uint32 val = GetULong(buf);
+ return *((float*)(void*)&val);
+}
+
+bool write_mapcache(const uint8 *buf, int32 buf_len, bool is_compressed, const char *mapname, int16 xs, int16 ys)
+{
+ struct map_cache_header header = { 0 };
+ char file_path[255];
+ int mapname_len;
+ unsigned long compressed_buf_len;
+ uint8 *compressed_buf = NULL;
+ FILE *new_mapcache_fp;
+
+ nullpo_retr(false, buf);
+ nullpo_retr(false, mapname);
+
+ mapname_len = (int)strlen(mapname);
+
+ if (mapname_len > MAP_NAME_LENGTH || mapname_len < 1) {
+ ShowError("write_mapcache: A map with invalid name length has beed passed '%s' size (%d)\n", mapname, mapname_len);
+ return false;
+ }
+
+ if ((xs < 0 || ys < 0)) {
+ ShowError("write_mapcache: '%s' given with invalid coords xs = %d, ys = %d\n", mapname, xs, ys);
+ return false;
+ }
+
+ if (((int)xs * ys) > MAX_MAP_SIZE) {
+ ShowError("write_mapcache: map '%s' exceeded MAX_MAP_SIZE of %d\n", mapname, MAX_MAP_SIZE);
+ return false;
+ }
+
+
+
+ snprintf(file_path, sizeof(file_path), "%s%s%s.%s", "maps/", DBPATH, mapname, "mcache");
+ new_mapcache_fp = fopen(file_path, "wb");
+
+ if (new_mapcache_fp == NULL) {
+ ShowWarning("Could not open file '%s', map cache creating failed.\n", file_path);
+ return false;
+ }
+
+ header.version = 0x1;
+ header.xs = xs;
+ header.ys = ys;
+
+ if (is_compressed == false) {
+ compressed_buf_len = buf_len * 2; //Creating big enough buffer to ensure ability to hold compressed data
+ CREATE(compressed_buf, uint8, compressed_buf_len);
+ grfio->encode_zip(compressed_buf, &compressed_buf_len, buf, buf_len);
+
+ header.len = (int)compressed_buf_len;
+ md5->binary(compressed_buf, (int)compressed_buf_len, header.md5_checksum);
+ } else {
+ header.len = buf_len;
+ md5->binary(buf, buf_len, header.md5_checksum);
+ }
+
+
+ fwrite(&header, sizeof(header), 1, new_mapcache_fp);
+ if (is_compressed == false)
+ fwrite(compressed_buf, compressed_buf_len, 1, new_mapcache_fp);
+ else
+ fwrite(buf, buf_len, 1, new_mapcache_fp);
+
+ fclose(new_mapcache_fp);
+ if (compressed_buf != NULL)
+ aFree(compressed_buf);
+
+ return true;
+}
+
+bool convert_old_mapcache(void)
+{
+ const char *path = "db/"DBPATH"map_cache.dat";
+ FILE *mapcache_fp = fopen(path, "rb");
+ struct old_mapcache_main_header header = { 0 };
+ uint8 *p, *cursor;
+ uint32 file_size;
+ int i;
+
+ if (mapcache_fp == NULL) {
+ ShowError("Could not open mapcache file in the following path '%s' \n", path);
+ return false;
+ }
+
+ if (fread(&header, sizeof(header), 1, mapcache_fp) != 1) {
+ ShowError("Failed to read mapcache header \n");
+ fclose(mapcache_fp);
+ return false;
+ }
+
+ fseek(mapcache_fp, 0, SEEK_END);
+ file_size = (int)ftell(mapcache_fp);
+ fseek(mapcache_fp, 0, SEEK_SET);
+
+ if (file_size != header.file_size) {
+ ShowError("File size in mapcache header doesn't match actual mapcache file size \n");
+ fclose(mapcache_fp);
+ return false;
+ }
+
+ CREATE(p, uint8, header.file_size);
+ cursor = p + sizeof(header);
+
+ if (fread(p, header.file_size, 1, mapcache_fp) != 1) {
+ ShowError("Could not load mapcache file into memory, fread failed.\n");
+ aFree(p);
+ fclose(mapcache_fp);
+ return false;
+ }
+
+ for (i = 0; i < header.map_count; ++i) {
+ struct old_mapcache_map_info *info = (struct old_mapcache_map_info *)cursor;
+
+ ShowStatus("Creating mapcache: %s"CL_CLL"\n", info->name);
+
+ if (write_mapcache((uint8 *)info + sizeof(*info), info->len, true, info->name, info->xs, info->ys) == false) {
+ ShowError("failed To convert map '%s'\n", info->name);
+ }
+
+ cursor += sizeof(*info) + info->len;
+ }
+
+ aFree(p);
+ fclose(mapcache_fp);
+ return true;
+}
+
+bool mapcache_read_maplist(const char *filepath)
+{
+ char line[4096] = { 0 };
+ FILE *fp;
+
+ nullpo_retr(false, filepath);
+
+ fp = fopen(filepath, "r");
+
+ if (fp == NULL)
+ return false;
+
+ while (fgets(line, sizeof(line), fp)) {
+ char map_name[MAP_NAME_LENGTH];
+ if (line[0] == '/' && line[1] == '/')
+ continue;
+
+ if (sscanf(line, "%11s", map_name) == 1) {
+ VECTOR_ENSURE(maplist, 1, 1);
+ VECTOR_PUSH(maplist, aStrdup(map_name));
+ }
+ }
+
+ ShowStatus("%d map loaded from map_index.txt\n", VECTOR_LENGTH(maplist));
+ fclose(fp);
+ return true;
+}
+
+bool mapcache_cache_map(const char *mapname)
+{
+ char filepath[255] = { 0 };
+ uint8 *gat, *rsw, *gat_cursor;
+ uint8 *cells;
+ int water_height, map_size, xy;
+ int16 xs, ys;
+
+ nullpo_retr(false, mapname);
+
+ snprintf(filepath, sizeof(filepath), "data\\%s.gat", mapname);
+ gat = grfio_read(filepath);
+
+ if (gat == NULL) {
+ ShowError("mapcache_cache_map: Could not read %s, aborting caching map %s\n", filepath, mapname);
+ return false;
+ }
+
+ snprintf(filepath, sizeof(filepath), "data\\%s.rsw", mapname);
+
+ rsw = grfio_read(filepath);
+
+ if (rsw == NULL) {
+ water_height = NO_WATER;
+ } else {
+ water_height = (int)GetFloat(rsw + 166);
+ aFree(rsw);
+ }
+
+ xs = (int16)GetULong(gat + 6);
+ ys = (int16)GetULong(gat + 10);
+
+ if (xs <= 0 || ys <= 0) {
+ ShowError("mapcache_cache_map: map '%s' doesn't have valid size xs = %d, ys = %d\n", mapname, xs, ys);
+ aFree(gat);
+ return false;
+ }
+
+ map_size = xs * ys;
+ CREATE(cells, uint8, map_size);
+
+ gat_cursor = gat;
+ for (xy = 0; xy < map_size; ++xy) {
+ float height = GetFloat(gat_cursor + 14);
+ uint32 type = GetULong(gat_cursor + 30);
+ gat_cursor += 20;
+
+ if (type == 0 && water_height != NO_WATER && height > water_height)
+ type = 3;
+
+ cells[xy] = (uint8)type;
+ }
+
+ write_mapcache(cells, map_size, false, mapname, xs, ys);
+
+ aFree(gat);
+ aFree(cells);
+ return true;
+}
+
+bool mapcache_rebuild(void)
+{
+ int i;
+ char file_path[255];
+
+ if (mapcache_read_maplist("db/map_index.txt") == false) {
+ ShowError("mapcache_rebuild: Could not read maplist, aborting\n");
+ return false;
+ }
+
+ for (i = 0; i < VECTOR_LENGTH(maplist); ++i) {
+ snprintf(file_path, sizeof(file_path), "%s%s%s.%s", "maps/", DBPATH, VECTOR_INDEX(maplist, i), "mcache");
+ if (access(file_path, F_OK) == 0 && remove(file_path) != 0) {
+ ShowWarning("mapcache_rebuild: Could not remove file '%s' \n", file_path);
+ }
+ }
+
+ for (i = 0; i < VECTOR_LENGTH(maplist); ++i) {
+ ShowStatus("Creating mapcache: %s"CL_CLL"\r", VECTOR_INDEX(maplist, i));
+ mapcache_cache_map(VECTOR_INDEX(maplist, i));
+ }
+
+ return true;
+}
+
+CMDLINEARG(convertmapcache)
+{
+ map->minimal = true;
+ return convert_old_mapcache();
+}
+
+CMDLINEARG(rebuild)
+{
+ needs_grfio = true;
+ grfio->init("conf/grf-files.txt");
+ map->minimal = true;
+ return mapcache_rebuild();
+}
+
+CMDLINEARG(cachemap)
+{
+ needs_grfio = true;
+ grfio->init("conf/grf-files.txt");
+ map->minimal = true;
+ return mapcache_cache_map(params);
+}
+
+HPExport void server_preinit(void)
+{
+ addArg("--convert-old-mapcache", false, convertmapcache,
+ "Converts an old db/"DBPATH"map_cache.dat file to the new format.");
+ addArg("--rebuild-mapcache", false, rebuild,
+ "Rebuilds the entire mapcache folder (maps/"DBPATH"), using db/map_index.txt as index.");
+ addArg("--map", true, cachemap,
+ "Rebuilds an individual map's cache into maps/"DBPATH" (usage: --map <map_name_without_extension>).");
+
+ needs_grfio = false;
+ VECTOR_INIT(maplist);
+}
+
+HPExport void plugin_final(void)
+{
+ VECTOR_CLEAR(maplist);
+ if (needs_grfio)
+ grfio->final();
+}
diff --git a/src/tool/Makefile.in b/src/tool/Makefile.in
index 6e8643c56..fff29145e 100644
--- a/src/tool/Makefile.in
+++ b/src/tool/Makefile.in
@@ -36,26 +36,15 @@ LIBCONFIG_OBJ = $(addprefix $(LIBCONFIG_D)/, libconfig.o grammar.o scanctx.o \
LIBCONFIG_H = $(addprefix $(LIBCONFIG_D)/, libconfig.h grammar.h parsectx.h \
scanctx.h scanner.h strbuf.h wincompat.h)
-MAPCACHE_OBJ = obj_all/mapcache.o
-MAPCACHE_C = mapcache.c
-MAPCACHE_H =
-MAPCACHE_DEPENDS = $(MAPCACHE_OBJ) $(COMMON_D)/obj_all/common_mini.a $(LIBCONFIG_OBJ) $(SYSINFO_INC)
-
@SET_MAKE@
CC = @CC@
export CC
#####################################################################
-.PHONY: all mapcache clean buildclean help
-
-all: mapcache Makefile
-
-mapcache: ../../mapcache@EXEEXT@
+.PHONY: all clean buildclean help
-../../mapcache@EXEEXT@: $(MAPCACHE_DEPENDS) Makefile
- @echo " LD $(notdir $@)"
- @$(CC) @STATIC@ @LDFLAGS@ -o ../../mapcache@EXEEXT@ $(MAPCACHE_OBJ) $(COMMON_D)/obj_all/common_mini.a $(LIBCONFIG_OBJ) @LIBS@
+all: Makefile
buildclean:
@echo " CLEAN tool (build temp files)"
@@ -63,11 +52,9 @@ buildclean:
clean: buildclean
@echo " CLEAN tool"
- @rm -rf ../../mapcache@EXEEXT@
help:
- @echo "possible targets are 'mapcache' 'all' 'clean' 'help'"
- @echo "'mapcache' - mapcache generator"
+ @echo "possible targets are 'all' 'clean' 'help'"
@echo "'all' - builds all above targets"
@echo "'clean' - cleans builds and objects"
@echo "'buildclean' - cleans build temporary (object) files, without deleting the"
@@ -79,7 +66,7 @@ help:
Makefile: Makefile.in
@$(MAKE) -C ../.. src/tool/Makefile
-$(SYSINFO_INC): $(MAPCACHE_C) $(MAPCACHE_H) $(COMMON_H) $(CONFIG_H) $(LIBCONFIG_H)
+$(SYSINFO_INC): $(COMMON_H) $(CONFIG_H) $(LIBCONFIG_H)
@echo " MAKE $@"
@$(MAKE) -C ../.. sysinfo
@@ -87,7 +74,7 @@ obj_all:
@echo " MKDIR obj_all"
@-mkdir obj_all
-obj_all/%.o: %.c $(MAPCACHE_H) $(COMMON_H) $(CONFIG_H) $(LIBCONFIG_H) | obj_all
+obj_all/%.o: %.c $(COMMON_H) $(CONFIG_H) $(LIBCONFIG_H) | obj_all
@echo " CC $<"
@$(CC) @CFLAGS@ @DEFS@ $(COMMON_INCLUDE) $(THIRDPARTY_INCLUDE) @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
diff --git a/src/tool/mapcache.c b/src/tool/mapcache.c
deleted file mode 100644
index 5eb0843aa..000000000
--- a/src/tool/mapcache.c
+++ /dev/null
@@ -1,377 +0,0 @@
-/**
- * This file is part of Hercules.
- * http://herc.ws - http://github.com/HerculesWS/Hercules
- *
- * Copyright (C) 2012-2016 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
- *
- * Hercules is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-#define HERCULES_CORE
-
-#include "common/cbasetypes.h"
-#include "common/core.h"
-#include "common/grfio.h"
-#include "common/memmgr.h"
-#include "common/mmo.h"
-#include "common/showmsg.h"
-#include "common/strlib.h"
-#include "common/utils.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#ifndef _WIN32
-#include <unistd.h>
-#endif
-
-#define NO_WATER 1000000
-
-char *grf_list_file;
-char *map_list_file;
-char *map_cache_file;
-int rebuild = 0;
-
-FILE *map_cache_fp;
-
-unsigned long file_size;
-
-// Used internally, this structure contains the physical map cells
-struct map_data {
- int16 xs;
- int16 ys;
- unsigned char *cells;
-};
-
-// This is the main header found at the very beginning of the file
-struct main_header {
- uint32 file_size;
- uint16 map_count;
-} header;
-
-// This is the header appended before every compressed map cells info
-struct map_info {
- char name[MAP_NAME_LENGTH];
- int16 xs;
- int16 ys;
- int32 len;
-};
-
-// Reads a map from GRF's GAT and RSW files
-int read_map(char *name, struct map_data *m)
-{
- char filename[256];
- unsigned char *gat, *rsw;
- int water_height;
- size_t xy, off, num_cells;
-
- // Open map GAT
- sprintf(filename,"data\\%s.gat", name);
- gat = grfio_read(filename);
- if (gat == NULL)
- return 0;
-
- // Open map RSW
- sprintf(filename,"data\\%s.rsw", name);
- rsw = grfio_read(filename);
-
- // Read water height
- if (rsw) {
- water_height = (int)GetFloat(rsw+166);
- aFree(rsw);
- } else
- water_height = NO_WATER;
-
- // Read map size and allocate needed memory
- m->xs = (int16)GetULong(gat+6);
- m->ys = (int16)GetULong(gat+10);
- if (m->xs <= 0 || m->ys <= 0) {
- aFree(gat);
- return 0;
- }
- num_cells = (size_t)m->xs*(size_t)m->ys;
- m->cells = (unsigned char *)aMalloc(num_cells);
-
- // Set cell properties
- off = 14;
- for (xy = 0; xy < num_cells; xy++) {
- // Height of the bottom-left corner
- float height = GetFloat(gat + off);
- // Type of cell
- uint32 type = GetULong(gat + off + 16);
- off += 20;
-
- 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->cells[xy] = (unsigned char)type;
- }
-
- aFree(gat);
-
- return 1;
-}
-
-/**
- * Adds a map to the cache.
- *
- * @param name The map name.
- * @param m Map data to cache.
- * @retval true if the map was successfully added to the cache.
- */
-bool cache_map(char *name, struct map_data *m)
-{
- struct map_info info;
- unsigned long len;
- unsigned char *write_buf;
-
- // Create an output buffer twice as big as the uncompressed map... this way we're sure it fits
- len = (unsigned long)m->xs*(unsigned long)m->ys*2;
- write_buf = (unsigned char *)aMalloc(len);
- // Compress the cells and get the compressed length
- grfio->encode_zip(write_buf, &len, m->cells, m->xs*m->ys);
-
- // Fill the map header
- safestrncpy(info.name, name, MAP_NAME_LENGTH);
- if (strlen(name) > MAP_NAME_LENGTH) // It does not hurt to warn that there are maps with name longer than allowed.
- ShowWarning("Map name '%s' (length %"PRIuS") is too long. Truncating to '%s' (length %d).\n",
- name, strlen(name), info.name, MAP_NAME_LENGTH);
- info.xs = MakeShortLE(m->xs);
- info.ys = MakeShortLE(m->ys);
- info.len = MakeLongLE((uint32)len);
-
- // Append map header then compressed cells at the end of the file
- if (fseek(map_cache_fp, header.file_size, SEEK_SET) != 0) {
- aFree(write_buf);
- aFree(m->cells);
- return false;
- }
- fwrite(&info, sizeof(struct map_info), 1, map_cache_fp);
- fwrite(write_buf, 1, len, map_cache_fp);
- header.file_size += sizeof(struct map_info) + len;
- header.map_count++;
-
- aFree(write_buf);
- aFree(m->cells);
-
- return true;
-}
-
-/**
- * Checks whether a map is already is the cache.
- *
- * @param name The map name.
- * @retval true if the map is already cached.
- */
-bool find_map(char *name)
-{
- int i;
- struct map_info info;
-
- if (fseek(map_cache_fp, sizeof(struct main_header), SEEK_SET) != 0)
- return false;
-
- for (i = 0; i < header.map_count; i++) {
- if (fread(&info, sizeof(info), 1, map_cache_fp) != 1)
- printf("An error as occured in fread while reading map_cache\n");
- if (strcmp(name, info.name) == 0) // Map found
- return true;
- // Map not found, jump to the beginning of the next map info header
- if (fseek(map_cache_fp, GetLong((unsigned char *)&(info.len)), SEEK_CUR) != 0)
- return false;
- }
-
- return false;
-}
-
-// Cuts the extension from a map name
-char *remove_extension(char *mapname)
-{
- char *ptr, *ptr2;
- ptr = strchr(mapname, '.');
- if (ptr) { //Check and remove extension.
- while (ptr[1] && (ptr2 = strchr(ptr+1, '.')) != NULL)
- ptr = ptr2; //Skip to the last dot.
- if (strcmp(ptr,".gat") == 0)
- *ptr = '\0'; //Remove extension.
- }
- return mapname;
-}
-
-/**
- * --grf-list handler
- *
- * Overrides the default grf list filename.
- * @see cmdline->exec
- */
-static CMDLINEARG(grflist)
-{
- aFree(grf_list_file);
- grf_list_file = aStrdup(params);
- return true;
-}
-
-/**
- * --map-list handler
- *
- * Overrides the default map list filename.
- * @see cmdline->exec
- */
-static CMDLINEARG(maplist)
-{
- aFree(map_list_file);
- map_list_file = aStrdup(params);
- return true;
-}
-
-/**
- * --map-cache handler
- *
- * Overrides the default map cache filename.
- * @see cmdline->exec
- */
-static CMDLINEARG(mapcache)
-{
- aFree(map_cache_file);
- map_cache_file = aStrdup(params);
- return true;
-}
-
-/**
- * --rebuild handler
- *
- * Forces a rebuild of the mapcache, rather than only adding missing maps.
- * @see cmdline->exec
- */
-static CMDLINEARG(rebuild)
-{
- rebuild = 1;
- return true;
-}
-
-/**
- * Defines the local command line arguments
- */
-void cmdline_args_init_local(void)
-{
- CMDLINEARG_DEF2(grf-list, grflist, "Alternative grf list file", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM);
- CMDLINEARG_DEF2(map-list, maplist, "Alternative map list file", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM);
- CMDLINEARG_DEF2(map-cache, mapcache, "Alternative map cache file", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM);
- CMDLINEARG_DEF2(rebuild, rebuild, "Forces a rebuild of the map cache, rather than only adding missing maps", CMDLINE_OPT_NORMAL);
-}
-
-int do_init(int argc, char** argv)
-{
- FILE *list;
- char line[1024];
- struct map_data map;
- char name[MAP_NAME_LENGTH_EXT];
-
- grf_list_file = aStrdup("conf/grf-files.txt");
- map_list_file = aStrdup("db/map_index.txt");
- /* setup pre-defined, #define-dependant */
- map_cache_file = aStrdup("db/"DBPATH"map_cache.dat");
-
- cmdline->exec(argc, argv, CMDLINE_OPT_PREINIT);
- cmdline->exec(argc, argv, CMDLINE_OPT_NORMAL);
-
- ShowStatus("Initializing grfio with %s\n", grf_list_file);
- grfio->init(grf_list_file);
-
- // Attempt to open the map cache file and force rebuild if not found
- ShowStatus("Opening map cache: %s\n", map_cache_file);
- if(!rebuild) {
- map_cache_fp = fopen(map_cache_file, "rb");
- if(map_cache_fp == NULL) {
- ShowNotice("Existing map cache not found, forcing rebuild mode\n");
- rebuild = 1;
- } else
- fclose(map_cache_fp);
- }
- if(rebuild)
- map_cache_fp = fopen(map_cache_file, "w+b");
- else
- map_cache_fp = fopen(map_cache_file, "r+b");
- if(map_cache_fp == NULL) {
- ShowError("Failure when opening map cache file %s\n", map_cache_file);
- exit(EXIT_FAILURE);
- }
-
- // Open the map list
- ShowStatus("Opening map list: %s\n", map_list_file);
- list = fopen(map_list_file, "r");
- if(list == NULL) {
- ShowError("Failure when opening maps list file %s\n", map_list_file);
- exit(EXIT_FAILURE);
- }
-
- // Initialize the main header
- if(rebuild) {
- header.file_size = sizeof(struct main_header);
- header.map_count = 0;
- } else {
- if(fread(&header, sizeof(struct main_header), 1, map_cache_fp) != 1){ printf("An error as occured while reading map_cache_fp \n"); }
- header.file_size = GetULong((unsigned char *)&(header.file_size));
- header.map_count = GetUShort((unsigned char *)&(header.map_count));
- }
-
- // Read and process the map list
- while(fgets(line, sizeof(line), list))
- {
- if(line[0] == '/' && line[1] == '/')
- continue;
-
- if(sscanf(line, "%15s", name) < 1)
- continue;
-
- if(strcmp("map:", name) == 0 && sscanf(line, "%*s %15s", name) < 1)
- continue;
-
- name[MAP_NAME_LENGTH_EXT-1] = '\0';
- remove_extension(name);
- if (find_map(name)) {
- ShowInfo("Map '"CL_WHITE"%s"CL_RESET"' already in cache.\n", name);
- } else if(!read_map(name, &map)) {
- ShowError("Map '"CL_WHITE"%s"CL_RESET"' not found!\n", name);
- } else if (!cache_map(name, &map)) {
- ShowError("Map '"CL_WHITE"%s"CL_RESET"' failed to cache (write error).\n", name);
- } else {
- ShowInfo("Map '"CL_WHITE"%s"CL_RESET"' successfully cached.\n", name);
- }
- }
-
- ShowStatus("Closing map list: %s\n", map_list_file);
- fclose(list);
-
- // Write the main header and close the map cache
- ShowStatus("Closing map cache: %s\n", map_cache_file);
- fseek(map_cache_fp, 0, SEEK_SET);
- fwrite(&header, sizeof(struct main_header), 1, map_cache_fp);
- fclose(map_cache_fp);
-
- ShowStatus("Finalizing grfio\n");
- grfio->final();
-
- ShowInfo("%d maps now in cache\n", header.map_count);
-
- aFree(grf_list_file);
- aFree(map_list_file);
- aFree(map_cache_file);
-
- return 0;
-}
-
-int do_final(void)
-{
- return EXIT_SUCCESS;
-}