ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/socket/image.C
Revision: 1.57
Committed: Fri Dec 26 10:44:17 2008 UTC (15 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.56: +0 -15 lines
Log Message:
extdnedMapInfos removal, mapextended removal

File Contents

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