mapcache.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  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 "../config/core.h"
  10. #include "../common/cbasetypes.h"
  11. #include "../common/grfio.h"
  12. #include "../common/malloc.h"
  13. #include "../common/mmo.h"
  14. #include "../common/showmsg.h"
  15. #include "../common/utils.h"
  16. #define NO_WATER 1000000
  17. char grf_list_file[256] = "conf/grf-files.txt";
  18. char map_list_file[256] = "db/map_index.txt";
  19. char map_cache_file[256];
  20. int rebuild = 0;
  21. FILE *map_cache_fp;
  22. unsigned long file_size;
  23. // Used internally, this structure contains the physical map cells
  24. struct map_data {
  25. int16 xs;
  26. int16 ys;
  27. unsigned char *cells;
  28. };
  29. // This is the main header found at the very beginning of the file
  30. struct main_header {
  31. uint32 file_size;
  32. uint16 map_count;
  33. } header;
  34. // This is the header appended before every compressed map cells info
  35. struct map_info {
  36. char name[MAP_NAME_LENGTH];
  37. int16 xs;
  38. int16 ys;
  39. int32 len;
  40. };
  41. // Reads a map from GRF's GAT and RSW files
  42. int read_map(char *name, struct map_data *m)
  43. {
  44. char filename[256];
  45. unsigned char *gat, *rsw;
  46. int water_height;
  47. size_t xy, off, num_cells;
  48. // Open map GAT
  49. sprintf(filename,"data\\%s.gat", name);
  50. gat = (unsigned char *)grfio_read(filename);
  51. if (gat == NULL)
  52. return 0;
  53. // Open map RSW
  54. sprintf(filename,"data\\%s.rsw", name);
  55. rsw = (unsigned char *)grfio_read(filename);
  56. // Read water height
  57. if (rsw) {
  58. water_height = (int)GetFloat(rsw+166);
  59. aFree(rsw);
  60. } else
  61. water_height = NO_WATER;
  62. // Read map size and allocate needed memory
  63. m->xs = (int16)GetULong(gat+6);
  64. m->ys = (int16)GetULong(gat+10);
  65. if (m->xs <= 0 || m->ys <= 0) {
  66. aFree(gat);
  67. return 0;
  68. }
  69. num_cells = (size_t)m->xs*(size_t)m->ys;
  70. m->cells = (unsigned char *)aMalloc(num_cells);
  71. // Set cell properties
  72. off = 14;
  73. for (xy = 0; xy < num_cells; xy++)
  74. {
  75. // Height of the bottom-left corner
  76. float height = GetFloat( gat + off );
  77. // Type of cell
  78. uint32 type = GetULong( gat + off + 16 );
  79. off += 20;
  80. if (type == 0 && water_height != NO_WATER && height > water_height)
  81. type = 3; // Cell is 0 (walkable) but under water level, set to 3 (walkable water)
  82. m->cells[xy] = (unsigned char)type;
  83. }
  84. aFree(gat);
  85. return 1;
  86. }
  87. // Adds a map to the cache
  88. void cache_map(char *name, struct map_data *m)
  89. {
  90. struct map_info info;
  91. unsigned long len;
  92. unsigned char *write_buf;
  93. // Create an output buffer twice as big as the uncompressed map... this way we're sure it fits
  94. len = (unsigned long)m->xs*(unsigned long)m->ys*2;
  95. write_buf = (unsigned char *)aMalloc(len);
  96. // Compress the cells and get the compressed length
  97. encode_zip(write_buf, &len, m->cells, m->xs*m->ys);
  98. // Fill the map header
  99. if (strlen(name) > MAP_NAME_LENGTH) // It does not hurt to warn that there are maps with name longer than allowed.
  100. ShowWarning ("Map name '%s' size '%d' is too long. Truncating to '%d'.\n", name, strlen(name), MAP_NAME_LENGTH);
  101. strncpy(info.name, name, MAP_NAME_LENGTH);
  102. info.xs = MakeShortLE(m->xs);
  103. info.ys = MakeShortLE(m->ys);
  104. info.len = MakeLongLE(len);
  105. // Append map header then compressed cells at the end of the file
  106. fseek(map_cache_fp, header.file_size, SEEK_SET);
  107. fwrite(&info, sizeof(struct map_info), 1, map_cache_fp);
  108. fwrite(write_buf, 1, len, map_cache_fp);
  109. header.file_size += sizeof(struct map_info) + len;
  110. header.map_count++;
  111. aFree(write_buf);
  112. aFree(m->cells);
  113. return;
  114. }
  115. // Checks whether a map is already is the cache
  116. int find_map(char *name)
  117. {
  118. int i;
  119. struct map_info info;
  120. fseek(map_cache_fp, sizeof(struct main_header), SEEK_SET);
  121. for(i = 0; i < header.map_count; i++) {
  122. if(fread(&info, sizeof(info), 1, map_cache_fp) != 1) printf("An error as occured in fread while reading map_cache\n");
  123. if(strcmp(name, info.name) == 0) // Map found
  124. return 1;
  125. else // Map not found, jump to the beginning of the next map info header
  126. fseek(map_cache_fp, GetLong((unsigned char *)&(info.len)), SEEK_CUR);
  127. }
  128. return 0;
  129. }
  130. // Cuts the extension from a map name
  131. char *remove_extension(char *mapname)
  132. {
  133. char *ptr, *ptr2;
  134. ptr = strchr(mapname, '.');
  135. if (ptr) { //Check and remove extension.
  136. while (ptr[1] && (ptr2 = strchr(ptr+1, '.')))
  137. ptr = ptr2; //Skip to the last dot.
  138. if (strcmp(ptr,".gat") == 0)
  139. *ptr = '\0'; //Remove extension.
  140. }
  141. return mapname;
  142. }
  143. // Processes command-line arguments
  144. int process_args(int argc, char *argv[])
  145. {
  146. int i;
  147. for(i = 1; i < argc; i++) {
  148. if(strcmp(argv[i], "-grf") == 0) {
  149. if(opt_has_next_value(argv[i],i,argc)) strcpy(grf_list_file, argv[++i]);
  150. else return 1;
  151. } else if(strcmp(argv[i], "-list") == 0) {
  152. if(opt_has_next_value(argv[i],i,argc)) strcpy(map_list_file, argv[++i]);
  153. else return 1;
  154. } else if(strcmp(argv[i], "-cache") == 0) {
  155. if(opt_has_next_value(argv[i],i,argc)) strcpy(map_cache_file, argv[++i]);
  156. else return 1;
  157. } else if(strcmp(argv[i], "-rebuild") == 0) {
  158. rebuild = 1;
  159. } else {
  160. ShowWarning("Invalid argument given '%s'.\n", argv[i]);
  161. return 1;
  162. }
  163. }
  164. return 0;
  165. }
  166. int do_init(int argc, char** argv)
  167. {
  168. FILE *list;
  169. char line[1024];
  170. struct map_data map;
  171. char name[MAP_NAME_LENGTH_EXT];
  172. /* setup pre-defined, #define-dependant, use -cache option to override this */
  173. sprintf(map_cache_file,"db/%smap_cache.dat",DBPATH);
  174. // Process the command-line arguments
  175. if(process_args(argc, argv))
  176. return 0;
  177. ShowStatus("Initializing grfio with %s\n", grf_list_file);
  178. grfio_init(grf_list_file);
  179. // Attempt to open the map cache file and force rebuild if not found
  180. ShowStatus("Opening map cache: %s\n", map_cache_file);
  181. if(!rebuild) {
  182. map_cache_fp = fopen(map_cache_file, "rb");
  183. if(map_cache_fp == NULL) {
  184. ShowNotice("Existing map cache not found, forcing rebuild mode\n");
  185. rebuild = 1;
  186. } else
  187. fclose(map_cache_fp);
  188. }
  189. if(rebuild)
  190. map_cache_fp = fopen(map_cache_file, "w+b");
  191. else
  192. map_cache_fp = fopen(map_cache_file, "r+b");
  193. if(map_cache_fp == NULL) {
  194. ShowError("Failure when opening map cache file %s\n", map_cache_file);
  195. exit(EXIT_FAILURE);
  196. }
  197. // Open the map list
  198. ShowStatus("Opening map list: %s\n", map_list_file);
  199. list = fopen(map_list_file, "r");
  200. if(list == NULL) {
  201. ShowError("Failure when opening maps list file %s\n", map_list_file);
  202. exit(EXIT_FAILURE);
  203. }
  204. // Initialize the main header
  205. if(rebuild) {
  206. header.file_size = sizeof(struct main_header);
  207. header.map_count = 0;
  208. } else {
  209. if(fread(&header, sizeof(struct main_header), 1, map_cache_fp) != 1){ printf("An error as occured while reading map_cache_fp \n"); }
  210. header.file_size = GetULong((unsigned char *)&(header.file_size));
  211. header.map_count = GetUShort((unsigned char *)&(header.map_count));
  212. }
  213. // Read and process the map list
  214. while(fgets(line, sizeof(line), list))
  215. {
  216. if(line[0] == '/' && line[1] == '/')
  217. continue;
  218. if(sscanf(line, "%15s", name) < 1)
  219. continue;
  220. if(strcmp("map:", name) == 0 && sscanf(line, "%*s %15s", name) < 1)
  221. continue;
  222. name[MAP_NAME_LENGTH_EXT-1] = '\0';
  223. remove_extension(name);
  224. if(find_map(name))
  225. ShowInfo("Map '"CL_WHITE"%s"CL_RESET"' already in cache.\n", name);
  226. else if(read_map(name, &map)) {
  227. cache_map(name, &map);
  228. ShowInfo("Map '"CL_WHITE"%s"CL_RESET"' successfully cached.\n", name);
  229. } else
  230. ShowError("Map '"CL_WHITE"%s"CL_RESET"' not found!\n", name);
  231. }
  232. ShowStatus("Closing map list: %s\n", map_list_file);
  233. fclose(list);
  234. // Write the main header and close the map cache
  235. ShowStatus("Closing map cache: %s\n", map_cache_file);
  236. fseek(map_cache_fp, 0, SEEK_SET);
  237. fwrite(&header, sizeof(struct main_header), 1, map_cache_fp);
  238. fclose(map_cache_fp);
  239. ShowStatus("Finalizing grfio\n");
  240. grfio_final();
  241. ShowInfo("%d maps now in cache\n", header.map_count);
  242. return 0;
  243. }
  244. void do_final(void)
  245. {
  246. }