ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/image.C
Revision: 1.23
Committed: Sat Mar 10 19:48:17 2007 UTC (17 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.22: +4 -0 lines
Log Message:
- improve image_sums
- DOWNGRADE server protocol version to 1026.
  * this disables requestinfo image_sums and image_info in gcfclient,
    allowing us to use up to 10000 faces dynamically
    (right now, we already sue up to 7500 faces, but the 10000 face limit
    is, of coruse, hardcoded into gcfclient))

--
A student, in hopes of understanding the Lambda-nature, came to
Greenblatt.  As they spoke a Multics system hacker walked by.  "Is it
true", asked the student, "that PL-1 has many of the same data types as
Lisp".  Almost before the student had finshed his question, Greenblatt
shouted, "FOO!", and hit the student with a stick.

File Contents

# Content
1 /*
2 * CrossFire, A Multiplayer game
3 *
4 * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
5 * Copyright (C) 2001 Mark Wedel
6 * Copyright (C) 1992 Frank Tore Johansen
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 * The author can be reached via e-mail to <crossfire@schmorp.de>
23 */
24
25 /** \file
26 * Image related communication
27 *
28 * \date 2003-12-02
29 *
30 * This file deals with the image related communication to the
31 * client. I've located all the functions in this file - this
32 * localizes it more, and means that we don't need to declare
33 * things like all the structures as globals.
34 */
35
36 #include <global.h>
37 #include <sproto.h>
38
39 #include "crc.h"
40
41 #define MAX_FACE_SETS 20 /**< Maximum number of image sets the program will handle */
42
43 /** Information about one image */
44 typedef struct FaceInfo
45 {
46 uint8 *data; /**< image data */
47 uint16 datalen; /**< length of the xpm data */
48 uint32 checksum; /**< Checksum of face data */
49 } FaceInfo;
50
51 /** Information about one face set */
52 typedef struct
53 {
54 char *prefix; /**< */
55 char *fullname;
56
57 uint8 fallback; /**< faceset to use when an image is not found in this faceset */
58 char *size;
59 char *extension;
60 char *comment;
61
62 FaceInfo *faces; /**< images in this faceset */
63 } FaceSets;
64
65 static FaceSets facesets[MAX_FACE_SETS]; /**< All facesets */
66
67 /**
68 * Checks specified faceset is valid
69 * \param fsn faceset number
70 */
71 int
72 is_valid_faceset (int fsn)
73 {
74 if (fsn >= 0 && fsn < MAX_FACE_SETS && facesets[fsn].prefix)
75 return TRUE;
76 return FALSE;
77 }
78
79 /**
80 * Frees all faceset information
81 */
82 void
83 free_socket_images (void)
84 {
85 int num, q;
86
87 for (num = 0; num < MAX_FACE_SETS; num++)
88 {
89 if (facesets[num].prefix)
90 {
91 for (q = 0; q < nrofpixmaps; q++)
92 if (facesets[num].faces[q].data)
93 free (facesets[num].faces[q].data);
94
95 free (facesets[num].prefix);
96 free (facesets[num].fullname);
97 free (facesets[num].size);
98 free (facesets[num].extension);
99 free (facesets[num].comment);
100 free (facesets[num].faces);
101 }
102 }
103 }
104
105 /**
106 * This returns the set we will actually use when sending
107 * a face. This is used because the image files may be sparse.
108 * This function is recursive. imageno is the face number we are
109 * trying to send
110 *
111 * If face is not found in specified faceset, tries with 'fallback' faceset.
112 *
113 * \param faceset faceset to check
114 * \param imageno image number
115 *
116 */
117 static int
118 get_face_fallback (int faceset, int imageno)
119 {
120 /* faceset 0 is supposed to have every image, so just return. Doing
121 * so also prevents infinite loops in the case if it not having
122 * the face, but in that case, we are likely to crash when we try
123 * to access the data, but that is probably preferable to an infinite
124 * loop.
125 */
126 if (faceset == 0)
127 return 0;
128
129 if (!facesets[faceset].prefix)
130 {
131 LOG (llevError, "get_face_fallback called with unused set (%d)?\n", faceset);
132 return 0; /* use default set */
133 }
134
135 if (facesets[faceset].faces[imageno].data)
136 return faceset;
137
138 return get_face_fallback (facesets[faceset].fallback, imageno);
139 }
140
141 /**
142 * Checks fallback are correctly defined.
143 * This is a simple recursive function that makes sure the fallbacks
144 * are all proper (eg, the fall back to defined sets, and also
145 * eventually fall back to 0). At the top level, togo is set to MAX_FACE_SETS,
146 * if togo gets to zero, it means we have a loop.
147 * This is only run when we first load the facesets.
148 */
149 static void
150 check_faceset_fallback (int faceset, int togo)
151 {
152 int fallback = facesets[faceset].fallback;
153
154 /* proper case - falls back to base set */
155 if (fallback == 0)
156 return;
157
158 if (!facesets[fallback].prefix)
159 {
160 LOG (llevError, "Face set %d falls to non set faceset %d\n", faceset, fallback);
161 abort ();
162 }
163
164 togo--;
165 if (togo == 0)
166 {
167 LOG (llevError, "Infinite loop found in facesets. aborting.\n");
168 abort ();
169 }
170
171 check_faceset_fallback (fallback, togo);
172 }
173
174 #define MAX_IMAGE_SIZE 10000
175
176 /**
177 * Loads all the image types into memory.
178 *
179 * This way, we can easily send them to the client. We should really do something
180 * better than abort on any errors - on the other hand, these are all fatal
181 * to the server (can't work around them), but the abort just seems a bit
182 * messy (exit would probably be better.)
183 *
184 * Couple of notes: We assume that the faces are in a continous block.
185 * This works fine for now, but this could perhaps change in the future
186 *
187 * Function largely rewritten May 2000 to be more general purpose.
188 * The server itself does not care what the image data is - to the server,
189 * it is just data it needs to allocate. As such, the code is written
190 * to do such.
191 */
192 void
193 read_client_images (void)
194 {
195 char filename[400];
196 char buf[HUGE_BUF];
197 char *cp, *cps[7];
198 FILE *infile;
199 int num, len, compressed, fileno, i, badline;
200
201 memset (facesets, 0, sizeof (facesets));
202 sprintf (filename, "%s/image_info", settings.datadir);
203 if ((infile = open_and_uncompress (filename, 0, &compressed)) == NULL)
204 {
205 LOG (llevError, "Unable to open %s\n", filename);
206 abort ();
207 }
208
209 while (fgets (buf, HUGE_BUF - 1, infile) != NULL)
210 {
211 badline = 0;
212
213 if (buf[0] == '#')
214 continue;
215
216 if (!(cps[0] = strtok (buf, ":")))
217 badline = 1;
218
219 for (i = 1; i < 7; i++)
220 if (!(cps[i] = strtok (NULL, ":")))
221 badline = 1;
222
223 if (badline)
224 LOG (llevError, "Bad line in image_info file, ignoring line:\n %s", buf);
225 else
226 {
227 len = atoi (cps[0]);
228 if (len >= MAX_FACE_SETS)
229 {
230 LOG (llevError, "To high a setnum in image_info file: %d > %d\n", len, MAX_FACE_SETS);
231 abort ();
232 }
233 facesets[len].prefix = strdup (cps[1]);
234 facesets[len].fullname = strdup (cps[2]);
235 facesets[len].fallback = atoi (cps[3]);
236 facesets[len].size = strdup (cps[4]);
237 facesets[len].extension = strdup (cps[5]);
238 facesets[len].comment = strdup (cps[6]);
239 }
240 }
241
242 close_and_delete (infile, compressed);
243
244 for (i = 0; i < MAX_FACE_SETS; i++)
245 {
246 if (facesets[i].prefix)
247 check_faceset_fallback (i, MAX_FACE_SETS);
248 }
249
250 /* Loaded the faceset information - now need to load up the
251 * actual faces.
252 */
253
254 for (fileno = 0; fileno < MAX_FACE_SETS; fileno++)
255 {
256 /* if prefix is not set, this is not used */
257 if (!facesets[fileno].prefix)
258 continue;
259
260 facesets[fileno].faces = (FaceInfo *) calloc (nrofpixmaps, sizeof (FaceInfo));
261
262 sprintf (filename, "%s/crossfire.%d", settings.datadir, fileno);
263 LOG (llevDebug, "Loading image file %s\n", filename);
264
265 if ((infile = open_and_uncompress (filename, 0, &compressed)) == NULL)
266 {
267 LOG (llevError, "Unable to open %s\n", filename);
268 abort ();
269 }
270
271 while (fgets (buf, HUGE_BUF - 1, infile) != NULL)
272 {
273 if (strncmp (buf, "IMAGE ", 6) != 0)
274 {
275 LOG (llevError, "read_client_images:Bad image line - not IMAGE, instead\n%s", buf);
276 abort ();
277 }
278
279 num = atoi (buf + 6);
280 if (num < 0 || num >= nrofpixmaps)
281 {
282 LOG (llevError, "read_client_images: Image num %d not in 0..%d\n%s", num, nrofpixmaps, buf);
283 abort ();
284 }
285
286 /* Skip accross the number data */
287 for (cp = buf + 6; *cp != ' '; cp++)
288 ;
289
290 len = atoi (cp);
291 if (len == 0 || len > MAX_IMAGE_SIZE)
292 {
293 LOG (llevError, "read_client_images: length not valid: %d > %d \n%s", len, MAX_IMAGE_SIZE, buf);
294 abort ();
295 }
296
297 /* We don't actualy care about the name of the image that
298 * is embedded in the image file, so just ignore it.
299 */
300 facesets[fileno].faces[num].datalen = len;
301 facesets[fileno].faces[num].data = (uint8 *) malloc (len);
302 if ((i = fread (facesets[fileno].faces[num].data, len, 1, infile)) != 1)
303 {
304 LOG (llevError, "read_client_images: Did not read desired amount of data, wanted %d, got %d\n%s", len, i, buf);
305 abort ();
306 }
307
308 crc32 chksum;
309
310 for (i = 0; i < len; i++)
311 chksum (facesets[fileno].faces[num].data[i]);
312
313 facesets[fileno].faces[num].checksum = chksum;
314 }
315
316 close_and_delete (infile, compressed);
317 } /* For fileno < MAX_FACE_SETS */
318 }
319
320 /**
321 * Client tells us what type of faces it wants. Also sets
322 * the caching attribute.
323 *
324 */
325 void
326 SetFaceMode (char *buf, int len, client *ns)
327 {
328 int mask = (atoi (buf) & CF_FACE_CACHE), mode = (atoi (buf) & ~CF_FACE_CACHE);
329
330 if (mode == CF_FACE_NONE)
331 ns->facecache = 1;
332 else if (mode != CF_FACE_PNG)
333 ns->send_packet_printf ("drawinfo %d %s", NDI_RED, "Warning - send unsupported face mode. Will use Png");
334
335 if (mask)
336 ns->facecache = 1;
337 }
338
339 /**
340 * Client has requested pixmap that it somehow missed getting.
341 * This will be called often if the client is
342 * caching images.
343 */
344 void
345 SendFaceCmd (char *buf, int len, client *ns)
346 {
347 uint16 facenum = atoi (buf);
348
349 if (facenum != 0)
350 esrv_send_face (ns, facenum, 1);
351 }
352
353 /**
354 * Sends a face to a client if they are in pixmap mode
355 * nothing gets sent in bitmap mode.
356 * If nocache is true (nonzero), ignore the cache setting from the client -
357 * this is needed for the askface, in which we really do want to send the
358 * face (and askface is the only place that should be setting it). Otherwise,
359 * we look at the facecache, and if set, send the image name.
360 */
361 void
362 esrv_send_face (client *ns, short face_num, int nocache)
363 {
364 char fallback;
365
366 if (face_num <= 0 || face_num >= nrofpixmaps)
367 {
368 LOG (llevError, "esrv_send_face (%d) out of bounds??\n", face_num);
369 return;
370 }
371
372 packet sl;
373 fallback = get_face_fallback (ns->faceset, face_num);
374
375 if (facesets[fallback].faces[face_num].data == NULL)
376 {
377 LOG (llevError, "esrv_send_face: faces[%d].data == NULL\n", face_num);
378 return;
379 }
380
381 if (ns->facecache && !nocache)
382 {
383 sl << (ns->image2 ? "face2 " : "face1 ")
384 << uint16 (face_num);
385
386 if (ns->image2)
387 sl << uint8 (fallback);
388
389 sl << uint32 (facesets[fallback].faces[face_num].checksum)
390 << new_faces[face_num].name;
391
392 ns->send_packet (sl);
393 }
394 else
395 {
396 sl << (ns->image2 ? "image2 " : "image ")
397 << uint32 (face_num);
398
399 if (ns->image2)
400 sl << uint8 (fallback);
401
402 sl << uint32 (facesets[fallback].faces[face_num].datalen)
403 << data (facesets[fallback].faces[face_num].data, facesets[fallback].faces[face_num].datalen);
404
405 ns->send_packet (sl);
406 }
407
408 ns->faces_sent[face_num] |= NS_FACESENT_FACE;
409 }
410
411 /**
412 * Sends the number of images, checksum of the face file,
413 * and the image_info file information. See the doc/Developers/protocol
414 * if you want further detail.
415 */
416
417 void
418 send_image_info (client *ns, char *params)
419 {
420 packet sl;
421
422 sl.printf ("replyinfo image_info\n%d\n%u\n", nrofpixmaps - 1, (unsigned int)bmaps_checksum);
423
424 for (int i = 0; i < MAX_FACE_SETS; i++)
425 if (facesets[i].prefix)
426 sl.printf ("%d:%s:%s:%d:%s:%s:%s", i,
427 facesets[i].prefix, facesets[i].fullname , facesets[i].fallback,
428 facesets[i].size , facesets[i].extension, facesets[i].comment);
429
430 ns->send_packet (sl);
431 }
432
433 /**
434 * Sends requested face information.
435 * \param ns socket to send to
436 * \param params contains first and last index of face
437 *
438 * For each image in [start..stop] sends
439 * - checksum
440 * - name
441 */
442 void
443 send_image_sums (client *ns, char *params)
444 {
445 int start, stop;
446 char *cp;
447
448 packet sl;
449
450 start = atoi (params);
451 for (cp = params; *cp != '\0'; cp++)
452 if (*cp == ' ')
453 break;
454
455 stop = atoi (cp);
456 if (stop < start || *cp == '\0' || (stop - start) > 1000 || stop >= nrofpixmaps)
457 {
458 sl.printf ("replyinfo image_sums %d %d", start, stop);
459 ns->send_packet (sl);
460 sl.reset ();
461 return;
462 }
463
464 sl.printf ("replyinfo image_sums %d %d ", start, stop);
465
466 for (int i = start; i <= stop; i++)
467 {
468 ns->faces_sent[i] |= NS_FACESENT_FACE;
469
470 int qq = get_face_fallback (ns->faceset, i);
471
472 if (sl.room () < 2 + 4 + 1 + new_faces[i].name.length () + 1)
473 break;
474
475 sl << uint16 (i)
476 << uint32 (facesets[qq].faces[i].checksum)
477 << uint8 (qq)
478 << data8 (&new_faces[i].name, new_faces[i].name.length () + 1);
479 }
480
481 /* It would make more sense to catch this pre-emptively in the code above.
482 * however, if this really happens, we probably just want to cut down the
483 * size to less than 1000, since that is what we claim the protocol would
484 * support.
485 */
486 //TODO: taken care of above, should simply abort or make sure the above code is correct
487 if (sl.length () >= MAXSOCKBUF)
488 {
489 LOG (llevError, "send_image_send: buffer overrun, %d > %d\n", sl.length (), MAXSOCKBUF);
490 abort ();
491 }
492
493 ns->send_packet (sl);
494 }
495