void MapMgr::LoadAllCells() { // eek MapCell* cellInfo; CellSpawns* spawns; for(uint32 x = 0 ; x < _sizeX ; x ++) { for(uint32 y = 0 ; y < _sizeY ; y ++) { cellInfo = GetCell(x , y); if(!cellInfo) { // Cell doesn't exist, create it. // There is no spoon. Err... cell. cellInfo = Create(x , y); cellInfo->Init(x , y , this); LOG_DETAIL("Created cell [%u,%u] on map %u (instance %u)." , x , y , _mapId , m_instanceID); cellInfo->SetActivity(true); _map->CellGoneActive(x , y); ARCEMU_ASSERT(!cellInfo->IsLoaded()); spawns = _map->GetSpawnsList(x , y); if(spawns) cellInfo->LoadObjects(spawns); } else { // Cell exists, but is inactive if(!cellInfo->IsActive()) { LOG_DETAIL("Activated cell [%u,%u] on map %u (instance %u).", x, y, _mapId, m_instanceID); _map->CellGoneActive(x , y); cellInfo->SetActivity(true); if(!cellInfo->IsLoaded()) { //LOG_DETAIL("Loading objects for Cell [%u][%u] on map %u (instance %u)...", // posX, posY, this->_mapId, m_instanceID); spawns = _map->GetSpawnsList(x , y); if(spawns) cellInfo->LoadObjects(spawns); } } } } } }
void WorldSession::HandleQuestPushResult(WorldPacket & recvPacket) { CHECK_INWORLD_RETURN uint64 guid; uint8 msg; recvPacket >> guid; uint32 questid = 0; if(recvPacket.size() >= 13) //VLack: The client can send a 13 byte packet, where the result message is the 13th byte, and we have some data before it... Usually it is the quest id, but I have seen this as uint32(0) too. recvPacket >> questid; recvPacket >> msg; LOG_DETAIL("WORLD: Received MSG_QUEST_PUSH_RESULT"); if(GetPlayer()->GetQuestSharer()) { Player* pPlayer = objmgr.GetPlayer(GetPlayer()->GetQuestSharer()); if(pPlayer) { WorldPacket data(MSG_QUEST_PUSH_RESULT, 9); if(recvPacket.size() >= 13) //VLack: In case the packet was the longer one, its guid is the quest giver player, thus in the response we have to tell him that _this_ player reported the particular state. I think this type of response could also eliminate our SetQuestSharer/GetQuestSharer mess and its possible lock up conditions... data << uint64(_player->GetGUID()); else data << uint64(guid); data << uint8(msg); pPlayer->GetSession()->SendPacket(&data); GetPlayer()->SetQuestSharer(0); } } }
void Player::SendInitialLogonPackets() { // Initial Packets... they seem to be re-sent on port. //m_session->OutPacket(SMSG_SET_REST_START_OBSOLETE, 4, &m_timeLogoff); // Seem to be unused by client StackWorldPacket<32> data(SMSG_BINDPOINTUPDATE); data << float(m_bind_pos_x); data << float(m_bind_pos_y); data << float(m_bind_pos_z); data << uint32(m_bind_mapid); data << uint32(m_bind_zoneid); m_session->SendPacket(&data); //Proficiencies SendSetProficiency(4, armor_proficiency); SendSetProficiency(2, weapon_proficiency); //Tutorial Flags data.Initialize(SMSG_TUTORIAL_FLAGS); for (uint8 i = 0; i < 8; i++) data << uint32(m_Tutorials[i]); m_session->SendPacket(&data); smsg_TalentsInfo(false); smsg_InitialSpells(); data.Initialize(SMSG_SEND_UNLEARN_SPELLS); data << uint32(0); // count, for (count) uint32; GetSession()->SendPacket(&data); SendInitialActions(); smsg_InitialFactions(); data.Initialize(SMSG_LOGIN_SETTIMESPEED); data << uint32(Arcemu::Util::MAKE_GAME_TIME()); data << float(0.0166666669777748f); // Normal Game Speed data << uint32(0); // 3.1.2 m_session->SendPacket(&data); // cebernic for speedhack bug m_lastRunSpeed = 0; UpdateSpeed(); WorldPacket ArenaSettings(SMSG_UPDATE_WORLD_STATE, 16); ArenaSettings << uint32(0xC77); ArenaSettings << uint32(sWorld.Arena_Progress); ArenaSettings << uint32(0xF3D); ArenaSettings << uint32(sWorld.Arena_Season); m_session->SendPacket(&ArenaSettings); LOG_DETAIL("WORLD: Sent initial logon packets for %s.", GetName()); }
void MapMgr::UnloadCell(uint32 x, uint32 y) { MapCell* c = GetCell(x, y); if(c == NULL || c->HasPlayers() || _CellActive(x, y) || !c->IsUnloadPending()) return; LOG_DETAIL("Unloading Cell [%u][%u] on map %u (instance %u)...", x, y, _mapId, m_instanceID); c->Unload(); }
////////////////////////////////////////////////////////////// /// This function handles MSG_CORPSE_QUERY: ////////////////////////////////////////////////////////////// void WorldSession::HandleCorpseQueryOpcode(WorldPacket &recv_data) { CHECK_INWORLD_RETURN LOG_DETAIL("WORLD: Received MSG_CORPSE_QUERY"); Corpse *pCorpse; WorldPacket data(MSG_CORPSE_QUERY, 25); MapInfo *pMapinfo; pCorpse = objmgr.GetCorpseByOwner(GetPlayer()->GetLowGUID()); if(pCorpse) { pMapinfo = WorldMapInfoStorage.LookupEntry(pCorpse->GetMapId()); if(pMapinfo) { if(pMapinfo->type == INSTANCE_NULL || pMapinfo->type == INSTANCE_BATTLEGROUND) { data << uint8(0x01); //show ? data << pCorpse->GetMapId(); // mapid (that tombstones shown on) data << pCorpse->GetPositionX(); data << pCorpse->GetPositionY(); data << pCorpse->GetPositionZ(); data << pCorpse->GetMapId(); //instance mapid (needs to be same as mapid to be able to recover corpse) data << uint32(0); SendPacket(&data); } else { data << uint8(0x01); //show ? data << pMapinfo->repopmapid; // mapid (that tombstones shown on) data << pMapinfo->repopx; data << pMapinfo->repopy; data << pMapinfo->repopz; data << pCorpse->GetMapId(); //instance mapid (needs to be same as mapid to be able to recover corpse) data << uint32(0); SendPacket(&data); } } else { data << uint8(0x01); //show ? data << pCorpse->GetMapId(); // mapid (that tombstones shown on) data << pCorpse->GetPositionX(); data << pCorpse->GetPositionY(); data << pCorpse->GetPositionZ(); data << pCorpse->GetMapId(); //instance mapid (needs to be same as mapid to be able to recover corpse) data << uint32(0); SendPacket(&data); } } }
void AddonMgr::SaveToDB() { LOG_DETAIL("AddonMgr: Saving any new addons discovered in this session to database."); KnownAddonsItr itr; for(itr = mKnownAddons.begin(); itr != mKnownAddons.end(); ++itr) { if(itr->second->isNew) { LOG_DETAIL("Saving new addon %s", itr->second->name.c_str()); std::stringstream ss; ss << "INSERT INTO clientaddons (name, crc, banned, showinlist) VALUES(\"" << WorldDatabase.EscapeString(itr->second->name) << "\",\"" << itr->second->crc << "\",\"" << itr->second->banned << "\",\"" << itr->second->showinlist << "\");"; WorldDatabase.Execute(ss.str().c_str()); } } }
int _tmain(int argc, _TCHAR* argv[]) { oLog::initialise(); sLog.Init( 5, LOGON_LOG ); LOG_DETAIL( "服务器启动..." ); CNet net; if ( !net.Startup() ) { return -1; } CServer server; CClient client; net.Listen( 6000, &server ); net.Connect( "127.0.0.1", 6000, &client ); LOG_DETAIL( "%s", "welcome, the serve is started..." ); while( 1 ) { net.Process(); server.Process(); client.Process(); } net.Clearup(); LOG_DETAIL( "服务器退出..." ); sLog.Close(); oLog::release(); return 0; }
bool ChatHandler::HandleGMAnnounceCommand(const char* args, WorldSession* m_session) { if(!*args) { LOG_DETAIL("ERROR: HandleGMAnnounceCommand !args = failed"); return false; } char GMAnnounce[1024]; snprintf(GMAnnounce, 1024, MSG_COLOR_RED "[Team]" MSG_COLOR_GREEN " |Hplayer:%s|h[%s]|h:" MSG_COLOR_YELLOW " %s", m_session->GetPlayer()->GetName(), m_session->GetPlayer()->GetName(), args); sWorld.SendGMWorldText(GMAnnounce); sGMLog.writefromsession(m_session, "used team announce command, [%s]", args); return true; }
extern "C" VALUE update_node_bayeux( VALUE self, VALUE node, VALUE value ) { const pubsub::node_name node_name = hash_to_node( node ); const json::value node_value = ruby_to_json( value, node_name ); LOG_DETAIL( log_context << "update: " << node_name << " to " << node_value ); bayeux_server* server_ptr = 0; Data_Get_Struct( self, bayeux_server, server_ptr ); assert( server_ptr ); server_ptr->update_node( node_name, node_value ); return self; }
void LogonCommHandler::UpdateSockets() { mapLock.Acquire(); map<LogonServer*, LogonCommClientSocket*>::iterator itr = logons.begin(); LogonCommClientSocket* cs; uint32 t = (uint32)UNIXTIME; for(; itr != logons.end(); ++itr) { cs = itr->second; if(cs != 0) { if(!pings) continue; if(cs->IsDeleted() || !cs->IsConnected()) { cs->_id = 0; itr->second = 0; continue; } if(cs->last_pong < t && ((t - cs->last_pong) > 60)) { // no pong for 60 seconds -> remove the socket LOG_DETAIL(" >> realm id %u connection dropped due to pong timeout.", (unsigned int)itr->first->ID); cs->_id = 0; cs->Disconnect(); itr->second = 0; continue; } if((t - cs->last_ping) > 15) { // send a ping packet. cs->SendPing(); } } else { // check retry time if(t >= itr->first->RetryTime) { Connect(itr->first); } } } mapLock.Release(); }
void WorldSocket::_HandlePing(WorldPacket* recvPacket) { uint32 ping; if(recvPacket->size() < 4) { LOG_DETAIL("ERROR: Socket closed due to incomplete ping packet."); Disconnect(); return; } *recvPacket >> ping; *recvPacket >> _latency; if(mSession) { mSession->_latency = _latency; mSession->m_lastPing = (uint32)UNIXTIME; // reset the move time diff calculator, don't worry it will be re-calculated next movement packet. mSession->m_clientTimeDelay = 0; } OutPacket(SMSG_PONG, 4, &ping); #ifdef WIN32 // Dynamically change nagle buffering status based on latency. //if(_latency >= 250) // I think 350 is better, in a MMO 350 latency isn't that big that we need to worry about reducing the number of packets being sent. if(_latency >= 350) { if(!m_nagleEanbled) { u_long arg = 0; setsockopt(GetFd(), 0x6, 0x1, (const char*)&arg, sizeof(arg)); m_nagleEanbled = true; } } else { if(m_nagleEanbled) { u_long arg = 1; setsockopt(GetFd(), 0x6, 0x1, (const char*)&arg, sizeof(arg)); m_nagleEanbled = false; } } #endif }
void WorldSocket::_HandleAuthSession(WorldPacket* recvPacket) { std::string account; uint32 unk2, unk3; uint64 unk4; uint32 unk5, unk6, unk7; _latency = getMSTime() - _latency; try { *recvPacket >> mClientBuild; *recvPacket >> unk2; *recvPacket >> account; *recvPacket >> unk3; *recvPacket >> mClientSeed; *recvPacket >> unk4; *recvPacket >> unk5; *recvPacket >> unk6; *recvPacket >> unk7; } catch(ByteBuffer::error &) { LOG_DETAIL("Incomplete copy of AUTH_SESSION Received."); return; } // Send out a request for this account. mRequestID = sLogonCommHandler.ClientConnected(account, this); if(mRequestID == 0xFFFFFFFF) { Disconnect(); return; } // shitty hash ! m_fullAccountName = new string(account); // Set the authentication packet pAuthenticationPacket = recvPacket; }
bool EquipmentSetMgr::LoadfromDB(QueryResult* result) { if(result == NULL) return false; uint32 setcount = 0; EquipmentSet* set = NULL; Field* fields = NULL; do { if(setcount >= 10) { LOG_DETAIL("ERROR: There were more than 10 equipment sets for GUID: %u", ownerGUID); return true; } fields = result->Fetch(); set = new EquipmentSet(); if(set == NULL) return false; set->SetGUID = fields[ 1 ].GetUInt32(); set->SetID = fields[ 2 ].GetUInt32(); set->SetName = fields[ 3 ].GetString(); set->IconName = fields[ 4 ].GetString(); for(uint32 i = 0; i < set->ItemGUID.size(); ++i) set->ItemGUID[ i ] = fields[ 5 + i ].GetUInt32(); EquipmentSets.insert(std::pair< uint32, EquipmentSet* >(set->SetGUID, set)); set = NULL; setcount++; } while(result->NextRow()); return true; }
void IPBanner::Reload() { listBusy.Acquire(); banList.clear(); QueryResult* result = sLogonSQL->Query("SELECT ip, expire FROM ipbans"); if(result != NULL) { do { IPBan ipb; std::string smask = "32"; std::string ip = result->Fetch()[0].GetString(); std::string::size_type i = ip.find("/"); std::string stmp = ip.substr(0, i); if(i == std::string::npos) { LOG_DETAIL("IP ban \"%s\" netmask not specified. assuming /32", ip.c_str()); } else smask = ip.substr(i + 1); unsigned int ipraw = MakeIP(stmp.c_str()); unsigned int ipmask = atoi(smask.c_str()); if(ipraw == 0 || ipmask == 0) { LOG_ERROR("IP ban \"%s\" could not be parsed. Ignoring", ip.c_str()); continue; } ipb.Bytes = static_cast<unsigned char>(ipmask); ipb.Mask = ipraw; ipb.Expire = result->Fetch()[1].GetUInt32(); ipb.db_ip = ip; banList.push_back(ipb); } while(result->NextRow()); delete result; } listBusy.Release(); }
LootMgr::~LootMgr() { LOG_DETAIL(" Deleting Loot Tables..."); for(LootStore::iterator iter = CreatureLoot.begin(); iter != CreatureLoot.end(); ++iter) delete [] iter->second.items; for(LootStore::iterator iter = FishingLoot.begin(); iter != FishingLoot.end(); ++iter) delete [] iter->second.items; for(LootStore::iterator iter = SkinningLoot.begin(); iter != SkinningLoot.end(); ++iter) delete [] iter->second.items; for(LootStore::iterator iter = GOLoot.begin(); iter != GOLoot.end(); ++iter) delete [] iter->second.items; for(LootStore::iterator iter = ItemLoot.begin(); iter != ItemLoot.end(); ++iter) delete [] iter->second.items; for(LootStore::iterator iter = PickpocketingLoot.begin(); iter != PickpocketingLoot.end(); ++iter) delete [] iter->second.items; }
void InformationCore::CheckServers() { serverSocketLock.Acquire(); std::set<LogonCommServerSocket*>::iterator itr, it2; LogonCommServerSocket* s; for(itr = m_serverSockets.begin(); itr != m_serverSockets.end();) { s = *itr; it2 = itr; ++itr; if(!IsServerAllowed(s->GetRemoteAddress().s_addr)) { LOG_DETAIL("Disconnecting socket: %s due to it no longer being on an allowed IP.", s->GetRemoteIP().c_str()); s->Disconnect(); } } serverSocketLock.Release(); }
////////////////////////////////////////////////////////////// /// This function handles CMSG_GOSSIP_SELECT_OPTION: ////////////////////////////////////////////////////////////// void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket & recv_data) { CHECK_INWORLD_RETURN uint32 option; uint32 unk24; uint64 guid; recv_data >> guid >> unk24 >> option; LOG_DETAIL("WORLD: CMSG_GOSSIP_SELECT_OPTION Option %i Guid %.8X", option, guid); Arcemu::Gossip::Script* script = NULL; uint32 guidtype = GET_TYPE_FROM_GUID(guid); Object* qst_giver; if(guidtype == HIGHGUID_TYPE_ITEM) //Item objects are retrieved differently. { qst_giver = GetPlayer()->GetItemInterface()->GetItemByGUID(guid); if(qst_giver != NULL) script = Arcemu::Gossip::Script::GetInterface(TO_ITEM(qst_giver)); } else qst_giver = GetPlayer()->GetMapMgr()->_GetObject(guid); if(qst_giver != NULL) { if(guidtype == HIGHGUID_TYPE_UNIT) script = Arcemu::Gossip::Script::GetInterface(TO_CREATURE(qst_giver)); else if(guidtype == HIGHGUID_TYPE_GAMEOBJECT) script = Arcemu::Gossip::Script::GetInterface(TO_GAMEOBJECT(qst_giver)); } if(script != NULL) { string str; if(recv_data.rpos() != recv_data.wpos()) recv_data >> str; if(str.length() > 0) script->OnSelectOption(qst_giver, GetPlayer() , option, str.c_str()); else script->OnSelectOption(qst_giver, GetPlayer() , option, NULL); }
/*** Signal Handler ***/ void _OnSignal(int s) { switch (s) { #ifndef WIN32 case SIGHUP: { LOG_DETAIL("Received SIGHUP signal, reloading accounts."); AccountMgr::getSingleton().ReloadAccounts(true); }break; #endif case SIGINT: case SIGTERM: case SIGABRT: #ifdef _WIN32 case SIGBREAK: #endif mrunning.SetVal(false); break; } signal(s, _OnSignal); }
void WorldSocket::OutPacket(uint16 opcode, size_t len, const void* data) { OUTPACKET_RESULT res; if((len + 10) > WORLDSOCKET_SENDBUF_SIZE) { LOG_DETAIL("ERROR: WARNING: Tried to send a packet of %u bytes (which is too large) to a socket. Opcode was: %u (0x%03X)", (unsigned int)len, (unsigned int)opcode, (unsigned int)opcode); return; } res = _OutPacket(opcode, len, data); if(res == OUTPACKET_RESULT_SUCCESS) return; if(res == OUTPACKET_RESULT_NO_ROOM_IN_BUFFER) { /* queue the packet */ queueLock.Acquire(); WorldPacket* pck = new WorldPacket(opcode, len); if(len) pck->append((const uint8*)data, len); _queue.Push(pck); queueLock.Release(); } }
bool DayWatcherThread::runThread() { LOG_DETAIL("Started."); currenttime = UNIXTIME; dupe_tm_pointer(localtime(¤ttime), &local_currenttime); load_settings(); set_tm_pointers(); m_busy = false; while (GetThreadState() != THREADSTATE_TERMINATE) { m_busy = true; currenttime = UNIXTIME; dupe_tm_pointer(localtime(¤ttime), &local_currenttime); if (has_timeout_expired(&local_currenttime, &local_last_arena_time, arena_period)) update_arena(); if (has_timeout_expired(&local_currenttime, &local_last_daily_time, daily_period)) update_daily(); if (m_dirty) update_settings(); m_busy = false; if (GetThreadState() == THREADSTATE_TERMINATE) break; cond.Wait(THREAD_LOOP_INTERVAL * 1000); if (!m_running) break; } return true; }
////////////////////////////////////////////////////////////// /// This function handles CMSG_CREATURE_QUERY: ////////////////////////////////////////////////////////////// void WorldSession::HandleCreatureQueryOpcode( WorldPacket & recv_data ) { CHECK_INWORLD_RETURN CHECK_PACKET_SIZE(recv_data, 12); WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 250); //VLack: thanks Aspire, this was 146 before uint32 entry; uint64 guid; CreatureInfo *ci; recv_data >> entry; recv_data >> guid; if(entry == 300000) { data << (uint32)entry; data << "WayPoint"; data << uint8(0) << uint8(0) << uint8(0); data << "Level is WayPoint ID"; for(uint32 i = 0; i < 8;i++) { data << uint32(0); } data << uint8(0); } else { ci = CreatureNameStorage.LookupEntry(entry); if(ci == NULL) return; LocalizedCreatureName * lcn = (language>0) ? sLocalizationMgr.GetLocalizedCreatureName(entry, language) : NULL; if(lcn == NULL) { LOG_DETAIL("WORLD: CMSG_CREATURE_QUERY '%s'", ci->Name); data << (uint32)entry; data << ci->Name; // name of the creature data << uint8(0); // name2, always seems to be empty data << uint8(0); // name3, always seems to be empty data << uint8(0); // name4, always seems to be empty data << ci->SubName; // this is the title/guild of the creature } else { LOG_DETAIL("WORLD: CMSG_CREATURE_QUERY '%s' (localized to %s)", ci->Name, lcn->Name); data << (uint32)entry; data << lcn->Name; data << uint8(0); data << uint8(0); data << uint8(0); data << lcn->SubName; } data << ci->info_str; //!!! this is a string in 2.3.0 Example: stormwind guard has : "Direction" data << ci->Flags1; // flags like skinnable data << ci->Type; // humanoid, beast, etc data << ci->Family; // petfamily data << ci->Rank; // normal, elite, etc data << ci->killcredit[0]; // quest kill credit 1 data << ci->killcredit[1]; // quest kill credit 2 data << ci->Male_DisplayID; data << ci->Female_DisplayID; data << ci->Male_DisplayID2; data << ci->Female_DisplayID2; data << ci->unkfloat1; data << ci->unkfloat2; data << ci->Leader; // faction leader // these are the 6 seperate quest items a creature can drop for(uint32 i = 0; i < 6; ++i) { data << uint32(ci->QuestItems[i]); } data << ci->waypointid; } SendPacket( &data ); }
void WorldSession::HandleSpellClick(WorldPacket & recvPacket) { CHECK_INWORLD_RETURN LOG_DETAIL("WORLD: got CMSG_SPELLCLICK packet, data length = %i", recvPacket.size()); if(_player->getDeathState() == CORPSE) return; uint64 target_guid; // this will store the guid of the object we are going to use it's spell. There must be a dbc that indicates what spells a unit has recvPacket >> target_guid; //we have only 1 example atm for entry : 28605 Unit* target_unit = _player->GetMapMgr()->GetUnit(target_guid); if(!target_unit) return; if( !_player->isInRange( target_unit, MAX_INTERACTION_RANGE ) ) return; if( target_unit->IsVehicle() ){ if( target_unit->GetVehicleComponent() != NULL ) target_unit->GetVehicleComponent()->AddPassenger( _player ); return; } uint32 creature_id = target_unit->GetEntry(); uint32 cast_spell_id = 0; if(!_player->HasAurasWithNameHash(SPELL_HASH_LIGHTWELL_RENEW) && target_unit->RemoveAura(59907)) { SpellClickSpell *sp = SpellClickSpellStorage.LookupEntry( creature_id ); if( sp == NULL ){ if( target_unit->IsCreature() ){ Creature *c = TO< Creature* >( target_unit ); sChatHandler.BlueSystemMessage( this, "NPC Id %u ( %s ) has no spellclick spell associated with it.", c->GetProto()->Id, c->GetCreatureInfo()->Name ); LOG_DETAIL("ERROR: Spellclick packet received for creature %u but there is no spell associated with it.", creature_id ); return; } } cast_spell_id = sp->SpellID; target_unit->CastSpell(_player, cast_spell_id, true); if(!target_unit->HasAura(59907)) TO_CREATURE(target_unit)->Despawn(0, 0); //IsCreature() check is not needed, refer to r2387 and r3230 return; } SpellClickSpell *sp = SpellClickSpellStorage.LookupEntry( creature_id ); if( sp == NULL ){ if( target_unit->IsCreature() ){ Creature *c = TO< Creature* >( target_unit ); sChatHandler.BlueSystemMessage( this, "NPC Id %u ( %s ) has no spellclick spell associated with it.", c->GetProto()->Id, c->GetCreatureInfo()->Name ); LOG_DETAIL("ERROR: Spellclick packet received for creature %u but there is no spell associated with it.", creature_id ); return; } } cast_spell_id = sp->SpellID; if(cast_spell_id == 0) return; SpellEntry* spellInfo = dbcSpell.LookupEntryForced(cast_spell_id); if(spellInfo == NULL) return; Spell* spell = sSpellFactoryMgr.NewSpell(_player, spellInfo, false, NULL); SpellCastTargets targets(target_guid); spell->prepare(&targets); }
////////////////////////////////////////////////////////////// /// This function handles CMSG_GAMEOBJECT_QUERY: ////////////////////////////////////////////////////////////// void WorldSession::HandleGameObjectQueryOpcode( WorldPacket & recv_data ) { CHECK_INWORLD_RETURN CHECK_PACKET_SIZE(recv_data, 12); WorldPacket data(SMSG_GAMEOBJECT_QUERY_RESPONSE, 900); uint32 entryID; uint64 guid; GameObjectInfo *goinfo; recv_data >> entryID; recv_data >> guid; LOG_DETAIL("WORLD: CMSG_GAMEOBJECT_QUERY '%u'", entryID); goinfo = GameObjectNameStorage.LookupEntry(entryID); if(goinfo == NULL) return; LocalizedGameObjectName * lgn = (language>0) ? sLocalizationMgr.GetLocalizedGameObjectName(entryID, language) : NULL; data << entryID; // unique identifier of the GO template data << goinfo->Type; // type of the gameobject data << goinfo->DisplayID; // displayid/modelid of the gameobject // Name of the gameobject if(lgn) data << lgn->Name; else data << goinfo->Name; data << uint8( 0 ); // name2, always seems to be empty data << uint8( 0 ); // name3, always seems to be empty data << uint8( 0 ); // name4, always seems to be empty data << goinfo->Category; // Category string of the GO, like "attack", "pvp", "point", etc data << goinfo->Castbartext; // text displayed when using the go, like "collecting", "summoning" etc data << goinfo->Unkstr; data << goinfo->SpellFocus; // spellfocus id, ex.: spell casted when interacting with the GO data << goinfo->sound1; data << goinfo->sound2; data << goinfo->sound3; data << goinfo->sound4; data << goinfo->sound5; data << goinfo->sound6; data << goinfo->sound7; data << goinfo->sound8; data << goinfo->sound9; data << goinfo->Unknown1; data << goinfo->Unknown2; data << goinfo->Unknown3; data << goinfo->Unknown4; data << goinfo->Unknown5; data << goinfo->Unknown6; data << goinfo->Unknown7; data << goinfo->Unknown8; data << goinfo->Unknown9; data << goinfo->Unknown10; data << goinfo->Unknown11; data << goinfo->Unknown12; data << goinfo->Unknown13; data << goinfo->Unknown14; data << float(goinfo->Size); // scaling of the GO // questitems that the go can contain for(uint32 i = 0; i < 6; ++i) { data << uint32(goinfo->QuestItems[i]); } SendPacket( &data ); }
void AuthSocket::HandleChallenge() { // No header if(readBuffer.GetContiguiousBytes() < 4) { LOG_ERROR("[AuthChallenge] Packet has no header. Refusing to handle."); return; } // Check the rest of the packet is complete. uint8* ReceiveBuffer = (uint8*)readBuffer.GetBufferStart(); uint16 full_size = *(uint16*)&ReceiveBuffer[2]; LOG_DETAIL("[AuthChallenge] got header, body is %u bytes", full_size); if(readBuffer.GetSize() < uint32(full_size + 4)) { LOG_ERROR("[AuthChallenge] Packet is smaller than expected, refusing to handle"); return; } // Copy the data into our cached challenge structure if(full_size > sizeof(sAuthLogonChallenge_C)) { LOG_ERROR("[AuthChallenge] Packet is larger than expected, refusing to handle!"); Disconnect(); return; } LOG_DEBUG("[AuthChallenge] got a complete packet."); //memcpy(&m_challenge, ReceiveBuffer, full_size + 4); //RemoveReadBufferBytes(full_size + 4, true); readBuffer.Read(&m_challenge, full_size + 4); // Check client build. uint16 build = m_challenge.build; // Check client build. if(build > LogonServer::getSingleton().max_build) { // wtf? LOG_DETAIL("[AuthChallenge] Client %s has wrong version. More up to date than server. Server: %u, Client: %u", GetRemoteIP().c_str(), LogonServer::getSingleton().max_build, m_challenge.build); SendChallengeError(CE_WRONG_BUILD_NUMBER); return; } if(build < LogonServer::getSingleton().min_build) { // can we patch? char flippedloc[5] = {0, 0, 0, 0, 0}; flippedloc[0] = m_challenge.country[3]; flippedloc[1] = m_challenge.country[2]; flippedloc[2] = m_challenge.country[1]; flippedloc[3] = m_challenge.country[0]; m_patch = PatchMgr::getSingleton().FindPatchForClient(build, flippedloc); if(m_patch == NULL) { // could not find a valid patch LOG_DETAIL("[AuthChallenge] Client %s has wrong version. More out of date than server. Server: %u, Client: %u", GetRemoteIP().c_str(), LogonServer::getSingleton().min_build, m_challenge.build); SendChallengeError(CE_WRONG_BUILD_NUMBER); return; } Log.Debug("Patch", "Selected patch %u%s for client.", m_patch->Version, m_patch->Locality); uint8 response[119] = { 0x00, 0x00, 0x00, 0x72, 0x50, 0xa7, 0xc9, 0x27, 0x4a, 0xfa, 0xb8, 0x77, 0x80, 0x70, 0x22, 0xda, 0xb8, 0x3b, 0x06, 0x50, 0x53, 0x4a, 0x16, 0xe2, 0x65, 0xba, 0xe4, 0x43, 0x6f, 0xe3, 0x29, 0x36, 0x18, 0xe3, 0x45, 0x01, 0x07, 0x20, 0x89, 0x4b, 0x64, 0x5e, 0x89, 0xe1, 0x53, 0x5b, 0xbd, 0xad, 0x5b, 0x8b, 0x29, 0x06, 0x50, 0x53, 0x08, 0x01, 0xb1, 0x8e, 0xbf, 0xbf, 0x5e, 0x8f, 0xab, 0x3c, 0x82, 0x87, 0x2a, 0x3e, 0x9b, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x32, 0xa3, 0x49, 0x76, 0x5c, 0x5b, 0x35, 0x9a, 0x93, 0x3c, 0x6f, 0x3c, 0x63, 0x6d, 0xc0, 0x00 }; Send(response, 119); return; } // Check for a possible IP ban on this client. BAN_STATUS ipb = IPBanner::getSingleton().CalculateBanStatus(GetRemoteAddress()); if(ipb != BAN_STATUS_NOT_BANNED) LOG_DETAIL("[AuthChallenge] Client %s is banned, refusing to continue.", GetRemoteIP().c_str()); switch(ipb) { case BAN_STATUS_PERMANENT_BAN: SendChallengeError(CE_ACCOUNT_CLOSED); return; case BAN_STATUS_TIME_LEFT_ON_BAN: SendChallengeError(CE_ACCOUNT_FREEZED); return; default: break; } // Null-terminate the account string if(m_challenge.I_len >= 50) { Disconnect(); return; } m_challenge.I[m_challenge.I_len] = 0; // Clear the shitty hash (for server) string AccountName = (char*)&m_challenge.I; string::size_type i = AccountName.rfind("#"); if(i != string::npos) { LOG_ERROR("# ACCOUNTNAME!"); return; //AccountName.erase( i ); } // Look up the account information LOG_DEBUG("[AuthChallenge] Account Name: \"%s\"", AccountName.c_str()); m_account = AccountMgr::getSingleton().GetAccount(AccountName); if(m_account == 0) { LOG_DEBUG("[AuthChallenge] Invalid account."); // Non-existant account SendChallengeError(CE_NO_ACCOUNT); return; } LOG_DEBUG("[AuthChallenge] Account banned state = %u", m_account->Banned); // Check that the account isn't banned. if(m_account->Banned == 1) { SendChallengeError(CE_ACCOUNT_CLOSED); return; } else if(m_account->Banned > 0) { SendChallengeError(CE_ACCOUNT_FREEZED); return; } // update cached locale if(!m_account->forcedLocale) { char temp[4]; temp[0] = m_challenge.country[3]; temp[1] = m_challenge.country[2]; temp[2] = m_challenge.country[1]; temp[3] = m_challenge.country[0]; *(uint32*)&m_account->Locale[0] = *(uint32*)temp; } //////////////////////////////////////////////// SRP6 Challenge //////////////////////////////////////////////// // // // First we will generate the Verifier value using the following formulas // // x = SHA1(s | SHA1(I | ":" | P)) // v = g^x % N // // The SHA1(I | ":" | P) part for x we have in the account database, this is the encrypted password, reversed // N is a safe prime // g is the generator // | means concatenation in this contect // // Sha1Hash sha; sha.UpdateData(s.AsByteArray(), 32); sha.UpdateData(m_account->SrpHash, 20); sha.Finalize(); BigNumber x; x.SetBinary(sha.GetDigest(), sha.GetLength()); v = g.ModExp(x, N); // Next we generate b, and B which are the public and private values of the server // // b = random() // B = k*v + g^b % N // // in our case the multiplier parameters, k = 3 b.SetRand(152); uint8 k = 3; BigNumber gmod = g.ModExp(b, N); B = ((v * k) + gmod) % N; ASSERT(gmod.GetNumBytes() <= 32); BigNumber unk; unk.SetRand(128); // Now we send B, g, N and s to the client as a challenge, asking the client for the proof sAuthLogonChallenge_S challenge; challenge.cmd = 0; challenge.error = 0; challenge.unk2 = CE_SUCCESS; memcpy(challenge.B, B.AsByteArray(), 32); challenge.g_len = 1; challenge.g = (g.AsByteArray())[ 0 ]; challenge.N_len = 32; memcpy(challenge.N, N.AsByteArray(), 32); memcpy(challenge.s, s.AsByteArray(), 32); memcpy(challenge.unk3, unk.AsByteArray(), 16); challenge.unk4 = 0; Send(reinterpret_cast< uint8* >(&challenge), sizeof(sAuthLogonChallenge_S)); }
////////////////////////////////////////////////////////////////////////////////////////// /// This function handles CMSG_GAMEOBJECT_QUERY: ////////////////////////////////////////////////////////////////////////////////////////// void WorldSession::HandleGameObjectQueryOpcode(WorldPacket& recv_data) { CHECK_INWORLD_RETURN CHECK_PACKET_SIZE(recv_data, 12); WorldPacket data(SMSG_GAMEOBJECT_QUERY_RESPONSE, 900); uint32 entryID; uint64 guid; recv_data >> entryID; recv_data >> guid; LOG_DETAIL("WORLD: CMSG_GAMEOBJECT_QUERY '%u'", entryID); auto gameobject_info = GameObjectNameStorage.LookupEntry(entryID); if (gameobject_info == nullptr) return; LocalizedGameObjectName* lgn = (language > 0) ? sLocalizationMgr.GetLocalizedGameObjectName(entryID, language) : NULL; data << entryID; // unique identifier of the GO template data << gameobject_info->type; // type of the gameobject data << gameobject_info->display_id; // displayid/modelid of the gameobject // Name of the gameobject if (lgn) data << lgn->Name; else data << gameobject_info->name; data << uint8(0); // name2, always seems to be empty data << uint8(0); // name3, always seems to be empty data << uint8(0); // name4, always seems to be empty data << gameobject_info->category_name; // Category string of the GO, like "attack", "pvp", "point", etc data << gameobject_info->cast_bar_text; // text displayed when using the go, like "collecting", "summoning" etc data << gameobject_info->Unkstr; data << gameobject_info->parameter_0; // spellfocus id, ex.: spell casted when interacting with the GO data << gameobject_info->parameter_1; data << gameobject_info->parameter_2; data << gameobject_info->parameter_3; data << gameobject_info->parameter_4; data << gameobject_info->parameter_5; data << gameobject_info->parameter_6; data << gameobject_info->parameter_7; data << gameobject_info->parameter_8; data << gameobject_info->parameter_9; data << gameobject_info->parameter_10; data << gameobject_info->parameter_11; data << gameobject_info->parameter_12; data << gameobject_info->parameter_13; data << gameobject_info->parameter_14; data << gameobject_info->parameter_15; data << gameobject_info->parameter_16; data << gameobject_info->parameter_17; data << gameobject_info->parameter_18; data << gameobject_info->parameter_19; data << gameobject_info->parameter_20; data << gameobject_info->parameter_21; data << gameobject_info->parameter_22; data << gameobject_info->parameter_23; data << float(gameobject_info->size); // scaling of the GO // questitems that the go can contain for (uint32 i = 0; i < 6; ++i) { data << uint32(gameobject_info->QuestItems[i]); } SendPacket(&data); }
void AuthSocket::HandleReconnectChallenge() { // No header if(readBuffer.GetContiguiousBytes() < 4) return; // Check the rest of the packet is complete. uint8* ReceiveBuffer = /*GetReadBuffer(0)*/(uint8*)readBuffer.GetBufferStart(); uint16 full_size = *(uint16*)&ReceiveBuffer[2]; LOG_DETAIL("[AuthChallenge] got header, body is %u bytes", full_size); if(readBuffer.GetSize() < (uint32)full_size + 4) return; // Copy the data into our cached challenge structure if((size_t)(full_size + 4) > sizeof(sAuthLogonChallenge_C)) { Disconnect(); return; } LOG_DEBUG("[AuthChallenge] got full packet."); memcpy(&m_challenge, ReceiveBuffer, full_size + 4); //RemoveReadBufferBytes(full_size + 4, false); readBuffer.Read(&m_challenge, full_size + 4); // Check client build. if(m_challenge.build > LogonServer::getSingleton().max_build || m_challenge.build < LogonServer::getSingleton().min_build) { SendChallengeError(CE_WRONG_BUILD_NUMBER); return; } // Check for a possible IP ban on this client. BAN_STATUS ipb = IPBanner::getSingleton().CalculateBanStatus(GetRemoteAddress()); switch(ipb) { case BAN_STATUS_PERMANENT_BAN: SendChallengeError(CE_ACCOUNT_CLOSED); return; case BAN_STATUS_TIME_LEFT_ON_BAN: SendChallengeError(CE_ACCOUNT_FREEZED); return; default: break; } /* buffer overflow thing */ if(m_challenge.I_len >= 50) { Disconnect(); return; } // Null-terminate the account string m_challenge.I[m_challenge.I_len] = 0; // Clear the shitty hash (for server) /* size_t i = 0; for( i = m_challenge.I_len; i >= 0; --i ) { if( m_challenge.I[i] == '#' ) { m_challenge.I[i] = '\0'; break; } }*/ // Look up the account information string AccountName = (char*)&m_challenge.I; LOG_DEBUG("[AuthChallenge] Account Name: \"%s\"", AccountName.c_str()); m_account = AccountMgr::getSingleton().GetAccount(AccountName); if(m_account == 0) { LOG_DEBUG("[AuthChallenge] Invalid account."); // Non-existant account SendChallengeError(CE_NO_ACCOUNT); return; } LOG_DEBUG("[AuthChallenge] Account banned state = %u", m_account->Banned); // Check that the account isn't banned. if(m_account->Banned == 1) { SendChallengeError(CE_ACCOUNT_CLOSED); return; } else if(m_account->Banned > 0) { SendChallengeError(CE_ACCOUNT_FREEZED); return; } if(!m_account->SessionKey) { SendChallengeError(CE_SERVER_FULL); return; } /** burlex: this is pure speculation, I really have no idea what this does :p * just guessed the md5 because it was 16 byte blocks. */ MD5_CTX ctx; MD5_Init(&ctx); MD5_Update(&ctx, m_account->SessionKey, 40); uint8 buffer[20]; MD5_Final(buffer, &ctx); ByteBuffer buf; buf << uint16(2); buf.append(buffer, 20); buf << uint64(0); buf << uint64(0); Send(buf.contents(), 34); }
void WorldSession::HandleCastSpellOpcode(WorldPacket & recvPacket) { CHECK_INWORLD_RETURN uint32 spellId; uint8 cn, unk; //Alice : Added to 3.0.2 recvPacket >> cn >> spellId >> unk; // check for spell id SpellEntry* spellInfo = dbcSpell.LookupEntryForced(spellId); if(!spellInfo) { LOG_DETAIL("ERROR: WORLD: unknown spell id %i", spellId); return; } if(!_player->isAlive() && _player->GetShapeShift() != FORM_SPIRITOFREDEMPTION && !(spellInfo->Attributes & ATTRIBUTES_DEAD_CASTABLE)) //They're dead, not in spirit of redemption and the spell can't be cast while dead. return; LOG_DETAIL("WORLD: got cast spell packet, spellId - %i (%s), data length = %i", spellId, spellInfo->Name, recvPacket.size()); // Cheat Detection only if player and not from an item // this could f**k up things but meh it's needed ALOT of the newbs are using WPE now // WPE allows them to mod the outgoing packet and basically choose what ever spell they want :( if(!GetPlayer()->HasSpell(spellId)) { sCheatLog.writefromsession(this, "Cast spell %lu but doesn't have that spell.", spellId); LOG_DETAIL("WORLD: Spell isn't cast because player \'%s\' is cheating", GetPlayer()->GetName()); return; } if(spellInfo->Attributes & ATTRIBUTES_PASSIVE) { sCheatLog.writefromsession(this, "Cast passive spell %lu.", spellId); LOG_DETAIL("WORLD: Spell isn't cast because player \'%s\' is cheating", GetPlayer()->GetName()); return; } if(GetPlayer()->GetOnMeleeSpell() != spellId) { //autoshot 75 if((spellInfo->AttributesExB & ATTRIBUTESEXB_ACTIVATE_AUTO_SHOT) /*spellInfo->Attributes == 327698*/) // auto shot.. { //sLog.outString( "HandleSpellCast: Auto Shot-type spell cast (id %u, name %s)" , spellInfo->Id , spellInfo->Name ); Item* weapon = GetPlayer()->GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_RANGED); if(!weapon) return; uint32 spellid; switch(weapon->GetProto()->SubClass) { case 2: // bows case 3: // guns case 18: // crossbow spellid = SPELL_RANGED_GENERAL; break; case 16: // thrown spellid = SPELL_RANGED_THROW; break; case 19: // wands spellid = SPELL_RANGED_WAND; break; default: spellid = 0; break; } if(!spellid) spellid = spellInfo->Id; if(!_player->m_onAutoShot) { _player->m_AutoShotTarget = _player->GetSelection(); uint32 duration = _player->GetBaseAttackTime(RANGED); SpellCastTargets targets(recvPacket, GetPlayer()->GetGUID()); if(!targets.m_unitTarget) { LOG_DEBUG("Cancelling auto-shot cast because targets.m_unitTarget is null!"); return; } SpellEntry* sp = dbcSpell.LookupEntry(spellid); _player->m_AutoShotSpell = sp; _player->m_AutoShotDuration = duration; //This will fix fast clicks if(_player->m_AutoShotAttackTimer < 500) _player->m_AutoShotAttackTimer = 500; _player->m_onAutoShot = true; } return; } if(_player->m_currentSpell) { if(_player->m_currentSpell->getState() == SPELL_STATE_CASTING) { // cancel the existing channel spell, cast this one _player->m_currentSpell->cancel(); } else { // send the error message _player->SendCastResult(spellInfo->Id, SPELL_FAILED_SPELL_IN_PROGRESS, cn, 0); return; } } SpellCastTargets targets(recvPacket, GetPlayer()->GetGUID()); // some anticheat stuff if(spellInfo->self_cast_only) { if(targets.m_unitTarget && targets.m_unitTarget != _player->GetGUID()) { // send the error message _player->SendCastResult(spellInfo->Id, SPELL_FAILED_BAD_TARGETS, cn, 0); return; } } Spell* spell = sSpellFactoryMgr.NewSpell(GetPlayer(), spellInfo, false, NULL); spell->extra_cast_number = cn; spell->prepare(&targets); } }
void Player::SendInitialLogonPackets() { // Initial Packets... they seem to be re-sent on port. //m_session->OutPacket(SMSG_SET_REST_START_OBSOLETE, 4, &m_timeLogoff); // Seem to be unused by client StackWorldPacket<32> data(SMSG_BINDPOINTUPDATE); data << float(m_bind_pos_x); data << float(m_bind_pos_y); data << float(m_bind_pos_z); data << uint32(m_bind_mapid); data << uint32(m_bind_zoneid); m_session->SendPacket(&data); //Proficiencies SendSetProficiency(4, armor_proficiency); SendSetProficiency(2, weapon_proficiency); //Tutorial Flags data.Initialize(SMSG_TUTORIAL_FLAGS); for(int i = 0; i < 8; i++) data << uint32(m_Tutorials[i]); m_session->SendPacket(&data); smsg_TalentsInfo(false); smsg_InitialSpells(); data.Initialize(SMSG_SEND_UNLEARN_SPELLS); data << uint32(0); // count, for(count) uint32; GetSession()->SendPacket(&data); SendInitialActions(); smsg_InitialFactions(); /* Some minor documentation about the time field // MOVE THIS DOCUMENTATION TO THE WIKI minute's = 0x0000003F 00000000000000000000000000111111 hour's = 0x000007C0 00000000000000000000011111000000 weekdays = 0x00003800 00000000000000000011100000000000 days = 0x000FC000 00000000000011111100000000000000 months = 0x00F00000 00000000111100000000000000000000 years = 0x1F000000 00011111000000000000000000000000 unk = 0xE0000000 11100000000000000000000000000000 */ data.Initialize(SMSG_LOGIN_SETTIMESPEED); time_t minutes = sWorld.GetGameTime() / 60; time_t hours = minutes / 60; minutes %= 60; time_t gameTime = 0; // TODO: Add stuff to handle these variables time_t basetime = UNIXTIME; uint32 DayOfTheWeek; if(localtime(&basetime)->tm_wday == 0) DayOfTheWeek = 6; else DayOfTheWeek = localtime(&basetime)->tm_wday - 1; uint32 DayOfTheMonth = localtime(&basetime)->tm_mday - 1; uint32 CurrentMonth = localtime(&basetime)->tm_mon; uint32 CurrentYear = localtime(&basetime)->tm_year - 100; #define MINUTE_BITMASK 0x0000003F #define HOUR_BITMASK 0x000007C0 #define WEEKDAY_BITMASK 0x00003800 #define DAY_BITMASK 0x000FC000 #define MONTH_BITMASK 0x00F00000 #define YEAR_BITMASK 0x1F000000 #define UNK_BITMASK 0xE0000000 #define MINUTE_SHIFTMASK 0 #define HOUR_SHIFTMASK 6 #define WEEKDAY_SHIFTMASK 11 #define DAY_SHIFTMASK 14 #define MONTH_SHIFTMASK 20 #define YEAR_SHIFTMASK 24 #define UNK_SHIFTMASK 29 gameTime = ((minutes << MINUTE_SHIFTMASK) & MINUTE_BITMASK); gameTime |= ((hours << HOUR_SHIFTMASK) & HOUR_BITMASK); gameTime |= ((DayOfTheWeek << WEEKDAY_SHIFTMASK) & WEEKDAY_BITMASK); gameTime |= ((DayOfTheMonth << DAY_SHIFTMASK) & DAY_BITMASK); gameTime |= ((CurrentMonth << MONTH_SHIFTMASK) & MONTH_BITMASK); gameTime |= ((CurrentYear << YEAR_SHIFTMASK) & YEAR_BITMASK); data << uint32(gameTime); data << float(0.0166666669777748f); // Normal Game Speed data << uint32(0); // 3.1.2 m_session->SendPacket(&data); // cebernic for speedhack bug m_lastRunSpeed = 0; UpdateSpeed(); WorldPacket ArenaSettings(SMSG_UPDATE_WORLD_STATE, 16); ArenaSettings << uint32(0xC77); ArenaSettings << uint32(sWorld.Arena_Progress); ArenaSettings << uint32(0xF3D); ArenaSettings << uint32(sWorld.Arena_Season); m_session->SendPacket(&ArenaSettings); LOG_DETAIL("WORLD: Sent initial logon packets for %s.", GetName()); }
void SpellFactoryMgr::LoadSpellAreas() { mSpellAreaMap.clear(); mSpellAreaForQuestMap.clear(); mSpellAreaForActiveQuestMap.clear(); mSpellAreaForQuestEndMap.clear(); mSpellAreaForAuraMap.clear(); // 0 1 2 3 4 5 6 7 8 QueryResult* result = WorldDatabase.Query("SELECT spell, area, quest_start, quest_start_active, quest_end, aura_spell, racemask, gender, autocast FROM spell_area"); if (!result) { LOG_DETAIL("Loaded 0 spell area requirements. DB table `spell_area` is empty."); return; } uint32 pCount = 0; do { Field* fields = result->Fetch(); uint32 spell = fields[0].GetUInt32(); SpellArea spellArea; spellArea.spellId = spell; spellArea.areaId = fields[1].GetUInt32(); spellArea.questStart = fields[2].GetUInt32(); spellArea.questStartCanActive = fields[3].GetBool(); spellArea.questEnd = fields[4].GetUInt32(); spellArea.auraSpell = fields[5].GetInt32(); spellArea.raceMask = fields[6].GetUInt32(); spellArea.gender = Gender(fields[7].GetUInt8()); spellArea.autocast = fields[8].GetBool(); { bool ok = true; SpellAreaMapBounds sa_bounds = GetSpellAreaMapBounds(spellArea.spellId); for (SpellAreaMap::const_iterator itr = sa_bounds.first; itr != sa_bounds.second; ++itr) { if (spellArea.spellId != itr->second.spellId) continue; if (spellArea.areaId != itr->second.areaId) continue; if (spellArea.questStart != itr->second.questStart) continue; if (spellArea.auraSpell != itr->second.auraSpell) continue; if ((spellArea.raceMask & itr->second.raceMask) == 0) continue; if (spellArea.gender != itr->second.gender) continue; // duplicate by requirements ok = false; break; } if (!ok) { LOG_ERROR("Spell %u listed in `spell_area` already listed with similar requirements.", spell); continue; } } /* if (spellArea.areaId && !AreaTriggerStorage.LookupEntry(spellArea.areaId)) { printf("Spell %u listed in `spell_area` have wrong area (%u) requirement \n", spell, spellArea.areaId); continue; } */ if (spellArea.questStart && !sMySQLStore.getQuestProperties(spellArea.questStart)) { LOG_ERROR("Spell %u listed in `spell_area` have wrong start quest (%u) requirement.", spell, spellArea.questStart); continue; } if (spellArea.questEnd) { if (!sMySQLStore.getQuestProperties(spellArea.questEnd)) { LOG_ERROR("Spell %u listed in `spell_area` have wrong end quest (%u) requirement.", spell, spellArea.questEnd); continue; } if (spellArea.questEnd == spellArea.questStart && !spellArea.questStartCanActive) { LOG_ERROR("Spell %u listed in `spell_area` have quest (%u) requirement for start and end in same time.", spell, spellArea.questEnd); continue; } } if (spellArea.auraSpell) { SpellInfo const* spellInfo = sSpellCustomizations.GetSpellInfo(abs(spellArea.auraSpell)); if (!spellInfo) { LOG_ERROR("Spell %u listed in `spell_area` have wrong aura spell (%u) requirement.", spell, abs(spellArea.auraSpell)); continue; } if (uint32(abs(spellArea.auraSpell)) == spellArea.spellId) { LogDebugFlag(LF_SPELL, "Spell %u listed in `spell_area` have aura spell (%u) requirement for itself.", spell, abs(spellArea.auraSpell)); continue; } // not allow autocast chains by auraSpell field (but allow use as alternative if not present) if (spellArea.autocast && spellArea.auraSpell > 0) { bool chain = false; SpellAreaForAuraMapBounds saBound = GetSpellAreaForAuraMapBounds(spellArea.spellId); for (SpellAreaForAuraMap::const_iterator itr = saBound.first; itr != saBound.second; ++itr) { if (itr->second->autocast && itr->second->auraSpell > 0) { chain = true; break; } } if (chain) { LogDebugFlag(LF_SPELL, "Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura.", spell, spellArea.auraSpell); continue; } SpellAreaMapBounds saBound2 = GetSpellAreaMapBounds(spellArea.auraSpell); for (SpellAreaMap::const_iterator itr2 = saBound2.first; itr2 != saBound2.second; ++itr2) { if (itr2->second.autocast && itr2->second.auraSpell > 0) { chain = true; break; } } if (chain) { LogDebugFlag(LF_SPELL, "Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura.", spell, spellArea.auraSpell); continue; } } } if (spellArea.raceMask && (spellArea.raceMask & RACEMASK_ALL_PLAYABLE) == 0) { LOG_ERROR("Spell %u listed in `spell_area` have wrong race mask (%u) requirement.", spell, spellArea.raceMask); continue; } if (spellArea.gender != GENDER_NONE && spellArea.gender != GENDER_FEMALE && spellArea.gender != GENDER_MALE) { LOG_ERROR("Spell %u listed in `spell_area` have wrong gender (%u) requirement.", spell, spellArea.gender); continue; } SpellArea const* sa = &mSpellAreaMap.insert(SpellAreaMap::value_type(spell, spellArea))->second; // for search by current zone/subzone at zone/subzone change if (spellArea.areaId) mSpellAreaForAreaMap.insert(SpellAreaForAreaMap::value_type(spellArea.areaId, sa)); // for search at quest start/reward if (spellArea.questStart) { if (spellArea.questStartCanActive) mSpellAreaForActiveQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questStart, sa)); else mSpellAreaForQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questStart, sa)); } // for search at quest start/reward if (spellArea.questEnd) mSpellAreaForQuestEndMap.insert(SpellAreaForQuestMap::value_type(spellArea.questEnd, sa)); // for search at aura apply if (spellArea.auraSpell) mSpellAreaForAuraMap.insert(SpellAreaForAuraMap::value_type(abs(spellArea.auraSpell), sa)); ++pCount; } while (result->NextRow()); delete result; LOG_DETAIL("Loaded %u spell area requirements.", pCount); }
void AddonMgr::SendAddonInfoPacket(WorldPacket* source, uint32 pos, WorldSession* m_session) { WorldPacket returnpacket; returnpacket.Initialize(SMSG_ADDON_INFO); // SMSG_ADDON_INFO uint32 realsize; uLongf rsize; try { *source >> realsize; } catch(ByteBuffer::error &) { LOG_DEBUG("Warning: Incomplete auth session sent."); return; } rsize = realsize; size_t position = source->rpos(); ByteBuffer unpacked; unpacked.resize(realsize); if((source->size() - position) < 4 || realsize == 0) { // we shouldn't get here.. but just in case this will stop any crash here. LOG_DEBUG("Warning: Incomplete auth session sent."); return; } int32 result = uncompress((uint8*)unpacked.contents(), &rsize, (uint8*)(*source).contents() + position, (uLong)((*source).size() - position)); if(result != Z_OK) { LOG_ERROR("Decompression of addon section of CMSG_AUTH_SESSION failed."); return; } LOG_DETAIL("Decompression of addon section of CMSG_AUTH_SESSION succeeded."); uint8 Enable; // based on the parsed files from retool uint32 crc; uint32 unknown; std::string name; uint32 addoncount; unpacked >> addoncount; uint8 unk; uint8 unk1; uint8 unk2; for(uint32 i = 0; i < addoncount; ++i) { if(unpacked.rpos() >= unpacked.size()) break; unpacked >> name; unpacked >> Enable; unpacked >> crc; unpacked >> unknown; // Hacky fix, Yea I know its a hacky fix I will make a proper handler one's I got the crc crap /* if (crc != 0x4C1C776D) // CRC of public key version 2.0.1 returnpacket.append(PublicKey,264); // part of the hacky fix else returnpacket << uint8(0x02) << uint8(0x01) << uint8(0x00) << uint32(0) << uint8(0);*/ /*if(!AppendPublicKey(returnpacket, name, crc)) returnpacket << uint8(1) << uint8(0) << uint8(0);*/ unk = (Enable ? 2 : 1); returnpacket << unk; unk1 = (Enable ? 1 : 0); returnpacket << unk1; if(unk1) { if(crc != 0x4C1C776D) { returnpacket << uint8(1); returnpacket.append(PublicKey, 264); } else returnpacket << uint8(0); returnpacket << uint32(0); } unk2 = (Enable ? 0 : 1); returnpacket << unk2; if(unk2) returnpacket << uint8(0); } /*unknown 4 bytes at the end of the packet. Stays 0 for me. Tried custom addons, deleting, faulty etc. It stays 0. */ returnpacket << uint32(0); //Some additional count for additional records, but we won't send them. m_session->SendPacket(&returnpacket); }