I'm still here!

Rewrote fame ranking lists- changed MAP_NAME_LENGTH to 12, now there's MAP_NAME_LENGTH_EXT at 16 for
	  uses where there is / may be the .gat extension, code adjusted accordingly
- moved map_normalize_name to mapindex_normalize_name so that everything
	  handling map names uses the same extension-removing function
- greatly enhanced the map cache generator, complete documentation on the
	  tool and the map cache format can be found in doc/
- the map cache format changed a bit as a consequence, but of course a new
	  valid one is included (contains latest Nameless Island maps)
- fixed a duplicate entry in map index


git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@10167 54d463be-8e91-2dee-dedb-b68131a5f0ec
This commit is contained in:
DracoRPG 2007-04-06 17:22:40 +00:00
parent a881931cb6
commit 7c8f12ccd5
25 changed files with 425 additions and 243 deletions

View File

@ -5,6 +5,17 @@ IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
2007/04/07
* Final touches to the whole map crap [DracoRPG]
- changed MAP_NAME_LENGTH to 12, now there's MAP_NAME_LENGTH_EXT at 16 for
uses where there is / may be the .gat extension, code adjusted accordingly
- moved map_normalize_name to mapindex_normalize_name so that everything
handling map names uses the same extension-removing function
- greatly enhanced the map cache generator, complete documentation on the
tool and the map cache format can be found in doc/
- the map cache format changed a bit as a consequence, but of course a new
valid one is included (contains latest Nameless Island maps)
- and I'm sorry for the number of times I've moved around and renamed files,
now the final structure should have been reached
* Capped clif_heal's heal field (the argument received is int, but the
packet field is short, meaning that if the heal is high enough, the client
would receive a negative heal amount). [Skotlex]

View File

@ -744,7 +744,6 @@ map: ice_dun04
// --- Veins & Thor Dungeon ---
// -- 2006-12-19sdata_k.gpf --
map: que_thor
map: thor_camp
map: thor_v01
@ -760,6 +759,17 @@ map: ve_fild05
map: ve_fild06
map: ve_fild07
// --- Unknown Island & Abbey Dungeon ---
// -- 2007-04-02sdata_k.gpf
map: nameless_i
map: nameless_n
map: nameless_in
map: abbey01
map: abbey02
map: abbey03
map: poring_w01
map: poring_w02
//------------------------- Clone Maps ---------------------------
//------------------------- Extra Maps ---------------------------

View File

@ -21,6 +21,8 @@
========================
04/07
* Updated map index and map cache with Nameless Island maps [DracoRPG]
- also removed the duplicate g_room2 entry from map index, read the note
* Corrected Aliza card's item_db line. [Skotlex]
04/05
* Fixed some items that should heal percentual hp/sp [Playtester]

View File

@ -1,15 +0,0 @@
//-----------------------------------------
// GRF List
//-----------------------------------------
grf: C:\Program Files\Gravity\RO\data.grf
grf: C:\Program Files\Gravity\RO\sdata.grf
// You may add more in this format
// grf: <data file path>
//------ Others ---------------------------
//Path to directory that contains the data dir
//NOTE: Path must include trailing backslash, only one data_dir entry is supported.
//data_dir: C:\Program Files\Gravity\RO\

Binary file not shown.

View File

@ -9,6 +9,11 @@
//mapname <- map will use index of previous map +1
//Note that map index 0 is special and reserved for "error" status.
// NOTE TO DEVELOPERS
// Due to a removed duplicate, index 591 is free, if you have to add a single map,
// please add it there instead of the end. Then remove the 592 on next line (rachel)
// and remove all those comments. ~DracoRPG
alb_ship 1
alb2trea
alberta
@ -599,8 +604,8 @@ job_hunter
job_knight
job_priest
job_wizard
g_room2
rachel
// INDEX 591 IS FREE, PLEASE USE IT
rachel 592
ra_in01
ra_fild01
ra_fild02
@ -645,6 +650,14 @@ ve_fild07
poring_c01
poring_c02
que_ng
nameless_i
nameless_n
nameless_in
abbey01
abbey02
abbey03
poring_w01
poring_w02
// Only add maps under this line if they are not standard maps!

View File

@ -1,18 +1,67 @@
"How to use the mapcache builder"
DracoRPG
//===== Athena Doc ========================================
//= Map Cache Builder and Format Documentation
//===== By ================================================
//= DracoRPG
//===== Version ===========================================
//= 1.0
//=========================================================
//= 0.1 - Short howto for the initial builder version
//= 1.0 - Complete manual covering the improved version
//===== Description =======================================
//= A complete manual for eAthena's map cache generator
//= as well as a reference on the map cache format used
//=========================================================
Preface:
-------------------------------------------------------------------------------
Since SVN revision ~10000, the map-server does not know how to read RO client files anymore. It reads maps from a
"map cache" file that contains all and only the useful data about the maps. A map cache containing every official
kRO Sakray map currently supported by eAthena is provided as a default.
If you have custom maps or want to minimize the size of your map cache because your server does not load all of them
(multi-map-server or light test server), you can use the map cache builder to generate a new one fitting your needs.
Map cache builder manual:
-------------------------------------------------------------------------------
The source code for the map cache builder is located in src/tool/. It can be built using "make tools" if you use the Makefile
or using the "mapcache" project under Visual Studio. Named "mapcache", the executable will be in your eAthena main folder.
The map cache builder needs 3 file paths : one is a list of GRFs and/or data directory containing the maps, the second
is the list of maps to add to the map cache, and the last one is the path of the map cache to generate. Default values for
those paths are "tools/mapcache/grf_files.txt", "db/map_index.txt" and "db/map_cache.dat".
The list of GRF and/or data directory must follow the format and indication of the default file: as many "grf:" entries as
you wish and optionally one only "data_dir:" entry with trailing backslash included. // comments are supported as usual.
In fact, any file with one map name per line can be used as a map list, that's why the map index list is used as a default:
we are sure it contains every map supported by the server. Anything after the map name is ignored, // comments are supported
and if the first word on the line is "map:" then the second word is used as the map name instead: that allows using
maps_athena.conf as your map list, which is handy if you want to generate a minimal map cache for each of your multiple
map-servers.
The map cache file path can point to an already existing file, as the builder adds a map only if it's not already cached.
This way, you can add custom maps to the base map cache without even needing kRO Sakray maps. If you wish to rebuild the
entire map cache, though, you can either provide a path to a non-existing file, or force the rebuild mode.
Here are the command-line arguments you can provide to the map cache builder to customize its behavior:
-grf path/to/grf/list
Allows to specify the file containing the list of GRFs and/or data directory
-list path/to/map/list
Allows to specify the file containing the list of maps to add to the map cache
-cache path/to/map/cache
Allows to specify the path to the generated map cache
- rebuild
Allows to force the rebuild mode (map cache will be overwritten even if it already exists)
This is only useful if you have custom maps, as eAthena is provided with an updated mapcache containing every map
from kRO Sakray's data.
Map cache format reference:
-------------------------------------------------------------------------------
1. First add the path to the directory / GRF containing your maps to db/grf_files.txt
/!\ Please note you must also have the official maps as the whole mapcache will be rebuilt from scratch
2. Then add those custom maps at the end of db/map_list.txt, carefully chosing their index
3. Now just run the mapcache builder and it'll build a new one at db/map_cache.dat
NOTE:
You can override those default paths by providing your own ones as command-line arguments to the mapcache builder:
$> mapcache [grf_files_path [map_list_path [map_cache_path]]]
The file is written as little-endian, even on big-endian systems, for cross-compatibility reasons. Appropriate conversions
are done when generating it, so don't worry about it.
The first 6 bytes are a main header:
<unsigned long> file size
<unsigned short> number of maps
Then maps are stored one right after another:
<12-characters-long string> map name
<short> X size
<short> Y size
<long> compressed cell data length
<variable> compressed cell data

