New mapcache system :x

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@9971 54d463be-8e91-2dee-dedb-b68131a5f0ec
This commit is contained in:
DracoRPG 2007-03-07 02:02:32 +00:00
parent 07e53259a5
commit deb34a8ae5
12 changed files with 811 additions and 1491 deletions

View File

@ -3,6 +3,15 @@ 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.
2007/03/08
* Here comes the new mapcache system! [DracoRPG]
- The last and only big "feature" (kind of cleanup in fact) you'll see
- Totally removes GRF/GAT handling from map-server that only reads from cache
- The cache now also contains map indexes, and is mostly zipped (1.5MB atm)
- It is shipped with eA => 100% client-independant, no more missing maps
- If you want to add custom maps, the mapcache builder is available, doc
and Unix Makefile coming as soon as possible (VC8 project only ATM :/)
- Removed now useless AFM/AF2 support, as well as the startup screen notice
2007/03/07
* Corrected the define for NK no cardfix (def).
* Fixed the char sql server not escaping the server name before inserting

View File

@ -1,5 +1,10 @@
Date Added
2007/03/08
* Adjustments for the new mapcache [DracoRPG]
- Removed ".gat" from map names in maps_athena.conf
- Removed read_map_from_cache option as there's no more choice to do
- Removed afm_dir option as there's no more need for AFM/AF2 support
2007/03/06
* Added the two new packet versions to battle/client.conf [Zephiris]
2007/03/05

View File

@ -69,26 +69,12 @@ stdout_with_ansisequence: no
//Example: "console_silent: 7" Hides information, status and notice messages (1+2+4)
console_silent: 0
//Preferred map loading method
// 0: Read directly from grf
// 1: Read from cache (with compression)
// 2: Read from cache (without compression)
// If the cache was not found it will read the maps from the GRF and copy
// any necessary data into a newly created cache.
// 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_cache: 1
//
//Where is the bitmap file stored?
map_cache_file: db/mapinfo.txt
//Where should the map data be read from?
map_cache_file: db/map_cache.dat
//Where should all database data be read from?
db_path: db
// Advanced Fusion Maps directory
afm_dir: afm
// Enable the @guildspy and @partyspy at commands?
// Note that enabling them decreases packet sending performance.
enable_spy: no

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,10 @@
-----
========================
03/08
* Added new map_cache.dat containing every map you need at the moment [DracoRPG]
- Beware as it was built by a little-endian (i386), for a little-endian!
- It will be updated by devs when new maps will be added to eA
03/07
* Updated skills that shouldn't ignore the target's cards: Smoking, Fling,
Zenynage. [Skotlex]

BIN
db/map_cache.dat Normal file

Binary file not shown.

View File

