--- deliantra/server/socket/request.C 2006/08/13 17:16:06 1.1 +++ deliantra/server/socket/request.C 2006/08/21 07:13:32 1.7 @@ -1,6 +1,6 @@ /* * static char *rcsid_init_c = - * "$Id: request.C,v 1.1 2006/08/13 17:16:06 elmex Exp $"; + * "$Id: request.C,v 1.7 2006/08/21 07:13:32 root Exp $"; */ /* @@ -106,39 +106,131 @@ -1 /* Disease - not fully done yet */ }; +static void +socket_map_scroll (NewSocket *ns, int dx, int dy) +{ + struct Map newmap; + int x,y, mx, my; + + { + char buf[MAXSOCKBUF]; + + sprintf(buf,"map_scroll %d %d", dx, dy); + Write_String_To_Socket(ns, buf, strlen (buf)); + } + + /* If we are using the Map1aCmd, we may in fact send + * head information that is outside the viewable map. + * So set the mx,my to the max value we want to + * look for. Removed code to do so - it caused extra + * complexities for the client, and probably doesn't make + * that much difference in bandwidth. + */ + mx = ns->mapx; + my = ns->mapy; + + if (ns->mapmode == Map1aCmd) { + mx += MAX_HEAD_OFFSET; + my += MAX_HEAD_OFFSET; + } + + /* the x and y here are coordinates for the new map, i.e. if we moved + * (dx,dy), newmap[x][y] = oldmap[x-dx][y-dy]. For this reason, + * if the destination x or y coordinate is outside the viewable + * area, we clear the values - otherwise, the old values + * are preserved, and the check_head thinks it needs to clear them. + */ + for(x=0; x= ns->mapx || y >= ns->mapy) { + /* clear cells outside the viewable area */ + memset(&newmap.cells[x][y], 0, sizeof(struct MapCell)); + } + else if ((x+dx) < 0 || (x+dx) >= ns->mapx || (y+dy) < 0 || (y + dy) >= ns->mapy) { + /* clear newly visible tiles within the viewable area */ + memset(&(newmap.cells[x][y]), 0, sizeof(struct MapCell)); + } + else { + memcpy(&(newmap.cells[x][y]), + &(ns->lastmap.cells[x+dx][y+dy]),sizeof(struct MapCell)); + } + } + } + + memcpy(&(ns->lastmap), &newmap,sizeof(struct Map)); + + /* Make sure that the next "map1" command will be sent (even if it is + * empty). + */ + ns->sent_scroll = 1; +} + +static void +clear_map (player *pl) +{ + NewSocket &socket = pl->socket; + + memset (&socket.lastmap, 0, sizeof (socket.lastmap)); + + if (socket.newmapcmd == 1) + Write_String_To_Socket (&socket, "newmap", 6); + + socket.update_look = 1; + socket.look_position = 0; +} + /** check for map change and send new map data */ static void check_map_change (player *pl) { + NewSocket &socket = pl->socket; + object *ob = pl->ob; char buf[MAX_BUF]; /* eauugggh */ - object *ob = pl->ob; + if (socket.current_map != ob->map) + { + socket.current_map = ob->map; - if (!pl->socket.mapinfocmd) - return; + clear_map (pl); + + if (socket.mapinfocmd) + { + if (ob->map && ob->map->path [0]) + { + int flags = 0; - if (pl->socket.current_map != ob->map) + 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); + } + else + snprintf (buf, MAX_BUF, "mapinfo current"); + + Write_String_To_Socket (&socket, buf, strlen (buf)); + } + } + else if (socket.current_x != ob->x || socket.current_y != ob->y) { - pl->socket.current_map = ob->map; + int dx = ob->x - socket.current_x; + int dy = ob->y - socket.current_y; - if (ob->map && ob->map->path [0]) + if (socket.buggy_mapscroll && (abs (dx) > 8 || abs (dy) > 8)) + clear_map (pl); // current (<= 1.9.1) clients have unchecked buffer overflows + else { - 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, pl->socket.mapx / 2 - ob->x, pl->socket.mapy / 2 - ob->y, - ob->map->width, ob->map->height, ob->map->path); + socket_map_scroll (&socket, ob->x - socket.current_x, ob->y - socket.current_y); + socket.update_look = 1; + socket.look_position = 0; } - else - snprintf (buf, MAX_BUF, "mapinfo current"); - - Write_String_To_Socket (&pl->socket, buf, strlen (buf)); } + + socket.current_x = ob->x; + socket.current_y = ob->y; } void ExtCmd (char *buf, int len, player *pl) @@ -295,6 +387,9 @@ } else if (!strcmp(cmd,"extcmd")) { ns->extcmd = atoi(param); safe_strcat(cmdback, "1", &slen, HUGE_BUF); + } else if (!strcmp(cmd,"extmap")) { + ns->extmap = atoi(param); + safe_strcat(cmdback, "1", &slen, HUGE_BUF); } else if (!strcmp(cmd,"facecache")) { ns->facecache = atoi(param); safe_strcat(cmdback, param, &slen, HUGE_BUF); @@ -747,6 +842,8 @@ if (cp) { LOG(llevDebug,"CS: connection from client of type <%s>, ip %s\n", cp, ns->host); + snprintf (ns->client, sizeof (ns->client), "%s", cp + 1); + /* This is first implementation - i skip all beta DX clients with it * Add later stuff here for other clients */ @@ -790,18 +887,6 @@ #endif } -/** Newmap command */ -void MapNewmapCmd( player *pl) -{ - if( pl->socket.newmapcmd == 1) { - memset(&pl->socket.lastmap, 0, sizeof(pl->socket.lastmap)); - Write_String_To_Socket( &pl->socket, "newmap", 6); - } - pl->socket.current_map = 0; -} - - - /** * Moves an object (typically, container to inventory). * syntax is: move (to) (tag) (nrof) @@ -1204,10 +1289,11 @@ /** Clears a map cell */ static void map_clearcell(struct MapCell *cell, int face0, int face1, int face2, int count) { - cell->count=count; cell->faces[0] = face0; cell->faces[1] = face1; cell->faces[2] = face2; + cell->count = count; + cell->stat_hp = 0; } #define MAX_HEAD_POS MAX(MAX_CLIENT_X, MAX_CLIENT_Y) @@ -1242,7 +1328,7 @@ * if needed, and returning 1. If this no data needs to get * sent, it returns zero. */ -static inline int check_head(SockList *sl, NewSocket *ns, int ax, int ay, int layer) +static int check_head (SockList &sl, NewSocket &ns, int ax, int ay, int layer) { short face_num; @@ -1251,12 +1337,12 @@ else face_num = 0; - if (face_num != ns->lastmap.cells[ax][ay].faces[layer]) { - SockList_AddShort(sl, face_num); - if (face_num && !(ns->faces_sent[face_num] & NS_FACESENT_FACE)) - esrv_send_face(ns, face_num, 0); + if (face_num != ns.lastmap.cells[ax][ay].faces[layer]) { + SockList_AddShort (&sl, 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; + ns.lastmap.cells[ax][ay].faces[layer] = face_num; return 1; } @@ -1283,7 +1369,7 @@ * actually match. */ -static inline int update_space(SockList *sl, NewSocket *ns, mapstruct *mp, int mx, int my, int sx, int sy, int layer) +static int update_space(SockList *sl, NewSocket *ns, mapstruct *mp, int mx, int my, int sx, int sy, int layer) { object *ob, *head; uint16 face_num; @@ -1562,27 +1648,30 @@ uint16 ewhatstart,ewhatflag; uint8 extendedinfos; mapstruct *m; + NewSocket &socket = pl->contr->socket; + + check_map_change (pl->contr); sl.buf=(unsigned char*)malloc(MAXSOCKBUF); - if (pl->contr->socket.mapmode == Map1Cmd) + if (socket.mapmode == Map1Cmd) strcpy((char*)sl.buf,"map1 "); else strcpy((char*)sl.buf,"map1a "); sl.len=strlen((char*)sl.buf); startlen = sl.len; /*Extendedmapinfo structure initialisation*/ - if (pl->contr->socket.ext_mapinfos){ + if (socket.ext_mapinfos){ esl.buf=(unsigned char*)malloc(MAXSOCKBUF); strcpy((char*)esl.buf,"mapextended "); esl.len=strlen((char*)esl.buf); extendedinfos=EMI_NOREDRAW; - if (pl->contr->socket.EMI_smooth) + if (socket.EMI_smooth) extendedinfos|=EMI_SMOOTH; ewhatstart=esl.len; ewhatflag=extendedinfos; /*The EMI_NOREDRAW bit could need to be taken away*/ SockList_AddChar(&esl, extendedinfos); - eentrysize=getExtendedMapInfoSize(&(pl->contr->socket)); + eentrysize=getExtendedMapInfoSize(&socket); SockList_AddChar(&esl, eentrysize); estartlen = esl.len; } else { @@ -1602,16 +1691,16 @@ /* 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+(pl->contr->socket.mapx+1)/2; - max_y = pl->y+(pl->contr->socket.mapy+1)/2; - if (pl->contr->socket.mapmode == Map1aCmd) { + max_x = pl->x+(socket.mapx+1)/2; + max_y = pl->y+(socket.mapy+1)/2; + if (socket.mapmode == Map1aCmd) { max_x += MAX_HEAD_OFFSET; max_y += MAX_HEAD_OFFSET; } - for(y=pl->y-pl->contr->socket.mapy/2; yy-socket.mapy/2; yx-pl->contr->socket.mapx/2;xx-socket.mapx/2;x= pl->contr->socket.mapx || ay >= pl->contr->socket.mapy) { + if (ax >= socket.mapx || ay >= socket.mapy) { int i, got_one; oldlen = sl.len; - SockList_AddShort(&sl, mask); - if (check_head(&sl, &pl->contr->socket, ax, ay, 2)) + if (check_head (sl, socket, ax, ay, 2)) mask |= 0x4; - if (check_head(&sl, &pl->contr->socket, ax, ay, 1)) + if (check_head (sl, socket, ax, ay, 1)) mask |= 0x2; - if (check_head(&sl, &pl->contr->socket, ax, ay, 0)) + if (check_head (sl, socket, ax, ay, 0)) mask |= 0x1; /* If all we are doing is sending 0 (blank) faces, we don't @@ -1649,10 +1737,10 @@ if (got_one && (mask & 0xf)) { sl.buf[oldlen+1] = mask & 0xff; } else { /*either all faces blank, either no face at all*/ - if (mask & 0xf) /*at least 1 face, we know it's blank, only send coordinates*/ - sl.len = oldlen + 2; - else - sl.len = oldlen; + if (mask & 0xf) /*at least 1 face, we know it's blank, only send coordinates*/ + sl.len = oldlen + 2; + else + sl.len = oldlen; } /*What concerns extendinfos, nothing to be done for now * (perhaps effects layer later) @@ -1660,6 +1748,8 @@ continue; /* don't do processing below */ } + MapCell &lastcell = socket.lastmap.cells[ax][ay]; + d = pl->contr->blocked_los[ax][ay]; /* If the coordinates are not valid, or it is too dark to see, @@ -1673,9 +1763,9 @@ * if this hasn't already been done. If the space is out * of the map, it shouldn't have a head */ - if (pl->contr->socket.lastmap.cells[ax][ay].count != -1) { + if (lastcell.count != -1) { SockList_AddShort(&sl, mask); - map_clearcell(&pl->contr->socket.lastmap.cells[ax][ay],0,0,0,-1); + map_clearcell(&lastcell,0,0,0,-1); } } else if (d>3) { int need_send=0, count; @@ -1684,45 +1774,31 @@ */ oldlen = sl.len; -#if 0 - /* First thing we do is blank out this space (clear it) - * if not already done. If the client is using darkness, and - * this space is at the edge, we also include the darkness. - */ - if (d==4) { - if (pl->contr->socket.darkness && pl->contr->socket.lastmap.cells[ax][ay].count != d) { - mask |= 8; - SockList_AddShort(&sl, mask); - SockList_AddChar(&sl, 0); - } - count = d; - } else -#endif - { - SockList_AddShort(&sl, mask); - if (pl->contr->socket.lastmap.cells[ax][ay].count != -1) need_send=1; - count = -1; - } - if (pl->contr->socket.mapmode == Map1aCmd && have_head(ax, ay)) { + SockList_AddShort(&sl, mask); + if (lastcell.count != -1) need_send=1; + 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, &pl->contr->socket, ax, ay, 2)) + if (check_head (sl, socket, ax, ay, 2)) mask |= 0x4; - if (check_head(&sl, &pl->contr->socket, ax, ay, 1)) + if (check_head (sl, socket, ax, ay, 1)) mask |= 0x2; - if (check_head(&sl, &pl->contr->socket, ax, ay, 0)) + if (check_head (sl, socket, ax, ay, 0)) mask |= 0x1; - pl->contr->socket.lastmap.cells[ax][ay].count = count; + + lastcell.count = count; } else { - struct MapCell *cell = &pl->contr->socket.lastmap.cells[ax][ay]; + struct MapCell *cell = &lastcell; /* properly clear a previously sent big face */ if(cell->faces[0] != 0 || cell->faces[1] != 0 || cell->faces[2] != 0) need_send = 1; - map_clearcell(&pl->contr->socket.lastmap.cells[ax][ay], 0, 0, 0, count); + map_clearcell(&lastcell, 0, 0, 0, count); } if ((mask & 0xf) || need_send) { @@ -1751,65 +1827,89 @@ emask = (ax & 0x3f) << 10 | (ay & 0x3f) << 4; SockList_AddShort(&sl, mask); - if (pl->contr->socket.ext_mapinfos) + if (socket.ext_mapinfos) SockList_AddShort(&esl, emask); + unsigned char dummy; + unsigned char *last_ext = &dummy; + /* Darkness changed */ - if (pl->contr->socket.lastmap.cells[ax][ay].count != d && pl->contr->socket.darkness) { - pl->contr->socket.lastmap.cells[ax][ay].count = d; - mask |= 0x8; /* darkness bit */ - - /* Protocol defines 255 full bright, 0 full dark. - * We currently don't have that many darkness ranges, - * so we current what limited values we do have. - */ - if (d==0) SockList_AddChar(&sl, 255); - else if (d==1) SockList_AddChar(&sl, 191); - else if (d==2) SockList_AddChar(&sl, 127); - else if (d==3) SockList_AddChar(&sl, 63); - } - else { - /* need to reset from -1 so that if it does become blocked again, - * the code that deals with that can detect that it needs to tell - * the client that this space is now blocked. - */ - pl->contr->socket.lastmap.cells[ax][ay].count = d; + if (lastcell.count != d && socket.darkness) { + mask |= 0x8; + + if (socket.extmap) + { + *last_ext |= 0x80; last_ext = sl.buf + sl.len; SockList_AddChar (&sl, d); + } + else + SockList_AddChar (&sl, 255 - 64 * d); } + lastcell.count = d; + + if (socket.extmap) + { + uint8 stat_hp = 0; + uint8 stat_width = 0; + + // send hp information, if applicable + if (object *op = GET_MAP_FACE_OBJ (m, nx, ny, 0)) + if (!op->head + && op->stats.maxhp > 0 + && (unsigned)op->stats.maxhp > (unsigned)op->stats.hp + && IS_LIVE (op)) + { + stat_hp = 255 - (op->stats.hp * 255 + 254) / op->stats.maxhp; + stat_width = op->arch->tail_x; + } + + if (lastcell.stat_hp != stat_hp) + { + lastcell.stat_hp = stat_hp; + + mask |= 0x8; + *last_ext |= 0x80; last_ext = sl.buf + sl.len; SockList_AddChar (&sl, 5); + SockList_AddChar (&sl, stat_hp); + + if (stat_width > 1) + { + *last_ext |= 0x80; last_ext = sl.buf + sl.len; SockList_AddChar (&sl, 6); + SockList_AddChar (&sl, stat_width); + } + } + } + /* Floor face */ - if (update_space(&sl, &pl->contr->socket, m, nx, ny, ax, ay, 2)) + if (update_space(&sl, &socket, m, nx, ny, ax, ay, 2)) mask |= 0x4; - if (pl->contr->socket.EMI_smooth) - if (update_smooth(&esl, &pl->contr->socket, m, nx, ny, ax, ay, 2)){ + if (socket.EMI_smooth) + if (update_smooth(&esl, &socket, m, nx, ny, ax, ay, 2)) emask |= 0x4; - } /* Middle face */ - if (update_space(&sl, &pl->contr->socket, m, nx, ny, ax, ay, 1)) + if (update_space(&sl, &socket, m, nx, ny, ax, ay, 1)) mask |= 0x2; - if (pl->contr->socket.EMI_smooth) - if (update_smooth(&esl, &pl->contr->socket, m, nx, ny, ax, ay, 1)){ + if (socket.EMI_smooth) + if (update_smooth(&esl, &socket, m, nx, ny, ax, ay, 1)) emask |= 0x2; - } - if(nx == pl->x && ny == pl->y && pl->invisible & (pl->invisible < 50 ? 4 : 1)) { - if (pl->contr->socket.lastmap.cells[ax][ay].faces[0] != pl->face->number) { - pl->contr->socket.lastmap.cells[ax][ay].faces[0] = pl->face->number; + if (lastcell.faces[0] != pl->face->number) { + lastcell.faces[0] = pl->face->number; mask |= 0x1; - if (!(pl->contr->socket.faces_sent[pl->face->number] &NS_FACESENT_FACE)) - esrv_send_face(&pl->contr->socket, pl->face->number, 0); + if (!(socket.faces_sent[pl->face->number] &NS_FACESENT_FACE)) + esrv_send_face(&socket, pl->face->number, 0); SockList_AddShort(&sl, pl->face->number); } } /* Top face */ else { - if (update_space(&sl, &pl->contr->socket, m, nx, ny, ax, ay, 0)) + if (update_space(&sl, &socket, m, nx, ny, ax, ay, 0)) mask |= 0x1; - if (pl->contr->socket.EMI_smooth) - if (update_smooth(&esl, &pl->contr->socket, m, nx, ny, ax, ay, 0)){ + if (socket.EMI_smooth) + if (update_smooth(&esl, &socket, m, nx, ny, ax, ay, 0)){ emask |= 0x1; } } @@ -1833,8 +1933,8 @@ } /* for y loop */ /* Verify that we in fact do need to send this */ - if (pl->contr->socket.ext_mapinfos){ - if (!(sl.len>startlen || pl->contr->socket.sent_scroll)){ + if (socket.ext_mapinfos){ + if (!(sl.len>startlen || socket.sent_scroll)){ /* No map data will follow, so don't say the client * it doesn't need draw! */ @@ -1842,17 +1942,15 @@ esl.buf[ewhatstart+1] = ewhatflag & 0xff; } if (esl.len>estartlen) { - Send_With_Handling(&pl->contr->socket, &esl); + Send_With_Handling(&socket, &esl); } free(esl.buf); } - if (sl.len>startlen || pl->contr->socket.sent_scroll) { - Send_With_Handling(&pl->contr->socket, &sl); - pl->contr->socket.sent_scroll = 0; + if (sl.len>startlen || socket.sent_scroll) { + Send_With_Handling(&socket, &sl); + socket.sent_scroll = 0; } free(sl.buf); - - check_map_change (pl->contr); } /** @@ -1980,61 +2078,6 @@ } -void esrv_map_scroll(NewSocket *ns,int dx,int dy) -{ - struct Map newmap; - int x,y, mx, my; - char buf[MAXSOCKBUF]; - - sprintf(buf,"map_scroll %d %d", dx, dy); - Write_String_To_Socket(ns, buf, strlen(buf)); - - /* If we are using the Map1aCmd, we may in fact send - * head information that is outside the viewable map. - * So set the mx,my to the max value we want to - * look for. Removed code to do so - it caused extra - * complexities for the client, and probably doesn't make - * that much difference in bandwidth. - */ - mx = ns->mapx; - my = ns->mapy; - - if (ns->mapmode == Map1aCmd) { - mx += MAX_HEAD_OFFSET; - my += MAX_HEAD_OFFSET; - } - - /* the x and y here are coordinates for the new map, i.e. if we moved - * (dx,dy), newmap[x][y] = oldmap[x-dx][y-dy]. For this reason, - * if the destination x or y coordinate is outside the viewable - * area, we clear the values - otherwise, the old values - * are preserved, and the check_head thinks it needs to clear them. - */ - for(x=0; x= ns->mapx || y >= ns->mapy) { - /* clear cells outside the viewable area */ - memset(&newmap.cells[x][y], 0, sizeof(struct MapCell)); - } - else if ((x+dx) < 0 || (x+dx) >= ns->mapx || (y+dy) < 0 || (y + dy) >= ns->mapy) { - /* clear newly visible tiles within the viewable area */ - memset(&(newmap.cells[x][y]), 0, sizeof(struct MapCell)); - } - else { - memcpy(&(newmap.cells[x][y]), - &(ns->lastmap.cells[x+dx][y+dy]),sizeof(struct MapCell)); - } - } - } - - memcpy(&(ns->lastmap), &newmap,sizeof(struct Map)); - - /* Make sure that the next "map1" command will be sent (even if it is - * empty). - */ - ns->sent_scroll = 1; -} - /*****************************************************************************/ /* 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 */