|
Atrinik Client 2.5
|
00001 /************************************************************************ 00002 * Atrinik, a Multiplayer Online Role Playing Game * 00003 * * 00004 * Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team * 00005 * * 00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game) * 00007 * and Crossfire (Multiplayer game for X-windows). * 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 * This program is distributed in the hope that it will be useful, * 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00017 * GNU General Public License for more details. * 00018 * * 00019 * You should have received a copy of the GNU General Public License * 00020 * along with this program; if not, write to the Free Software * 00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 00022 * * 00023 * The author can be reached at admin@atrinik.org * 00024 ************************************************************************/ 00025 00030 #include <global.h> 00031 00033 static bmap_struct *bmaps_default[BMAPS_MAX]; 00035 static bmap_struct *bmaps = NULL; 00037 static size_t bmaps_size = 0; 00038 00043 static unsigned long bmap_hash(const char *str) 00044 { 00045 unsigned long hash = 0; 00046 int i = 0; 00047 unsigned int rot = 0; 00048 const char *p; 00049 00050 for (p = str; i < MAXSTRING && *p; p++, i++) 00051 { 00052 hash ^= (unsigned long) *p << rot; 00053 rot += 2; 00054 00055 if (rot >= (sizeof(unsigned long) - sizeof(char)) * CHAR_BIT) 00056 { 00057 rot = 0; 00058 } 00059 } 00060 00061 return hash % BMAPS_MAX; 00062 } 00063 00068 bmap_struct *bmap_find(const char *name) 00069 { 00070 bmap_struct *bmap; 00071 unsigned long idx; 00072 00073 if (name == NULL) 00074 { 00075 return NULL; 00076 } 00077 00078 idx = bmap_hash(name); 00079 00080 for (; ;) 00081 { 00082 bmap = bmaps_default[idx]; 00083 00084 /* Not in the array. */ 00085 if (!bmap) 00086 { 00087 return NULL; 00088 } 00089 00090 if (!strcmp(bmap->name, name)) 00091 { 00092 return bmap; 00093 } 00094 00095 if (++idx >= BMAPS_MAX) 00096 { 00097 idx = 0; 00098 } 00099 } 00100 } 00101 00105 void bmap_add(bmap_struct *bmap) 00106 { 00107 unsigned long idx = bmap_hash(bmap->name), orig_idx = idx; 00108 00109 for (; ;) 00110 { 00111 if (bmaps_default[idx] && !strcmp(bmaps_default[idx]->name, bmap->name)) 00112 { 00113 LOG(llevBug, "bmap_add(): Double use of bmap name %s.\n", bmap->name); 00114 } 00115 00116 if (!bmaps_default[idx]) 00117 { 00118 bmaps_default[idx] = bmap; 00119 return; 00120 } 00121 00122 if (++idx == BMAPS_MAX) 00123 { 00124 idx = 0; 00125 } 00126 00127 if (idx == orig_idx) 00128 { 00129 LOG(llevBug, "bmap_add(): bmaps array is too small for %s.\n", bmap->name); 00130 return; 00131 } 00132 } 00133 } 00134 00137 void read_bmaps_p0() 00138 { 00139 FILE *fp; 00140 size_t tmp_buf_size, pos; 00141 char *tmp_buf, buf[MAX_BUF], *cp, *end; 00142 size_t len; 00143 bmap_struct *bmap; 00144 00145 fp = fopen_wrapper(FILE_ATRINIK_P0, "rb"); 00146 00147 if (!fp) 00148 { 00149 LOG(llevError, "%s doesn't exist.\n", FILE_ATRINIK_P0); 00150 } 00151 00152 memset((void *) bmaps_default, 0, BMAPS_MAX * sizeof(bmap_struct *)); 00153 00154 tmp_buf_size = 24 * 1024; 00155 tmp_buf = malloc(tmp_buf_size); 00156 00157 while (fgets(buf, sizeof(buf) - 1, fp) != NULL) 00158 { 00159 if (strncmp(buf, "IMAGE ", 6)) 00160 { 00161 LOG(llevError, "The file %s is corrupted.\n", FILE_ATRINIK_P0); 00162 } 00163 00164 /* Skip across the image ID data. */ 00165 for (cp = buf + 6; *cp != ' '; cp++) 00166 { 00167 } 00168 00169 len = atoi(cp); 00170 00171 /* Skip across the length data. */ 00172 for (cp = cp + 1; *cp != ' '; cp++) 00173 { 00174 } 00175 00176 /* Adjust the buffer if necessary. */ 00177 if (len > tmp_buf_size) 00178 { 00179 tmp_buf_size = len; 00180 tmp_buf = realloc(tmp_buf, tmp_buf_size); 00181 } 00182 00183 pos = ftell(fp); 00184 00185 if (!fread(tmp_buf, 1, len, fp)) 00186 { 00187 break; 00188 } 00189 00190 /* Eliminate newline. */ 00191 end = strchr(cp, '\n'); 00192 00193 if (end) 00194 { 00195 *end = '\0'; 00196 } 00197 00198 /* Trim left whitespace. */ 00199 while (*cp == ' ') 00200 { 00201 cp++; 00202 } 00203 00204 bmap = malloc(sizeof(bmap_struct)); 00205 bmap->name = strdup(cp); 00206 bmap->crc32 = crc32(1L, (const unsigned char FAR *) tmp_buf, len); 00207 bmap->len = len; 00208 bmap->pos = pos; 00209 bmap_add(bmap); 00210 } 00211 00212 free(tmp_buf); 00213 fclose(fp); 00214 } 00215 00218 void read_bmaps() 00219 { 00220 FILE *fp; 00221 char buf[HUGE_BUF], name[MAX_BUF]; 00222 uint32 len, crc; 00223 bmap_struct *bmap; 00224 size_t i; 00225 00226 fp = server_file_open(SERVER_FILE_BMAPS); 00227 00228 if (!fp) 00229 { 00230 return; 00231 } 00232 00233 /* Free previously allocated bmaps. */ 00234 if (bmaps) 00235 { 00236 for (i = 0; i < bmaps_size; i++) 00237 { 00238 free(bmaps[i].name); 00239 } 00240 00241 free(bmaps); 00242 bmaps_size = 0; 00243 bmaps = NULL; 00244 } 00245 00246 for (i = 0; i < MAX_FACE_TILES; i++) 00247 { 00248 if (FaceList[i].name) 00249 { 00250 free(FaceList[i].name); 00251 FaceList[i].name = NULL; 00252 sprite_free_sprite(FaceList[i].sprite); 00253 FaceList[i].sprite = NULL; 00254 FaceList[i].checksum = 0; 00255 FaceList[i].flags = 0; 00256 } 00257 } 00258 00259 while (fgets(buf, sizeof(buf) - 1, fp)) 00260 { 00261 if (sscanf(buf, "%x %x %s", &len, &crc, name) != 3) 00262 { 00263 LOG(llevBug, "Syntax error in server bmaps file: %s\n", buf); 00264 break; 00265 } 00266 00267 /* Find the bmap. */ 00268 bmap = bmap_find(name); 00269 /* Expand the array. */ 00270 bmaps = realloc(bmaps, sizeof(*bmaps) * (bmaps_size + 1)); 00271 00272 /* Does it exist, and the lengths and checksums match? */ 00273 if (bmap && bmap->len == len && bmap->crc32 == crc) 00274 { 00275 bmaps[bmaps_size].pos = bmap->pos; 00276 } 00277 /* It doesn't exist in the atrinik.p0 file. */ 00278 else 00279 { 00280 bmaps[bmaps_size].pos = -1; 00281 } 00282 00283 bmaps[bmaps_size].len = len; 00284 bmaps[bmaps_size].crc32 = crc; 00285 bmaps[bmaps_size].name = strdup(name); 00286 00287 bmaps_size++; 00288 } 00289 00290 fclose(fp); 00291 } 00292 00298 void finish_face_cmd(int pnum, uint32 checksum, char *face) 00299 { 00300 char buf[2048]; 00301 FILE *stream; 00302 struct stat statbuf; 00303 size_t len; 00304 static uint32 newsum = 0; 00305 unsigned char *data; 00306 00307 /* Loaded or requested. */ 00308 if (FaceList[pnum].name) 00309 { 00310 /* Let's check the name, checksum and sprite. Only if all is ok, 00311 * we stay with it */ 00312 if (!strcmp(face, FaceList[pnum].name) && checksum == FaceList[pnum].checksum && FaceList[pnum].sprite) 00313 { 00314 return; 00315 } 00316 00317 /* Something is different. */ 00318 free(FaceList[pnum].name); 00319 FaceList[pnum].name = NULL; 00320 sprite_free_sprite(FaceList[pnum].sprite); 00321 } 00322 00323 snprintf(buf, sizeof(buf), "%s.png", face); 00324 FaceList[pnum].name = (char *) malloc(strlen(buf) + 1); 00325 strcpy(FaceList[pnum].name, buf); 00326 00327 FaceList[pnum].checksum = checksum; 00328 00329 /* Check private cache first */ 00330 snprintf(buf, sizeof(buf), DIRECTORY_CACHE"/%s", FaceList[pnum].name); 00331 00332 if ((stream = fopen_wrapper(buf, "rb")) != NULL) 00333 { 00334 fstat(fileno (stream), &statbuf); 00335 len = statbuf.st_size; 00336 data = malloc(len); 00337 len = fread(data, 1, len, stream); 00338 fclose(stream); 00339 newsum = 0; 00340 00341 /* Something is wrong... Unlink the file and let it reload. */ 00342 if (len <= 0) 00343 { 00344 unlink(buf); 00345 checksum = 1; 00346 } 00347 /* Checksum check */ 00348 else 00349 { 00350 newsum = crc32(1L, data, len); 00351 } 00352 00353 free(data); 00354 00355 if (newsum == checksum) 00356 { 00357 FaceList[pnum].sprite = sprite_tryload_file(buf, 0, NULL); 00358 00359 if (FaceList[pnum].sprite) 00360 { 00361 return; 00362 } 00363 } 00364 } 00365 00366 snprintf(buf, sizeof(buf), "askface %d", pnum); 00367 cs_write_string(buf, strlen(buf)); 00368 } 00369 00374 static int load_picture_from_pack(int num) 00375 { 00376 FILE *stream; 00377 char *pbuf; 00378 SDL_RWops *rwop; 00379 00380 if ((stream = fopen_wrapper(FILE_ATRINIK_P0, "rb")) == NULL) 00381 { 00382 return 1; 00383 } 00384 00385 lseek(fileno(stream), bmaps[num].pos, SEEK_SET); 00386 00387 pbuf = malloc(bmaps[num].len); 00388 00389 if (!fread(pbuf, bmaps[num].len, 1, stream)) 00390 { 00391 fclose(stream); 00392 return 0; 00393 } 00394 00395 fclose(stream); 00396 00397 rwop = SDL_RWFromMem(pbuf, bmaps[num].len); 00398 00399 FaceList[num].sprite = sprite_tryload_file(NULL, 0, rwop); 00400 00401 SDL_FreeRW(rwop); 00402 free(pbuf); 00403 00404 return 0; 00405 } 00406 00411 static int load_gfx_user_face(uint16 num) 00412 { 00413 char buf[MAX_BUF]; 00414 FILE *stream; 00415 struct stat statbuf; 00416 size_t len; 00417 unsigned char *data; 00418 00419 /* First check for this image in gfx_user directory. */ 00420 snprintf(buf, sizeof(buf), DIRECTORY_GFX_USER"/%s.png", bmaps[num].name); 00421 00422 if ((stream = fopen_wrapper(buf, "rb")) != NULL) 00423 { 00424 fstat(fileno(stream), &statbuf); 00425 len = statbuf.st_size; 00426 data = malloc(len); 00427 len = fread(data, 1, len, stream); 00428 fclose(stream); 00429 00430 if (len > 0) 00431 { 00432 if (FaceList[num].sprite) 00433 { 00434 sprite_free_sprite(FaceList[num].sprite); 00435 } 00436 00437 if (FaceList[num].name) 00438 { 00439 free(FaceList[num].name); 00440 FaceList[num].name = NULL; 00441 } 00442 00443 /* Try to load it. */ 00444 FaceList[num].sprite = sprite_tryload_file(buf, 0, NULL); 00445 00446 if (FaceList[num].sprite) 00447 { 00448 snprintf(buf, sizeof(buf), DIRECTORY_GFX_USER"/%s.png", bmaps[num].name); 00449 FaceList[num].name = (char *) malloc(strlen(buf) + 1); 00450 strcpy(FaceList[num].name, buf); 00451 FaceList[num].checksum = crc32(1L, data, len); 00452 free(data); 00453 return 1; 00454 } 00455 } 00456 00457 /* If we are here something was wrong with the file. */ 00458 free(data); 00459 } 00460 00461 return 0; 00462 } 00463 00469 int request_face(int pnum) 00470 { 00471 char buf[MAX_BUF]; 00472 uint16 num = (uint16) (pnum &~ 0x8000); 00473 00474 if (setting_get_int(OPT_CAT_DEVEL, OPT_RELOAD_GFX) && load_gfx_user_face(num)) 00475 { 00476 return 1; 00477 } 00478 00479 /* Loaded or requested */ 00480 if (FaceList[num].name || FaceList[num].flags & FACE_REQUESTED) 00481 { 00482 return 1; 00483 } 00484 00485 if (num >= bmaps_size) 00486 { 00487 LOG(llevBug, "request_face(): Server sent picture ID too big (%d, max: %"FMT64U")\n", num, (uint64) bmaps_size); 00488 return 0; 00489 } 00490 00491 if (load_gfx_user_face(num)) 00492 { 00493 return 1; 00494 } 00495 00496 /* Best case - we have it in atrinik.p0 */ 00497 if (bmaps[num].pos != -1) 00498 { 00499 snprintf(buf, sizeof(buf), "%s.png", bmaps[num].name); 00500 FaceList[num].name = (char *) malloc(strlen(buf) + 1); 00501 strcpy(FaceList[num].name, buf); 00502 FaceList[num].checksum = bmaps[num].crc32; 00503 load_picture_from_pack(num); 00504 } 00505 /* Second best case - check the cache for it, or request it. */ 00506 else 00507 { 00508 FaceList[num].flags |= FACE_REQUESTED; 00509 finish_face_cmd(num, bmaps[num].crc32, bmaps[num].name); 00510 } 00511 00512 return 1; 00513 } 00514 00519 int get_bmap_id(char *name) 00520 { 00521 int l = 0, r = bmaps_size - 1, x, cmp; 00522 00523 /* All the faces in ::bmaps are already sorted, so we can use a 00524 * binary search here. */ 00525 while (r >= l) 00526 { 00527 x = (l + r) / 2; 00528 cmp = strcmp(name, bmaps[x].name); 00529 00530 if (cmp < 0) 00531 { 00532 r = x - 1; 00533 } 00534 else if (cmp > 0) 00535 { 00536 l = x + 1; 00537 } 00538 else 00539 { 00540 request_face(x); 00541 return x; 00542 } 00543 } 00544 00545 return -1; 00546 } 00547 00553 void blit_face(int id, int x, int y) 00554 { 00555 if (id == -1 || !FaceList[id].sprite) 00556 { 00557 return; 00558 } 00559 00560 sprite_blt(FaceList[id].sprite, x, y, NULL, NULL); 00561 }
1.7.4