ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/image.C
Revision: 1.50
Committed: Tue Jul 24 04:55:34 2007 UTC (16 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.49: +29 -150 lines
Log Message:
welcome to fxix protocol version 3, with uniform handling over all resources

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_IMAGE_SIZE 10000
41    
42     /**
43     * Client tells us what type of faces it wants. Also sets
44     * the caching attribute.
45     *
46     */
47 root 1.3 void
48 root 1.13 SetFaceMode (char *buf, int len, client *ns)
49 elmex 1.1 {
50 root 1.3 int mask = (atoi (buf) & CF_FACE_CACHE), mode = (atoi (buf) & ~CF_FACE_CACHE);
51 elmex 1.1
52 root 1.3 if (mode == CF_FACE_NONE)
53 root 1.7 ns->facecache = 1;
54 root 1.3 else if (mode != CF_FACE_PNG)
55 root 1.14 ns->send_packet_printf ("drawinfo %d %s", NDI_RED, "Warning - send unsupported face mode. Will use Png");
56 root 1.7
57 root 1.3 if (mask)
58 root 1.7 ns->facecache = 1;
59 elmex 1.1 }
60    
61     /**
62 root 1.43 * client requested an image. send it rate-limited
63     * before flushing.
64 elmex 1.1 */
65 root 1.3 void
66 root 1.43 AskFaceCmd (char *buf, int len, client *ns)
67 elmex 1.1 {
68 root 1.43 int idx = 0, pri = 0;
69    
70     sscanf (buf, "%d %d", &idx, &pri);
71    
72     const facedata *d = face_data (idx, ns->faceset);
73    
74     if (!d)
75     return; // doh
76    
77     client::ixsend ix;
78    
79     ix.pri = pri;
80     ix.idx = idx;
81     ix.ofs = d->data.size ();
82    
83 root 1.46 auto (pos, ns->ixface.end ());
84    
85     if (ns->fxix < 2)
86     {
87     // gcfclient does not support prioritising, older cfplus versions
88     // do not support interleaved transfers.
89     if (!ns->ixface.empty ())
90     pos = ns->ixface.end () - 1;
91     }
92     else
93     {
94     // the by far most common case will be to insert
95     // near the end, so little looping.
96     while (pos != ns->ixface.begin ())
97     {
98     --pos;
99    
100     // sort within 2k bins, to slightly prefer smaller images
101     if (pri > pos->pri || (pri == pos->pri && (ix.ofs >> 11) <= (pos->ofs >> 11)))
102     {
103     ++pos;
104     break;
105     }
106     }
107     }
108    
109     ns->ixface.insert (pos, ix);
110 root 1.45
111     #if 0
112 root 1.46 for (auto (i, ns->ixface.begin ()); i != ns->ixface.end (); ++i)
113     fprintf (stderr, "<%d,%d> ", i->pri, i->ofs);
114     fprintf (stderr, "\n");
115 root 1.45 #endif
116 root 1.43 }
117    
118     /**
119     * Tells client the picture it has to use
120     * to smooth a picture number given as argument.
121     */
122     void
123     AskSmooth (char *buf, int len, client *ns)
124     {
125 root 1.50 ns->send_face (atoi (buf), -100);
126 root 1.43 ns->flush_fx ();
127 elmex 1.1 }
128    
129 root 1.24 // how lame
130     static void print_facename (packet &sl, const facedata &d)
131     {
132 root 1.25 for (int i = 0; i < CHKSUM_SIZE; ++i)
133     sl.printf ("%02x", d.chksum [i]);
134 root 1.24 }
135    
136 root 1.32 // gcfclient uses the server-provided checksum for comparison, but always
137     // writes a broken checksum to its cache file, so we have to provide
138     // gcfclient with the same broken (and useless) checksum just to have it
139     // cache the image despite its bugs.
140 root 1.26 static uint32 gcfclient_checksum (const facedata *d)
141     {
142     uint32 csum = 0;
143    
144     for (std::string::const_iterator i = d->data.begin ();
145     i != d->data.end ();
146     ++i)
147     {
148     csum = rotate_right (csum);
149     csum += *(uint8 *)&*i;
150     }
151    
152     return csum;
153     }
154    
155 elmex 1.1 /**
156     * Sends a face to a client if they are in pixmap mode
157     * nothing gets sent in bitmap mode.
158     * If nocache is true (nonzero), ignore the cache setting from the client -
159     * this is needed for the askface, in which we really do want to send the
160     * face (and askface is the only place that should be setting it). Otherwise,
161     * we look at the facecache, and if set, send the image name.
162     */
163 root 1.3 void
164 root 1.50 client::send_face (faceidx facenum, int pri)
165 elmex 1.1 {
166 root 1.28 // never send face 0. ever. it does not exist.
167     if (!facenum)
168     return;
169    
170 root 1.50 faceinfo *f = face_info (facenum);
171 root 1.28
172 root 1.50 if (!f)
173 root 1.3 {
174 root 1.28 LOG (llevError, "client::send_face (%d) out of bounds??\n", facenum);
175 root 1.3 return;
176     }
177    
178 root 1.50 // refuse to send non-image faces
179     if (!fx_want [f->type])
180     return;
181 root 1.49
182 root 1.50 if (faces_sent [facenum])
183 root 1.48 return;
184    
185 root 1.50 faces_sent[facenum] = true;
186 root 1.32
187 root 1.38 // if for some reason we let a client without face caching connect,
188     // we better support that decision here and implement it.
189 root 1.33 if (!facecache)
190 root 1.38 return send_image (facenum);
191 root 1.33
192 root 1.39 if (fxix)
193     {
194     fxface.push_back (facenum);
195     return;
196     }
197    
198 root 1.50 const facedata *d = f->data (faceset);
199    
200 root 1.8 packet sl;
201 root 1.3
202 root 1.32 if (force_face0)
203     sl << "face " << uint16 (facenum);
204     else if (image2)
205     sl << "face2 " << uint16 (facenum) << uint8 (0) << uint32 (force_bad_checksum ? gcfclient_checksum (d) : 0);
206     else
207     sl << "face1 " << uint16 (facenum) << uint32 (force_bad_checksum ? gcfclient_checksum (d) : 0);
208    
209     // how lame
210     print_facename (sl, *d);
211     send_packet (sl);
212    
213 root 1.40 if (EMI_smooth)
214 root 1.3 {
215 root 1.40 if (f->smooth)
216     {
217     send_face (f->smooth);
218    
219     packet sl ("smooth");
220 root 1.30
221 root 1.40 sl << uint16 (facenum)
222     << uint16 (f->smooth);
223 root 1.31
224 root 1.40 send_packet (sl);
225     }
226 root 1.32 }
227     }
228    
229 root 1.39 void client::flush_fx ()
230     {
231     while (!fxface.empty ())
232     {
233 root 1.40 packet fx ("fx");
234     packet sx ("sx");
235 root 1.50 int type = 0;
236 root 1.39
237     do
238     {
239     faceidx facenum = fxface.back (); fxface.pop_back ();
240    
241 root 1.50 if (const faceinfo *f = face_info (facenum))
242     {
243     if (f->type != type)
244     {
245     type = f->type;
246    
247     fx << ber32 (0)
248     << uint8 (1) << uint8 (type);
249     }
250    
251     const facedata *d = f->data (faceset);
252 root 1.39
253 root 1.40 fx << ber32 (facenum)
254 root 1.39 << data8 (d->chksum, CHKSUM_SIZE);
255    
256 root 1.40 if (smoothing)
257     {
258     faceinfo *f = face_info (facenum);
259    
260     if (f->smooth)
261     {
262 root 1.50 send_face (f->smooth, -110);
263    
264 root 1.40 sx << ber32 (facenum)
265     << ber32 (f->smooth)
266     << ber32 (f->smoothlevel);
267     }
268     }
269 root 1.39 }
270     }
271 root 1.40 while (!fxface.empty ()
272 root 1.50 && fx.room () > ber32::size + CHKSUM_SIZE + 1 + 3 /* type switch */
273 root 1.40 && sx.room () > ber32::size * 3);
274 root 1.39
275 root 1.40 send_packet (fx);
276     if (sx.length () > 3) send_packet (sx);
277 root 1.39 }
278     }
279    
280 root 1.32 void
281     client::send_image (faceidx facenum)
282     {
283     // never send face 0. ever. it does not exist.
284     if (!facenum)
285     return;
286 root 1.31
287 root 1.32 const facedata *d = face_data (facenum, faceset);
288 root 1.30
289 root 1.43 faces_sent[facenum] = true;
290    
291 root 1.32 if (!d)
292     {
293     LOG (llevError, "client::send_image (%d) out of bounds??\n", facenum);
294     return;
295     }
296 root 1.43
297     //TODO: check type here?
298 root 1.34
299 root 1.36 if (force_image_newmap)
300     force_newmap = true;
301    
302 root 1.32 packet sl;
303 root 1.30
304 root 1.32 sl << (image2 ? "image2 " : "image ")
305     << uint32 (facenum);
306 root 1.6
307 root 1.32 if (image2)
308     sl << uint8 (0);
309 root 1.6
310 root 1.32 sl << uint32 (d->data.size ())
311     << data (d->data.data (), d->data.size ());
312 root 1.31
313 root 1.32 send_packet (sl);
314 root 1.28 }
315    
316     // send all faces of this object to the client
317     // this uses more bandwidth initially, but makes
318     // animations look much smoother, and every client
319     // is supposed to do client-side caching anyways.
320     void
321     client::send_faces (object *ob)
322     {
323 root 1.50 send_face (ob->face, 10);
324 root 1.28
325     if (ob->animation_id)
326     {
327     animation &anim = animations [ob->animation_id];
328    
329     for (int i = 0; i < anim.num_animations; i++)
330 root 1.50 send_face (anim.faces [i], -10);
331 root 1.28 }
332     }
333    
334     /**
335     * Need to send an animation sequence to the client.
336     * We will send appropriate face commands to the client if we haven't
337     * sent them the face yet (this can become quite costly in terms of
338     * how much we are sending - on the other hand, this should only happen
339     * when the player logs in and picks stuff up.
340     */
341     void
342     client::send_animation (short anim_num)
343     {
344     /* Do some checking on the anim_num we got. Note that the animations
345     * are added in contigous order, so if the number is in the valid
346     * range, it must be a valid animation.
347     */
348 root 1.41 if (anim_num < 0 || anim_num >= animations.size ())
349 root 1.28 {
350     LOG (llevError, "esrv_send_anim (%d) out of bounds??\n", anim_num);
351     return;
352     }
353    
354     packet sl ("anim");
355    
356     sl << uint16 (anim_num)
357     << uint16 (0); /* flags - not used right now */
358    
359     /* Build up the list of faces. Also, send any information (ie, the
360     * the face itself) down to the client.
361     */
362     for (int i = 0; i < animations[anim_num].num_animations; i++)
363     {
364 root 1.50 send_face (animations[anim_num].faces[i], -20);
365 root 1.28 sl << uint16 (animations[anim_num].faces[i]); /* flags - not used right now */
366 elmex 1.1 }
367 root 1.6
368 root 1.28 send_packet (sl);
369    
370     anims_sent[anim_num] = 1;
371 elmex 1.1 }
372    
373     /**
374     * Sends the number of images, checksum of the face file,
375     * and the image_info file information. See the doc/Developers/protocol
376     * if you want further detail.
377     */
378 root 1.3 void
379 root 1.15 send_image_info (client *ns, char *params)
380 elmex 1.1 {
381 root 1.8 packet sl;
382 elmex 1.1
383 root 1.24 //TODO: second parameter is a checksum, but it makes no sense in this current framework
384     sl.printf ("replyinfo image_info\n%d\n%u\n", MAX_FACES, 0);
385 root 1.6
386 root 1.24 sl << "0:base:standard:0:32x32:none:The old 32x32 faceset.\n";
387 elmex 1.1
388 root 1.11 ns->send_packet (sl);
389 elmex 1.1 }
390    
391     /**
392     * Sends requested face information.
393     * \param ns socket to send to
394     * \param params contains first and last index of face
395     *
396     * For each image in [start..stop] sends
397     * - checksum
398     * - name
399     */
400 root 1.3 void
401 root 1.15 send_image_sums (client *ns, char *params)
402 elmex 1.1 {
403 root 1.3 int start, stop;
404 pippijn 1.22 char *cp;
405 root 1.3
406 root 1.8 packet sl;
407 root 1.3
408     start = atoi (params);
409     for (cp = params; *cp != '\0'; cp++)
410     if (*cp == ' ')
411     break;
412    
413     stop = atoi (cp);
414 root 1.24 if (stop < start || *cp == '\0' || (stop - start) > 1000 || stop >= MAX_FACES)
415 root 1.3 {
416 root 1.7 sl.printf ("replyinfo image_sums %d %d", start, stop);
417     ns->send_packet (sl);
418     sl.reset ();
419 root 1.3 return;
420     }
421    
422 root 1.6 sl.printf ("replyinfo image_sums %d %d ", start, stop);
423 root 1.3
424 root 1.24 for (int i = start; i <= stop && i < faces.size (); i++)
425 root 1.3 {
426 root 1.30 ns->faces_sent[i] = true;
427 root 1.3
428 root 1.24 const facedata *d = face_data (i, ns->faceset);
429 root 1.6
430 root 1.24 if (sl.room () < 2 + 4 + 1 + d->data.size () + 1)
431 root 1.23 break;
432    
433 root 1.6 sl << uint16 (i)
434 root 1.24 << uint32 (0) // checksum
435     << uint8 (ns->faceset);
436    
437     print_facename (sl, *d); sl << uint8 (0);
438 root 1.3 }
439 root 1.6
440 root 1.3 /* It would make more sense to catch this pre-emptively in the code above.
441     * however, if this really happens, we probably just want to cut down the
442     * size to less than 1000, since that is what we claim the protocol would
443     * support.
444     */
445 root 1.23 //TODO: taken care of above, should simply abort or make sure the above code is correct
446 root 1.9 if (sl.length () >= MAXSOCKBUF)
447 root 1.3 {
448 root 1.9 LOG (llevError, "send_image_send: buffer overrun, %d > %d\n", sl.length (), MAXSOCKBUF);
449 root 1.3 abort ();
450 elmex 1.1 }
451 root 1.6
452 root 1.11 ns->send_packet (sl);
453 elmex 1.1 }
454 root 1.6