ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/image.C
Revision: 1.44
Committed: Sun Jul 1 05:00:20 2007 UTC (16 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.43: +11 -12 lines
Log Message:
- upgrade crossfire trt to the GPL version 3 (hopefully correctly).
- add a single file covered by the GNU Affero General Public License
  (which is not yet released, so I used the current draft, which is
  legally a bit wavy, but its likely better than nothing as it expresses
  direct intent by the authors, and we can upgrade as soon as it has been
  released).
  * this should ensure availability of source code for the server at least
    and hopefully also archetypes and maps even when modified versions
    are not being distributed, in accordance of section 13 of the agplv3.

File Contents

# User Rev Content
1 elmex 1.1 /*
2 root 1.44 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
3 root 1.42 *
4     * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
5     * Copyright (©) 2001,2007 Mark Wedel
6     * Copyright (©) 1992,2007 Frank Tore Johansen
7     *
8 root 1.44 * Crossfire TRT 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 3 of the License, or
11     * (at your option) any later version.
12 root 1.42 *
13 root 1.44 * 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 root 1.42 *
18 root 1.44 * You should have received a copy of the GNU General Public License
19     * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 root 1.42 *
21     * The authors can be reached via e-mail to <crossfire@schmorp.de>
22 root 1.17 */
23 elmex 1.1
24     /** \file
25     * Image related communication
26     *
27     * \date 2003-12-02
28     *
29     * This file deals with the image related communication to the
30     * client. I've located all the functions in this file - this
31     * localizes it more, and means that we don't need to declare
32     * things like all the structures as globals.
33     */
34    
35     #include <global.h>
36     #include <sproto.h>
37    
38 root 1.20 #include "crc.h"
39    
40 elmex 1.1 #define MAX_FACE_SETS 20 /**< Maximum number of image sets the program will handle */
41    
42     /** Information about one image */
43 root 1.3 typedef struct FaceInfo
44     {
45     uint8 *data; /**< image data */
46     uint16 datalen; /**< length of the xpm data */
47     uint32 checksum; /**< Checksum of face data */
48 elmex 1.1 } FaceInfo;
49    
50     /** Information about one face set */
51 root 1.3 typedef struct
52     {
53     char *prefix; /**< */
54     char *fullname;
55    
56     uint8 fallback; /**< faceset to use when an image is not found in this faceset */
57     char *size;
58     char *extension;
59     char *comment;
60    
61     FaceInfo *faces; /**< images in this faceset */
62 elmex 1.1 } FaceSets;
63    
64     static FaceSets facesets[MAX_FACE_SETS]; /**< All facesets */
65    
66     /**
67     * Checks specified faceset is valid
68     * \param fsn faceset number
69     */
70 root 1.3 int
71     is_valid_faceset (int fsn)
72 elmex 1.1 {
73 root 1.3 if (fsn >= 0 && fsn < MAX_FACE_SETS && facesets[fsn].prefix)
74     return TRUE;
75     return FALSE;
76 elmex 1.1 }
77    
78     /**
79     * Frees all faceset information
80     */
81 root 1.3 void
82     free_socket_images (void)
83 elmex 1.1 {
84 root 1.3 int num, q;
85 elmex 1.1
86 root 1.3 for (num = 0; num < MAX_FACE_SETS; num++)
87     {
88     if (facesets[num].prefix)
89     {
90 root 1.24 for (q = 0; q < faces.size (); q++)
91 root 1.3 if (facesets[num].faces[q].data)
92     free (facesets[num].faces[q].data);
93 root 1.15
94 root 1.3 free (facesets[num].prefix);
95     free (facesets[num].fullname);
96     free (facesets[num].size);
97     free (facesets[num].extension);
98     free (facesets[num].comment);
99     free (facesets[num].faces);
100 root 1.2 }
101 elmex 1.1 }
102     }
103    
104     /**
105     * This returns the set we will actually use when sending
106     * a face. This is used because the image files may be sparse.
107     * This function is recursive. imageno is the face number we are
108     * trying to send
109     *
110     * If face is not found in specified faceset, tries with 'fallback' faceset.
111     *
112     * \param faceset faceset to check
113     * \param imageno image number
114     *
115     */
116 root 1.3 static int
117     get_face_fallback (int faceset, int imageno)
118 elmex 1.1 {
119 root 1.3 /* faceset 0 is supposed to have every image, so just return. Doing
120     * so also prevents infinite loops in the case if it not having
121     * the face, but in that case, we are likely to crash when we try
122     * to access the data, but that is probably preferable to an infinite
123     * loop.
124     */
125     if (faceset == 0)
126     return 0;
127    
128     if (!facesets[faceset].prefix)
129     {
130     LOG (llevError, "get_face_fallback called with unused set (%d)?\n", faceset);
131     return 0; /* use default set */
132     }
133 root 1.15
134 root 1.3 if (facesets[faceset].faces[imageno].data)
135     return faceset;
136 root 1.15
137 root 1.3 return get_face_fallback (facesets[faceset].fallback, imageno);
138 elmex 1.1 }
139    
140     /**
141     * Checks fallback are correctly defined.
142     * This is a simple recursive function that makes sure the fallbacks
143     * are all proper (eg, the fall back to defined sets, and also
144     * eventually fall back to 0). At the top level, togo is set to MAX_FACE_SETS,
145     * if togo gets to zero, it means we have a loop.
146     * This is only run when we first load the facesets.
147     */
148 root 1.3 static void
149     check_faceset_fallback (int faceset, int togo)
150 elmex 1.1 {
151 root 1.3 int fallback = facesets[faceset].fallback;
152 elmex 1.1
153 root 1.3 /* proper case - falls back to base set */
154     if (fallback == 0)
155     return;
156    
157     if (!facesets[fallback].prefix)
158     {
159     LOG (llevError, "Face set %d falls to non set faceset %d\n", faceset, fallback);
160     abort ();
161     }
162 root 1.15
163 root 1.3 togo--;
164     if (togo == 0)
165     {
166     LOG (llevError, "Infinite loop found in facesets. aborting.\n");
167     abort ();
168 elmex 1.1 }
169 root 1.15
170 root 1.3 check_faceset_fallback (fallback, togo);
171 elmex 1.1 }
172    
173     #define MAX_IMAGE_SIZE 10000
174    
175     /**
176     * Client tells us what type of faces it wants. Also sets
177     * the caching attribute.
178     *
179     */
180 root 1.3 void
181 root 1.13 SetFaceMode (char *buf, int len, client *ns)
182 elmex 1.1 {
183 root 1.3 int mask = (atoi (buf) & CF_FACE_CACHE), mode = (atoi (buf) & ~CF_FACE_CACHE);
184 elmex 1.1
185 root 1.3 if (mode == CF_FACE_NONE)
186 root 1.7 ns->facecache = 1;
187 root 1.3 else if (mode != CF_FACE_PNG)
188 root 1.14 ns->send_packet_printf ("drawinfo %d %s", NDI_RED, "Warning - send unsupported face mode. Will use Png");
189 root 1.7
190 root 1.3 if (mask)
191 root 1.7 ns->facecache = 1;
192 elmex 1.1 }
193    
194     /**
195 root 1.43 * client requested an image. send it rate-limited
196     * before flushing.
197 elmex 1.1 */
198 root 1.3 void
199 root 1.43 AskFaceCmd (char *buf, int len, client *ns)
200 elmex 1.1 {
201 root 1.43 int idx = 0, pri = 0;
202    
203     sscanf (buf, "%d %d", &idx, &pri);
204    
205     const facedata *d = face_data (idx, ns->faceset);
206    
207     if (!d)
208     return; // doh
209    
210     client::ixsend ix;
211    
212     ix.pri = pri;
213     ix.idx = idx;
214     ix.ofs = d->data.size ();
215    
216     // the by far most common case will be to insert
217     // right at the end, so no looping.
218     auto (i, ns->ixface.end ());
219     for (; i != ns->ixface.begin (); )
220     if (pri >= (--i)->pri)
221     break;
222    
223     ns->ixface.insert (i, ix);
224     }
225    
226     /**
227     * Tells client the picture it has to use
228     * to smooth a picture number given as argument.
229     */
230     void
231     AskSmooth (char *buf, int len, client *ns)
232     {
233     ns->send_face (atoi (buf));
234     ns->flush_fx ();
235 elmex 1.1 }
236    
237 root 1.24 // how lame
238     static void print_facename (packet &sl, const facedata &d)
239     {
240 root 1.25 for (int i = 0; i < CHKSUM_SIZE; ++i)
241     sl.printf ("%02x", d.chksum [i]);
242 root 1.24 }
243    
244 root 1.32 // gcfclient uses the server-provided checksum for comparison, but always
245     // writes a broken checksum to its cache file, so we have to provide
246     // gcfclient with the same broken (and useless) checksum just to have it
247     // cache the image despite its bugs.
248 root 1.26 static uint32 gcfclient_checksum (const facedata *d)
249     {
250     uint32 csum = 0;
251    
252     for (std::string::const_iterator i = d->data.begin ();
253     i != d->data.end ();
254     ++i)
255     {
256     csum = rotate_right (csum);
257     csum += *(uint8 *)&*i;
258     }
259    
260     return csum;
261     }
262    
263 elmex 1.1 /**
264     * Sends a face to a client if they are in pixmap mode
265     * nothing gets sent in bitmap mode.
266     * If nocache is true (nonzero), ignore the cache setting from the client -
267     * this is needed for the askface, in which we really do want to send the
268     * face (and askface is the only place that should be setting it). Otherwise,
269     * we look at the facecache, and if set, send the image name.
270     */
271 root 1.3 void
272 root 1.32 client::send_face (faceidx facenum)
273 elmex 1.1 {
274 root 1.28 // never send face 0. ever. it does not exist.
275     if (!facenum)
276     return;
277    
278     const facedata *d = face_data (facenum, faceset);
279    
280     if (!d)
281 root 1.3 {
282 root 1.28 LOG (llevError, "client::send_face (%d) out of bounds??\n", facenum);
283 root 1.3 return;
284     }
285    
286 root 1.32 if (faces_sent[facenum])
287     return;
288    
289     faces_sent[facenum] = true;
290    
291 root 1.38 // if for some reason we let a client without face caching connect,
292     // we better support that decision here and implement it.
293 root 1.33 if (!facecache)
294 root 1.38 return send_image (facenum);
295 root 1.33
296 root 1.39 if (fxix)
297     {
298     fxface.push_back (facenum);
299     return;
300     }
301    
302 root 1.8 packet sl;
303 root 1.3
304 root 1.32 if (force_face0)
305     sl << "face " << uint16 (facenum);
306     else if (image2)
307     sl << "face2 " << uint16 (facenum) << uint8 (0) << uint32 (force_bad_checksum ? gcfclient_checksum (d) : 0);
308     else
309     sl << "face1 " << uint16 (facenum) << uint32 (force_bad_checksum ? gcfclient_checksum (d) : 0);
310    
311     // how lame
312     print_facename (sl, *d);
313     send_packet (sl);
314    
315 root 1.40 if (EMI_smooth)
316 root 1.3 {
317 root 1.40 faceinfo *f = face_info (facenum);
318 root 1.28
319 root 1.40 if (f->smooth)
320     {
321     send_face (f->smooth);
322    
323     packet sl ("smooth");
324 root 1.30
325 root 1.40 sl << uint16 (facenum)
326     << uint16 (f->smooth);
327 root 1.31
328 root 1.40 send_packet (sl);
329     }
330 root 1.32 }
331     }
332    
333 root 1.39 void client::flush_fx ()
334     {
335     while (!fxface.empty ())
336     {
337 root 1.40 packet fx ("fx");
338     packet sx ("sx");
339 root 1.39
340     do
341     {
342     faceidx facenum = fxface.back (); fxface.pop_back ();
343    
344     const facedata *d = face_data (facenum, faceset);
345    
346     if (d)
347     {
348 root 1.40 fx << ber32 (facenum)
349 root 1.39 << data8 (d->chksum, CHKSUM_SIZE);
350    
351 root 1.40 if (smoothing)
352     {
353     faceinfo *f = face_info (facenum);
354    
355     if (f->smooth)
356     {
357     send_face (f->smooth);
358     sx << ber32 (facenum)
359     << ber32 (f->smooth)
360     << ber32 (f->smoothlevel);
361     }
362     }
363 root 1.39 }
364     }
365 root 1.40 while (!fxface.empty ()
366     && fx.room () > ber32::size + CHKSUM_SIZE + 1
367     && sx.room () > ber32::size * 3);
368 root 1.39
369 root 1.40 send_packet (fx);
370     if (sx.length () > 3) send_packet (sx);
371 root 1.39 }
372     }
373    
374 root 1.32 void
375     client::send_image (faceidx facenum)
376     {
377     // never send face 0. ever. it does not exist.
378     if (!facenum)
379     return;
380 root 1.31
381 root 1.32 const facedata *d = face_data (facenum, faceset);
382 root 1.30
383 root 1.43 faces_sent[facenum] = true;
384    
385 root 1.32 if (!d)
386     {
387     LOG (llevError, "client::send_image (%d) out of bounds??\n", facenum);
388     return;
389     }
390 root 1.43
391     //TODO: check type here?
392 root 1.34
393 root 1.36 if (force_image_newmap)
394     force_newmap = true;
395    
396 root 1.32 packet sl;
397 root 1.30
398 root 1.32 sl << (image2 ? "image2 " : "image ")
399     << uint32 (facenum);
400 root 1.6
401 root 1.32 if (image2)
402     sl << uint8 (0);
403 root 1.6
404 root 1.32 sl << uint32 (d->data.size ())
405     << data (d->data.data (), d->data.size ());
406 root 1.31
407 root 1.32 send_packet (sl);
408 root 1.28 }
409    
410     // send all faces of this object to the client
411     // this uses more bandwidth initially, but makes
412     // animations look much smoother, and every client
413     // is supposed to do client-side caching anyways.
414     void
415     client::send_faces (object *ob)
416     {
417     send_face (ob->face);
418    
419     if (ob->animation_id)
420     {
421     animation &anim = animations [ob->animation_id];
422    
423     for (int i = 0; i < anim.num_animations; i++)
424     send_face (anim.faces [i]);
425     }
426     }
427    
428     /**
429     * Need to send an animation sequence to the client.
430     * We will send appropriate face commands to the client if we haven't
431     * sent them the face yet (this can become quite costly in terms of
432     * how much we are sending - on the other hand, this should only happen
433     * when the player logs in and picks stuff up.
434     */
435     void
436     client::send_animation (short anim_num)
437     {
438     /* Do some checking on the anim_num we got. Note that the animations
439     * are added in contigous order, so if the number is in the valid
440     * range, it must be a valid animation.
441     */
442 root 1.41 if (anim_num < 0 || anim_num >= animations.size ())
443 root 1.28 {
444     LOG (llevError, "esrv_send_anim (%d) out of bounds??\n", anim_num);
445     return;
446     }
447    
448     packet sl ("anim");
449    
450     sl << uint16 (anim_num)
451     << uint16 (0); /* flags - not used right now */
452    
453     /* Build up the list of faces. Also, send any information (ie, the
454     * the face itself) down to the client.
455     */
456     for (int i = 0; i < animations[anim_num].num_animations; i++)
457     {
458     send_face (animations[anim_num].faces[i]);
459     sl << uint16 (animations[anim_num].faces[i]); /* flags - not used right now */
460 elmex 1.1 }
461 root 1.6
462 root 1.28 send_packet (sl);
463    
464     anims_sent[anim_num] = 1;
465 elmex 1.1 }
466    
467     /**
468     * Sends the number of images, checksum of the face file,
469     * and the image_info file information. See the doc/Developers/protocol
470     * if you want further detail.
471     */
472 root 1.3 void
473 root 1.15 send_image_info (client *ns, char *params)
474 elmex 1.1 {
475 root 1.8 packet sl;
476 elmex 1.1
477 root 1.24 //TODO: second parameter is a checksum, but it makes no sense in this current framework
478     sl.printf ("replyinfo image_info\n%d\n%u\n", MAX_FACES, 0);
479 root 1.6
480 root 1.24 sl << "0:base:standard:0:32x32:none:The old 32x32 faceset.\n";
481 elmex 1.1
482 root 1.11 ns->send_packet (sl);
483 elmex 1.1 }
484    
485     /**
486     * Sends requested face information.
487     * \param ns socket to send to
488     * \param params contains first and last index of face
489     *
490     * For each image in [start..stop] sends
491     * - checksum
492     * - name
493     */
494 root 1.3 void
495 root 1.15 send_image_sums (client *ns, char *params)
496 elmex 1.1 {
497 root 1.3 int start, stop;
498 pippijn 1.22 char *cp;
499 root 1.3
500 root 1.8 packet sl;
501 root 1.3
502     start = atoi (params);
503     for (cp = params; *cp != '\0'; cp++)
504     if (*cp == ' ')
505     break;
506    
507     stop = atoi (cp);
508 root 1.24 if (stop < start || *cp == '\0' || (stop - start) > 1000 || stop >= MAX_FACES)
509 root 1.3 {
510 root 1.7 sl.printf ("replyinfo image_sums %d %d", start, stop);
511     ns->send_packet (sl);
512     sl.reset ();
513 root 1.3 return;
514     }
515    
516 root 1.6 sl.printf ("replyinfo image_sums %d %d ", start, stop);
517 root 1.3
518 root 1.24 for (int i = start; i <= stop && i < faces.size (); i++)
519 root 1.3 {
520 root 1.30 ns->faces_sent[i] = true;
521 root 1.3
522 root 1.24 const facedata *d = face_data (i, ns->faceset);
523 root 1.6
524 root 1.24 if (sl.room () < 2 + 4 + 1 + d->data.size () + 1)
525 root 1.23 break;
526    
527 root 1.6 sl << uint16 (i)
528 root 1.24 << uint32 (0) // checksum
529     << uint8 (ns->faceset);
530    
531     print_facename (sl, *d); sl << uint8 (0);
532 root 1.3 }
533 root 1.6
534 root 1.3 /* It would make more sense to catch this pre-emptively in the code above.
535     * however, if this really happens, we probably just want to cut down the
536     * size to less than 1000, since that is what we claim the protocol would
537     * support.
538     */
539 root 1.23 //TODO: taken care of above, should simply abort or make sure the above code is correct
540 root 1.9 if (sl.length () >= MAXSOCKBUF)
541 root 1.3 {
542 root 1.9 LOG (llevError, "send_image_send: buffer overrun, %d > %d\n", sl.length (), MAXSOCKBUF);
543 root 1.3 abort ();
544 elmex 1.1 }
545 root 1.6
546 root 1.11 ns->send_packet (sl);
547 elmex 1.1 }
548 root 1.6