View File

@ -1605,10 +1605,6 @@ void create_online_files(void) {
if (online_display_option & 24) { // 8 or 16
// prepare map name
memcpy(temp, mapindex_id2name(char_dat[j].status.last_point.map), MAP_NAME_LENGTH);
temp[MAP_NAME_LENGTH] = '\0';
if (strstr(temp, ".gat") != NULL) {
temp[strstr(temp, ".gat") - temp] = 0; // suppress the '.gat'
}
// write map name
if (online_display_option & 16) { // map-name AND coordinates
fprintf(fp2, " <td>%s (%d, %d)</td>\n", temp, char_dat[j].status.last_point.x, char_dat[j].status.last_point.y);
@ -3532,13 +3528,13 @@ int parse_char(int fd)
{
//Send player to map
uint32 subnet_map_ip;
char map_name[MAP_NAME_LENGTH];
snprintf(map_name, MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(cd->last_point.map));
char map_name[MAP_NAME_LENGTH_EXT];
snprintf(map_name, MAP_NAME_LENGTH_EXT, "%s.gat", mapindex_id2name(cd->last_point.map));
WFIFOHEAD(fd,28);
WFIFOW(fd,0) = 0x71;
WFIFOL(fd,2) = cd->char_id;
memcpy(WFIFOP(fd,6), map_name, MAP_NAME_LENGTH);
memcpy(WFIFOP(fd,6), map_name, MAP_NAME_LENGTH_EXT);
// Advanced subnet check [LuzZza]
subnet_map_ip = lan_subnetcheck(ipl);

View File

@ -3340,13 +3340,12 @@ int parse_char(int fd)
{
//Send player to map.
uint32 subnet_map_ip;
char map_name[MAP_NAME_LENGTH];
snprintf(map_name, MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(char_dat.last_point.map));
char map_name[MAP_NAME_LENGTH_EXT];
snprintf(map_name, MAP_NAME_LENGTH_EXT, "%s.gat", mapindex_id2name(char_dat.last_point.map));
WFIFOHEAD(fd,28);
WFIFOW(fd,0) = 0x71;
WFIFOL(fd,2) = char_dat.char_id;
memcpy(WFIFOP(fd,6), map_name, MAP_NAME_LENGTH);
memcpy(WFIFOP(fd,6), map_name, MAP_NAME_LENGTH_EXT);
// Advanced subnet check [LuzZza]
subnet_map_ip = lan_subnetcheck(ipl);
@ -4024,17 +4023,15 @@ int char_config_read(const char *cfgName) {
} else if (strcmpi(w1, "save_log") == 0) {
save_log = config_switch(w2);
} else if (strcmpi(w1, "start_point") == 0) {
char map[MAP_NAME_LENGTH];
char map[MAP_NAME_LENGTH_EXT];
int x, y;
if (sscanf(w2, "%16[^,],%d,%d", map, &x, &y) < 3)
continue;
if (strstr(map, ".gat") != NULL) { // Verify at least if '.gat' is in the map name
start_point.map = mapindex_name2id(map);
if (!start_point.map)
ShowError("Specified start_point %s not found in map-index cache.\n", map);
start_point.x = x;
start_point.y = y;
}
start_point.map = mapindex_name2id(map);
if (!start_point.map)
ShowError("Specified start_point %s not found in map-index cache.\n", map);
start_point.x = x;
start_point.y = y;
} else if (strcmpi(w1, "start_zeny") == 0) {
start_zeny = atoi(w2);
if (start_zeny < 0)

View File

@ -15,42 +15,53 @@
//Leave an extra char of space to hold the terminator, in case for the strncpy(mapindex_id2name()) calls.
struct indexes {
char name[MAP_NAME_LENGTH+1]; //Stores map name
int length; //Stores string length WITHOUT the extension for quick lookup.
char exists; //Set to 1 if index exists
} indexes[MAX_MAPINDEX];
static unsigned short max_index = 0;
char mapindex_cfgfile[80] = "db/map_list.txt";
char mapindex_cfgfile[80] = "db/map_index.txt";
// Removes the extension from a map name
char *mapindex_normalize_name(char *mapname)
{
char *ptr, *ptr2;
ptr = strchr(mapname, '.');
if (ptr) { //Check and remove extension.
while (ptr[1] && (ptr2 = strchr(ptr+1, '.')))
ptr = ptr2; //Skip to the last dot.
if(stricmp(ptr,".gat") == 0 ||
stricmp(ptr,".afm") == 0 ||
stricmp(ptr,".af2") == 0)
*ptr = '\0'; //Remove extension.
}
return mapname;
}
/// Adds a map to the specified index
/// Returns 1 if successful, 0 oherwise
int mapindex_addmap(int index, const char *name)
{
char map_name[1024];
char *ext;
int length;
if (index < 0 || index >= MAX_MAPINDEX) {
ShowError("(mapindex_add) Map index (%d) for \"%s\" out of range (max is %d)\n", index, name, MAX_MAPINDEX);
return 0;
}
snprintf(map_name, 1024, "%s", name);
map_name[1023] = 0;
length = strlen(map_name);
if (length > MAP_NAME_LENGTH) {
mapindex_normalize_name(map_name);
if (strlen(map_name) > MAP_NAME_LENGTH-1) {
ShowError("(mapindex_add) Map name %s is too long. Maps are limited to %d characters.\n", map_name, MAP_NAME_LENGTH);
return 0;
}
if ((ext = strstr(map_name, ".")) != NULL) { // Remove extension
length = ext-map_name;
*ext = '\0';
}
if (indexes[index].length)
if (indexes[index].exists)
ShowWarning("(mapindex_add) Overriding index %d: map \"%s\" -> \"%s\"\n", index, indexes[index].name, map_name);
strncpy(indexes[index].name, map_name, MAP_NAME_LENGTH);
indexes[index].length = length;
indexes[index].exists = 1;
if (max_index <= index)
max_index = index+1;
return 1;
@ -59,17 +70,18 @@ int mapindex_addmap(int index, const char *name)
unsigned short mapindex_name2id(const char* name) {
//TODO: Perhaps use a db to speed this up? [Skotlex]
int i;
int length = strlen(name);
char *ext = strstr(name, ".");
if (ext)
length = ext-name; //Base map-name length without the extension.
char map_name[1024];
snprintf(map_name, 1024, "%s", name);
mapindex_normalize_name(map_name);
for (i = 1; i < max_index; i++)
{
if (strncmp(indexes[i].name,name,length)==0)
if (strcmp(indexes[i].name,map_name)==0)
return i;
}
#ifdef MAPINDEX_AUTOADD
if( mapindex_addmap(i,name) )
if( mapindex_addmap(i,map_name) )
{
ShowDebug("mapindex_name2id: Auto-added map \"%s\" to position %d\n", indexes[i], i);
return i;
@ -83,7 +95,7 @@ unsigned short mapindex_name2id(const char* name) {
}
const char* mapindex_id2name(unsigned short id) {
if (id > MAX_MAPINDEX || !indexes[id].length) {
if (id > MAX_MAPINDEX || !indexes[id].exists) {
ShowDebug("mapindex_id2name: Requested name for non-existant map index [%d] in cache.\n", id);
return indexes[0].name; //Theorically this should never happen, hence we return this string to prevent null pointer crashes.
}

View File

@ -37,6 +37,7 @@ extern char mapindex_cfgfile[80];
#define MAP_VEINS "veins"
#define MAP_JAIL "sec_pri"
#define MAP_NOVICE "new_zone01"
char *mapindex_normalize_name(char *mapname);
int mapindex_addmap(int index, const char *name);
unsigned short mapindex_name2id(const char*);
const char* mapindex_id2name(unsigned short);

View File

@ -77,8 +77,9 @@
#define NAME_LENGTH 24
//For item names, which tend to have much longer names.
#define ITEM_NAME_LENGTH 50
//For Map Names, which the client considers to be 16 in length
#define MAP_NAME_LENGTH 16
//For Map Names, which the client considers to be 16 in length including the .gat extension
#define MAP_NAME_LENGTH 12
#define MAP_NAME_LENGTH_EXT 16
#define MAX_FRIENDS 40
#define MAX_MEMOPOINTS 10

View File

@ -1310,7 +1310,7 @@ int atcommand_send(const int fd, struct map_session_data* sd, const char* comman
*/
int atcommand_rura( const int fd, struct map_session_data* sd, const char* command, const char* message)
{
char map_name[MAP_NAME_LENGTH];
char map_name[MAP_NAME_LENGTH_EXT];
unsigned short mapindex;
int x = 0, y = 0;
int m = -1;
@ -1698,7 +1698,7 @@ int atcommand_whomap3(const int fd, struct map_session_data* sd, const char* com
int i, count, users;
int pl_GM_level, GM_level;
int map_id;
char map_name[MAP_NAME_LENGTH];
char map_name[MAP_NAME_LENGTH_EXT];
memset(atcmd_output, '\0', sizeof(atcmd_output));
memset(map_name, '\0', sizeof(map_name));
@ -1752,7 +1752,7 @@ int atcommand_whomap2(const int fd, struct map_session_data* sd, const char* com
int i, count, users;
int pl_GM_level, GM_level;
int map_id = 0;
char map_name[MAP_NAME_LENGTH];
char map_name[MAP_NAME_LENGTH_EXT];
nullpo_retr(-1, sd);
@ -1810,7 +1810,7 @@ int atcommand_whomap(const int fd, struct map_session_data* sd, const char* comm
int i, count, users;
int pl_GM_level, GM_level;
int map_id = 0;
char map_name[MAP_NAME_LENGTH];
char map_name[MAP_NAME_LENGTH_EXT];
struct guild *g;
struct party_data *p;
@ -3190,10 +3190,10 @@ int atcommand_go(const int fd, struct map_session_data* sd, const char* command,
{
int i;
int town;
char map_name[MAP_NAME_LENGTH];
char map_name[MAP_NAME_LENGTH_EXT];
int m;
const struct { char map[MAP_NAME_LENGTH]; int x, y; } data[] = {
const struct { char map[MAP_NAME_LENGTH_EXT]; int x, y; } data[] = {
{ MAP_PRONTERA, 156, 191 }, // 0=Prontera
{ MAP_MORROC, 156, 93 }, // 1=Morroc
{ MAP_GEFFEN, 119, 59 }, // 2=Geffen
@ -3250,7 +3250,7 @@ int atcommand_go(const int fd, struct map_session_data* sd, const char* command,
return -1;
} else {
// get possible name of the city
map_name[MAP_NAME_LENGTH-1] = '\0';
map_name[MAP_NAME_LENGTH_EXT-1] = '\0';
for (i = 0; map_name[i]; i++)
map_name[i] = TOLOWER(map_name[i]);
// try to see if it's a name, and not a number (try a lot of possibilities, write errors and abbreviations too)
@ -3636,7 +3636,7 @@ static int atkillmonster_sub(struct block_list *bl, va_list ap)
void atcommand_killmonster_sub(const int fd, struct map_session_data* sd, const char* message, const int drop)
{
int map_id;
char map_name[MAP_NAME_LENGTH];
char map_name[MAP_NAME_LENGTH_EXT];
if (!sd) return;
@ -5432,8 +5432,8 @@ int atcommand_mapinfo(const int fd, struct map_session_data* sd, const char* com
}
if (atcmd_player_name[0] == '\0') {
memcpy(atcmd_player_name, mapindex_id2name(sd->mapindex), MAP_NAME_LENGTH);
atcmd_player_name[MAP_NAME_LENGTH] = '\0';
memcpy(atcmd_player_name, mapindex_id2name(sd->mapindex), MAP_NAME_LENGTH_EXT);
atcmd_player_name[MAP_NAME_LENGTH_EXT] = '\0';
m_id = map_mapindex2mapid(sd->mapindex);
} else {
m_id = map_mapname2mapid(atcmd_player_name);

View File

@ -617,7 +617,7 @@ int charcommand_save(
const int fd, struct map_session_data* sd,
const char* command, const char* message)
{
char map_name[MAP_NAME_LENGTH];
char map_name[MAP_NAME_LENGTH_EXT];
char character[NAME_LENGTH];
struct map_session_data* pl_sd;
int x = 0, y = 0;
@ -1130,7 +1130,7 @@ int charcommand_warp(
const int fd, struct map_session_data* sd,
const char* command, const char* message)
{
char map_name[MAP_NAME_LENGTH];
char map_name[MAP_NAME_LENGTH_EXT];
char character[NAME_LENGTH];
int x = 0, y = 0;
struct map_session_data *pl_sd;

View File

@ -328,7 +328,7 @@ int chrif_changemapserver(struct map_session_data *sd, short map, int x, int y,
int chrif_changemapserverack(int fd)
{
struct map_session_data *sd;
char mapname[MAP_NAME_LENGTH+1];
char mapname[MAP_NAME_LENGTH_EXT];
RFIFOHEAD(fd);
sd = map_id2sd(RFIFOL(fd,2));

View File

@ -1208,12 +1208,16 @@ static void clif_spiritball_single(int fd, struct map_session_data *sd)
*------------------------------------------
*/
static int clif_set0192(int fd, int m, int x, int y, int type) {
char map_name[MAP_NAME_LENGTH_EXT];
sprintf(map_name, "%s.gat", map[m].name);
WFIFOHEAD(fd, packet_len(0x192));
WFIFOW(fd,0) = 0x192;
WFIFOW(fd,2) = x;
WFIFOW(fd,4) = y;
WFIFOW(fd,6) = type;
memcpy(WFIFOP(fd,8),map[m].name,MAP_NAME_LENGTH);
memcpy(WFIFOP(fd,8),map_name,MAP_NAME_LENGTH_EXT);
WFIFOSET(fd,packet_len(0x192));
return 0;
@ -1600,17 +1604,17 @@ void clif_setwaitclose(int fd) {
*/
int clif_changemap(struct map_session_data *sd, short map, int x, int y) {
int fd;
char map_name[MAP_NAME_LENGTH];
char map_name[MAP_NAME_LENGTH_EXT];
nullpo_retr(0, sd);
fd = sd->fd;
snprintf(map_name, MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(map));
sprintf(map_name, "%s.gat", mapindex_id2name(map));
WFIFOHEAD(fd, packet_len(0x91));
WFIFOW(fd,0) = 0x91;
memcpy(WFIFOP(fd,2), map_name, MAP_NAME_LENGTH);
memcpy(WFIFOP(fd,2), map_name, MAP_NAME_LENGTH_EXT);
WFIFOW(fd,18) = x;
WFIFOW(fd,20) = y;
WFIFOSET(fd, packet_len(0x91));
@ -1631,7 +1635,7 @@ int clif_changemapserver(struct map_session_data* sd, const char* mapname, int x
WFIFOHEAD(fd, packet_len(0x92));
WFIFOW(fd,0) = 0x92;
//Better not trust the null-terminator is there. [Skotlex]
memcpy(WFIFOP(fd,2), mapname, MAP_NAME_LENGTH);
memcpy(WFIFOP(fd,2), mapname, MAP_NAME_LENGTH_EXT);
WFIFOB(fd,17) = 0; //Null terminator for mapname
WFIFOW(fd,18) = x;
WFIFOW(fd,20) = y;
@ -4661,10 +4665,10 @@ int clif_skill_warppoint(struct map_session_data *sd,int skill_num,int skill_lv,
WFIFOHEAD(fd,packet_len(0x11c));
WFIFOW(fd,0)=0x11c;
WFIFOW(fd,2)=skill_num;
strncpy((char*)WFIFOP(fd, 4),map1,MAP_NAME_LENGTH);
strncpy((char*)WFIFOP(fd,20),map2,MAP_NAME_LENGTH);
strncpy((char*)WFIFOP(fd,36),map3,MAP_NAME_LENGTH);
strncpy((char*)WFIFOP(fd,52),map4,MAP_NAME_LENGTH);
strncpy((char*)WFIFOP(fd, 4),map1,MAP_NAME_LENGTH_EXT);
strncpy((char*)WFIFOP(fd,20),map2,MAP_NAME_LENGTH_EXT);
strncpy((char*)WFIFOP(fd,36),map3,MAP_NAME_LENGTH_EXT);
strncpy((char*)WFIFOP(fd,52),map4,MAP_NAME_LENGTH_EXT);
WFIFOSET(fd,packet_len(0x11c));
sd->menuskill_id = skill_num;
if (skill_num == AL_WARP)
@ -5660,7 +5664,7 @@ int clif_party_created(struct map_session_data *sd,int flag)
int clif_party_member_info(struct party_data *p, struct map_session_data *sd)
{
unsigned char buf[96];
char map_name[MAP_NAME_LENGTH];
char map_name[MAP_NAME_LENGTH_EXT];
if (!sd) { //Pick any party member (this call is used when changing item share rules)
int i;
@ -5669,7 +5673,7 @@ int clif_party_member_info(struct party_data *p, struct map_session_data *sd)
sd = p->data[i].sd;
}
snprintf(map_name, MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(sd->mapindex));
snprintf(map_name, MAP_NAME_LENGTH_EXT, "%s.gat", mapindex_id2name(sd->mapindex));
WBUFW(buf,0)=0x1e9;
WBUFL(buf,2)= sd->status.account_id;
@ -5679,7 +5683,7 @@ int clif_party_member_info(struct party_data *p, struct map_session_data *sd)
WBUFB(buf,14)=0; //Unconfirmed byte, could be online/offline.
memcpy(WBUFP(buf,15), p->party.name, NAME_LENGTH);
memcpy(WBUFP(buf,39), sd->status.name, NAME_LENGTH);
memcpy(WBUFP(buf,63), map_name, MAP_NAME_LENGTH);
memcpy(WBUFP(buf,63), map_name, MAP_NAME_LENGTH_EXT);
WBUFB(buf,79) = (p->party.item&1)?1:0;
WBUFB(buf,80) = (p->party.item&2)?1:0;
clif_send(buf,packet_len(0x1e9),&sd->bl,PARTY);
@ -5693,7 +5697,7 @@ int clif_party_member_info(struct party_data *p, struct map_session_data *sd)
*------------------------------------------*/
int clif_party_info(struct party_data* p, struct map_session_data *sd)
{
unsigned char buf[2+2+NAME_LENGTH+(4+NAME_LENGTH+MAP_NAME_LENGTH+1+1)*MAX_PARTY];
unsigned char buf[2+2+NAME_LENGTH+(4+NAME_LENGTH+MAP_NAME_LENGTH_EXT+1+1)*MAX_PARTY];
struct map_session_data* party_sd = NULL;
int i, c;
@ -5704,17 +5708,17 @@ int clif_party_info(struct party_data* p, struct map_session_data *sd)
for(i = 0, c = 0; i < MAX_PARTY; i++)
{
struct party_member* m = &p->party.member[i];
char map_name[MAP_NAME_LENGTH];
char map_name[MAP_NAME_LENGTH_EXT];
if(!m->account_id) continue;
if(party_sd == NULL) party_sd = p->data[i].sd;
snprintf(map_name, MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(m->map));
snprintf(map_name, MAP_NAME_LENGTH_EXT, "%s.gat", mapindex_id2name(m->map));
WBUFL(buf,28+c*46) = m->account_id;
memcpy(WBUFP(buf,28+c*46+4), m->name, NAME_LENGTH);
memcpy(WBUFP(buf,28+c*46+28), map_name, MAP_NAME_LENGTH);
memcpy(WBUFP(buf,28+c*46+28), map_name, MAP_NAME_LENGTH_EXT);
WBUFB(buf,28+c*46+44) = (m->leader) ? 0 : 1;
WBUFB(buf,28+c*46+45) = (m->online) ? 0 : 1;
c++;
@ -5993,12 +5997,12 @@ int clif_hpmeter(struct map_session_data *sd)
int clif_party_move(struct party *p,struct map_session_data *sd,int online)
{
unsigned char buf[128];
char map_name[MAP_NAME_LENGTH];
char map_name[MAP_NAME_LENGTH_EXT];
nullpo_retr(0, sd);
nullpo_retr(0, p);
snprintf(map_name, MAP_NAME_LENGTH, "%s.gat", map[sd->bl.m].name);
snprintf(map_name, MAP_NAME_LENGTH_EXT, "%s.gat", map[sd->bl.m].name);
WBUFW(buf, 0)=0x104;
WBUFL(buf, 2)=sd->status.account_id;
@ -6008,7 +6012,7 @@ int clif_party_move(struct party *p,struct map_session_data *sd,int online)
WBUFB(buf,14)=!online;
memcpy(WBUFP(buf,15),p->name, NAME_LENGTH);
memcpy(WBUFP(buf,39),sd->status.name, NAME_LENGTH);
memcpy(WBUFP(buf,63),map_name, MAP_NAME_LENGTH);
memcpy(WBUFP(buf,63),map_name, MAP_NAME_LENGTH_EXT);
clif_send(buf,packet_len(0x104),&sd->bl,PARTY);
return 0;
}
@ -6415,6 +6419,9 @@ int clif_changemapcell(int m,int x,int y,int cell_type,int type)
{
struct block_list bl;
unsigned char buf[32];
char map_name[MAP_NAME_LENGTH_EXT];
snprintf(map_name, MAP_NAME_LENGTH_EXT, "%s.gat", map[m].name);
bl.type = BL_NUL;
bl.m = m;
@ -6424,7 +6431,7 @@ int clif_changemapcell(int m,int x,int y,int cell_type,int type)
WBUFW(buf,2) = x;
WBUFW(buf,4) = y;
WBUFW(buf,6) = cell_type;
memcpy(WBUFP(buf,8),map[m].name,MAP_NAME_LENGTH);
memcpy(WBUFP(buf,8),map_name,MAP_NAME_LENGTH_EXT);
if(!type)
clif_send(buf,packet_len(0x192),&bl,AREA);
else
@ -7850,13 +7857,13 @@ void clif_gospel_info(struct map_session_data *sd, int type)
void clif_feel_info(struct map_session_data *sd, unsigned char feel_level, unsigned char type)
{
int fd=sd->fd;
char map_name[MAP_NAME_LENGTH];
char map_name[MAP_NAME_LENGTH_EXT];
snprintf(map_name, MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(sd->feel_map[feel_level].index));
snprintf(map_name, MAP_NAME_LENGTH_EXT, "%s.gat", mapindex_id2name(sd->feel_map[feel_level].index));
WFIFOHEAD(fd,packet_len(0x20e));
WFIFOW(fd,0)=0x20e;
memcpy(WFIFOP(fd,2),map_name, MAP_NAME_LENGTH);
memcpy(WFIFOP(fd,2),map_name, MAP_NAME_LENGTH_EXT);
WFIFOL(fd,26)=sd->bl.id;
WFIFOB(fd,30)=feel_level;
WFIFOB(fd,31)=type?1:0;
@ -8636,8 +8643,8 @@ int clif_message(struct block_list *bl, const char* msg)
*/
void clif_parse_MapMove(int fd, struct map_session_data *sd) {
// /m /mapmove (as @rura GM command)
char output[MAP_NAME_LENGTH+15]; // Max length of a short: ' -6XXXX' -> 7 digits
char message[MAP_NAME_LENGTH+15+5]; // "/mm "+output
char output[MAP_NAME_LENGTH_EXT+15]; // Max length of a short: ' -6XXXX' -> 7 digits
char message[MAP_NAME_LENGTH_EXT+15+5]; // "/mm "+output
char *map_name;
RFIFOHEAD(fd);
@ -8647,7 +8654,7 @@ void clif_parse_MapMove(int fd, struct map_session_data *sd) {
return;
map_name = RFIFOP(fd,2);
map_name[MAP_NAME_LENGTH-1]='\0';
map_name[MAP_NAME_LENGTH_EXT-1]='\0';
sprintf(output, "%s %d %d", map_name, RFIFOW(fd,18), RFIFOW(fd,20));
atcommand_rura(fd, sd, "@rura", output);
if(log_config.gm && get_atcommand_level(AtCommand_MapMove) >= log_config.gm)

View File

@ -9,6 +9,7 @@
#include "../common/timer.h"
#include "../common/nullpo.h"
#include "../common/malloc.h"
#include "../common/mapindex.h"
#include "../common/showmsg.h"
#include "../common/ers.h"
@ -183,7 +184,7 @@ static int guild_read_castledb(void)
gc=(struct guild_castle *)aCalloc(1,sizeof(struct guild_castle));
gc->castle_id=atoi(str[0]);
memcpy(gc->map_name,map_normalize_name(str[1]),MAP_NAME_LENGTH-1);
memcpy(gc->map_name,mapindex_normalize_name(str[1]),MAP_NAME_LENGTH-1);
memcpy(gc->castle_name,str[2],NAME_LENGTH-1);
memcpy(gc->castle_event,str[3],NAME_LENGTH-1);
@ -254,7 +255,7 @@ struct guild_castle *guild_mapname2gc(char *mapname)
int i;
struct guild_castle *gc=NULL;
map_normalize_name(mapname);
mapindex_normalize_name(mapname);
for(i=0;i<MAX_GUILDCASTLE;i++){
gc=guild_castle_search(i);

View File

@ -145,6 +145,20 @@ struct charid2nick {
int req_id;
};
// This is the main header found at the very beginning of the map cache
struct map_cache_main_header {
unsigned long file_size;
unsigned short 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];
short xs;
short ys;
long len;
};
char map_cache_file[256]="db/map_cache.dat";
char db_path[256] = "db";
char motd_txt[256] = "conf/motd.txt";
@ -2410,61 +2424,34 @@ int map_eraseipport(unsigned short mapindex, uint32 ip, uint16 port)
* Map cache reading
*===========================================*/
// This is the header appended before every compressed map cells info
struct map_cache_info {
char name[MAP_NAME_LENGTH];
unsigned short index;
short xs;
short ys;
long len;
};
FILE *map_cache_fp;
// Removes the extension from a map name
char *map_normalize_name(char *mapname)
{
char *ptr, *ptr2;
ptr = strchr(mapname, '.');
if (ptr) { //Check and remove extension.
while (ptr[1] && (ptr2 = strchr(ptr+1, '.')))
ptr = ptr2; //Skip to the last dot.
if(stricmp(ptr,".gat") == 0 ||
stricmp(ptr,".afm") == 0 ||
stricmp(ptr,".af2") == 0)
*ptr = '\0'; //Remove extension.
}
return mapname;
}
int map_readmap(struct map_data *m)
int map_readfromcache(struct map_data *m, FILE *fp)
{
int i;
unsigned short map_count;
struct map_cache_info info;
struct map_cache_main_header header;
struct map_cache_map_info info;
unsigned long size;
unsigned char *buf;
if(!map_cache_fp)
if(!fp)
return 0;
fseek(map_cache_fp, 0, SEEK_SET);
fread(&map_count, sizeof(map_count), 1, map_cache_fp);
fseek(fp, 0, SEEK_SET);
fread(&header, sizeof(struct map_cache_main_header), 1, fp);
for(i = 0; i < map_count; i++) {
fread(&info, sizeof(info), 1, map_cache_fp);
for(i = 0; i < header.map_count; i++) {
fread(&info, sizeof(struct map_cache_map_info), 1, fp);
if(strcmp(m->name, info.name) == 0) { // Map found
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);
fread(buf, info.len, 1, fp);
size = m->xs*m->ys;
decode_zip(m->gat, &size, buf, info.len); // Unzip the map from the buffer
aFree(buf);
return 1;
} else // Map not found, jump to the beginning of the next map info header
fseek(map_cache_fp, info.len, SEEK_CUR);
fseek(fp, info.len, SEEK_CUR);
}
return 0;
@ -2482,7 +2469,7 @@ int map_addmap(char *mapname) {
return 1;
}
memcpy(map[map_num].name, map_normalize_name(mapname), MAP_NAME_LENGTH-1);
memcpy(map[map_num].name, mapindex_normalize_name(mapname), MAP_NAME_LENGTH-1);
map_num++;
return 0;
}
@ -2520,8 +2507,9 @@ int map_readallmaps (void)
{
int i;
int maps_removed = 0;
FILE *fp;
if(!(map_cache_fp = fopen(map_cache_file, "rb")))
if(!(fp = fopen(map_cache_file, "rb")))
{
ShowFatalError("Unable to open map cache file "CL_WHITE"%s"CL_RESET"\n", map_cache_file);
exit(1); //No use launching server if maps can't be read.
@ -2559,7 +2547,7 @@ int map_readallmaps (void)
fflush(stdout);
}
if(!map_readmap(&map[i])) {
if(!map_readfromcache(&map[i], fp)) {
map_delmapid(i);
maps_removed++;
i--;
@ -2609,6 +2597,8 @@ int map_readallmaps (void)
map[i].block_mob_count = (int*)aCallocA(size, 1);
}
fclose(fp);
// finished map loading
printf("\r");
ShowInfo("Successfully loaded '"CL_WHITE"%d"CL_RESET"' maps.%30s\n",map_num,"");

View File

@ -1030,7 +1030,7 @@ enum { ATK_LUCKY=1,ATK_FLEE,ATK_DEF}; //
struct map_data {
char name[MAP_NAME_LENGTH];
unsigned short index; //Index is the map index used by the mapindex* functions.
unsigned char *gat; // NULLなら下のmap_data_other_serverとして扱う
unsigned char *gat; // If this is NULL the map is not on this map-server
unsigned char *cell; //Contains temporary cell data that is set/unset on tiles.
#ifdef CELL_NOSTACK
unsigned char *cell_bl; //Holds amount of bls in any given cell.
@ -1350,7 +1350,6 @@ void map_foreachpc(int (*func)(DBKey,void*,va_list),...);
int map_foreachiddb(int (*)(DBKey,void*,va_list),...);
void map_addnickdb(struct map_session_data *);
struct map_session_data * map_nick2sd(const char*);
char *map_normalize_name(char *mapname);
// ‚»‚Ì‘¼
int map_check_dir(int s_dir,int t_dir);

View File

@ -1659,7 +1659,7 @@ int npc_parse_warp (char *w1,char *w2,char *w3,char *w4)
{
int x, y, xs, ys, to_x, to_y, m;
int i;
char mapname[MAP_NAME_LENGTH], to_mapname[MAP_NAME_LENGTH];
char mapname[MAP_NAME_LENGTH_EXT], to_mapname[MAP_NAME_LENGTH_EXT];
struct npc_data *nd;
// 引数の個数チェック
@ -1723,7 +1723,7 @@ static int npc_parse_shop (char *w1, char *w2, char *w3, char *w4)
#define MAX_SHOPITEM 100
char *p;
int x, y, dir, m, pos = 0;
char mapname[MAP_NAME_LENGTH];
char mapname[MAP_NAME_LENGTH_EXT];
struct npc_data *nd;
if (strcmp(w1, "-") == 0) {
@ -1953,7 +1953,7 @@ static int npc_skip_script (char *w1,char *w2,char *w3,char *w4,char *first_line
static int npc_parse_script(char *w1,char *w2,char *w3,char *w4,char *first_line,FILE *fp,int *lines,const char* file)
{
int x, y, dir = 0, m, xs = 0, ys = 0, class_ = 0; // [Valaris] thanks to fov
char mapname[MAP_NAME_LENGTH];
char mapname[MAP_NAME_LENGTH_EXT];
unsigned char *srcbuf = NULL;
struct script_code *script;
int srcsize = 65536;
@ -2380,7 +2380,7 @@ int npc_parse_mob2 (struct spawn_data *mob, int index)
int npc_parse_mob (char *w1, char *w2, char *w3, char *w4)
{
int level, num, class_, mode, x,y,xs,ys;
char mapname[MAP_NAME_LENGTH];
char mapname[MAP_NAME_LENGTH_EXT];
char mobname[NAME_LENGTH];
struct spawn_data mob, *data;
@ -2515,7 +2515,7 @@ int npc_parse_mob (char *w1, char *w2, char *w3, char *w4)
static int npc_parse_mapflag (char *w1, char *w2, char *w3, char *w4)
{
int m;
char mapname[MAP_NAME_LENGTH];
char mapname[MAP_NAME_LENGTH_EXT];
int state = 1;
// 引数の個数チェック
@ -2530,7 +2530,7 @@ static int npc_parse_mapflag (char *w1, char *w2, char *w3, char *w4)
//マップフラグ
if (strcmpi(w3, "nosave") == 0) {
char savemap[MAP_NAME_LENGTH];
char savemap[MAP_NAME_LENGTH_EXT];
int savex, savey;
if (state == 0)
; //Map flag disabled.
@ -2764,7 +2764,7 @@ static int npc_parse_mapflag (char *w1, char *w2, char *w3, char *w4)
static int npc_parse_mapcell (char *w1, char *w2, char *w3, char *w4)
{
int m, cell, x, y, x0, y0, x1, y1;
char type[24], mapname[MAP_NAME_LENGTH];
char type[24], mapname[MAP_NAME_LENGTH_EXT];
if (sscanf(w1, "%15[^,]", mapname) != 1)
return 1;

View File

@ -9119,10 +9119,10 @@ BUILDIN_FUNC(flagemblem)
BUILDIN_FUNC(getcastlename)
{
char mapname[MAP_NAME_LENGTH];
char mapname[MAP_NAME_LENGTH_EXT];
struct guild_castle *gc;
strncpy(mapname, script_getstr(st,2), MAP_NAME_LENGTH);
strncpy(mapname, script_getstr(st,2), MAP_NAME_LENGTH_EXT);
gc = guild_mapname2gc(mapname);
if(gc)
@ -9134,13 +9134,13 @@ BUILDIN_FUNC(getcastlename)
BUILDIN_FUNC(getcastledata)
{
char mapname[MAP_NAME_LENGTH];
char mapname[MAP_NAME_LENGTH_EXT];
int index=script_getnum(st,3);
const char *event=NULL;
struct guild_castle *gc;
int i;
strncpy(mapname, script_getstr(st,2), MAP_NAME_LENGTH);
strncpy(mapname, script_getstr(st,2), MAP_NAME_LENGTH_EXT);
gc = guild_mapname2gc(mapname);
if(script_hasdata(st,4) && index==0 && gc) {
@ -9202,12 +9202,12 @@ BUILDIN_FUNC(getcastledata)
BUILDIN_FUNC(setcastledata)
{
char mapname[MAP_NAME_LENGTH];
char mapname[MAP_NAME_LENGTH_EXT];
int index=script_getnum(st,3);
int value=script_getnum(st,4);
struct guild_castle *gc;
strncpy(mapname, script_getstr(st,2), MAP_NAME_LENGTH);
strncpy(mapname, script_getstr(st,2), MAP_NAME_LENGTH_EXT);
gc = guild_mapname2gc(mapname);
if(gc) {
@ -11084,9 +11084,9 @@ BUILDIN_FUNC(getsavepoint)
y=sd->status.save_point.y;
switch(type){
case 0:
mapname=(char *) aMallocA((MAP_NAME_LENGTH+1)*sizeof(char));
mapname=(char *) aMallocA((MAP_NAME_LENGTH)*sizeof(char));
memcpy(mapname, mapindex_id2name(sd->status.save_point.map), MAP_NAME_LENGTH);
mapname[MAP_NAME_LENGTH]='\0';
mapname[MAP_NAME_LENGTH-1]='\0';
script_pushstr(st,mapname);
break;
case 1:
@ -11133,7 +11133,7 @@ BUILDIN_FUNC(getmapxy)
char prefix;
int x,y,type;
char mapname[MAP_NAME_LENGTH+1];
char mapname[MAP_NAME_LENGTH];
memset(mapname, 0, sizeof(mapname));
if( !data_isreference(script_getdata(st,2)) ){

View File

@ -4445,8 +4445,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
} else {
if (sd->skillitem != AL_TELEPORT)
{
char save_map[MAP_NAME_LENGTH];
snprintf(save_map, MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(sd->status.save_point.map));
char save_map[MAP_NAME_LENGTH_EXT];
snprintf(save_map, MAP_NAME_LENGTH_EXT, "%s.gat", mapindex_id2name(sd->status.save_point.map));
clif_skill_warppoint(sd,skillid,skilllv,"Random",save_map,"","");
}
else //Autocasted Teleport level 2??
@ -6086,14 +6086,14 @@ int skill_castend_pos2 (struct block_list *src, int x, int y, int skillid, int s
case AL_WARP:
if(sd) {
char memo[4][MAP_NAME_LENGTH] = {"", "", "", ""};
snprintf(memo[0], MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(sd->status.save_point.map));
char memo[4][MAP_NAME_LENGTH_EXT] = {"", "", "", ""};
snprintf(memo[0], MAP_NAME_LENGTH_EXT, "%s.gat", mapindex_id2name(sd->status.save_point.map));
if (skilllv>1 && sd->status.memo_point[0].map)
snprintf(memo[1], MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(sd->status.memo_point[0].map));
snprintf(memo[1], MAP_NAME_LENGTH_EXT, "%s.gat", mapindex_id2name(sd->status.memo_point[0].map));
if (skilllv>2 && sd->status.memo_point[1].map)
snprintf(memo[2], MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(sd->status.memo_point[1].map));
snprintf(memo[2], MAP_NAME_LENGTH_EXT, "%s.gat", mapindex_id2name(sd->status.memo_point[1].map));
if (skilllv>3 && sd->status.memo_point[2].map)
snprintf(memo[3], MAP_NAME_LENGTH, "%s.gat", mapindex_id2name(sd->status.memo_point[2].map));
snprintf(memo[3], MAP_NAME_LENGTH_EXT, "%s.gat", mapindex_id2name(sd->status.memo_point[2].map));
clif_skill_warppoint(sd,skillid,skilllv,
memo[0],memo[1],memo[2],memo[3]);

View File

@ -578,7 +578,6 @@ void* grfio_reads(char *fname, int *size)
if (entry != NULL && entry->gentry < 0) {
entry->gentry = -entry->gentry; // local file checked
} else {
printf("%s not found (grfio_reads - local file %s)\n", fname, lfname);
return NULL;
}
}

View File

@ -4,6 +4,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#ifndef _WIN32
#include <unistd.h>
@ -11,13 +12,19 @@
#include "grfio.h"
char grf_list_file[256] = "db/grf_files.txt";
char map_list_file[256] = "db/map_list.txt";
char map_cache_file[256] = "db/map_cache.dat";
#define MAP_NAME_LENGTH 16
#define MAP_NAME_LENGTH 12
#define MAP_NAME_LENGTH_EXT 16
#define NO_WATER 1000000
char grf_list_file[256] = "tools/mapcache/grf_files.txt";
char map_list_file[256] = "db/map_index.txt";
char map_cache_file[256] = "db/map_cache.dat";
int rebuild = 0;
FILE *map_cache_fp;
unsigned long file_size;
// Used internally, this structure contains the physical map cells
struct map_data {
short xs;
@ -26,31 +33,25 @@ struct map_data {
};
// This is the main header found at the very beginning of the file
unsigned short map_count;
struct main_header {
unsigned long file_size;
unsigned short map_count;
} header;
// This is the header appended before every compressed map cells info
struct map_cache_info {
struct map_info {
char name[MAP_NAME_LENGTH];
unsigned short index;
short xs;
short ys;
long len;
};
FILE *map_cache_fp;
int filesize;
/*************************************
* Big-endian compatibility functions *
*************************************/
/// Converts an unsigned short (16 bits) from current machine order to little-endian
unsigned short MakeUShortLE(unsigned short val)
{
unsigned char buf[2];
buf[0] = (unsigned char)( (val & 0x00FF) );
buf[1] = (unsigned char)( (val & 0xFF00) >> 0x08 );
return *((unsigned short*)buf);
}
/// Converts a short (16 bits) from current machine order to little-endian
// Converts a short (16 bits) from current machine order to little-endian
short MakeShortLE(short val)
{
unsigned char buf[2];
@ -59,7 +60,7 @@ short MakeShortLE(short val)
return *((short*)buf);
}
/// Converts a long (32 bits) from current machine order to little-endian
// Converts a long (32 bits) from current machine order to little-endian
long MakeLongLE(long val)
{
unsigned char buf[4];
@ -70,7 +71,23 @@ long MakeLongLE(long val)
return *((long*)buf);
}
/// Reads an unsigned long (32 bits) in little-endian from the buffer
// Reads an unsigned short (16 bits) in little-endian from the buffer
unsigned short GetUShort(const unsigned char *buf)
{
return ( ((unsigned short)(buf[0])) )
|( ((unsigned short)(buf[1])) << 0x08 );
}
// Reads a long (32 bits) in little-endian from the buffer
long GetLong(const unsigned char *buf)
{
return ( ((long)(buf[0])) )
|( ((long)(buf[1])) << 0x08 )
|( ((long)(buf[2])) << 0x10 )
|( ((long)(buf[3])) << 0x18 );
}
// Reads an unsigned long (32 bits) in little-endian from the buffer
unsigned long GetULong(const unsigned char *buf)
{
return ( ((unsigned long)(buf[0])) )
@ -87,7 +104,7 @@ float GetFloat(const unsigned char *buf)
}
// Read map from GRF's GAT and RSW files
// Reads a map from GRF's GAT and RSW files
int read_map(char *name, struct map_data *m)
{
char filename[256];
@ -143,31 +160,31 @@ int read_map(char *name, struct map_data *m)
return 1;
}
void cache_map(char *name, unsigned short index, struct map_data *m)
// Adds a map to the cache
void cache_map(char *name, struct map_data *m)
{
struct map_cache_info info;
unsigned long len;
char *write_buf;
struct map_info info;
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 = m->xs*m->ys*2;
write_buf = (char *)malloc(len);
write_buf = (unsigned char *)malloc(len);
// Compress the cells and get the compressed length
encode_zip((unsigned char *)write_buf, &len, m->cells, m->xs*m->ys);
encode_zip(write_buf, &len, m->cells, m->xs*m->ys);
// Fill the map header
strncpy(info.name, name, MAP_NAME_LENGTH);
info.index = MakeUShortLE(index);
info.xs = MakeShortLE(m->xs);
info.ys = MakeShortLE(m->ys);
info.len = MakeLongLE((long)len);
info.len = MakeLongLE(len);
// Append map header then compressed cells at the end of the file
fseek(map_cache_fp, filesize, SEEK_SET);
fwrite(&info, sizeof(struct map_cache_info), 1, map_cache_fp);
fseek(map_cache_fp, header.file_size, SEEK_SET);
fwrite(&info, sizeof(struct map_info), 1, map_cache_fp);
fwrite(write_buf, 1, len, map_cache_fp);
map_count++;
filesize += sizeof(struct map_cache_info) + len;
header.file_size += sizeof(struct map_info) + len;
header.map_count++;
free(write_buf);
free(m->cells);
@ -175,41 +192,111 @@ void cache_map(char *name, unsigned short index, struct map_data *m)
return;
}
// Checks whether a map is already is the cache
int find_map(char *name)
{
int i;
struct map_info info;
fseek(map_cache_fp, sizeof(struct main_header), SEEK_SET);
for(i = 0; i < header.map_count; i++) {
fread(&info, sizeof(info), 1, map_cache_fp);
if(strcmp(name, info.name) == 0) // Map found
return 1;
else // Map not found, jump to the beginning of the next map info header
fseek(map_cache_fp, GetLong((unsigned char *)&(info.len)), SEEK_CUR);
}
return 0;
}
// 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, '.')))
ptr = ptr2; //Skip to the last dot.
if(stricmp(ptr,".gat") == 0 ||
stricmp(ptr,".afm") == 0 ||
stricmp(ptr,".af2") == 0)
*ptr = '\0'; //Remove extension.
}
return mapname;
}
// Processes command-line arguments
void process_args(int argc, char *argv[])
{
int i;
for(i = 0; i < argc; i++) {
if(strcmp(argv[i], "-grf") == 0) {
if(++i < argc)
strcpy(grf_list_file, argv[i]);
} else if(strcmp(argv[i], "-list") == 0) {
if(++i < argc)
strcpy(map_list_file, argv[i]);
} else if(strcmp(argv[i], "-cache") == 0) {
if(++i < argc)
strcpy(map_cache_file, argv[i]);
} else if(strcmp(argv[i], "-rebuild") == 0)
rebuild = 1;
}
}
int main(int argc, char *argv[])
{
FILE *list;
char line[1024];
struct map_data map;
char name[MAP_NAME_LENGTH];
unsigned short index = 1;
char name[MAP_NAME_LENGTH_EXT];
if(argc > 1)
strcpy(grf_list_file, argv[1]);
if(argc > 2)
strcpy(map_list_file, argv[2]);
if(argc > 3)
strcpy(map_cache_file, argv[3]);
// Process the command-line arguments
process_args(argc, argv);
printf("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
printf("Opening map cache: %s\n", map_cache_file);
map_cache_fp = fopen(map_cache_file, "wb");
if( map_cache_fp == NULL ) {
if(!rebuild) {
map_cache_fp = fopen(map_cache_file, "rb");
if(map_cache_fp == NULL) {
printf("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) {
printf("Failure when opening map cache file %s\n", map_cache_file);
exit(1);
}
// Open the map list
printf("Opening map list: %s\n", map_list_file);
list = fopen(map_list_file, "r");
if( list == NULL ) {
if(list == NULL) {
printf("Failure when opening maps list file %s\n", map_list_file);
exit(1);
exit(2);
}
// Initialize the main header
map_count = 0;
filesize = sizeof(map_count);
if(rebuild) {
header.file_size = sizeof(struct main_header);
header.map_count = 0;
} else {
fread(&header, sizeof(struct main_header), 1, map_cache_fp);
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, 1020, list)){
@ -217,30 +304,37 @@ int main(int argc, char *argv[])
if(line[0] == '/' && line[1] == '/')
continue;
if(sscanf(line, "%16s %hu", name, &index) > 0) { // No defines in strings, 16 is hardcoded here
printf("Index %d : %s\n", index, name);
if(read_map(name, &map))
cache_map(name, index, &map);
else
printf("Map file not found in GRF\n");
// If the 2nd argument is omitted at next line, we'll keep last used index + 1
index++;
}
if(sscanf(line, "%15s", name) < 1)
continue;
if(strcmp("map:", name) == 0 && sscanf(line, "%*s %15s", name) < 1)
continue;
remove_extension(name);
printf("%s", name);
if(find_map(name))
printf(" already in cache!\n");
else if(read_map(name, &map)) {
cache_map(name, &map);
printf(" successfully cached\n");
} else
printf(" not found in GRF!\n");
}
printf("Closing map list: %s\n", map_list_file);
fclose(list);
printf("Closing map cache: %s\n", map_cache_file);
// Write the main header and close the map cache
printf("Closing map cache: %s\n", map_cache_file);
fseek(map_cache_fp, 0, SEEK_SET);
fwrite(&map_count, sizeof(map_count), 1, map_cache_fp);
fwrite(&header, sizeof(struct main_header), 1, map_cache_fp);
fclose(map_cache_fp);
printf("Finalizing grfio\n");
grfio_final();
printf("%d maps cached\n", map_count);
printf("%d maps now in cache\n", header.map_count);
return 0;
}

View File

@ -0,0 +1,15 @@
//-----------------------------------------
// GRF List
// Add as many entries as you wish
//-----------------------------------------
//grf: C:\Program Files\Gravity\RO\data.grf
grf: C:\Program Files\Gravity\RO\sdata.grf
//-----------------------------------------
// Data Directory
// Path must include trailing backslash
// Only one entry supported!
//-----------------------------------------
//data_dir: C:\Program Files\Gravity\RO\