--- deliantra/server/socket/request.C 2007/04/03 00:21:38 1.84 +++ deliantra/server/socket/request.C 2007/08/26 04:21:30 1.122 @@ -1,25 +1,24 @@ /* - * CrossFire, A Multiplayer game for X-windows + * This file is part of Crossfire TRT, the Roguelike Realtime MORPG. * - * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team - * Copyright (C) 2001 Mark Wedel - * Copyright (C) 1992 Frank Tore Johansen + * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team + * Copyright (©) 2001,2007 Mark Wedel + * Copyright (©) 1992,2007 Frank Tore Johansen * - * This program is free software; you can redistribute it and/or modify + * 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 */ /** @@ -132,6 +131,8 @@ static void clear_map (player *pl) { + pl->ns->mapinfo_queue_clear (); + memset (&pl->ns->lastmap, 0, sizeof (pl->ns->lastmap)); pl->ns->force_newmap = false; @@ -147,17 +148,9 @@ check_map_change (player *pl) { client &socket = *pl->ns; - object *ob = pl->ob; - char buf[MAX_BUF]; /* eauugggh */ + object *ob = pl->observe; - if (socket.force_newmap) - { - // force newmap is used for clients that do not redraw their map - // after image uploads. - socket.current_map = ob->map; - clear_map (pl); - } - else if (socket.current_map != ob->map) + if (socket.current_map != ob->map || socket.force_newmap) { clear_map (pl); socket.current_map = ob->map; @@ -168,22 +161,17 @@ { int flags = 0; - if (ob->map->tile_path[0]) - flags |= 1; - if (ob->map->tile_path[1]) - flags |= 2; - if (ob->map->tile_path[2]) - flags |= 4; - if (ob->map->tile_path[3]) - flags |= 8; - - snprintf (buf, MAX_BUF, "mapinfo - spatial %d %d %d %d %d %s", - flags, socket.mapx / 2 - ob->x, socket.mapy / 2 - ob->y, ob->map->width, ob->map->height, &ob->map->path); + if (ob->map->tile_path[0]) flags |= 1; + if (ob->map->tile_path[1]) flags |= 2; + if (ob->map->tile_path[2]) flags |= 4; + if (ob->map->tile_path[3]) flags |= 8; + + socket.send_packet_printf ("mapinfo - spatial %d %d %d %d %d %s", + flags, socket.mapx / 2 - ob->x, socket.mapy / 2 - ob->y, + ob->map->width, ob->map->height, &ob->map->path); } else - snprintf (buf, MAX_BUF, "mapinfo current"); - - socket.send_packet (buf); + socket.send_packet ("mapinfo current"); } } else if (socket.current_x != ob->x || socket.current_y != ob->y) @@ -206,8 +194,8 @@ region *reg = ob->region (); if (socket.current_region != reg) { + INVOKE_PLAYER (REGION_CHANGE, pl, ARG_REGION (reg), ARG_REGION (socket.current_region)); socket.current_region = reg; - socket.send_packet_printf ("drawinfo 0 You are now %s.\n(use whereami for more details)", ®->longname); } } @@ -217,29 +205,17 @@ * that information. */ void -RequestInfo (char *buf, int len, client * ns) +RequestInfo (char *buf, int len, client *ns) { - char *params = NULL, *cp; - - /* No match */ - char bigbuf[MAX_BUF]; - int slen; - - /* Set up replyinfo before we modify any of the buffers - this is used - * if we don't find a match. - */ - strcpy (bigbuf, "replyinfo "); - slen = strlen (bigbuf); - safe_strcat (bigbuf, buf, &slen, MAX_BUF); + char *params; /* find the first space, make it null, and update the * params pointer. */ - for (cp = buf; *cp != '\0'; cp++) - if (*cp == ' ') + for (params = buf; *params; params++) + if (*params == ' ') { - *cp = '\0'; - params = cp + 1; + *params++ = 0; break; } @@ -252,7 +228,13 @@ else if (!strcmp (buf, "spell_paths")) send_spell_paths (ns, params); else - ns->send_packet (bigbuf, len); + { + // undo tokenisation above and send replyinfo with the request unchanged + if (*params) + *--params = ' '; + + ns->send_packet_printf ("replyinfo %s", buf); + } } void @@ -268,90 +250,117 @@ } void -MapInfoCmd (char *buf, int len, player *pl) +client::mapinfo_queue_clear () { - // mapinfo tag spatial flags x y w h hash + for (auto (i, mapinfo_queue.begin ()); i != mapinfo_queue.end (); ++i) + free (*i); - char bigbuf[MAX_BUF], *token; + mapinfo_queue.clear (); +} - token = buf; - // copy token - if (!(buf = strchr (buf, ' '))) - return; +bool +client::mapinfo_try (char *buf) +{ + char *token = buf; + buf += strlen (buf) + 9; - *buf++ = 0; + // initial map and its origin + maptile *map = pl->observe->map; + int mapx = pl->ns->mapx / 2 - pl->observe->x; + int mapy = pl->ns->mapy / 2 - pl->observe->y; + int max_distance = 8; // limit maximum path length to something generous - if (!strncmp (buf, "spatial ", 8)) + while (*buf && map && max_distance) { - buf += 8; - - // initial map and its origin - maptile *map = pl->ob->map; - sint16 dx, dy; - int mapx = pl->ns->mapx / 2 - pl->ob->x; - int mapy = pl->ns->mapy / 2 - pl->ob->y; - int max_distance = 8; // limit maximum path length to something generous + int dir = *buf++ - '1'; - while (*buf && map && max_distance) + if (dir >= 0 && dir <= 3) { - int dir = *buf++; - - switch (dir) + if (!map->tile_path [dir]) + map = 0; + else if (map->tile_available (dir, false)) { - case '1': - dx = 0; - dy = -1; - map = map->xy_find (dx, dy); - map && (mapy -= map->height); - break; - case '2': - mapx += map->width; - dx = map->width; - dy = 0; - map = map->xy_find (dx, dy); - break; - case '3': - mapy += map->height; - dx = 0; - dy = map->height; - map = map->xy_find (dx, dy); - break; - case '4': - dx = -1; - dy = 0; - map = map->xy_find (dx, dy); - map && (mapx -= map->width); - break; - } + maptile *neigh = map->tile_map [dir]; - --max_distance; + switch (dir) + { + case 0: mapy -= neigh->height; break; + case 2: mapy += map ->height; break; + case 3: mapx -= neigh->width ; break; + case 1: mapx += map ->width ; break; + } + + map = neigh; + --max_distance; + } + else + return 0; } + else + max_distance = 0; + } - if (!max_distance) - snprintf (bigbuf, MAX_BUF, "mapinfo %s error", token); - else if (map && map->path[0]) - { - int flags = 0; + if (!max_distance) + send_packet_printf ("mapinfo %s error", token); + else if (!map || !map->path) + send_packet_printf ("mapinfo %s nomap", token); + else + { + int flags = 0; - if (map->tile_path[0]) - flags |= 1; - if (map->tile_path[1]) - flags |= 2; - if (map->tile_path[2]) - flags |= 4; - if (map->tile_path[3]) - flags |= 8; + if (map->tile_path[0]) flags |= 1; + if (map->tile_path[1]) flags |= 2; + if (map->tile_path[2]) flags |= 4; + if (map->tile_path[3]) flags |= 8; - snprintf (bigbuf, MAX_BUF, "mapinfo %s spatial %d %d %d %d %d %s", token, flags, mapx, mapy, map->width, map->height, &map->path); - } + send_packet_printf ("mapinfo %s spatial %d %d %d %d %d %s", token, flags, mapx, mapy, map->width, map->height, &map->path); + } + + return 1; +} + +void +client::mapinfo_queue_run () +{ + if (mapinfo_queue.empty () || !pl) + return; + + for (int i = 0; i < mapinfo_queue.size (); ++i) + if (mapinfo_try (mapinfo_queue [i])) + { + free (mapinfo_queue [i]); + mapinfo_queue.erase (i); + } + else + ++i; +} + +void +MapInfoCmd (char *buf, int len, player *pl) +{ + // mapinfo tag spatial flags x y w h hash + + char *token = buf; + + if (!(buf = strchr (buf, ' '))) + return; + + if (!strncmp (buf, " spatial ", 9)) + { + char *copy = strdup (token); + copy [buf - token] = 0; + +#if 0 + // this makes only sense when we flush the buffer immediately + if (pl->ns->mapinfo_try (copy)) + free (copy); else - snprintf (bigbuf, MAX_BUF, "mapinfo %s nomap", token); +#endif + pl->ns->mapinfo_queue.push_back (copy); } else - snprintf (bigbuf, MAX_BUF, "mapinfo %s unsupported", token); - - pl->ns->send_packet (bigbuf); + pl->ns->send_packet_printf ("mapinfo %s unsupported", token); } /** This is the Setup cmd */ @@ -490,27 +499,6 @@ } /** - * client requested an image. send it rate-limited - * before flushing. - */ -void -AskFaceCmd (char *buf, int len, client *ns) -{ - ns->askface.push_back (atoi (buf)); -} - -/** - * 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 (); -} - -/** * This handles the general commands from the client (ie, north, fire, cast, * etc.) */ @@ -541,7 +529,6 @@ pl->count = 0; } - /** * This handles the general commands from the client (ie, north, fire, cast, * etc.). It is a lot like PlayerCmd above, but is called with the @@ -553,7 +540,7 @@ { if (len <= 6) { - LOG (llevDebug, "Corrupt ncom command <%s> not long enough - discarding\n", buf); + LOG (llevDebug, "%s: corrupt ncom command <%s>: not long enough (%d) - discarding\n", pl->ns->host, buf, len); return; } @@ -620,10 +607,6 @@ LOG (llevError, "Got reply message with ST_PLAYING input state\n"); break; - case ST_CHANGE_CLASS: - key_change_class (pl->ob, buf[0]); - break; - case ST_GET_PARTY_PASSWORD: /* Get password for party */ receive_party_password (pl->ob, 13); break; @@ -672,7 +655,7 @@ if (cp) { - assign (ns->version, cp + 1); + ns->version = cp + 1; if (ns->sc_version < 1026) ns->send_packet_printf ("drawinfo %d %s", NDI_RED, @@ -747,6 +730,34 @@ ns->send_packet_printf ("query %d %s", flags, text ? text : ""); } +/** + * Get player's current range attack in obuf. + */ +static void +rangetostring (player *pl, char *obuf) +{ + dynbuf_text buf; + + if (pl->ranged_ob) + buf << " Range" << (pl->ob->current_weapon == pl->ranged_ob ? "*" : "") << ": " << pl->ranged_ob->name; + + if (pl->combat_ob) + buf << " Combat" << (pl->ob->current_weapon == pl->combat_ob ? "*" : "") << ": " << pl->combat_ob->name; + +#if 0 + //TODO: remove this when slot system is working, this is only for debugging + if (pl->ob->chosen_skill) + buf << " Skill*: " << pl->ob->chosen_skill->name; +#endif + + //TODO: maybe golem should become the current_weapon, quite simply? + if (pl->golem) + buf << " Golem*: " << pl->golem->name; + + buf << '\0'; + buf.linearise (obuf); +} + #define AddIfInt64(Old,New,Type) if (Old != New) {\ Old = New; \ sl << uint8 (Type) << uint64 (New); \ @@ -762,9 +773,9 @@ sl << uint8 (Type) << uint16 (New); \ } -#define AddIfFloat(Old,New,Type) if (Old != New) {\ +#define AddIfFloat(Old,New,Type,mult) if (Old != New) {\ Old = New; \ - sl << uint8 (Type) << uint32 (New*FLOAT_MULTI); \ + sl << uint8 (Type) << uint32 (New*FLOAT_MULTI*mult); \ } #define AddIfString(Old,New,Type) if (Old == NULL || strcmp(Old,New)) {\ @@ -788,10 +799,12 @@ if (!ns) return; - object *ob = pl->ob; + object *ob = pl->observe; if (!ob) return; + player *opl = ob->contr ? static_cast(ob->contr) : pl; + packet sl ("stats"); AddIfShort (ns->last_stats.hp, ob->stats.hp, CS_STAT_HP); @@ -809,7 +822,7 @@ AddIfShort (ns->last_stats.Cha, ob->stats.Cha, CS_STAT_CHA); for (int s = 0; s < NUM_SKILLS; s++) - if (object *skill = pl->last_skill_ob[s]) + if (object *skill = opl->last_skill_ob[s]) if (skill->stats.exp != ns->last_skill_exp [s]) { ns->last_skill_exp [s] = skill->stats.exp; @@ -827,17 +840,17 @@ AddIfShort (ns->last_stats.wc, ob->stats.wc, CS_STAT_WC); AddIfShort (ns->last_stats.ac, ob->stats.ac, CS_STAT_AC); AddIfShort (ns->last_stats.dam, ob->stats.dam, CS_STAT_DAM); - AddIfFloat (ns->last_speed, ob->speed, CS_STAT_SPEED); + AddIfFloat (ns->last_speed, ob->speed, CS_STAT_SPEED, 1.f/TICK); AddIfShort (ns->last_stats.food, ob->stats.food, CS_STAT_FOOD); - AddIfFloat (ns->last_weapon_sp, pl->weapon_sp, CS_STAT_WEAP_SP); + AddIfFloat (ns->last_weapon_sp, pl->weapon_sp, CS_STAT_WEAP_SP, 1.f/TICK); AddIfInt (ns->last_weight_limit, weight_limit[ob->stats.Str], CS_STAT_WEIGHT_LIM); flags = 0; - if (pl->fire_on) + if (opl->fire_on) flags |= SF_FIREON; - if (pl->run_on) + if (opl->run_on) flags |= SF_RUNON; AddIfShort (ns->last_flags, flags, CS_STAT_FLAGS); @@ -861,7 +874,7 @@ AddIfInt (ns->last_path_denied, ob->path_denied, CS_STAT_SPELL_DENY); } - rangetostring (ob, buf); /* we want use the new fire & run system in new client */ + rangetostring (opl, buf); /* we want use the new fire & run system in new client */ AddIfString (ns->stats.range, buf, CS_STAT_RANGE); set_title (ob, buf); AddIfString (ns->stats.title, buf, CS_STAT_TITLE); @@ -953,7 +966,7 @@ if (ob) ns.send_faces (ob); else - ns.send_face (face_num); + ns.send_face (face_num, 10); sl << uint16 (face_num); return 1; @@ -1005,45 +1018,66 @@ } /** - * This function uses the new map1 protocol command to send the map - * to the client. It is necessary because the old map command supports - * a maximum map size of 15x15. - * This function is much simpler than the old one. This is because - * the old function optimized to send as few face identifiers as possible, - * at the expense of sending more coordinate location (coordinates were - * only 1 byte, faces 2 bytes, so this was a worthwhile savings). Since - * we need 2 bytes for coordinates and 2 bytes for faces, such a trade off - * maps no sense. Instead, we actually really only use 12 bits for coordinates, - * and use the other 4 bits for other informatiion. For full documentation - * of what we send, see the doc/Protocol file. - * I will describe internally what we do: - * the ns->lastmap shows how the map last looked when sent to the client. - * in the lastmap structure, there is a cells array, which is set to the - * maximum viewable size (As set in config.h). - * in the cells, there are faces and a count value. - * we use the count value to hold the darkness value. If -1, then this space - * is not viewable. - * we use faces[0] faces[1] faces[2] to hold what the three layers - * look like. + * Draws client map. */ void -draw_client_map1 (object *pl) +draw_client_map (player *pl) { + object *ob = pl->observe; + if (!ob->active) + return; + + maptile *plmap = ob->map; + + /* If player is just joining the game, he isn't here yet, so the map + * can get swapped out. If so, don't try to send them a map. All will + * be OK once they really log in. + */ + if (!plmap || plmap->in_memory != MAP_IN_MEMORY) + return; + int x, y, ax, ay, startlen, max_x, max_y, oldlen; - sint16 nx, ny; int estartlen, eoldlen; uint8 eentrysize; uint16 ewhatstart, ewhatflag; uint8 extendedinfos; - maptile *m; - client &socket = *pl->contr->ns; + check_map_change (pl); + prefetch_surrounding_maps (pl->ob); - if (!pl->active) - return; + /* do LOS after calls to update_position */ + if (ob != pl->ob) + clear_los (pl); + else if (pl->do_los) + { + update_los (ob); + pl->do_los = 0; + } + + /** + * This function uses the new map1 protocol command to send the map + * to the client. It is necessary because the old map command supports + * a maximum map size of 15x15. + * This function is much simpler than the old one. This is because + * the old function optimized to send as few face identifiers as possible, + * at the expense of sending more coordinate location (coordinates were + * only 1 byte, faces 2 bytes, so this was a worthwhile savings). Since + * we need 2 bytes for coordinates and 2 bytes for faces, such a trade off + * maps no sense. Instead, we actually really only use 12 bits for coordinates, + * and use the other 4 bits for other informatiion. For full documentation + * of what we send, see the doc/Protocol file. + * I will describe internally what we do: + * the ns->lastmap shows how the map last looked when sent to the client. + * in the lastmap structure, there is a cells array, which is set to the + * maximum viewable size (As set in config.h). + * in the cells, there are faces and a count value. + * we use the count value to hold the darkness value. If -1, then this space + * is not viewable. + * we use faces[0] faces[1] faces[2] to hold what the three layers + * look like. + */ - check_map_change (pl->contr); - prefetch_surrounding_maps (pl); + client &socket = *pl->ns; packet sl (socket.mapmode == Map1Cmd ? "map1" : "map1a"); packet esl; @@ -1077,16 +1111,32 @@ /* We could do this logic as conditionals in the if statement, * but that started to get a bit messy to look at. */ - max_x = pl->x + (socket.mapx + 1) / 2; - max_y = pl->y + (socket.mapy + 1) / 2; - - maptile *plmap = pl->map; + max_x = ob->x + (socket.mapx + 1) / 2; + max_y = ob->y + (socket.mapy + 1) / 2; - for (y = pl->y - socket.mapy / 2; y < max_y; y++, ay++) + for (y = ob->y - socket.mapy / 2; y < max_y; y++, ay++) { + sint16 nx, ny; + maptile *m = 0; + ax = 0; - for (x = pl->x - socket.mapx / 2; x < max_x; x++, ax++) + for (x = ob->x - socket.mapx / 2; x < max_x; x++, ax++) { + // check to see if we can simply go one right quickly + ++nx; + if (m && nx >= m->width) + m = 0; + + if (!m) + { + nx = x; ny = y; m = plmap; + + if (xy_normalise (m, nx, ny)) + m->touch (); + else + m = 0; + } + int emask, mask; emask = mask = (ax & 0x3f) << 10 | (ay & 0x3f) << 4; @@ -1095,10 +1145,6 @@ /* If the coordinates are not valid, or it is too dark to see, * we tell the client as such */ - nx = x; - ny = y; - m = get_map_from_coord (plmap, &nx, &ny); - if (!m) { /* space is out of map. Update space and clear values @@ -1114,9 +1160,7 @@ continue; } - m->touch (); - - int d = pl->contr->blocked_los[ax][ay]; + int d = pl->blocked_los[ax][ay]; if (d > 3) { @@ -1189,13 +1233,14 @@ lastcell.count = d; mapspace &ms = m->at (nx, ny); + ms.update (); if (socket.extmap) { - uint8 stat_hp = 0; + uint8 stat_hp = 0; uint8 stat_width = 0; - uint8 flags = 0; - UUID player = 0; + uint8 flags = 0; + tag_t player = 0; // send hp information, if applicable if (object *op = ms.faces_obj [0]) @@ -1208,14 +1253,14 @@ if (op->stats.maxhp > 0 && (unsigned) op->stats.maxhp > (unsigned) op->stats.hp) { stat_hp = 255 - (op->stats.hp * 255 + 254) / op->stats.maxhp; - stat_width = op->arch->tail_x; + stat_width = op->arch->max_x - op->arch->x; //TODO: should be upper-left edge } } if (op->msg && op->msg[0] == '@') flags |= 1; - if (op->type == PLAYER && op != pl) + if (op->type == PLAYER && op != ob) player = op->count; } @@ -1246,7 +1291,7 @@ *last_ext |= 0x80; last_ext = &sl[sl.length ()]; - sl << uint8 (0x47) << uint8 (8) << (uint64)player; + sl << uint8 (0x47) << uint8 (4) << (uint32)player; } if (lastcell.flags != flags) @@ -1269,24 +1314,23 @@ if (update_space (sl, socket, ms, lastcell, 1)) mask |= 0x2; - if (ms.player () == pl - && (pl->invisible & (pl->invisible < 50 ? 1 : 7))) + if (ms.player () == ob + && (ob->invisible & (ob->invisible < 50 ? 1 : 7))) { // force player to be visible to himself if invisible - if (lastcell.faces[0] != pl->face) + if (lastcell.faces[0] != ob->face) { - lastcell.faces[0] = pl->face; + lastcell.faces[0] = ob->face; mask |= 0x1; - sl << uint16 (pl->face); + sl << uint16 (ob->face); - socket.send_faces (pl); + socket.send_faces (ob); } } /* Top face */ else if (update_space (sl, socket, ms, lastcell, 0)) mask |= 0x1; - /* Check to see if we are in fact sending anything for this * space by checking the mask. If so, update the mask. @@ -1355,74 +1399,10 @@ } } -/** - * Draws client map. - */ -void -draw_client_map (object *pl) -{ - int i, j; - sint16 ax, ay; /* ax and ay goes from 0 to max-size of arrays */ - int mflags; - struct Map newmap; - maptile *m, *pm; - - if (pl->type != PLAYER) - { - LOG (llevError, "draw_client_map called with non player/non eric-server\n"); - return; - } - - pm = pl->map; - - /* If player is just joining the game, he isn't here yet, so the map - * can get swapped out. If so, don't try to send them a map. All will - * be OK once they really log in. - */ - if (pm == NULL || pm->in_memory != MAP_IN_MEMORY) - return; - - memset (&newmap, 0, sizeof (struct Map)); - - for (j = (pl->y - pl->contr->ns->mapy / 2); j < (pl->y + (pl->contr->ns->mapy + 1) / 2); j++) - for (i = (pl->x - pl->contr->ns->mapx / 2); i < (pl->x + (pl->contr->ns->mapx + 1) / 2); i++) - { - ax = i; - ay = j; - m = pm; - mflags = get_map_flags (m, &m, ax, ay, &ax, &ay); - - if (mflags & P_OUT_OF_MAP) - continue; - - /* If a map is visible to the player, we don't want to swap it out - * just to reload it. This should really call something like - * swap_map, but this is much more efficient and 'good enough' - */ - if (mflags & P_NEW_MAP) - m->timeout = 50; - } - - /* do LOS after calls to update_position */ - if (pl->contr->do_los) - { - update_los (pl); - pl->contr->do_los = 0; - } - - /* Big maps need a different drawing mechanism to work */ - draw_client_map1 (pl); -} - - /*****************************************************************************/ - /* GROS: The following one is used to allow a plugin to send a generic cmd to*/ - /* a player. Of course, the client need to know the command to be able to */ - /* manage it ! */ - /*****************************************************************************/ void send_plugin_custom_message (object *pl, char *buf) @@ -1443,7 +1423,7 @@ for (int i = 1; i < NUM_SKILLS; i++) sl.printf ("%d:%s\n", i + CS_STAT_SKILLINFO, &skill_names[i]); - if (sl.length () >= MAXSOCKBUF) + if (sl.length () > MAXSOCKBUF) { LOG (llevError, "Buffer overflow in send_skill_info!\n"); fatal (0); @@ -1466,7 +1446,7 @@ for (int i = 0; i < NRSPELLPATHS; i++) sl.printf ("%d:%s\n", 1 << i, spellpathnames[i]); - if (sl.length () >= MAXSOCKBUF) + if (sl.length () > MAXSOCKBUF) { LOG (llevError, "Buffer overflow in send_spell_paths!\n"); fatal (0); @@ -1585,6 +1565,8 @@ spell->face = face_find ("burnout.x11", blank_face); } + pl->ns->send_face (spell->face); + /* send the current values */ sl << uint32 (spell->count) << uint16 (spell->level) @@ -1629,16 +1611,17 @@ * won't take us over the length limit for the socket, if it does, * we need to send what we already have, and restart packet formation */ + if (spell->type != SPELL) + continue; + /* Seeing crashes by overflowed buffers. Quick arithemetic seems * to show add_spell is 26 bytes + 2 strings. However, the overun * is hundreds of bytes off, so correcting 22 vs 26 doesn't seem * like it will fix this */ - if (spell->type != SPELL) - continue; - - if (sl.length () >= (MAXSOCKBUF - (26 + strlen (spell->name) + (spell->msg ? strlen (spell->msg) : 0)))) + if (sl.length () > (MAXSOCKBUF - (26 + strlen (spell->name) + (spell->msg ? strlen (spell->msg) : 0)))) { + pl->ns->flush_fx (); pl->ns->send_packet (sl); sl.reset (); @@ -1656,13 +1639,14 @@ else append_spell (pl, sl, spell); - if (sl.length () >= MAXSOCKBUF) + if (sl.length () > MAXSOCKBUF) { LOG (llevError, "Buffer overflow in esrv_add_spells!\n"); fatal (0); } /* finally, we can send the packet */ + pl->ns->flush_fx (); pl->ns->send_packet (sl); }