diff --git a/src/Client/DefScriptInterface.cpp b/src/Client/DefScriptInterface.cpp index 033b4ed..8179fb8 100644 --- a/src/Client/DefScriptInterface.cpp +++ b/src/Client/DefScriptInterface.cpp @@ -98,19 +98,24 @@ DefReturnResult DefScriptPackage::SCSendChatMessage(CmdSet& Set){ DefReturnResult DefScriptPackage::SCsavecache(CmdSet& Set){ ((PseuInstance*)parentMethod)->SaveAllCache(); - std::stringstream str; - if(((PseuInstance*)parentMethod)->GetWSession()) - { - str << "Cache saved. [ "; - str << ((PseuInstance*)parentMethod)->GetWSession()->plrNameCache.GetSize(); - str << " Playernames, "; - str << ((PseuInstance*)parentMethod)->GetWSession()->objmgr.GetItemProtoCount(); - str << " Item Prototypes"; - str << " ]"; + if(DefScriptTools::isTrue(Set.defaultarg)) + { + std::stringstream str; + if(((PseuInstance*)parentMethod)->GetWSession()) + { + str << "Cache saved. [ "; + str << ((PseuInstance*)parentMethod)->GetWSession()->plrNameCache.GetSize(); + str << " Playernames, "; + str << ((PseuInstance*)parentMethod)->GetWSession()->objmgr.GetItemProtoCount(); + str << " Item Prototypes, "; + str << ((PseuInstance*)parentMethod)->GetWSession()->objmgr.GetCreatureTemplateCount(); + str << " Creature Templates"; + str << " ]"; - ((PseuInstance*)parentMethod)->GetWSession()->SendChatMessage(CHAT_MSG_SAY,0,str.str(),""); - } - return true; + ((PseuInstance*)parentMethod)->GetWSession()->SendChatMessage(CHAT_MSG_SAY,0,str.str(),""); + } + } + return true; } DefReturnResult DefScriptPackage::SCemote(CmdSet& Set){ diff --git a/src/Client/GUI/SceneWorld.cpp b/src/Client/GUI/SceneWorld.cpp index 84da634..9bdccb1 100644 --- a/src/Client/GUI/SceneWorld.cpp +++ b/src/Client/GUI/SceneWorld.cpp @@ -327,6 +327,12 @@ WorldPosition SceneWorld::GetWorldPosition(void) // get the current maptile and use the coords of the top-left corner as relative positions MapTile *tile = mapmgr->GetCurrentTile(); + if(!tile) + { + logerror("SceneWorld::GetWorldPosition failed, MapTile not loaded!"); + return WorldPosition(); + } + float mapx = tile->GetBaseX(); float mapy = tile->GetBaseY(); diff --git a/src/Client/PseuWoW.cpp b/src/Client/PseuWoW.cpp index f7df032..eeaa764 100644 --- a/src/Client/PseuWoW.cpp +++ b/src/Client/PseuWoW.cpp @@ -359,6 +359,7 @@ void PseuInstance::SaveAllCache(void) { GetWSession()->plrNameCache.SaveToFile(); ItemProtoCache_WriteDataToCache(GetWSession()); + CreatureTemplateCache_WriteDataToCache(GetWSession()); //... } } diff --git a/src/Client/World/CMSGConstructor.cpp b/src/Client/World/CMSGConstructor.cpp index 927ea23..3107a18 100644 --- a/src/Client/World/CMSGConstructor.cpp +++ b/src/Client/World/CMSGConstructor.cpp @@ -63,16 +63,16 @@ void WorldSession::SendEmote(uint32 id) SendWorldPacket(packet); } -void WorldSession::SendQueryItem(uint32 id, uint64 guid) // is it a guid? not sure +void WorldSession::SendQueryItem(uint32 entry, uint64 guid) // is it a guid? not sure { - if(objmgr.ItemNonExistent(id)) + if(objmgr.ItemNonExistent(entry)) { - logdebug("Skipped query of item %u (was marked as nonexistent before)",id); + logdebug("Skipped query of item %u (was marked as nonexistent before)",entry); return; } - logdebug("Sending Item query, id=%u",id); + logdebug("Sending Item query, id=%u",entry); WorldPacket packet; - packet << id << guid; + packet << entry << guid; packet.SetOpcode(CMSG_ITEM_QUERY_SINGLE); SendWorldPacket(packet); } @@ -179,7 +179,18 @@ void WorldSession::SendWhoListRequest(uint32 minlvl, uint32 maxlvl, uint32 racem SendWorldPacket(pkt); } - +void WorldSession::SendQueryCreature(uint32 entry, uint64 guid) +{ + if(objmgr.CreatureNonExistent(entry)) + { + logdebug("Skipped query of creature %u (was marked as nonexistent before)",entry); + return; + } + logdebug("Sending creature query, id=%u",entry); + WorldPacket wp(CMSG_CREATURE_QUERY,4+8); + wp << entry << guid; + SendWorldPacket(wp); +} diff --git a/src/Client/World/CacheHandler.cpp b/src/Client/World/CacheHandler.cpp index ac80911..15dfedd 100644 --- a/src/Client/World/CacheHandler.cpp +++ b/src/Client/World/CacheHandler.cpp @@ -11,7 +11,8 @@ #include "Item.h" // increase this number whenever you change something that makes old files unusable -uint32 ITEMPROTOTYPES_CACHE_VERSION = 0x00000002; +uint32 ITEMPROTOTYPES_CACHE_VERSION = 3; +uint32 CREATURETEMPLATES_CACHE_VERSION = 0; PlayerNameCache::~PlayerNameCache() { @@ -162,7 +163,11 @@ void ItemProtoCache_InsertDataToSession(WorldSession *session) return; } - uint32 cacheversion; + uint32 cacheversion, total; + + try + { + fh.read((char*)&cacheversion,4); if(cacheversion != ITEMPROTOTYPES_CACHE_VERSION) { @@ -170,27 +175,24 @@ void ItemProtoCache_InsertDataToSession(WorldSession *session) fh.close(); return; } + fh.read((char*)&total,4); + logdetail("ItemProtoCache: %u item prototypes stored",total); - uint32 datasize,counter=0,unk; + uint32 datasize,unk, counter = 0; ByteBuffer buf; - while(!fh.eof()) + for(uint32 i = 0; i < total && !fh.eof(); i++) { buf.clear(); fh.read((char*)&datasize,sizeof(uint32)); + DEBUG(logdebug("ItemProtoCache: (%u/%u) - datasize=%u",i,total,datasize)); buf.resize(datasize); - if(buf.size() < datasize) - { - logerror("ItemProtoCache: Failed to resize ByteBuffer!"); - return; - } fh.read((char*)buf.contents(),datasize); - ItemProto *proto = new ItemProto; + ItemProto *proto = new ItemProto(); buf >> proto->Id; buf >> proto->Class; buf >> proto->SubClass; buf >> unk; - for(uint8 i=0;i<4;i++) - buf >> proto->Name[i]; + buf >> proto->Name; buf >> proto->DisplayInfoID; buf >> proto->Quality; buf >> proto->Flags; @@ -280,13 +282,21 @@ void ItemProtoCache_InsertDataToSession(WorldSession *session) } else delete proto; } + + } + catch (ByteBufferException bbe) + { + logerror("ByteBuffer exception: attempt to \"%s\" %u bytes at position %u out of total %u bytes. (wpos=%u)", + bbe.action, bbe.readsize, bbe.rpos, bbe.cursize, bbe.wpos); + } + fh.close(); - logdetail("ItemProtoCache: Loaded %u Item Prototypes",counter); + logdetail("ItemProtoCache: Loaded %u Item Prototypes",total); } void ItemProtoCache_WriteDataToCache(WorldSession *session) { - if (session->objmgr.GetItemProtoCount() <= 0) + if (!session->objmgr.GetItemProtoCount()) return; char* fn = "./cache/ItemPrototypes.cache"; @@ -297,18 +307,21 @@ void ItemProtoCache_WriteDataToCache(WorldSession *session) logerror("ItemProtoCache: Could not write to file '%s'!",fn); return; } + + uint32 total = session->objmgr.GetItemProtoCount(); fh.write((char*)&(uint32)ITEMPROTOTYPES_CACHE_VERSION,4); + fh.write((char*)&total,4); + uint32 counter=0; ByteBuffer buf; - for(uint32 i=0;iobjmgr.GetItemProtoCount();i++) + for(ItemProtoMap::iterator it = session->objmgr.GetItemProtoStorage()->begin(); it != session->objmgr.GetItemProtoStorage()->end(); it++) { buf.clear(); - ItemProto *proto = session->objmgr.GetItemProtoByPos(i); + ItemProto *proto = it->second; buf << proto->Id; buf << proto->Class; buf << proto->SubClass; - for(uint8 i=0;i<4;i++) - buf << proto->Name[i]; + buf << proto->Name; buf << proto->DisplayInfoID; buf << proto->Quality; buf << proto->Flags; @@ -399,3 +412,117 @@ void ItemProtoCache_WriteDataToCache(WorldSession *session) fh.close(); log("ItemProtoCache: Saved %u Item Prototypes",counter); } + +void CreatureTemplateCache_InsertDataToSession(WorldSession *session) +{ + logdetail("CreatureTemplateCache: Loading..."); + char* fn = "./cache/CreatureTemplates.cache"; + std::fstream fh; + fh.open(fn, std::ios_base::in | std::ios_base::binary); + if(!fh) + { + logerror("CreatureTemplateCache: Could not open file '%s'!",fn); + return; + } + + uint32 cacheversion, total, counter = 0; + + try + { + + fh.read((char*)&cacheversion,4); + if(cacheversion != CREATURETEMPLATES_CACHE_VERSION) + { + logerror("CreatureTemplateCache is outdated! Creating new cache."); + fh.close(); + return; + } + fh.read((char*)&total,4); + logdetail("CreatureTemplateCache: %u creature templates stored",total); + + uint32 datasize; + ByteBuffer buf; + for(uint32 i = 0; i < total && !fh.eof(); i++) + { + buf.clear(); + fh.read((char*)&datasize,sizeof(uint32)); + buf.resize(datasize); + fh.read((char*)buf.contents(),datasize); + CreatureTemplate *ct = new CreatureTemplate(); + buf >> ct->entry; + buf >> ct->name; + buf >> ct->subname; + buf >> ct->flag1; + buf >> ct->type; + buf >> ct->family; + buf >> ct->rank; + buf >> ct->SpellDataId; + buf >> ct->displayid_A; + buf >> ct->displayid_H; + buf >> ct->displayid_AF; + buf >> ct->displayid_HF; + buf >> ct->RacialLeader; + + if(ct->entry) + { + session->objmgr.Add(ct); + counter++; + } else + delete ct; + } + + } + catch (ByteBufferException bbe) + { + logerror("ByteBuffer exception: attempt to \"%s\" %u bytes at position %u out of total %u bytes. (wpos=%u)", + bbe.action, bbe.readsize, bbe.rpos, bbe.cursize, bbe.wpos); + } + + fh.close(); + logdetail("CreatureTemplateCache: Loaded %u Creature Templates",counter); +} + +void CreatureTemplateCache_WriteDataToCache(WorldSession *session) +{ + if (!session->objmgr.GetCreatureTemplateCount()) + return; + + char* fn = "./cache/CreatureTemplates.cache"; + std::fstream fh; + fh.open(fn, std::ios_base::out | std::ios_base::binary); + if(!fh) + { + logerror("CreatureTemplateCache: Could not write to file '%s'!",fn); + return; + } + uint32 total = session->objmgr.GetCreatureTemplateCount(); + fh.write((char*)&(uint32)CREATURETEMPLATES_CACHE_VERSION,4); + fh.write((char*)&total,4); + uint32 counter=0; + ByteBuffer buf; + for(CreatureTemplateMap::iterator it = session->objmgr.GetCreatureTemplateStorage()->begin(); it != session->objmgr.GetCreatureTemplateStorage()->end(); it++) + { + buf.clear(); + CreatureTemplate *ct = it->second; + buf << ct->entry; + buf << ct->name; + buf << ct->subname; + buf << ct->flag1; + buf << ct->type; + buf << ct->family; + buf << ct->rank; + buf << ct->SpellDataId; + buf << ct->displayid_A; + buf << ct->displayid_H; + buf << ct->displayid_AF; + buf << ct->displayid_HF; + buf << ct->RacialLeader; + + uint32 size = buf.size(); + fh.write((char*)&size,sizeof(uint32)); + fh.write((char*)buf.contents(),buf.size()); + counter++; + } + fh.close(); + log("CreatureTemplateCache: Saved %u Creature Templates",counter); +} diff --git a/src/Client/World/CacheHandler.h b/src/Client/World/CacheHandler.h index fae0623..16b5d90 100644 --- a/src/Client/World/CacheHandler.h +++ b/src/Client/World/CacheHandler.h @@ -25,4 +25,7 @@ private: void ItemProtoCache_InsertDataToSession(WorldSession *session); void ItemProtoCache_WriteDataToCache(WorldSession *session); +void CreatureTemplateCache_InsertDataToSession(WorldSession *session); +void CreatureTemplateCache_WriteDataToCache(WorldSession *session); + #endif diff --git a/src/Client/World/Corpse.cpp b/src/Client/World/Corpse.cpp index 33d3336..8be92bd 100644 --- a/src/Client/World/Corpse.cpp +++ b/src/Client/World/Corpse.cpp @@ -2,7 +2,6 @@ Corpse::Corpse() { - _uint32values=NULL; _type=TYPE_CORPSE; _typeid=TYPEID_CORPSE; _valuescount=CORPSE_END; diff --git a/src/Client/World/Item.cpp b/src/Client/World/Item.cpp index 6c33a11..0c04c3b 100644 --- a/src/Client/World/Item.cpp +++ b/src/Client/World/Item.cpp @@ -6,18 +6,19 @@ void WorldSession::_HandleItemQuerySingleResponseOpcode(WorldPacket& recvPacket) { - ItemProto *proto = new ItemProto; + ItemProto *proto = new ItemProto(); recvPacket >> proto->Id; uint8 field[64]; uint32 unk; + std::string s; memset(field,0,64); if(memcmp(recvPacket.contents()+sizeof(uint32),field,64)) { recvPacket >> proto->Class; recvPacket >> proto->SubClass; recvPacket >> unk; // dont need that value? - for(uint8 i=0;i<4;i++) - recvPacket >> proto->Name[i]; + recvPacket >> proto->Name; + recvPacket >> s >> s >> s; // strip name1-4 recvPacket >> proto->DisplayInfoID; recvPacket >> proto->Quality; recvPacket >> proto->Flags; @@ -98,8 +99,10 @@ void WorldSession::_HandleItemQuerySingleResponseOpcode(WorldPacket& recvPacket) recvPacket >> proto->ArmorDamageModifier; logdetail("Got Item Info: Id=%u Name='%s' ReqLevel=%u Armor=%u Desc='%s'", - proto->Id, proto->Name[0].c_str(), proto->RequiredLevel, proto->Armor, proto->Description.c_str()); + proto->Id, proto->Name.c_str(), proto->RequiredLevel, proto->Armor, proto->Description.c_str()); objmgr.Add(proto); + objmgr.AssignNameToObj(proto->Id, TYPEID_ITEM, proto->Name); + objmgr.AssignNameToObj(proto->Id, TYPEID_CONTAINER, proto->Name); } else { diff --git a/src/Client/World/Item.h b/src/Client/World/Item.h index 1c58849..71a6bcf 100644 --- a/src/Client/World/Item.h +++ b/src/Client/World/Item.h @@ -354,7 +354,7 @@ struct ItemProto uint32 Id; uint32 Class; uint32 SubClass; - std::string Name[4]; + std::string Name; uint32 DisplayInfoID; uint32 Quality; uint32 Flags; diff --git a/src/Client/World/ObjMgr.cpp b/src/Client/World/ObjMgr.cpp index dfe4085..8c61e5b 100644 --- a/src/Client/World/ObjMgr.cpp +++ b/src/Client/World/ObjMgr.cpp @@ -22,9 +22,13 @@ void ObjMgr::SetInstance(PseuInstance *i) void ObjMgr::RemoveAll(void) { - for(ItemProtoList::iterator i = _iproto.begin(); i!=_iproto.end(); i++) + for(ItemProtoMap::iterator i = _iproto.begin(); i!=_iproto.end(); i++) { - delete *i; + delete i->second; + } + for(CreatureTemplateMap::iterator i = _creature_templ.begin(); i!=_creature_templ.end(); i++) + { + delete i->second; } while(_obj.size()) { @@ -45,6 +49,8 @@ void ObjMgr::Remove(uint64 guid) } } +// -- Object part -- + void ObjMgr::Add(Object *o) { _obj[o->GetGUID()] = o; @@ -64,24 +70,35 @@ Object *ObjMgr::GetObj(uint64 guid) return NULL; } +// iterate over all objects and assign a name to all matching the entry and typemask +uint32 ObjMgr::AssignNameToObj(uint32 entry, uint8 type, std::string name) +{ + uint32 changed = 0; + for(ObjectMap::iterator it = _obj.begin(); it != _obj.end(); it++) + { + if(it->second->GetEntry() && (it->second->GetTypeId() == type)) + { + it->second->SetName(name); + changed++; + } + } + return changed; +} + +// -- Item part -- + void ObjMgr::Add(ItemProto *proto) { - _iproto.push_back(proto); + _iproto[proto->Id] = proto; } ItemProto *ObjMgr::GetItemProto(uint32 entry) { - for(ItemProtoList::iterator i = _iproto.begin(); i!=_iproto.end(); i++) - if((*i)->Id == entry) - return *i; + if(_iproto.find(entry) != _iproto.end()) + return _iproto[entry]; return NULL; } -ItemProto *ObjMgr::GetItemProtoByPos(uint32 pos) -{ - return _iproto[pos]; -} - void ObjMgr::AddNonexistentItem(uint32 id) { _noitem.insert(id); @@ -92,6 +109,32 @@ bool ObjMgr::ItemNonExistent(uint32 id) return _noitem.find(id) != _noitem.end(); } +// -- Creature part -- + +void ObjMgr::Add(CreatureTemplate *cr) +{ + _creature_templ[cr->entry] = cr; +} + +CreatureTemplate *ObjMgr::GetCreatureTemplate(uint32 entry) +{ + if(_creature_templ.find(entry) != _creature_templ.end()) + return _creature_templ[entry]; + return NULL; +} + +void ObjMgr::AddNonexistentCreature(uint32 id) +{ + _nocreature.insert(id); +} + +bool ObjMgr::CreatureNonExistent(uint32 id) +{ + return _nocreature.find(id) != _nocreature.end(); +} + +// -- misc part -- + void ObjMgr::AddRequestedPlayerGUID(uint32 loguid) { _reqpnames.insert(loguid); diff --git a/src/Client/World/ObjMgr.h b/src/Client/World/ObjMgr.h index 279a712..5653784 100644 --- a/src/Client/World/ObjMgr.h +++ b/src/Client/World/ObjMgr.h @@ -3,10 +3,11 @@ #include "common.h" #include -#include "Object.h" #include "Item.h" +#include "Unit.h" -typedef std::vector ItemProtoList; +typedef std::map ItemProtoMap; +typedef std::map CreatureTemplateMap; typedef std::map ObjectMap; class PseuInstance; @@ -22,13 +23,23 @@ public: // Item Prototype functions uint32 GetItemProtoCount(void) { return _iproto.size(); } ItemProto *GetItemProto(uint32); - ItemProto *GetItemProtoByPos(uint32); void Add(ItemProto*); + ItemProtoMap *GetItemProtoStorage(void) { return &_iproto; } // nonexistent items handler void AddNonexistentItem(uint32); bool ItemNonExistent(uint32); + // Creature template functions + uint32 GetCreatureTemplateCount(void) { return _creature_templ.size(); } + CreatureTemplate *GetCreatureTemplate(uint32); + void Add(CreatureTemplate*); + CreatureTemplateMap *GetCreatureTemplateStorage(void) { return &_creature_templ; } + + // nonexistent creatures handler + void AddNonexistentCreature(uint32); + bool CreatureNonExistent(uint32); + // player names related void AddRequestedPlayerGUID(uint32); bool IsRequestedPlayerGUID(uint32); @@ -41,12 +52,15 @@ public: void Remove(uint64); // remove all objects with that guid (should be only 1 object in total anyway) Object *GetObj(uint64 guid); inline uint32 GetObjectCount(void) { return _obj.size(); } + uint32 AssignNameToObj(uint32 entry, uint8 type, std::string name); private: - ItemProtoList _iproto; + ItemProtoMap _iproto; + CreatureTemplateMap _creature_templ; ObjectMap _obj; std::set _noitem; std::set _reqpnames; + std::set _nocreature; PseuInstance *_instance; }; diff --git a/src/Client/World/Object.cpp b/src/Client/World/Object.cpp index d1258b1..f3248e9 100644 --- a/src/Client/World/Object.cpp +++ b/src/Client/World/Object.cpp @@ -8,7 +8,7 @@ Object::Object() _uint32values=NULL; _type=TYPE_OBJECT; _typeid=TYPEID_OBJECT; - _valuescount=0; // base class. this value will be set by derived classes + _valuescount=OBJECT_END; // base class. this value will be set by derived classes } Object::~Object() diff --git a/src/Client/World/Object.h b/src/Client/World/Object.h index 630a2f1..22af8fb 100644 --- a/src/Client/World/Object.h +++ b/src/Client/World/Object.h @@ -9,7 +9,7 @@ enum TYPE { TYPE_OBJECT = 1, TYPE_ITEM = 2, - TYPE_CONTAINER = 6, + TYPE_CONTAINER = 6, // a container is ALWAYS an item! TYPE_UNIT = 8, TYPE_PLAYER = 16, TYPE_GAMEOBJECT = 32, @@ -45,7 +45,14 @@ public: inline const uint8 GetTypeId() { return _typeid; } inline const uint8 GetTypeMask() { return _type; } - inline bool isType(uint8 mask) { return (mask & _type) ? true : false; } + inline bool IsType(uint8 mask) { return (mask & _type) ? true : false; } + inline bool IsPlayer(void) { return _typeid == TYPEID_PLAYER; } // specific + inline bool IsUnit(void) { return _type & TYPE_UNIT; } // generic (unit = creature or player) + inline bool IsCreature(void) { return IsUnit() && !IsPlayer(); } // specific + inline bool IsItem(void) { return _type & TYPE_ITEM; } // generic (item or container) + inline bool IsContainer(void) { return _typeid == TYPEID_CONTAINER; } // specific + inline bool IsCorpse(void) { return _typeid == TYPEID_CORPSE; } // specific + inline bool IsDynObject(void) { return _typeid == TYPEID_DYNAMICOBJECT; } // specific inline const uint32 GetUInt32Value( uint16 index ) const { return _uint32values[ index ]; @@ -73,6 +80,9 @@ public: _uint32values[ index ] = value; } + inline void SetName(std::string name) { _name = name; } + inline std::string GetName(void) { return _name; } + void Create(uint64 guid); protected: @@ -87,6 +97,7 @@ protected: }; uint8 _type; uint8 _typeid; + std::string _name; }; class WorldObject : public Object @@ -99,13 +110,11 @@ public: inline float GetY(void) { return _y; } inline float GetZ(void) { return _z; } inline float GetO(void) { return _o; } - inline void SetName(std::string name) { _name = name; } - inline std::string GetName(void) { return _name; } + protected: WorldObject(); float _x,_y,_z,_o; // coords, orientation uint16 _m; // map - std::string _name; }; diff --git a/src/Client/World/Unit.h b/src/Client/World/Unit.h index 1a0dc2b..e03a708 100644 --- a/src/Client/World/Unit.h +++ b/src/Client/World/Unit.h @@ -41,6 +41,28 @@ enum UnitFlags UNIT_FLAG_SHEATHE = 0x40000000 }; +struct CreatureTemplate +{ + uint32 entry; + std::string name; + std::string subname; + std::string directions; + uint32 flag1; + uint32 type; + uint32 family; + uint32 rank; + //uint32 unk1; + uint32 SpellDataId; + uint32 displayid_A; + uint32 displayid_H; + uint32 displayid_AF; + uint32 displayid_HF; + //float unkf1; + //float unkf2; + uint8 RacialLeader; +}; + + class Unit : public WorldObject diff --git a/src/Client/World/UpdateData.cpp b/src/Client/World/UpdateData.cpp index b5473ba..bd02f0f 100644 --- a/src/Client/World/UpdateData.cpp +++ b/src/Client/World/UpdateData.cpp @@ -366,10 +366,14 @@ void WorldSession::_QueryObjectInfo(uint64 guid) case TYPEID_CONTAINER: { ItemProto *proto = objmgr.GetItemProto(obj->GetEntry()); - if(!proto) + if(proto) + { + obj->SetName(proto->Name); + } + else { logdebug("Found unknown item: GUID="I64FMT" entry=%u",obj->GetGUID(),obj->GetEntry()); - SendQueryItem(obj->GetEntry(),obj->GetGUID()); // not sure if sending GUID is correct + SendQueryItem(obj->GetEntry(),guid); // not sure if sending GUID is correct } break; } @@ -378,11 +382,20 @@ void WorldSession::_QueryObjectInfo(uint64 guid) std::string name = GetOrRequestPlayerName(obj->GetGUID()); if(!name.empty()) { - ((WorldObject*)obj)->SetName(name); + obj->SetName(name); } // else: name will be set when server answers (_HandleNameQueryResponseOpcode) break; } + case TYPEID_UNIT: // checked after player; this one here should cover creatures only + { + CreatureTemplate *ct = objmgr.GetCreatureTemplate(obj->GetEntry()); + if(ct) + obj->SetName(ct->name); + else + SendQueryCreature(obj->GetEntry(),guid); + break; + } //case... } } diff --git a/src/Client/World/WorldSession.cpp b/src/Client/World/WorldSession.cpp index 412b10a..5bf3c0f 100644 --- a/src/Client/World/WorldSession.cpp +++ b/src/Client/World/WorldSession.cpp @@ -88,6 +88,7 @@ void WorldSession::_LoadCache(void) logdetail("Loading Cache..."); plrNameCache.ReadFromFile(); // load names/guids of known players ItemProtoCache_InsertDataToSession(this); + CreatureTemplateCache_InsertDataToSession(this); //... } @@ -190,6 +191,13 @@ void WorldSession::HandleWorldPacket(WorldPacket *packet) } } + catch (ByteBufferException bbe) + { + logerror("WorldSession: ByteBufferException"); + logerror("ByteBuffer reported: attempt to \"%s\" %u bytes at position %u out of total %u bytes. (wpos=%u)", + bbe.action, bbe.readsize, bbe.rpos, bbe.cursize, bbe.wpos); + throw; + } catch (...) { logerror("Exception while handling opcode %u!",packet->GetOpcode()); @@ -253,6 +261,7 @@ OpcodeHandler *WorldSession::_GetOpcodeHandlerTable() const {SMSG_MOTD, &WorldSession::_HandleMotdOpcode}, {SMSG_NOTIFICATION, &WorldSession::_HandleNotificationOpcode}, {SMSG_WHO, &WorldSession::_HandleWhoOpcode}, + {SMSG_CREATURE_QUERY_RESPONSE, &WorldSession::_HandleCreatureQueryResponseOpcode}, // table termination { 0, NULL } @@ -532,13 +541,24 @@ void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket) uint32 lang=0; uint64 source_guid=0; uint64 target_guid=0; + uint64 npc_guid=0; // for CHAT_MSG_MONSTER_SAY uint32 msglen=0; uint32 unk=0; + uint32 npc_name_len; + std::string npc_name; std::string msg,channel=""; bool isCmd=false; recvPacket >> type >> lang; + if(lang == CHAT_MSG_MONSTER_SAY) + { + recvPacket >> npc_guid; + recvPacket >> unk; + recvPacket >> npc_name_len; + recvPacket >> npc_name; + } + if(lang == LANG_ADDON && GetInstance()->GetConf()->skipaddonchat) return; @@ -551,18 +571,24 @@ void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket) std::string langname = GetDBMgr().GetLangName(lang); const char* ln = langname.c_str(); + std::string name; - std::string plrname; - if(source_guid) + if(type == CHAT_MSG_MONSTER_SAY) { - plrname = GetOrRequestPlayerName(source_guid); - if(plrname.empty()) + name = npc_name; + source_guid = npc_guid; + } + + if(source_guid && IS_PLAYER_GUID(source_guid)) + { + name = GetOrRequestPlayerName(source_guid); + if(name.empty()) { _DelayWorldPacket(recvPacket, GetLagMS() * 1.2f); // guess time how long it will take until we got player name from the server return; // handle later } } - GetInstance()->GetScripts()->variables.Set("@thismsg_name",plrname); + GetInstance()->GetScripts()->variables.Set("@thismsg_name",name); GetInstance()->GetScripts()->variables.Set("@thismsg",toString(target_guid)); @@ -575,39 +601,43 @@ void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket) } else if (type==CHAT_MSG_WHISPER ) { - logcustom(0,WHITE,"WHISP: %s [%s]: %s",plrname.c_str(),ln,msg.c_str()); + logcustom(0,WHITE,"WHISP: %s [%s]: %s",name.c_str(),ln,msg.c_str()); } else if (type==CHAT_MSG_CHANNEL ) { - logcustom(0,WHITE,"CHANNEL: [%s]: %s [%s]: %s",channel.c_str(),plrname.c_str(),ln,msg.c_str()); + logcustom(0,WHITE,"CHANNEL: [%s]: %s [%s]: %s",channel.c_str(),name.c_str(),ln,msg.c_str()); } else if (type==CHAT_MSG_SAY ) { - logcustom(0,WHITE,"CHAT: %s [%s]: %s",plrname.c_str(),ln,msg.c_str()); + logcustom(0,WHITE,"CHAT: %s [%s]: %s",name.c_str(),ln,msg.c_str()); } else if (type==CHAT_MSG_YELL ) { - logcustom(0,WHITE,"CHAT: %s yells [%s]: %s ",plrname.c_str(),ln,msg.c_str()); + logcustom(0,WHITE,"CHAT: %s yells [%s]: %s ",name.c_str(),ln,msg.c_str()); } else if (type==CHAT_MSG_WHISPER_INFORM ) { - logcustom(0,WHITE,"TO %s [%s]: %s",plrname.c_str(),ln,msg.c_str()); + logcustom(0,WHITE,"TO %s [%s]: %s",name.c_str(),ln,msg.c_str()); } else if (type==CHAT_MSG_GUILD ) { - logcustom(0,WHITE,"GUILD: %s [%s]: %s",plrname.c_str(),ln,msg.c_str()); + logcustom(0,WHITE,"GUILD: %s [%s]: %s",name.c_str(),ln,msg.c_str()); } else if (type==CHAT_MSG_PARTY ) { - logcustom(0,WHITE,"PARTY: %s [%s]: %s",plrname.c_str(),ln,msg.c_str()); + logcustom(0,WHITE,"PARTY: %s [%s]: %s",name.c_str(),ln,msg.c_str()); } else if (type==CHAT_MSG_EMOTE ) { - logcustom(0,WHITE,"EMOTE [%s]: %s %s",ln,plrname.c_str(),msg.c_str()); + logcustom(0,WHITE,"EMOTE [%s]: %s %s",ln,name.c_str(),msg.c_str()); + } + else if (type==CHAT_MSG_MONSTER_SAY) + { + logcustom(0,WHITE,"NPC: %s [%s]: %s",name.c_str(),ln,msg.c_str()); } else { - logcustom(0,WHITE,"UNK CHAT TYPE (%u): %s [%s]: %s",type,plrname.c_str(),ln,msg.c_str()); + logcustom(0,WHITE,"UNK CHAT TYPE (%u): %s [%s]: %s",type,name.c_str(),ln,msg.c_str()); } if(target_guid!=GetGuid() && msg.length()>1 && msg.at(0)=='-' && GetInstance()->GetConf()->allowgamecmd) @@ -652,12 +682,12 @@ void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket) if(isCmd) { - GetInstance()->GetScripts()->variables.Set("@thiscmd_name",plrname); + GetInstance()->GetScripts()->variables.Set("@thiscmd_name",name); GetInstance()->GetScripts()->variables.Set("@thiscmd",toString(target_guid)); std::string lin=msg.substr(1,msg.length()-1); try { - GetInstance()->GetScripts()->My_Run(lin,plrname); + GetInstance()->GetScripts()->My_Run(lin,name); } catch (...) { @@ -669,7 +699,7 @@ void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket) // TODO: remove this block soon, its obsoelete and has to be done via scripting! if(type==CHAT_MSG_WHISPER && (!isCmd) && target_guid!=GetGuid()) { - GetInstance()->GetScripts()->variables.Set("@thiswhisper_name",plrname); + GetInstance()->GetScripts()->variables.Set("@thiswhisper_name",name); GetInstance()->GetScripts()->variables.Set("@thiswhisper",toString(target_guid)); GetInstance()->GetScripts()->variables.Set("@thiswhisper_lang",toString((uint64)lang)); GetInstance()->GetScripts()->RunScript("_onwhisper",NULL); @@ -860,11 +890,11 @@ void WorldSession::_HandleChannelNotifyOpcode(WorldPacket& recvPacket) void WorldSession::_HandleCastResultOpcode(WorldPacket& recvPacket) { uint32 spellid,otherr = 0; - uint8 result; - recvPacket >> spellid >> result; - if (recvPacket.rpos()+1 < recvPacket.size()) + uint8 result, castCount; + recvPacket >> spellid >> result >> castCount; + if (recvPacket.rpos()+sizeof(uint32) <= recvPacket.size()) recvPacket >> otherr; - logdetail("Cast of spell %u failed. result=%u, additional info=%u",spellid,result,otherr); + logdetail("Cast of spell %u failed. result=%u, cast count=%u, additional info=%u",spellid,result,castCount,otherr); } void WorldSession::_HandleCastSuccessOpcode(WorldPacket& recvPacket) @@ -873,9 +903,18 @@ void WorldSession::_HandleCastSuccessOpcode(WorldPacket& recvPacket) uint64 casterGuid; casterGuid = recvPacket.GetPackedGuid(); - recvPacket >> spellId; - logdetail("Cast of spell %u successful.",spellId); + + if (GetMyChar()->GetGUID() == casterGuid) + logdetail("Cast of spell %u successful.",spellId); + else + { + Object *caster = objmgr.GetObj(casterGuid); + if(caster) + logdetail("%s casted spell %u", caster->GetName(), spellId); + else + logerror("Caster of spell %u (GUID "I64FMT") is unknown object!"); + } } void WorldSession::_HandleInitialSpellsOpcode(WorldPacket& recvPacket) @@ -916,24 +955,33 @@ void WorldSession::_HandleChannelListOpcode(WorldPacket& recvPacket) void WorldSession::_HandleEmoteOpcode(WorldPacket& recvPacket) { - std::string plrname; + std::string name; uint32 anim; // animation id? uint64 guid; // guid of the unit performing the emote recvPacket >> anim >> guid; - // TODO: check if the emote came from a player or a mob, and query mob name if it was a mob if(guid) { - plrname = GetOrRequestPlayerName(guid); - if(plrname.empty()) + Object *o = objmgr.GetObj(guid); + if(o) { - _DelayWorldPacket(recvPacket, GetLagMS() * 1.2f); - return; + name = o->GetName(); + } + if(name.empty()) + { + if(o->IsPlayer()) + { + name = GetOrRequestPlayerName(guid); + if(name.empty()) + { + _DelayWorldPacket(recvPacket, GetLagMS() * 1.2f); + return; + } + } } } - // TODO: check for mobs - logdebug(I64FMT " / %s performing emote; anim=%u",guid,plrname.c_str(),anim); + logdebug(I64FMT " / %s performing emote; anim=%u",guid,name.c_str(),anim); // TODO: show emote in GUI :P } @@ -1110,8 +1158,60 @@ void WorldSession::_HandleWhoOpcode(WorldPacket& recvPacket) } } +void WorldSession::_HandleCreatureQueryResponseOpcode(WorldPacket& recvPacket) +{ + uint32 entry; + recvPacket >> entry; + if( (!entry) || (entry & 0x80000000) ) // last bit marks that entry is invalid / does not exist on server side + { + uint32 real_entry = entry & ~0x80000000; + logerror("Creature %u does not exist!", real_entry); + objmgr.AddNonexistentCreature(real_entry); + return; + } + + CreatureTemplate *ct = new CreatureTemplate(); + std::string s; + uint32 unk; + float unkf; + ct->entry = entry; + recvPacket >> ct->name; + recvPacket >> s; + recvPacket >> s; + recvPacket >> s; + recvPacket >> ct->subname; + recvPacket >> ct->directions; + recvPacket >> ct->flag1; + recvPacket >> ct->type; + recvPacket >> ct->family; + recvPacket >> ct->rank; + recvPacket >> unk; + recvPacket >> ct->SpellDataId; + recvPacket >> ct->displayid_A; + recvPacket >> ct->displayid_H; + recvPacket >> ct->displayid_AF; + recvPacket >> ct->displayid_HF; + recvPacket >> unkf; + recvPacket >> unkf; + recvPacket >> ct->RacialLeader; + + std::stringstream ss; + ss << "Got info for creature " << entry << ":" << ct->name; + if(!ct->subname.empty()) + ss << " <" << ct->subname << ">"; + ss << " type " << ct->type; + ss << " flags " << ct->flag1; + ss << " models " << ct->displayid_A << "/" << ct->displayid_H; + logdetail("%s",ss.str().c_str()); + + objmgr.Add(ct); + objmgr.AssignNameToObj(entry, TYPEID_UNIT, ct->name); +} + + // TODO: delete world on LogoutComplete once implemented + diff --git a/src/Client/World/WorldSession.h b/src/Client/World/WorldSession.h index 6aa0a58..13b56ae 100644 --- a/src/Client/World/WorldSession.h +++ b/src/Client/World/WorldSession.h @@ -76,10 +76,11 @@ public: void SendQueryPlayerName(uint64 guid); void SendPing(uint32); void SendEmote(uint32); - void SendQueryItem(uint32, uint64); + void SendQueryItem(uint32 id, uint64 guid = 0); void SendSetSelection(uint64); void SendCastSpell(uint32 spellid, bool nocheck=false); void SendWhoListRequest(uint32 minlvl=0, uint32 maxlvl=100, uint32 racemask=-1, uint32 classmask=-1, std::string name="", std::string guildname="", std::vector *zonelist=NULL, std::vector *strlist=NULL); + void SendQueryCreature(uint32 entry, uint64 guid = 0); void HandleWorldPacket(WorldPacket*); @@ -127,6 +128,7 @@ private: void _HandleMotdOpcode(WorldPacket& recvPacket); void _HandleNotificationOpcode(WorldPacket& recvPacket); void _HandleWhoOpcode(WorldPacket& recvPacket); + void _HandleCreatureQueryResponseOpcode(WorldPacket& recvPacket); // helper functions to keep SMSG_(COMPRESSED_)UPDATE_OBJECT easy to handle void _MovementUpdate(uint8 objtypeid, uint64 guid, WorldPacket& recvPacket); // Helper for _HandleUpdateObjectOpcode diff --git a/src/shared/ByteBuffer.h b/src/shared/ByteBuffer.h index cacfc98..3c15192 100644 --- a/src/shared/ByteBuffer.h +++ b/src/shared/ByteBuffer.h @@ -23,6 +23,21 @@ #include #include +class ByteBufferException +{ +public: + ByteBufferException(const char *act, uint32 rp, uint32 wp, uint32 rs, uint32 cs) + { + action = act; + rpos = rp; + wpos = wp; + readsize = rs; + cursize = cs; + } + uint32 rpos, wpos, readsize, cursize; + const char *action; +}; + class ByteBuffer { public: @@ -188,6 +203,8 @@ class ByteBuffer }; template T read(size_t pos) const { + if(pos + sizeof(T) > size()) + throw ByteBufferException("read", pos, _wpos, sizeof(T), size()); return *((T*)&_storage[pos]); } @@ -199,7 +216,7 @@ class ByteBuffer } else { - throw error(); + throw ByteBufferException("read-into", _rpos, _wpos, len, size()); } _rpos += len; }