summaryrefslogblamecommitdiff
path: root/src/tool/mapcache.c
blob: c7e6aaa608590beb99b234a6b1cf647582814d6f (plain) (tree)









































































































































































































                                                                                                                                                                                                    
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>

#ifndef _WIN32
#include <unistd.h>
#endif

#include "grfio.h"

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";

#define MAP_NAME_LENGTH 16
#define NO_WATER 1000000

// Used internally, this structure contains the physical map cells
struct map_data {
	short xs;
	short ys;
	unsigned char *cells;
};

// 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;
};

// 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;


// Read map from GRF's GAT and RSW files
int read_map(char *name, struct map_data *m)
{
	char filename[256];
	char *gat, *rsw;
	int water_height;
	int x, y, xs, ys;
	struct gat_cell {
		float height[4];
		int type;
	} *p = NULL;

	// Open map GAT
	sprintf(filename,"data\\%s.gat", name);
	gat = (char *)grfio_read(filename);
	if (gat == NULL)
		return 0;

	// Open map RSW
	sprintf(filename,"data\\%s.rsw", name);
	rsw = (char *)grfio_read(filename);

	// Read water height
	if (rsw) { 
		float temp = *(float*)(rsw+166);
		water_height = (int)temp;
		free(rsw);
	} else
		water_height = NO_WATER;

	// Read map size and allocate needed memory
	xs = m->xs = *(int*)(gat+6);
	ys = m->ys = *(int*)(gat+10);
	m->cells = (unsigned char *)malloc(xs*ys);

	// Set cell properties
	for (y = 0; y < ys; y++) {
		p = (struct gat_cell*)(gat+14+y*xs*20);
		for (x = 0; x < xs; x++) {
			if (water_height != NO_WATER && p->type == 0 && (p->height[0] > water_height || p->height[1] > water_height || p->height[2] > water_height || p->height[3] > water_height))
				m->cells[x+y*xs] = 3; // Cell is 0 (walkable) but under water level, set to 3 (walkable water)
			else
				m->cells[x+y*xs] = p->type;
			p++;
		}
	}

	free(gat);

	return 1;
}

void cache_map(char *name, unsigned short index, struct map_data *m)
{
	struct map_cache_info info;
	unsigned long len;
	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);
	// Compress the cells and get the compressed length
	encode_zip((unsigned char *)write_buf, &len, m->cells, m->xs*m->ys);

	// Fill the map header
	strncpy(info.name, name, MAP_NAME_LENGTH);
	info.index = index;
	info.xs = m->xs;
	info.ys = m->ys;
	info.len = len;

	// Append map header then compressed cells at the end of the file
	fseek(map_cache_fp, header.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;

	free(write_buf);
	free(m->cells);

	return;
}

int main(int argc, char *argv[])
{
	FILE *list;
	char line[1024];
	struct map_data map;
	char name[MAP_NAME_LENGTH];
	unsigned short index = 1;

	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]);

	printf("Initializing grfio with %s\n", grf_list_file);
	grfio_init(grf_list_file);

	printf("Opening map cache: %s\n", map_cache_file);
	if(!(map_cache_fp = fopen(map_cache_file, "wb"))) {
		printf("Failure when opening map cache file %s\n", map_cache_file);
		exit(1);
	}

	printf("Opening map list: %s\n", map_list_file);
	if(!(list = fopen(map_list_file, "r"))) {
		printf("Failure when opening maps list file %s\n", map_list_file);
		exit(1);
	}

	// 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);

	// Read and process the map list
	while(fgets(line, 1020, list)){

		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++;
		} else
				printf("Skipping incorrect line\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
	fseek(map_cache_fp, 0, SEEK_SET);
	fwrite(&header, sizeof(struct map_cache_head), 1, map_cache_fp);
	fclose(map_cache_fp);

	printf("Finalizing grfio\n");
	grfio_final();

	printf("%d maps cached\n", header.map_count);

	return 0;
}