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

# Content
1 /*
2 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
3 *
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 * 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 *
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, see <http://www.gnu.org/licenses/>.
20 *
21 * The authors can be reached via e-mail to <crossfire@schmorp.de>
22 */
23
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 #include "crc.h"
39
40 #define MAX_FACE_SETS 20 /**< Maximum number of image sets the program will handle */
41
42 /** Information about one image */
43 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 } FaceInfo;
49
50 /** Information about one face set */
51 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 } 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 int
71 is_valid_faceset (int fsn)
72 {
73 if (fsn >= 0 && fsn < MAX_FACE_SETS && facesets[fsn].prefix)
74 return TRUE;
75 return FALSE;
76 }
77
78 /**
79 * Frees all faceset information
80 */
81 void
82 free_socket_images (void)
83 {
84 int num, q;
85
86 for (num = 0; num < MAX_FACE_SETS; num++)
87 {
88 if (facesets[num].prefix)
89 {
90 for (q = 0; q < faces.size (); q++)
91 if (facesets[num].faces[q].data)
92 free (facesets[num].faces[q].data);
93
94 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 }
101 }
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 static int
117 get_face_fallback (int faceset, int imageno)
118 {
119 /* 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
134 if (facesets[faceset].faces[imageno].data)
135 return faceset;
136
137 return get_face_fallback (facesets[faceset].fallback, imageno);
138 }
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 static void
149 check_faceset_fallback (int faceset, int togo)
150 {
151 int fallback = facesets[faceset].fallback;
152
153 /* 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
163 togo--;
164 if (togo == 0)
165 {
166 LOG (llevError, "Infinite loop found in facesets. aborting.\n");
167 abort ();
168 }
169
170 check_faceset_fallback (fallback, togo);
171 }
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 void
181 SetFaceMode (char *buf, int len, client *ns)
182 {
183 int mask = (atoi (buf) & CF_FACE_CACHE), mode = (atoi (buf) & ~CF_FACE_CACHE);
184
185 if (mode == CF_FACE_NONE)
186 ns->facecache = 1;
187 else if (mode != CF_FACE_PNG)
188 ns->send_packet_printf ("drawinfo %d %s", NDI_RED, "Warning - send unsupported face mode. Will use Png");
189
190 if (mask)
191 ns->facecache = 1;
192 }
193
194 /**
195 * client requested an image. send it rate-limited
196 * before flushing.
197 */
198 void
199 AskFaceCmd (char *buf, int len, client *ns)
200 {
201 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 }
236
237 // how lame
238 static void print_facename (packet &sl, const facedata &d)
239 {
240 for (int i = 0; i < CHKSUM_SIZE; ++i)
241 sl.printf ("%02x", d.chksum [i]);
242 }
243
244 // 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 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 /**
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 void
272 client::send_face (faceidx facenum)
273 {
274 // 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 {
282 LOG (llevError, "client::send_face (%d) out of bounds??\n", facenum);
283 return;
284 }
285
286 if (faces_sent[facenum])
287 return;
288
289 faces_sent[facenum] = true;
290
291 // if for some reason we let a client without face caching connect,
292 // we better support that decision here and implement it.
293 if (!facecache)
294 return send_image (facenum);
295
296 if (fxix)
297 {
298 fxface.push_back (facenum);
299 return;
300 }
301
302 packet sl;
303
304 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 if (EMI_smooth)
316 {
317 faceinfo *f = face_info (facenum);
318
319 if (f->smooth)
320 {
321 send_face (f->smooth);
322
323 packet sl ("smooth");
324
325 sl << uint16 (facenum)
326 << uint16 (f->smooth);
327
328 send_packet (sl);
329 }
330 }
331 }
332
333 void client::flush_fx ()
334 {
335 while (!fxface.empty ())
336 {
337 packet fx ("fx");
338 packet sx ("sx");
339
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 fx << ber32 (facenum)
349 << data8 (d->chksum, CHKSUM_SIZE);
350
351 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 }
364 }
365 while (!fxface.empty ()
366 && fx.room () > ber32::size + CHKSUM_SIZE + 1
367 && sx.room () > ber32::size * 3);
368
369 send_packet (fx);
370 if (sx.length () > 3) send_packet (sx);
371 }
372 }
373
374 void
375 client::send_image (faceidx facenum)
376 {
377 // never send face 0. ever. it does not exist.
378 if (!facenum)
379 return;
380
381 const facedata *d = face_data (facenum, faceset);
382
383 faces_sent[facenum] = true;
384
385 if (!d)
386 {
387 LOG (llevError, "client::send_image (%d) out of bounds??\n", facenum);
388 return;
389 }
390
391 //TODO: check type here?
392
393 if (force_image_newmap)
394 force_newmap = true;
395
396 packet sl;
397
398 sl << (image2 ? "image2 " : "image ")
399 << uint32 (facenum);
400
401 if (image2)
402 sl << uint8 (0);
403
404 sl << uint32 (d->data.size ())
405 << data (d->data.data (), d->data.size ());
406
407 send_packet (sl);
408 }
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 if (anim_num < 0 || anim_num >= animations.size ())
443 {
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 }
461
462 send_packet (sl);
463
464 anims_sent[anim_num] = 1;
465 }
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 void
473 send_image_info (client *ns, char *params)
474 {
475 packet sl;
476
477 //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
480 sl << "0:base:standard:0:32x32:none:The old 32x32 faceset.\n";
481
482 ns->send_packet (sl);
483 }
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 void
495 send_image_sums (client *ns, char *params)
496 {
497 int start, stop;
498 char *cp;
499
500 packet sl;
501
502 start = atoi (params);
503 for (cp = params; *cp != '\0'; cp++)
504 if (*cp == ' ')
505 break;
506
507 stop = atoi (cp);
508 if (stop < start || *cp == '\0' || (stop - start) > 1000 || stop >= MAX_FACES)
509 {
510 sl.printf ("replyinfo image_sums %d %d", start, stop);
511 ns->send_packet (sl);
512 sl.reset ();
513 return;
514 }
515
516 sl.printf ("replyinfo image_sums %d %d ", start, stop);
517
518 for (int i = start; i <= stop && i < faces.size (); i++)
519 {
520 ns->faces_sent[i] = true;
521
522 const facedata *d = face_data (i, ns->faceset);
523
524 if (sl.room () < 2 + 4 + 1 + d->data.size () + 1)
525 break;
526
527 sl << uint16 (i)
528 << uint32 (0) // checksum
529 << uint8 (ns->faceset);
530
531 print_facename (sl, *d); sl << uint8 (0);
532 }
533
534 /* 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 //TODO: taken care of above, should simply abort or make sure the above code is correct
540 if (sl.length () >= MAXSOCKBUF)
541 {
542 LOG (llevError, "send_image_send: buffer overrun, %d > %d\n", sl.length (), MAXSOCKBUF);
543 abort ();
544 }
545
546 ns->send_packet (sl);
547 }
548