* added creature query & cache

* fixed crash when transforming irr to world coord, when maptile was not loaded
* fixed possible bugs wtih corpse object type
* removed name2-4 fields from item protos, they are useless
* added IsPlayer(), IsCreature(), etc functions to Object class. TypeID check sucks.
* changed item proto storage in ObjMgr to std::map instead of vector for faster lookup.
* added exception handling to ByteBuffer class to prevent possible crashes on invalid read access. this also fixes possible startup crashes with corrupted item/creature cache files.
* CHAT_MSG_MONSTER_SAY should work now (monster yell handled differently by MaNGOS?!)
* forgot last rev: no more stair effect on terrain. thx bLuma for patch!
This commit is contained in:
false_genesis 2008-02-11 17:43:39 +00:00
parent 38cbcb026c
commit fe86400f60
18 changed files with 474 additions and 99 deletions

View File

@ -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){

View File

@ -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();

View File

@ -359,6 +359,7 @@ void PseuInstance::SaveAllCache(void)
{
GetWSession()->plrNameCache.SaveToFile();
ItemProtoCache_WriteDataToCache(GetWSession());
CreatureTemplateCache_WriteDataToCache(GetWSession());
//...
}
}

View File

@ -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);
}

View File

@ -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;i<session->objmgr.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);
}

View File

@ -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

View File

@ -2,7 +2,6 @@
Corpse::Corpse()
{
_uint32values=NULL;
_type=TYPE_CORPSE;
_typeid=TYPEID_CORPSE;
_valuescount=CORPSE_END;

View File

@ -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
{

View File

@ -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;

View File

@ -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);

View File

@ -3,10 +3,11 @@
#include "common.h"
#include <set>
#include "Object.h"
#include "Item.h"
#include "Unit.h"
typedef std::vector<ItemProto*> ItemProtoList;
typedef std::map<uint32,ItemProto*> ItemProtoMap;
typedef std::map<uint32,CreatureTemplate*> CreatureTemplateMap;
typedef std::map<uint64,Object*> 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<uint32> _noitem;
std::set<uint32> _reqpnames;
std::set<uint32> _nocreature;
PseuInstance *_instance;
};

View File

@ -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()

View File

@ -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;
};

View File

@ -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

View File

@ -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...
}
}

View File

@ -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

View File

@ -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<uint32> *zonelist=NULL, std::vector<std::string> *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

View File

@ -23,6 +23,21 @@
#include <list>
#include <map>
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 <typename T> 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;
}