--- deliantra/server/socket/request.C 2007/01/19 17:50:11 1.63 +++ deliantra/server/socket/request.C 2007/03/11 21:26:05 1.70 @@ -1,26 +1,26 @@ /* - CrossFire, A Multiplayer game for X-windows - - 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 - 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. - - 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 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 -*/ + * CrossFire, A Multiplayer game for X-windows + * + * 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 + * 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. + * + * 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 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 + */ /** * \file @@ -38,9 +38,6 @@ * * esrv_map_new starts updating the map * - * esrv_map_setbelow allows filling in all of the faces for the map. - * if a face has not already been sent to the client, it is sent now. - * */ #include @@ -149,7 +146,7 @@ pl->ns->floorbox_reset (); } -/** check for map change and send new map data */ +/** check for map/region change and send new map data */ static void check_map_change (player *pl) { @@ -203,6 +200,13 @@ socket.current_x = ob->x; socket.current_y = ob->y; + + region *reg = ob->region (); + if (socket.current_region != reg) + { + socket.current_region = reg; + socket.send_packet_printf ("drawinfo 0 You are now %s.\n(use whereami for more details)", ®->longname); + } } /** @@ -703,10 +707,10 @@ /* If we can't find a face, return and set it so we won't try to send this * again. */ - if ((!FindSmooth (face, &smoothface)) && (!FindSmooth (smooth_face->number, &smoothface))) + if (!FindSmooth (face, &smoothface)) { - LOG (llevError, "could not findsmooth for %d. Neither default (%s)\n", face, &smooth_face->name); + LOG (llevError, "could not findsmooth for %d.\n", face); ns->faces_sent[face] |= NS_FACESENT_SMOOTH; return; } @@ -724,10 +728,10 @@ ns->send_packet (sl); } - /** - * Tells client the picture it has to use - * to smooth a picture number given as argument. - */ +/** + * Tells client the picture it has to use + * to smooth a picture number given as argument. + */ void AskSmooth (char *buf, int len, client *ns) { @@ -800,9 +804,9 @@ pl->count = 0; //TODO: schmorp thinks whatever this calculates, it makes no sense at all - int time = FABS (pl->ob->speed) < 0.001 + int time = fabs (pl->ob->speed) < 0.001 ? time = MAX_TIME * 100 - : time = (int) (MAX_TIME / FABS (pl->ob->speed)); + : time = (int) (MAX_TIME / fabs (pl->ob->speed)); /* Send confirmation of command execution now */ packet sl ("comc"); @@ -1106,7 +1110,7 @@ sl << uint32 (pl->ob->count) << uint32 (weight) - << uint32 (pl->ob->face->number) + << uint32 (pl->ob->face) << data8 (pl->ob->name); pl->ns->last_weight = weight; @@ -1162,98 +1166,21 @@ * ******************************************************************************/ -/** - * This adds face_num to a map cell at x,y. If the client doesn't have - * the face yet, we will also send it. - */ -static void -esrv_map_setbelow (client * ns, int x, int y, short face_num, struct Map *newmap) -{ - if (newmap->cells[x][y].count >= MAP_LAYERS) - { - //TODO: one or the other, can't both have abort and return, verify and act - LOG (llevError, "Too many faces in map cell %d %d\n", x, y); - return; - abort (); - } - - newmap->cells[x][y].faces[newmap->cells[x][y].count] = face_num; - newmap->cells[x][y].count++; - - if (!(ns->faces_sent[face_num] & NS_FACESENT_FACE)) - esrv_send_face (ns, face_num, 0); -} - /** Clears a map cell */ static void -map_clearcell (struct MapCell *cell, int face0, int face1, int face2, int count) +map_clearcell (struct MapCell *cell, int count) { - cell->faces[0] = face0; - cell->faces[1] = face1; - cell->faces[2] = face2; + cell->faces[0] = 0; + cell->faces[1] = 0; + cell->faces[2] = 0; cell->count = count; cell->stat_hp = 0; cell->flags = 0; cell->player = 0; } -#define MAX_HEAD_POS MAX(MAX_CLIENT_X, MAX_CLIENT_Y) #define MAX_LAYERS 3 -/* Using a global really isn't a good approach, but saves the over head of - * allocating and deallocating such a block of data each time run through, - * and saves the space of allocating this in the socket object when we only - * need it for this cycle. If the server is ever threaded, this needs to be - * re-examined. - */ -static object *heads[MAX_HEAD_POS * MAX_HEAD_POS * MAX_LAYERS]; - -/** - * Returns true if any of the heads for this - * space is set. Returns false if all are blank - this is used - * for empty space checking. - */ -static inline int -have_head (int ax, int ay) -{ - if (heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS] || - heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS + 1] || heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS + 2]) - return 1; - - return 0; -} - -/** - * check_head is a bit simplistic version of update_space below. - * basically, it only checks the that the head on space ax,ay at layer - * needs to get sent - if so, it adds the data, sending the head - * if needed, and returning 1. If this no data needs to get - * sent, it returns zero. - */ -static int -check_head (packet &sl, client &ns, int ax, int ay, int layer) -{ - short face_num; - - if (heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS + layer]) - face_num = heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS + layer]->face->number; - else - face_num = 0; - - if (face_num != ns.lastmap.cells[ax][ay].faces[layer]) - { - sl << uint16 (face_num); - if (face_num && !(ns.faces_sent[face_num] & NS_FACESENT_FACE)) - esrv_send_face (&ns, face_num, 0); - - heads[(ay * MAX_HEAD_POS + ax) * MAX_LAYERS + layer] = NULL; - ns.lastmap.cells[ax][ay].faces[layer] = face_num; - return 1; - } - - return 0; /* No change */ -} - /** * Removes the need to replicate the same code for each layer. * this returns true if this space is now in fact different than @@ -1276,49 +1203,10 @@ static int update_space (packet &sl, client &ns, maptile *mp, int mx, int my, int sx, int sy, int layer) { - object *ob, *head; uint16 face_num; int bx, by, i; - /* If there is a multipart object stored away, treat that as more important. - * If not, then do the normal processing. - */ - head = heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + layer]; - - /* Check to see if this head is part of the set of objects - * we would normally send for this space. If so, then - * don't use the head value. We need to do the check - * here and not when setting up the heads[] value for two reasons - - * 1) the heads[] values will get used even if the space is not visible. - * 2) its possible the head is not on the same map as a part, and I'd - * rather not need to do the map translation overhead. - * 3) We need to do some extra checking to make sure that we will - * otherwise send the image as this layer, eg, either it matches - * the head value, or is not multipart. - */ - if (head && !head->more) - { - for (i = 0; i < MAP_LAYERS; i++) - { - ob = GET_MAP_FACE_OBJ (mp, mx, my, i); - if (!ob) - continue; - - if (ob->head) - ob = ob->head; - - if (ob == head) - { - heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + layer] = NULL; - head = NULL; - break; - } - } - } - - ob = head; - if (!ob) - ob = GET_MAP_FACE_OBJ (mp, mx, my, layer); + object *ob = GET_MAP_FACE_OBJ (mp, mx, my, layer); /* If there is no object for this space, or if the face for the object * is the blank face, set the face number to zero. @@ -1328,137 +1216,11 @@ */ if (!ob || ob->face == blank_face) face_num = 0; - else if (head) - { - /* if this is a head that had previously been stored */ - face_num = ob->face->number; - } else - { - /* if the faces for the different parts of a multipart object - * are the same, we only want to send the bottom right most - * portion of the object. That info is in the tail_.. values - * of the head. Note that for the head itself, ob->head will - * be null, so we only do this block if we are working on - * a tail piece. - */ - - /* tail_x and tail_y will only be set in the head object. If - * this is the head object and these are set, we proceed - * with logic to only send bottom right. Similarly, if - * this is one of the more parts but the head has those values - * set, we want to do the processing. There can be cases where - * the head is not visible but one of its parts is, so we just - * can always expect that ob->arch->tail_x will be true for all - * object we may want to display. - */ - if ((ob->arch->tail_x || ob->arch->tail_y) || (ob->head && (ob->head->arch->tail_x || ob->head->arch->tail_y))) - { - - if (ob->head) - head = ob->head; - else - head = ob; - - /* Basically figure out where the offset is from where we are right - * now. the ob->arch->clone.{x,y} values hold the offset that this current - * piece is from the head, and the tail is where the tail is from the - * head. Note that bx and by will equal sx and sy if we are already working - * on the bottom right corner. If ob is the head, the clone values - * will be zero, so the right thing will still happen. - */ - bx = sx + head->arch->tail_x - ob->arch->clone.x; - by = sy + head->arch->tail_y - ob->arch->clone.y; - - /* I don't think this can ever happen, but better to check for it just - * in case. - */ - if (bx < sx || by < sy) - { - LOG (llevError, "update_space: bx (%d) or by (%d) is less than sx (%d) or sy (%d)\n", bx, by, sx, sy); - face_num = 0; - } - /* single part object, multipart object with non merged faces, - * of multipart object already at lower right. - */ - else if (bx == sx && by == sy) - { - face_num = ob->face->number; - - /* if this face matches one stored away, clear that one away. - * this code relies on the fact that the map1 commands - * goes from 2 down to 0. - */ - for (i = 0; i < MAP_LAYERS; i++) - if (heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + i] && - heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + i]->face->number == face_num) - heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + i] = NULL; - } - else - { - /* If this head is stored away, clear it - otherwise, - * there can be cases where a object is on multiple layers - - * we only want to send it once. - */ - face_num = head->face->number; - for (i = 0; i < MAP_LAYERS; i++) - if (heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + i] && - heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + i]->face->number == face_num) - heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + i] = NULL; - - /* First, try to put the new head on the same layer. If that is used up, - * then find another layer. - */ - if (heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + layer] == NULL) - { - heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + layer] = head; - } - else - for (i = 0; i < MAX_LAYERS; i++) - { - if (heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + i] == NULL || - heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + i] == head) - { - heads[(by * MAX_HEAD_POS + bx) * MAX_LAYERS + i] = head; - } - } - face_num = 0; /* Don't send this object - we'll send the head later */ - } - } - else - { - /* In this case, we are already at the lower right or single part object, - * so nothing special - */ - face_num = ob->face->number; - - /* clear out any head entries that have the same face as this one */ - for (bx = 0; bx < layer; bx++) - if (heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + bx] && - heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + bx]->face->number == face_num) - heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + bx] = NULL; - } - } /* else not already head object or blank face */ - - /* This is a real hack. Basically, if we have nothing to send for this layer, - * but there is a head on the next layer, send that instead. - * Without this, what happens is you can get the case where the player stands - * on the same space as the head. However, if you have overlapping big objects - * of the same type, what happens then is it doesn't think it needs to send - * This tends to make stacking also work/look better. - */ - if (!face_num && layer > 0 && heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + layer - 1]) - { - face_num = heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + layer - 1]->face->number; - heads[(sy * MAX_HEAD_POS + sx) * MAX_LAYERS + layer - 1] = NULL; - } - - /* Another hack - because of heads and whatnot, this face may match one - * we already sent for a lower layer. In that case, don't send - * this one. - */ - if (face_num && layer + 1 < MAP_LAYERS && ns.lastmap.cells[sx][sy].faces[layer + 1] == face_num) - face_num = 0; + /* In this case, we are already at the lower right or single part object, + * so nothing special + */ + face_num = ob->face; /* We've gotten what face we want to use for the object. Now see if * if it has changed since we last sent it to the client. @@ -1512,8 +1274,8 @@ else { smoothlevel = ob->smoothlevel; - if (smoothlevel && !(ns.faces_sent[ob->face->number] & NS_FACESENT_SMOOTH)) - SendSmooth (&ns, ob->face->number); + if (smoothlevel && !(ns.faces_sent[ob->face] & NS_FACESENT_SMOOTH)) + SendSmooth (&ns, ob->face); } /* else not already head object or blank face */ /* We've gotten what face we want to use for the object. Now see if @@ -1649,9 +1411,6 @@ estartlen = 0; } - /* Init data to zero */ - memset (heads, 0, sizeof (object *) * MAX_HEAD_POS * MAX_HEAD_POS * MAX_LAYERS); - /* x,y are the real map locations. ax, ay are viewport relative * locations. */ @@ -1690,10 +1449,6 @@ sl << uint16 (mask); - if (check_head (sl, socket, ax, ay, 2)) mask |= 0x4; - if (check_head (sl, socket, ax, ay, 1)) mask |= 0x2; - if (check_head (sl, socket, ax, ay, 0)) mask |= 0x1; - /* If all we are doing is sending 0 (blank) faces, we don't * actually need to send that - just the coordinates * with no faces tells the client to blank out the @@ -1740,7 +1495,7 @@ if (lastcell.count != -1) { sl << uint16 (mask); - map_clearcell (&lastcell, 0, 0, 0, -1); + map_clearcell (&lastcell, -1); } } else if (d > 3) @@ -1762,25 +1517,12 @@ count = -1; - if (socket.mapmode == Map1aCmd && have_head (ax, ay)) - { - /* Now check to see if any heads need to be sent */ - - if (check_head (sl, socket, ax, ay, 2)) mask |= 0x4; - if (check_head (sl, socket, ax, ay, 1)) mask |= 0x2; - if (check_head (sl, socket, ax, ay, 0)) mask |= 0x1; - - lastcell.count = count; - } - else - { - /* properly clear a previously sent big face */ - if (lastcell.faces[0] != 0 || lastcell.faces[1] != 0 || lastcell.faces[2] != 0 - || lastcell.stat_hp || lastcell.flags || lastcell.player) - need_send = 1; + /* properly clear a previously sent big face */ + if (lastcell.faces[0] != 0 || lastcell.faces[1] != 0 || lastcell.faces[2] != 0 + || lastcell.stat_hp || lastcell.flags || lastcell.player) + need_send = 1; - map_clearcell (&lastcell, 0, 0, 0, count); - } + map_clearcell (&lastcell, count); if ((mask & 0xf) || need_send) sl[oldlen + 1] = mask & 0xff; @@ -1923,15 +1665,15 @@ if (nx == pl->x && ny == pl->y && pl->invisible & (pl->invisible < 50 ? 4 : 1)) { - if (lastcell.faces[0] != pl->face->number) + if (lastcell.faces[0] != pl->face) { - lastcell.faces[0] = pl->face->number; + lastcell.faces[0] = pl->face; mask |= 0x1; - if (!(socket.faces_sent[pl->face->number] & NS_FACESENT_FACE)) - esrv_send_face (&socket, pl->face->number, 0); + if (!(socket.faces_sent[pl->face] & NS_FACESENT_FACE)) + esrv_send_face (&socket, pl->face, 0); - sl << uint16 (pl->face->number); + sl << uint16 (pl->face); } } else @@ -1993,10 +1735,8 @@ draw_client_map (object *pl) { int i, j; - sint16 ax, ay, nx, ny; /* ax and ay goes from 0 to max-size of arrays */ - facetile *face, *floor; - facetile *floor2; - int d, mflags; + sint16 ax, ay; /* ax and ay goes from 0 to max-size of arrays */ + int mflags; struct Map newmap; maptile *m, *pm; @@ -2187,7 +1927,7 @@ static void append_spell (player *pl, packet &sl, object *spell) { - int len, i, skill = 0; + int i, skill = 0; if (!(spell->name)) { @@ -2211,6 +1951,13 @@ } } + // spells better have a face + if (!spell->face) + { + LOG (llevError, "%s: spell has no face, but face is mandatory.\n", &spell->name); + spell->face = face_find ("burnout.x11", blank_face); + } + /* send the current values */ sl << uint32 (spell->count) << uint16 (spell->level) @@ -2220,7 +1967,7 @@ << uint16 (spell->last_eat) << uint8 (skill) << uint32 (spell->path_attuned) - << uint32 (spell->face ? spell->face->number : 0) + << uint32 (spell->face) << data8 (spell->name) << data16 (spell->msg); } @@ -2245,7 +1992,7 @@ if (!spell) { - for (spell = pl->ob->inv; spell != NULL; spell = spell->below) + for (spell = pl->ob->inv; spell; spell = spell->below) { /* were we to simply keep appending data here, we could exceed * MAXSOCKBUF if the player has enough spells to add, we know that