/// Dumps given buffer into file pointed to by a handle. void WriteDump(FILE* fp, const void* buffer, size_t length) { size_t i; char hex[48+1], ascii[16+1]; fprintf(fp, "--- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F 0123456789ABCDEF\n"); ascii[16] = 0; for( i = 0; i < length; i++ ) { char c = RBUFB(buffer,i); ascii[i%16] = ISCNTRL(c) ? '.' : c; sprintf(hex+(i%16)*3, "%02X ", RBUFB(buffer,i)); if( (i%16) == 15 ) { fprintf(fp, "%03X %s %s\n", (unsigned int)(i/16), hex, ascii); } } if( (i%16) != 0 ) { ascii[i%16] = 0; fprintf(fp, "%03X %-48s %-16s\n", (unsigned int)(i/16), hex, ascii); } }
/// Dumps given buffer on the console. void ShowDump(const void* buffer, size_t length) { size_t i; char hex[48+1], ascii[16+1]; ShowDebug("--- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F 0123456789ABCDEF\n"); ascii[16] = 0; for( i = 0; i < length; i++ ) { char c = RBUFB(buffer,i); ascii[i%16] = ISCNTRL(c) ? '.' : c; sprintf(hex+(i%16)*3, "%02X ", RBUFB(buffer,i)); if( (i%16) == 15 ) { ShowDebug("%03X %s %s\n", i/16, hex, ascii); } } if( (i%16) != 0 ) { ascii[i%16] = 0; ShowDebug("%03X %-48s %-16s\n", i/16, hex, ascii); } }
CCharEmotionPacket::CCharEmotionPacket(CCharEntity * PChar, int8* buff) { this->type = 0x5a; this->size = 0x0c; WBUFL(data,(0x04)-4) = PChar->id; WBUFW(data,(0x0C)-4) = PChar->targid; WBUFL(data,(0x08)-4) = RBUFL(buff,(0x04)); WBUFW(data,(0x0E)-4) = RBUFW(buff,(0x08)); uint8 emoteID = RBUFB(buff,(0x0A)); if (emoteID == 0x4A) { uint8 offset = RBUFB(buff,(0x0C)) - 0x1F; WBUFB(data,(0x10)-4) = emoteID + offset; WBUFB(data,(0x12)-4) = offset; }else{ WBUFB(data,(0x10)-4) = emoteID; CItem * weapon = PChar->getStorage(LOC_INVENTORY)->GetItem(PChar->equip[SLOT_MAIN]); if (weapon != NULL && weapon->getID() != 0xFFFF) { WBUFW(data,(0x12)-4) = weapon->getID(); } } WBUFB(data,(0x16)-4) = RBUFB(buff,(0x0B)); }
CAddtoEquipSet::CAddtoEquipSet(int8* orig) { //Im guessing this is here to check if you can use A Item, as it seems useless to have this sent to server //as It will check requirements when it goes to equip the items anyway //0x04 is slot of updated item //0x08 is info for updated item //0x0C is first slot every 4 bytes is another set, in (01-equip 0-2 remve),(container),(ID),(ID) //in this list the slot of whats being updated is old value, replace with new in 116 //Should Push 0x116 (size 68) in responce //0x04 is start, contains 16 4 byte parts repersently each slot in order this->type = 0x16; this->size = 0x23; uint8 slotID = RBUFB(orig, 0x04); for (int i = 0; i < 0x10; i++) { if (i == slotID) { WBUFB(data, (0x04) + (0x04 * i) ) = RBUFB(orig, 0x08); WBUFB(data, (0x05) + (0x04 * i) ) = RBUFB(orig, 0x09); WBUFB(data, (0x06) + (0x04 * i) ) = RBUFB(orig, 0x0A); WBUFB(data, (0x07) + (0x04 * i) ) = RBUFB(orig, 0x0B); } else { WBUFB(data, (0x04) + (0x04 * i) ) = RBUFB(orig, 0x0C + (0x04 * i)); WBUFB(data, (0x05) + (0x04 * i) ) = RBUFB(orig, 0x0D + (0x04 * i)); WBUFB(data, (0x06) + (0x04 * i) ) = RBUFB(orig, 0x0E + (0x04 * i)); WBUFB(data, (0x07) + (0x04 * i) ) = RBUFB(orig, 0x0F + (0x04 * i)); } } }
void HandleAuctionHouseRequest(CTCPRequestPacket* PTCPRequest) { uint8* data = (uint8*)PTCPRequest->GetData(); uint8 AHCatID = RBUFB(data,(0x16)); //2 - уровень -- level //3 - раса -- race //4 - профессия -- job //5 - урон -- damage //6 - задержка -- delay //7 - защита -- defense //8 - сопротивление -- resistance //9 - название -- name string_t OrderByString = "ORDER BY"; uint8 paramCount = RBUFB(data,0x12); for (uint8 i = 0; i < paramCount; ++i) // параметры сортировки предметов { uint8 param = RBUFL(data,(0x18)+8*i); ShowMessage(" Param%u: %u\n", i, param); switch (param) { case 2: OrderByString.append(" item_armor.level DESC,"); case 5: OrderByString.append(" item_weapon.dmg DESC,"); case 6: OrderByString.append(" item_weapon.delay DESC,"); case 9: OrderByString.append(" item_basic.sortname,"); } } OrderByString.append(" item_basic.itemid"); int8* OrderByArray = (int8*)OrderByString.data(); CDataLoader* PDataLoader = new CDataLoader(); std::vector<ahItem*> ItemList = PDataLoader->GetAHItemsToCategory(AHCatID,OrderByArray); uint8 PacketsCount = (ItemList.size() / 20) + (ItemList.size() % 20 != 0) + (ItemList.size() == 0); for(uint8 i = 0; i < PacketsCount; ++i) { CAHItemsListPacket* PAHPacket = new CAHItemsListPacket(20*i); PAHPacket->SetItemCount(ItemList.size()); for (uint16 y = 20*i; (y != 20*(i+1)) && (y < ItemList.size()); ++y) { PAHPacket->AddItem(ItemList.at(y)); } PTCPRequest->SendToSocket(PAHPacket->GetData(), PAHPacket->GetSize()); delete PAHPacket; } delete PDataLoader; }
void HandleAuctionHouseHistoru(CTCPRequestPacket* PTCPRequest) { uint8* data = (uint8*)PTCPRequest->GetData(); uint16 ItemID = RBUFW(data,(0x12)); uint8 stack = RBUFB(data,(0x15)); CAHHistoryPacket* PAHPacket = new CAHHistoryPacket(ItemID); CDataLoader* PDataLoader = new CDataLoader(); std::vector<ahHistory*> HistoryList = PDataLoader->GetAHItemHystory(ItemID, stack != 0); for (uint8 i = 0; i < HistoryList.size(); ++i) { PAHPacket->AddItem(HistoryList.at(i)); } PTCPRequest->SendToSocket(PAHPacket->GetData(), PAHPacket->GetSize()); delete PDataLoader; delete PAHPacket; }
int32 parse(int8* buff, size_t* buffsize, sockaddr_in* from, map_session_data_t* map_session_data) { // начало обработки входящего пакета int8* PacketData_Begin = &buff[FFXI_HEADER_SIZE]; int8* PacketData_End = &buff[*buffsize]; CCharEntity *PChar = map_session_data->PChar; uint16 SmallPD_Size = 0; uint16 SmallPD_Type = 0; uint16 SmallPD_Code = RBUFW(buff, 0); for (int8* SmallPD_ptr = PacketData_Begin; SmallPD_ptr + (RBUFB(SmallPD_ptr, 1) & 0xFE) * 2 <= PacketData_End && (RBUFB(SmallPD_ptr, 1) & 0xFE); SmallPD_ptr = SmallPD_ptr + SmallPD_Size * 2) { SmallPD_Size = (RBUFB(SmallPD_ptr, 1) & 0x0FE); SmallPD_Type = (RBUFW(SmallPD_ptr, 0) & 0x1FF); if (PacketSize[SmallPD_Type] == SmallPD_Size || PacketSize[SmallPD_Type] == 0) // Tests incoming packets for the correct size prior to processing { // если код текущего пакета меньше либо равен последнему полученному // или больше глобального то игнорируем пакет if ((RBUFW(SmallPD_ptr, 2) <= map_session_data->client_packet_id) || (RBUFW(SmallPD_ptr, 2) > SmallPD_Code)) { continue; } if (SmallPD_Type != 0x15) { ShowInfo("parse: %03hX | %04hX %04hX %02hX from user: %s\n", SmallPD_Type, RBUFW(SmallPD_ptr, 2), RBUFW(buff, 2), SmallPD_Size, PChar->GetName()); } if (PChar->loc.zone == nullptr && SmallPD_Type != 0x0A) { ShowWarning("This packet is unexpected from %s - Received %03hX earlier without matching 0x0A\n", PChar->GetName(), SmallPD_Type); } else { PacketParser[SmallPD_Type](map_session_data, PChar, CBasicPacket(reinterpret_cast<uint8*>(SmallPD_ptr))); } } else { ShowWarning("Bad packet size %03hX | %04hX %04hX %02hX from user: %s\n", SmallPD_Type, RBUFW(SmallPD_ptr, 2), RBUFW(buff, 2), SmallPD_Size, PChar->GetName()); } } ((CAICharNormal*)PChar->PBattleAI)->CheckActionAfterReceive(gettick()); map_session_data->client_packet_id = SmallPD_Code; // здесь мы проверяем, получил ли клиент предыдущий пакет // если не получил, то мы не создаем новый, а отправляем предыдущий if (RBUFW(buff, 2) != map_session_data->server_packet_id) { WBUFW(map_session_data->server_packet_data, 2) = SmallPD_Code; WBUFW(map_session_data->server_packet_data, 8) = (uint32)time(nullptr); g_PBuff = map_session_data->server_packet_data; *buffsize = map_session_data->server_packet_size; map_session_data->server_packet_data = buff; return -1; } // увеличиваем номер отправленного пакета только в случае отправки новых данных map_session_data->server_packet_id += 1; return 0; }
void EmptyHandler(session_data_t* session, CPlayer* PPlayer, int8* data) { ShowWarning(CL_YELLOW"packet parser: unhandled packet %02hX from username %s\n" CL_RESET, RBUFB(data, 0), PPlayer->GetName()); }
search_req _HandleSearchRequest(CTCPRequestPacket* PTCPRequest, SOCKET socket) { // суть в том, чтобы заполнить некоторую структуру, на основании которой будет создан запрос к базе // результат поиска в базе отправляется клиенту uint32 bitOffset = 0; unsigned char sortDescending = 0; unsigned char isPresent = 0; unsigned char areaCount = 0; uint8 name[16]; uint8 nameLen = 0; uint8 minLvl = 0; uint8 maxLvl = 0; uint8 jobid = 0; uint16 areas[10]; uint8* data = (uint8*)PTCPRequest->GetData(); uint8 size = RBUFB(data,(0x10)); uint16 workloadBits = size * 8; memset(areas, 0, sizeof(areas)); //ShowMessage("Received a search packet with size %u byte\n", size); while(bitOffset < workloadBits) { if ((bitOffset+5) >= workloadBits) { bitOffset = workloadBits; break; } uint8 EntryType = (uint8)unpackBitsLE(&data[0x11], bitOffset, 5); bitOffset+=5; if ((EntryType != SEARCH_FRIEND) && (EntryType != SEARCH_LINKSHELL) && (EntryType != SEARCH_COMMENT) && (EntryType != SEARCH_FLAGS2)) { if ((bitOffset+3) >= workloadBits) //so 0000000 at the end does not get interpretet as name entry ... { bitOffset=workloadBits; break; } sortDescending = (unsigned char)unpackBitsLE(&data[0x11],bitOffset,1); bitOffset+=1; isPresent = (unsigned char)unpackBitsLE(&data[0x11],bitOffset,1); bitOffset+=1; } switch(EntryType) { case SEARCH_NAME: { if (isPresent==0x1) //Name send { if ((bitOffset+5) >= workloadBits) { bitOffset=workloadBits; break; } nameLen = (unsigned char)unpackBitsLE(&data[0x11],bitOffset,5); name[nameLen]='\0'; bitOffset+=5; for (unsigned char i = 0; i < nameLen; i++) { name[i] = (char)unpackBitsLE(&data[0x11],bitOffset,7); bitOffset+=7; } //printf("SEARCH::Name Entry Found. (%s).\n",name); } //printf("SEARCH::SortByName: %s.\n",(sortDescending == 0 ? "ascending" : "descending")); //packetData.sortDescendingByName=sortDescending; break; } case SEARCH_AREA: //Area Code Entry - 10 bit { if (isPresent == 0) //no more Area entries { //printf("SEARCH::Area List End found.\n"); } else // 8 Bit = 1 Byte per Area Code { areas[areaCount] = (uint16)unpackBitsLE(&data[0x11],bitOffset,10); areaCount++; bitOffset+=10; // printf("SEARCH::Area List Entry found(%2X)!\n",areas[areaCount-1]); } break; } case SEARCH_NATION: //Country - 2 bit { if (isPresent==0x1) { unsigned char country = (unsigned char)unpackBitsLE(&data[0x11],bitOffset,2); bitOffset+=2; printf("SEARCH::Nationality Entry found. (%2X) Sorting: (%s).\n",country,(sortDescending==0x00)?"ascending":"descending"); } break; } case SEARCH_JOB: //Job - 5 bit { if (isPresent==0x1) { unsigned char job = (unsigned char)unpackBitsLE(&data[0x11],bitOffset,5); bitOffset+=5; jobid = job; //printf("SEARCH::Job Entry found. (%2X) Sorting: (%s).\n",job,(sortDescending==0x00)?"ascending":"descending"); } //packetData.sortDescendingByJob=sortDescending; //printf("SEARCH::SortByJob: %s.\n",(sortDescending==0x00)?"ascending":"descending"); break; } case SEARCH_LEVEL: //Level- 16 bit { if (isPresent==0x1) { unsigned char fromLvl = (unsigned char)unpackBitsLE(&data[0x11],bitOffset,8); bitOffset+=8; unsigned char toLvl = (unsigned char)unpackBitsLE(&data[0x11],bitOffset,8); bitOffset+=8; minLvl = fromLvl; maxLvl = toLvl; //printf("SEARCH::Level Entry found. (%d - %d) Sorting: (%s).\n",fromLvl,toLvl,(sortDescending==0x00)?"ascending":"descending"); } //packetData.sortDescendingByLevel=sortDescending; //printf("SEARCH::SortByLevel: %s.\n",(sortDescending==0x00)?"ascending":"descending"); break; } case SEARCH_RACE: //Race - 4 bit { if (isPresent==0x1) { unsigned char race = (unsigned char)unpackBitsLE(&data[0x11],bitOffset,4); bitOffset+=4; printf("SEARCH::Race Entry found. (%2X) Sorting: (%s).\n",race,(sortDescending==0x00)?"ascending":"descending"); } printf("SEARCH::SortByRace: %s.\n",(sortDescending==0x00)?"ascending":"descending"); //packetData.sortDescendingByRace=sortDescending; break; } case SEARCH_RANK: //Rank - 2 byte { if (isPresent==0x1) { unsigned char fromRank = (unsigned char)unpackBitsLE(&data[0x11],bitOffset,8); bitOffset+=8; unsigned char toRank = (unsigned char)unpackBitsLE(&data[0x11],bitOffset,8); bitOffset+=8; printf("SEARCH::Rank Entry found. (%d - %d) Sorting: (%s).\n",fromRank,toRank,(sortDescending==0x00)?"ascending":"descending"); } printf("SEARCH::SortByRank: %s.\n",(sortDescending==0x00)?"ascending":"descending"); //packetData.sortDescendingByRank=sortDescending; break; } case SEARCH_COMMENT: //4 Byte { unsigned int comment = (unsigned int)unpackBitsLE(&data[0x11],bitOffset,32); bitOffset+=32; printf("SEARCH::Comment Entry found. (%8X).\n",comment); break; } //the following 4 Entries were generated with /sea (ballista|friend|linkshell|away|inv) //so they may be off case SEARCH_LINKSHELL: // 4 Byte { unsigned int lsId= (unsigned int)unpackBitsLE(&data[0x11],bitOffset,32); bitOffset+=32; printf("SEARCH::Linkshell Entry found. Value: %.8X\n",lsId); break; } case SEARCH_FRIEND: // Friend Packet, 0 byte { printf("SEARCH::Friend Entry found.\n"); break; } case SEARCH_FLAGS1: // Flag Entry #1, 2 byte, { if (isPresent==0x1) { unsigned short flags1 = (unsigned short)unpackBitsLE(&data[0x11],bitOffset,16); bitOffset+=16; printf("SEARCH::Flag Entry #1 (%.4X) found. Sorting: (%s).\n",flags1,(sortDescending==0x00)?"ascending":"descending"); } printf("SEARCH::SortByFlags: %s\n",(sortDescending == 0? "ascending" : "descending")); //packetData.sortDescendingByFlags=sortDescending; break; } case SEARCH_FLAGS2: // Flag Entry #2 - 4 byte { unsigned int flags=(unsigned int)unpackBitsLE(&data[0x11],bitOffset,32); bitOffset+=32; /* if ((flags & 0xFFFF)!=(packetData.flags1)) { printf("SEARCH::Flag mismatch: %.8X != %.8X\n",flags,packetData.flags1&0xFFFF); } packetData.flags2=flags; printf("SEARCH::Flag Entry #2 (%.8X) found.\n",packetData.flags2); */ break; } default: { printf("SEARCH::Unknown Search Param %.2X!\n",EntryType); //outputPacket=true; break; } } } printf("\n"); ShowMessage("Name: %s Job: %u Lvls: %u ~ %u \n",(nameLen>0 ? name : 0),jobid,minLvl,maxLvl); search_req sr; sr.jobid = jobid; sr.maxlvl = maxLvl; sr.minlvl = minLvl; sr.nameLen = nameLen; memcpy(sr.zoneid, areas, sizeof(sr.zoneid)); if(nameLen>0){ sr.name.insert(0,(int8*)name); } return sr; // не обрабатываем последние биты, что мешает в одну кучу например "/blacklist delete Name" и "/sea all Name" }
uint8 CItemFurnishing::getCol() { return RBUFB(m_extra, 0x06); }
uint8 CItemFurnishing::getRotation() { return RBUFB(m_extra, 0x09); }
uint8 CItemFurnishing::getLevel() { return RBUFB(m_extra, 0x07); }
uint8 CItemFurnishing::getRow() { return RBUFB(m_extra, 0x08); }
int32 parse(int8* buff, size_t* buffsize, sockaddr_in* from, map_session_data_t* map_session_data) { // начало обработки входящего пакета int8* PacketData_Begin = &buff[FFXI_HEADER_SIZE]; int8* PacketData_End = &buff[*buffsize]; CCharEntity *PChar = map_session_data->PChar; uint16 SmallPD_Size = 0; uint16 SmallPD_Type = 0; uint16 SmallPD_Code = RBUFW(buff,0); for(int8* SmallPD_ptr = PacketData_Begin; SmallPD_ptr + (RBUFB(SmallPD_ptr,1) & 0xFE)*2 <= PacketData_End && (RBUFB(SmallPD_ptr,1) & 0xFE); SmallPD_ptr = SmallPD_ptr + SmallPD_Size*2) { SmallPD_Size = (RBUFB(SmallPD_ptr,1) & 0x0FE); SmallPD_Type = (RBUFW(SmallPD_ptr,0) & 0x1FF); if(PacketSize[SmallPD_Type] == SmallPD_Size || PacketSize[SmallPD_Type] == 0) // Tests incoming packets for the correct size prior to processing { // если код текущего пакета меньше либо равен последнему полученному // или больше глобального то игнорируем пакет if ((RBUFW(SmallPD_ptr,2) <= map_session_data->client_packet_id) || (RBUFW(SmallPD_ptr,2) > SmallPD_Code)) { continue; } if (SmallPD_Type != 0x15) { ShowInfo("parse: %03hX | %04hX %04hX %02hX from user: %s\n", SmallPD_Type, RBUFW(SmallPD_ptr,2), RBUFW(buff,2), SmallPD_Size, PChar->GetName()); } if (PChar->loc.zone == NULL && SmallPD_Type != 0x0A) { ShowWarning("This packet is unexpected from %s - Received %03hX earlier without matching 0x0A\n", PChar->GetName(), SmallPD_Type); } else { PacketParser[SmallPD_Type](map_session_data, PChar, SmallPD_ptr); } } else { ShowWarning("Bad packet size %03hX | %04hX %04hX %02hX from user: %s\n", SmallPD_Type, RBUFW(SmallPD_ptr,2), RBUFW(buff,2), SmallPD_Size, PChar->GetName()); } } map_session_data->client_packet_id = SmallPD_Code; // здесь мы проверяем, получил ли клиент предыдущий пакет // если не получил, то мы не создаем новый, а отправляем предыдущий if (RBUFW(buff,2) != map_session_data->server_packet_id) { WBUFW(map_session_data->server_packet_data,2) = SmallPD_Code; WBUFW(map_session_data->server_packet_data,8) = (uint32)time(NULL); g_PBuff = map_session_data->server_packet_data; *buffsize = map_session_data->server_packet_size; map_session_data->server_packet_data = buff; return -1; } // увеличиваем номер отправленного пакета только в случае отправки новых данных map_session_data->server_packet_id += 1; // собираем большой пакет, состоящий из нескольких маленьких CBasicPacket* PSmallPacket; *buffsize = FFXI_HEADER_SIZE; while(!PChar->isPacketListEmpty() && *buffsize + PChar->firstPacketSize()*2 < map_config.buffer_size ) { PSmallPacket = PChar->popPacket(); PSmallPacket->setCode(map_session_data->server_packet_id); memcpy(buff+*buffsize, PSmallPacket, PSmallPacket->getSize()*2); *buffsize += PSmallPacket->getSize()*2; delete PSmallPacket; } return 0; }
void CZoneEntities::PushPacket(CBaseEntity* PEntity, GLOBAL_MESSAGE_TYPE message_type, CBasicPacket* packet) { // Do not send packets that are updates of a hidden GM.. if (packet != NULL && packet->getType() == 0x0D && PEntity != NULL && PEntity->objtype == TYPE_PC && ((CCharEntity*)PEntity)->m_isGMHidden) { // Ensure this packet is not despawning us.. if (packet->getData()[0x06] != 0x20) { delete packet; return; } } if (!m_charList.empty()) { switch (message_type) { case CHAR_INRANGE_SELF: { if (PEntity->objtype == TYPE_PC) { ((CCharEntity*)PEntity)->pushPacket(new CBasicPacket(*packet)); } } case CHAR_INRANGE: { for (EntityList_t::const_iterator it = m_charList.begin(); it != m_charList.end(); ++it) { CCharEntity* PCurrentChar = (CCharEntity*)it->second; if (PEntity != PCurrentChar) { if (distance(PEntity->loc.p, PCurrentChar->loc.p) < 50) { if (packet != NULL && packet->getType() == 0x0E && (RBUFB(packet->getData(), (0x0A) - 4) != 0x20 || RBUFB(packet->getData(), (0x0A) - 4) != 0x0F)) { uint32 id = RBUFL(packet->getData(), (0x04) - 4); uint16 targid = RBUFW(packet->getData(), (0x08) - 4); CBaseEntity* entity = GetEntity(targid); SpawnIDList_t spawnlist; if (entity) { if (entity->targid < 0x400) { if (entity->objtype == TYPE_MOB) { spawnlist = PCurrentChar->SpawnMOBList; } else if (entity->objtype == TYPE_NPC) { spawnlist = PCurrentChar->SpawnNPCList; } } else if (entity->targid >= 0x700) { spawnlist = PCurrentChar->SpawnPETList; } else { entity = NULL; } } if (!entity) { // got a char or nothing as the target of this entity update (which really shouldn't happen ever) // so we're just going to skip this packet break; } SpawnIDList_t::iterator iter = spawnlist.lower_bound(id); if (!(iter == spawnlist.end() || spawnlist.key_comp()(id, iter->first))) { PCurrentChar->pushPacket(new CBasicPacket(*packet)); } } else { PCurrentChar->pushPacket(new CBasicPacket(*packet)); } } } } } break; case CHAR_INSHOUT: { for (EntityList_t::const_iterator it = m_charList.begin(); it != m_charList.end(); ++it) { CCharEntity* PCurrentChar = (CCharEntity*)it->second; if (PEntity != PCurrentChar) { if (distance(PEntity->loc.p, PCurrentChar->loc.p) < 180) { PCurrentChar->pushPacket(new CBasicPacket(*packet)); } } } } break; case CHAR_INZONE: { for (EntityList_t::const_iterator it = m_charList.begin(); it != m_charList.end(); ++it) { CCharEntity* PCurrentChar = (CCharEntity*)it->second; if (PEntity != PCurrentChar) { PCurrentChar->pushPacket(new CBasicPacket(*packet)); } } } break; } } delete packet; }