--- deliantra/server/socket/image.C 2007/03/11 02:12:45 1.24 +++ deliantra/server/socket/image.C 2007/04/12 14:18:06 1.41 @@ -200,21 +200,33 @@ void SendFaceCmd (char *buf, int len, client *ns) { - uint16 facenum = atoi (buf); - - if (facenum != 0) - esrv_send_face (ns, facenum, 1); + ns->send_image (atoi (buf)); } // how lame static void print_facename (packet &sl, const facedata &d) { - sl.printf ("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" - "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - d.chksum [ 0], d.chksum [ 1], d.chksum [ 2], d.chksum [ 3], - d.chksum [ 4], d.chksum [ 5], d.chksum [ 6], d.chksum [ 7], - d.chksum [ 8], d.chksum [ 9], d.chksum [10], d.chksum [11], - d.chksum [12], d.chksum [13], d.chksum [14], d.chksum [15]); + for (int i = 0; i < CHKSUM_SIZE; ++i) + sl.printf ("%02x", d.chksum [i]); +} + +// gcfclient uses the server-provided checksum for comparison, but always +// writes a broken checksum to its cache file, so we have to provide +// gcfclient with the same broken (and useless) checksum just to have it +// cache the image despite its bugs. +static uint32 gcfclient_checksum (const facedata *d) +{ + uint32 csum = 0; + + for (std::string::const_iterator i = d->data.begin (); + i != d->data.end (); + ++i) + { + csum = rotate_right (csum); + csum += *(uint8 *)&*i; + } + + return csum; } /** @@ -226,48 +238,197 @@ * we look at the facecache, and if set, send the image name. */ void -esrv_send_face (client *ns, short face_num, int nocache) +client::send_face (faceidx facenum) { - if (face_num <= 0 || face_num >= faces.size ()) + // never send face 0. ever. it does not exist. + if (!facenum) + return; + + const facedata *d = face_data (facenum, faceset); + + if (!d) { - LOG (llevError, "esrv_send_face (%d) out of bounds??\n", face_num); + LOG (llevError, "client::send_face (%d) out of bounds??\n", facenum); return; } - const facedata *d = face_data (face_num, ns->faceset); + if (faces_sent[facenum]) + return; + + faces_sent[facenum] = true; + + // if for some reason we let a client without face caching connect, + // we better support that decision here and implement it. + if (!facecache) + return send_image (facenum); + + if (fxix) + { + fxface.push_back (facenum); + return; + } packet sl; - if (ns->facecache && !nocache) + if (force_face0) + sl << "face " << uint16 (facenum); + else if (image2) + sl << "face2 " << uint16 (facenum) << uint8 (0) << uint32 (force_bad_checksum ? gcfclient_checksum (d) : 0); + else + sl << "face1 " << uint16 (facenum) << uint32 (force_bad_checksum ? gcfclient_checksum (d) : 0); + + // how lame + print_facename (sl, *d); + send_packet (sl); + + if (EMI_smooth) { - sl << (ns->image2 ? "face2 " : "face1 ") - << uint16 (face_num); + faceinfo *f = face_info (facenum); - if (ns->image2) - sl << uint8 (0); + if (f->smooth) + { + send_face (f->smooth); - sl << uint32 (0); + packet sl ("smooth"); - // how lame - print_facename (sl, *d); + sl << uint16 (facenum) + << uint16 (f->smooth); - ns->send_packet (sl); + send_packet (sl); + } } - else +} + +void client::flush_fx () +{ + while (!fxface.empty ()) { - sl << (ns->image2 ? "image2 " : "image ") - << uint32 (face_num); + packet fx ("fx"); + packet sx ("sx"); + + do + { + faceidx facenum = fxface.back (); fxface.pop_back (); + + const facedata *d = face_data (facenum, faceset); + + if (d) + { + fx << ber32 (facenum) + << data8 (d->chksum, CHKSUM_SIZE); + + if (smoothing) + { + faceinfo *f = face_info (facenum); + + if (f->smooth) + { + send_face (f->smooth); + sx << ber32 (facenum) + << ber32 (f->smooth) + << ber32 (f->smoothlevel); + } + } + } + } + while (!fxface.empty () + && fx.room () > ber32::size + CHKSUM_SIZE + 1 + && sx.room () > ber32::size * 3); - if (ns->image2) - sl << uint8 (0); + send_packet (fx); + if (sx.length () > 3) send_packet (sx); + } +} + +void +client::send_image (faceidx facenum) +{ + // never send face 0. ever. it does not exist. + if (!facenum) + return; - sl << uint32 (d->data.size ()) - << data (d->data.data (), d->data.size ()); + const facedata *d = face_data (facenum, faceset); - ns->send_packet (sl); + if (!d) + { + LOG (llevError, "client::send_image (%d) out of bounds??\n", facenum); + return; } - ns->faces_sent[face_num] |= NS_FACESENT_FACE; + faces_sent[facenum] = true; + + if (force_image_newmap) + force_newmap = true; + + packet sl; + + sl << (image2 ? "image2 " : "image ") + << uint32 (facenum); + + if (image2) + sl << uint8 (0); + + sl << uint32 (d->data.size ()) + << data (d->data.data (), d->data.size ()); + + send_packet (sl); +} + +// send all faces of this object to the client +// this uses more bandwidth initially, but makes +// animations look much smoother, and every client +// is supposed to do client-side caching anyways. +void +client::send_faces (object *ob) +{ + send_face (ob->face); + + if (ob->animation_id) + { + animation &anim = animations [ob->animation_id]; + + for (int i = 0; i < anim.num_animations; i++) + send_face (anim.faces [i]); + } +} + +/** + * Need to send an animation sequence to the client. + * We will send appropriate face commands to the client if we haven't + * sent them the face yet (this can become quite costly in terms of + * how much we are sending - on the other hand, this should only happen + * when the player logs in and picks stuff up. + */ +void +client::send_animation (short anim_num) +{ + /* Do some checking on the anim_num we got. Note that the animations + * are added in contigous order, so if the number is in the valid + * range, it must be a valid animation. + */ + if (anim_num < 0 || anim_num >= animations.size ()) + { + LOG (llevError, "esrv_send_anim (%d) out of bounds??\n", anim_num); + return; + } + + packet sl ("anim"); + + sl << uint16 (anim_num) + << uint16 (0); /* flags - not used right now */ + + /* Build up the list of faces. Also, send any information (ie, the + * the face itself) down to the client. + */ + for (int i = 0; i < animations[anim_num].num_animations; i++) + { + send_face (animations[anim_num].faces[i]); + sl << uint16 (animations[anim_num].faces[i]); /* flags - not used right now */ + } + + send_packet (sl); + + anims_sent[anim_num] = 1; } /** @@ -275,7 +436,6 @@ * and the image_info file information. See the doc/Developers/protocol * if you want further detail. */ - void send_image_info (client *ns, char *params) { @@ -324,7 +484,7 @@ for (int i = start; i <= stop && i < faces.size (); i++) { - ns->faces_sent[i] |= NS_FACESENT_FACE; + ns->faces_sent[i] = true; const facedata *d = face_data (i, ns->faceset);