Changeset 6 for trunk/src/game
- Timestamp:
- 11/19/08 13:22:12 (17 years ago)
- Location:
- trunk/src/game
- Files:
-
- 39 modified
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/game/AggressorAI.cpp
r2 r6 44 44 AggressorAI::MoveInLineOfSight(Unit *u) 45 45 { 46 if( i_creature.GetDistanceZ(u) > CREATURE_Z_ATTACK_RANGE ) 46 // Ignore Z for flying creatures 47 if( !i_creature.canFly() && i_creature.GetDistanceZ(u) > CREATURE_Z_ATTACK_RANGE ) 47 48 return; 49 48 50 if( !i_creature.getVictim() && !i_creature.hasUnitState(UNIT_STAT_STUNDED) && u->isTargetableForAttack() && 49 51 ( i_creature.IsHostileTo( u ) /*|| u->getVictim() && i_creature.IsFriendlyTo( u->getVictim() )*/ ) && -
trunk/src/game/CharacterHandler.cpp
r2 r6 20 20 #include "Database/DatabaseEnv.h" 21 21 #include "WorldPacket.h" 22 #include " WorldSocket.h"22 #include "SharedDefines.h" 23 23 #include "WorldSession.h" 24 24 #include "Opcodes.h" … … 367 367 SendPacket( &data ); 368 368 369 std::string IP_str = _socket ? _socket->GetRemoteAddress().c_str() : "-";369 std::string IP_str = GetRemoteAddress().c_str(); 370 370 sLog.outBasic("Account: %d (IP: %s) Create Character:[%s]",GetAccountId(),IP_str.c_str(),name.c_str()); 371 371 sLog.outChar("Account: %d (IP: %s) Create Character:[%s]",GetAccountId(),IP_str.c_str(),name.c_str()); … … 417 417 return; 418 418 419 std::string IP_str = _socket ? _socket->GetRemoteAddress().c_str() : "-";419 std::string IP_str = GetRemoteAddress(); 420 420 sLog.outBasic("Account: %d (IP: %s) Delete Character:[%s] (guid:%u)",GetAccountId(),IP_str.c_str(),name.c_str(),GUID_LOPART(guid)); 421 421 sLog.outChar("Account: %d (IP: %s) Delete Character:[%s] (guid: %u)",GetAccountId(),IP_str.c_str(),name.c_str(),GUID_LOPART(guid)); … … 735 735 SendNotification("GM mode is ON"); 736 736 737 std::string IP_str = _socket ? _socket->GetRemoteAddress().c_str() : "-";737 std::string IP_str = GetRemoteAddress(); 738 738 sLog.outChar("Account: %d (IP: %s) Login Character:[%s] (guid:%u)",GetAccountId(),IP_str.c_str(),pCurrChar->GetName() ,pCurrChar->GetGUID()); 739 739 … … 967 967 CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid ='%u'", GUID_LOPART(guid)); 968 968 969 std::string IP_str = _socket ? _socket->GetRemoteAddress().c_str() : "-";969 std::string IP_str = GetRemoteAddress(); 970 970 sLog.outChar("Account: %d (IP: %s) Character:[%s] (guid:%u) Changed name to: %s",GetAccountId(),IP_str.c_str(),oldname.c_str(),GUID_LOPART(guid),newname.c_str()); 971 971 -
trunk/src/game/Chat.cpp
r2 r6 194 194 { 195 195 { "all", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllCommand, "", NULL }, 196 { "all_loot", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllLootCommand, "", NULL }, 197 { "all_npc", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllNpcCommand, "", NULL }, 196 198 { "all_quest", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllQuestCommand, "", NULL }, 197 { "all_loot", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllLootCommand, "", NULL },198 199 { "all_scripts", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllScriptsCommand, "", NULL }, 199 200 { "all_spell", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadAllSpellCommand, "", NULL }, … … 213 214 { "fishing_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesFishingCommand, "", NULL }, 214 215 { "game_graveyard_zone", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadGameGraveyardZoneCommand, "", NULL }, 216 { "game_tele", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadGameTeleCommand, "", NULL }, 215 217 { "gameobject_involvedrelation", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadGOQuestInvRelationsCommand, "", NULL }, 216 218 { "gameobject_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesGameobjectCommand, "", NULL }, … … 220 222 { "item_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesItemCommand, "", NULL }, 221 223 { "mangos_string", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadMangosStringCommand, "", NULL }, 224 { "npc_gossip", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadNpcGossipCommand, "", NULL }, 225 { "npc_trainer", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadNpcTrainerCommand, "", NULL }, 226 { "npc_vendor", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadNpcVendorCommand, "", NULL }, 222 227 { "page_text", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadPageTextsCommand, "", NULL }, 223 228 { "pickpocketing_loot_template", SEC_ADMINISTRATOR, &ChatHandler::HandleReloadLootTemplatesPickpocketingCommand,"",NULL}, … … 265 270 }; 266 271 272 static ChatCommand lookupPlayerCommandTable[] = 273 { 274 { "ip", SEC_GAMEMASTER, &ChatHandler::HandleLookupPlayerIpCommand, "", NULL }, 275 { "account", SEC_GAMEMASTER, &ChatHandler::HandleLookupPlayerAccountCommand, "", NULL }, 276 { "email", SEC_GAMEMASTER, &ChatHandler::HandleLookupPlayerEmailCommand, "", NULL }, 277 { NULL, 0, NULL, "", NULL } 278 }; 279 267 280 static ChatCommand lookupCommandTable[] = 268 281 { … … 275 288 { "object", SEC_ADMINISTRATOR, &ChatHandler::HandleLookupObjectCommand, "", NULL }, 276 289 { "quest", SEC_ADMINISTRATOR, &ChatHandler::HandleLookupQuestCommand, "", NULL }, 290 { "player", SEC_GAMEMASTER, NULL, "", lookupPlayerCommandTable }, 277 291 { "skill", SEC_ADMINISTRATOR, &ChatHandler::HandleLookupSkillCommand, "", NULL }, 278 292 { "spell", SEC_ADMINISTRATOR, &ChatHandler::HandleLookupSpellCommand, "", NULL }, … … 1102 1116 } 1103 1117 1118 GameTele const* ChatHandler::extractGameTeleFromLink(char* text) 1119 { 1120 // id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r 1121 char* cId = extractKeyFromLink(text,"Htele"); 1122 if(!cId) 1123 return false; 1124 1125 // id case (explicit or from shift link) 1126 if(cId[0] >= '0' || cId[0] >= '9') 1127 if(uint32 id = atoi(cId)) 1128 return objmgr.GetGameTele(id); 1129 1130 return objmgr.GetGameTele(cId); 1131 } -
trunk/src/game/Chat.h
r2 r6 27 27 class Player; 28 28 class Unit; 29 struct GameTele; 29 30 30 31 struct LanguageDesc … … 151 152 bool HandleReloadAllItemCommand(const char* args); 152 153 bool HandleReloadAllLootCommand(const char* args); 154 bool HandleReloadAllNpcCommand(const char* args); 153 155 bool HandleReloadAllQuestCommand(const char* args); 154 156 bool HandleReloadAllScriptsCommand(const char* args); … … 165 167 bool HandleReloadGameGraveyardZoneCommand(const char* args); 166 168 bool HandleReloadGameObjectScriptsCommand(const char* args); 169 bool HandleReloadGameTeleCommand(const char* args); 167 170 bool HandleReloadGOQuestRelationsCommand(const char* args); 168 171 bool HandleReloadGOQuestInvRelationsCommand(const char* args); … … 178 181 bool HandleReloadLootTemplatesSkinningCommand(const char* args); 179 182 bool HandleReloadMangosStringCommand(const char* args); 183 bool HandleReloadNpcGossipCommand(const char* args); 184 bool HandleReloadNpcTrainerCommand(const char* args); 185 bool HandleReloadNpcVendorCommand(const char* args); 180 186 bool HandleReloadQuestAreaTriggersCommand(const char* args); 181 187 bool HandleReloadQuestEndScriptsCommand(const char* args); … … 265 271 bool HandleAllowMovementCommand(const char* args); 266 272 bool HandleGoCommand(const char* args); 273 267 274 bool HandleLearnCommand(const char* args); 268 275 bool HandleLearnAllCommand(const char* args); … … 275 282 bool HandleLearnAllMySpellsCommand(const char* args); 276 283 bool HandleLearnAllMyTalentsCommand(const char* args); 284 285 bool HandleLookupAreaCommand(const char* args); 286 bool HandleLookupCreatureCommand(const char* args); 287 bool HandleLookupEventCommand(const char* args); 288 bool HandleLookupFactionCommand(const char * args); 289 bool HandleLookupItemCommand(const char * args); 290 bool HandleLookupItemSetCommand(const char * args); 291 bool HandleLookupObjectCommand(const char* args); 292 bool HandleLookupPlayerIpCommand(const char* args); 293 bool HandleLookupPlayerAccountCommand(const char* args); 294 bool HandleLookupPlayerEmailCommand(const char* args); 295 bool HandleLookupQuestCommand(const char* args); 296 bool HandleLookupSkillCommand(const char* args); 297 bool HandleLookupSpellCommand(const char* args); 298 bool HandleLookupTeleCommand(const char * args); 299 277 300 bool HandleCooldownCommand(const char* args); 278 301 bool HandleUnLearnCommand(const char* args); … … 300 323 bool HandleAddItemCommand(const char* args); 301 324 bool HandleAddItemSetCommand(const char* args); 302 bool HandleLookupItemCommand(const char * args); 303 bool HandleLookupItemSetCommand(const char * args); 325 304 326 bool HandleGuildCreateCommand(const char* args); 305 327 bool HandleGuildInviteCommand(const char* args); … … 315 337 bool HandleDelTeleCommand(const char * args); 316 338 bool HandleListAurasCommand(const char * args); 317 bool HandleLookupTeleCommand(const char * args);318 339 319 340 bool HandleResetHonorCommand(const char * args); … … 333 354 bool HandleListObjectCommand(const char* args); 334 355 bool HandleNearObjectCommand(const char* args); 335 bool HandleLookupAreaCommand(const char* args);336 bool HandleLookupCreatureCommand(const char* args);337 bool HandleLookupEventCommand(const char* args);338 bool HandleLookupFactionCommand(const char * args);339 bool HandleLookupObjectCommand(const char* args);340 bool HandleLookupQuestCommand(const char* args);341 bool HandleLookupSkillCommand(const char* args);342 bool HandleLookupSpellCommand(const char* args);343 356 bool HandlePasswordCommand(const char* args); 344 357 bool HandleLockAccountCommand(const char* args); … … 387 400 char* extractKeyFromLink(char* text, char const* const* linkTypes, int* found_idx, char** something1 = NULL); 388 401 uint32 extractSpellIdFromLink(char* text); 402 GameTele const* extractGameTeleFromLink(char* text); 389 403 390 404 GameObject* GetObjectGlobalyWithGuidOrNearWithDbGuid(uint32 lowguid,uint32 entry); … … 395 409 void ShowTicket(uint64 guid, char const* text, char const* time); 396 410 uint32 GetTicketIDByNum(uint32 num); 411 bool LookupPlayerSearchCommand(QueryResult* result, int32 limit); 397 412 398 413 void SetSentErrorMessage(bool val){ sentErrorMessage = val;}; -
trunk/src/game/Creature.cpp
r2 r6 47 47 #include "Policies/SingletonImp.h" 48 48 49 void TrainerSpellData::Clear() 50 { 51 for (TrainerSpellList::iterator itr = spellList.begin(); itr != spellList.end(); ++itr) 52 delete (*itr); 53 spellList.empty(); 54 } 55 56 TrainerSpell const* TrainerSpellData::Find(uint32 spell_id) const 57 { 58 for(TrainerSpellList::const_iterator itr = spellList.begin(); itr != spellList.end(); ++itr) 59 if((*itr)->spell == spell_id) 60 return *itr; 61 62 return NULL; 63 } 64 49 65 Creature::Creature() : 50 66 Unit(), i_AI(NULL), 51 67 lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLeaderGUID(0), 52 m_itemsLoaded(false), m_ trainerSpellsLoaded(false), m_trainer_type(0), m_lootMoney(0), m_lootRecipient(0),68 m_itemsLoaded(false), m_lootMoney(0), m_lootRecipient(0), 53 69 m_deathTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_respawnradius(0.0f), 54 m_gossipOptionLoaded(false),m_ NPCTextId(0), m_emoteState(0), m_isPet(false), m_isTotem(false),70 m_gossipOptionLoaded(false),m_emoteState(0), m_isPet(false), m_isTotem(false), 55 71 m_regenTimer(2000), m_defaultMovementType(IDLE_MOTION_TYPE), m_equipmentId(0), 56 72 m_AlreadyCallAssistence(false), m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false), … … 72 88 CleanupsBeforeDelete(); 73 89 74 m_trainer_spells.clear();75 90 m_vendor_items.clear(); 76 91 … … 91 106 if(IsInWorld()) ObjectAccessor::Instance().RemoveObject(this); 92 107 Unit::RemoveFromWorld(); 93 }94 95 void Creature::LoadTrainerSpells()96 {97 if(m_trainerSpellsLoaded)98 return;99 100 m_trainer_spells.clear();101 m_trainer_type = 0;102 103 Field *fields;104 QueryResult *result = WorldDatabase.PQuery("SELECT spell,spellcost,reqskill,reqskillvalue,reqlevel FROM npc_trainer WHERE entry = '%u'", GetEntry());105 106 if(!result)107 return;108 109 do110 {111 fields = result->Fetch();112 113 uint32 spellid = fields[0].GetUInt32();114 SpellEntry const *spellinfo = sSpellStore.LookupEntry(spellid);115 116 if(!spellinfo)117 {118 sLog.outErrorDb("Trainer (Entry: %u ) has non existing spell %u",GetEntry(),spellid);119 continue;120 }121 122 if(!SpellMgr::IsSpellValid(spellinfo))123 {124 sLog.outErrorDb("LoadTrainerSpells: Trainer (Entry: %u) has broken learning spell %u.", GetEntry(), spellid);125 continue;126 }127 128 if(SpellMgr::IsProfessionSpell(spellinfo->Id))129 m_trainer_type = 2;130 131 TrainerSpell tspell;132 tspell.spell = spellinfo;133 tspell.spellcost = fields[1].GetUInt32();134 tspell.reqskill = fields[2].GetUInt32();135 tspell.reqskillvalue= fields[3].GetUInt32();136 tspell.reqlevel = fields[4].GetUInt32();137 138 m_trainer_spells.push_back(tspell);139 140 } while( result->NextRow() );141 142 delete result;143 144 m_trainerSpellsLoaded = true;145 108 } 146 109 … … 551 514 return false; 552 515 553 if(m_trainer_spells.empty()) 516 TrainerSpellData const* trainer_spells = GetTrainerSpells(); 517 518 519 if(!trainer_spells || trainer_spells->spellList.empty()) 554 520 { 555 521 sLog.outErrorDb("Creature %u (Entry: %u) have UNIT_NPC_FLAG_TRAINER but have empty trainer spell list.", … … 719 685 break; 720 686 case GOSSIP_OPTION_TRAINER: 721 // Lazy loading at first access722 LoadTrainerSpells();723 724 687 if(!isCanTrainingOf(pPlayer,false)) 725 688 cantalking=false; … … 757 720 if(!gso->Option.empty() && cantalking ) 758 721 { //note for future dev: should have database fields for BoxMessage & BoxMoney 759 pm->GetGossipMenu() ->AddMenuItem((uint8)gso->Icon,gso->Option, gossipid,gso->Action,"",0,false);722 pm->GetGossipMenu().AddMenuItem((uint8)gso->Icon,gso->Option, gossipid,gso->Action,"",0,false); 760 723 ingso=gso; 761 724 } … … 764 727 765 728 ///some gossips aren't handled in normal way ... so we need to do it this way .. TODO: handle it in normal way ;-) 766 if(pm-> GetGossipMenu()->MenuItemCount()==0 && !pm->GetQuestMenu()->MenuItemCount())729 if(pm->Empty()) 767 730 { 768 731 if(HasFlag(UNIT_NPC_FLAGS,UNIT_NPC_FLAG_TRAINER)) 769 732 { 770 LoadTrainerSpells(); // Lazy loading at first access771 733 isCanTrainingOf(pPlayer,true); // output error message if need 772 734 } … … 783 745 return; 784 746 785 GossipMenu *gossipmenu = player->PlayerTalkClass->GetGossipMenu();747 GossipMenu& gossipmenu = player->PlayerTalkClass->GetGossipMenu(); 786 748 787 749 // in case empty gossip menu open quest menu if any 788 if (gossipmenu ->MenuItemCount() == 0&& GetNpcTextId() == 0)750 if (gossipmenu.Empty() && GetNpcTextId() == 0) 789 751 { 790 752 player->SendPreparedQuest(GetGUID()); … … 799 761 void Creature::OnGossipSelect(Player* player, uint32 option) 800 762 { 801 GossipMenu* gossipmenu = player->PlayerTalkClass->GetGossipMenu(); 802 uint32 action=gossipmenu->GetItem(option).m_gAction; 763 GossipMenu& gossipmenu = player->PlayerTalkClass->GetGossipMenu(); 764 765 if(option >= gossipmenu.MenuItemCount()) 766 return; 767 768 uint32 action=gossipmenu.GetItem(option).m_gAction; 803 769 uint32 zoneid=GetZoneId(); 804 770 uint64 guid=GetGUID(); … … 969 935 uint32 Creature::GetNpcTextId() 970 936 { 971 // already loaded and cached 972 if(m_NPCTextId) 973 return m_NPCTextId; 974 975 QueryResult* result = WorldDatabase.PQuery("SELECT textid FROM npc_gossip WHERE npc_guid= '%u'", m_DBTableGuid); 976 if(result) 977 { 978 Field *fields = result->Fetch(); 979 m_NPCTextId = fields[0].GetUInt32(); 980 delete result; 981 } 982 else 983 m_NPCTextId = DEFAULT_GOSSIP_MESSAGE; 984 985 return m_NPCTextId; 937 if(uint32 pos = objmgr.GetNpcGossip(m_DBTableGuid)) 938 return pos; 939 940 return DEFAULT_GOSSIP_MESSAGE; 986 941 } 987 942 … … 1400 1355 m_vendor_items.clear(); 1401 1356 1402 QueryResult *result = WorldDatabase.PQuery("SELECT item, maxcount, incrtime, ExtendedCost FROM npc_vendor WHERE entry = '%u'", GetEntry()); 1403 1404 if(!result) 1357 VendorItemList const* vList = objmgr.GetNpcVendorItemList(GetEntry()); 1358 if(!vList) 1405 1359 return; 1406 1360 1407 do 1408 { 1409 Field *fields = result->Fetch(); 1410 1411 if (GetItemCount() >= MAX_VENDOR_ITEMS) 1412 { 1413 sLog.outErrorDb( "Vendor %u has too many items (%u >= %i). Check the DB!", GetEntry(), GetItemCount(), MAX_VENDOR_ITEMS ); 1414 break; 1415 } 1416 1417 uint32 item_id = fields[0].GetUInt32(); 1418 if(!sItemStorage.LookupEntry<ItemPrototype>(item_id)) 1419 { 1420 sLog.outErrorDb("Vendor %u have in item list non-existed item %u",GetEntry(),item_id); 1421 continue; 1422 } 1423 1424 uint32 ExtendedCost = fields[3].GetUInt32(); 1425 if(ExtendedCost && !sItemExtendedCostStore.LookupEntry(ExtendedCost)) 1426 sLog.outErrorDb("Item (Entry: %u) has wrong ExtendedCost (%u) for vendor (%u)",item_id,ExtendedCost,GetEntry()); 1427 1428 AddItem( item_id, fields[1].GetUInt32(), fields[2].GetUInt32(), ExtendedCost); 1429 } 1430 while( result->NextRow() ); 1431 1432 delete result; 1361 for (VendorItemList::const_iterator _item_iter = vList->begin(); _item_iter != vList->end(); ++_item_iter) 1362 AddItem( (*_item_iter)->item, (*_item_iter)->maxcount, (*_item_iter)->incrtime, (*_item_iter)->ExtendedCost); 1433 1363 1434 1364 m_itemsLoaded = true; … … 1992 1922 return ObjectMgr::GetCreatureTemplate(GetEntry())->ScriptName; 1993 1923 } 1924 1925 TrainerSpellData const* Creature::GetTrainerSpells() const 1926 { 1927 return objmgr.GetNpcTrainerSpells(GetEntry()); 1928 } -
trunk/src/game/Creature.h
r2 r6 124 124 uint32 lastincr; 125 125 uint32 ExtendedCost; 126 };127 128 struct TrainerSpell129 {130 SpellEntry const* spell;131 uint32 spellcost;132 uint32 reqskill;133 uint32 reqskillvalue;134 uint32 reqlevel;135 126 }; 136 127 … … 301 292 #endif 302 293 294 struct TrainerSpell 295 { 296 uint32 spell; 297 uint32 spellcost; 298 uint32 reqskill; 299 uint32 reqskillvalue; 300 uint32 reqlevel; 301 }; 302 303 typedef std::vector<TrainerSpell*> TrainerSpellList; 304 305 struct TrainerSpellData 306 { 307 TrainerSpellData() : trainerType(0) {} 308 309 TrainerSpellList spellList; 310 uint32 trainerType; // trainer type based at trainer spells, can be different from creature_template value. 311 // req. for correct show non-prof. trainers like weaponmaster, allowed values 0 and 2. 312 313 void Clear(); 314 TrainerSpell const* Find(uint32 spell_id) const; 315 }; 316 303 317 typedef std::list<GossipOption> GossipOptionList; 304 318 … … 441 455 } 442 456 443 /*********************************************************/ 444 /*** TRAINER SYSTEM ***/ 445 /*********************************************************/ 446 typedef std::list<TrainerSpell> SpellsList; 447 void LoadTrainerSpells(); // must be called before access to trainer spells, lazy loading at first call 448 void ReloadTrainerSpells() { m_trainerSpellsLoaded = false; LoadTrainerSpells(); } 449 SpellsList const& GetTrainerSpells() const { return m_trainer_spells; } 450 uint32 GetTrainerType() const { return m_trainer_type; } 457 TrainerSpellData const* GetTrainerSpells() const; 451 458 452 459 CreatureInfo const *GetCreatureInfo() const { return m_creatureInfo; } … … 559 566 bool m_itemsLoaded; // vendor items loading state 560 567 561 // trainer spells562 bool m_trainerSpellsLoaded; // trainer spells loading state563 SpellsList m_trainer_spells;564 uint32 m_trainer_type; // trainer type based at trainer spells, can be different from creature_template value.565 // req. for correct show non-prof. trainers like weaponmaster.566 568 void _RealtimeSetCreatureInfo(); 567 569 … … 581 583 bool m_gossipOptionLoaded; 582 584 GossipOptionList m_goptions; 583 uint32 m_NPCTextId; // cached value584 585 585 586 uint8 m_emoteState; -
trunk/src/game/CreatureAISelector.cpp
r2 r6 54 54 { 55 55 if( creature->isGuard() ) 56 ai name="GuardAI";56 ai_factory = ai_registry.GetRegistryItem("GuardAI"); 57 57 else if(creature->isPet() || creature->isCharmed()) 58 ai name="PetAI";58 ai_factory = ai_registry.GetRegistryItem("PetAI"); 59 59 else if(creature->isTotem()) 60 ainame="TotemAI"; 61 62 ai_factory = ai_registry.GetRegistryItem( ainame.c_str() ); 60 ai_factory = ai_registry.GetRegistryItem("TotemAI"); 63 61 } 64 62 -
trunk/src/game/GossipDef.cpp
r2 r6 92 92 } 93 93 94 PlayerMenu::PlayerMenu( WorldSession *Session ) 95 { 96 pGossipMenu = new GossipMenu(); 97 pQuestMenu = new QuestMenu(); 98 pSession = Session; 94 PlayerMenu::PlayerMenu( WorldSession *session ) : pSession(session) 95 { 99 96 } 100 97 101 98 PlayerMenu::~PlayerMenu() 102 99 { 103 delete pGossipMenu; 104 delete pQuestMenu; 100 ClearMenus(); 105 101 } 106 102 107 103 void PlayerMenu::ClearMenus() 108 104 { 109 pGossipMenu->ClearMenu();110 pQuestMenu->ClearMenu();105 mGossipMenu.ClearMenu(); 106 mQuestMenu.ClearMenu(); 111 107 } 112 108 113 109 uint32 PlayerMenu::GossipOptionSender( unsigned int Selection ) 114 110 { 115 return pGossipMenu->MenuItemSender( Selection );111 return mGossipMenu.MenuItemSender( Selection ); 116 112 } 117 113 118 114 uint32 PlayerMenu::GossipOptionAction( unsigned int Selection ) 119 115 { 120 return pGossipMenu->MenuItemAction( Selection );116 return mGossipMenu.MenuItemAction( Selection ); 121 117 } 122 118 123 119 bool PlayerMenu::GossipOptionCoded( unsigned int Selection ) 124 120 { 125 return pGossipMenu->MenuItemCoded( Selection );121 return mGossipMenu.MenuItemCoded( Selection ); 126 122 } 127 123 … … 132 128 data << uint32(0); // new 2.4.0 133 129 data << uint32( TitleTextId ); 134 data << uint32( pGossipMenu->MenuItemCount() ); // max count 0x0F135 136 for ( unsigned int iI = 0; iI < pGossipMenu->MenuItemCount(); iI++ )137 { 138 GossipMenuItem const& gItem = pGossipMenu->GetItem(iI);130 data << uint32( mGossipMenu.MenuItemCount() ); // max count 0x0F 131 132 for ( unsigned int iI = 0; iI < mGossipMenu.MenuItemCount(); iI++ ) 133 { 134 GossipMenuItem const& gItem = mGossipMenu.GetItem(iI); 139 135 data << uint32( iI ); 140 136 data << uint8( gItem.m_gIcon ); … … 151 147 } 152 148 153 data << uint32( pQuestMenu->MenuItemCount() ); // max count 0x20154 155 for ( uint16 iI = 0; iI < pQuestMenu->MenuItemCount(); iI++ )156 { 157 QuestMenuItem const& qItem = pQuestMenu->GetItem(iI);149 data << uint32( mQuestMenu.MenuItemCount() ); // max count 0x20 150 151 for ( uint16 iI = 0; iI < mQuestMenu.MenuItemCount(); iI++ ) 152 { 153 QuestMenuItem const& qItem = mQuestMenu.GetItem(iI); 158 154 uint32 questID = qItem.m_qId; 159 155 Quest const* pQuest = objmgr.GetQuestTemplate(questID); … … 358 354 data << uint32(eEmote._Delay ); // player emote 359 355 data << uint32(eEmote._Emote ); // NPC emote 360 data << uint8 ( pQuestMenu->MenuItemCount() ); 361 362 for ( uint16 iI = 0; iI < pQuestMenu->MenuItemCount(); iI++ ) 363 { 364 QuestMenuItem qmi=pQuestMenu->GetItem(iI); 356 data << uint8 ( mQuestMenu.MenuItemCount() ); 357 358 for ( uint16 iI = 0; iI < mQuestMenu.MenuItemCount(); iI++ ) 359 { 360 QuestMenuItem const& qmi = mQuestMenu.GetItem(iI); 361 365 362 uint32 questID = qmi.m_qId; 366 363 Quest const *pQuest = objmgr.GetQuestTemplate(questID); -
trunk/src/game/GossipDef.h
r2 r6 109 109 void AddMenuItem(uint8 Icon, char const* Message, uint32 dtSender, uint32 dtAction, char const* BoxMessage, uint32 BoxMoney, bool Coded = false); 110 110 111 unsigned int MenuItemCount() 111 unsigned int MenuItemCount() const 112 112 { 113 113 return m_gItems.size(); 114 } 115 116 bool Empty() const 117 { 118 return m_gItems.empty(); 114 119 } 115 120 … … 138 143 void ClearMenu(); 139 144 140 uint8 MenuItemCount() 145 uint8 MenuItemCount() const 141 146 { 142 147 return m_qItems.size(); 143 148 } 149 150 bool Empty() const 151 { 152 return m_qItems.empty(); 153 } 154 144 155 bool HasItem( uint32 questid ); 145 156 … … 156 167 { 157 168 private: 158 GossipMenu * pGossipMenu;159 QuestMenu * pQuestMenu;169 GossipMenu mGossipMenu; 170 QuestMenu mQuestMenu; 160 171 WorldSession* pSession; 161 172 … … 164 175 ~PlayerMenu(); 165 176 166 GossipMenu* GetGossipMenu() { return pGossipMenu; } 167 QuestMenu* GetQuestMenu() { return pQuestMenu; } 177 GossipMenu& GetGossipMenu() { return mGossipMenu; } 178 QuestMenu& GetQuestMenu() { return mQuestMenu; } 179 180 bool Empty() const { return mGossipMenu.Empty() && mQuestMenu.Empty(); } 168 181 169 182 void ClearMenus(); -
trunk/src/game/GridNotifiers.h
r2 r6 113 113 bool i_ownTeamOnly; 114 114 float i_dist; 115 MessageDistDeliverer(Player &pl, WorldPacket *msg, bool to_self, bool ownTeamOnly, float dist) : i_player(pl), i_message(msg), i_toSelf(to_self), i_ownTeamOnly(ownTeamOnly), i_dist(dist) {}115 MessageDistDeliverer(Player &pl, WorldPacket *msg, float dist, bool to_self, bool ownTeamOnly) : i_player(pl), i_message(msg), i_dist(dist), i_toSelf(to_self), i_ownTeamOnly(ownTeamOnly) {} 116 116 void Visit(PlayerMapType &m); 117 117 template<class SKIP> void Visit(GridRefManager<SKIP> &) {} -
trunk/src/game/GuardAI.cpp
r2 r6 38 38 void GuardAI::MoveInLineOfSight(Unit *u) 39 39 { 40 // Ignore Z for flying creatures 41 if ( !i_creature.canFly() && i_creature.GetDistanceZ(u) > CREATURE_Z_ATTACK_RANGE ) 42 return; 43 40 44 if( !i_creature.getVictim() && u->isTargetableForAttack() && 41 45 ( u->IsHostileToPlayers() || i_creature.IsHostileTo(u) /*|| u->getVictim() && i_creature.IsFriendlyTo(u->getVictim())*/ ) && … … 43 47 { 44 48 float attackRadius = i_creature.GetAttackDistance(u); 45 if(i_creature.IsWithinDistInMap(u,attackRadius) && i_creature.GetDistanceZ(u) <= CREATURE_Z_ATTACK_RANGE)49 if(i_creature.IsWithinDistInMap(u,attackRadius)) 46 50 { 47 51 //Need add code to let guard support player -
trunk/src/game/Guild.cpp
r2 r6 1806 1806 need_space = count; 1807 1807 1808 dest.push_back(GuildItemPosCount(slot,need_space)); 1809 count -= need_space; 1808 GuildItemPosCount newPosition = GuildItemPosCount(slot,need_space); 1809 if(!newPosition.isContainedIn(dest)) 1810 { 1811 dest.push_back(newPosition); 1812 count -= need_space; 1813 } 1814 1810 1815 return EQUIP_ERR_OK; 1811 1816 } … … 1837 1842 need_space = count; 1838 1843 1839 dest.push_back(GuildItemPosCount(j,need_space)); 1844 GuildItemPosCount newPosition = GuildItemPosCount(j,need_space); 1845 if(!newPosition.isContainedIn(dest)) 1846 { 1847 dest.push_back(newPosition); 1848 count -= need_space; 1849 1850 if(count==0) 1851 return EQUIP_ERR_OK; 1852 } 1853 } 1854 } 1855 else 1856 { 1857 uint32 need_space = pSrcItem->GetMaxStackCount(); 1858 if(need_space > count) 1859 need_space = count; 1860 1861 GuildItemPosCount newPosition = GuildItemPosCount(j,need_space); 1862 if(!newPosition.isContainedIn(dest)) 1863 { 1864 dest.push_back(newPosition); 1840 1865 count -= need_space; 1841 1866 … … 1843 1868 return EQUIP_ERR_OK; 1844 1869 } 1845 }1846 else1847 {1848 uint32 need_space = pSrcItem->GetMaxStackCount();1849 if(need_space > count)1850 need_space = count;1851 1852 dest.push_back(GuildItemPosCount(j,need_space));1853 count -= need_space;1854 1855 if(count==0)1856 return EQUIP_ERR_OK;1857 1870 } 1858 1871 } … … 1939 1952 session->SendPacket(&data); 1940 1953 } 1954 1955 bool GuildItemPosCount::isContainedIn(GuildItemPosCountVec const &vec) const 1956 { 1957 for(GuildItemPosCountVec::const_iterator itr = vec.begin(); itr != vec.end();++itr) 1958 if(itr->slot == this->slot) 1959 return true; 1960 1961 return false; 1962 } 1963 -
trunk/src/game/Guild.h
r2 r6 217 217 { 218 218 GuildItemPosCount(uint8 _slot, uint8 _count) : slot(_slot), count(_count) {} 219 220 bool isContainedIn(std::vector<GuildItemPosCount> const& vec) const; 219 221 220 222 uint8 slot; -
trunk/src/game/Language.h
r2 r6 154 154 LANG_COMMAND_TELE_NOTFOUND = 164, 155 155 LANG_COMMAND_TELE_PARAMETER = 165, 156 LANG_COMMAND_TELE_NO REQUEST= 166,157 LANG_COMMAND_TELE_NOLOCATION = 167,156 LANG_COMMAND_TELE_NOLOCATION = 166, 157 // 167 // not used 158 158 LANG_COMMAND_TELE_LOCATION = 168, 159 159 … … 301 301 LANG_COMMAND_FACTION_NOREP_ERROR = 326, 302 302 LANG_FACTION_NOREPUTATION = 327, 303 LANG_LOOKUP_PLAYER_ACCOUNT = 328, 304 LANG_LOOKUP_PLAYER_CHARACTER = 329, 305 LANG_NO_PLAYERS_FOUND = 330, 303 306 304 307 // Room for more level 2 … … 376 379 LANG_COMMAND_TP_ADDEDERR = 464, 377 380 LANG_COMMAND_TP_DELETED = 465, 378 LANG_COMMAND_TP_DELETEERR = 466,381 // 466, // not used 379 382 380 383 LANG_COMMAND_TARGET_LISTAURAS = 467, -
trunk/src/game/Level1.cpp
r2 r6 1555 1555 } 1556 1556 1557 //Teleport by game_tele entry1558 1557 bool ChatHandler::HandleModifyHonorCommand (const char* args) 1559 1558 { … … 1585 1584 Player* _player = m_session->GetPlayer(); 1586 1585 1587 char* cId = extractKeyFromLink((char*)args,"Htele"); // string or [name] Shift-click form |color|Htele:name|h[name]|h|r 1588 if(!cId) 1589 return false; 1590 1591 std::string name = cId; 1592 WorldDatabase.escape_string(name); 1593 1594 QueryResult *result = WorldDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map FROM game_tele WHERE name = '%s'",name.c_str()); 1595 if (!result) 1586 // id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r 1587 GameTele const* tele = extractGameTeleFromLink((char*)args); 1588 1589 if (!tele) 1596 1590 { 1597 1591 SendSysMessage(LANG_COMMAND_TELE_NOTFOUND); 1598 SetSentErrorMessage(true);1599 return false;1600 }1601 Field *fields = result->Fetch();1602 float x = fields[0].GetFloat();1603 float y = fields[1].GetFloat();1604 float z = fields[2].GetFloat();1605 float ort = fields[3].GetFloat();1606 int mapid = fields[4].GetUInt16();1607 delete result;1608 1609 if(!MapManager::IsValidMapCoord(mapid,x,y,x,ort))1610 {1611 PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid);1612 1592 SetSentErrorMessage(true); 1613 1593 return false; … … 1624 1604 _player->SaveRecallPosition(); 1625 1605 1626 _player->TeleportTo( mapid, x, y, z, ort);1606 _player->TeleportTo(tele->mapId, tele->position_x, tele->position_y, tele->position_z, tele->orientation); 1627 1607 return true; 1628 1608 } … … 1703 1683 1704 1684 std::string namepart = str; 1705 WorldDatabase.escape_string(namepart); 1706 QueryResult *result = WorldDatabase.PQuery("SELECT name FROM game_tele WHERE name "_LIKE_" '""%%%s%%""'",namepart.c_str()); 1707 if (!result) 1708 { 1709 SendSysMessage(LANG_COMMAND_TELE_NOREQUEST); 1710 SetSentErrorMessage(true); 1711 return false; 1712 } 1713 std::string reply; 1714 for (uint64 i=0; i < result->GetRowCount(); i++) 1715 { 1716 Field *fields = result->Fetch(); 1717 reply += " |cffffffff|Htele:"; 1718 reply += fields[0].GetCppString(); 1719 reply += "|h["; 1720 reply += fields[0].GetCppString(); 1721 reply += "]|h|r\n"; 1722 result->NextRow(); 1723 } 1724 delete result; 1725 1726 if(reply.empty()) 1685 std::wstring wnamepart; 1686 1687 if(!Utf8toWStr(namepart,wnamepart)) 1688 return false; 1689 1690 // converting string that we try to find to lower case 1691 wstrToLower( wnamepart ); 1692 1693 GameTeleMap const & teleMap = objmgr.GetGameTeleMap(); 1694 1695 std::ostringstream reply; 1696 for(GameTeleMap::const_iterator itr = teleMap.begin(); itr != teleMap.end(); ++itr) 1697 { 1698 GameTele const* tele = &itr->second; 1699 1700 if(tele->wnameLow.find(wnamepart) == std::wstring::npos) 1701 continue; 1702 1703 reply << " |cffffffff|Htele:"; 1704 reply << itr->first; 1705 reply << "|h["; 1706 reply << tele->name; 1707 reply << "]|h|r\n"; 1708 } 1709 1710 if(reply.str().empty()) 1727 1711 SendSysMessage(LANG_COMMAND_TELE_NOLOCATION); 1728 1712 else 1729 { 1730 reply = GetMangosString(LANG_COMMAND_TELE_LOCATION) + reply; 1731 SendSysMessage(reply.c_str()); 1732 } 1713 PSendSysMessage(LANG_COMMAND_TELE_LOCATION,reply.str().c_str()); 1714 1733 1715 return true; 1734 1716 } … … 1862 1844 return false; 1863 1845 1846 std::string name = pName; 1847 1848 if(!normalizePlayerName(name)) 1849 { 1850 SendSysMessage(LANG_PLAYER_NOT_FOUND); 1851 SetSentErrorMessage(true); 1852 return false; 1853 } 1854 1864 1855 char* tail = strtok(NULL, ""); 1865 1856 if(!tail) 1866 1857 return false; 1867 1858 1868 char* cId = extractKeyFromLink((char*)tail,"Htele"); // string or [name] Shift-click form |color|Htele:name|h[name]|h|r 1869 if(!cId) 1870 return false; 1871 1872 std::string location = cId; 1873 1874 std::string name = pName; 1875 1876 if(!normalizePlayerName(name)) 1877 { 1878 SendSysMessage(LANG_PLAYER_NOT_FOUND); 1879 SetSentErrorMessage(true); 1880 return false; 1881 } 1882 1883 WorldDatabase.escape_string(location); 1884 QueryResult *result = WorldDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map FROM game_tele WHERE name = '%s'",location.c_str()); 1885 if (!result) 1859 // id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r 1860 GameTele const* tele = extractGameTeleFromLink(tail); 1861 if(!tele) 1886 1862 { 1887 1863 SendSysMessage(LANG_COMMAND_TELE_NOTFOUND); 1888 SetSentErrorMessage(true);1889 return false;1890 }1891 1892 Field *fields = result->Fetch();1893 float x = fields[0].GetFloat();1894 float y = fields[1].GetFloat();1895 float z = fields[2].GetFloat();1896 float ort = fields[3].GetFloat();1897 int mapid = fields[4].GetUInt16();1898 delete result;1899 1900 if(!MapManager::IsValidMapCoord(mapid,x,y,x,ort))1901 {1902 PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid);1903 1864 SetSentErrorMessage(true); 1904 1865 return false; … … 1916 1877 } 1917 1878 1918 PSendSysMessage(LANG_TELEPORTING_TO, chr->GetName(),"", location.c_str());1879 PSendSysMessage(LANG_TELEPORTING_TO, chr->GetName(),"", tele->name.c_str()); 1919 1880 1920 1881 if (m_session->GetPlayer()->IsVisibleGloballyFor(chr)) … … 1931 1892 chr->SaveRecallPosition(); 1932 1893 1933 chr->TeleportTo( mapid,x,y,z,chr->GetOrientation());1894 chr->TeleportTo(tele->mapId,tele->position_x,tele->position_y,tele->position_z,tele->orientation); 1934 1895 } 1935 1896 else if (uint64 guid = objmgr.GetPlayerGUIDByName(name.c_str())) 1936 1897 { 1937 PSendSysMessage(LANG_TELEPORTING_TO, name.c_str(), GetMangosString(LANG_OFFLINE), location.c_str());1938 Player::SavePositionInDB( mapid,x,y,z,ort,MapManager::Instance().GetZoneId(mapid,x,y),guid);1898 PSendSysMessage(LANG_TELEPORTING_TO, name.c_str(), GetMangosString(LANG_OFFLINE), tele->name.c_str()); 1899 Player::SavePositionInDB(tele->mapId,tele->position_x,tele->position_y,tele->position_z,tele->orientation,MapManager::Instance().GetZoneId(tele->mapId,tele->position_x,tele->position_y),guid); 1939 1900 } 1940 1901 else … … 1958 1919 } 1959 1920 1960 char* cId = extractKeyFromLink((char*)args,"Htele"); // string or [name] Shift-click form |color|Htele:name|h[name]|h|r 1961 if(!cId) 1962 return false; 1963 1964 std::string location = cId; 1965 1966 WorldDatabase.escape_string(location); 1967 QueryResult *result = WorldDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map FROM game_tele WHERE name = '%s'",location.c_str()); 1968 if (!result) 1921 // id, or string, or [name] Shift-click form |color|Htele:id|h[name]|h|r 1922 GameTele const* tele = extractGameTeleFromLink((char*)args); 1923 if(!tele) 1969 1924 { 1970 1925 SendSysMessage(LANG_COMMAND_TELE_NOTFOUND); … … 1972 1927 return false; 1973 1928 } 1974 Field *fields = result->Fetch();1975 float x = fields[0].GetFloat();1976 float y = fields[1].GetFloat();1977 float z = fields[2].GetFloat();1978 float ort = fields[3].GetFloat();1979 int mapid = fields[4].GetUInt16();1980 delete result;1981 1982 if(!MapManager::IsValidMapCoord(mapid,x,y,z,ort))1983 {1984 PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid);1985 SetSentErrorMessage(true);1986 return false;1987 }1988 1929 1989 1930 Group *grp = player->GetGroup(); 1990 1991 1931 if(!grp) 1992 1932 { … … 2009 1949 } 2010 1950 2011 PSendSysMessage(LANG_TELEPORTING_TO, pl->GetName(),"", location.c_str());1951 PSendSysMessage(LANG_TELEPORTING_TO, pl->GetName(),"", tele->name.c_str()); 2012 1952 2013 1953 if (m_session->GetPlayer() != pl && m_session->GetPlayer()->IsVisibleGloballyFor(pl)) … … 2024 1964 pl->SaveRecallPosition(); 2025 1965 2026 pl->TeleportTo( mapid, x, y, z, ort);1966 pl->TeleportTo(tele->mapId, tele->position_x, tele->position_y, tele->position_z, tele->orientation); 2027 1967 } 2028 1968 -
trunk/src/game/Level2.cpp
r2 r6 34 34 #include "GameEvent.h" 35 35 #include "SpellMgr.h" 36 #include "AccountMgr.h" 36 37 #include "WaypointManager.h" 37 38 #include "Util.h" … … 208 209 result = WorldDatabase.PQuery( 209 210 "SELECT guid, id, position_x, position_y, position_z, orientation, map, (POW(position_x - %f, 2) + POW(position_y - %f, 2) + POW(position_z - %f, 2)) AS order_ " 210 "FROM gameobject,gameobject_template WHERE gameobject_template.entry = gameobject.id AND map = %i AND name "_LIKE_" '""%%%s%%""'ORDER BY order_ ASC LIMIT 1",211 "FROM gameobject,gameobject_template WHERE gameobject_template.entry = gameobject.id AND map = %i AND name "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'")" ORDER BY order_ ASC LIMIT 1", 211 212 pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), pl->GetMapId(),name.c_str()); 212 213 } … … 3947 3948 return false; 3948 3949 } 3950 3951 bool ChatHandler::HandleLookupPlayerIpCommand(const char* args) 3952 { 3953 3954 if(!*args) 3955 return false; 3956 3957 std::string ip = strtok((char*)args, " "); 3958 char* limit_str = strtok(NULL, " "); 3959 int32 limit = limit_str ? atoi(limit_str) : -1; 3960 3961 loginDatabase.escape_string(ip); 3962 3963 QueryResult* result = loginDatabase.PQuery("SELECT id,username FROM account WHERE last_ip = '%s'", ip.c_str()); 3964 3965 return LookupPlayerSearchCommand(result,limit); 3966 } 3967 3968 bool ChatHandler::HandleLookupPlayerAccountCommand(const char* args) 3969 { 3970 if(!*args) 3971 return false; 3972 3973 std::string account = strtok((char*)args, " "); 3974 char* limit_str = strtok(NULL, " "); 3975 int32 limit = limit_str ? atoi(limit_str) : -1; 3976 3977 if(!AccountMgr::normilizeString(account)) 3978 return false; 3979 3980 loginDatabase.escape_string(account); 3981 3982 QueryResult* result = loginDatabase.PQuery("SELECT id,username FROM account WHERE username = '%s'", account.c_str()); 3983 3984 return LookupPlayerSearchCommand(result,limit); 3985 } 3986 3987 bool ChatHandler::HandleLookupPlayerEmailCommand(const char* args) 3988 { 3989 3990 if(!*args) 3991 return false; 3992 3993 std::string email = strtok((char*)args, " "); 3994 char* limit_str = strtok(NULL, " "); 3995 int32 limit = limit_str ? atoi(limit_str) : -1; 3996 3997 loginDatabase.escape_string(email); 3998 3999 QueryResult* result = loginDatabase.PQuery("SELECT id,username FROM account WHERE email = '%s'", email.c_str()); 4000 4001 return LookupPlayerSearchCommand(result,limit); 4002 } 4003 4004 bool ChatHandler::LookupPlayerSearchCommand(QueryResult* result, int32 limit) 4005 { 4006 if(!result) 4007 { 4008 PSendSysMessage(LANG_NO_PLAYERS_FOUND); 4009 SetSentErrorMessage(true); 4010 return false; 4011 } 4012 4013 int i =0; 4014 do 4015 { 4016 Field* fields = result->Fetch(); 4017 uint32 acc_id = fields[0].GetUInt32(); 4018 std::string acc_name = fields[1].GetCppString(); 4019 4020 QueryResult* chars = CharacterDatabase.PQuery("SELECT guid,name FROM characters WHERE account = '%u'", acc_id); 4021 if(chars) 4022 { 4023 PSendSysMessage(LANG_LOOKUP_PLAYER_ACCOUNT,acc_name.c_str(),acc_id); 4024 4025 uint64 guid = 0; 4026 std::string name; 4027 4028 do 4029 { 4030 Field* charfields = chars->Fetch(); 4031 guid = charfields[0].GetUInt64(); 4032 name = charfields[1].GetCppString(); 4033 4034 PSendSysMessage(LANG_LOOKUP_PLAYER_CHARACTER,name.c_str(),guid); 4035 ++i; 4036 4037 } while( chars->NextRow() && ( limit == -1 || i < limit ) ); 4038 4039 delete chars; 4040 } 4041 } while(result->NextRow()); 4042 4043 delete result; 4044 4045 return true; 4046 } -
trunk/src/game/Level3.cpp
r2 r6 62 62 { 63 63 HandleReloadAreaTriggerTeleportCommand(""); 64 //HandleReloadAreaTriggerTavernCommand(""); -- reloaded in HandleReloadAreaTriggerTavernCommand65 //HandleReloadQuestAreaTriggersCommand(""); -- reloaded in HandleReloadAllQuestCommand66 64 HandleReloadSkillFishingBaseLevelCommand(""); 67 65 66 HandleReloadAllAreaCommand(""); 68 67 HandleReloadAllLootCommand(""); 68 HandleReloadAllNpcCommand(""); 69 69 HandleReloadAllQuestCommand(""); 70 70 HandleReloadAllSpellCommand(""); … … 74 74 HandleReloadReservedNameCommand(""); 75 75 HandleReloadMangosStringCommand(""); 76 HandleReloadGameTeleCommand(""); 76 77 return true; 77 78 } … … 79 80 bool ChatHandler::HandleReloadAllAreaCommand(const char*) 80 81 { 82 //HandleReloadQuestAreaTriggersCommand(""); -- reloaded in HandleReloadAllQuestCommand 81 83 HandleReloadAreaTriggerTeleportCommand(""); 82 //HandleReloadAreaTriggerTavernCommand(""); -- reloaded in HandleReloadAreaTriggerTavernCommand 84 HandleReloadAreaTriggerTavernCommand(""); 85 HandleReloadGameGraveyardZoneCommand(""); 86 return true; 87 } 88 89 bool ChatHandler::HandleReloadAllLootCommand(const char*) 90 { 91 sLog.outString( "Re-Loading Loot Tables..." ); 92 LoadLootTables(); 93 SendGlobalSysMessage("DB tables `*_loot_template` reloaded."); 94 return true; 95 } 96 97 bool ChatHandler::HandleReloadAllNpcCommand(const char* /*args*/) 98 { 99 HandleReloadNpcGossipCommand("a"); 100 HandleReloadNpcTrainerCommand("a"); 101 HandleReloadNpcVendorCommand("a"); 83 102 return true; 84 103 } … … 92 111 objmgr.LoadQuestRelations(); 93 112 SendGlobalSysMessage("DB tables `*_questrelation` and `*_involvedrelation` reloaded."); 94 return true;95 }96 97 bool ChatHandler::HandleReloadAllLootCommand(const char*)98 {99 sLog.outString( "Re-Loading Loot Tables..." );100 LoadLootTables();101 SendGlobalSysMessage("DB tables `*_loot_template` reloaded.");102 113 return true; 103 114 } … … 321 332 } 322 333 334 bool ChatHandler::HandleReloadNpcGossipCommand(const char*) 335 { 336 sLog.outString( "Re-Loading `npc_gossip` Table!" ); 337 objmgr.LoadNpcTextId(); 338 SendGlobalSysMessage("DB table `npc_gossip` reloaded."); 339 return true; 340 } 341 342 bool ChatHandler::HandleReloadNpcTrainerCommand(const char*) 343 { 344 sLog.outString( "Re-Loading `npc_trainer` Table!" ); 345 objmgr.LoadTrainerSpell(); 346 SendGlobalSysMessage("DB table `npc_trainer` reloaded."); 347 return true; 348 } 349 350 bool ChatHandler::HandleReloadNpcVendorCommand(const char*) 351 { 352 sLog.outString( "Re-Loading `npc_vendor` Table!" ); 353 objmgr.LoadVendors(); 354 SendGlobalSysMessage("DB table `npc_vendor` reloaded."); 355 return true; 356 } 357 323 358 bool ChatHandler::HandleReloadReservedNameCommand(const char*) 324 359 { … … 548 583 549 584 SendGlobalSysMessage("DB table `game_graveyard_zone` reloaded."); 585 586 return true; 587 } 588 589 bool ChatHandler::HandleReloadGameTeleCommand(const char* /*arg*/) 590 { 591 sLog.outString( "Re-Loading Game Tele coordinates..."); 592 593 objmgr.LoadGameTele(); 594 595 SendGlobalSysMessage("DB table `game_tele` reloaded."); 550 596 551 597 return true; … … 3870 3916 if(!*args) 3871 3917 return false; 3872 QueryResult *result; 3918 3873 3919 Player *player=m_session->GetPlayer(); 3874 if (!player) return false; 3920 if (!player) 3921 return false; 3875 3922 3876 3923 std::string name = args; 3877 WorldDatabase.escape_string(name); 3878 result = WorldDatabase.PQuery("SELECT id FROM game_tele WHERE name = '%s'",name.c_str()); 3879 if (result) 3924 3925 if(objmgr.GetGameTele(name)) 3880 3926 { 3881 3927 SendSysMessage(LANG_COMMAND_TP_ALREADYEXIST); 3882 delete result; 3883 SetSentErrorMessage(true); 3884 return false; 3885 } 3886 3887 float x = player->GetPositionX(); 3888 float y = player->GetPositionY(); 3889 float z = player->GetPositionZ(); 3890 float ort = player->GetOrientation(); 3891 int mapid = player->GetMapId(); 3892 3893 if(WorldDatabase.PExecuteLog("INSERT INTO game_tele (position_x,position_y,position_z,orientation,map,name) VALUES (%f,%f,%f,%f,%d,'%s')",x,y,z,ort,mapid,name.c_str())) 3928 SetSentErrorMessage(true); 3929 return false; 3930 } 3931 3932 GameTele tele; 3933 tele.position_x = player->GetPositionX(); 3934 tele.position_y = player->GetPositionY(); 3935 tele.position_z = player->GetPositionZ(); 3936 tele.orientation = player->GetOrientation(); 3937 tele.mapId = player->GetMapId(); 3938 tele.name = name; 3939 3940 if(objmgr.AddGameTele(tele)) 3894 3941 { 3895 3942 SendSysMessage(LANG_COMMAND_TP_ADDED); … … 3911 3958 3912 3959 std::string name = args; 3913 WorldDatabase.escape_string(name); 3914 3915 QueryResult *result=WorldDatabase.PQuery("SELECT id FROM game_tele WHERE name = '%s'",name.c_str()); 3916 if (!result) 3960 3961 if(!objmgr.DeleteGameTele(name)) 3917 3962 { 3918 3963 SendSysMessage(LANG_COMMAND_TELE_NOTFOUND); … … 3920 3965 return false; 3921 3966 } 3922 delete result; 3923 3924 if(WorldDatabase.PExecuteLog("DELETE FROM game_tele WHERE name = '%s'",name.c_str())) 3925 { 3926 SendSysMessage(LANG_COMMAND_TP_DELETED); 3927 } 3928 else 3929 { 3930 SendSysMessage(LANG_COMMAND_TP_DELETEERR); 3931 SetSentErrorMessage(true); 3932 return false; 3933 } 3967 3968 SendSysMessage(LANG_COMMAND_TP_DELETED); 3934 3969 return true; 3935 3970 } … … 4759 4794 if(Type == "ip") 4760 4795 { 4761 result = loginDatabase.PQuery("SELECT ip FROM ip_banned WHERE ip "_LIKE_" '""%%%s%%""'",Filter.c_str());4796 result = loginDatabase.PQuery("SELECT ip FROM ip_banned WHERE ip "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'"),Filter.c_str()); 4762 4797 if(!result) 4763 4798 { … … 4778 4813 if(Type == "account") 4779 4814 { 4780 result = loginDatabase.PQuery("SELECT id FROM account WHERE username "_LIKE_" '""%%%s%%""' ",Filter.c_str());4815 result = loginDatabase.PQuery("SELECT id FROM account WHERE username "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'"),Filter.c_str()); 4781 4816 if (!result) 4782 4817 { … … 4788 4823 else if(Type == "characters") 4789 4824 { 4790 result = CharacterDatabase.PQuery("SELECT account FROM characters, WHERE name "_LIKE_" '""%%%s%%""' ",Filter.c_str());4825 result = CharacterDatabase.PQuery("SELECT account FROM characters, WHERE name "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'"),Filter.c_str()); 4791 4826 if (!result) 4792 4827 { -
trunk/src/game/Makefile.am
r2 r6 31 31 $(POSTGRE_INCLUDES) \ 32 32 -I$(top_srcdir)/dep/include \ 33 -I$(top_srcdir)/dep/ACE_wrappers \ 34 -I$(top_builddir)/dep/ACE_wrappers \ 33 35 -I$(top_srcdir)/src/framework \ 34 36 -I$(top_srcdir)/src/shared \ -
trunk/src/game/NPCHandler.cpp
r2 r6 130 130 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); 131 131 132 // Lazy loading at first access133 unit->LoadTrainerSpells();134 135 132 // trainer list loaded at check; 136 133 if(!unit->isCanTrainingOf(_player,true)) … … 145 142 } 146 143 147 Creature::SpellsList const& trainer_spells = unit->GetTrainerSpells(); 148 149 WorldPacket data( SMSG_TRAINER_LIST, 8+4+4+trainer_spells.size()*38 + strTitle.size()+1); 144 TrainerSpellData const* trainer_spells = unit->GetTrainerSpells(); 145 if(!trainer_spells) 146 { 147 sLog.outDebug( "WORLD: SendTrainerList - Training spells not found for creature (GUID: %u Entry: %u)", guid, unit->GetEntry()); 148 return; 149 } 150 151 WorldPacket data( SMSG_TRAINER_LIST, 8+4+4+trainer_spells->spellList.size()*38 + strTitle.size()+1); 150 152 data << guid; 151 data << uint32( unit->GetTrainerType());153 data << uint32(trainer_spells->trainerType); 152 154 153 155 size_t count_pos = data.wpos(); 154 data << uint32(trainer_spells .size());156 data << uint32(trainer_spells->spellList.size()); 155 157 156 158 // reputation discount … … 158 160 159 161 uint32 count = 0; 160 for(Creature::SpellsList::const_iterator itr = trainer_spells.begin(); itr != trainer_spells.end(); ++itr) 161 { 162 if(!_player->IsSpellFitByClassAndRace(itr->spell->Id)) 162 for(TrainerSpellList::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr) 163 { 164 TrainerSpell const* tSpell = *itr; 165 166 if(!_player->IsSpellFitByClassAndRace(tSpell->spell)) 163 167 continue; 164 168 165 169 ++count; 166 170 167 bool primary_prof_first_rank = spellmgr.IsPrimaryProfessionFirstRankSpell( itr->spell->Id);168 169 SpellChainNode const* chain_node = spellmgr.GetSpellChainNode( itr->spell->Id);170 171 data << uint32( itr->spell->Id);172 data << uint8(_player->GetTrainerSpellState( &*itr));173 data << uint32(floor( itr->spellcost * fDiscountMod));171 bool primary_prof_first_rank = spellmgr.IsPrimaryProfessionFirstRankSpell(tSpell->spell); 172 173 SpellChainNode const* chain_node = spellmgr.GetSpellChainNode(tSpell->spell); 174 175 data << uint32(tSpell->spell); 176 data << uint8(_player->GetTrainerSpellState(tSpell)); 177 data << uint32(floor(tSpell->spellcost * fDiscountMod)); 174 178 175 179 data << uint32(primary_prof_first_rank ? 1 : 0); // primary prof. learn confirmation dialog 176 180 data << uint32(primary_prof_first_rank ? 1 : 0); // must be equal prev. field to have learn button in enabled state 177 data << uint8( itr->reqlevel ? itr->reqlevel : itr->spell->spellLevel);178 data << uint32( itr->reqskill);179 data << uint32( itr->reqskillvalue);181 data << uint8(tSpell->reqlevel); 182 data << uint32(tSpell->reqskill); 183 data << uint32(tSpell->reqskillvalue); 180 184 data << uint32(chain_node ? (chain_node->prev ? chain_node->prev : chain_node->req) : 0); 181 185 data << uint32(chain_node && chain_node->prev ? chain_node->req : 0); … … 210 214 GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); 211 215 212 // Lazy loading at first access213 unit->LoadTrainerSpells();214 215 216 if(!unit->isCanTrainingOf(_player,true)) 216 217 return; 217 218 218 TrainerSpell const* trainer_spell = NULL;219 220 219 // check present spell in trainer spell list 221 Creature::SpellsList const& trainer_spells = unit->GetTrainerSpells(); 222 for(Creature::SpellsList::const_iterator itr = trainer_spells.begin(); itr != trainer_spells.end(); ++itr) 223 { 224 if(itr->spell->Id == spellId) 225 { 226 trainer_spell = &*itr; 227 break; 228 } 229 } 220 TrainerSpellData const* trainer_spells = unit->GetTrainerSpells(); 221 if(!trainer_spells) 222 return; 230 223 231 224 // not found, cheat? 225 TrainerSpell const* trainer_spell = trainer_spells->Find(spellId); 232 226 if(!trainer_spell) 233 227 return; … … 255 249 256 250 // learn explicitly to prevent lost money at lags, learning spell will be only show spell animation 257 _player->learnSpell(trainer_spell->spell ->Id);251 _player->learnSpell(trainer_spell->spell); 258 252 259 253 data.Initialize(SMSG_TRAINER_BUY_SUCCEEDED, 12); -
trunk/src/game/ObjectMgr.cpp
r2 r6 133 133 for(ItemMap::iterator itr = mAitems.begin(); itr != mAitems.end(); ++itr) 134 134 delete itr->second; 135 136 for (CacheVendorItemMap::iterator itr = m_mCacheVendorItemMap.begin(); itr != m_mCacheVendorItemMap.end(); ++itr) 137 for (VendorItemList::iterator itr2 = itr->second.begin(); itr2 != itr->second.end(); ++itr2) 138 delete (*itr2); 139 140 for (CacheTrainerSpellMap::iterator itr = m_mCacheTrainerSpellMap.begin(); itr != m_mCacheTrainerSpellMap.end(); ++itr) 141 itr->second.Clear(); 135 142 } 136 143 … … 255 262 void ObjectMgr::SendAuctionWonMail( AuctionEntry *auction ) 256 263 { 257 Item *pItem = objmgr.GetAItem(auction->item_guidlow);264 Item *pItem = GetAItem(auction->item_guidlow); 258 265 if(!pItem) 259 266 return; 260 267 261 268 uint64 bidder_guid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER); 262 Player *bidder = objmgr.GetPlayer(bidder_guid);269 Player *bidder = GetPlayer(bidder_guid); 263 270 264 271 uint32 bidder_accId = 0; … … 328 335 bidder->GetSession()->SendAuctionBidderNotification( auction->location, auction->Id, bidder_guid, 0, 0, auction->item_template); 329 336 else 330 objmgr.RemoveAItem(pItem->GetGUIDLow());// we have to remove the item, before we delete it !!337 RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !! 331 338 332 339 // will delete item or place to receiver mail list … … 337 344 { 338 345 CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid='%u'", pItem->GetGUIDLow()); 339 objmgr.RemoveAItem(pItem->GetGUIDLow());// we have to remove the item, before we delete it !!346 RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !! 340 347 delete pItem; 341 348 } … … 345 352 { 346 353 uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER); 347 Player *owner = objmgr.GetPlayer(owner_guid);354 Player *owner = GetPlayer(owner_guid); 348 355 349 356 // owner exist (online or offline) … … 376 383 { 377 384 uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER); 378 Player *owner = objmgr.GetPlayer(owner_guid);385 Player *owner = GetPlayer(owner_guid); 379 386 380 387 uint32 owner_accId = 0; … … 415 422 void ObjectMgr::SendAuctionExpiredMail( AuctionEntry * auction ) 416 423 { //return an item in auction to its owner by mail 417 Item *pItem = objmgr.GetAItem(auction->item_guidlow);424 Item *pItem = GetAItem(auction->item_guidlow); 418 425 if(!pItem) 419 426 { … … 423 430 424 431 uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER); 425 Player *owner = objmgr.GetPlayer(owner_guid);432 Player *owner = GetPlayer(owner_guid); 426 433 427 434 uint32 owner_accId = 0; … … 438 445 owner->GetSession()->SendAuctionOwnerNotification( auction ); 439 446 else 440 objmgr.RemoveAItem(pItem->GetGUIDLow());// we have to remove the item, before we delete it !!447 RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !! 441 448 442 449 MailItemsInfo mi; … … 451 458 { 452 459 CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid='%u'",pItem->GetGUIDLow()); 453 objmgr.RemoveAItem(pItem->GetGUIDLow());// we have to remove the item, before we delete it !!460 RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !! 454 461 delete pItem; 455 462 } … … 1737 1744 uint32 item_template = fields[1].GetUInt32(); 1738 1745 1739 ItemPrototype const *proto = objmgr.GetItemPrototype(item_template);1746 ItemPrototype const *proto = GetItemPrototype(item_template); 1740 1747 1741 1748 if(!proto) … … 3688 3695 case SCRIPT_COMMAND_QUEST_EXPLORED: 3689 3696 { 3690 Quest const* quest = objmgr.GetQuestTemplate(tmp.datalong);3697 Quest const* quest = GetQuestTemplate(tmp.datalong); 3691 3698 if(!quest) 3692 3699 { … … 3768 3775 void ObjectMgr::LoadQuestEndScripts() 3769 3776 { 3770 objmgr.LoadScripts(sQuestEndScripts, "quest_end_scripts");3777 LoadScripts(sQuestEndScripts, "quest_end_scripts"); 3771 3778 3772 3779 // check ids … … 3780 3787 void ObjectMgr::LoadQuestStartScripts() 3781 3788 { 3782 objmgr.LoadScripts(sQuestStartScripts,"quest_start_scripts");3789 LoadScripts(sQuestStartScripts,"quest_start_scripts"); 3783 3790 3784 3791 // check ids … … 3792 3799 void ObjectMgr::LoadSpellScripts() 3793 3800 { 3794 objmgr.LoadScripts(sSpellScripts, "spell_scripts");3801 LoadScripts(sSpellScripts, "spell_scripts"); 3795 3802 3796 3803 // check ids … … 3827 3834 void ObjectMgr::LoadEventScripts() 3828 3835 { 3829 objmgr.LoadScripts(sEventScripts, "event_scripts");3836 LoadScripts(sEventScripts, "event_scripts"); 3830 3837 3831 3838 std::set<uint32> evt_scripts; … … 4231 4238 Player *pl = 0; 4232 4239 if (serverUp) 4233 pl = objmgr.GetPlayer((uint64)m->receiver);4240 pl = GetPlayer((uint64)m->receiver); 4234 4241 if (pl && pl->m_mailsLoaded) 4235 4242 { //this code will run very improbably (the time is between 4 and 5 am, in game is online a player, who has old mail … … 4504 4511 { 4505 4512 mount_entry = node->alliance_mount_type; 4506 CreatureInfo const *ci = objmgr.GetCreatureTemplate(mount_entry);4513 CreatureInfo const *ci = GetCreatureTemplate(mount_entry); 4507 4514 if(ci) 4508 4515 mount_id = ci->DisplayID_A; … … 4511 4518 { 4512 4519 mount_entry = node->horde_mount_type; 4513 CreatureInfo const *ci = objmgr.GetCreatureTemplate(mount_entry);4520 CreatureInfo const *ci = GetCreatureTemplate(mount_entry); 4514 4521 if(ci) 4515 4522 mount_id = ci->DisplayID_H; … … 4517 4524 } 4518 4525 4519 CreatureModelInfo const *minfo = objmgr.GetCreatureModelInfo(mount_id);4526 CreatureModelInfo const *minfo = GetCreatureModelInfo(mount_id); 4520 4527 if(!minfo) 4521 4528 { … … 4809 4816 if(at.requiredItem) 4810 4817 { 4811 ItemPrototype const *pProto = objmgr.GetItemPrototype(at.requiredItem);4818 ItemPrototype const *pProto = GetItemPrototype(at.requiredItem); 4812 4819 if(!pProto) 4813 4820 { … … 4818 4825 if(at.requiredItem2) 4819 4826 { 4820 ItemPrototype const *pProto = objmgr.GetItemPrototype(at.requiredItem2);4827 ItemPrototype const *pProto = GetItemPrototype(at.requiredItem2); 4821 4828 if(!pProto) 4822 4829 { … … 4828 4835 if(at.heroicKey) 4829 4836 { 4830 ItemPrototype const *pProto = objmgr.GetItemPrototype(at.heroicKey);4837 ItemPrototype const *pProto = GetItemPrototype(at.heroicKey); 4831 4838 if(!pProto) 4832 4839 { … … 4838 4845 if(at.heroicKey2) 4839 4846 { 4840 ItemPrototype const *pProto = objmgr.GetItemPrototype(at.heroicKey2);4847 ItemPrototype const *pProto = GetItemPrototype(at.heroicKey2); 4841 4848 if(!pProto) 4842 4849 { … … 5446 5453 if(list0.empty() || list1.empty()) 5447 5454 { 5448 CreatureInfo const *cinfo = objmgr.GetCreatureTemplate(entry);5455 CreatureInfo const *cinfo = GetCreatureTemplate(entry); 5449 5456 char* petname = GetPetName(cinfo->family, sWorld.GetDefaultDbcLocale()); 5450 5457 if(!petname) … … 5540 5547 repOnKill.repfaction2 = fields[2].GetUInt32(); 5541 5548 repOnKill.is_teamaward1 = fields[3].GetBool(); 5542 repOnKill.reput ration_max_cap1= fields[4].GetUInt32();5549 repOnKill.reputation_max_cap1 = fields[4].GetUInt32(); 5543 5550 repOnKill.repvalue1 = fields[5].GetInt32(); 5544 5551 repOnKill.is_teamaward2 = fields[6].GetBool(); 5545 repOnKill.reput ration_max_cap2= fields[7].GetUInt32();5552 repOnKill.reputation_max_cap2 = fields[7].GetUInt32(); 5546 5553 repOnKill.repvalue2 = fields[8].GetInt32(); 5547 5554 repOnKill.team_dependent = fields[9].GetUInt8(); … … 6098 6105 } 6099 6106 6100 bool ObjectMgr::LoadMangosStrings(DatabaseType& db, char const* table, bool positive_entries)6107 bool ObjectMgr::LoadMangosStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value) 6101 6108 { 6102 6109 // cleanup affected map part for reloading case 6103 6110 for(MangosStringLocaleMap::iterator itr = mMangosStringLocaleMap.begin(); itr != mMangosStringLocaleMap.end();) 6104 6111 { 6105 if(itr->first > 0 && positive_entries || itr->first < 0 && !positive_entries)6112 if(itr->first >= min_value && itr->first <= max_value) 6106 6113 { 6107 6114 MangosStringLocaleMap::iterator itr2 = itr; … … 6122 6129 6123 6130 sLog.outString(""); 6124 if( positive_entries)// error only in case internal strings6131 if(min_value > 0) // error only in case internal strings 6125 6132 sLog.outErrorDb(">> Loaded 0 mangos strings. DB table `%s` is empty. Cannot continue.",table); 6126 6133 else 6127 sLog.outString(">> Loaded 0 mangos strings. DB table `%s` is empty.",table);6134 sLog.outString(">> Loaded 0 string templates. DB table `%s` is empty.",table); 6128 6135 return false; 6129 6136 } 6137 6138 uint32 count = 0; 6130 6139 6131 6140 barGoLink bar(result->GetRowCount()); … … 6143 6152 continue; 6144 6153 } 6145 else if(entry < 0) 6146 { 6147 if(positive_entries) 6148 { 6149 sLog.outString("Table `%s` contain unexpected negative entry %i, ignored.",table,entry); 6150 continue; 6151 } 6152 } 6153 else 6154 { 6155 if(!positive_entries) 6156 { 6157 sLog.outString("Table `%s` contain unexpected positive entry %i, ignored.",table,entry); 6158 continue; 6159 } 6154 else if(entry < min_value || entry > max_value) 6155 { 6156 int32 start = min_value > 0 ? min_value : max_value; 6157 int32 end = min_value > 0 ? max_value : min_value; 6158 sLog.outString("Table `%s` contain entry %i out of allowed range (%d - %d), ignored.",table,entry,start,end); 6159 continue; 6160 6160 } 6161 6161 6162 6162 MangosStringLocale& data = mMangosStringLocaleMap[entry]; 6163 6163 6164 if(data.Content.size() < 1) 6165 data.Content.resize(1); 6164 if(data.Content.size() > 0) 6165 { 6166 sLog.outString("Table `%s` contain data for already loaded entry %i (from another table?), ignored.",table,entry); 6167 continue; 6168 } 6169 6170 data.Content.resize(1); 6171 ++count; 6166 6172 6167 6173 // 0 -> default, idx in to idx+1 … … 6189 6195 6190 6196 sLog.outString(); 6191 sLog.outString( ">> Loaded %u MaNGOS strings from table %s", mMangosStringLocaleMap.size(),table); 6197 if(min_value > 0) // internal mangos strings 6198 sLog.outString( ">> Loaded %u MaNGOS strings from table %s", count,table); 6199 else 6200 sLog.outString( ">> Loaded %u string templates from %s", count,table); 6201 6192 6202 return true; 6193 6203 } … … 6500 6510 } 6501 6511 6512 void ObjectMgr::LoadGameTele() 6513 { 6514 m_GameTeleMap.clear(); // for relaod case 6515 6516 uint32 count = 0; 6517 QueryResult *result = WorldDatabase.Query("SELECT id, position_x, position_y, position_z, orientation, map, name FROM game_tele"); 6518 6519 if( !result ) 6520 { 6521 barGoLink bar( 1 ); 6522 6523 bar.step(); 6524 6525 sLog.outString(); 6526 sLog.outErrorDb(">> Loaded `game_tele`, table is empty!"); 6527 return; 6528 } 6529 6530 barGoLink bar( result->GetRowCount() ); 6531 6532 do 6533 { 6534 bar.step(); 6535 6536 Field *fields = result->Fetch(); 6537 6538 uint32 id = fields[0].GetUInt32(); 6539 6540 GameTele gt; 6541 6542 gt.position_x = fields[1].GetFloat(); 6543 gt.position_y = fields[2].GetFloat(); 6544 gt.position_z = fields[3].GetFloat(); 6545 gt.orientation = fields[4].GetFloat(); 6546 gt.mapId = fields[5].GetUInt32(); 6547 gt.name = fields[6].GetCppString(); 6548 6549 if(!MapManager::IsValidMapCoord(gt.mapId,gt.position_x,gt.position_y,gt.position_z,gt.orientation)) 6550 { 6551 sLog.outErrorDb("Wrong position for id %u (name: %s) in `game_tele` table, ignoring.",id,gt.name.c_str()); 6552 continue; 6553 } 6554 6555 if(!Utf8toWStr(gt.name,gt.wnameLow)) 6556 { 6557 sLog.outErrorDb("Wrong UTF8 name for id %u in `game_tele` table, ignoring.",id); 6558 continue; 6559 } 6560 6561 wstrToLower( gt.wnameLow ); 6562 6563 m_GameTeleMap[id] = gt; 6564 6565 ++count; 6566 } 6567 while (result->NextRow()); 6568 6569 delete result; 6570 6571 sLog.outString(); 6572 sLog.outString( ">> Loaded %u game tele's", count ); 6573 } 6574 6575 GameTele const* ObjectMgr::GetGameTele(std::string name) const 6576 { 6577 // explicit name case 6578 std::wstring wname; 6579 if(!Utf8toWStr(name,wname)) 6580 return false; 6581 6582 // converting string that we try to find to lower case 6583 wstrToLower( wname ); 6584 6585 for(GameTeleMap::const_iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr) 6586 if(itr->second.wnameLow == wname) 6587 return &itr->second; 6588 6589 return NULL; 6590 } 6591 6592 bool ObjectMgr::AddGameTele(GameTele& tele) 6593 { 6594 // find max id 6595 uint32 new_id = 0; 6596 for(GameTeleMap::const_iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr) 6597 if(itr->first > new_id) 6598 new_id = itr->first; 6599 6600 // use next 6601 ++new_id; 6602 6603 if(!Utf8toWStr(tele.name,tele.wnameLow)) 6604 return false; 6605 6606 wstrToLower( tele.wnameLow ); 6607 6608 m_GameTeleMap[new_id] = tele; 6609 6610 return WorldDatabase.PExecuteLog("INSERT INTO game_tele (id,position_x,position_y,position_z,orientation,map,name) VALUES (%u,%f,%f,%f,%f,%d,'%s')", 6611 new_id,tele.position_x,tele.position_y,tele.position_z,tele.orientation,tele.mapId,tele.name.c_str()); 6612 } 6613 6614 bool ObjectMgr::DeleteGameTele(std::string name) 6615 { 6616 // explicit name case 6617 std::wstring wname; 6618 if(!Utf8toWStr(name,wname)) 6619 return false; 6620 6621 // converting string that we try to find to lower case 6622 wstrToLower( wname ); 6623 6624 for(GameTeleMap::iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr) 6625 { 6626 if(itr->second.wnameLow == wname) 6627 { 6628 WorldDatabase.PExecuteLog("DELETE FROM game_tele WHERE name = '%s'",itr->second.name.c_str()); 6629 m_GameTeleMap.erase(itr); 6630 return true; 6631 } 6632 } 6633 6634 return false; 6635 } 6636 6637 void ObjectMgr::LoadTrainerSpell() 6638 { 6639 // For reload case 6640 for (CacheTrainerSpellMap::iterator itr = m_mCacheTrainerSpellMap.begin(); itr != m_mCacheTrainerSpellMap.end(); ++itr) 6641 itr->second.Clear(); 6642 m_mCacheTrainerSpellMap.clear(); 6643 6644 QueryResult *result = WorldDatabase.PQuery("SELECT entry, spell,spellcost,reqskill,reqskillvalue,reqlevel FROM npc_trainer"); 6645 6646 if( !result ) 6647 { 6648 barGoLink bar( 1 ); 6649 6650 bar.step(); 6651 6652 sLog.outString(); 6653 sLog.outErrorDb(">> Loaded `npc_trainer`, table is empty!"); 6654 return; 6655 } 6656 6657 barGoLink bar( result->GetRowCount() ); 6658 6659 uint32 count = 0,entry,spell; 6660 do 6661 { 6662 bar.step(); 6663 6664 Field* fields = result->Fetch(); 6665 6666 entry = fields[0].GetUInt32(); 6667 spell = fields[1].GetUInt32(); 6668 6669 if(!GetCreatureTemplate(entry)) 6670 { 6671 sLog.outErrorDb("Table `npc_trainer` have entry for not existed creature template (Entry: %u), ignore", entry); 6672 continue; 6673 } 6674 6675 SpellEntry const *spellinfo = sSpellStore.LookupEntry(spell); 6676 if(!spellinfo) 6677 { 6678 sLog.outErrorDb("Table `npc_trainer` for Trainer (Entry: %u ) has non existing spell %u, ignore", entry,spell); 6679 continue; 6680 } 6681 6682 if(!SpellMgr::IsSpellValid(spellinfo)) 6683 { 6684 sLog.outErrorDb("Table `npc_trainer` for Trainer (Entry: %u) has broken learning spell %u, ignore", entry, spell); 6685 continue; 6686 } 6687 6688 TrainerSpell* pTrainerSpell = new TrainerSpell(); 6689 pTrainerSpell->spell = spell; 6690 pTrainerSpell->spellcost = fields[2].GetUInt32(); 6691 pTrainerSpell->reqskill = fields[3].GetUInt32(); 6692 pTrainerSpell->reqskillvalue = fields[4].GetUInt32(); 6693 pTrainerSpell->reqlevel = fields[5].GetUInt32(); 6694 6695 if(!pTrainerSpell->reqlevel) 6696 pTrainerSpell->reqlevel = spellinfo->spellLevel; 6697 6698 6699 TrainerSpellData& data = m_mCacheTrainerSpellMap[entry]; 6700 6701 if(SpellMgr::IsProfessionSpell(spell)) 6702 data.trainerType = 2; 6703 6704 data.spellList.push_back(pTrainerSpell); 6705 ++count; 6706 6707 } while (result->NextRow()); 6708 delete result; 6709 6710 sLog.outString(); 6711 sLog.outString( ">> Loaded Trainers %d", count ); 6712 } 6713 6714 void ObjectMgr::LoadVendors() 6715 { 6716 // For reload case 6717 for (CacheVendorItemMap::iterator itr = m_mCacheVendorItemMap.begin(); itr != m_mCacheVendorItemMap.end(); ++itr) 6718 { 6719 for (VendorItemList::iterator itr2 = itr->second.begin(); itr2 != itr->second.end(); ++itr2) 6720 delete (*itr2); 6721 } 6722 m_mCacheVendorItemMap.clear(); 6723 6724 QueryResult *result = WorldDatabase.PQuery("SELECT entry, item, maxcount, incrtime, ExtendedCost FROM npc_vendor"); 6725 if( !result ) 6726 { 6727 barGoLink bar( 1 ); 6728 6729 bar.step(); 6730 6731 sLog.outString(); 6732 sLog.outErrorDb(">> Loaded `npc_vendor`, table is empty!"); 6733 return; 6734 } 6735 6736 barGoLink bar( result->GetRowCount() ); 6737 6738 uint32 count = 0; 6739 uint32 entry, item_id, ExtendedCost; 6740 do 6741 { 6742 bar.step(); 6743 Field* fields = result->Fetch(); 6744 6745 entry = fields[0].GetUInt32(); 6746 if(!GetCreatureTemplate(entry)) 6747 { 6748 sLog.outErrorDb("Table `npc_vendor` have data for not existed creature template (Entry: %u), ignore", entry); 6749 continue; 6750 } 6751 6752 item_id = fields[1].GetUInt32(); 6753 if(!GetItemPrototype(item_id)) 6754 { 6755 sLog.outErrorDb("Table `npc_vendor` for Vendor (Entry: %u) have in item list non-existed item (%u), ignore",entry,item_id); 6756 continue; 6757 } 6758 6759 ExtendedCost = fields[4].GetUInt32(); 6760 if(ExtendedCost && !sItemExtendedCostStore.LookupEntry(ExtendedCost)) 6761 { 6762 sLog.outErrorDb("Table `npc_vendor` have Item (Entry: %u) with wrong ExtendedCost (%u) for vendor (%u), ignore",item_id,ExtendedCost,entry); 6763 continue; 6764 } 6765 6766 VendorItemList& vList = m_mCacheVendorItemMap[entry]; 6767 6768 if(vList.size() >= MAX_VENDOR_ITEMS) 6769 { 6770 sLog.outErrorDb( "Table `npc_vendor` has too many items (%u >= %i) for vendor (Entry: %u), ignore", vList.size(), MAX_VENDOR_ITEMS, entry); 6771 continue; 6772 } 6773 6774 VendorItem* pVendorItem = new VendorItem(); 6775 pVendorItem->item = item_id; 6776 pVendorItem->maxcount = fields[2].GetUInt32(); 6777 pVendorItem->incrtime = fields[3].GetUInt32(); 6778 pVendorItem->ExtendedCost = ExtendedCost; 6779 6780 vList.push_back(pVendorItem); 6781 ++count; 6782 6783 } while (result->NextRow()); 6784 delete result; 6785 6786 sLog.outString(); 6787 sLog.outString( ">> Loaded %d Vendors ", count ); 6788 } 6789 6790 void ObjectMgr::LoadNpcTextId() 6791 { 6792 6793 m_mCacheNpcTextIdMap.clear(); 6794 6795 QueryResult* result = WorldDatabase.PQuery("SELECT npc_guid, textid FROM npc_gossip"); 6796 if( !result ) 6797 { 6798 barGoLink bar( 1 ); 6799 6800 bar.step(); 6801 6802 sLog.outString(); 6803 sLog.outErrorDb(">> Loaded `npc_gossip`, table is empty!"); 6804 return; 6805 } 6806 6807 barGoLink bar( result->GetRowCount() ); 6808 6809 uint32 count = 0; 6810 uint32 guid,textid; 6811 do 6812 { 6813 bar.step(); 6814 6815 Field* fields = result->Fetch(); 6816 6817 guid = fields[0].GetUInt32(); 6818 textid = fields[1].GetUInt32(); 6819 6820 if (!GetCreatureData(guid)) 6821 { 6822 sLog.outErrorDb("Table `npc_gossip` have not existed creature (GUID: %u) entry, ignore. ",guid); 6823 continue; 6824 } 6825 if (!GetGossipText(textid)) 6826 { 6827 sLog.outErrorDb("Table `npc_gossip` for creature (GUID: %u) have wrong Textid (%u), ignore. ", guid, textid); 6828 continue; 6829 } 6830 6831 m_mCacheNpcTextIdMap[guid] = textid ; 6832 ++count; 6833 6834 } while (result->NextRow()); 6835 delete result; 6836 6837 sLog.outString(); 6838 sLog.outString( ">> Loaded %d NpcTextId ", count ); 6839 } 6840 6841 // Functions for scripting access 6502 6842 const char* GetAreaTriggerScriptNameById(uint32 id) 6503 6843 { … … 6505 6845 } 6506 6846 6507 6508 bool LoadMangosStrings(DatabaseType& db, char const* table) 6509 { 6847 bool LoadMangosStrings(DatabaseType& db, char const* table,int32 start_value, int32 end_value) 6848 { 6849 if(start_value >= 0 || start_value <= end_value) // start/end reversed for negative values 6850 { 6851 sLog.outError("Table '%s' attempt loaded with invalid range (%d - %d), use (%d - %d) instead.",table,start_value,end_value,-1,std::numeric_limits<int32>::min()); 6852 start_value = -1; 6853 end_value = std::numeric_limits<int32>::min(); 6854 } 6855 6510 6856 // for scripting localized strings allowed use _only_ negative entries 6511 return objmgr.LoadMangosStrings(db,table, false);6512 } 6857 return objmgr.LoadMangosStrings(db,table,end_value,start_value); 6858 } -
trunk/src/game/ObjectMgr.h
r2 r6 43 43 #include <string> 44 44 #include <map> 45 #include <limits> 45 46 46 47 extern SQLStorage sCreatureStorage; … … 60 61 class TransportPath; 61 62 class Item; 63 64 struct GameTele 65 { 66 float position_x; 67 float position_y; 68 float position_z; 69 float orientation; 70 uint32 mapId; 71 std::string name; 72 std::wstring wnameLow; 73 }; 74 75 typedef HM_NAMESPACE::hash_map<uint32, GameTele > GameTeleMap; 62 76 63 77 struct ScriptInfo … … 144 158 uint32 repfaction2; 145 159 bool is_teamaward1; 146 uint32 reput ration_max_cap1;160 uint32 reputation_max_cap1; 147 161 int32 repvalue1; 148 162 bool is_teamaward2; 149 uint32 reput ration_max_cap2;163 uint32 reputation_max_cap2; 150 164 int32 repvalue2; 151 165 bool team_dependent; … … 212 226 }; 213 227 228 // NPC gossip text id 229 typedef HM_NAMESPACE::hash_map<uint32, uint32> CacheNpcTextIdMap; 230 231 // Vendors 232 struct VendorItem 233 { 234 uint32 item; 235 uint32 maxcount; 236 uint32 incrtime; 237 uint32 ExtendedCost; 238 }; 239 typedef std::vector<VendorItem*> VendorItemList; 240 241 typedef HM_NAMESPACE::hash_map<uint32, VendorItemList> CacheVendorItemMap; 242 243 typedef HM_NAMESPACE::hash_map<uint32, TrainerSpellData> CacheTrainerSpellMap; 244 214 245 enum SkillRangeType 215 246 { … … 467 498 void LoadSpellScripts(); 468 499 469 bool LoadMangosStrings(DatabaseType& db, char const* table, bool positive_entries);470 bool LoadMangosStrings() { return LoadMangosStrings(WorldDatabase,"mangos_string", true); }500 bool LoadMangosStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value); 501 bool LoadMangosStrings() { return LoadMangosStrings(WorldDatabase,"mangos_string",1,std::numeric_limits<int32>::max()); } 471 502 void LoadPetCreateSpells(); 472 503 void LoadCreatureLocales(); … … 513 544 514 545 void LoadWeatherZoneChances(); 546 void LoadGameTele(); 547 548 void LoadNpcTextId(); 549 void LoadVendors(); 550 void LoadTrainerSpell(); 515 551 516 552 std::string GeneratePetName(uint32 entry); … … 664 700 665 701 return mConditions[condition_id].Meets(player); 702 } 703 704 GameTele const* GetGameTele(uint32 id) const 705 { 706 GameTeleMap::const_iterator itr = m_GameTeleMap.find(id); 707 if(itr==m_GameTeleMap.end()) return NULL; 708 return &itr->second; 709 } 710 GameTele const* GetGameTele(std::string name) const; 711 GameTeleMap const& GetGameTeleMap() const { return m_GameTeleMap; } 712 bool AddGameTele(GameTele& data); 713 bool DeleteGameTele(std::string name); 714 715 uint32 GetNpcGossip(uint32 entry) const 716 { 717 CacheNpcTextIdMap::const_iterator iter = m_mCacheNpcTextIdMap.find(entry); 718 if(iter == m_mCacheNpcTextIdMap.end()) 719 return 0; 720 721 return iter->second; 722 } 723 724 TrainerSpellData const* GetNpcTrainerSpells(uint32 entry) const 725 { 726 CacheTrainerSpellMap::const_iterator iter = m_mCacheTrainerSpellMap.find(entry); 727 if(iter == m_mCacheTrainerSpellMap.end()) 728 return NULL; 729 730 return &iter->second; 731 } 732 733 VendorItemList const* GetNpcVendorItemList(uint32 entry) const 734 { 735 CacheVendorItemMap::const_iterator iter = m_mCacheVendorItemMap.find(entry); 736 if(iter == m_mCacheVendorItemMap.end()) 737 return NULL; 738 739 return &iter->second; 666 740 } 667 741 protected: … … 721 795 722 796 GraveYardMap mGraveYardMap; 797 798 GameTeleMap m_GameTeleMap; 723 799 724 800 typedef std::vector<LocaleConstant> LocalForIndex; … … 771 847 ConditionStore mConditions; 772 848 849 CacheNpcTextIdMap m_mCacheNpcTextIdMap; 850 CacheVendorItemMap m_mCacheVendorItemMap; 851 CacheTrainerSpellMap m_mCacheTrainerSpellMap; 773 852 }; 774 853 775 854 #define objmgr MaNGOS::Singleton<ObjectMgr>::Instance() 855 856 // scripting access functions 857 bool MANGOS_DLL_SPEC LoadMangosStrings(DatabaseType& db, char const* table,int32 start_value = -1, int32 end_value = std::numeric_limits<int32>::min()); 858 MANGOS_DLL_SPEC const char* GetAreaTriggerScriptNameById(uint32 id); 859 776 860 #endif 777 778 // scripting access functions779 bool MANGOS_DLL_SPEC LoadMangosStrings(DatabaseType& db, char const* table);780 MANGOS_DLL_SPEC const char* GetAreaTriggerScriptNameById(uint32 id); -
trunk/src/game/Player.cpp
r2 r6 357 357 m_ArmorProficiency = 0; 358 358 m_canParry = false; 359 m_canBlock = false; 359 360 m_canDualWield = false; 360 361 m_ammoDPS = 0.0f; … … 617 618 ++action_itr[i]; 618 619 } 619 620 UpdateBlockPercentage();621 620 622 621 for (PlayerCreateInfoItems::const_iterator item_id_itr = info->item.begin(); item_id_itr!=info->item.end(); ++item_id_itr++) … … 2249 2248 SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1+i, 0.0f); 2250 2249 2251 // Base parry percents 2252 SetFloatValue(PLAYER_PARRY_PERCENTAGE, 5.0f); 2253 2254 //Base block percentage 2255 SetFloatValue(PLAYER_BLOCK_PERCENTAGE, 5.0f); 2256 2250 SetFloatValue(PLAYER_PARRY_PERCENTAGE, 0.0f); 2251 SetFloatValue(PLAYER_BLOCK_PERCENTAGE, 0.0f); 2257 2252 SetUInt32Value(PLAYER_SHIELD_BLOCK, 0); 2258 2253 … … 3287 3282 updateVisualBits.SetBit(i); 3288 3283 3289 for(uint16 i = 0; i < INVENTORY_SLOT_BAG_END; i++)3290 {3291 updateVisualBits.SetBit((uint16)(PLAYER_FIELD_INV_SLOT_HEAD + i*2));3292 updateVisualBits.SetBit((uint16)(PLAYER_FIELD_INV_SLOT_HEAD + (i*2) + 1));3293 }3294 3284 //Players visible items are not inventory stuff 3295 3285 //431) = 884 (0x374) = main weapon … … 3406 3396 3407 3397 // known spell 3408 if(HasSpell(trainer_spell->spell ->Id))3398 if(HasSpell(trainer_spell->spell)) 3409 3399 return TRAINER_SPELL_GRAY; 3410 3400 3411 3401 // check race/class requirement 3412 if(!IsSpellFitByClassAndRace(trainer_spell->spell ->Id))3402 if(!IsSpellFitByClassAndRace(trainer_spell->spell)) 3413 3403 return TRAINER_SPELL_RED; 3414 3404 3415 3405 // check level requirement 3416 if(getLevel() < ( trainer_spell->reqlevel ? trainer_spell->reqlevel : trainer_spell->spell->spellLevel))3406 if(getLevel() < trainer_spell->reqlevel) 3417 3407 return TRAINER_SPELL_RED; 3418 3408 3419 if(SpellChainNode const* spell_chain = spellmgr.GetSpellChainNode(trainer_spell->spell ->Id))3409 if(SpellChainNode const* spell_chain = spellmgr.GetSpellChainNode(trainer_spell->spell)) 3420 3410 { 3421 3411 // check prev.rank requirement … … 3432 3422 return TRAINER_SPELL_RED; 3433 3423 3424 // exist, already checked at loading 3425 SpellEntry const* spell = sSpellStore.LookupEntry(trainer_spell->spell); 3426 3434 3427 // secondary prof. or not prof. spell 3435 uint32 skill = trainer_spell->spell->EffectMiscValue[1];3436 3437 if( trainer_spell->spell->Effect[1] != SPELL_EFFECT_SKILL || !IsPrimaryProfessionSkill(skill))3428 uint32 skill = spell->EffectMiscValue[1]; 3429 3430 if(spell->Effect[1] != SPELL_EFFECT_SKILL || !IsPrimaryProfessionSkill(skill)) 3438 3431 return TRAINER_SPELL_GREEN; 3439 3432 3440 3433 // check primary prof. limit 3441 if(spellmgr.IsPrimaryProfessionFirstRankSpell( trainer_spell->spell->Id) && GetFreePrimaryProffesionPoints() == 0)3434 if(spellmgr.IsPrimaryProfessionFirstRankSpell(spell->Id) && GetFreePrimaryProffesionPoints() == 0) 3442 3435 return TRAINER_SPELL_RED; 3443 3436 … … 4877 4870 4878 4871 if(pskill == SKILL_DEFENSE) 4879 { 4880 UpdateBlockPercentage(); 4881 } 4872 UpdateDefenseBonusesMod(); 4882 4873 } 4883 4874 } … … 5791 5782 FactionEntry const *factionEntry1 = sFactionStore.LookupEntry(Rep->repfaction1); 5792 5783 uint32 current_reputation_rank1 = GetReputationRank(factionEntry1); 5793 if(factionEntry1 && current_reputation_rank1 <= Rep->reput ration_max_cap1)5784 if(factionEntry1 && current_reputation_rank1 <= Rep->reputation_max_cap1) 5794 5785 ModifyFactionReputation(factionEntry1, donerep1); 5795 5786 … … 5809 5800 FactionEntry const *factionEntry2 = sFactionStore.LookupEntry(Rep->repfaction2); 5810 5801 uint32 current_reputation_rank2 = GetReputationRank(factionEntry2); 5811 if(factionEntry2 && current_reputation_rank2 <= Rep->reput ration_max_cap2)5802 if(factionEntry2 && current_reputation_rank2 <= Rep->reputation_max_cap2) 5812 5803 ModifyFactionReputation(factionEntry2, donerep2); 5813 5804 … … 11553 11544 } 11554 11545 11555 QuestMenu *qm = PlayerTalkClass->GetQuestMenu();11556 qm ->ClearMenu();11546 QuestMenu &qm = PlayerTalkClass->GetQuestMenu(); 11547 qm.ClearMenu(); 11557 11548 11558 11549 for(QuestRelations::const_iterator i = pObjectQIR->lower_bound(pObject->GetEntry()); i != pObjectQIR->upper_bound(pObject->GetEntry()); ++i) … … 11561 11552 QuestStatus status = GetQuestStatus( quest_id ); 11562 11553 if ( status == QUEST_STATUS_COMPLETE && !GetQuestRewardStatus( quest_id ) ) 11563 qm ->AddMenuItem(quest_id, DIALOG_STATUS_REWARD_REP);11554 qm.AddMenuItem(quest_id, DIALOG_STATUS_REWARD_REP); 11564 11555 else if ( status == QUEST_STATUS_INCOMPLETE ) 11565 qm ->AddMenuItem(quest_id, DIALOG_STATUS_INCOMPLETE);11556 qm.AddMenuItem(quest_id, DIALOG_STATUS_INCOMPLETE); 11566 11557 else if (status == QUEST_STATUS_AVAILABLE ) 11567 qm ->AddMenuItem(quest_id, DIALOG_STATUS_CHAT);11558 qm.AddMenuItem(quest_id, DIALOG_STATUS_CHAT); 11568 11559 } 11569 11560 … … 11577 11568 11578 11569 if (pQuest->IsAutoComplete() && CanTakeQuest(pQuest, false)) 11579 qm ->AddMenuItem(quest_id, DIALOG_STATUS_REWARD_REP);11570 qm.AddMenuItem(quest_id, DIALOG_STATUS_REWARD_REP); 11580 11571 else if ( status == QUEST_STATUS_NONE && CanTakeQuest( pQuest, false ) ) 11581 qm ->AddMenuItem(quest_id, DIALOG_STATUS_AVAILABLE);11572 qm.AddMenuItem(quest_id, DIALOG_STATUS_AVAILABLE); 11582 11573 } 11583 11574 } … … 11585 11576 void Player::SendPreparedQuest( uint64 guid ) 11586 11577 { 11587 QuestMenu * pQuestMenu = PlayerTalkClass->GetQuestMenu();11588 if( !pQuestMenu || pQuestMenu->MenuItemCount() < 1)11578 QuestMenu& questMenu = PlayerTalkClass->GetQuestMenu(); 11579 if( questMenu.Empty() ) 11589 11580 return; 11590 11581 11591 uint32 status = pQuestMenu->GetItem(0).m_qIcon; 11592 if ( pQuestMenu->MenuItemCount() == 1 ) 11582 QuestMenuItem const& qmi0 = questMenu.GetItem( 0 ); 11583 11584 uint32 status = qmi0.m_qIcon; 11585 11586 // single element case 11587 if ( questMenu.MenuItemCount() == 1 ) 11593 11588 { 11594 11589 // Auto open -- maybe also should verify there is no greeting 11595 uint32 quest_id = pQuestMenu->GetItem(0).m_qId;11590 uint32 quest_id = qmi0.m_qId; 11596 11591 Quest const* pQuest = objmgr.GetQuestTemplate(quest_id); 11597 11592 if ( pQuest ) … … 11608 11603 } 11609 11604 } 11605 // multiply entries 11610 11606 else 11611 11607 { … … 13772 13768 break; 13773 13769 } 13774 }13775 13776 //Unmount Player from previous mount, so speed bug with mount is no more...13777 if(IsMounted())13778 {13779 Unmount();13780 RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);13781 13770 } 13782 13771 … … 15627 15616 void Player::BuildPlayerChat(WorldPacket *data, uint8 msgtype, std::string text, uint32 language) const 15628 15617 { 15629 bool pre = (msgtype==CHAT_MSG_EMOTE);15630 15631 15618 *data << (uint8)msgtype; 15632 15619 *data << (uint32)language; … … 15634 15621 *data << (uint32)language; //language 2.1.0 ? 15635 15622 *data << (uint64)GetGUID(); 15636 *data << (uint32)(text.length()+1+(pre?3:0)); 15637 if(pre) 15638 data->append("%s ",3); 15623 *data << (uint32)(text.length()+1); 15639 15624 *data << text; 15640 15625 *data << (uint8)chatTag(); … … 17152 17137 data << (float)0.01666667f; // game speed 17153 17138 GetSession()->SendPacket( &data ); 17139 17140 // set fly flag if in fly form or taxi flight to prevent visually drop at ground in showup moment 17141 if(HasAuraType(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED) || isInFlight()) 17142 SetUnitMovementFlags(GetUnitMovementFlags() | MOVEMENTFLAG_FLYING2); 17154 17143 } 17155 17144 … … 17163 17152 static const AuraType auratypes[] = 17164 17153 { 17165 SPELL_AURA_MOD_FEAR, SPELL_AURA_TRANSFORM, SPELL_AURA_WATER_WALK,17166 SPELL_AURA_FEATHER_FALL, SPELL_AURA_HOVER, SPELL_AURA_SAFE_FALL,17167 SPELL_AURA_FLY, SPELL_AURA_ NONE17154 SPELL_AURA_MOD_FEAR, SPELL_AURA_TRANSFORM, SPELL_AURA_WATER_WALK, 17155 SPELL_AURA_FEATHER_FALL, SPELL_AURA_HOVER, SPELL_AURA_SAFE_FALL, 17156 SPELL_AURA_FLY, SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED, SPELL_AURA_NONE 17168 17157 }; 17169 17158 for(AuraType const* itr = &auratypes[0]; itr && itr[0] != SPELL_AURA_NONE; ++itr) … … 18117 18106 } 18118 18107 18119 bool ItemPosCount::isContainedIn(ItemPosCountVec &vec) 18108 void Player::SetCanParry( bool value ) 18109 { 18110 if(m_canParry==value) 18111 return; 18112 18113 m_canParry = value; 18114 UpdateParryPercentage(); 18115 } 18116 18117 void Player::SetCanBlock( bool value ) 18118 { 18119 if(m_canBlock==value) 18120 return; 18121 18122 m_canBlock = value; 18123 UpdateBlockPercentage(); 18124 } 18125 18126 bool ItemPosCount::isContainedIn(ItemPosCountVec const& vec) const 18120 18127 { 18121 18128 for(ItemPosCountVec::const_iterator itr = vec.begin(); itr != vec.end();++itr) 18122 { 18123 if(itr->pos == this->pos/* && itr->count == this.count*/) 18124 { 18129 if(itr->pos == this->pos) 18125 18130 return true; 18126 } 18127 } 18131 18128 18132 return false; 18129 18133 } 18130 -
trunk/src/game/Player.h
r2 r6 671 671 { 672 672 ItemPosCount(uint16 _pos, uint8 _count) : pos(_pos), count(_count) {} 673 bool isContainedIn(std::vector<ItemPosCount> &);673 bool isContainedIn(std::vector<ItemPosCount> const& vec) const; 674 674 uint16 pos; 675 675 uint8 count; … … 1742 1742 uint32 GetShieldBlockValue() const; // overwrite Unit version (virtual) 1743 1743 bool CanParry() const { return m_canParry; } 1744 void SetCanParry(bool value) { m_canParry = value; } 1744 void SetCanParry(bool value); 1745 bool CanBlock() const { return m_canBlock; } 1746 void SetCanBlock(bool value); 1745 1747 bool CanDualWield() const { return m_canDualWield; } 1746 1748 void SetCanDualWield(bool value) { m_canDualWield = value; } … … 2202 2204 uint32 m_ArmorProficiency; 2203 2205 bool m_canParry; 2206 bool m_canBlock; 2204 2207 bool m_canDualWield; 2205 2208 uint8 m_swingErrorMsg; -
trunk/src/game/SharedDefines.h
r2 r6 1995 1995 SUMMON_TYPE_POSESSED2 = 428 1996 1996 }; 1997 1998 enum ResponseCodes 1999 { 2000 RESPONSE_SUCCESS = 0x00, 2001 RESPONSE_FAILURE = 0x01, 2002 RESPONSE_CANCELLED = 0x02, 2003 RESPONSE_DISCONNECTED = 0x03, 2004 RESPONSE_FAILED_TO_CONNECT = 0x04, 2005 RESPONSE_CONNECTED = 0x05, 2006 RESPONSE_VERSION_MISMATCH = 0x06, 2007 2008 CSTATUS_CONNECTING = 0x07, 2009 CSTATUS_NEGOTIATING_SECURITY = 0x08, 2010 CSTATUS_NEGOTIATION_COMPLETE = 0x09, 2011 CSTATUS_NEGOTIATION_FAILED = 0x0A, 2012 CSTATUS_AUTHENTICATING = 0x0B, 2013 2014 AUTH_OK = 0x0C, 2015 AUTH_FAILED = 0x0D, 2016 AUTH_REJECT = 0x0E, 2017 AUTH_BAD_SERVER_PROOF = 0x0F, 2018 AUTH_UNAVAILABLE = 0x10, 2019 AUTH_SYSTEM_ERROR = 0x11, 2020 AUTH_BILLING_ERROR = 0x12, 2021 AUTH_BILLING_EXPIRED = 0x13, 2022 AUTH_VERSION_MISMATCH = 0x14, 2023 AUTH_UNKNOWN_ACCOUNT = 0x15, 2024 AUTH_INCORRECT_PASSWORD = 0x16, 2025 AUTH_SESSION_EXPIRED = 0x17, 2026 AUTH_SERVER_SHUTTING_DOWN = 0x18, 2027 AUTH_ALREADY_LOGGING_IN = 0x19, 2028 AUTH_LOGIN_SERVER_NOT_FOUND = 0x1A, 2029 AUTH_WAIT_QUEUE = 0x1B, 2030 AUTH_BANNED = 0x1C, 2031 AUTH_ALREADY_ONLINE = 0x1D, 2032 AUTH_NO_TIME = 0x1E, 2033 AUTH_DB_BUSY = 0x1F, 2034 AUTH_SUSPENDED = 0x20, 2035 AUTH_PARENTAL_CONTROL = 0x21, 2036 AUTH_LOCKED_ENFORCED = 0x22, 2037 2038 REALM_LIST_IN_PROGRESS = 0x23, 2039 REALM_LIST_SUCCESS = 0x24, 2040 REALM_LIST_FAILED = 0x25, 2041 REALM_LIST_INVALID = 0x26, 2042 REALM_LIST_REALM_NOT_FOUND = 0x27, 2043 2044 ACCOUNT_CREATE_IN_PROGRESS = 0x28, 2045 ACCOUNT_CREATE_SUCCESS = 0x29, 2046 ACCOUNT_CREATE_FAILED = 0x2A, 2047 2048 CHAR_LIST_RETRIEVING = 0x2B, 2049 CHAR_LIST_RETRIEVED = 0x2C, 2050 CHAR_LIST_FAILED = 0x2D, 2051 2052 CHAR_CREATE_IN_PROGRESS = 0x2E, 2053 CHAR_CREATE_SUCCESS = 0x2F, 2054 CHAR_CREATE_ERROR = 0x30, 2055 CHAR_CREATE_FAILED = 0x31, 2056 CHAR_CREATE_NAME_IN_USE = 0x32, 2057 CHAR_CREATE_DISABLED = 0x33, 2058 CHAR_CREATE_PVP_TEAMS_VIOLATION = 0x34, 2059 CHAR_CREATE_SERVER_LIMIT = 0x35, 2060 CHAR_CREATE_ACCOUNT_LIMIT = 0x36, 2061 CHAR_CREATE_SERVER_QUEUE = 0x37, 2062 CHAR_CREATE_ONLY_EXISTING = 0x38, 2063 CHAR_CREATE_EXPANSION = 0x39, 2064 2065 CHAR_DELETE_IN_PROGRESS = 0x3A, 2066 CHAR_DELETE_SUCCESS = 0x3B, 2067 CHAR_DELETE_FAILED = 0x3C, 2068 CHAR_DELETE_FAILED_LOCKED_FOR_TRANSFER = 0x3D, 2069 CHAR_DELETE_FAILED_GUILD_LEADER = 0x3E, 2070 CHAR_DELETE_FAILED_ARENA_CAPTAIN = 0x3F, 2071 2072 CHAR_LOGIN_IN_PROGRESS = 0x40, 2073 CHAR_LOGIN_SUCCESS = 0x41, 2074 CHAR_LOGIN_NO_WORLD = 0x42, 2075 CHAR_LOGIN_DUPLICATE_CHARACTER = 0x43, 2076 CHAR_LOGIN_NO_INSTANCES = 0x44, 2077 CHAR_LOGIN_FAILED = 0x45, 2078 CHAR_LOGIN_DISABLED = 0x46, 2079 CHAR_LOGIN_NO_CHARACTER = 0x47, 2080 CHAR_LOGIN_LOCKED_FOR_TRANSFER = 0x48, 2081 CHAR_LOGIN_LOCKED_BY_BILLING = 0x49, 2082 2083 CHAR_NAME_SUCCESS = 0x4A, 2084 CHAR_NAME_FAILURE = 0x4B, 2085 CHAR_NAME_NO_NAME = 0x4C, 2086 CHAR_NAME_TOO_SHORT = 0x4D, 2087 CHAR_NAME_TOO_LONG = 0x4E, 2088 CHAR_NAME_INVALID_CHARACTER = 0x4F, 2089 CHAR_NAME_MIXED_LANGUAGES = 0x50, 2090 CHAR_NAME_PROFANE = 0x51, 2091 CHAR_NAME_RESERVED = 0x52, 2092 CHAR_NAME_INVALID_APOSTROPHE = 0x53, 2093 CHAR_NAME_MULTIPLE_APOSTROPHES = 0x54, 2094 CHAR_NAME_THREE_CONSECUTIVE = 0x55, 2095 CHAR_NAME_INVALID_SPACE = 0x56, 2096 CHAR_NAME_CONSECUTIVE_SPACES = 0x57, 2097 CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS = 0x58, 2098 CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END = 0x59, 2099 CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = 0x5A, 2100 }; 1997 2101 #endif -
trunk/src/game/Spell.cpp
r2 r6 524 524 case SPELL_EFFECT_RESURRECT: 525 525 case SPELL_EFFECT_PARRY: 526 case SPELL_EFFECT_BLOCK: 526 527 case SPELL_EFFECT_CREATE_ITEM: 527 528 case SPELL_EFFECT_TRIGGER_SPELL: … … 3477 3478 case SPELL_EFFECT_DUMMY: 3478 3479 { 3479 // Execute 3480 if(m_spellInfo->SpellIconID == 1648) 3480 if(m_spellInfo->SpellIconID == 1648) // Execute 3481 3481 { 3482 3482 if(!m_targets.getUnitTarget() || m_targets.getUnitTarget()->GetHealth() > m_targets.getUnitTarget()->GetMaxHealth()*0.2) 3483 3483 return SPELL_FAILED_BAD_TARGETS; 3484 3484 } 3485 else if (m_spellInfo->Id == 51582) 3485 else if (m_spellInfo->Id == 51582) // Rocket Boots Engaged 3486 3486 { 3487 3487 if(m_caster->IsInWater()) 3488 3488 return SPELL_FAILED_ONLY_ABOVEWATER; 3489 } 3490 else if(m_spellInfo->SpellIconID==156) // Holy Shock 3491 { 3492 // spell different for friends and enemies 3493 // hart version required facing 3494 if(m_targets.getUnitTarget() && !m_caster->IsFriendlyTo(m_targets.getUnitTarget()) && !m_caster->HasInArc( M_PI, target )) 3495 return SPELL_FAILED_UNIT_NOT_INFRONT; 3489 3496 } 3490 3497 break; … … 4232 4239 if(dist < min_range) 4233 4240 return SPELL_FAILED_TOO_CLOSE; 4234 if( !m_IsTriggeredSpell && m_caster->GetTypeId() == TYPEID_PLAYER && 4235 !IsPositiveSpell(m_spellInfo->Id) && !m_caster->HasInArc( M_PI, target ) ) 4236 { 4237 // Spell-Family Related Checks 4238 switch (m_spellInfo->SpellFamilyName) 4239 { 4240 case SPELLFAMILY_PRIEST: 4241 { 4242 // Shadow Word: Death, castable without facing 4243 if (m_spellInfo->SpellFamilyFlags & 0x200000000LL) 4244 return 0; // this is not TARGET_FLAG_DEST_LOCATION so we can return safely 4245 break; 4246 } 4247 case SPELLFAMILY_PALADIN: 4248 { 4249 // Holy Shock, require facing 4250 if (m_spellInfo->SpellFamilyFlags & 0x200000LL) 4251 return SPELL_FAILED_UNIT_NOT_INFRONT; 4252 break; 4253 } 4254 case SPELLFAMILY_WARRIOR: 4255 { 4256 // Charge, require facing 4257 if (m_spellInfo->SpellFamilyFlags & 1) 4258 return SPELL_FAILED_UNIT_NOT_INFRONT; 4259 break; 4260 } 4261 } 4262 4263 // Ranged Weapon 4264 if (IsRangedSpell()) 4265 return SPELL_FAILED_UNIT_NOT_INFRONT; 4266 4267 // Melee Combat 4268 if (m_spellInfo->rangeIndex == 2) 4269 return SPELL_FAILED_UNIT_NOT_INFRONT; 4270 4271 // Missile Effect 4272 if (m_spellInfo->speed > 0) 4273 return SPELL_FAILED_UNIT_NOT_INFRONT; 4274 4275 // Channeled Spells need facing 4276 if (IsChanneledSpell(m_spellInfo)) 4277 return SPELL_FAILED_UNIT_NOT_INFRONT; 4278 4279 // Direct Damage and charge effects 4280 for (uint8 i=0;i<3;++i) 4281 { 4282 if (m_spellInfo->Effect[i] == SPELL_EFFECT_SCHOOL_DAMAGE || 4283 m_spellInfo->Effect[i] == SPELL_EFFECT_POWER_BURN || 4284 m_spellInfo->Effect[i] == SPELL_EFFECT_HEALTH_LEECH || 4285 m_spellInfo->Effect[i] == SPELL_EFFECT_CHARGE) 4286 return SPELL_FAILED_UNIT_NOT_INFRONT; 4287 } 4288 } 4241 if( m_caster->GetTypeId() == TYPEID_PLAYER && 4242 (m_spellInfo->FacingCasterFlags & SPELL_FACING_FLAG_INFRONT) && !m_caster->HasInArc( M_PI, target ) ) 4243 return SPELL_FAILED_UNIT_NOT_INFRONT; 4289 4244 } 4290 4245 -
trunk/src/game/Spell.h
r2 r6 252 252 void EffectResurrect(uint32 i); 253 253 void EffectParry(uint32 i); 254 void EffectBlock(uint32 i); 254 255 void EffectMomentMove(uint32 i); 255 256 void EffectTransmitted(uint32 i); -
trunk/src/game/SpellEffects.cpp
r2 r6 79 79 &Spell::EffectUnused, // 21 SPELL_EFFECT_EVADE one spell: Evade (DND) 80 80 &Spell::EffectParry, // 22 SPELL_EFFECT_PARRY 81 &Spell::Effect Unused,// 23 SPELL_EFFECT_BLOCK one spell: Block81 &Spell::EffectBlock, // 23 SPELL_EFFECT_BLOCK one spell: Block 82 82 &Spell::EffectCreateItem, // 24 SPELL_EFFECT_CREATE_ITEM 83 83 &Spell::EffectUnused, // 25 SPELL_EFFECT_WEAPON … … 5331 5331 } 5332 5332 5333 void Spell::EffectBlock(uint32 /*i*/) 5334 { 5335 if (unitTarget->GetTypeId() != TYPEID_PLAYER) 5336 return; 5337 5338 ((Player*)unitTarget)->SetCanBlock(true); 5339 } 5340 5333 5341 void Spell::EffectMomentMove(uint32 i) 5334 5342 { -
trunk/src/game/StatSystem.cpp
r2 r6 432 432 void Player::UpdateBlockPercentage() 433 433 { 434 // Base value 435 float value = 5.0f; 436 // Modify value from defense skill 437 value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f; 438 // Increase from SPELL_AURA_MOD_BLOCK_PERCENT aura 439 value += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT); 440 // Increase from rating 441 value += GetRatingBonusValue(CR_BLOCK); 442 value = value < 0.0f ? 0.0f : value; 434 // No block 435 float value = 0.0f; 436 if(CanBlock()) 437 { 438 // Base value 439 value = 5.0f; 440 // Modify value from defense skill 441 value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f; 442 // Increase from SPELL_AURA_MOD_BLOCK_PERCENT aura 443 value += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT); 444 // Increase from rating 445 value += GetRatingBonusValue(CR_BLOCK); 446 value = value < 0.0f ? 0.0f : value; 447 } 443 448 SetStatFloatValue(PLAYER_BLOCK_PERCENTAGE, value); 444 449 } … … 492 497 void Player::UpdateParryPercentage() 493 498 { 494 // Base parry 495 float value = 5.0f; 496 // Modify value from defense skill 497 value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f; 498 // Parry from SPELL_AURA_MOD_PARRY_PERCENT aura 499 value += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT); 500 // Parry from rating 501 value += GetRatingBonusValue(CR_PARRY); 502 value = value < 0.0f ? 0.0f : value; 499 // No parry 500 float value = 0.0f; 501 if (CanParry()) 502 { 503 // Base parry 504 value = 5.0f; 505 // Modify value from defense skill 506 value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f; 507 // Parry from SPELL_AURA_MOD_PARRY_PERCENT aura 508 value += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT); 509 // Parry from rating 510 value += GetRatingBonusValue(CR_PARRY); 511 value = value < 0.0f ? 0.0f : value; 512 } 503 513 SetStatFloatValue(PLAYER_PARRY_PERCENTAGE, value); 504 514 } -
trunk/src/game/Unit.cpp
r2 r6 2991 2991 if(player->CanParry() ) 2992 2992 { 2993 Item *tmpitem = ((Player*)this)->GetWeaponForAttack(BASE_ATTACK,true);2993 Item *tmpitem = player->GetWeaponForAttack(BASE_ATTACK,true); 2994 2994 if(!tmpitem) 2995 tmpitem = ((Player*)this)->GetWeaponForAttack(OFF_ATTACK,true);2995 tmpitem = player->GetWeaponForAttack(OFF_ATTACK,true); 2996 2996 2997 2997 if(tmpitem) … … 3018 3018 if(GetTypeId() == TYPEID_PLAYER) 3019 3019 { 3020 Item *tmpitem = ((Player const*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); 3021 if(tmpitem && !tmpitem->IsBroken() && tmpitem->GetProto()->Block) 3022 return GetFloatValue(PLAYER_BLOCK_PERCENTAGE); 3023 else 3024 return 0.0f; 3020 Player const* player = (Player const*)this; 3021 if(player->CanBlock() ) 3022 { 3023 Item *tmpitem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND); 3024 if(tmpitem && !tmpitem->IsBroken() && tmpitem->GetProto()->Block) 3025 return GetFloatValue(PLAYER_BLOCK_PERCENTAGE); 3026 } 3027 // is player but has no block ability or no not broken shield equiped 3028 return 0.0f; 3025 3029 } 3026 3030 else … … 3416 3420 return c->canSwim(); 3417 3421 else 3418 return c->canWalk() ;3422 return c->canWalk() || c->canFly(); 3419 3423 } 3420 3424 -
trunk/src/game/Unit.h
r2 r6 116 116 117 117 #define MAX_SPELLMOD 32 118 119 enum SpellFacingFlags 120 { 121 SPELL_FACING_FLAG_INFRONT = 0x0001 122 }; 118 123 119 124 #define BASE_MINDAMAGE 1.0f -
trunk/src/game/WaypointMovementGenerator.cpp
r2 r6 112 112 // Now we re-set destination to same node and start travel 113 113 creature.addUnitState(UNIT_STAT_ROAMING); 114 if (creature.canFly()) 115 creature.SetUnitMovementFlags(MOVEMENTFLAG_FLYING2); 114 116 const WaypointNode &node = i_path->at(i_currentNode); 115 117 i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); … … 174 176 { 175 177 creature.addUnitState(UNIT_STAT_ROAMING); 178 if (creature.canFly()) 179 creature.SetUnitMovementFlags(MOVEMENTFLAG_FLYING2); 176 180 const WaypointNode &node = i_path->at(i_currentNode); 177 181 i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); -
trunk/src/game/World.cpp
r2 r6 22 22 23 23 #include "Common.h" 24 //#include "WorldSocket.h" 24 25 #include "Database/DatabaseEnv.h" 25 26 #include "Config/ConfigEnv.h" … … 51 52 #include "GameEvent.h" 52 53 #include "Database/DatabaseImpl.h" 53 #include "WorldSocket.h"54 54 #include "GridNotifiersImpl.h" 55 55 #include "CellImpl.h" … … 124 124 125 125 if(m_resultQueue) delete m_resultQueue; 126 127 //TODO free addSessQueue 126 128 } 127 129 … … 174 176 } 175 177 176 /// Add a session to the session list177 178 void World::AddSession(WorldSession* s) 178 179 { 179 ASSERT(s); 180 181 WorldSession* old = m_sessions[s->GetAccountId()]; 182 m_sessions[s->GetAccountId()] = s; 183 184 // if session already exist, prepare to it deleting at next world update 185 if(old) 186 m_kicked_sessions.insert(old); 187 } 188 189 int32 World::GetQueuePos(WorldSocket* socket) 180 addSessQueue.add(s); 181 } 182 183 void 184 World::AddSession_ (WorldSession* s) 185 { 186 ASSERT (s); 187 188 //NOTE - Still there is race condition in WorldSession* being used in the Sockets 189 190 ///- kick already loaded player with same account (if any) and remove session 191 ///- if player is in loading and want to load again, return 192 if (!RemoveSession (s->GetAccountId ())) 193 { 194 s->KickPlayer (); 195 m_kicked_sessions.insert (s); 196 return; 197 } 198 199 WorldSession* old = m_sessions[s->GetAccountId ()]; 200 m_sessions[s->GetAccountId ()] = s; 201 202 // if session already exist, prepare to it deleting at next world update 203 // NOTE - KickPlayer() should be called on "old" in RemoveSession() 204 if (old) 205 m_kicked_sessions.insert (old); 206 207 uint32 Sessions = GetActiveAndQueuedSessionCount (); 208 uint32 pLimit = GetPlayerAmountLimit (); 209 uint32 QueueSize = GetQueueSize (); //number of players in the queue 210 bool inQueue = false; 211 //so we don't count the user trying to 212 //login as a session and queue the socket that we are using 213 --Sessions; 214 215 if (pLimit > 0 && Sessions >= pLimit && s->GetSecurity () == SEC_PLAYER ) 216 { 217 AddQueuedPlayer (s); 218 UpdateMaxSessionCounters (); 219 sLog.outDetail ("PlayerQueue: Account id %u is in Queue Position (%u).", s->GetAccountId (), ++QueueSize); 220 return; 221 } 222 223 WorldPacket packet(SMSG_AUTH_RESPONSE, 1 + 4 + 1 + 4 + 1); 224 packet << uint8 (AUTH_OK); 225 packet << uint32 (0); // unknown random value... 226 packet << uint8 (0); 227 packet << uint32 (0); 228 packet << uint8 (s->IsTBC () ? 1 : 0); // 0 - normal, 1 - TBC, must be set in database manually for each account 229 s->SendPacket (&packet); 230 231 UpdateMaxSessionCounters (); 232 233 // Updates the population 234 if (pLimit > 0) 235 { 236 float popu = GetActiveSessionCount (); //updated number of users on the server 237 popu /= pLimit; 238 popu *= 2; 239 loginDatabase.PExecute ("UPDATE realmlist SET population = '%f' WHERE id = '%d'", popu, realmID); 240 sLog.outDetail ("Server Population (%f).", popu); 241 } 242 } 243 244 int32 World::GetQueuePos(WorldSession* sess) 190 245 { 191 246 uint32 position = 1; 192 247 193 248 for(Queue::iterator iter = m_QueuedPlayer.begin(); iter != m_QueuedPlayer.end(); ++iter, ++position) 194 if((*iter) == s ocket)249 if((*iter) == sess) 195 250 return position; 196 251 … … 198 253 } 199 254 200 void World::AddQueuedPlayer(WorldSocket* socket) 201 { 202 m_QueuedPlayer.push_back(socket); 203 } 204 205 void World::RemoveQueuedPlayer(WorldSocket* socket) 255 void World::AddQueuedPlayer(WorldSession* sess) 256 { 257 m_QueuedPlayer.push_back (sess); 258 259 // The 1st SMSG_AUTH_RESPONSE needs to contain other info too. 260 WorldPacket packet (SMSG_AUTH_RESPONSE, 1 + 4 + 1 + 4 + 1); 261 packet << uint8 (AUTH_WAIT_QUEUE); 262 packet << uint32 (0); // unknown random value... 263 packet << uint8 (0); 264 packet << uint32 (0); 265 packet << uint8 (sess->IsTBC () ? 1 : 0); // 0 - normal, 1 - TBC, must be set in database manually for each account 266 packet << uint32(GetQueuePos (sess)); 267 sess->SendPacket (&packet); 268 269 //sess->SendAuthWaitQue (GetQueuePos (sess)); 270 } 271 272 void World::RemoveQueuedPlayer(WorldSession* sess) 206 273 { 207 274 // sessions count including queued to remove (if removed_session set) … … 214 281 bool decrease_session = true; 215 282 216 // search socketto remove and count skipped positions283 // search to remove and count skipped positions 217 284 for(;iter != m_QueuedPlayer.end(); ++iter, ++position) 218 285 { 219 if(*iter==s ocket)286 if(*iter==sess) 220 287 { 221 288 Queue::iterator iter2 = iter; … … 237 304 if( (!m_playerLimit || sessions < m_playerLimit) && !m_QueuedPlayer.empty() ) 238 305 { 239 WorldS ocket* socket = m_QueuedPlayer.front();306 WorldSession * socket = m_QueuedPlayer.front(); 240 307 socket->SendAuthWaitQue(0); 241 308 m_QueuedPlayer.pop_front(); … … 1016 1083 objmgr.LoadBattleMastersEntry(); 1017 1084 1085 sLog.outString( "Loading GameTeleports..." ); 1086 objmgr.LoadGameTele(); 1087 1088 sLog.outString( "Loading Npc Text Id..." ); 1089 objmgr.LoadNpcTextId(); // must be after load Creature and NpcText 1090 1091 sLog.outString( "Loading vendors..." ); 1092 objmgr.LoadVendors(); // must be after load CreatureTemplate and ItemTemplate 1093 1094 sLog.outString( "Loading trainers..." ); 1095 objmgr.LoadTrainerSpell(); // must be after load CreatureTemplate 1096 1018 1097 sLog.outString( "Loading Waypoints..." ); 1019 1098 WaypointMgr.Load(); … … 2069 2148 { 2070 2149 // session not removed at kick and will removed in next update tick 2071 for (Queue::iterator itr = m_QueuedPlayer.begin(); itr != m_QueuedPlayer.end(); ++itr) 2072 if(WorldSession* session = (*itr)->GetSession()) 2073 session->KickPlayer(); 2150 //TODO here 2151 // for (Queue::iterator itr = m_QueuedPlayer.begin(); itr != m_QueuedPlayer.end(); ++itr) 2152 // if(WorldSession* session = (*itr)->GetSession()) 2153 // session->KickPlayer(); 2074 2154 2075 2155 m_QueuedPlayer.empty(); … … 2321 2401 void World::UpdateSessions( time_t diff ) 2322 2402 { 2403 while(!addSessQueue.empty()) 2404 { 2405 WorldSession* sess = addSessQueue.next (); 2406 AddSession_ (sess); 2407 } 2408 2323 2409 ///- Delete kicked sessions at add new session 2324 2410 for (std::set<WorldSession*>::iterator itr = m_kicked_sessions.begin(); itr != m_kicked_sessions.end(); ++itr) -
trunk/src/game/World.h
r2 r6 363 363 364 364 //player Queue 365 typedef std::list<WorldS ocket*> Queue;366 void AddQueuedPlayer(WorldS ocket* Socket);367 void RemoveQueuedPlayer(WorldS ocket* Socket);368 int32 GetQueuePos(WorldS ocket* Socket);365 typedef std::list<WorldSession*> Queue; 366 void AddQueuedPlayer(WorldSession*); 367 void RemoveQueuedPlayer(WorldSession*); 368 int32 GetQueuePos(WorldSession*); 369 369 uint32 GetQueueSize() const { return m_QueuedPlayer.size(); } 370 370 … … 526 526 //Player Queue 527 527 Queue m_QueuedPlayer; 528 529 //sessions that are added async 530 void AddSession_(WorldSession* s); 531 ZThread::LockedQueue<WorldSession*, ZThread::FastMutex> addSessQueue; 528 532 }; 529 533 -
trunk/src/game/WorldSession.cpp
r2 r6 21 21 */ 22 22 23 #include "WorldSocket.h" 23 24 #include "Common.h" 24 25 #include "Database/DatabaseEnv.h" … … 43 44 WorldSession::WorldSession(uint32 id, WorldSocket *sock, uint32 sec, bool tbc, time_t mute_time, LocaleConstant locale) : 44 45 LookingForGroup_auto_join(false), LookingForGroup_auto_add(false), m_muteTime(mute_time), 45 _player(NULL), _socket(sock),_security(sec), _accountId(id), m_isTBC(tbc),46 _player(NULL), m_Socket(sock),_security(sec), _accountId(id), m_isTBC(tbc), 46 47 m_sessionDbcLocale(sWorld.GetAvailableDbcLocale(locale)), m_sessionDbLocaleIndex(objmgr.GetIndexForLocale(locale)), 47 48 _logoutTime(0), m_playerLoading(false), m_playerLogout(false), m_playerRecentlyLogout(false), m_latency(0) 48 49 { 50 if (sock) 51 { 52 m_Address = sock->GetRemoteAddress (); 53 sock->AddReference (); 54 } 49 55 } 50 56 … … 57 63 58 64 /// - If have unclosed socket, close it 59 if(_socket) 60 _socket->CloseSocket(); 61 62 _socket = NULL; 65 if (m_Socket) 66 { 67 m_Socket->CloseSocket (); 68 m_Socket->RemoveReference (); 69 m_Socket = NULL; 70 } 63 71 64 72 ///- empty incoming packet queue … … 68 76 delete packet; 69 77 } 78 79 sWorld.RemoveQueuedPlayer(this); 70 80 } 71 81 … … 82 92 } 83 93 84 /// Set the WorldSocket associated with this session85 void WorldSession::SetSocket(WorldSocket *sock)86 {87 _socket = sock;88 }89 90 94 /// Send a packet to the client 91 95 void WorldSession::SendPacket(WorldPacket const* packet) 92 96 { 93 if (! _socket)97 if (!m_Socket) 94 98 return; 95 99 #ifdef MANGOS_DEBUG … … 125 129 sendLastPacketBytes = packet->wpos(); // wpos is real written size 126 130 } 127 #endif // !MANGOS_DEBUG 128 129 _socket->SendPacket(packet); 131 #endif // !MANGOS_DEBUG 132 133 if (m_Socket->SendPacket (*packet) == -1) 134 { 135 m_Socket->CloseSocket (); 136 } 130 137 } 131 138 132 139 /// Add an incoming packet to the queue 133 void WorldSession::QueuePacket(WorldPacket& packet) 134 { 135 WorldPacket *pck = new WorldPacket(packet); 136 _recvQueue.add(pck); 140 void WorldSession::QueuePacket(WorldPacket* new_packet) 141 { 142 _recvQueue.add(new_packet); 137 143 } 138 144 … … 149 155 bool WorldSession::Update(uint32 /*diff*/) 150 156 { 157 if (m_Socket) 158 if (m_Socket->IsClosed ()) 159 { 160 m_Socket->RemoveReference (); 161 m_Socket = NULL; 162 } 163 151 164 WorldPacket *packet; 152 165 … … 211 224 ///- If necessary, log the player out 212 225 time_t currTime = time(NULL); 213 if (! _socket || (ShouldLogOut(currTime) && !m_playerLoading))226 if (!m_Socket || (ShouldLogOut(currTime) && !m_playerLoading)) 214 227 LogoutPlayer(true); 215 228 216 if (! _socket)229 if (!m_Socket) 217 230 return false; //Will remove this session from the world session map 218 231 … … 344 357 // remove player from the group if he is: 345 358 // a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected) 346 if(_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && _socket)359 if(_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket) 347 360 _player->RemoveFromGroup(); 348 361 … … 386 399 void WorldSession::KickPlayer() 387 400 { 388 if(!_socket) 389 return; 390 391 // player will be logout and session will removed in next update tick 392 _socket->CloseSocket(); 393 _socket = NULL; 401 if (m_Socket) 402 { 403 m_Socket->CloseSocket (); 404 } 394 405 } 395 406 … … 462 473 recvPacket.GetOpcode()); 463 474 } 475 476 void WorldSession::SendAuthWaitQue(uint32 position) 477 { 478 if(position == 0) 479 { 480 WorldPacket packet( SMSG_AUTH_RESPONSE, 1 ); 481 packet << uint8( AUTH_OK ); 482 SendPacket(&packet); 483 } 484 else 485 { 486 WorldPacket packet( SMSG_AUTH_RESPONSE, 5 ); 487 packet << uint8( AUTH_WAIT_QUEUE ); 488 packet << uint32 (position); 489 SendPacket(&packet); 490 } 491 } 492 493 -
trunk/src/game/WorldSession.h
r2 r6 89 89 char const* GetPlayerName() const; 90 90 void SetSecurity(uint32 security) { _security = security; } 91 void SetSocket(WorldSocket *sock);91 std::string& GetRemoteAddress() { return m_Address; } 92 92 void SetPlayer(Player *plr) { _player = plr; } 93 93 bool IsTBC() const { return m_isTBC; } … … 111 111 void KickPlayer(); 112 112 113 void QueuePacket(WorldPacket &packet);113 void QueuePacket(WorldPacket* new_packet); 114 114 bool Update(uint32 diff); 115 116 /// Handle the authentication waiting queue (to be completed) 117 void SendAuthWaitQue(uint32 position); 115 118 116 119 //void SendTestCreatureQueryOpcode( uint32 entry, uint64 guid, uint32 testvalue ); … … 619 622 void logUnexpectedOpcode(WorldPacket *packet, const char * reason); 620 623 Player *_player; 621 WorldSocket *_socket; 624 WorldSocket *m_Socket; 625 std::string m_Address; 622 626 623 627 uint32 _security; -
trunk/src/game/WorldSocket.cpp
r2 r6 1 /* 1 /* 2 2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/> 3 3 * … … 17 17 */ 18 18 19 /** \file20 \ingroup u2w21 */22 23 19 #include "Common.h" 24 #include "Log.h" 20 #include "WorldSocket.h" 21 #include <ace/Message_Block.h> 22 #include <ace/OS_NS_string.h> 23 #include <ace/OS_NS_unistd.h> 24 #include <ace/os_include/arpa/os_inet.h> 25 #include <ace/os_include/netinet/os_tcp.h> 26 #include <ace/os_include/sys/os_types.h> 27 #include <ace/os_include/sys/os_socket.h> 28 #include <ace/OS_NS_string.h> 29 #include <ace/Reactor.h> 30 #include <ace/Auto_Ptr.h> 31 32 #include "Util.h" 33 #include "World.h" 34 #include "WorldPacket.h" 35 #include "SharedDefines.h" 36 #include "ByteBuffer.h" 37 #include "AddonHandler.h" 25 38 #include "Opcodes.h" 26 39 #include "Database/DatabaseEnv.h" 27 40 #include "Auth/Sha1.h" 28 #include "WorldPacket.h"29 #include "WorldSocket.h"30 41 #include "WorldSession.h" 31 #include "World.h"32 42 #include "WorldSocketMgr.h" 33 #include " Policies/SingletonImp.h"43 #include "Log.h" 34 44 #include "WorldLog.h" 35 #include "AddonHandler.h" 36 #include "sockets/Utility.h" 37 #include "Util.h" 38 39 // GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform 45 40 46 #if defined( __GNUC__ ) 41 47 #pragma pack(1) … … 44 50 #endif 45 51 46 /// Client Packet Header 52 struct ServerPktHeader 53 { 54 ACE_UINT16 size; 55 ACE_UINT16 cmd; 56 }; 57 47 58 struct ClientPktHeader 48 59 { 49 uint16 size;50 uint32 cmd;60 ACE_UINT16 size; 61 ACE_UINT32 cmd; 51 62 }; 52 63 53 /// Server Packet Header54 struct ServerPktHeader55 {56 uint16 size;57 uint16 cmd;58 };59 60 // GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform61 64 #if defined( __GNUC__ ) 62 65 #pragma pack() … … 65 68 #endif 66 69 67 #define SOCKET_CHECK_PACKET_SIZE(P,S) if((P).size() < (S)) return SizeError((P),(S)); 68 69 /// WorldSocket construction and initialization. 70 WorldSocket::WorldSocket(ISocketHandler &sh): TcpSocket(sh), _cmd(0), _remaining(0), _session(NULL) 71 { 72 _seed = static_cast<uint32>(rand32()); 73 m_LastPingMSTime = 0; // first time it will counted as overspeed maybe, but this is not important 74 m_OverSpeedPings = 0; 75 76 if (sWorld.getConfig(CONFIG_TCP_NO_DELAY)) 77 SetTcpNodelay(true); 78 } 79 80 /// WorldSocket destructor 81 WorldSocket::~WorldSocket() 82 { 83 if(_session) 84 _session->SetSocket(0); 85 86 WorldPacket *packet; 87 88 ///- Go through the to-be-sent queue and delete remaining packets 89 while(!_sendQueue.empty()) 90 { 91 packet = _sendQueue.next(); 92 delete packet; 93 } 94 } 95 96 /// Copy the packet to the to-be-sent queue 97 void WorldSocket::SendPacket(WorldPacket const* packet) 98 { 99 WorldPacket *pck = new WorldPacket(*packet); 100 ASSERT(pck); 101 _sendQueue.add(pck); 102 } 103 104 /// On client connection 105 void WorldSocket::OnAccept() 106 { 107 ///- Add the current socket to the list of sockets to be managed (WorldSocketMgr) 108 sWorldSocketMgr.AddSocket(this); 109 Utility::ResolveLocal(); 110 111 ///- Send a AUTH_CHALLENGE packet 112 WorldPacket packet( SMSG_AUTH_CHALLENGE, 4 ); 113 packet << _seed; 114 115 SendPacket(&packet); 116 } 117 118 /// Read the client transmitted data 119 void WorldSocket::OnRead() 120 { 121 TcpSocket::OnRead(); 122 123 while(1) 124 { 125 ///- Read the packet header and decipher it (if needed) 126 if (!_remaining) 127 { 128 if (ibuf.GetLength() < 6) 129 break; 130 131 ClientPktHeader hdr; 132 133 ibuf.Read((char *)&hdr, 6); 134 _crypt.DecryptRecv((uint8 *)&hdr, 6); 135 136 _remaining = ntohs(hdr.size) - 4; 137 _cmd = hdr.cmd; 138 } 139 140 if (ibuf.GetLength() < _remaining) 141 break; 142 143 ///- Read the remaining of the packet 144 WorldPacket packet((uint16)_cmd, _remaining); 145 146 packet.resize(_remaining); 147 if(_remaining) ibuf.Read((char*)packet.contents(), _remaining); 148 _remaining = 0; 149 150 ///- If log of world packets is enable, log the incoming packet 151 if( sWorldLog.LogWorld() ) 152 { 153 sWorldLog.Log("CLIENT:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", 154 (uint32)GetSocket(), 155 packet.size(), 156 LookupOpcodeName(packet.GetOpcode()), 157 packet.GetOpcode()); 158 159 uint32 p = 0; 160 while (p < packet.size()) 70 // used when testing to alow login without password and encryption 71 // #define _NETCODE_FAKE_AUTH 72 73 WorldSocket::WorldSocket (void) : 74 WorldHandler (), 75 m_Session (0), 76 m_RecvWPct (0), 77 m_RecvPct (), 78 m_Header (sizeof (ClientPktHeader)), 79 m_OutBuffer (0), 80 m_OutBufferSize (65536), 81 m_OutActive (false), 82 m_Seed (static_cast<uint32> (rand32 ())), 83 m_OverSpeedPings (0), 84 m_LastPingTime (ACE_Time_Value::zero) 85 { 86 this->reference_counting_policy ().value (ACE_Event_Handler::Reference_Counting_Policy::ENABLED); 87 } 88 89 WorldSocket::~WorldSocket (void) 90 { 91 if (m_RecvWPct) 92 delete m_RecvWPct; 93 94 if (m_OutBuffer) 95 m_OutBuffer->release (); 96 97 this->closing_ = true; 98 99 this->peer ().close (); 100 101 WorldPacket* pct; 102 while (m_PacketQueue.dequeue_head (pct) == 0) 103 delete pct; 104 } 105 106 bool 107 WorldSocket::IsClosed (void) const 108 { 109 return this->closing_; 110 } 111 112 void 113 WorldSocket::CloseSocket (void) 114 { 115 { 116 ACE_GUARD (LockType, Guard, m_OutBufferLock); 117 118 if (this->closing_) 119 return; 120 121 this->closing_ = true; 122 123 this->peer ().close_writer (); 124 } 125 126 { 127 ACE_GUARD (LockType, Guard, m_SessionLock); 128 129 m_Session = NULL; 130 } 131 132 } 133 134 const std::string& 135 WorldSocket::GetRemoteAddress (void) const 136 { 137 return m_Address; 138 } 139 140 int 141 WorldSocket::SendPacket (const WorldPacket& pct) 142 { 143 ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); 144 145 if (this->closing_) 146 return -1; 147 148 // Dump outgoing packet. 149 if (sWorldLog.LogWorld ()) 150 { 151 sWorldLog.Log ("SERVER:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", 152 (uint32) get_handle (), 153 pct.size (), 154 LookupOpcodeName (pct.GetOpcode ()), 155 pct.GetOpcode ()); 156 157 uint32 p = 0; 158 while (p < pct.size ()) 159 { 160 for (uint32 j = 0; j < 16 && p < pct.size (); j++) 161 sWorldLog.Log ("%.2X ", const_cast<WorldPacket&>(pct)[p++]); 162 163 sWorldLog.Log ("\n"); 164 } 165 166 sWorldLog.Log ("\n\n"); 167 } 168 169 if (iSendPacket (pct) == -1) 170 { 171 WorldPacket* npct; 172 173 ACE_NEW_RETURN (npct, WorldPacket (pct), -1); 174 175 // NOTE maybe check of the size of the queue can be good ? 176 // to make it bounded instead of unbounded 177 if (m_PacketQueue.enqueue_tail (npct) == -1) 178 { 179 delete npct; 180 sLog.outError ("WorldSocket::SendPacket: m_PacketQueue.enqueue_tail failed"); 181 return -1; 182 } 183 } 184 185 return 0; 186 } 187 188 long 189 WorldSocket::AddReference (void) 190 { 191 return static_cast<long> (this->add_reference ()); 192 } 193 194 long 195 WorldSocket::RemoveReference (void) 196 { 197 return static_cast<long> (this->remove_reference ()); 198 } 199 200 int 201 WorldSocket::open (void *a) 202 { 203 ACE_UNUSED_ARG (a); 204 205 // Prevent double call to this func. 206 if (m_OutBuffer) 207 return -1; 208 209 // This will also prevent the socket from being Updated 210 // while we are initializing it. 211 m_OutActive = true; 212 213 // Hook for the manager. 214 if (sWorldSocketMgr->OnSocketOpen (this) == -1) 215 return -1; 216 217 // Allocate the buffer. 218 ACE_NEW_RETURN (m_OutBuffer, ACE_Message_Block (m_OutBufferSize), -1); 219 220 // Store peer address. 221 ACE_INET_Addr remote_addr; 222 223 if (this->peer ().get_remote_addr (remote_addr) == -1) 224 { 225 sLog.outError ("WorldSocket::open: peer ().get_remote_addr errno = %s", ACE_OS::strerror (errno)); 226 return -1; 227 } 228 229 m_Address = remote_addr.get_host_addr (); 230 231 // Send startup packet. 232 WorldPacket packet (SMSG_AUTH_CHALLENGE, 4); 233 packet << m_Seed; 234 235 if (SendPacket (packet) == -1) 236 return -1; 237 238 // Register with ACE Reactor 239 if (this->reactor ()->register_handler 240 (this, 241 ACE_Event_Handler::READ_MASK | ACE_Event_Handler::WRITE_MASK) == -1) 242 { 243 sLog.outError ("WorldSocket::open: unable to register client handler errno = %s", ACE_OS::strerror (errno)); 244 return -1; 245 } 246 247 // reactor takes care of the socket from now on 248 this->remove_reference (); 249 250 return 0; 251 } 252 253 int 254 WorldSocket::close (int) 255 { 256 this->shutdown (); 257 258 this->closing_ = true; 259 260 this->remove_reference (); 261 262 return 0; 263 } 264 265 int 266 WorldSocket::handle_input (ACE_HANDLE) 267 { 268 if (this->closing_) 269 return -1; 270 271 switch (this->handle_input_missing_data ()) 272 { 273 case -1 : 274 { 275 if ((errno == EWOULDBLOCK) || 276 (errno == EAGAIN)) 277 { 278 //return 0; 279 return this->Update (); // interesting line ,isnt it ? 280 } 281 282 DEBUG_LOG ("WorldSocket::handle_input: Peer error closing connection errno = %s", ACE_OS::strerror (errno)); 283 284 return -1; 285 } 286 case 0: 287 { 288 DEBUG_LOG ("WorldSocket::handle_input: Peer has closed connection\n"); 289 290 errno = ECONNRESET; 291 292 return -1; 293 } 294 case 1: 295 return 1; 296 } 297 298 //return 0; 299 return this->Update (); // another interesting line ;) 300 } 301 302 int 303 WorldSocket::handle_output (ACE_HANDLE) 304 { 305 ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); 306 307 if (this->closing_) 308 return -1; 309 310 const size_t send_len = m_OutBuffer->length (); 311 312 if (send_len == 0) 313 return this->cancel_wakeup_output (Guard); 314 315 // TODO SO_NOSIGPIPE on platforms that support it 316 #ifdef MSG_NOSIGNAL 317 ssize_t n = this->peer ().send (m_OutBuffer->rd_ptr (), send_len, MSG_NOSIGNAL); 318 #else 319 ssize_t n = this->peer ().send (m_OutBuffer->rd_ptr (), send_len); 320 #endif // MSG_NOSIGNAL 321 322 if (n == 0) 323 return -1; 324 else if (n == -1) 325 { 326 if (errno == EWOULDBLOCK || errno == EAGAIN) 327 return this->schedule_wakeup_output (Guard); 328 329 return -1; 330 } 331 else if (n < send_len) //now n > 0 332 { 333 m_OutBuffer->rd_ptr (static_cast<size_t> (n)); 334 335 // move the data to the base of the buffer 336 m_OutBuffer->crunch (); 337 338 return this->schedule_wakeup_output (Guard); 339 } 340 else //now n == send_len 341 { 342 m_OutBuffer->reset (); 343 344 if (!iFlushPacketQueue ()) 345 return this->cancel_wakeup_output (Guard); 346 else 347 return this->schedule_wakeup_output (Guard); 348 } 349 350 ACE_NOTREACHED (return 0); 351 } 352 353 int 354 WorldSocket::handle_close (ACE_HANDLE h, ACE_Reactor_Mask) 355 { 356 // Critical section 357 { 358 ACE_GUARD_RETURN (LockType, Guard, m_OutBufferLock, -1); 359 360 this->closing_ = true; 361 362 if (h == ACE_INVALID_HANDLE) 363 this->peer ().close_writer (); 364 } 365 366 // Critical section 367 { 368 ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); 369 370 m_Session = NULL; 371 } 372 373 return 0; 374 } 375 376 int 377 WorldSocket::Update (void) 378 { 379 if (this->closing_) 380 return -1; 381 382 if (m_OutActive || m_OutBuffer->length () == 0) 383 return 0; 384 385 return this->handle_output (this->get_handle ()); 386 } 387 388 int 389 WorldSocket::handle_input_header (void) 390 { 391 ACE_ASSERT (m_RecvWPct == NULL); 392 393 if (m_Header.length () != sizeof (ClientPktHeader)) 394 { 395 sLog.outError ("WorldSocket::handle_input_header: internal error: invalid header"); 396 errno = EINVAL; 397 return -1; 398 } 399 400 m_Crypt.DecryptRecv ((ACE_UINT8*) m_Header.rd_ptr (), sizeof (ClientPktHeader)); 401 402 ClientPktHeader& header = *((ClientPktHeader*) m_Header.rd_ptr ()); 403 404 header.size = ACE_NTOHS (header.size); 405 406 #if ACE_BYTE_ORDER == ACE_BIG_ENDIAN 407 header.cmd = ACE_SWAP_LONG (header.cmd) 408 #endif // ACE_BIG_ENDIAN 409 410 if ((header.size < 4) || 411 (header.size > 10240) || 412 (header.cmd <= 0) || 413 (header.cmd > 10240) 414 ) 415 { 416 sLog.outError ("WorldSocket::handle_input_header: client sent mailformed packet size = %d , cmd = %d", 417 header.size, 418 header.cmd); 419 420 errno = EINVAL; 421 return -1; 422 } 423 424 header.size -= 4; 425 426 ACE_NEW_RETURN (m_RecvWPct, WorldPacket ((uint16) header.cmd, header.size), -1); 427 428 if(header.size > 0) 429 { 430 m_RecvWPct->resize (header.size); 431 m_RecvPct.base ((char*) m_RecvWPct->contents (), m_RecvWPct->size ()); 432 } 433 else 434 { 435 ACE_ASSERT(m_RecvPct.space() == 0); 436 } 437 438 439 return 0; 440 } 441 442 int 443 WorldSocket::handle_input_payload (void) 444 { 445 // set errno properly here on error !!! 446 // now have a header and payload 447 448 ACE_ASSERT (m_RecvPct.space () == 0); 449 ACE_ASSERT (m_Header.space () == 0); 450 ACE_ASSERT (m_RecvWPct != NULL); 451 452 const int ret = this->ProcessIncoming (m_RecvWPct); 453 454 m_RecvPct.base (NULL, 0); 455 m_RecvPct.reset (); 456 m_RecvWPct = NULL; 457 458 m_Header.reset (); 459 460 if (ret == -1) 461 errno = EINVAL; 462 463 return ret; 464 } 465 466 int 467 WorldSocket::handle_input_missing_data (void) 468 { 469 char buf [1024]; 470 471 ACE_Data_Block db (sizeof (buf), 472 ACE_Message_Block::MB_DATA, 473 buf, 474 0, 475 0, 476 ACE_Message_Block::DONT_DELETE, 477 0); 478 479 ACE_Message_Block message_block (&db, 480 ACE_Message_Block::DONT_DELETE, 481 0); 482 483 const size_t recv_size = message_block.space (); 484 485 const ssize_t n = this->peer ().recv (message_block.wr_ptr (), 486 recv_size); 487 488 if (n <= 0) 489 return n; 490 491 message_block.wr_ptr (n); 492 493 while (message_block.length () > 0) 494 { 495 if (m_Header.space () > 0) 496 { 497 //need to recieve the header 498 const size_t to_header = (message_block.length () > m_Header.space () ? m_Header.space () : message_block.length ()); 499 m_Header.copy (message_block.rd_ptr (), to_header); 500 message_block.rd_ptr (to_header); 501 502 if (m_Header.space () > 0) 161 503 { 162 for (uint32 j = 0; j < 16 && p < packet.size(); j++) 163 sWorldLog.Log("%.2X ", packet[p++]); 164 sWorldLog.Log("\n"); 504 //couldnt recieve the whole header this time 505 ACE_ASSERT (message_block.length () == 0); 506 errno = EWOULDBLOCK; 507 return -1; 165 508 } 166 sWorldLog.Log("\n\n"); 167 } 168 169 ///- If the packet is PING, KEEP_ALIVE or AUTH_SESSION, handle immediately 170 switch (_cmd) 171 { 172 case CMSG_KEEP_ALIVE: 173 break; // just ignore, network connectivity timeout preventing 174 case CMSG_PING: 509 510 //we just recieved nice new header 511 if (this->handle_input_header () == -1) 175 512 { 176 _HandlePing(packet);177 break;513 ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN)); 514 return -1; 178 515 } 179 case CMSG_AUTH_SESSION: 516 } 517 518 // Its possible on some error situations that this happens 519 // for example on closing when epoll recieves more chunked data and stuff 520 // hope this is not hack ,as proper m_RecvWPct is asserted around 521 if (!m_RecvWPct) 522 { 523 sLog.outError ("Forsing close on input m_RecvWPct = NULL"); 524 errno = EINVAL; 525 return -1; 526 } 527 528 // We have full readed header, now check the data payload 529 if (m_RecvPct.space () > 0) 530 { 531 //need more data in the payload 532 const size_t to_data = (message_block.length () > m_RecvPct.space () ? m_RecvPct.space () : message_block.length ()); 533 m_RecvPct.copy (message_block.rd_ptr (), to_data); 534 message_block.rd_ptr (to_data); 535 536 if (m_RecvPct.space () > 0) 180 537 { 181 _HandleAuthSession(packet); 182 break; 538 //couldnt recieve the whole data this time 539 ACE_ASSERT (message_block.length () == 0); 540 errno = EWOULDBLOCK; 541 return -1; 183 542 } 184 default: 543 } 544 545 //just recieved fresh new payload 546 if (this->handle_input_payload () == -1) 547 { 548 ACE_ASSERT ((errno != EWOULDBLOCK) && (errno != EAGAIN)); 549 return -1; 550 } 551 } 552 553 return n == recv_size ? 1 : 2; 554 } 555 556 int 557 WorldSocket::cancel_wakeup_output (GuardType& g) 558 { 559 if (!m_OutActive) 560 return 0; 561 562 m_OutActive = false; 563 564 g.release (); 565 566 if (this->reactor ()->cancel_wakeup 567 (this, ACE_Event_Handler::WRITE_MASK) == -1) 568 { 569 // would be good to store errno from reactor with errno guard 570 sLog.outError ("WorldSocket::cancel_wakeup_output"); 571 return -1; 572 } 573 574 return 0; 575 } 576 577 int 578 WorldSocket::schedule_wakeup_output (GuardType& g) 579 { 580 if (m_OutActive) 581 return 0; 582 583 m_OutActive = true; 584 585 g.release (); 586 587 if (this->reactor ()->schedule_wakeup 588 (this, ACE_Event_Handler::WRITE_MASK) == -1) 589 { 590 sLog.outError ("WorldSocket::schedule_wakeup_output"); 591 return -1; 592 } 593 594 return 0; 595 } 596 597 int 598 WorldSocket::ProcessIncoming (WorldPacket* new_pct) 599 { 600 ACE_ASSERT (new_pct); 601 602 // manage memory ;) 603 ACE_Auto_Ptr<WorldPacket> aptr (new_pct); 604 605 const ACE_UINT16 opcode = new_pct->GetOpcode (); 606 607 if (this->closing_) 608 return -1; 609 610 // dump recieved packet 611 if (sWorldLog.LogWorld ()) 612 { 613 sWorldLog.Log ("CLIENT:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", 614 (uint32) get_handle (), 615 new_pct->size (), 616 LookupOpcodeName (new_pct->GetOpcode ()), 617 new_pct->GetOpcode ()); 618 619 uint32 p = 0; 620 while (p < new_pct->size ()) 621 { 622 for (uint32 j = 0; j < 16 && p < new_pct->size (); j++) 623 sWorldLog.Log ("%.2X ", (*new_pct)[p++]); 624 sWorldLog.Log ("\n"); 625 } 626 sWorldLog.Log ("\n\n"); 627 } 628 629 // like one switch ;) 630 if (opcode == CMSG_PING) 631 { 632 return HandlePing (*new_pct); 633 } 634 else if (opcode == CMSG_AUTH_SESSION) 635 { 636 if (m_Session) 637 { 638 sLog.outError ("WorldSocket::ProcessIncoming: Player send CMSG_AUTH_SESSION again"); 639 return -1; 640 } 641 642 return HandleAuthSession (*new_pct); 643 } 644 else if (opcode == CMSG_KEEP_ALIVE) 645 { 646 DEBUG_LOG ("CMSG_KEEP_ALIVE ,size: %d", new_pct->size ()); 647 648 return 0; 649 } 650 else 651 { 652 ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); 653 654 if (m_Session != NULL) 655 { 656 // OK ,give the packet to WorldSession 657 aptr.release (); 658 // WARNINIG here we call it with locks held. 659 // Its possible to cause deadlock if QueuePacket calls back 660 m_Session->QueuePacket (new_pct); 661 return 0; 662 } 663 else 664 { 665 sLog.outError ("WorldSocket::ProcessIncoming: Client not authed opcode = ", opcode); 666 return -1; 667 } 668 } 669 670 ACE_NOTREACHED (return 0); 671 } 672 673 int 674 WorldSocket::HandleAuthSession (WorldPacket& recvPacket) 675 { 676 uint8 digest[20]; 677 uint32 clientSeed; 678 uint32 unk2; 679 uint32 BuiltNumberClient; 680 uint32 id, security; 681 bool tbc = false; 682 LocaleConstant locale; 683 std::string account; 684 Sha1Hash sha1; 685 BigNumber v, s, g, N, x, I; 686 WorldPacket packet, SendAddonPacked; 687 688 BigNumber K; 689 690 if (recvPacket.size () < (4 + 4 + 1 + 4 + 20)) 691 { 692 sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size"); 693 return -1; 694 } 695 696 // Read the content of the packet 697 recvPacket >> BuiltNumberClient; // for now no use 698 recvPacket >> unk2; 699 recvPacket >> account; 700 701 if (recvPacket.size () < (4 + 4 + (account.size () + 1) + 4 + 20)) 702 { 703 sLog.outError ("WorldSocket::HandleAuthSession: wrong packet size second check"); 704 return -1; 705 } 706 707 recvPacket >> clientSeed; 708 recvPacket.read (digest, 20); 709 710 DEBUG_LOG ("WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, clientseed %u", 711 BuiltNumberClient, 712 unk2, 713 account.c_str (), 714 clientSeed); 715 716 #if defined _NETCODE_FAKE_AUTH 717 bool dontchechtheacc = false; 718 uint8 digest_fake[sizeof (digest)]; 719 memset ((void*) digest_fake, '\0', sizeof (digest_fake)); 720 if (memcmp ((void*) digest, (void*) digest_fake, sizeof (digest_fake)) == 0) 721 { 722 dontchechtheacc = true; 723 } 724 #endif //_NETCODE_FAKE_AUTH 725 726 // Get the account information from the realmd database 727 std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below 728 loginDatabase.escape_string (safe_account); 729 // No SQL injection, username escaped. 730 731 QueryResult *result = 732 loginDatabase.PQuery ("SELECT " 733 "id, " //0 734 "gmlevel, " //1 735 "sessionkey, " //2 736 "last_ip, " //3 737 "locked, " //4 738 "sha_pass_hash, " //5 739 "v, " //6 740 "s, " //7 741 "tbc, " //8 742 "mutetime, " //9 743 "locale " //10 744 "FROM account " 745 "WHERE username = '%s'", 746 safe_account.c_str ()); 747 748 // Stop if the account is not found 749 if (!result) 750 { 751 packet.Initialize (SMSG_AUTH_RESPONSE, 1); 752 packet << uint8 (AUTH_UNKNOWN_ACCOUNT); 753 754 SendPacket (packet); 755 756 sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (unknown account)."); 757 return -1; 758 } 759 760 Field* fields = result->Fetch (); 761 762 tbc = fields[8].GetUInt8 () && sWorld.getConfig (CONFIG_EXPANSION) > 0; 763 764 N.SetHexStr ("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); 765 g.SetDword (7); 766 I.SetHexStr (fields[5].GetString ()); 767 768 //In case of leading zeros in the I hash, restore them 769 uint8 mDigest[SHA_DIGEST_LENGTH]; 770 memset (mDigest, 0, SHA_DIGEST_LENGTH); 771 772 if (I.GetNumBytes () <= SHA_DIGEST_LENGTH) 773 memcpy (mDigest, I.AsByteArray (), I.GetNumBytes ()); 774 775 std::reverse (mDigest, mDigest + SHA_DIGEST_LENGTH); 776 777 s.SetHexStr (fields[7].GetString ()); 778 sha1.UpdateData (s.AsByteArray (), s.GetNumBytes ()); 779 sha1.UpdateData (mDigest, SHA_DIGEST_LENGTH); 780 sha1.Finalize (); 781 x.SetBinary (sha1.GetDigest (), sha1.GetLength ()); 782 v = g.ModExp (x, N); 783 784 const char* sStr = s.AsHexStr (); //Must be freed by OPENSSL_free() 785 const char* vStr = v.AsHexStr (); //Must be freed by OPENSSL_free() 786 const char* vold = fields[6].GetString (); 787 788 DEBUG_LOG ("WorldSocket::HandleAuthSession: (s,v) check s: %s v_old: %s v_new: %s", 789 sStr, 790 vold, 791 vStr); 792 793 loginDatabase.PExecute ("UPDATE account " 794 "SET " 795 "v = '0', " 796 "s = '0' " 797 "WHERE username = '%s'", 798 safe_account.c_str ()); 799 800 #if defined _NETCODE_FAKE_AUTH 801 if (!dontchechtheacc) 802 { 803 #endif 804 if (!vold || strcmp (vStr, vold)) 805 { 806 packet.Initialize (SMSG_AUTH_RESPONSE, 1); 807 packet << uint8 (AUTH_UNKNOWN_ACCOUNT); 808 SendPacket (packet); 809 delete result; 810 OPENSSL_free ((void*) sStr); 811 OPENSSL_free ((void*) vStr); 812 813 sLog.outError ("WorldSocket::HandleAuthSession: User not logged."); 814 return -1; 815 } 816 #if defined _NETCODE_FAKE_AUTH 817 } 818 #endif 819 820 OPENSSL_free ((void*) sStr); 821 OPENSSL_free ((void*) vStr); 822 823 ///- Re-check ip locking (same check as in realmd). 824 if (fields[4].GetUInt8 () == 1) // if ip is locked 825 { 826 if (strcmp (fields[3].GetString (), GetRemoteAddress ().c_str ())) 827 { 828 packet.Initialize (SMSG_AUTH_RESPONSE, 1); 829 packet << uint8 (AUTH_FAILED); 830 SendPacket (packet); 831 832 delete result; 833 sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs)."); 834 return -1; 835 } 836 } 837 838 id = fields[0].GetUInt32 (); 839 security = fields[1].GetUInt16 (); 840 K.SetHexStr (fields[2].GetString ()); 841 842 time_t mutetime = time_t (fields[9].GetUInt64 ()); 843 844 locale = LocaleConstant (fields[10].GetUInt8 ()); 845 if (locale >= MAX_LOCALE) 846 locale = LOCALE_enUS; 847 848 delete result; 849 850 #if defined _NETCODE_FAKE_AUTH 851 if (!dontchechtheacc) 852 { 853 #endif 854 // Re-check account ban (same check as in realmd) 855 QueryResult *banresult = 856 loginDatabase.PQuery ("SELECT " 857 "bandate, " 858 "unbandate " 859 "FROM account_banned " 860 "WHERE id = '%u' " 861 "AND active = 1", 862 id); 863 864 if (banresult) // if account banned 865 { 866 packet.Initialize (SMSG_AUTH_RESPONSE, 1); 867 packet << uint8 (AUTH_BANNED); 868 SendPacket (packet); 869 870 delete banresult; 871 872 sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (Account banned)."); 873 return -1; 874 } 875 876 // Check locked state for server 877 AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit (); 878 879 if (allowedAccountType > SEC_PLAYER && security < allowedAccountType) 880 { 881 WorldPacket Packet (SMSG_AUTH_RESPONSE, 1); 882 Packet << uint8 (AUTH_UNAVAILABLE); 883 884 SendPacket (packet); 885 886 sLog.outBasic ("WorldSocket::HandleAuthSession: User tryes to login but his security level is not enough"); 887 return -1; 888 } 889 890 // Check that Key and account name are the same on client and server 891 Sha1Hash sha; 892 893 uint32 t = 0; 894 uint32 seed = m_Seed; 895 896 sha.UpdateData (account); 897 sha.UpdateData ((uint8 *) & t, 4); 898 sha.UpdateData ((uint8 *) & clientSeed, 4); 899 sha.UpdateData ((uint8 *) & seed, 4); 900 sha.UpdateBigNumbers (&K, NULL); 901 sha.Finalize (); 902 903 if (memcmp (sha.GetDigest (), digest, 20)) 904 { 905 packet.Initialize (SMSG_AUTH_RESPONSE, 1); 906 packet << uint8 (AUTH_FAILED); 907 908 SendPacket (packet); 909 910 sLog.outError ("WorldSocket::HandleAuthSession: Sent Auth Response (authentification failed)."); 911 return -1; 912 } 913 #if defined _NETCODE_FAKE_AUTH 914 } 915 #endif 916 917 std::string address = this->GetRemoteAddress (); 918 919 DEBUG_LOG ("WorldSocket::HandleAuthSession: Client '%s' authenticated successfully from %s.", 920 account.c_str (), 921 address.c_str ()); 922 923 // Update the last_ip in the database 924 // No SQL injection, username escaped. 925 loginDatabase.escape_string (address); 926 927 loginDatabase.PExecute ("UPDATE account " 928 "SET last_ip = '%s' " 929 "WHERE username = '%s'", 930 address.c_str (), 931 safe_account.c_str ()); 932 933 // TODO protect here probably ? 934 // Althought atm the socket is singlethreaded 935 ACE_NEW_RETURN (m_Session, WorldSession (id, this, security, tbc, mutetime, locale), -1); 936 937 #if defined _NETCODE_FAKE_AUTH 938 if (!dontchechtheacc) 939 { 940 #endif 941 this->m_Crypt.SetKey (&K); 942 this->m_Crypt.Init (); 943 #if defined _NETCODE_FAKE_AUTH 944 } 945 #endif 946 947 // In case needed sometime the second arg is in microseconds 1 000 000 = 1 sec 948 ACE_OS::sleep (ACE_Time_Value (0, 10000)); 949 950 // TODO error handling 951 sWorld.AddSession (this->m_Session); 952 953 // Create and send the Addon packet 954 if (sAddOnHandler.BuildAddonPacket (&recvPacket, &SendAddonPacked)) 955 SendPacket (SendAddonPacked); 956 957 return 0; 958 } 959 960 int 961 WorldSocket::HandlePing (WorldPacket& recvPacket) 962 { 963 uint32 ping; 964 uint32 latency; 965 966 if (recvPacket.size () < 8) 967 { 968 sLog.outError ("WorldSocket::_HandlePing wrong packet size"); 969 return -1; 970 } 971 972 // Get the ping packet content 973 recvPacket >> ping; 974 recvPacket >> latency; 975 976 if (m_LastPingTime == ACE_Time_Value::zero) 977 m_LastPingTime = ACE_OS::gettimeofday (); // for 1st ping 978 else 979 { 980 ACE_Time_Value cur_time = ACE_OS::gettimeofday (); 981 ACE_Time_Value diff_time (cur_time); 982 diff_time -= m_LastPingTime; 983 m_LastPingTime = cur_time; 984 985 if (diff_time < ACE_Time_Value (27)) 986 { 987 ++m_OverSpeedPings; 988 989 uint32 max_count = sWorld.getConfig (CONFIG_MAX_OVERSPEED_PINGS); 990 991 if (max_count && m_OverSpeedPings > max_count) 185 992 { 186 ///- Else, put it in the world session queue for this user (need to be already authenticated) 187 if (_session) 188 _session->QueuePacket(packet); 189 else 190 sLog.outDetail("Received out of place packet with cmdid 0x%.4X", _cmd); 191 break; 993 ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); 994 995 if (m_Session && m_Session->GetSecurity () == SEC_PLAYER) 996 { 997 sLog.outError ("WorldSocket::HandlePing: Player kicked for " 998 "overspeeded pings adress = %s", 999 GetRemoteAddress ().c_str ()); 1000 1001 return -1; 1002 } 192 1003 } 193 1004 } 194 } 195 } 196 197 /// On socket closing 198 void WorldSocket::CloseSocket() 199 { 200 ///- Set CloseAndDelete flag for TcpSocket class 201 SetCloseAndDelete(true); 202 203 ///- Set _session to NULL. Prevent crashes 204 _session = NULL; 205 } 206 207 /// On socket deleting 208 void WorldSocket::OnDelete() 209 { 210 ///- Stop sending remaining data through this socket 211 if (_session) 212 { 213 _session->SetSocket(NULL); 214 // Session deleted from World session list at socket==0, This is only back reference from socket to session. 215 _session = NULL; 216 } 217 218 ///- Remove the socket from the WorldSocketMgr list 219 sWorldSocketMgr.RemoveSocket(this); 220 221 ///- Removes socket from player queue 222 sWorld.RemoveQueuedPlayer(this); 223 } 224 225 /// Handle the client authentication packet 226 void WorldSocket::_HandleAuthSession(WorldPacket& recvPacket) 227 { 228 uint8 digest[20]; 229 uint32 clientSeed; 230 uint32 unk2; 231 uint32 BuiltNumberClient; 232 uint32 id, security; 233 bool tbc = false; 234 std::string account; 235 Sha1Hash sha1; 236 BigNumber v, s, g, N, x, I; 237 WorldPacket packet, SendAddonPacked; 238 239 BigNumber K; 240 241 SOCKET_CHECK_PACKET_SIZE(recvPacket,4+4+1+4+20); 242 243 ///- Read the content of the packet 244 recvPacket >> BuiltNumberClient; // for now no use 245 recvPacket >> unk2; 246 recvPacket >> account; 247 248 // recheck size 249 SOCKET_CHECK_PACKET_SIZE(recvPacket,4+4+(account.size()+1)+4+20); 250 251 recvPacket >> clientSeed; 252 recvPacket.read(digest, 20); 253 254 sLog.outDebug("Auth: client %u, unk2 %u, account %s, clientseed %u", BuiltNumberClient, unk2, account.c_str(), clientSeed); 255 256 ///- Normalize account name 257 //utf8ToUpperOnlyLatin(account); -- client already send account in expected form 258 259 ///- Get the account information from the realmd database 260 std::string safe_account = account; // Duplicate, else will screw the SHA hash verification below 261 loginDatabase.escape_string(safe_account); 262 //No SQL injection, username escaped. 263 // 0 1 2 3 4 5 6 7 8 9 10 264 QueryResult *result = loginDatabase.PQuery("SELECT id, gmlevel, sessionkey, last_ip, locked, sha_pass_hash, v, s, tbc, mutetime, locale FROM account WHERE username = '%s'", safe_account.c_str()); 265 266 ///- Stop if the account is not found 267 if ( !result ) 268 { 269 packet.Initialize( SMSG_AUTH_RESPONSE, 1 ); 270 packet << uint8( AUTH_UNKNOWN_ACCOUNT ); 271 SendPacket( &packet ); 272 sLog.outDetail( "SOCKET: Sent Auth Response (unknown account)." ); 273 return; 274 } 275 276 Field* fields = result->Fetch(); 277 278 tbc = fields[8].GetUInt8() && sWorld.getConfig(CONFIG_EXPANSION) > 0; 279 280 N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"); 281 g.SetDword(7); 282 I.SetHexStr(fields[5].GetString()); 283 284 //In case of leading zeros in the I hash, restore them 285 uint8 mDigest[SHA_DIGEST_LENGTH]; 286 memset(mDigest,0,SHA_DIGEST_LENGTH); 287 if (I.GetNumBytes() <= SHA_DIGEST_LENGTH) 288 memcpy(mDigest,I.AsByteArray(),I.GetNumBytes()); 289 290 std::reverse(mDigest,mDigest+SHA_DIGEST_LENGTH); 291 292 s.SetHexStr(fields[7].GetString()); 293 sha1.UpdateData(s.AsByteArray(), s.GetNumBytes()); 294 sha1.UpdateData(mDigest, SHA_DIGEST_LENGTH); 295 sha1.Finalize(); 296 x.SetBinary(sha1.GetDigest(), sha1.GetLength()); 297 v = g.ModExp(x, N); 298 299 const char* sStr = s.AsHexStr(); //Must be freed by OPENSSL_free() 300 const char* vStr = v.AsHexStr(); //Must be freed by OPENSSL_free() 301 const char* vold = fields[6].GetString(); 302 sLog.outDebug("SOCKET: (s,v) check s: %s v_old: %s v_new: %s", sStr, vold, vStr ); 303 loginDatabase.PExecute("UPDATE account SET v = '0', s = '0' WHERE username = '%s'", safe_account.c_str()); 304 if ( !vold || strcmp( vStr, vold ) ) 305 { 306 packet.Initialize( SMSG_AUTH_RESPONSE, 1 ); 307 packet << uint8( AUTH_UNKNOWN_ACCOUNT ); 308 SendPacket( &packet ); 309 sLog.outDetail( "SOCKET: User not logged."); 310 delete result; 311 OPENSSL_free((void*)sStr); 312 OPENSSL_free((void*)vStr); 313 return; 314 } 315 OPENSSL_free((void*)sStr); 316 OPENSSL_free((void*)vStr); 317 318 ///- Re-check ip locking (same check as in realmd). 319 if(fields[4].GetUInt8() == 1) // if ip is locked 320 { 321 if ( strcmp(fields[3].GetString(),GetRemoteAddress().c_str()) ) 322 { 323 packet.Initialize( SMSG_AUTH_RESPONSE, 1 ); 324 packet << uint8( AUTH_FAILED ); 325 SendPacket( &packet ); 326 327 sLog.outDetail( "SOCKET: Sent Auth Response (Account IP differs)." ); 328 delete result; 329 return; 330 } 331 } 332 333 id = fields[0].GetUInt32(); 334 security = fields[1].GetUInt16(); 335 K.SetHexStr(fields[2].GetString()); 336 time_t mutetime = time_t(fields[9].GetUInt64()); 337 338 LocaleConstant locale = LocaleConstant(fields[10].GetUInt8()); 339 if (locale>=MAX_LOCALE) 340 locale=LOCALE_enUS; 341 342 delete result; 343 344 ///- Re-check account ban (same check as in realmd) /// TO DO: why on earth do 2 checks for same thing? 345 QueryResult *banresult = loginDatabase.PQuery("SELECT bandate,unbandate FROM account_banned WHERE id = '%u' AND active = 1", id); 346 if(banresult) // if account banned 347 { 348 packet.Initialize( SMSG_AUTH_RESPONSE, 1 ); 349 packet << uint8( AUTH_BANNED ); 350 SendPacket( &packet ); 351 352 sLog.outDetail( "SOCKET: Sent Auth Response (Account banned)." ); 353 delete banresult; 354 return; 355 } 356 357 ///- Check locked state for server 358 AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit(); 359 if( allowedAccountType > SEC_PLAYER && security < allowedAccountType) 360 { 361 WorldPacket Packet(SMSG_AUTH_RESPONSE, 1); 362 Packet << uint8(AUTH_UNAVAILABLE); 363 SendPacket(&Packet); 364 return; 365 } 366 367 ///- kick already loaded player with same account (if any) and remove session 368 ///- if player is in loading and want to load again, return 369 if(!sWorld.RemoveSession(id)) 370 { 371 return; 372 } 373 374 ///- Check that Key and account name are the same on client and server 375 Sha1Hash sha; 376 377 uint32 t = 0; 378 uint32 seed = _seed; 379 380 sha.UpdateData(account); 381 sha.UpdateData((uint8 *)&t, 4); 382 sha.UpdateData((uint8 *)&clientSeed, 4); 383 sha.UpdateData((uint8 *)&seed, 4); 384 sha.UpdateBigNumbers(&K, NULL); 385 sha.Finalize(); 386 387 if (memcmp(sha.GetDigest(), digest, 20)) 388 { 389 packet.Initialize( SMSG_AUTH_RESPONSE, 1 ); 390 packet << uint8( AUTH_FAILED ); 391 SendPacket( &packet ); 392 393 sLog.outDetail( "SOCKET: Sent Auth Response (authentication failed)." ); 394 return; 395 } 396 397 ///- Initialize the encryption with the Key 398 _crypt.SetKey(&K); 399 _crypt.Init(); 400 401 ///- Send 'Auth is ok' 402 packet.Initialize( SMSG_AUTH_RESPONSE, 1+4+1+4+1 ); 403 packet << uint8( AUTH_OK ); 404 packet << uint32(0); // unknown random value... 405 packet << uint8(0); // can be 0 and 2 406 packet << uint32(0); // const 0 407 packet << uint8(tbc ? 1 : 0); // 0 - normal, 1 - TBC, must be set in database manually for each account 408 SendPacket(&packet); 409 410 ///- Create a new WorldSession for the player and add it to the World 411 _session = new WorldSession(id, this,security,tbc,mutetime,locale); 412 sWorld.AddSession(_session); 413 414 if(sLog.IsOutDebug()) // optimize disabled debug output 415 { 416 sLog.outDebug( "SOCKET: Client '%s' authenticated successfully.", account.c_str() ); 417 sLog.outDebug( "Account: '%s' Logged in from IP %s.", account.c_str(), GetRemoteAddress().c_str()); 418 } 419 420 ///- Update the last_ip in the database 421 //No SQL injection, username escaped. 422 std::string address = GetRemoteAddress(); 423 loginDatabase.escape_string(address); 424 loginDatabase.PExecute("UPDATE account SET last_ip = '%s' WHERE username = '%s'",address.c_str(), safe_account.c_str()); 425 426 // do small delay (10ms) at accepting successful authed connection to prevent dropping packets by client 427 // don't must harm anyone (let login ~100 accounts in 1 sec ;) ) 428 #ifdef WIN32 429 Sleep(10); 430 #else 431 ZThread::Thread::sleep(10); 432 #endif 433 434 ///- Check that we do not exceed the maximum number of online players in the realm 435 uint32 Sessions = sWorld.GetActiveAndQueuedSessionCount(); 436 uint32 pLimit = sWorld.GetPlayerAmountLimit(); 437 uint32 QueueSize = sWorld.GetQueueSize(); //number of players in the queue 438 bool inQueue = false; 439 --Sessions; //so we don't count the user trying to login as a session and queue the socket that we are using 440 441 if( pLimit > 0 && Sessions >= pLimit && security == SEC_PLAYER ) 442 { 443 sWorld.AddQueuedPlayer(this); 444 SendAuthWaitQue(sWorld.GetQueuePos(this)); 445 sWorld.UpdateMaxSessionCounters(); 446 sLog.outDetail( "PlayerQueue: %s is in Queue Position (%u).",safe_account.c_str(),++QueueSize); 447 inQueue = true; 448 } 449 450 ///- Create and send the Addon packet 451 if(sAddOnHandler.BuildAddonPacket(&recvPacket, &SendAddonPacked)) 452 SendPacket(&SendAddonPacked); 453 454 if(inQueue) 455 return; 456 457 sWorld.UpdateMaxSessionCounters(); 458 459 // Updates the population 460 if (pLimit > 0) 461 { 462 float popu = sWorld.GetActiveSessionCount(); //updated number of users on the server 463 popu /= pLimit; 464 popu *= 2; 465 loginDatabase.PExecute("UPDATE realmlist SET population = '%f' WHERE id = '%d'",popu,realmID); 466 sLog.outDetail( "Server Population (%f).",popu); 467 } 468 469 return; 470 } 471 472 /// Handle the Ping packet 473 void WorldSocket::_HandlePing(WorldPacket& recvPacket) 474 { 475 uint32 ping; 476 uint32 latency; 477 478 CHECK_PACKET_SIZE(recvPacket,8); 479 480 ///- Get the ping packet content 481 recvPacket >> ping; 482 recvPacket >> latency; 483 484 if (_session ) 485 _session->SetLatency(latency); 486 487 ///- check ping speed for players 488 if(_session && _session->GetSecurity() == SEC_PLAYER) 489 { 490 uint32 cur_mstime = getMSTime(); 491 492 // can overflow and start from 0 493 uint32 diff_mstime = getMSTimeDiff(m_LastPingMSTime,cur_mstime); 494 m_LastPingMSTime = cur_mstime; 495 if(diff_mstime < 27000) // should be 30000 (=30 secs), add little tolerance 496 { 497 ++m_OverSpeedPings; 498 499 uint32 max_count = sWorld.getConfig(CONFIG_MAX_OVERSPEED_PINGS); 500 if(max_count && m_OverSpeedPings > max_count) 1005 else 1006 m_OverSpeedPings = 0; 1007 } 1008 1009 // critical section 1010 { 1011 ACE_GUARD_RETURN (LockType, Guard, m_SessionLock, -1); 1012 1013 if (m_Session) 1014 m_Session->SetLatency (latency); 1015 else 1016 { 1017 sLog.outError ("WorldSocket::HandlePing: peer sent CMSG_PING, " 1018 "but is not authenticated or got recently kicked," 1019 " adress = %s", 1020 this->GetRemoteAddress ().c_str ()); 1021 return -1; 1022 } 1023 } 1024 1025 WorldPacket packet (SMSG_PONG, 4); 1026 packet << ping; 1027 return this->SendPacket (packet); 1028 } 1029 1030 int 1031 WorldSocket::iSendPacket (const WorldPacket& pct) 1032 { 1033 if (m_OutBuffer->space () < pct.size () + sizeof (ServerPktHeader)) 1034 { 1035 errno = ENOBUFS; 1036 return -1; 1037 } 1038 1039 ServerPktHeader header; 1040 1041 header.cmd = pct.GetOpcode (); 1042 1043 #if ACE_BYTE_ORDER == ACE_BIG_ENDIAN 1044 header.cmd = ACE_SWAP_WORD (header.cmd) 1045 #endif 1046 1047 header.size = (uint16) pct.size () + 2; 1048 header.size = ACE_HTONS (header.size); 1049 1050 m_Crypt.EncryptSend ((uint8*) & header, sizeof (header)); 1051 1052 if (m_OutBuffer->copy ((char*) & header, sizeof (header)) == -1) 1053 ACE_ASSERT (false); 1054 1055 if (!pct.empty ()) 1056 if (m_OutBuffer->copy ((char*) pct.contents (), pct.size ()) == -1) 1057 ACE_ASSERT (false); 1058 1059 return 0; 1060 } 1061 1062 bool 1063 WorldSocket::iFlushPacketQueue () 1064 { 1065 WorldPacket *pct; 1066 bool haveone = false; 1067 1068 while (m_PacketQueue.dequeue_head (pct) == 0) 1069 { 1070 if (iSendPacket (*pct) == -1) 1071 { 1072 if (m_PacketQueue.enqueue_head (pct) == -1) 501 1073 { 502 sLog.outBasic("Player %s from account id %u kicked for overspeed ping packets from client (non-playable connection lags or cheating) ",_session->GetPlayerName(),_session->GetAccountId());503 _session->KickPlayer();504 return;1074 delete pct; 1075 sLog.outError ("WorldSocket::iFlushPacketQueue m_PacketQueue->enqueue_head"); 1076 return false; 505 1077 } 506 } 507 else 508 m_OverSpeedPings = 0; 509 510 } 511 512 ///- And put the pong answer in the to-be-sent queue 513 WorldPacket packet( SMSG_PONG, 4 ); 514 packet << ping; 515 SendPacket(&packet); 516 517 return; 518 } 519 520 /// Handle the update order for the socket 521 void WorldSocket::SendSinglePacket() 522 { 523 WorldPacket *packet; 524 ServerPktHeader hdr; 525 526 ///- If we have packet to send 527 if (!_sendQueue.empty()) 528 { 529 packet = _sendQueue.next(); 530 531 hdr.size = ntohs((uint16)packet->size() + 2); 532 hdr.cmd = packet->GetOpcode(); 533 534 if( sWorldLog.LogWorld() ) 535 { 536 sWorldLog.Log("SERVER:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", 537 (uint32)GetSocket(), 538 packet->size(), 539 LookupOpcodeName(packet->GetOpcode()), 540 packet->GetOpcode()); 541 542 uint32 p = 0; 543 while (p < packet->size()) 544 { 545 for (uint32 j = 0; j < 16 && p < packet->size(); j++) 546 sWorldLog.Log("%.2X ", (*packet)[p++]); 547 548 sWorldLog.Log("\n"); 549 } 550 551 sWorldLog.Log("\n\n"); 552 } 553 554 ///- Encrypt (if needed) the header 555 _crypt.EncryptSend((uint8*)&hdr, 4); 556 557 ///- Send the header and body to the client 558 TcpSocket::SendBuf((char*)&hdr, 4); 559 if(!packet->empty()) TcpSocket::SendBuf((char*)packet->contents(), packet->size()); 560 561 delete packet; 562 } 563 } 564 565 void WorldSocket::Update(time_t diff) 566 { 567 const uint32 SEND_PACKETS_MAX = 100; 568 const uint32 SEND_BUFFER_SIZE = 1024; 569 570 uint8 sendBuffer[SEND_BUFFER_SIZE]; 571 572 while (!_sendQueue.empty()) 573 { 574 bool haveBigPacket = false; 575 uint32 bufferSize = 0; 576 577 ///- While we have packets to send 578 for (uint32 packetCount = 0; (packetCount < SEND_PACKETS_MAX) && !_sendQueue.empty(); packetCount++) 579 { 580 ServerPktHeader *hdr = (ServerPktHeader*)&sendBuffer[bufferSize]; 581 582 // check merge possibility. 583 WorldPacket *front = _sendQueue.front(); 584 uint32 packetSize = front->size(); 585 586 if ((sizeof(*hdr) + packetSize) > SEND_BUFFER_SIZE) 587 { 588 haveBigPacket = true; 589 break; 590 } 591 592 if ((bufferSize + sizeof(*hdr) + packetSize) > sizeof(sendBuffer)) 593 break; 594 595 // can be merged 596 WorldPacket *packet = _sendQueue.next(); 597 598 hdr->size = ntohs((uint16)packetSize + 2); 599 hdr->cmd = packet->GetOpcode(); 600 601 if( sWorldLog.LogWorld() ) 602 { 603 sWorldLog.Log("SERVER:\nSOCKET: %u\nLENGTH: %u\nOPCODE: %s (0x%.4X)\nDATA:\n", 604 (uint32)GetSocket(), 605 packetSize, 606 LookupOpcodeName(packet->GetOpcode()), 607 packet->GetOpcode()); 608 609 uint32 p = 0; 610 while (p < packetSize) 611 { 612 for (uint32 j = 0; j < 16 && p < packetSize; j++) 613 sWorldLog.Log("%.2X ", (*packet)[p++]); 614 615 sWorldLog.Log("\n"); 616 } 617 618 sWorldLog.Log("\n\n"); 619 } 620 621 ///- Encrypt (if needed) the header 622 _crypt.EncryptSend((uint8*)hdr, sizeof(*hdr)); 623 bufferSize += sizeof(*hdr); 624 625 if (packetSize) 626 { 627 memcpy(&sendBuffer[bufferSize], packet->contents(), packetSize); 628 bufferSize += packetSize; 629 } 630 631 ///- Send the header and body to the client 632 delete packet; 633 } 634 635 // send merged packets 636 if (bufferSize) TcpSocket::SendBuf((char*)sendBuffer, bufferSize); 637 // send too big non-merged packet 638 if (haveBigPacket) SendSinglePacket(); 639 } 640 } 641 642 /// Handle the authentication waiting queue (to be completed) 643 void WorldSocket::SendAuthWaitQue(uint32 position) 644 { 645 if(position == 0) 646 { 647 WorldPacket packet( SMSG_AUTH_RESPONSE, 1 ); 648 packet << uint8( AUTH_OK ); 649 SendPacket(&packet); 650 } 651 else 652 { 653 WorldPacket packet( SMSG_AUTH_RESPONSE, 5 ); 654 packet << uint8( AUTH_WAIT_QUEUE ); 655 packet << uint32 (position); //amount of players in queue 656 SendPacket(&packet); 657 } 658 } 659 660 void WorldSocket::SizeError(WorldPacket const& packet, uint32 size) const 661 { 662 sLog.outError("Client send packet %s (%u) with size %u but expected %u (attempt crash server?), skipped", 663 LookupOpcodeName(packet.GetOpcode()),packet.GetOpcode(),packet.size(),size); 664 } 1078 1079 break; 1080 } 1081 else 1082 { 1083 haveone = true; 1084 delete pct; 1085 } 1086 } 1087 1088 return haveone; 1089 } -
trunk/src/game/WorldSocket.h
r2 r6 1 /* 1 /* 2 2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/> 3 3 * … … 17 17 */ 18 18 19 /// \addtogroup u2w 20 /// @{ 21 /// \file 22 23 #ifndef __WORLDSOCKET_H 24 #define __WORLDSOCKET_H 25 26 #include "sockets/TcpSocket.h" 27 #include "Auth/AuthCrypt.h" 28 29 enum ResponseCodes 19 /** \addtogroup u2w User to World Communication 20 * @{ 21 * \file WorldSocket.h 22 * \author Derex <derex101@gmail.com> 23 */ 24 25 #ifndef _WORLDSOCKET_H 26 #define _WORLDSOCKET_H 27 28 #include <ace/Basic_Types.h> 29 #include <ace/Synch_Traits.h> 30 #include <ace/Svc_Handler.h> 31 #include <ace/SOCK_Stream.h> 32 #include <ace/SOCK_Acceptor.h> 33 #include <ace/Acceptor.h> 34 #include <ace/Thread_Mutex.h> 35 #include <ace/Guard_T.h> 36 #include <ace/Unbounded_Queue.h> 37 #include <ace/Message_Block.h> 38 39 #if !defined (ACE_LACKS_PRAGMA_ONCE) 40 #pragma once 41 #endif /* ACE_LACKS_PRAGMA_ONCE */ 42 43 #include "Common.h" 44 #include "Auth/AuthCrypt.h" 45 46 class ACE_Message_Block; 47 class WorldPacket; 48 class WorldSession; 49 50 /// Handler that can communicate over stream sockets. 51 typedef ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH> WorldHandler; 52 53 /** 54 * WorldSocket. 55 * 56 * This class is responsible for the comunication with 57 * remote clients. 58 * Most methods return -1 on failure. 59 * The class uses refferece counting. 60 * 61 * For output the class uses one buffer (64K usually) and 62 * a queue where it stores packet if there is no place on 63 * the queue. The reason this is done, is because the server 64 * does realy a lot of small-size writes to it, and it doesn't 65 * scale well to allocate memory for every. When something is 66 * writen to the output buffer the socket is not immideately 67 * activated for output (again for the same reason), there 68 * is 10ms celling (thats why there is Update() method). 69 * This concept is simmilar to TCP_CORK, but TCP_CORK 70 * usses 200ms celling. As result overhead generated by 71 * sending packets from "producer" threads is minimal, 72 * and doing a lot of writes with small size is tollerated. 73 * 74 * The calls to Upate () method are managed by WorldSocketMgr 75 * and ReactorRunnable. 76 * 77 * For input ,the class uses one 1024 bytes buffer on stack 78 * to which it does recv() calls. And then recieved data is 79 * distributed where its needed. 1024 matches pritey well the 80 * traffic generated by client for now. 81 * 82 * The input/output do speculative reads/writes (AKA it tryes 83 * to read all data avaible in the kernel buffer or tryes to 84 * write everything avaible in userspace buffer), 85 * which is ok for using with Level and Edge Trigered IO 86 * notification. 87 * 88 */ 89 class WorldSocket : protected WorldHandler 30 90 { 31 RESPONSE_SUCCESS = 0x00, 32 RESPONSE_FAILURE = 0x01, 33 RESPONSE_CANCELLED = 0x02, 34 RESPONSE_DISCONNECTED = 0x03, 35 RESPONSE_FAILED_TO_CONNECT = 0x04, 36 RESPONSE_CONNECTED = 0x05, 37 RESPONSE_VERSION_MISMATCH = 0x06, 38 39 CSTATUS_CONNECTING = 0x07, 40 CSTATUS_NEGOTIATING_SECURITY = 0x08, 41 CSTATUS_NEGOTIATION_COMPLETE = 0x09, 42 CSTATUS_NEGOTIATION_FAILED = 0x0A, 43 CSTATUS_AUTHENTICATING = 0x0B, 44 45 AUTH_OK = 0x0C, 46 AUTH_FAILED = 0x0D, 47 AUTH_REJECT = 0x0E, 48 AUTH_BAD_SERVER_PROOF = 0x0F, 49 AUTH_UNAVAILABLE = 0x10, 50 AUTH_SYSTEM_ERROR = 0x11, 51 AUTH_BILLING_ERROR = 0x12, 52 AUTH_BILLING_EXPIRED = 0x13, 53 AUTH_VERSION_MISMATCH = 0x14, 54 AUTH_UNKNOWN_ACCOUNT = 0x15, 55 AUTH_INCORRECT_PASSWORD = 0x16, 56 AUTH_SESSION_EXPIRED = 0x17, 57 AUTH_SERVER_SHUTTING_DOWN = 0x18, 58 AUTH_ALREADY_LOGGING_IN = 0x19, 59 AUTH_LOGIN_SERVER_NOT_FOUND = 0x1A, 60 AUTH_WAIT_QUEUE = 0x1B, 61 AUTH_BANNED = 0x1C, 62 AUTH_ALREADY_ONLINE = 0x1D, 63 AUTH_NO_TIME = 0x1E, 64 AUTH_DB_BUSY = 0x1F, 65 AUTH_SUSPENDED = 0x20, 66 AUTH_PARENTAL_CONTROL = 0x21, 67 AUTH_LOCKED_ENFORCED = 0x22, 68 69 REALM_LIST_IN_PROGRESS = 0x23, 70 REALM_LIST_SUCCESS = 0x24, 71 REALM_LIST_FAILED = 0x25, 72 REALM_LIST_INVALID = 0x26, 73 REALM_LIST_REALM_NOT_FOUND = 0x27, 74 75 ACCOUNT_CREATE_IN_PROGRESS = 0x28, 76 ACCOUNT_CREATE_SUCCESS = 0x29, 77 ACCOUNT_CREATE_FAILED = 0x2A, 78 79 CHAR_LIST_RETRIEVING = 0x2B, 80 CHAR_LIST_RETRIEVED = 0x2C, 81 CHAR_LIST_FAILED = 0x2D, 82 83 CHAR_CREATE_IN_PROGRESS = 0x2E, 84 CHAR_CREATE_SUCCESS = 0x2F, 85 CHAR_CREATE_ERROR = 0x30, 86 CHAR_CREATE_FAILED = 0x31, 87 CHAR_CREATE_NAME_IN_USE = 0x32, 88 CHAR_CREATE_DISABLED = 0x33, 89 CHAR_CREATE_PVP_TEAMS_VIOLATION = 0x34, 90 CHAR_CREATE_SERVER_LIMIT = 0x35, 91 CHAR_CREATE_ACCOUNT_LIMIT = 0x36, 92 CHAR_CREATE_SERVER_QUEUE = 0x37, 93 CHAR_CREATE_ONLY_EXISTING = 0x38, 94 CHAR_CREATE_EXPANSION = 0x39, 95 96 CHAR_DELETE_IN_PROGRESS = 0x3A, 97 CHAR_DELETE_SUCCESS = 0x3B, 98 CHAR_DELETE_FAILED = 0x3C, 99 CHAR_DELETE_FAILED_LOCKED_FOR_TRANSFER = 0x3D, 100 CHAR_DELETE_FAILED_GUILD_LEADER = 0x3E, 101 CHAR_DELETE_FAILED_ARENA_CAPTAIN = 0x3F, 102 103 CHAR_LOGIN_IN_PROGRESS = 0x40, 104 CHAR_LOGIN_SUCCESS = 0x41, 105 CHAR_LOGIN_NO_WORLD = 0x42, 106 CHAR_LOGIN_DUPLICATE_CHARACTER = 0x43, 107 CHAR_LOGIN_NO_INSTANCES = 0x44, 108 CHAR_LOGIN_FAILED = 0x45, 109 CHAR_LOGIN_DISABLED = 0x46, 110 CHAR_LOGIN_NO_CHARACTER = 0x47, 111 CHAR_LOGIN_LOCKED_FOR_TRANSFER = 0x48, 112 CHAR_LOGIN_LOCKED_BY_BILLING = 0x49, 113 114 CHAR_NAME_SUCCESS = 0x4A, 115 CHAR_NAME_FAILURE = 0x4B, 116 CHAR_NAME_NO_NAME = 0x4C, 117 CHAR_NAME_TOO_SHORT = 0x4D, 118 CHAR_NAME_TOO_LONG = 0x4E, 119 CHAR_NAME_INVALID_CHARACTER = 0x4F, 120 CHAR_NAME_MIXED_LANGUAGES = 0x50, 121 CHAR_NAME_PROFANE = 0x51, 122 CHAR_NAME_RESERVED = 0x52, 123 CHAR_NAME_INVALID_APOSTROPHE = 0x53, 124 CHAR_NAME_MULTIPLE_APOSTROPHES = 0x54, 125 CHAR_NAME_THREE_CONSECUTIVE = 0x55, 126 CHAR_NAME_INVALID_SPACE = 0x56, 127 CHAR_NAME_CONSECUTIVE_SPACES = 0x57, 128 CHAR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS = 0x58, 129 CHAR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END = 0x59, 130 CHAR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = 0x5A, 91 public: 92 /// Declare some friends 93 friend class ACE_Acceptor< WorldSocket, ACE_SOCK_ACCEPTOR >; 94 friend class WorldSocketMgr; 95 friend class ReactorRunnable; 96 97 /// Declare the acceptor for this class 98 typedef ACE_Acceptor< WorldSocket, ACE_SOCK_ACCEPTOR > Acceptor; 99 100 /// Mutex type used for various syncronizations. 101 typedef ACE_Thread_Mutex LockType; 102 typedef ACE_Guard<LockType> GuardType; 103 104 /// Queue for storing packets for which there is no space. 105 typedef ACE_Unbounded_Queue< WorldPacket* > PacketQueueT; 106 107 /// Check if socket is closed. 108 bool IsClosed (void) const; 109 110 /// Close the socket. 111 void CloseSocket (void); 112 113 /// Get address of connected peer. 114 const std::string& GetRemoteAddress (void) const; 115 116 /// Send A packet on the socket, this function is reentrant. 117 /// @param pct packet to send 118 /// @return -1 of failure 119 int SendPacket (const WorldPacket& pct); 120 121 /// Add refference to this object. 122 long AddReference (void); 123 124 /// Remove refference to this object. 125 long RemoveReference (void); 126 127 protected: 128 /// things called by ACE framework. 129 WorldSocket (void); 130 virtual ~WorldSocket (void); 131 132 /// Called on open ,the void* is the acceptor. 133 virtual int open (void *); 134 135 /// Called on failures inside of the acceptor, don't call from your code. 136 virtual int close (int); 137 138 /// Called when we can read from the socket. 139 virtual int handle_input (ACE_HANDLE = ACE_INVALID_HANDLE); 140 141 /// Called when the socket can write. 142 virtual int handle_output (ACE_HANDLE = ACE_INVALID_HANDLE); 143 144 /// Called when connection is closed or error happens. 145 virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE, 146 ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK); 147 148 /// Called by WorldSocketMgr/ReactorRunnable. 149 int Update (void); 150 151 private: 152 /// Helper functions for processing incoming data. 153 int handle_input_header (void); 154 int handle_input_payload (void); 155 int handle_input_missing_data (void); 156 157 /// Help functions to mark/unmark the socket for output. 158 /// @param g the guard is for m_OutBufferLock, the function will release it 159 int cancel_wakeup_output (GuardType& g); 160 int schedule_wakeup_output (GuardType& g); 161 162 /// process one incoming packet. 163 /// @param new_pct received packet ,note that you need to delete it. 164 int ProcessIncoming (WorldPacket* new_pct); 165 166 /// Called by ProcessIncoming() on CMSG_AUTH_SESSION. 167 int HandleAuthSession (WorldPacket& recvPacket); 168 169 /// Called by ProcessIncoming() on CMSG_PING. 170 int HandlePing (WorldPacket& recvPacket); 171 172 /// Try to write WorldPacket to m_OutBuffer ,return -1 if no space 173 /// Need to be called with m_OutBufferLock lock held 174 int iSendPacket (const WorldPacket& pct); 175 176 /// Flush m_PacketQueue if there are packets in it 177 /// Need to be called with m_OutBufferLock lock held 178 /// @return true if it wrote to the buffer ( AKA you need 179 /// to mark the socket for output ). 180 bool iFlushPacketQueue (); 181 182 private: 183 /// Time in which the last ping was received 184 ACE_Time_Value m_LastPingTime; 185 186 /// Keep track of overspeed pings ,to prevent ping flood. 187 uint32 m_OverSpeedPings; 188 189 /// Address of the remote peer 190 std::string m_Address; 191 192 /// Class used for managing encryption of the headers 193 AuthCrypt m_Crypt; 194 195 /// Mutex lock to protect m_Session 196 LockType m_SessionLock; 197 198 /// Session to which recieved packets are routed 199 WorldSession* m_Session; 200 201 /// here are stored the fragmens of the recieved data 202 WorldPacket* m_RecvWPct; 203 204 /// This block actually refers to m_RecvWPct contents, 205 /// which alows easy and safe writing to it. 206 /// It wont free memory when its deleted. m_RecvWPct takes care of freeing. 207 ACE_Message_Block m_RecvPct; 208 209 /// Fragment of the recieved header. 210 ACE_Message_Block m_Header; 211 212 /// Mutex for protecting otuput related data. 213 LockType m_OutBufferLock; 214 215 /// Buffer used for writing output. 216 ACE_Message_Block *m_OutBuffer; 217 218 /// Size of the m_OutBuffer. 219 size_t m_OutBufferSize; 220 221 /// Here are stored packets for which there was no space on m_OutBuffer, 222 /// this alows not-to kick player if its buffer is overflowed. 223 PacketQueueT m_PacketQueue; 224 225 /// True if the socket is registered with the reactor for output 226 bool m_OutActive; 227 228 uint32 m_Seed; 131 229 }; 132 230 133 class WorldPacket; 134 class SocketHandler; 135 class WorldSession; 136 137 /// Handle connection with the client software 138 class WorldSocket : public TcpSocket 139 { 140 public: 141 WorldSocket(ISocketHandler&); 142 ~WorldSocket(); 143 144 void SendPacket(WorldPacket const* packet); 145 void CloseSocket(); 146 147 void OnAccept(); 148 void OnRead(); 149 void OnDelete(); 150 151 void Update(time_t diff); 152 // Player Queue 153 void SendAuthWaitQue(uint32 position); 154 155 WorldSession* GetSession() const { return _session; } 156 protected: 157 void SendSinglePacket(); 158 159 protected: 160 void _HandleAuthSession(WorldPacket& recvPacket); 161 void _HandlePing(WorldPacket& recvPacket); 162 163 private: 164 AuthCrypt _crypt; 165 uint32 _seed; 166 uint32 _cmd; 167 uint16 _remaining; 168 WorldSession* _session; 169 170 ZThread::LockedQueue<WorldPacket*,ZThread::FastMutex> _sendQueue; 171 172 uint32 m_LastPingMSTime; 173 uint32 m_OverSpeedPings; 174 175 // internal checks 176 void SizeError(WorldPacket const& packet, uint32 size) const; 177 }; 178 #endif 231 #endif /* _WORLDSOCKET_H */ 232 179 233 /// @} -
trunk/src/game/WorldSocketMgr.cpp
r2 r6 17 17 */ 18 18 19 /** \file 20 \ingroup u2w 21 */ 22 19 /** \file WorldSocketMgr.cpp 20 * \ingroup u2w 21 * \author Derex <derex101@gmail.com> 22 */ 23 24 #include "WorldSocketMgr.h" 25 26 #include <ace/ACE.h> 27 #include <ace/Log_Msg.h> 28 #include <ace/Reactor.h> 29 #include <ace/Reactor_Impl.h> 30 #include <ace/TP_Reactor.h> 31 #include <ace/Dev_Poll_Reactor.h> 32 #include <ace/Guard_T.h> 33 #include <ace/Atomic_Op.h> 34 #include <ace/os_include/arpa/os_inet.h> 35 #include <ace/os_include/netinet/os_tcp.h> 36 #include <ace/os_include/sys/os_types.h> 37 #include <ace/os_include/sys/os_socket.h> 38 39 #include <set> 40 41 #include "Log.h" 23 42 #include "Common.h" 43 #include "Config/ConfigEnv.h" 44 #include "Database/DatabaseEnv.h" 24 45 #include "WorldSocket.h" 25 #include "WorldSocketMgr.h" 26 #include "Policies/SingletonImp.h" 27 28 INSTANTIATE_SINGLETON_1( WorldSocketMgr ); 29 30 /// WorldSocketMgr constructor 31 WorldSocketMgr::WorldSocketMgr() 32 { 33 } 34 35 /// Add a WorldSocket to the set 36 void WorldSocketMgr::AddSocket(WorldSocket *s) 37 { 38 m_sockets.insert(s); 39 } 40 41 /// Remove a WorldSocket to the set 42 void WorldSocketMgr::RemoveSocket(WorldSocket *s) 43 { 44 m_sockets.erase(s); 45 } 46 47 /// Triggers an 'update' to all sockets in the set 48 void WorldSocketMgr::Update(time_t diff) 49 { 50 SocketSet::iterator i; 51 for(i = m_sockets.begin(); i != m_sockets.end(); i++) 52 { 53 (*i)->Update(diff); 54 } 55 } 46 47 /** 48 * This is a helper class to WorldSocketMgr ,that manages 49 * network threads, and assigning connections from acceptor thread 50 * to other network threads 51 */ 52 class ReactorRunnable : protected ACE_Task_Base 53 { 54 public: 55 56 ReactorRunnable () : 57 m_ThreadId (-1), 58 m_Connections (0), 59 m_Reactor (0) 60 { 61 ACE_Reactor_Impl* imp = 0; 62 63 #if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL) 64 imp = new ACE_Dev_Poll_Reactor (); 65 66 imp->max_notify_iterations (128); 67 imp->restart (1); 68 #else 69 imp = new ACE_TP_Reactor (); 70 imp->max_notify_iterations (128); 71 #endif 72 73 m_Reactor = new ACE_Reactor (imp, 1); 74 } 75 76 virtual 77 ~ReactorRunnable () 78 { 79 this->Stop (); 80 this->Wait (); 81 82 if (m_Reactor) 83 delete m_Reactor; 84 } 85 86 void 87 Stop () 88 { 89 m_Reactor->end_reactor_event_loop (); 90 } 91 92 int 93 Start () 94 { 95 if (m_ThreadId != -1) 96 return -1; 97 98 return (m_ThreadId = this->activate ()); 99 } 100 101 void 102 Wait () 103 { 104 ACE_Task_Base::wait (); 105 } 106 107 long 108 Connections () 109 { 110 return static_cast<long> (m_Connections.value ()); 111 } 112 113 int 114 AddSocket (WorldSocket* sock) 115 { 116 ACE_GUARD_RETURN (ACE_Thread_Mutex, Guard, m_NewSockets_Lock, -1); 117 118 ++m_Connections; 119 sock->AddReference(); 120 sock->reactor (m_Reactor); 121 m_NewSockets.insert (sock); 122 123 return 0; 124 } 125 126 ACE_Reactor* GetReactor () 127 { 128 return m_Reactor; 129 } 130 131 protected: 132 133 void 134 AddNewSockets () 135 { 136 ACE_GUARD (ACE_Thread_Mutex, Guard, m_NewSockets_Lock); 137 138 if (m_NewSockets.empty ()) 139 return; 140 141 for (SocketSet::iterator i = m_NewSockets.begin (); i != m_NewSockets.end (); ++i) 142 { 143 WorldSocket* sock = (*i); 144 145 if (sock->IsClosed ()) 146 { 147 sock->RemoveReference (); 148 --m_Connections; 149 } 150 else 151 m_Sockets.insert (sock); 152 } 153 154 m_NewSockets.clear (); 155 } 156 157 virtual int 158 svc (void) 159 { 160 DEBUG_LOG ("Network Thread Starting"); 161 162 WorldDatabase.ThreadStart (); 163 164 ACE_ASSERT (m_Reactor); 165 166 SocketSet::iterator i, t; 167 168 while (!m_Reactor->reactor_event_loop_done ()) 169 { 170 // dont be too smart to move this outside the loop 171 // the run_reactor_event_loop will modify interval 172 ACE_Time_Value interval (0, 10000); 173 174 if (m_Reactor->run_reactor_event_loop (interval) == -1) 175 break; 176 177 AddNewSockets (); 178 179 for (i = m_Sockets.begin (); i != m_Sockets.end ();) 180 { 181 if ((*i)->Update () == -1) 182 { 183 t = i; 184 i++; 185 (*t)->CloseSocket (); 186 (*t)->RemoveReference (); 187 --m_Connections; 188 m_Sockets.erase (t); 189 } 190 else 191 i++; 192 } 193 } 194 195 WorldDatabase.ThreadEnd (); 196 197 DEBUG_LOG ("Network Thread Exitting"); 198 199 return 0; 200 } 201 202 private: 203 typedef ACE_Atomic_Op<ACE_SYNCH_MUTEX, long> AtomicInt; 204 typedef std::set<WorldSocket*> SocketSet; 205 206 ACE_Reactor* m_Reactor; 207 AtomicInt m_Connections; 208 int m_ThreadId; 209 210 SocketSet m_Sockets; 211 212 SocketSet m_NewSockets; 213 ACE_Thread_Mutex m_NewSockets_Lock; 214 }; 215 216 217 218 WorldSocketMgr::WorldSocketMgr () : 219 m_NetThreadsCount (0), 220 m_NetThreads (0), 221 m_SockOutKBuff (-1), 222 m_SockOutUBuff (65536), 223 m_UseNoDelay (true), 224 m_Acceptor (0) {} 225 226 WorldSocketMgr::~WorldSocketMgr () 227 { 228 if (m_NetThreads) 229 delete [] m_NetThreads; 230 231 if(m_Acceptor) 232 delete m_Acceptor; 233 } 234 235 int 236 WorldSocketMgr::StartReactiveIO (ACE_UINT16 port, const char* address) 237 { 238 m_UseNoDelay = sConfig.GetBoolDefault ("Network.TcpNodelay", true); 239 240 int num_threads = sConfig.GetIntDefault ("Network.Threads", 1); 241 242 if (num_threads <= 0) 243 { 244 sLog.outError ("Network.Threads is wrong in your config file"); 245 return -1; 246 } 247 248 m_NetThreadsCount = static_cast<size_t> (num_threads + 1); 249 250 m_NetThreads = new ReactorRunnable[m_NetThreadsCount]; 251 252 sLog.outBasic ("Max alowed socket connections %d",ACE::max_handles ()); 253 254 m_SockOutKBuff = sConfig.GetIntDefault ("Network.OutKBuff", -1); // -1 means use default 255 256 m_SockOutUBuff = sConfig.GetIntDefault ("Network.OutUBuff", 65536); 257 258 if ( m_SockOutUBuff <= 0 ) 259 { 260 sLog.outError ("Network.OutUBuff is wrong in your config file"); 261 return -1; 262 } 263 264 WorldSocket::Acceptor *acc = new WorldSocket::Acceptor; 265 m_Acceptor = acc; 266 267 ACE_INET_Addr listen_addr (port, address); 268 269 if (acc->open (listen_addr, m_NetThreads[0].GetReactor (), ACE_NONBLOCK) == -1) 270 { 271 sLog.outError ("Failed to open acceptor ,check if the port is free"); 272 return -1; 273 } 274 275 for (size_t i = 0; i < m_NetThreadsCount; ++i) 276 m_NetThreads[i].Start (); 277 278 return 0; 279 } 280 281 int 282 WorldSocketMgr::StartNetwork (ACE_UINT16 port, const char* address) 283 { 284 if (!sLog.IsOutDebug ()) 285 ACE_Log_Msg::instance ()->priority_mask (LM_ERROR, ACE_Log_Msg::PROCESS); 286 287 if (this->StartReactiveIO (port, address) == -1) 288 return -1; 289 290 return 0; 291 } 292 293 void 294 WorldSocketMgr::StopNetwork () 295 { 296 if (m_Acceptor) 297 { 298 WorldSocket::Acceptor* acc = dynamic_cast<WorldSocket::Acceptor*> (m_Acceptor); 299 300 if (acc) 301 acc->close (); 302 } 303 304 if (m_NetThreadsCount != 0) 305 { 306 for (size_t i = 0; i < m_NetThreadsCount; ++i) 307 m_NetThreads[i].Stop (); 308 } 309 310 this->Wait (); 311 } 312 313 void 314 WorldSocketMgr::Wait () 315 { 316 if (m_NetThreadsCount != 0) 317 { 318 for (size_t i = 0; i < m_NetThreadsCount; ++i) 319 m_NetThreads[i].Wait (); 320 } 321 } 322 323 int 324 WorldSocketMgr::OnSocketOpen (WorldSocket* sock) 325 { 326 // set some options here 327 if (m_SockOutKBuff >= 0) 328 if (sock->peer ().set_option (SOL_SOCKET, 329 SO_SNDBUF, 330 (void*) & m_SockOutKBuff, 331 sizeof (int)) == -1 && errno != ENOTSUP) 332 { 333 sLog.outError ("WorldSocketMgr::OnSocketOpen set_option SO_SNDBUF"); 334 return -1; 335 } 336 337 static const int ndoption = 1; 338 339 // Set TCP_NODELAY. 340 if (m_UseNoDelay) 341 if (sock->peer ().set_option (ACE_IPPROTO_TCP, 342 TCP_NODELAY, 343 (void*) & ndoption, 344 sizeof (int)) == -1) 345 { 346 sLog.outError ("WorldSocketMgr::OnSocketOpen: peer ().set_option TCP_NODELAY errno = %s", ACE_OS::strerror (errno)); 347 return -1; 348 } 349 350 sock->m_OutBufferSize = static_cast<size_t> (m_SockOutUBuff); 351 352 // we skip the Acceptor Thread 353 size_t min = 1; 354 355 ACE_ASSERT (m_NetThreadsCount >= 1); 356 357 for (size_t i = 1; i < m_NetThreadsCount; ++i) 358 if (m_NetThreads[i].Connections () < m_NetThreads[min].Connections ()) 359 min = i; 360 361 return m_NetThreads[min].AddSocket (sock); 362 363 return 0; 364 } 365 366 WorldSocketMgr* 367 WorldSocketMgr::Instance () 368 { 369 return ACE_Singleton<WorldSocketMgr,ACE_Thread_Mutex>::instance(); 370 } -
trunk/src/game/WorldSocketMgr.h
r2 r6 17 17 */ 18 18 19 /// \addtogroup u2w User to World Communication 20 /// @{ 21 /// \file 19 /** \addtogroup u2w User to World Communication 20 * @{ 21 * \file WorldSocketMgr.h 22 * \author Derex <derex101@gmail.com> 23 */ 22 24 23 25 #ifndef __WORLDSOCKETMGR_H 24 26 #define __WORLDSOCKETMGR_H 25 27 26 #include "Policies/Singleton.h" 28 #include <ace/Basic_Types.h> 29 #include <ace/Singleton.h> 30 #include <ace/Thread_Mutex.h> 27 31 28 32 class WorldSocket; 33 class ReactorRunnable; 34 class ACE_Event_Handler; 29 35 30 /// Manages the list of connected WorldSockets31 class WorldSocketMgr 36 /// Manages all sockets connected to peers and network threads 37 class WorldSocketMgr 32 38 { 33 public: 34 WorldSocketMgr(); 39 public: 40 friend class WorldSocket; 41 friend class ACE_Singleton<WorldSocketMgr,ACE_Thread_Mutex>; 35 42 36 void AddSocket(WorldSocket *s); 37 void RemoveSocket(WorldSocket *s); 38 void Update(time_t diff); 39 40 private: 41 typedef std::set<WorldSocket*> SocketSet; 42 SocketSet m_sockets; 43 /// Start network, listen at address:port . 44 int StartNetwork (ACE_UINT16 port, const char* address); 45 46 /// Stops all network threads, It will wait for all running threads . 47 void StopNetwork (); 48 49 /// Wait untill all network threads have "joined" . 50 void Wait (); 51 52 /// Make this class singleton . 53 static WorldSocketMgr* Instance (); 54 55 private: 56 int OnSocketOpen(WorldSocket* sock); 57 58 int StartReactiveIO(ACE_UINT16 port, const char* address); 59 60 private: 61 WorldSocketMgr (); 62 virtual ~WorldSocketMgr (); 63 64 ReactorRunnable* m_NetThreads; 65 size_t m_NetThreadsCount; 66 67 int m_SockOutKBuff; 68 int m_SockOutUBuff; 69 bool m_UseNoDelay; 70 71 ACE_Event_Handler* m_Acceptor; 43 72 }; 44 73 45 #define sWorldSocketMgr MaNGOS::Singleton<WorldSocketMgr>::Instance() 74 #define sWorldSocketMgr WorldSocketMgr::Instance () 75 46 76 #endif 47 77 /// @}