summaryrefslogtreecommitdiff
path: root/src/map/map.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/map.c')
-rw-r--r--src/map/map.c403
1 files changed, 348 insertions, 55 deletions
diff --git a/src/map/map.c b/src/map/map.c
index 55718a37d..46705dc8d 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -150,6 +150,25 @@ 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_getcell(int,int x,int y,CELL_CHK cellchk);
+int map_getcellp(struct map_data* m,int x,int y,CELL_CHK cellchk);
+
+char map_bitmap_filename[256]="db/map.info";//ビットマップファイルのデフォルトパス
+
char motd_txt[256] = "conf/motd.txt";
char help_txt[256] = "conf/help.txt";
@@ -769,7 +788,7 @@ int map_clearflooritem_timer(int tid,unsigned int tick,int id,int data) {
*------------------------------------------
*/
int map_searchrandfreecell(int m,int x,int y,int range) {
- int free_cell,i,j,c;
+ int free_cell,i,j;
for(free_cell=0,i=-range;i<=range;i++){
if(i+y<0 || i+y>=map[m].ys)
@@ -777,7 +796,7 @@ int map_searchrandfreecell(int m,int x,int y,int range) {
for(j=-range;j<=range;j++){
if(j+x<0 || j+x>=map[m].xs)
continue;
- if((c=read_gat(m,j+x,i+y))==1 || c==5)
+ if(map_getcell(m,j+x,i+y,CELL_CHKNOPASS))
continue;
free_cell++;
}
@@ -791,7 +810,7 @@ int map_searchrandfreecell(int m,int x,int y,int range) {
for(j=-range;j<=range;j++){
if(j+x<0 || j+x>=map[m].xs)
continue;
- if((c=read_gat(m,j+x,i+y))==1 || c==5)
+ if(map_getcell(m,j+x,i+y,CELL_CHKNOPASS))
continue;
if(free_cell==0){
x+=j;
@@ -1340,23 +1359,77 @@ int map_calc_dir( struct block_list *src,int x,int y) {
// gat系
/*==========================================
- * (m,x,y)の?態を調べる
+ * (m,x,y)の状態を調べる
*------------------------------------------
*/
-int map_getcell(int m,int x,int y) {
- if(x<0 || x>=map[m].xs-1 || y<0 || y>=map[m].ys-1)
- return 1;
- return map[m].gat[x+y*map[m].xs];
+
+int map_getcell(int m,int x,int y,CELL_CHK cellchk)
+{
+ return (m < 0 || m > MAX_MAP_PER_SERVER) ? 0 : map_getcellp(&map[m],x,y,cellchk);
+}
+
+int map_getcellp(struct map_data* m,int x,int y,CELL_CHK cellchk)
+{
+ int j;
+ nullpo_ret(m);
+ if(x<0 || x>=m->xs-1 || y<0 || y>=m->ys-1)
+ {
+ if(cellchk==CELL_CHKNOPASS) return 1;
+ return 0;
+ }
+ j=x+y*m->xs;
+
+ switch(cellchk)
+ {
+ case CELL_CHKTOUCH:
+ if(m->gat[j]&0x80) return 1;return 0;
+ case CELL_CHKWATER:
+ if(m->gat[j]==3) return 1;return 0;
+ case CELL_CHKHIGH:
+ if(m->gat[j]==5) return 1;return 0;
+ case CELL_CHKPASS:
+ if(m->gat[j]!=1&&m->gat[j]!=5) return 1; return 0;
+ case CELL_CHKNOPASS:
+ if(m->gat[j]==1||m->gat[j]==5) return 1; return 0;
+ case CELL_CHKTYPE:
+ return m->gat[j];
+ default: return 0;
+ }
+ return 0;
}
/*==========================================
- * (m,x,y)の?態をtにする
+ * (m,x,y)の状態を設定する
*------------------------------------------
*/
-int map_setcell(int m,int x,int y,int t) {
+int map_setcell(int m,int x,int y,CELL_SET cellset)
+{
+ int i,j;
+
if(x<0 || x>=map[m].xs || y<0 || y>=map[m].ys)
- return t;
- return map[m].gat[x+y*map[m].xs]=t;
+ return 0;
+ j=x+y*map[m].xs;
+ switch(cellset)
+ {
+ case CELL_SETTOUCH:
+ return map[m].gat[j]|=0x80;
+ break;
+ case CELL_SETWATER://3
+ i=3;break;
+ case CELL_SETPASS://0
+ i=0;break;
+ case CELL_SETNOPASS://gat_fileused[0](READ_FROM_BITMAP)か1(READ_FROM_GAT)
+ i=1;break;
+ case CELL_SETHIGH://5
+ i=5;break;
+ case CELL_SETNOHIGH://5
+ i=5;break;
+ default:
+ return 0;
+ }
+ map[m].gat[j]=i;
+
+ return 1;
}
/*==========================================
@@ -1440,6 +1513,178 @@ static void map_readwater(char *watertxt) {
}
fclose(fp);
}
+/*==========================================
+* マップキャッシュに追加する
+*===========================================*/
+
+// マップキャッシュの最大値
+#define MAX_CAHCE_MAX 768
+
+//各マップごとの最小限情報を入れるもの、READ_FROM_BITMAP用
+struct MAP_CACHE_INFO {
+ char fn[32];//ファイル名
+ int xs,ys; //幅と高さ
+ int water_height;
+ int pos; // データが入れてある場所
+ int compressed; // zilb通せるようにする為の予約
+ int compressed_len; // zilb通せるようにする為の予約
+}; // 56 byte
+
+struct {
+ struct MAP_CACHE_HEAD {
+ int sizeof_header;
+ int sizeof_map;
+ // 上の2つ改変不可
+ int nmaps; // マップの個数
+ int filesize;
+ } head;
+ struct MAP_CACHE_INFO *map;
+ FILE *fp;
+ int dirty;
+} map_cache;
+
+static int map_cache_open(char *fn);
+static void map_cache_close(void);
+static int map_cache_read(struct map_data *m);
+static int map_cache_write(struct map_data *m);
+
+static int map_cache_open(char *fn) {
+ atexit(map_cache_close);
+ if(map_cache.fp) {
+ map_cache_close();
+ }
+ map_cache.fp = fopen(fn,"r+b");
+ if(map_cache.fp) {
+ fread(&map_cache.head,1,sizeof(struct MAP_CACHE_HEAD),map_cache.fp);
+ fseek(map_cache.fp,0,SEEK_END);
+ if(
+ map_cache.head.sizeof_header == sizeof(struct MAP_CACHE_HEAD) &&
+ map_cache.head.sizeof_map == sizeof(struct MAP_CACHE_INFO) &&
+ map_cache.head.filesize == ftell(map_cache.fp)
+ ) {
+ // キャッシュ読み込み成功
+ map_cache.map = aMalloc(sizeof(struct MAP_CACHE_INFO) * map_cache.head.nmaps);
+ fseek(map_cache.fp,sizeof(struct MAP_CACHE_HEAD),SEEK_SET);
+ fread(map_cache.map,sizeof(struct MAP_CACHE_INFO),map_cache.head.nmaps,map_cache.fp);
+ return 1;
+ }
+ fclose(map_cache.fp);
+ } else {
+ map_read_flag = CREATE_BITMAP;
+ }
+ // 読み込みに失敗したので新規に作成する
+ map_cache.fp = fopen(fn,"wb");
+ if(map_cache.fp) {
+ memset(&map_cache.head,0,sizeof(struct MAP_CACHE_HEAD));
+ map_cache.map = aCalloc(sizeof(struct MAP_CACHE_INFO),MAX_CAHCE_MAX);
+ map_cache.head.nmaps = MAX_CAHCE_MAX;
+ map_cache.head.sizeof_header = sizeof(struct MAP_CACHE_HEAD);
+ map_cache.head.sizeof_map = sizeof(struct MAP_CACHE_INFO);
+
+ map_cache.head.filesize = sizeof(struct MAP_CACHE_HEAD);
+ map_cache.head.filesize += sizeof(struct MAP_CACHE_INFO) * map_cache.head.nmaps;
+
+ map_cache.dirty = 1;
+ return 1;
+ }
+ return 0;
+}
+
+static void map_cache_close(void) {
+ if(!map_cache.fp) { return; }
+ if(map_cache.dirty) {
+ fseek(map_cache.fp,0,SEEK_SET);
+ fwrite(&map_cache.head,1,sizeof(struct MAP_CACHE_HEAD),map_cache.fp);
+ fwrite(map_cache.map,map_cache.head.nmaps,sizeof(struct MAP_CACHE_INFO),map_cache.fp);
+ }
+ fclose(map_cache.fp);
+ free(map_cache.map);
+ map_cache.fp = NULL;
+ return;
+}
+
+int map_cache_read(struct map_data *m) {
+ int i;
+ 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].water_height != map_waterheight(m->name)) {
+ // 水場の高さが違うので読み直し
+ return 0;
+ } else if(map_cache.map[i].compressed) {
+ // 圧縮ファイルは未対応
+ return 0;
+ } else {
+ 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;
+ m->gat = (unsigned char *)aCalloc(m->xs * m->ys,sizeof(unsigned char));
+ fseek(map_cache.fp,map_cache.map[i].pos,SEEK_SET);
+ if(fread(m->gat,1,size,map_cache.fp) == size) {
+ // 成功
+ return 1;
+ } else {
+ // なぜかファイル後半が欠けてるので読み直し
+ m->xs = 0;
+ m->ys = 0;
+ free(m->gat);
+ m->gat = NULL;
+ return 0;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static int map_cache_write(struct map_data *m) {
+ int i;
+ 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
+ ) {
+ // 幅と高さ同じで圧縮してないなら場所は変わらない
+ fseek(map_cache.fp,map_cache.map[i].pos,SEEK_SET);
+ fwrite(m->gat,m->xs,m->ys,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);
+ 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.map[i].water_height = map_waterheight(m->name);
+ map_cache.dirty = 1;
+ return 0;
+ }
+ }
+ // 同じエントリが無ければ書き込める場所を探す
+ for(i = 0;i < map_cache.head.nmaps ; i++) {
+ if(map_cache.map[i].fn[0] == 0) {
+ // 新しい場所に登録
+ int size = m->xs * m->ys;
+ 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);
+ 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.dirty = 1;
+ return 0;
+ }
+ }
+ // 書き込めなかった
+ return 1;
+}
#ifdef USE_AFM
static int map_readafm(int m,char *fn) {
@@ -1587,28 +1832,20 @@ static int map_readafm(int m,char *fn) {
#endif
/*==========================================
- * マップ1枚?み?み
- *------------------------------------------
- */
-static int map_readmap(int m,char *fn, char *alias) {
+ * マップ1枚読み込み
+ * ===================================================*/
+static int map_readmap(int m,char *fn, char *alias, int *map_cache) {
unsigned char *gat="";
- int s;
- int x,y,xs,ys;
- struct gat_1cell {float high[4]; int type;} *p=NULL;
- int wh;
+ size_t size;
+
int i;
int e = 0;
-
- size_t size;
char progress[21] = " ";
- // read & convert fn
- gat=grfio_read(fn);
- if(gat==NULL)
- return -1;
+
//printf("\rLoading Maps [%d/%d]: %-50s ",m,map_num,fn);
if (map_num) { //avoid map-server crashing if there are 0 maps
- printf("\r");
- ShowStatus("Progress: ");
+ printf("\r");
+ ShowStatus("Progress: ");
i=m*20/420;
printf("[");
for (e=0;e<i;e++) progress[e] = '#';
@@ -1616,32 +1853,52 @@ static int map_readmap(int m,char *fn, char *alias) {
printf("] Working: [");
fflush(stdout);
}
+
+ if(map_cache_read(&map[m])) {
+ // キャッシュから読み込めた
+ (*map_cache)++;
+ } else {
+ int s;
+ int wh;
+ int x,y,xs,ys;
+ struct gat_1cell {float high[4]; int type;} *p=NULL;
+ // read & convert fn
+ gat=grfio_read(fn);
+ if(gat==NULL) {
+ return -1;
+ // さすがにマップが読めないのはまずいので終了する
+ //printf("Can't load map %s\n",fn);
+ //exit(1);
+ }
+
+ xs=map[m].xs=*(int*)(gat+6);
+ ys=map[m].ys=*(int*)(gat+10);
+ map[m].gat = (unsigned char *)aCalloc(s = map[m].xs * map[m].ys,sizeof(unsigned char));
+ wh=map_waterheight(map[m].name);
+ for(y=0;y<ys;y++){
+ p=(struct gat_1cell*)(gat+y*xs*20+14);
+ for(x=0;x<xs;x++){
+ if(wh!=NO_WATER && p->type==0){
+ // 水場判定
+ map[m].gat[x+y*xs]=(p->high[0]>wh || p->high[1]>wh || p->high[2]>wh || p->high[3]>wh) ? 3 : 0;
+ } else {
+ map[m].gat[x+y*xs]=p->type;
+ }
+ p++;
+ }
+ }
+ map_cache_write(&map[m]);
+ free(gat);
+ }
+
map[m].m=m;
- xs=map[m].xs=*(int*)(gat+6);
- ys=map[m].ys=*(int*)(gat+10);
- map[m].gat = (unsigned char *)aCalloc(s = map[m].xs * map[m].ys,sizeof(unsigned char));
map[m].npc_num=0;
map[m].users=0;
memset(&map[m].flag,0,sizeof(map[m].flag));
if(battle_config.pk_mode)
map[m].flag.pvp = 1; // make all maps pvp for pk_mode [Valaris]
- wh=map_waterheight(map[m].name);
- for(y=0;y<ys;y++){
- p=(struct gat_1cell*)(gat+y*xs*20+14);
- for(x=0;x<xs;x++){
- if(wh!=NO_WATER && p->type==0){
- // 水場判定
- map[m].gat[x+y*xs]=(p->high[0]>wh || p->high[1]>wh || p->high[2]>wh || p->high[3]>wh) ? 3 : 0;
- } else {
- map[m].gat[x+y*xs]=p->type;
- }
- p++;
- }
- }
- free(gat);
-
- map[m].bxs=(xs+BLOCK_SIZE-1)/BLOCK_SIZE;
- map[m].bys=(ys+BLOCK_SIZE-1)/BLOCK_SIZE;
+ map[m].bxs=(map[m].xs+BLOCK_SIZE-1)/BLOCK_SIZE;
+ map[m].bys=(map[m].ys+BLOCK_SIZE-1)/BLOCK_SIZE;
size = map[m].bxs * map[m].bys * sizeof(struct block_list*);
map[m].block = (struct block_list **)aCalloc(1,size);
map[m].block_mob = (struct block_list **)aCalloc(1,size);
@@ -1671,18 +1928,31 @@ int map_readallmap(void) {
#ifdef USE_AFM
FILE *afm_file;
#endif
+ int map_cache = 0;
+
+ // マップキャッシュを開く
+ if(map_read_flag == READ_FROM_BITMAP) {
+ map_cache_open(map_bitmap_filename);
+ }
- ShowStatus("Loading Maps...\n");
+ 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 == READ_FROM_AFM ? " (w/ AFM)" : ""));
+ ShowStatus(tmp_output);
// 先に全部のャbプの存在を確認
for(i=0;i<map_num;i++){
+
#ifdef USE_AFM
char afm_name[256] = "";
char *p;
- strncpy(afm_name, map[i].name, strlen(map[i].name) - 4);
- strcat(afm_name, ".afm");
+ if(!strstr(map[i].name,".afm")) {
+ // check if it's necessary to replace the extension - speeds up loading abit
+ strncpy(afm_name, map[i].name, strlen(map[i].name) - 4);
+ strcat(afm_name, ".afm");
+ }
map[i].alias = NULL;
-
sprintf(fn,"%s\\%s",afm_dir,afm_name);
for(p=&fn[0];*p!=0;p++) if (*p=='\\') *p = '/'; // * At the time of Unix
@@ -1705,7 +1975,7 @@ int map_readallmap(void) {
map[i].alias = NULL;
sprintf(fn,"data\\%s",map[i].name);
- if(map_readmap(i,fn, p) == -1) {
+ if(map_readmap(i,fn, p, &map_cache) == -1) {
map_delmap(map[i].name);
maps_removed++;
i--;
@@ -1729,6 +1999,12 @@ int map_readallmap(void) {
printf("\r");
snprintf(tmp_output,sizeof(tmp_output),"Successfully loaded '"CL_WHITE"%d"CL_RESET"' maps.%30s\n",map_num,"");
ShowInfo(tmp_output);
+
+ map_cache_close();
+ if(map_read_flag == CREATE_BITMAP) {
+ map_read_flag = READ_FROM_BITMAP;
+ }
+
if (maps_removed) {
snprintf(tmp_output,sizeof(tmp_output),"Maps Removed: '"CL_WHITE"%d"CL_RESET"'\n",maps_removed);
ShowNotice(tmp_output);
@@ -1937,6 +2213,11 @@ int map_config_read(char *cfgName) {
strcpy(help_txt, w2);
} else if (strcmpi(w1, "mapreg_txt") == 0) {
strcpy(mapreg_txt, w2);
+ }else if(strcmpi(w1,"read_map_from_bitmap")==0){
+ if (atoi(w2) == 1)
+ map_read_flag = READ_FROM_BITMAP;
+ else
+ map_read_flag = READ_FROM_GAT;
} else if (strcmpi(w1, "import") == 0) {
map_config_read(w2);
} else if (strcmpi(w1, "console") == 0) {
@@ -2125,6 +2406,13 @@ int sql_config_read(char *cfgName)
strcpy(log_db_pw, w2);
} 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)
+ 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);
//support the import command, just like any other config
} else if(strcmpi(w1,"import")==0){
sql_config_read(w2);
@@ -2250,7 +2538,10 @@ void do_final(void) {
numdb_final(charid_db, charid_db_final);
for(i=0;i<=map_num;i++){
- if(map[i].gat) free(map[i].gat);
+ if(map[i].gat) {
+ free(map[i].gat);
+ map[i].gat=NULL;
+ }
if(map[i].block) free(map[i].block);
if(map[i].block_mob) free(map[i].block_mob);
if(map[i].block_count) free(map[i].block_count);
@@ -2350,8 +2641,10 @@ int do_init(int argc, char *argv[]) {
else if (strcmp(argv[i],"--sql_config") == 0 || strcmp(argv[i],"--sql-config") == 0)
SQL_CONF_NAME = argv[i+1];
else if (strcmp(argv[i],"--log_config") == 0 || strcmp(argv[i],"--log-config") == 0)
- LOG_CONF_NAME = argv[i+1];
+ LOG_CONF_NAME = argv[i+1];
#endif /* not TXT_ONLY */
+ else if (strcmp(argv[i],"--run_once") == 0) // close the map-server as soon as its done.. for testing [Celest]
+ runflag = 0;
}
map_config_read(MAP_CONF_NAME);