root/src/tool/mapcache.c @ 1

Revision 1, 8.6 kB (checked in by jinshiro, 17 years ago)
Line 
1// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
2// For more information, see LICENCE in the main folder
3
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7
8#ifndef _WIN32
9#include <unistd.h>
10#endif
11
12#include "grfio.h"
13
14#define MAP_NAME_LENGTH 12
15#define MAP_NAME_LENGTH_EXT 16
16#define NO_WATER 1000000
17
18char grf_list_file[256] = "conf/grf-files.txt";
19char map_list_file[256] = "db/map_index.txt";
20char map_cache_file[256] = "db/map_cache.dat";
21int rebuild = 0;
22
23FILE *map_cache_fp;
24
25unsigned long file_size;
26
27// Used internally, this structure contains the physical map cells
28struct map_data {
29        short xs;
30        short ys;
31        unsigned char *cells;
32};
33
34// This is the main header found at the very beginning of the file
35struct main_header {
36        unsigned long file_size;
37        unsigned short map_count;
38} header;
39
40// This is the header appended before every compressed map cells info
41struct map_info {
42        char name[MAP_NAME_LENGTH];
43        short xs;
44        short ys;
45        long len;
46};
47
48
49/*************************************
50* Big-endian compatibility functions *
51*************************************/
52
53// Converts a short (16 bits) from current machine order to little-endian
54short MakeShortLE(short val)
55{
56        unsigned char buf[2];
57        buf[0] = (unsigned char)( (val & 0x00FF)         );
58        buf[1] = (unsigned char)( (val & 0xFF00) >> 0x08 );
59        return *((short*)buf);
60}
61
62// Converts a long (32 bits) from current machine order to little-endian
63long MakeLongLE(long val)
64{
65        unsigned char buf[4];
66        buf[0] = (unsigned char)( (val & 0x000000FF)         );
67        buf[1] = (unsigned char)( (val & 0x0000FF00) >> 0x08 );
68        buf[2] = (unsigned char)( (val & 0x00FF0000) >> 0x10 );
69        buf[3] = (unsigned char)( (val & 0xFF000000) >> 0x18 );
70        return *((long*)buf);
71}
72
73// Reads an unsigned short (16 bits) in little-endian from the buffer
74unsigned short GetUShort(const unsigned char *buf)
75{
76        return   ( ((unsigned short)(buf[0]))         )
77                        |( ((unsigned short)(buf[1])) << 0x08 );
78}
79
80// Reads a long (32 bits) in little-endian from the buffer
81long GetLong(const unsigned char *buf)
82{
83        return   ( ((long)(buf[0]))         )
84                        |( ((long)(buf[1])) << 0x08 )
85                        |( ((long)(buf[2])) << 0x10 )
86                        |( ((long)(buf[3])) << 0x18 );
87}
88
89// Reads an unsigned long (32 bits) in little-endian from the buffer
90unsigned long GetULong(const unsigned char *buf)
91{
92        return   ( ((unsigned long)(buf[0]))         )
93                        |( ((unsigned long)(buf[1])) << 0x08 )
94                        |( ((unsigned long)(buf[2])) << 0x10 )
95                        |( ((unsigned long)(buf[3])) << 0x18 );
96}
97
98// Reads a float (32 bits) from the buffer
99float GetFloat(const unsigned char *buf)
100{
101        unsigned long val = GetULong(buf);
102        return *((float*)&val);
103}
104
105
106// Reads a map from GRF's GAT and RSW files
107int read_map(char *name, struct map_data *m)
108{
109        char filename[256];
110        unsigned char *gat, *rsw;
111        int water_height;
112        size_t xy, off, num_cells;
113        float height;
114        unsigned long type;
115
116        // Open map GAT
117        sprintf(filename,"data\\%s.gat", name);
118        gat = (unsigned char *)grfio_read(filename);
119        if (gat == NULL)
120                return 0;
121
122        // Open map RSW
123        sprintf(filename,"data\\%s.rsw", name);
124        rsw = (unsigned char *)grfio_read(filename);
125
126        // Read water height
127        if (rsw) { 
128                water_height = (int)GetFloat(rsw+166);
129                free(rsw);
130        } else
131                water_height = NO_WATER;
132
133        // Read map size and allocate needed memory
134        m->xs = (short)GetULong(gat+6);
135        m->ys = (short)GetULong(gat+10);
136        num_cells = (size_t)m->xs*m->ys;
137        m->cells = (unsigned char *)malloc(num_cells);
138
139        // Set cell properties
140        off = 14;
141        for (xy = 0; xy < num_cells; xy++)
142        {
143                // Height of the bottom-left corner
144                height = GetFloat( gat + off      );
145                // Type of cell
146                type   = GetULong( gat + off + 16 );
147                off += 20;
148
149                if (type == 0 && water_height != NO_WATER && height > water_height)
150                        type = 3; // Cell is 0 (walkable) but under water level, set to 3 (walkable water)
151
152                m->cells[xy] = (unsigned char)type;
153        }
154
155        free(gat);
156
157        return 1;
158}
159
160// Adds a map to the cache
161void cache_map(char *name, struct map_data *m)
162{
163        struct map_info info;
164        unsigned long len;
165        unsigned char *write_buf;
166
167        // Create an output buffer twice as big as the uncompressed map... this way we're sure it fits
168        len = m->xs*m->ys*2;
169        write_buf = (unsigned char *)malloc(len);
170        // Compress the cells and get the compressed length
171        encode_zip(write_buf, &len, m->cells, m->xs*m->ys);
172
173        // Fill the map header
174        strncpy(info.name, name, MAP_NAME_LENGTH);
175        info.xs = MakeShortLE(m->xs);
176        info.ys = MakeShortLE(m->ys);
177        info.len = MakeLongLE(len);
178
179        // Append map header then compressed cells at the end of the file
180        fseek(map_cache_fp, header.file_size, SEEK_SET);
181        fwrite(&info, sizeof(struct map_info), 1, map_cache_fp);
182        fwrite(write_buf, 1, len, map_cache_fp);
183        header.file_size += sizeof(struct map_info) + len;
184        header.map_count++;
185
186        free(write_buf);
187        free(m->cells);
188
189        return;
190}
191
192// Checks whether a map is already is the cache
193int find_map(char *name)
194{
195        int i;
196        struct map_info info;
197
198        fseek(map_cache_fp, sizeof(struct main_header), SEEK_SET);
199
200        for(i = 0; i < header.map_count; i++) {
201                fread(&info, sizeof(info), 1, map_cache_fp);
202                if(strcmp(name, info.name) == 0) // Map found
203                        return 1;
204                else // Map not found, jump to the beginning of the next map info header
205                        fseek(map_cache_fp, GetLong((unsigned char *)&(info.len)), SEEK_CUR);
206        }
207
208        return 0;
209}
210
211// Cuts the extension from a map name
212char *remove_extension(char *mapname)
213{
214        char *ptr, *ptr2;
215        ptr = strchr(mapname, '.');
216        if (ptr) { //Check and remove extension.
217                while (ptr[1] && (ptr2 = strchr(ptr+1, '.')))
218                        ptr = ptr2; //Skip to the last dot.
219                if (strcmp(ptr,".gat") == 0)
220                        *ptr = '\0'; //Remove extension.
221        }
222        return mapname;
223}
224
225// Processes command-line arguments
226void process_args(int argc, char *argv[])
227{
228        int i;
229
230        for(i = 0; i < argc; i++) {
231                if(strcmp(argv[i], "-grf") == 0) {
232                        if(++i < argc)
233                                strcpy(grf_list_file, argv[i]);
234                } else if(strcmp(argv[i], "-list") == 0) {
235                        if(++i < argc)
236                                strcpy(map_list_file, argv[i]);
237                } else if(strcmp(argv[i], "-cache") == 0) {
238                        if(++i < argc)
239                                strcpy(map_cache_file, argv[i]);
240                } else if(strcmp(argv[i], "-rebuild") == 0)
241                        rebuild = 1;
242        }
243
244}
245
246int main(int argc, char *argv[])
247{
248        FILE *list;
249        char line[1024];
250        struct map_data map;
251        char name[MAP_NAME_LENGTH_EXT];
252
253        // Process the command-line arguments
254        process_args(argc, argv);
255
256        printf("Initializing grfio with %s\n", grf_list_file);
257        grfio_init(grf_list_file);
258
259        // Attempt to open the map cache file and force rebuild if not found
260        printf("Opening map cache: %s\n", map_cache_file);
261        if(!rebuild) {
262                map_cache_fp = fopen(map_cache_file, "rb");
263                if(map_cache_fp == NULL) {
264                        printf("Existing map cache not found, forcing rebuild mode\n");
265                        rebuild = 1;
266                } else
267                        fclose(map_cache_fp);
268        }
269        if(rebuild)
270                map_cache_fp = fopen(map_cache_file, "w+b");
271        else
272                map_cache_fp = fopen(map_cache_file, "r+b");
273        if(map_cache_fp == NULL) {
274                printf("Failure when opening map cache file %s\n", map_cache_file);
275                exit(EXIT_FAILURE);
276        }
277
278        // Open the map list
279        printf("Opening map list: %s\n", map_list_file);
280        list = fopen(map_list_file, "r");
281        if(list == NULL) {
282                printf("Failure when opening maps list file %s\n", map_list_file);
283                exit(EXIT_FAILURE);
284        }
285
286        // Initialize the main header
287        if(rebuild) {
288                header.file_size = sizeof(struct main_header);
289                header.map_count = 0;
290        } else {
291                fread(&header, sizeof(struct main_header), 1, map_cache_fp);
292                header.file_size = GetULong((unsigned char *)&(header.file_size));
293                header.map_count = GetUShort((unsigned char *)&(header.map_count));
294        }
295
296        // Read and process the map list
297        while(fgets(line, sizeof(line), list))
298        {
299                if(line[0] == '/' && line[1] == '/')
300                        continue;
301
302                if(sscanf(line, "%15s", name) < 1)
303                        continue;
304
305                if(strcmp("map:", name) == 0 && sscanf(line, "%*s %15s", name) < 1)
306                        continue;
307
308                name[MAP_NAME_LENGTH_EXT-1] = '\0';
309                remove_extension(name);
310                printf("%s", name);
311                if(find_map(name))
312                        printf(" already in cache!\n");
313                else if(read_map(name, &map)) {
314                        cache_map(name, &map);
315                        printf(" successfully cached\n");
316                } else
317                        printf(" not found in GRF!\n");
318
319        }
320
321        printf("Closing map list: %s\n", map_list_file);
322        fclose(list);
323
324        // Write the main header and close the map cache
325        printf("Closing map cache: %s\n", map_cache_file);
326        fseek(map_cache_fp, 0, SEEK_SET);
327        fwrite(&header, sizeof(struct main_header), 1, map_cache_fp);
328        fclose(map_cache_fp);
329
330        printf("Finalizing grfio\n");
331        grfio_final();
332
333        printf("%d maps now in cache\n", header.map_count);
334
335        return 0;
336}
Note: See TracBrowser for help on using the browser.