--- deliantra/server/socket/image.C 2007/03/14 00:07:26 1.29 +++ deliantra/server/socket/image.C 2007/07/01 05:00:20 1.44 @@ -1,25 +1,24 @@ /* - * CrossFire, A Multiplayer game - * - * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team - * Copyright (C) 2001 Mark Wedel - * Copyright (C) 1992 Frank Tore Johansen - * - * This program is free software; you can redistribute it and/or modify + * This file is part of Crossfire TRT, the Roguelike Realtime MORPG. + * + * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team + * Copyright (©) 2001,2007 Mark Wedel + * Copyright (©) 1992,2007 Frank Tore Johansen + * + * Crossfire TRT is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * The author can be reached via e-mail to + * along with this program. If not, see . + * + * The authors can be reached via e-mail to */ /** \file @@ -193,14 +192,46 @@ } /** - * Client has requested pixmap that it somehow missed getting. - * This will be called often if the client is - * caching images. + * client requested an image. send it rate-limited + * before flushing. */ void -SendFaceCmd (char *buf, int len, client *ns) +AskFaceCmd (char *buf, int len, client *ns) { - ns->send_face (atoi (buf), 1); + int idx = 0, pri = 0; + + sscanf (buf, "%d %d", &idx, &pri); + + const facedata *d = face_data (idx, ns->faceset); + + if (!d) + return; // doh + + client::ixsend ix; + + ix.pri = pri; + ix.idx = idx; + ix.ofs = d->data.size (); + + // the by far most common case will be to insert + // right at the end, so no looping. + auto (i, ns->ixface.end ()); + for (; i != ns->ixface.begin (); ) + if (pri >= (--i)->pri) + break; + + ns->ixface.insert (i, ix); +} + +/** + * Tells client the picture it has to use + * to smooth a picture number given as argument. + */ +void +AskSmooth (char *buf, int len, client *ns) +{ + ns->send_face (atoi (buf)); + ns->flush_fx (); } // how lame @@ -210,10 +241,10 @@ sl.printf ("%02x", d.chksum [i]); } -// gcfclient uses the server-provided checksum for comparison, -// but always wrotes a broken checksum to its cache file, so we -// have to provide gcfclient with a useless checksum just to -// have to cache the image despite its bugs. +// 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; @@ -238,7 +269,7 @@ * we look at the facecache, and if set, send the image name. */ void -client::send_face (faceidx facenum, bool forced) +client::send_face (faceidx facenum) { // never send face 0. ever. it does not exist. if (!facenum) @@ -252,97 +283,148 @@ return; } - packet sl; - - if (facecache && !forced) - { - if (faces_sent[facenum] & NS_FACESENT_FACE) - return; + if (faces_sent[facenum]) + return; - faces_sent[facenum] |= NS_FACESENT_FACE; + faces_sent[facenum] = true; - 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); + // 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); - // how lame - print_facename (sl, *d); + if (fxix) + { + fxface.push_back (facenum); + return; } + + packet sl; + + 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 << (image2 ? "image2 " : "image ") - << uint32 (facenum); + faceinfo *f = face_info (facenum); - if (image2) - sl << uint8 (0); + if (f->smooth) + { + send_face (f->smooth); - sl << uint32 (d->data.size ()) - << data (d->data.data (), d->data.size ()); - } + packet sl ("smooth"); - send_packet (sl); + sl << uint16 (facenum) + << uint16 (f->smooth); + + 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) +void client::flush_fx () { - send_face (ob->face); - - if (ob->animation_id) + while (!fxface.empty ()) { - animation &anim = animations [ob->animation_id]; + packet fx ("fx"); + packet sx ("sx"); - for (int i = 0; i < anim.num_animations; i++) - send_face (anim.faces [i]); + 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); + + send_packet (fx); + if (sx.length () > 3) send_packet (sx); } } -/** - * A lot like the old AskSmooth (in fact, now called by AskSmooth). - * Basically, it makes no sense to wait for the client to request a - * a piece of data from us that we know the client wants. So - * if we know the client wants it, might as well push it to the - * client. - */ void -client::send_smooth (faceidx face) +client::send_image (faceidx facenum) { - faceinfo *f = face_info (face); - - if (!f) + // never send face 0. ever. it does not exist. + if (!facenum) return; - if (faces_sent[face] & NS_FACESENT_SMOOTH) - return; + const facedata *d = face_data (facenum, faceset); - faces_sent[face] |= NS_FACESENT_SMOOTH; + faces_sent[facenum] = true; - /* If we can't find a face, return and set it so we won't try to send this - * again. - */ - if (!f->smooth) + if (!d) { - LOG (llevError, "could not findsmooth for %d.\n", face); + LOG (llevError, "client::send_image (%d) out of bounds??\n", facenum); return; } + + //TODO: check type here? - send_face (f->smooth); + if (force_image_newmap) + force_newmap = true; - packet sl ("smooth"); + packet sl; + + sl << (image2 ? "image2 " : "image ") + << uint32 (facenum); + + if (image2) + sl << uint8 (0); - sl << uint16 (face) - << uint16 (f->smooth); + 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 @@ -357,7 +439,7 @@ * 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 > num_animations) + if (anim_num < 0 || anim_num >= animations.size ()) { LOG (llevError, "esrv_send_anim (%d) out of bounds??\n", anim_num); return; @@ -435,7 +517,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);