mapcache.c 8.3 KB

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