Atrinik Client 2.5
client/image.c
Go to the documentation of this file.
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 }