--- deliantra/server/socket/request.C 2007/07/10 06:05:55 1.114 +++ deliantra/server/socket/request.C 2008/05/06 16:55:26 1.128 @@ -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,2008 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; @@ -192,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); } } @@ -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; - - // 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]; + + 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; + } - --max_distance; + 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 */ @@ -855,8 +888,10 @@ * Tells the client that here is a player it should start using. */ void -esrv_new_player (player *pl, uint32 weight) +esrv_new_player (player *pl) { + sint32 weight = pl->ob->client_weight (); + packet sl ("player"); sl << uint32 (pl->ob->count) @@ -933,7 +968,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; @@ -1000,7 +1035,7 @@ * 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) + if (!plmap || plmap->in_memory != MAP_ACTIVE) return; int x, y, ax, ay, startlen, max_x, max_y, oldlen; @@ -1098,7 +1133,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 +1162,6 @@ continue; } - m->touch (); - int d = pl->blocked_los[ax][ay]; if (d > 3) @@ -1211,25 +1246,24 @@ // send hp information, if applicable if (object *op = ms.faces_obj [0]) - { - if (op->head || op->invisible) - ; // do not show - else if (op->type == PLAYER - || QUERY_FLAG (op, FLAG_MONSTER) || QUERY_FLAG (op, FLAG_ALIVE) || QUERY_FLAG (op, FLAG_GENERATOR)) - { - 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->max_x - op->arch->x; //TODO: should be upper-left edge - } - } - - if (op->msg && op->msg[0] == '@') - flags |= 1; - - if (op->type == PLAYER && op != ob) - player = op->count; - } + if (op->is_head () && !op->invisible) + { + if (op->stats.maxhp > op->stats.hp + && op->stats.maxhp > 0 + && (op->type == PLAYER + || op->type == DOOR // does not work, have maxhp 0 + || QUERY_FLAG (op, FLAG_MONSTER) || QUERY_FLAG (op, FLAG_ALIVE) || QUERY_FLAG (op, FLAG_GENERATOR))) + { + stat_hp = 255 - (op->stats.hp * 255 + 254) / op->stats.maxhp; + 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 != ob) + player = op->count; + } if (lastcell.stat_hp != stat_hp) { @@ -1390,7 +1424,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 +1447,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 +1566,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 +1612,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 +1640,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); }