@ -199,7 +199,6 @@ static void display_title(void)
ShowMessage(""CL_XXBL" ("CL_BOLD" ( e | n | g | l | i | s | h ) ( A | t | h | e | n | a ) "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); // 1: bold char, 0: normal char
ShowMessage(""CL_XXBL" ("CL_BOLD" \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); // 1: bold char, 0: normal char
ShowMessage(""CL_XXBL" ("CL_BOLD" "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); // yellow writing (33)
ShowMessage(""CL_XXBL" ("CL_BT_YELLOW" Advanced Fusion Maps (c) 2003-2005 The Fusion Project "CL_XXBL")"CL_CLL""CL_NORMAL"\n"); // yellow writing (33)
ShowMessage(""CL_WTBL" (=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=)"CL_CLL""CL_NORMAL"\n\n"); // reset color
ShowInfo("SVN Revision: '"CL_WHITE"%s"CL_RESET"'.\n", get_svn_revision());

View File

@ -100,7 +100,6 @@ ACMD_FUNC(produce);
ACMD_FUNC(memo);
ACMD_FUNC(gat);
ACMD_FUNC(packet);
ACMD_FUNC(waterlevel);
ACMD_FUNC(statuspoint);
ACMD_FUNC(skillpoint);
ACMD_FUNC(zeny);
@ -390,7 +389,6 @@ static AtCommandInfo atcommand_info[] = {
{ AtCommand_GAT, "@gat", 99, atcommand_gat }, // debug function
{ AtCommand_Packet, "@packet", 99, atcommand_packet }, // debug function
{ AtCommand_Packet, "@packetmode", 99, atcommand_packet }, // debug function
{ AtCommand_WaterLevel, "@waterlevel", 99, atcommand_waterlevel }, // debug function
{ AtCommand_StatusPoint, "@stpoint", 60, atcommand_statuspoint },
{ AtCommand_SkillPoint, "@skpoint", 60, atcommand_skillpoint },
{ AtCommand_Zeny, "@zeny", 60, atcommand_zeny },
@ -3935,32 +3933,6 @@ int atcommand_packet(const int fd, struct map_session_data* sd, const char* comm
return 0;
}
/*==========================================
* @waterlevel [Skotlex]
*------------------------------------------
*/
int atcommand_waterlevel(const int fd, struct map_session_data* sd, const char* command, const char* message)
{
int newlevel;
if (!message || !*message || sscanf(message, "%d", &newlevel) < 1) {
sprintf(atcmd_output, "%s's current water level: %d", map[sd->bl.m].name, map_waterheight(map[sd->bl.m].name));
clif_displaymessage(fd, atcmd_output);
return 0;
}
if (map_setwaterheight(sd->bl.m, map[sd->bl.m].name, newlevel)) {
if (newlevel > 0)
sprintf(atcmd_output, "%s's water level changed to: %d", map[sd->bl.m].name, newlevel);
else
sprintf(atcmd_output, "Removed %s's water level information.", map[sd->bl.m].name);
clif_displaymessage(fd, atcmd_output);
} else {
sprintf(atcmd_output, "Failed to change %s's water level.", map[sd->bl.m].name);
clif_displaymessage(fd, atcmd_output);
}
return 0;
}
/*==========================================
* @stpoint (Rewritten by [Yor])
*------------------------------------------
@ -5475,8 +5447,6 @@ int atcommand_mapinfo(const int fd, struct map_session_data* sd, const char* com
}
sprintf(atcmd_output, "Map Name: %s | Players In Map: %d | NPCs In Map: %d | Chats In Map: %d", atcmd_player_name, map[m_id].users, map[m_id].npc_num, chat_num);
clif_displaymessage(fd, atcmd_output);
if (map[m_id].flag.alias)
strcat(atcmd_output, "This map is an alias (a named clone of some other map).");
clif_displaymessage(fd, "------ Map Flags ------");
strcpy(atcmd_output,"PvP Flags: ");
if (map[m_id].flag.pvp)

View File

@ -58,7 +58,6 @@ enum AtCommandType {
AtCommand_Model,
AtCommand_Go,
AtCommand_Spawn,
//AtCommand_Monster, // removed for Skots [Reddozen]
AtCommand_MonsterSmall,
AtCommand_MonsterBig,
AtCommand_KillMonster,
@ -68,7 +67,6 @@ enum AtCommandType {
AtCommand_Memo,
AtCommand_GAT,
AtCommand_Packet,
AtCommand_WaterLevel,
AtCommand_StatusPoint,
AtCommand_SkillPoint,
AtCommand_Zeny,

View File

@ -142,8 +142,6 @@ static int block_free_count = 0, block_free_lock = 0;
static struct block_list *bl_list[BL_LIST_MAX];
static int bl_list_count = 0;
static char afm_dir[1024] = ""; // [Valaris]
struct map_data map[MAX_MAP_PER_SERVER];
int map_num = 0;
@ -161,11 +159,7 @@ struct charid2nick {
int req_id;
};
// ォ゙ォテォラォュォ罩テォキォ袮ラ鯑ォユォ鬮ー(map_athana.conf?ェホread_map_from_cacheェヌ<EFBDAA>・)
// 0:ララ鯑ェキェハェ、 1:゙ェ?<3F>ワチ<EFBE9C> 2:?<3F>ワチ<EFBE9C>
int map_read_flag = READ_FROM_GAT;
char map_cache_file[256]="db/map.info"; // ォ゙ォテォラォュォ罩テォキォ雖ユォ。ォ、ォ・」
char map_cache_file[256]="db/map_cache.dat";
char db_path[256] = "db";
char motd_txt[256] = "conf/motd.txt";
char help_txt[256] = "conf/help.txt";
@ -2432,328 +2426,58 @@ int map_eraseipport(unsigned short mapindex,unsigned long ip,int port)
return 0;
}
#define NO_WATER 1000000
static int map_setwaterheight_sub(int m) {
char fn[256];
char *gat;
int x,y;
int wh;
struct gat_1cell {float high[4]; int type;} *p = NULL;
if (m < 0)
return 0;
wh = map[m].water_height;
sprintf(fn,"data\\%s",mapindex_id2name(map[m].index));
// read & convert fn
// again, might not need to be unsigned char
gat = (char *) grfio_read (fn);
if (gat == NULL)
return 0;
for (y = 0; y < map[m].ys; y++) {
p = (struct gat_1cell*)(gat+y*map[m].xs*20+14);
for (x = 0; x < map[m].xs; x++) {
if (wh != NO_WATER && p->type == 0) //Set water cell
map[m].gat[x+y*map[m].xs] = (p->high[0]>wh || p->high[1]>wh || p->high[2]>wh || p->high[3]>wh) ? 3 : 0;
else //Remove water cell
map[m].gat[x+y*map[m].xs] = p->type==3?0:p->type;
p++;
}
}
aFree(gat);
return 1;
}
int map_setwaterheight(int m, char *mapname, int height) {
if (height < 0)
height = NO_WATER;
map[m].water_height = height;
return map_setwaterheight_sub(m);
}
/* map_readwaterheight
* Reads from the .rsw for each map
* Returns water height (or NO_WATER if file doesn't exist)
* or other error is encountered.
* This receives a map-name, and changes the extension to rsw if it isn't set already.
* Assumed path for file is data/mapname.rsw
* Credits to LittleWolf
*/
int map_waterheight(char *mapname) {
char fn[256];
char *rsw, *found;
float whtemp;
int wh;
//Look up for the rsw
if(!strstr(mapname,"data\\"))
sprintf(fn,"data\\%s", mapname);
else
strcpy(fn, mapname);
found = grfio_find_file(fn);
if (!found)
; //Stick to the current fn
else if(!strstr(found,"data\\"))
sprintf(fn,"data\\%s", found);
else
strcpy(fn, found);
rsw = strstr(fn, ".");
if (rsw && strstr(fn, ".rsw") == NULL)
sprintf(rsw,".rsw");
// read & convert fn
// again, might not need to be unsigned char
rsw = (char *) grfio_read (fn);
if (rsw)
{ //Load water height from file
whtemp = *(float*)(rsw+166);
wh = (int) whtemp;
aFree(rsw);
return wh;
}
ShowWarning("Failed to find water level for (%s)\n", mapname, fn);
return NO_WATER;
}
/*==========================================
*
* Map cache reading
*===========================================*/
// マップキャッシュの最大値
#define MAX_MAP_CACHE 768
// This is the main header found at the very beginning of the file
/*struct map_cache_head {
long filesize;
unsigned short map_count;
};*/
//各マップごとの最小限情報を入れるもの、READ_FROM_BITMAP用
// This is the header appended before every compressed map cells info
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 map_cache_head {
int sizeof_header;
int sizeof_map;
// 上の2つ改変不可
int nmaps; // マップの個数
int filesize;
char name[MAP_NAME_LENGTH];
unsigned short index;
short xs;
short ys;
long len;
};
struct {
struct map_cache_head head;
struct map_cache_info *map;
FILE *fp;
int dirty;
} map_cache;
FILE *map_cache_fp;
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)
int map_readmap(struct map_data *m)
{
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 = (struct map_cache_info *) 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);
int i;
unsigned short map_count;
struct map_cache_info info;
unsigned long size;
unsigned char *buf;
fseek(map_cache_fp, 0, SEEK_SET);
fread(&map_count, sizeof(map_count), 1, map_cache_fp);
for(i = 0; i < map_count; i++) {
fread(&info, sizeof(info), 1, map_cache_fp);
if(strcmp(m->name, info.name) == 0) { // Map found
m->index = info.index;
m->xs = info.xs;
m->ys = info.ys;
m->gat = (unsigned char *)aMalloc(m->xs*m->ys); // Allocate room for map cells data
buf = aMalloc(info.len); // Allocate a temp buffer to read the zipped map
fread(buf, info.len, 1, map_cache_fp);
size = m->xs*m->ys;
decode_zip(m->gat, &size, buf, info.len); // Unzip the map from the buffer
aFree(buf);
return 1;
}
fclose(map_cache.fp);
} else // Map not found, jump to the beginning of the next map info header
fseek(map_cache_fp, info.len, SEEK_CUR);
}
// 読み甲ンに失敗したので新規に作成する
map_cache.fp = fopen(fn,"wb");
if(map_cache.fp) {
memset(&map_cache.head,0,sizeof(struct map_cache_head));
map_cache.map = (struct map_cache_info *) aCalloc(sizeof(struct map_cache_info),MAX_MAP_CACHE);
map_cache.head.nmaps = MAX_MAP_CACHE;
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);
aFree(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].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;
m->water_height = map_cache.map[i].water_height;
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; aFree(m->gat); m->gat = NULL;
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->water_height = map_cache.map[i].water_height;
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) {
// なぜかファイル後半が欠けてるので読み直し
ShowError("fread error\n");
aFree(m->gat); m->xs = 0; m->ys = 0; m->gat = NULL;
aFree(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) {
// 正常に解凍が出来てない
aFree(m->gat); m->xs = 0; m->ys = 0; m->gat = NULL;
aFree(buf);
return 0;
}
aFree(buf);
return 1;
}
}
}
return 0;
}
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].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 == 2) {
// 圧縮保存
// さすがに2倍に膨れる事はないという事で
write_buf = (char *) aMalloc(m->xs * m->ys * 2);
len_new = m->xs * m->ys * 2;
encode_zip((unsigned char *) 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 = (char *) 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(write_buf,1,len_new,map_cache.fp);
} else {
// 新しい場所に登録
fseek(map_cache.fp,map_cache.head.filesize,SEEK_SET);
fwrite(write_buf,1,len_new,map_cache.fp);
map_cache.map[i].pos = map_cache.head.filesize;
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 = m->water_height;
map_cache.dirty = 1;
if(map_read_flag == 2) {
aFree(write_buf);
}
return 0;
}
}
// 同じエントリが無ければ書き甲゚る場所を探す
for(i = 0;i < map_cache.head.nmaps ; i++) {
if(map_cache.map[i].fn[0] == 0) {
// 新しい場所に登録
if(map_read_flag == 2) {
write_buf = (char *) aMalloc(m->xs * m->ys * 2);
len_new = m->xs * m->ys * 2;
encode_zip((unsigned char *) 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 = (char *) 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(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 = m->water_height;
map_cache.head.filesize += len_new;
map_cache.dirty = 1;
if(map_read_flag == 2)
aFree(write_buf);
return 0;
}
}
// 書き甲゚なかった
return 1;
}
/*==========================================
* ??mapを追加する
*------------------------------------------
*/
int map_addmap(char *mapname) {
if (strcmpi(mapname,"clear")==0) {
map_num=0;
@ -2770,10 +2494,6 @@ int map_addmap(char *mapname) {
return 0;
}
/*==========================================
* Removes the map in the index passed.
*------------------------------------------
*/
static void map_delmapid(int id)
{
ShowNotice("Removing map [ %s ] from maplist\n",map[id].name);
@ -2781,10 +2501,6 @@ static void map_delmapid(int id)
map_num--;
}
/*==========================================
* ??mapを削除する
*------------------------------------------
*/
int map_delmap(char *mapname) {
int i;
@ -2803,323 +2519,29 @@ int map_delmap(char *mapname) {
return 0;
}
////////////////////////////////////////////////
/*
Advanced Fusion Maps Support
(c) 2003-2004, The Fusion Project
- AlexKreuz
The following code has been provided by me for eAthena
under the GNU GPL. It provides Advanced Fusion
Map, the map format desgined by me for Fusion, support
for the eAthena emulator.
I understand that because it is under the GPL
that other emulators may very well use this code in their
GNU project as well.
The AFM map format was not originally a part of the GNU
GPL. It originated from scratch by my own hand. I understand
that distributing this code to read the AFM maps with eAthena
causes the GPL to apply to this code. But the actual AFM
maps are STILL copyrighted to the Fusion Project. By choosing
In exchange for that 'act of faith' I ask for the following.
A) Give credit where it is due. If you use this code, do not
place your name on the changelog. Credit should be given
to AlexKreuz.
B) As an act of courtesy, ask me and let me know that you are putting
AFM support in your project. You will have my blessings if you do.
C) Use the code in its entirety INCLUDING the copyright message.
Although the code provided may now be GPL, the AFM maps are not
and so I ask you to display the copyright message on the STARTUP
SCREEN as I have done here. (refer to core.c)
"Advanced Fusion Maps (c) 2003-2004 The Fusion Project"
Without this copyright, you are NOT entitled to bundle or distribute
the AFM maps at all. On top of that, your "support" for AFM maps
becomes just as shady as your "support" for Gravity GRF files.
The bottom line is this. I know that there are those of you who
would like to use this code but aren't going to want to provide the
proper credit. I know this because I speak frome experience. If
you are one of those people who is going to try to get around my
requests, then save your breath because I don't want to hear it.
I have zero faith in GPL and I know and accept that if you choose to
not display the copyright for the AFMs then there is absolutely nothing
I can do about it. I am not about to start a legal battle over something
this silly.
Provide the proper credit because you believe in the GPL. If you choose
not to and would rather argue about it, consider the GPL failed.
October 18th, 2004
- AlexKreuz
- The Fusion Project
*/
static int map_loadafm (struct map_data *m, char *fn)
{
// check if .afm file exists
FILE *afm_file = fopen(fn, "r");
if (afm_file != NULL) {
int x,y,xs,ys;
char afm_line[65535];
int afm_size[2];
char *str;
//Gotta skip the first two lines which are just a header of sorts.
str = fgets(afm_line, sizeof(afm_line)-1, afm_file);
str = fgets(afm_line, sizeof(afm_line)-1, afm_file);
str = fgets(afm_line, sizeof(afm_line)-1, afm_file);
if (!str) return 0;
sscanf(str , "%d%d", &afm_size[0], &afm_size[1]);
xs = m->xs = afm_size[0];
ys = m->ys = afm_size[1];
m->water_height = map_waterheight(m->name);
// check this, unsigned where it might not need to be
m->gat = (unsigned char*)aMallocA(xs * ys);
for (y = 0; y < ys; y++) {
str = fgets(afm_line, sizeof(afm_line)-1, afm_file);
for (x = 0; x < xs; x++)
m->gat[x+y*xs] = str[x]-48;
}
fclose(afm_file);
return 1;
}
return 0;
}
/*==================================
* .AFM format
*----------------------------------
*/
int map_readafm (struct map_data *m)
{
char afm_name[256] = "";
char fn[256], *p;
// convert map name to .afm
if(!strstr(m->name, ".afm")) {
// check if it's necessary to replace the extension - speeds up loading a bit
strncpy(afm_name, m->name, strlen(m->name) - 4);
strcat(afm_name, ".afm");
} else {
strcpy(afm_name, m->name);
}
sprintf(fn, "%s\\%s", afm_dir, afm_name);
for (p = &fn[0]; *p != 0; p++)
if (*p == '\\') *p = '/'; // * At the time of Unix
return map_loadafm(m, fn);
}
/*==================================
* .AF2 format
*----------------------------------
*/
int map_readaf2 (struct map_data *m)
{
FILE *af2_file;
char af2_name[256] = "";
char fn[256], *p, *out;
// convert map name to .af2
p = out = m->name;
while ((p = strchr(p, '/')) != NULL)
out = ++p;
strncpy (af2_name, out, strlen(out));
// grr, this is so troublesome >.< [celest]
p = strrchr (af2_name, '.');
if (p) *p++ = 0;
strcat(af2_name, ".af2");
sprintf(fn, "%s\\%s", afm_dir, af2_name);
for (p = &fn[0]; *p != 0; p++)
if (*p == '\\') *p = '/'; // * At the time of Unix
// check if .af2 file exists
af2_file = fopen(fn, "r");
if (af2_file != NULL) {
char out_file[256];
fclose(af2_file);
// convert map name to .out
strncpy (out_file, out, strlen(out));
p = strrchr (out_file, '.');
if (p) *p++ = 0;
strcat(out_file, ".out");
// unzip .out file and use loadafm()
if (deflate_file(fn, out_file) &&
map_loadafm(m, out_file))
{
unlink (out_file);
return 1;
}
}
return 0;
}
/*==========================================
* 1
* ===================================================*/
//static int map_readmap(int m,char *fn, char *alias, int *map_cache, int maxmap) {
/*==================================
* .GAT format
*----------------------------------
*/
int map_readgat (struct map_data *m)
{
char fn[256];
char *gat;
int wh,x,y,xs,ys;
struct gat_1cell {float high[4]; int type;} *p = NULL;
if (strstr(m->name,".gat") == NULL)
return 0;
sprintf(fn,"data\\%s",m->name);
// read & convert fn
// again, might not need to be unsigned char
gat = (char *) grfio_read (fn);
if (gat == NULL)
return 0;
xs = m->xs = *(int*)(gat+6);
ys = m->ys = *(int*)(gat+10);
m->gat = (unsigned char *)aMallocA((m->xs * m->ys)*sizeof(unsigned char));
m->water_height = wh = map_waterheight(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)
// 水場判定
m->gat[x+y*xs] = (p->high[0]>wh || p->high[1]>wh || p->high[2]>wh || p->high[3]>wh) ? 3 : 0;
else
m->gat[x+y*xs] = p->type;
p++;
}
}
aFree(gat);
return 1;
}
//////////////////////////////////////////////////////
static int map_cache_init (void);
static int map_readafm_init (void);
static int map_readaf2_init (void);
static int map_readgat_init (void);
// Todo: Properly implement this system as plugins/safer code [Celest]
enum {
MAP_CACHE = 0, // jAthena map cache
MAP_AFM, // Advanced Fusion Map
MAP_AF2, // Advanced Fusion Map
MAP_GAT, // GRF map
MAP_MAXSOURCE
};
// in descending order
int (*mapsource_init[MAP_MAXSOURCE])(void) = {
map_cache_init,
map_readafm_init,
map_readaf2_init,
map_readgat_init
};
int (*mapsource_read[MAP_MAXSOURCE])(struct map_data *) = {
map_cache_read,
map_readafm,
map_readaf2,
map_readgat
};
void (*mapsource_final[MAP_MAXSOURCE])(void) = {
map_cache_close,
NULL,
NULL,
NULL
};
static int map_cache_init (void)
{
if (map_read_flag >= READ_FROM_BITMAP && map_cache_open(map_cache_file)) {
ShowMessage("[cache] ");
return 1;
}
return 0;
}
static int map_readafm_init (void)
{
ShowMessage("[afm] ");
return 1;
}
static int map_readaf2_init (void)
{
// check if AFM loading is available,
// otherwise disable AF2 loading
if (mapsource_read[1] != NULL) {
ShowMessage("[af2] ");
return 1;
}
return 0;
}
static int map_readgat_init (void)
{
ShowMessage("[gat] ");
return 1;
}
/*======================================
* Initiate maps loading stage
*--------------------------------------
*/
int map_readallmaps (void)
int map_readallmaps()
{
// pre-loading stage
int i;
int maps_removed = 0;
int maps_cached = 0;
ShowMessage(CL_GREEN"[Status]"CL_RESET": Loading Maps with... "CL_WHITE);
if(!(map_cache_fp = fopen(map_cache_file, "rb")))
ShowError("Unable to open map cache file "CL_WHITE"%s"CL_RESET"\n", map_cache_file);
for (i = 0; i < MAP_MAXSOURCE; i++) {
if (mapsource_init[i] && // check if source requires initialisation
mapsource_init[i]() == 0) // if init failed
{
// remove all loading methods associated with this source
mapsource_init[i] = NULL;
mapsource_read[i] = NULL;
mapsource_final[i] = NULL;
}
}
ShowStatus("Loading maps...\n");
ShowMessage(CL_RESET"\n");
// initiate map loading
for (i = 0; i < map_num; i++)
for(i = 0; i < map_num; i++)
{
int success = 0;
static int lasti = -1;
static int last_time = -1;
int j = i*20/map_num;
size_t size;
// show progress
if (map_num && //avoid map-server crashing if there are 0 maps
(j != lasti || last_time != time(0)))
if(j != lasti || last_time != time(0))
{
char progress[21] = " ";
char c = '-';
@ -3141,99 +2563,52 @@ int map_readallmaps (void)
fflush(stdout);
}
// pre-init some data
map[i].alias = NULL;
map[i].m = i;
memset (map[i].moblist, 0, sizeof(map[i].moblist)); //Initialize moblist [Skotlex]
map[i].mob_delete_timer = -1; //Initialize timer [Skotlex]
if (battle_config.pk_mode)
map[i].flag.pvp = 1; // make all maps pvp for pk_mode [Valaris]
for (j = 0; j < MAP_MAXSOURCE; j++)
{
if (mapsource_read[j] && // check if map source is valid
mapsource_read[j](&map[i])) // check if map source is available
{
// successful, now initialise map
size_t size;
char *alias;
if (map[i].alias && (alias = strstr(map[i].name, "<")) != NULL) { // alias has been set by one of the sources
*alias++ = '\0';
}
if (map[i].alias)
map[i].index = mapindex_name2id(map[i].alias);
else
map[i].index = mapindex_name2id(map[i].name);
if (!map[i].index) {
if (map[i].alias)
ShowWarning("Map %s (alias %s) is not in the map-index cache!\n", map[i].name, map[i].alias);
else
ShowWarning("Map %s is not in the map-index cache!\n", map[i].name);
success = 0; //Can't load a map that isn't in our cache.
if (map[i].gat) {
aFree(map[i].gat);
map[i].gat = NULL;
}
break;
}
if (uidb_get(map_db,(unsigned int)map[i].index) != NULL) {
ShowWarning("Map %s already loaded!\n", map[i].name);
success = 0; //Can't load a map already in the db
if (map[i].gat) {
aFree(map[i].gat);
map[i].gat = NULL;
}
break;
}
map[i].cell = (unsigned char *)aCalloc(map[i].xs * map[i].ys, sizeof(unsigned char));
#ifdef CELL_NOSTACK
map[i].cell_bl = (unsigned char *)aCalloc(map[i].xs * map[i].ys, sizeof(unsigned char));
#endif
map[i].bxs = (map[i].xs + BLOCK_SIZE - 1) / BLOCK_SIZE;
map[i].bys = (map[i].ys + BLOCK_SIZE - 1) / BLOCK_SIZE;
// default experience multiplicator
map[i].jexp = 100;
map[i].bexp = 100;
size = map[i].bxs * map[i].bys * sizeof(struct block_list*);
map[i].block = (struct block_list**)aCalloc(size, 1);
map[i].block_mob = (struct block_list**)aCalloc(size, 1);
size = map[i].bxs * map[i].bys * sizeof(int);
map[i].block_count = (int*)aCallocA(size, 1);
map[i].block_mob_count = (int*)aCallocA(size, 1);
uidb_put(map_db, (unsigned int)map[i].index, &map[i]);
// cache our map if necessary
if (j != MAP_CACHE && mapsource_read[MAP_CACHE] != NULL) { // map data is not cached yet
map_cache_write(&map[i]);
maps_cached++;
}
// next map
success = 1;
break;
}
}
// no sources have been found, so remove map from list
if (!success) {
if(!map_readmap(&map[i])) {
map_delmapid(i);
maps_removed++;
i--;
continue;
}
}
// unload map sources
for (i = 0; i < MAP_MAXSOURCE; i++) {
if (mapsource_final[i])
mapsource_final[i]();
if (uidb_get(map_db,(unsigned int)map[i].index) != NULL) {
ShowWarning("Map %s already loaded!\n", map[i].name);
if (map[i].gat) {
aFree(map[i].gat);
map[i].gat = NULL;
}
map_delmapid(i);
maps_removed++;
i--;
continue;
}
map[i].m = i;
memset(map[i].moblist, 0, sizeof(map[i].moblist)); //Initialize moblist [Skotlex]
map[i].mob_delete_timer = -1; //Initialize timer [Skotlex]
if(battle_config.pk_mode)
map[i].flag.pvp = 1; // make all maps pvp for pk_mode [Valaris]
map[i].cell = (unsigned char *)aCalloc(map[i].xs * map[i].ys, sizeof(unsigned char));
#ifdef CELL_NOSTACK
map[i].cell_bl = (unsigned char *)aCalloc(map[i].xs * map[i].ys, sizeof(unsigned char));
#endif
map[i].bxs = (map[i].xs + BLOCK_SIZE - 1) / BLOCK_SIZE;
map[i].bys = (map[i].ys + BLOCK_SIZE - 1) / BLOCK_SIZE;
// default experience multiplicators
map[i].jexp = 100;
map[i].bexp = 100;
size = map[i].bxs * map[i].bys * sizeof(struct block_list*);
map[i].block = (struct block_list**)aCalloc(size, 1);
map[i].block_mob = (struct block_list**)aCalloc(size, 1);
size = map[i].bxs * map[i].bys * sizeof(int);
map[i].block_count = (int*)aCallocA(size, 1);
map[i].block_mob_count = (int*)aCallocA(size, 1);
uidb_put(map_db, (unsigned int)map[i].index, &map[i]);
}
// finished map loading
@ -3241,9 +2616,7 @@ int map_readallmaps (void)
ShowInfo("Successfully loaded '"CL_WHITE"%d"CL_RESET"' maps.%30s\n",map_num,"");
if (maps_removed)
ShowNotice("Maps Removed: '"CL_WHITE"%d"CL_RESET"'\n",maps_removed);
if (maps_cached)
ShowNotice("Maps Added to Cache: '"CL_WHITE"%d"CL_RESET"'\n",maps_cached);
ShowNotice("Maps removed: '"CL_WHITE"%d"CL_RESET"'\n",maps_removed);
return 0;
}
@ -3409,19 +2782,10 @@ int map_config_read(char *cfgName) {
strcpy(charhelp_txt, w2);
} else if (strcmpi(w1, "mapreg_txt") == 0) {
strcpy(mapreg_txt, w2);
} else if(strcmpi(w1,"read_map_from_cache") == 0){
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_cache_file") == 0) {
strncpy(map_cache_file,w2,255);
} else if(strcmpi(w1,"db_path") == 0) {
strncpy(db_path,w2,255);
} else if(strcmpi(w1,"afm_dir") == 0) {
strcpy(afm_dir, w2);
} else if (strcmpi(w1, "console") == 0) {
if(strcmpi(w2,"on") == 0 || strcmpi(w2,"yes") == 0 ) {
console = 1;
@ -3740,9 +3104,6 @@ void do_final(void) {
ShowStatus("Terminating...\n");
//we probably don't need the cache open at all times 'yet', so this is closed by mapsource_final [celest]
//map_cache_close();
for (i = 0; i < map_num; i++)
if (map[i].m >= 0)
map_foreachinmap(cleanup_sub, i, BL_ALL);
@ -3761,9 +3122,8 @@ void do_final(void) {
do_final_atcommand();
do_final_battle();
do_final_chrif(); // この内部でキャラを全て切断する
do_final_chrif();
do_final_npc();
// map_removenpc();
do_final_script();
do_final_itemdb();
do_final_storage();
@ -3804,8 +3164,6 @@ void do_final(void) {
pc_db->destroy(pc_db, NULL);
charid_db->destroy(charid_db, NULL);
//#endif
#ifndef TXT_ONLY
map_sql_close();
if(charsave_method)

View File

@ -1073,18 +1073,15 @@ struct map_data {
#ifdef CELL_NOSTACK
unsigned char *cell_bl; //Holds amount of bls in any given cell.
#endif
char *alias; // [MouseJstr]
struct block_list **block;
struct block_list **block_mob;
int *block_count,*block_mob_count;
int m;
short xs,ys;
short bxs,bys;
int water_height;
int npc_num;
int users;
struct map_flag {
unsigned alias : 1;
unsigned nomemo : 1;
unsigned noteleport : 1;
unsigned noreturn : 1;

View File

@ -14,7 +14,7 @@
char grf_list_file[256] = "tools/mapcache/grf_files.txt";
char map_list_file[256] = "tools/mapcache/map_list.txt";
char map_cache_file[256] = "map_cache.dat";
char map_cache_file[256] = "db/map_cache.dat";
#define MAP_NAME_LENGTH 16
#define NO_WATER 1000000
@ -26,6 +26,9 @@ struct map_data {
unsigned char *cells;
};
// This is the main header found at the very beginning of the file
unsigned short map_count;
// This is the header appended before every compressed map cells info
struct map_cache_info {
char name[MAP_NAME_LENGTH];
@ -35,16 +38,10 @@ struct map_cache_info {
long len;
};
// This is the main header found at the very beginning of the file
struct map_cache_head {
short sizeof_header;
short sizeof_mapinfo;
long filesize;
unsigned short map_count;
} header;
FILE *map_cache_fp;
int filesize;
// Read map from GRF's GAT and RSW files
int read_map(char *name, struct map_data *m)
@ -118,11 +115,11 @@ void cache_map(char *name, unsigned short index, struct map_data *m)
info.len = len;
// Append map header then compressed cells at the end of the file
fseek(map_cache_fp, header.filesize, SEEK_SET);
fseek(map_cache_fp, filesize, SEEK_SET);
fwrite(&info, sizeof(struct map_cache_info), 1, map_cache_fp);
fwrite(write_buf, 1, len, map_cache_fp);
header.map_count++;
header.filesize += header.sizeof_mapinfo + len;
map_count++;
filesize += sizeof(struct map_cache_info) + len;
free(write_buf);
free(m->cells);
@ -161,10 +158,8 @@ int main(int argc, char *argv[])
}
// Initialize the main header
header.sizeof_header = sizeof(struct map_cache_head);
header.sizeof_mapinfo = sizeof(struct map_cache_info);
header.map_count = 0;
header.filesize = sizeof(struct map_cache_head);
map_count = 0;
filesize = sizeof(map_count);
// Read and process the map list
while(fgets(line, 1020, list)){
@ -190,13 +185,13 @@ int main(int argc, char *argv[])
printf("Closing map cache: %s\n", map_cache_file);
// Write the main header and close the map cache
fseek(map_cache_fp, 0, SEEK_SET);
fwrite(&header, sizeof(struct map_cache_head), 1, map_cache_fp);
fwrite(&map_count, sizeof(map_count), 1, map_cache_fp);
fclose(map_cache_fp);
printf("Finalizing grfio\n");
grfio_final();
printf("%d maps cached\n", header.map_count);
printf("%d maps cached\n", map_count);
return 0;
}