--- deliantra/server/socket/request.C 2007/07/24 04:55:35 1.116 +++ deliantra/server/socket/request.C 2007/11/08 19:43:30 1.123 @@ -1,11 +1,11 @@ /* - * This file is part of Crossfire TRT, the Roguelike Realtime MORPG. + * 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 + * 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. @@ -18,7 +18,7 @@ * 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 */ /** @@ -131,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; @@ -248,86 +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; + int dir = *buf++ - '1'; - // 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 - - 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 */ @@ -1098,7 +1131,9 @@ { nx = x; ny = y; m = plmap; - if (!xy_normalise (m, nx, ny)) + if (xy_normalise (m, nx, ny)) + m->touch (); + else m = 0; } @@ -1125,8 +1160,6 @@ continue; } - m->touch (); - int d = pl->blocked_los[ax][ay]; if (d > 3) @@ -1390,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); @@ -1413,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); @@ -1532,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) @@ -1576,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 (); @@ -1603,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); }