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

# User Rev Content
1 elmex 1.1 /*
2 root 1.17 * 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 elmex 1.1
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 root 1.20 #include "crc.h"
40    
41 elmex 1.1 #define MAX_FACE_SETS 20 /**< Maximum number of image sets the program will handle */
42    
43     /** Information about one image */
44 root 1.3 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 elmex 1.1 } FaceInfo;
50    
51     /** Information about one face set */
52 root 1.3 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 elmex 1.1 } 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 root 1.3 int
72     is_valid_faceset (int fsn)
73 elmex 1.1 {
74 root 1.3 if (fsn >= 0 && fsn < MAX_FACE_SETS && facesets[fsn].prefix)
75     return TRUE;
76     return FALSE;
77 elmex 1.1 }
78    
79     /**
80     * Frees all faceset information
81     */
82 root 1.3 void
83     free_socket_images (void)
84 elmex 1.1 {
85 root 1.3 int num, q;
86 elmex 1.1
87 root 1.3 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 root 1.15
95 root 1.3 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 root 1.2 }
102 elmex 1.1 }
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 root 1.3 static int
118     get_face_fallback (int faceset, int imageno)
119 elmex 1.1 {
120 root 1.3 /* 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 root 1.15
135 root 1.3 if (facesets[faceset].faces[imageno].data)
136     return faceset;
137 root 1.15
138 root 1.3 return get_face_fallback (facesets[faceset].fallback, imageno);
139 elmex 1.1 }
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 root 1.3 static void
150     check_faceset_fallback (int faceset, int togo)
151 elmex 1.1 {
152 root 1.3 int fallback = facesets[faceset].fallback;
153 elmex 1.1
154 root 1.3 /* 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 root 1.15
164 root 1.3 togo--;
165     if (togo == 0)
166     {
167     LOG (llevError, "Infinite loop found in facesets. aborting.\n");
168     abort ();
169 elmex 1.1 }
170 root 1.15
171 root 1.3 check_faceset_fallback (fallback, togo);
172 elmex 1.1 }
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 root 1.3 void
193     read_client_images (void)
194 elmex 1.1 {
195 root 1.3 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 root 1.15
209 root 1.3 while (fgets (buf, HUGE_BUF - 1, infile) != NULL)
210     {
211     badline = 0;
212    
213     if (buf[0] == '#')
214     continue;
215 root 1.15
216 root 1.3 if (!(cps[0] = strtok (buf, ":")))
217     badline = 1;
218 root 1.15
219 root 1.3 for (i = 1; i < 7; i++)
220 root 1.15 if (!(cps[i] = strtok (NULL, ":")))
221     badline = 1;
222    
223 root 1.3 if (badline)
224 root 1.15 LOG (llevError, "Bad line in image_info file, ignoring line:\n %s", buf);
225 root 1.3 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 root 1.2 }
233 root 1.12 facesets[len].prefix = strdup (cps[1]);
234     facesets[len].fullname = strdup (cps[2]);
235 root 1.3 facesets[len].fallback = atoi (cps[3]);
236 root 1.12 facesets[len].size = strdup (cps[4]);
237     facesets[len].extension = strdup (cps[5]);
238     facesets[len].comment = strdup (cps[6]);
239 root 1.2 }
240 elmex 1.1 }
241 root 1.15
242 root 1.3 close_and_delete (infile, compressed);
243 root 1.15
244 root 1.3 for (i = 0; i < MAX_FACE_SETS; i++)
245     {
246     if (facesets[i].prefix)
247     check_faceset_fallback (i, MAX_FACE_SETS);
248     }
249 root 1.15
250 root 1.3 /* 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 root 1.15
260 root 1.3 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 root 1.2 }
270 root 1.15
271 root 1.3 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 root 1.2 }
278 root 1.15
279 root 1.3 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 root 1.2 }
285 root 1.15
286 root 1.3 /* Skip accross the number data */
287 root 1.21 for (cp = buf + 6; *cp != ' '; cp++)
288     ;
289    
290 root 1.3 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 root 1.2 }
296 root 1.15
297 root 1.5 /* We don't actualy care about the name of the image that
298 root 1.3 * 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 root 1.2 }
307 root 1.15
308 root 1.20 crc32 chksum;
309    
310 root 1.3 for (i = 0; i < len; i++)
311 root 1.20 chksum (facesets[fileno].faces[num].data[i]);
312    
313     facesets[fileno].faces[num].checksum = chksum;
314 root 1.2 }
315 root 1.15
316 root 1.3 close_and_delete (infile, compressed);
317     } /* For fileno < MAX_FACE_SETS */
318 elmex 1.1 }
319    
320     /**
321     * Client tells us what type of faces it wants. Also sets
322     * the caching attribute.
323     *
324     */
325 root 1.3 void
326 root 1.13 SetFaceMode (char *buf, int len, client *ns)
327 elmex 1.1 {
328 root 1.3 int mask = (atoi (buf) & CF_FACE_CACHE), mode = (atoi (buf) & ~CF_FACE_CACHE);
329 elmex 1.1
330 root 1.3 if (mode == CF_FACE_NONE)
331 root 1.7 ns->facecache = 1;
332 root 1.3 else if (mode != CF_FACE_PNG)
333 root 1.14 ns->send_packet_printf ("drawinfo %d %s", NDI_RED, "Warning - send unsupported face mode. Will use Png");
334 root 1.7
335 root 1.3 if (mask)
336 root 1.7 ns->facecache = 1;
337 elmex 1.1 }
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 root 1.3 void
345 root 1.15 SendFaceCmd (char *buf, int len, client *ns)
346 elmex 1.1 {
347 root 1.15 uint16 facenum = atoi (buf);
348 elmex 1.1
349 root 1.3 if (facenum != 0)
350     esrv_send_face (ns, facenum, 1);
351 elmex 1.1 }
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 root 1.3 void
362 root 1.13 esrv_send_face (client *ns, short face_num, int nocache)
363 elmex 1.1 {
364 root 1.3 char fallback;
365 elmex 1.1
366 root 1.3 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 root 1.8 packet sl;
373 root 1.3 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 root 1.6 sl << (ns->image2 ? "face2 " : "face1 ")
384     << uint16 (face_num);
385    
386 root 1.3 if (ns->image2)
387 root 1.6 sl << uint8 (fallback);
388    
389     sl << uint32 (facesets[fallback].faces[face_num].checksum)
390     << new_faces[face_num].name;
391 root 1.3
392 root 1.11 ns->send_packet (sl);
393 root 1.3 }
394     else
395     {
396 root 1.6 sl << (ns->image2 ? "image2 " : "image ")
397     << uint32 (face_num);
398    
399 root 1.3 if (ns->image2)
400 root 1.6 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 root 1.11 ns->send_packet (sl);
406 elmex 1.1 }
407 root 1.6
408 root 1.3 ns->faces_sent[face_num] |= NS_FACESENT_FACE;
409 elmex 1.1 }
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 root 1.3 void
418 root 1.15 send_image_info (client *ns, char *params)
419 elmex 1.1 {
420 root 1.8 packet sl;
421 elmex 1.1
422 root 1.19 sl.printf ("replyinfo image_info\n%d\n%u\n", nrofpixmaps - 1, (unsigned int)bmaps_checksum);
423 root 1.6
424     for (int i = 0; i < MAX_FACE_SETS; i++)
425     if (facesets[i].prefix)
426 root 1.15 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 elmex 1.1
430 root 1.11 ns->send_packet (sl);
431 elmex 1.1 }
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 root 1.3 void
443 root 1.15 send_image_sums (client *ns, char *params)
444 elmex 1.1 {
445 root 1.3 int start, stop;
446 pippijn 1.22 char *cp;
447 root 1.3
448 root 1.8 packet sl;
449 root 1.3
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 root 1.7 sl.printf ("replyinfo image_sums %d %d", start, stop);
459     ns->send_packet (sl);
460     sl.reset ();
461 root 1.3 return;
462     }
463    
464 root 1.6 sl.printf ("replyinfo image_sums %d %d ", start, stop);
465 root 1.3
466 root 1.6 for (int i = start; i <= stop; i++)
467 root 1.3 {
468     ns->faces_sent[i] |= NS_FACESENT_FACE;
469    
470 root 1.6 int qq = get_face_fallback (ns->faceset, i);
471    
472 root 1.23 if (sl.room () < 2 + 4 + 1 + new_faces[i].name.length () + 1)
473     break;
474    
475 root 1.6 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 root 1.3 }
480 root 1.6
481 root 1.3 /* 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 root 1.23 //TODO: taken care of above, should simply abort or make sure the above code is correct
487 root 1.9 if (sl.length () >= MAXSOCKBUF)
488 root 1.3 {
489 root 1.9 LOG (llevError, "send_image_send: buffer overrun, %d > %d\n", sl.length (), MAXSOCKBUF);
490 root 1.3 abort ();
491 elmex 1.1 }
492 root 1.6
493 root 1.11 ns->send_packet (sl);
494 elmex 1.1 }
495 root 1.6