ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/image.C
Revision: 1.28
Committed: Wed Mar 14 00:04:59 2007 UTC (17 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.27: +121 -23 lines
Log Message:
- rewrote smooth face handling, as a side-effect, smoothing seems to work
  again and smooth faces can be reloaded.
- the server now sends the full animation for an object the first time
  it is seen, this uses slightly more bandwidth initially, but avoids
  the flickering for objects change their face later.

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 root 1.24 for (q = 0; q < faces.size (); q++)
92 root 1.3 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     * Client tells us what type of faces it wants. Also sets
178     * the caching attribute.
179     *
180     */
181 root 1.3 void
182 root 1.13 SetFaceMode (char *buf, int len, client *ns)
183 elmex 1.1 {
184 root 1.3 int mask = (atoi (buf) & CF_FACE_CACHE), mode = (atoi (buf) & ~CF_FACE_CACHE);
185 elmex 1.1
186 root 1.3 if (mode == CF_FACE_NONE)
187 root 1.7 ns->facecache = 1;
188 root 1.3 else if (mode != CF_FACE_PNG)
189 root 1.14 ns->send_packet_printf ("drawinfo %d %s", NDI_RED, "Warning - send unsupported face mode. Will use Png");
190 root 1.7
191 root 1.3 if (mask)
192 root 1.7 ns->facecache = 1;
193 elmex 1.1 }
194    
195     /**
196     * Client has requested pixmap that it somehow missed getting.
197     * This will be called often if the client is
198     * caching images.
199     */
200 root 1.3 void
201 root 1.15 SendFaceCmd (char *buf, int len, client *ns)
202 elmex 1.1 {
203 root 1.28 ns->send_face (atoi (buf), 1);
204 elmex 1.1 }
205    
206 root 1.24 // how lame
207     static void print_facename (packet &sl, const facedata &d)
208     {
209 root 1.25 for (int i = 0; i < CHKSUM_SIZE; ++i)
210     sl.printf ("%02x", d.chksum [i]);
211 root 1.24 }
212    
213 root 1.26 // gcfclient uses the server-provided checksum for comparison,
214     // but always wrotes a broken checksum to its cache file, so we
215     // have to provide gcfclient with a useless checksum just to
216     // have to cache the image despite its bugs.
217     static uint32 gcfclient_checksum (const facedata *d)
218     {
219     uint32 csum = 0;
220    
221     for (std::string::const_iterator i = d->data.begin ();
222     i != d->data.end ();
223     ++i)
224     {
225     csum = rotate_right (csum);
226     csum += *(uint8 *)&*i;
227     }
228    
229     return csum;
230     }
231    
232 elmex 1.1 /**
233     * Sends a face to a client if they are in pixmap mode
234     * nothing gets sent in bitmap mode.
235     * If nocache is true (nonzero), ignore the cache setting from the client -
236     * this is needed for the askface, in which we really do want to send the
237     * face (and askface is the only place that should be setting it). Otherwise,
238     * we look at the facecache, and if set, send the image name.
239     */
240 root 1.3 void
241 root 1.28 client::send_face (faceidx facenum, bool forced)
242 elmex 1.1 {
243 root 1.28 // never send face 0. ever. it does not exist.
244     if (!facenum)
245     return;
246    
247     const facedata *d = face_data (facenum, faceset);
248    
249     if (!d)
250 root 1.3 {
251 root 1.28 LOG (llevError, "client::send_face (%d) out of bounds??\n", facenum);
252 root 1.3 return;
253     }
254    
255 root 1.8 packet sl;
256 root 1.3
257 root 1.28 if (facecache && !forced)
258 root 1.3 {
259 root 1.28 if (faces_sent[facenum] & NS_FACESENT_FACE)
260     return;
261    
262     faces_sent[facenum] |= NS_FACESENT_FACE;
263    
264     if (force_face0)
265     sl << "face " << uint16 (facenum);
266     else if (image2)
267     sl << "face2 " << uint16 (facenum) << uint8 (0) << uint32 (force_bad_checksum ? gcfclient_checksum (d) : 0);
268 root 1.26 else
269 root 1.28 sl << "face1 " << uint16 (facenum) << uint32 (force_bad_checksum ? gcfclient_checksum (d) : 0);
270 root 1.24
271     // how lame
272     print_facename (sl, *d);
273 root 1.3 }
274     else
275     {
276 root 1.28 fprintf (stderr, "image %d\n", facenum);//D
277     sl << (image2 ? "image2 " : "image ")
278     << uint32 (facenum);
279 root 1.6
280 root 1.28 if (image2)
281 root 1.24 sl << uint8 (0);
282 root 1.6
283 root 1.24 sl << uint32 (d->data.size ())
284     << data (d->data.data (), d->data.size ());
285 root 1.28 }
286    
287     send_packet (sl);
288     }
289    
290     // send all faces of this object to the client
291     // this uses more bandwidth initially, but makes
292     // animations look much smoother, and every client
293     // is supposed to do client-side caching anyways.
294     void
295     client::send_faces (object *ob)
296     {
297     send_face (ob->face);
298    
299     if (ob->animation_id)
300     {
301     animation &anim = animations [ob->animation_id];
302    
303     for (int i = 0; i < anim.num_animations; i++)
304     send_face (anim.faces [i]);
305     }
306     }
307    
308     /**
309     * A lot like the old AskSmooth (in fact, now called by AskSmooth).
310     * Basically, it makes no sense to wait for the client to request a
311     * a piece of data from us that we know the client wants. So
312     * if we know the client wants it, might as well push it to the
313     * client.
314     */
315     void
316     client::send_smooth (faceidx face)
317     {
318     faceinfo *f = face_info (face);
319    
320     if (!f)
321     return;
322    
323     if (faces_sent[face] & NS_FACESENT_SMOOTH)
324     return;
325    
326     faces_sent[face] |= NS_FACESENT_SMOOTH;
327 root 1.6
328 root 1.28 /* If we can't find a face, return and set it so we won't try to send this
329     * again.
330     */
331     if (!f->smooth)
332     {
333     LOG (llevError, "could not findsmooth for %d.\n", face);
334     return;
335     }
336    
337     send_face (f->smooth);
338    
339     packet sl ("smooth");
340    
341     sl << uint16 (face)
342     << uint16 (f->smooth);
343    
344     send_packet (sl);
345     }
346    
347     /**
348     * Need to send an animation sequence to the client.
349     * We will send appropriate face commands to the client if we haven't
350     * sent them the face yet (this can become quite costly in terms of
351     * how much we are sending - on the other hand, this should only happen
352     * when the player logs in and picks stuff up.
353     */
354     void
355     client::send_animation (short anim_num)
356     {
357     /* Do some checking on the anim_num we got. Note that the animations
358     * are added in contigous order, so if the number is in the valid
359     * range, it must be a valid animation.
360     */
361     if (anim_num < 0 || anim_num > num_animations)
362     {
363     LOG (llevError, "esrv_send_anim (%d) out of bounds??\n", anim_num);
364     return;
365     }
366    
367     packet sl ("anim");
368    
369     sl << uint16 (anim_num)
370     << uint16 (0); /* flags - not used right now */
371    
372     /* Build up the list of faces. Also, send any information (ie, the
373     * the face itself) down to the client.
374     */
375     for (int i = 0; i < animations[anim_num].num_animations; i++)
376     {
377     send_face (animations[anim_num].faces[i]);
378     sl << uint16 (animations[anim_num].faces[i]); /* flags - not used right now */
379 elmex 1.1 }
380 root 1.6
381 root 1.28 send_packet (sl);
382    
383     anims_sent[anim_num] = 1;
384 elmex 1.1 }
385    
386     /**
387     * Sends the number of images, checksum of the face file,
388     * and the image_info file information. See the doc/Developers/protocol
389     * if you want further detail.
390     */
391 root 1.3 void
392 root 1.15 send_image_info (client *ns, char *params)
393 elmex 1.1 {
394 root 1.8 packet sl;
395 elmex 1.1
396 root 1.24 //TODO: second parameter is a checksum, but it makes no sense in this current framework
397     sl.printf ("replyinfo image_info\n%d\n%u\n", MAX_FACES, 0);
398 root 1.6
399 root 1.24 sl << "0:base:standard:0:32x32:none:The old 32x32 faceset.\n";
400 elmex 1.1
401 root 1.11 ns->send_packet (sl);
402 elmex 1.1 }
403    
404     /**
405     * Sends requested face information.
406     * \param ns socket to send to
407     * \param params contains first and last index of face
408     *
409     * For each image in [start..stop] sends
410     * - checksum
411     * - name
412     */
413 root 1.3 void
414 root 1.15 send_image_sums (client *ns, char *params)
415 elmex 1.1 {
416 root 1.3 int start, stop;
417 pippijn 1.22 char *cp;
418 root 1.3
419 root 1.8 packet sl;
420 root 1.3
421     start = atoi (params);
422     for (cp = params; *cp != '\0'; cp++)
423     if (*cp == ' ')
424     break;
425    
426     stop = atoi (cp);
427 root 1.24 if (stop < start || *cp == '\0' || (stop - start) > 1000 || stop >= MAX_FACES)
428 root 1.3 {
429 root 1.7 sl.printf ("replyinfo image_sums %d %d", start, stop);
430     ns->send_packet (sl);
431     sl.reset ();
432 root 1.3 return;
433     }
434    
435 root 1.6 sl.printf ("replyinfo image_sums %d %d ", start, stop);
436 root 1.3
437 root 1.24 for (int i = start; i <= stop && i < faces.size (); i++)
438 root 1.3 {
439     ns->faces_sent[i] |= NS_FACESENT_FACE;
440    
441 root 1.24 const facedata *d = face_data (i, ns->faceset);
442 root 1.6
443 root 1.24 if (sl.room () < 2 + 4 + 1 + d->data.size () + 1)
444 root 1.23 break;
445    
446 root 1.6 sl << uint16 (i)
447 root 1.24 << uint32 (0) // checksum
448     << uint8 (ns->faceset);
449    
450     print_facename (sl, *d); sl << uint8 (0);
451 root 1.3 }
452 root 1.6
453 root 1.3 /* It would make more sense to catch this pre-emptively in the code above.
454     * however, if this really happens, we probably just want to cut down the
455     * size to less than 1000, since that is what we claim the protocol would
456     * support.
457     */
458 root 1.23 //TODO: taken care of above, should simply abort or make sure the above code is correct
459 root 1.9 if (sl.length () >= MAXSOCKBUF)
460 root 1.3 {
461 root 1.9 LOG (llevError, "send_image_send: buffer overrun, %d > %d\n", sl.length (), MAXSOCKBUF);
462 root 1.3 abort ();
463 elmex 1.1 }
464 root 1.6
465 root 1.11 ns->send_packet (sl);
466 elmex 1.1 }
467 root 1.6