summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changelog.txt2
-rw-r--r--conf-tmpl/map_athena.conf5
-rw-r--r--src/common/grfio.c73
-rw-r--r--src/common/grfio.h3
-rw-r--r--src/map/map.c149
-rw-r--r--src/map/map.h6
6 files changed, 188 insertions, 50 deletions
diff --git a/Changelog.txt b/Changelog.txt
index 209e486ef..713ff1501 100644
--- a/Changelog.txt
+++ b/Changelog.txt
@@ -1,5 +1,7 @@
Date Added
12/27
+ * Updated map cache system from jA 1087 - change read_map_from_bitmap to 2 to
+ enable zlib compression [celest]
* don't delete alive_timers of -1 (SVN 823) [MouseJstr]
* switched malloc,calloc,realloc to aMalloc, aCalloc, aRealloc
so support the use of a garbage collector (SVN 821) [MouseJstr]
diff --git a/conf-tmpl/map_athena.conf b/conf-tmpl/map_athena.conf
index 7f099cb0f..39f5d97d8 100644
--- a/conf-tmpl/map_athena.conf
+++ b/conf-tmpl/map_athena.conf
@@ -45,7 +45,10 @@ char_port: 6121
map_port: 5121
//Preferred map loading method
-//0: Read directly from grf, 1: Read from bitmap file
+//0: Read directly from grf, 1: Read from bitmap file (without compression)
+//2: Read from bitmap file (with compression). It is possible to reduce the map cache
+// to 1MB for 400+ maps with compression enabled. If all maps are already loaded in the
+// cache, Athena can boot without reading the grf files.
read_map_from_bitmap: 1
//
//Where is the bitmap file stored?
diff --git a/src/common/grfio.c b/src/common/grfio.c
index ea5bba6ab..37cf2b9ee 100644
--- a/src/common/grfio.c
+++ b/src/common/grfio.c
@@ -33,6 +33,30 @@
#include "showmsg.h"
#include "malloc.h"
+#ifdef _WIN32
+ #include <windows.h>
+ #include "zlib_win32.h"
+ HINSTANCE zlib_dll;
+ #define zlib_inflateInit(strm) zlib_inflateInit_((strm),ZLIB_VERSION, sizeof(z_stream))
+ #define zlib_deflateInit(strm, level) zlib_deflateInit_((strm),(level),ZLIB_VERSION,sizeof(z_stream))
+
+ int (WINAPI* zlib_inflateInit_) (z_streamp strm, const char *version, int stream_size);
+ int (WINAPI* zlib_inflate) (z_streamp strm, int flush);
+ int (WINAPI* zlib_inflateEnd) (z_streamp strm);
+
+ int (WINAPI* zlib_deflateInit_) (z_streamp strm, int level, const char *version, int stream_size);
+ int (WINAPI* zlib_deflate) (z_streamp strm, int flush);
+ int (WINAPI* zlib_deflateEnd) (z_streamp strm);
+#else
+ #include <zlib.h>
+ #define zlib_inflateInit inflateInit
+ #define zlib_inflate inflate
+ #define zlib_inflateEnd inflateEnd
+ #define zlib_deflateInit deflateInit
+ #define zlib_deflate deflate
+ #define zlib_deflateEnd deflateEnd
+#endif
+
#ifdef MEMWATCH
#include "memwatch.h"
#endif
@@ -260,7 +284,7 @@ static void decode_des_etc(BYTE *buf,int len,int type,int cycle)
* Grf data decode sub : zip
*------------------------------------------
*/
-static int decode_zip(Bytef* dest, uLongf* destLen, const Bytef* source, uLong sourceLen)
+int decode_zip(char *dest, unsigned long* destLen, const char* source, unsigned long sourceLen)
{
z_stream stream;
int err;
@@ -290,6 +314,37 @@ static int decode_zip(Bytef* dest, uLongf* destLen, const Bytef* source, uLong s
err = inflateEnd(&stream);
return err;
}
+
+int encode_zip(char *dest, unsigned long* destLen, const char* source, unsigned long sourceLen) {
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+
+ err = zlib_deflateInit(&stream,Z_DEFAULT_COMPRESSION);
+ if (err != Z_OK) return err;
+
+ err = zlib_deflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ zlib_inflateEnd(&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *destLen = stream.total_out;
+
+ err = zlib_deflateEnd(&stream);
+ return err;
+}
+
/***********************************************************
*** File List Sobroutines ***
***********************************************************/
@@ -924,6 +979,22 @@ void grfio_init(char *fname)
char line[1024], w1[1024], w2[1024];
int result = 0, result2 = 0, result3 = 0, result4 = 0;
+#ifdef _WIN32
+ if(!zlib_dll) {
+ zlib_dll = LoadLibrary("zlib.dll");
+ (FARPROC)zlib_inflateInit_ = GetProcAddress(zlib_dll,"inflateInit_");
+ (FARPROC)zlib_inflate = GetProcAddress(zlib_dll,"inflate");
+ (FARPROC)zlib_inflateEnd = GetProcAddress(zlib_dll,"inflateEnd");
+ (FARPROC)zlib_deflateInit_ = GetProcAddress(zlib_dll,"deflateInit_");
+ (FARPROC)zlib_deflate = GetProcAddress(zlib_dll,"deflate");
+ (FARPROC)zlib_deflateEnd = GetProcAddress(zlib_dll,"deflateEnd");
+ if(zlib_dll == NULL) {
+ MessageBox(NULL,"Can't load zlib.dll","grfio.c",MB_OK);
+ exit(1);
+ }
+ }
+#endif
+
data_conf = fopen(fname, "r");
// It will read, if there is grf-files.txt.
diff --git a/src/common/grfio.h b/src/common/grfio.h
index 53b9da8d4..f39e9af1b 100644
--- a/src/common/grfio.h
+++ b/src/common/grfio.h
@@ -8,6 +8,9 @@ void* grfio_read(char*); // GRFIO data file read
void* grfio_reads(char*,int*); // GRFIO data file read & size get
int grfio_size(char*); // GRFIO data file size get
+int decode_zip(char *dest, unsigned long* destLen, const char* source, unsigned long sourceLen);
+int encode_zip(char *dest, unsigned long* destLen, const char* source, unsigned long sourceLen);
+
// Accessor to GRF filenames
char *grfio_setdatafile(const char *str);
char *grfio_setadatafile(const char *str);
diff --git a/src/map/map.c b/src/map/map.c
index 83ef75762..f36ef0ccf 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -150,20 +150,9 @@ struct charid2nick {
int req_id;
};
-//各マップごとの最小限情報を入れるもの、READ_FROM_BITMAP用
-/*typedef struct{
- char fn[32];//ファイル名
- int xs,ys; //幅と高さ
- int sizeinint;//intでの大きさ、1intに32セルの情報が入てる
- int celltype[MAX_CELL_TYPE];//マップごとにそのタイプのセルがあれば対応する数字が入る、なければ1
- //(タイプ1そのものは0と同じ配列gat_fileused[0]に
- long pos[MAX_CELL_TYPE];//ビットマップファイルでの場所、読み出す時に使う
-} CELL_INFO;*/
-
-//#define READ_FROM_GAT 0 //gatファイルから
-//#define READ_FROM_BITMAP 1 //ビットマップファイルから
-int map_read_flag = READ_FROM_GAT;//上の判定フラグ,どっちを使うかはmap_athana.conf内のread_map_from_bitmapで指定
- //0ならばREAD_FROM_GAT,1ならばREAD_FROM_BITMAP
+int map_read_flag = READ_FROM_GAT;
+// マップキャッシュ利用フラグ,どっちを使うかはmap_athana.conf内のread_map_from_bitmapで指定
+// 0ならば利用しない、1だと非圧縮保存、2だと圧縮して保存
int map_getcell(int,int x,int y,CELL_CHK cellchk);
int map_getcellp(struct map_data* m,int x,int y,CELL_CHK cellchk);
@@ -1569,9 +1558,9 @@ static int map_cache_open(char *fn) {
return 1;
}
fclose(map_cache.fp);
- } else {
- map_read_flag = CREATE_BITMAP;
- }
+ } else if (map_read_flag == READ_FROM_BITMAP || map_read_flag == READ_FROM_BITMAP_COMPRESSED)
+ ++map_read_flag; // set to CREATE flag
+
// 読み込みに失敗したので新規に作成する
map_cache.fp = fopen(fn,"wb");
if(map_cache.fp) {
@@ -1611,10 +1600,8 @@ int map_cache_read(struct map_data *m) {
if(map_cache.map[i].water_height != map_waterheight(m->name)) {
// 水場の高さが違うので読み直し
return 0;
- } else if(map_cache.map[i].compressed) {
- // 圧縮ファイルは未対応
- return 0;
- } else {
+ } else if(map_cache.map[i].compressed == 0) {
+ // 非圧縮ファイル
int size = map_cache.map[i].xs * map_cache.map[i].ys;
m->xs = map_cache.map[i].xs;
m->ys = map_cache.map[i].ys;
@@ -1625,12 +1612,36 @@ int map_cache_read(struct map_data *m) {
return 1;
} else {
// なぜかファイル後半が欠けてるので読み直し
- m->xs = 0;
- m->ys = 0;
- free(m->gat);
- m->gat = NULL;
+ m->xs = 0; m->ys = 0; m->gat = NULL; free(m->gat);
+ return 0;
+ }
+ } else if(map_cache.map[i].compressed == 1) {
+ // 圧縮フラグ=1 : zlib
+ unsigned char *buf;
+ unsigned long dest_len;
+ int size_compress = map_cache.map[i].compressed_len;
+ m->xs = map_cache.map[i].xs;
+ m->ys = map_cache.map[i].ys;
+ m->gat = (unsigned char *)aMalloc(m->xs * m->ys * sizeof(unsigned char));
+ buf = (unsigned char*)aMalloc(size_compress);
+ fseek(map_cache.fp,map_cache.map[i].pos,SEEK_SET);
+ if(fread(buf,1,size_compress,map_cache.fp) != size_compress) {
+ // なぜかファイル後半が欠けてるので読み直し
+ printf("fread error\n");
+ m->xs = 0; m->ys = 0; m->gat = NULL;
+ free(m->gat); free(buf);
return 0;
}
+ dest_len = m->xs * m->ys;
+ decode_zip(m->gat,&dest_len,buf,size_compress);
+ if(dest_len != map_cache.map[i].xs * map_cache.map[i].ys) {
+ // 正常に解凍が出来てない
+ m->xs = 0; m->ys = 0; m->gat = NULL;
+ free(m->gat); free(buf);
+ return 0;
+ }
+ free(buf);
+ return 1;
}
}
}
@@ -1639,29 +1650,52 @@ int map_cache_read(struct map_data *m) {
static int map_cache_write(struct map_data *m) {
int i;
+ unsigned long len_new , len_old;
+ char *write_buf;
if(!map_cache.fp) { return 0; }
for(i = 0;i < map_cache.head.nmaps ; i++) {
if(!strcmp(m->name,map_cache.map[i].fn)) {
// 同じエントリーがあれば上書き
- if(
- map_cache.map[i].xs == m->xs && map_cache.map[i].ys == m->ys &&
- !map_cache.map[i].compressed
- ) {
- // 幅と高さ同じで圧縮してないなら場所は変わらない
+ if(map_cache.map[i].compressed == 0) {
+ len_old = map_cache.map[i].xs * map_cache.map[i].ys;
+ } else if(map_cache.map[i].compressed == 1) {
+ len_old = map_cache.map[i].compressed_len;
+ } else {
+ // サポートされてない形式なので長さ0
+ len_old = 0;
+ }
+ if(map_read_flag >= READ_FROM_BITMAP_COMPRESSED) {
+ // 圧縮保存
+ // さすがに2倍に膨れる事はないという事で
+ write_buf = aMalloc(m->xs * m->ys * 2);
+ len_new = m->xs * m->ys * 2;
+ encode_zip(write_buf,&len_new,m->gat,m->xs * m->ys);
+ map_cache.map[i].compressed = 1;
+ map_cache.map[i].compressed_len = len_new;
+ } else {
+ len_new = m->xs * m->ys;
+ write_buf = m->gat;
+ map_cache.map[i].compressed = 0;
+ map_cache.map[i].compressed_len = 0;
+ }
+ if(len_new <= len_old) {
+ // サイズが同じか小さくなったので場所は変わらない
fseek(map_cache.fp,map_cache.map[i].pos,SEEK_SET);
- fwrite(m->gat,m->xs,m->ys,map_cache.fp);
+ fwrite(write_buf,1,len_new,map_cache.fp);
} else {
- // 幅と高さが違うなら新しい場所に登録
- int size = m->xs * m->ys;
+ // 新しい場所に登録
fseek(map_cache.fp,map_cache.head.filesize,SEEK_SET);
- fwrite(m->gat,1,size,map_cache.fp);
+ fwrite(write_buf,1,len_new,map_cache.fp);
map_cache.map[i].pos = map_cache.head.filesize;
- map_cache.map[i].xs = m->xs;
- map_cache.map[i].ys = m->ys;
- map_cache.head.filesize += size;
+ map_cache.head.filesize += len_new;
}
+ map_cache.map[i].xs = m->xs;
+ map_cache.map[i].ys = m->ys;
map_cache.map[i].water_height = map_waterheight(m->name);
map_cache.dirty = 1;
+ if(map_read_flag >= READ_FROM_BITMAP_COMPRESSED) {
+ free(write_buf);
+ }
return 0;
}
}
@@ -1669,16 +1703,30 @@ static int map_cache_write(struct map_data *m) {
for(i = 0;i < map_cache.head.nmaps ; i++) {
if(map_cache.map[i].fn[0] == 0) {
// 新しい場所に登録
- int size = m->xs * m->ys;
+ if(map_read_flag >= READ_FROM_BITMAP_COMPRESSED) {
+ write_buf = aMalloc(m->xs * m->ys * 2);
+ len_new = m->xs * m->ys * 2;
+ encode_zip(write_buf,&len_new,m->gat,m->xs * m->ys);
+ map_cache.map[i].compressed = 1;
+ map_cache.map[i].compressed_len = len_new;
+ } else {
+ len_new = m->xs * m->ys;
+ write_buf = m->gat;
+ map_cache.map[i].compressed = 0;
+ map_cache.map[i].compressed_len = 0;
+ }
strncpy(map_cache.map[i].fn,m->name,sizeof(map_cache.map[0].fn));
fseek(map_cache.fp,map_cache.head.filesize,SEEK_SET);
- fwrite(m->gat,1,size,map_cache.fp);
+ fwrite(write_buf,1,len_new,map_cache.fp);
map_cache.map[i].pos = map_cache.head.filesize;
map_cache.map[i].xs = m->xs;
map_cache.map[i].ys = m->ys;
map_cache.map[i].water_height = map_waterheight(m->name);
- map_cache.head.filesize += size;
+ map_cache.head.filesize += len_new;
map_cache.dirty = 1;
+ if(map_read_flag >= READ_FROM_BITMAP_COMPRESSED) {
+ free(write_buf);
+ }
return 0;
}
}
@@ -1931,13 +1979,14 @@ int map_readallmap(void) {
int map_cache = 0;
// マップキャッシュを開く
- if(map_read_flag == READ_FROM_BITMAP) {
+ if(map_read_flag >= READ_FROM_BITMAP) {
map_cache_open(map_bitmap_filename);
}
sprintf(tmp_output, "Loading Maps%s...\n",
- (map_read_flag == CREATE_BITMAP ? " (Generating Map Cache)" :
- map_read_flag == READ_FROM_BITMAP ? " (w/ Map Cache)" :
+ (map_read_flag == CREATE_BITMAP_COMPRESSED ? " (Generating Map Cache w/ Compression)" :
+ map_read_flag == CREATE_BITMAP ? " (Generating Map Cache)" :
+ map_read_flag >= READ_FROM_BITMAP ? " (w/ Map Cache)" :
map_read_flag == READ_FROM_AFM ? " (w/ AFM)" : ""));
ShowStatus(tmp_output);
@@ -2001,8 +2050,8 @@ int map_readallmap(void) {
ShowInfo(tmp_output);
map_cache_close();
- if(map_read_flag == CREATE_BITMAP) {
- map_read_flag = READ_FROM_BITMAP;
+ if(map_read_flag == CREATE_BITMAP || map_read_flag == CREATE_BITMAP_COMPRESSED) {
+ --map_read_flag;
}
if (maps_removed) {
@@ -2214,10 +2263,14 @@ int map_config_read(char *cfgName) {
} else if (strcmpi(w1, "mapreg_txt") == 0) {
strcpy(mapreg_txt, w2);
}else if(strcmpi(w1,"read_map_from_bitmap")==0){
- if (atoi(w2) == 1)
+ if (atoi(w2) == 2)
+ map_read_flag = READ_FROM_BITMAP_COMPRESSED;
+ else if (atoi(w2) == 1)
map_read_flag = READ_FROM_BITMAP;
else
map_read_flag = READ_FROM_GAT;
+ }else if(strcmpi(w1,"map_bitmap_path")==0){
+ strncpy(map_bitmap_filename,w2,255);
} else if (strcmpi(w1, "import") == 0) {
map_config_read(w2);
} else if (strcmpi(w1, "console") == 0) {
@@ -2408,7 +2461,9 @@ int sql_config_read(char *cfgName)
} else if(strcmpi(w1,"log_db_port")==0) {
log_db_port = atoi(w2);
}else if(strcmpi(w1,"read_map_from_bitmap")==0){
- if (atoi(w2) == 1)
+ if (atoi(w2) == 2)
+ map_read_flag = READ_FROM_BITMAP_COMPRESSED;
+ else if (atoi(w2) == 1)
map_read_flag = READ_FROM_BITMAP;
else
map_read_flag = READ_FROM_GAT;
diff --git a/src/map/map.h b/src/map/map.h
index dcda50978..cb8438352 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -668,7 +668,11 @@ extern int night_flag; // 0=day, 1=night [Yor]
int map_getcell(int,int,int,CELL_CHK);
int map_getcellp(struct map_data*,int,int,CELL_CHK);
extern int map_read_flag; //セル情報のソース判定フラグ、0ならgrfファイル、1ならビットマップファイル
-enum { READ_FROM_GAT, READ_FROM_AFM, READ_FROM_BITMAP, CREATE_BITMAP };
+enum {
+ READ_FROM_GAT, READ_FROM_AFM,
+ READ_FROM_BITMAP, CREATE_BITMAP,
+ READ_FROM_BITMAP_COMPRESSED, CREATE_BITMAP_COMPRESSED
+};
extern char motd_txt[];
extern char help_txt[];