--- deliantra/server/socket/image.C 2007/05/28 21:22:26 1.42
+++ deliantra/server/socket/image.C 2007/11/08 19:43:29 1.55
@@ -1,25 +1,24 @@
/*
- * This file is part of Crossfire TRT, the Multiplayer Online Role Playing Game.
+ * This file is part of Deliantra, the Roguelike Realtime MMORPG.
*
- * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
+ * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Deliantra 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 (at your option)
- * any later version.
+ * Deliantra 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 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 GNU General Public License
- * for more details.
+ * 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
+ * GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with Crossfire TRT; if not, write to the Free Software Foundation, Inc. 51
- * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
*
- * The authors can be reached via e-mail to
+ * The authors can be reached via e-mail to
*/
/** \file
@@ -38,169 +37,95 @@
#include "crc.h"
-#define MAX_FACE_SETS 20 /**< Maximum number of image sets the program will handle */
-
-/** Information about one image */
-typedef struct FaceInfo
-{
- uint8 *data; /**< image data */
- uint16 datalen; /**< length of the xpm data */
- uint32 checksum; /**< Checksum of face data */
-} FaceInfo;
-
-/** Information about one face set */
-typedef struct
-{
- char *prefix; /**< */
- char *fullname;
-
- uint8 fallback; /**< faceset to use when an image is not found in this faceset */
- char *size;
- char *extension;
- char *comment;
-
- FaceInfo *faces; /**< images in this faceset */
-} FaceSets;
-
-static FaceSets facesets[MAX_FACE_SETS]; /**< All facesets */
+#define MAX_IMAGE_SIZE 10000
/**
- * Checks specified faceset is valid
- * \param fsn faceset number
+ * Client tells us what type of faces it wants. Also sets
+ * the caching attribute.
+ *
*/
-int
-is_valid_faceset (int fsn)
+void
+SetFaceMode (char *buf, int len, client *ns)
{
- if (fsn >= 0 && fsn < MAX_FACE_SETS && facesets[fsn].prefix)
- return TRUE;
- return FALSE;
+ int mask = (atoi (buf) & CF_FACE_CACHE), mode = (atoi (buf) & ~CF_FACE_CACHE);
+
+ if (mode == CF_FACE_NONE)
+ ns->facecache = 1;
+ else if (mode != CF_FACE_PNG)
+ ns->send_packet_printf ("drawinfo %d %s", NDI_RED, "Warning - send unsupported face mode. Will use Png");
+
+ if (mask)
+ ns->facecache = 1;
}
/**
- * Frees all faceset information
+ * client requested an image. send it rate-limited
+ * before flushing.
*/
void
-free_socket_images (void)
+AskFaceCmd (char *buf, int len, client *ns)
{
- int num, q;
+ int idx = 0, pri = 0;
- for (num = 0; num < MAX_FACE_SETS; num++)
- {
- if (facesets[num].prefix)
- {
- for (q = 0; q < faces.size (); q++)
- if (facesets[num].faces[q].data)
- free (facesets[num].faces[q].data);
-
- free (facesets[num].prefix);
- free (facesets[num].fullname);
- free (facesets[num].size);
- free (facesets[num].extension);
- free (facesets[num].comment);
- free (facesets[num].faces);
- }
- }
-}
+ sscanf (buf, "%d %d", &idx, &pri);
-/**
- * This returns the set we will actually use when sending
- * a face. This is used because the image files may be sparse.
- * This function is recursive. imageno is the face number we are
- * trying to send
- *
- * If face is not found in specified faceset, tries with 'fallback' faceset.
- *
- * \param faceset faceset to check
- * \param imageno image number
- *
- */
-static int
-get_face_fallback (int faceset, int imageno)
-{
- /* faceset 0 is supposed to have every image, so just return. Doing
- * so also prevents infinite loops in the case if it not having
- * the face, but in that case, we are likely to crash when we try
- * to access the data, but that is probably preferable to an infinite
- * loop.
- */
- if (faceset == 0)
- return 0;
+ //TODO: somehow fetch default priority from send_fx here
- if (!facesets[faceset].prefix)
- {
- LOG (llevError, "get_face_fallback called with unused set (%d)?\n", faceset);
- return 0; /* use default set */
- }
+ const facedata *d = face_data (idx, ns->faceset);
- if (facesets[faceset].faces[imageno].data)
- return faceset;
+ if (!d)
+ return; // doh
- return get_face_fallback (facesets[faceset].fallback, imageno);
-}
+ client::ixsend ix;
-/**
- * Checks fallback are correctly defined.
- * This is a simple recursive function that makes sure the fallbacks
- * are all proper (eg, the fall back to defined sets, and also
- * eventually fall back to 0). At the top level, togo is set to MAX_FACE_SETS,
- * if togo gets to zero, it means we have a loop.
- * This is only run when we first load the facesets.
- */
-static void
-check_faceset_fallback (int faceset, int togo)
-{
- int fallback = facesets[faceset].fallback;
+ ix.pri = pri;
+ ix.idx = idx;
+ ix.ofs = d->data.size ();
- /* proper case - falls back to base set */
- if (fallback == 0)
- return;
+ auto (pos, ns->ixface.end ());
- if (!facesets[fallback].prefix)
+ if (ns->fxix < 2)
{
- LOG (llevError, "Face set %d falls to non set faceset %d\n", faceset, fallback);
- abort ();
+ // gcfclient does not support prioritising, older cfplus versions
+ // do not support interleaved transfers.
+ if (!ns->ixface.empty ())
+ pos = ns->ixface.end () - 1;
}
-
- togo--;
- if (togo == 0)
+ else
{
- LOG (llevError, "Infinite loop found in facesets. aborting.\n");
- abort ();
- }
-
- check_faceset_fallback (fallback, togo);
-}
-
-#define MAX_IMAGE_SIZE 10000
+ // the by far most common case will be to insert
+ // near the end, so little looping.
+ while (pos != ns->ixface.begin ())
+ {
+ --pos;
-/**
- * Client tells us what type of faces it wants. Also sets
- * the caching attribute.
- *
- */
-void
-SetFaceMode (char *buf, int len, client *ns)
-{
- int mask = (atoi (buf) & CF_FACE_CACHE), mode = (atoi (buf) & ~CF_FACE_CACHE);
+ // sort within 2k bins, to slightly prefer smaller images
+ if (pri > pos->pri || (pri == pos->pri && (ix.ofs >> 11) <= (pos->ofs >> 11)))
+ {
+ ++pos;
+ break;
+ }
+ }
+ }
- if (mode == CF_FACE_NONE)
- ns->facecache = 1;
- else if (mode != CF_FACE_PNG)
- ns->send_packet_printf ("drawinfo %d %s", NDI_RED, "Warning - send unsupported face mode. Will use Png");
+ ns->ixface.insert (pos, ix);
- if (mask)
- ns->facecache = 1;
+#if 0
+ for (auto (i, ns->ixface.begin ()); i != ns->ixface.end (); ++i)
+ fprintf (stderr, "<%d,%d> ", i->pri, i->ofs);
+ fprintf (stderr, "\n");
+#endif
}
/**
- * Client has requested pixmap that it somehow missed getting.
- * This will be called often if the client is
- * caching images.
+ * Tells client the picture it has to use
+ * to smooth a picture number given as argument.
*/
void
-SendFaceCmd (char *buf, int len, client *ns)
+AskSmooth (char *buf, int len, client *ns)
{
- ns->send_image (atoi (buf));
+ ns->send_face (atoi (buf), -100);
+ ns->flush_fx ();
}
// how lame
@@ -238,21 +163,25 @@
* we look at the facecache, and if set, send the image name.
*/
void
-client::send_face (faceidx facenum)
+client::send_face (faceidx facenum, int pri)
{
// never send face 0. ever. it does not exist.
if (!facenum)
return;
- const facedata *d = face_data (facenum, faceset);
+ faceinfo *f = face_info (facenum);
- if (!d)
+ if (!f)
{
- LOG (llevError, "client::send_face (%d) out of bounds??\n", facenum);
+ LOG (llevError | logBacktrace, "client::send_face (%d) out of bounds??\n", facenum);
return;
}
- if (faces_sent[facenum])
+ // refuse to send non-image faces
+ if (!fx_want [f->type])
+ return;
+
+ if (faces_sent [facenum])
return;
faces_sent[facenum] = true;
@@ -268,6 +197,8 @@
return;
}
+ const facedata *d = f->data (faceset);
+
packet sl;
if (force_face0)
@@ -283,8 +214,6 @@
if (EMI_smooth)
{
- faceinfo *f = face_info (facenum);
-
if (f->smooth)
{
send_face (f->smooth);
@@ -305,15 +234,24 @@
{
packet fx ("fx");
packet sx ("sx");
+ int type = 0;
do
{
faceidx facenum = fxface.back (); fxface.pop_back ();
- const facedata *d = face_data (facenum, faceset);
-
- if (d)
+ if (const faceinfo *f = face_info (facenum))
{
+ if (f->type != type)
+ {
+ type = f->type;
+
+ fx << ber32 (0)
+ << uint8 (1) << uint8 (type);
+ }
+
+ const facedata *d = f->data (faceset);
+
fx << ber32 (facenum)
<< data8 (d->chksum, CHKSUM_SIZE);
@@ -323,7 +261,8 @@
if (f->smooth)
{
- send_face (f->smooth);
+ send_face (f->smooth, -110);
+
sx << ber32 (facenum)
<< ber32 (f->smooth)
<< ber32 (f->smoothlevel);
@@ -332,7 +271,7 @@
}
}
while (!fxface.empty ()
- && fx.room () > ber32::size + CHKSUM_SIZE + 1
+ && fx.room () > ber32::size + CHKSUM_SIZE + 1 + 3 /* type switch */
&& sx.room () > ber32::size * 3);
send_packet (fx);
@@ -349,14 +288,14 @@
const facedata *d = face_data (facenum, faceset);
+ faces_sent[facenum] = true;
+
if (!d)
{
LOG (llevError, "client::send_image (%d) out of bounds??\n", facenum);
return;
}
-
- faces_sent[facenum] = true;
-
+
if (force_image_newmap)
force_newmap = true;
@@ -381,14 +320,14 @@
void
client::send_faces (object *ob)
{
- send_face (ob->face);
+ send_face (ob->face, 10);
if (ob->animation_id)
{
animation &anim = animations [ob->animation_id];
for (int i = 0; i < anim.num_animations; i++)
- send_face (anim.faces [i]);
+ send_face (anim.faces [i], -10);
}
}
@@ -422,7 +361,7 @@
*/
for (int i = 0; i < animations[anim_num].num_animations; i++)
{
- send_face (animations[anim_num].faces[i]);
+ send_face (animations[anim_num].faces[i], -20);
sl << uint16 (animations[anim_num].faces[i]); /* flags - not used right now */
}
@@ -483,20 +422,22 @@
sl.printf ("replyinfo image_sums %d %d ", start, stop);
for (int i = start; i <= stop && i < faces.size (); i++)
- {
- ns->faces_sent[i] = true;
+ if (const faceinfo *f = face_info (i))
+ if (ns->fx_want [f->type])
+ {
+ ns->faces_sent[i] = true;
- const facedata *d = face_data (i, ns->faceset);
+ const facedata *d = f->data (ns->faceset);
- if (sl.room () < 2 + 4 + 1 + d->data.size () + 1)
- break;
+ if (sl.room () < 2 + 4 + 1 + d->data.size () + 1)
+ break;
- sl << uint16 (i)
- << uint32 (0) // checksum
- << uint8 (ns->faceset);
+ sl << uint16 (i)
+ << uint32 (0) // checksum
+ << uint8 (ns->faceset);
- print_facename (sl, *d); sl << uint8 (0);
- }
+ print_facename (sl, *d); sl << uint8 (0);
+ }
/* It would make more sense to catch this pre-emptively in the code above.
* however, if this really happens, we probably just want to cut down the
@@ -504,7 +445,7 @@
* support.
*/
//TODO: taken care of above, should simply abort or make sure the above code is correct
- if (sl.length () >= MAXSOCKBUF)
+ if (sl.length () > MAXSOCKBUF)
{
LOG (llevError, "send_image_send: buffer overrun, %d > %d\n", sl.length (), MAXSOCKBUF);
abort ();