mapcache.cpp 7.8 KB

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