ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/image.C
Revision: 1.31
Committed: Wed Mar 14 04:12:29 2007 UTC (17 years, 2 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.30: +13 -12 lines
Log Message:
- rewrote more face handling code
- automatically send smooth faces, as the client will need them anyways
  and it makes little sense to wait for the client to axk for it. of course,
  gcfclient suffers from weird ordering problems again.
- UP_OBJ_FACE was often abused in situations where other things changed,
  updated lots of spaces, probably more to be done.
- update_smooth became so small that inlining it actually clarified
  the code. similar for update_space, which is not inlined for other reasons.
- faces were not initialised properly
- add versioncheck for face data
- rewrite invisibility handling a bit: god finger etc. now makes you blink,
  blinking routine has changed to be less annoying and more useful while
  still indicating invisibleness.

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 < faces.size (); 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 * Client tells us what type of faces it wants. Also sets
178 * the caching attribute.
179 *
180 */
181 void
182 SetFaceMode (char *buf, int len, client *ns)
183 {
184 int mask = (atoi (buf) & CF_FACE_CACHE), mode = (atoi (buf) & ~CF_FACE_CACHE);
185
186 if (mode == CF_FACE_NONE)
187 ns->facecache = 1;
188 else if (mode != CF_FACE_PNG)
189 ns->send_packet_printf ("drawinfo %d %s", NDI_RED, "Warning - send unsupported face mode. Will use Png");
190
191 if (mask)
192 ns->facecache = 1;
193 }
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 void
201 SendFaceCmd (char *buf, int len, client *ns)
202 {
203 ns->send_face (atoi (buf), 1);
204 }
205
206 // how lame
207 static void print_facename (packet &sl, const facedata &d)
208 {
209 for (int i = 0; i < CHKSUM_SIZE; ++i)
210 sl.printf ("%02x", d.chksum [i]);
211 }
212
213 // 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 /**
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 void
241 client::send_face (faceidx facenum, bool forced)
242 {
243 // 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 {
251 LOG (llevError, "client::send_face (%d) out of bounds??\n", facenum);
252 return;
253 }
254
255 packet sl;
256
257 if (facecache && !forced)
258 {
259 if (faces_sent[facenum])
260 return;
261
262 faces_sent[facenum] = true;
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 else
269 sl << "face1 " << uint16 (facenum) << uint32 (force_bad_checksum ? gcfclient_checksum (d) : 0);
270
271 // how lame
272 print_facename (sl, *d);
273 send_packet (sl);
274
275 faceinfo *f = face_info (facenum);
276 if (f->smooth && EMI_smooth)
277 {
278 send_face (f->smooth);
279
280 packet sl ("smooth");
281
282 sl << uint16 (facenum)
283 << uint16 (f->smooth);
284
285 send_packet (sl);
286 }
287 }
288 else
289 {
290 sl << (image2 ? "image2 " : "image ")
291 << uint32 (facenum);
292
293 if (image2)
294 sl << uint8 (0);
295
296 sl << uint32 (d->data.size ())
297 << data (d->data.data (), d->data.size ());
298
299 send_packet (sl);
300 }
301 }
302
303 // send all faces of this object to the client
304 // this uses more bandwidth initially, but makes
305 // animations look much smoother, and every client
306 // is supposed to do client-side caching anyways.
307 void
308 client::send_faces (object *ob)
309 {
310 send_face (ob->face);
311
312 if (ob->animation_id)
313 {
314 animation &anim = animations [ob->animation_id];
315
316 for (int i = 0; i < anim.num_animations; i++)
317 send_face (anim.faces [i]);
318 }
319 }
320
321 /**
322 * Need to send an animation sequence to the client.
323 * We will send appropriate face commands to the client if we haven't
324 * sent them the face yet (this can become quite costly in terms of
325 * how much we are sending - on the other hand, this should only happen
326 * when the player logs in and picks stuff up.
327 */
328 void
329 client::send_animation (short anim_num)
330 {
331 /* Do some checking on the anim_num we got. Note that the animations
332 * are added in contigous order, so if the number is in the valid
333 * range, it must be a valid animation.
334 */
335 if (anim_num < 0 || anim_num > num_animations)
336 {
337 LOG (llevError, "esrv_send_anim (%d) out of bounds??\n", anim_num);
338 return;
339 }
340
341 packet sl ("anim");
342
343 sl << uint16 (anim_num)
344 << uint16 (0); /* flags - not used right now */
345
346 /* Build up the list of faces. Also, send any information (ie, the
347 * the face itself) down to the client.
348 */
349 for (int i = 0; i < animations[anim_num].num_animations; i++)
350 {
351 send_face (animations[anim_num].faces[i]);
352 sl << uint16 (animations[anim_num].faces[i]); /* flags - not used right now */
353 }
354
355 send_packet (sl);
356
357 anims_sent[anim_num] = 1;
358 }
359
360 /**
361 * Sends the number of images, checksum of the face file,
362 * and the image_info file information. See the doc/Developers/protocol
363 * if you want further detail.
364 */
365 void
366 send_image_info (client *ns, char *params)
367 {
368 packet sl;
369
370 //TODO: second parameter is a checksum, but it makes no sense in this current framework
371 sl.printf ("replyinfo image_info\n%d\n%u\n", MAX_FACES, 0);
372
373 sl << "0:base:standard:0:32x32:none:The old 32x32 faceset.\n";
374
375 ns->send_packet (sl);
376 }
377
378 /**
379 * Sends requested face information.
380 * \param ns socket to send to
381 * \param params contains first and last index of face
382 *
383 * For each image in [start..stop] sends
384 * - checksum
385 * - name
386 */
387 void
388 send_image_sums (client *ns, char *params)
389 {
390 int start, stop;
391 char *cp;
392
393 packet sl;
394
395 start = atoi (params);
396 for (cp = params; *cp != '\0'; cp++)
397 if (*cp == ' ')
398 break;
399
400 stop = atoi (cp);
401 if (stop < start || *cp == '\0' || (stop - start) > 1000 || stop >= MAX_FACES)
402 {
403 sl.printf ("replyinfo image_sums %d %d", start, stop);
404 ns->send_packet (sl);
405 sl.reset ();
406 return;
407 }
408
409 sl.printf ("replyinfo image_sums %d %d ", start, stop);
410
411 for (int i = start; i <= stop && i < faces.size (); i++)
412 {
413 ns->faces_sent[i] = true;
414
415 const facedata *d = face_data (i, ns->faceset);
416
417 if (sl.room () < 2 + 4 + 1 + d->data.size () + 1)
418 break;
419
420 sl << uint16 (i)
421 << uint32 (0) // checksum
422 << uint8 (ns->faceset);
423
424 print_facename (sl, *d); sl << uint8 (0);
425 }
426
427 /* It would make more sense to catch this pre-emptively in the code above.
428 * however, if this really happens, we probably just want to cut down the
429 * size to less than 1000, since that is what we claim the protocol would
430 * support.
431 */
432 //TODO: taken care of above, should simply abort or make sure the above code is correct
433 if (sl.length () >= MAXSOCKBUF)
434 {
435 LOG (llevError, "send_image_send: buffer overrun, %d > %d\n", sl.length (), MAXSOCKBUF);
436 abort ();
437 }
438
439 ns->send_packet (sl);
440 }
441