From 442670af1617f895fcae9967da13100729a76391 Mon Sep 17 00:00:00 2001 From: false_genesis Date: Sat, 5 Jan 2008 17:58:43 +0000 Subject: [PATCH] * delay more packets with missing names * fixed problem with player name request looping * cleaned up channels in _enterworld.def * added MemoryDataHolder namespace, but not using it for now. will come handy in future (multi-instancing). UNTESTED yet! --- bin/scripts/_enterworld.def | 9 +- src/Client/MemoryDataHolder.cpp | 143 ++++++++++++++++++++++++++++++ src/Client/MemoryDataHolder.h | 14 +++ src/Client/World/Channel.cpp | 49 +++++----- src/Client/World/ObjMgr.cpp | 19 ++-- src/Client/World/ObjMgr.h | 12 ++- src/Client/World/UpdateData.cpp | 8 +- src/Client/World/WorldSession.cpp | 31 +++++-- src/Client/World/WorldSession.h | 4 + src/PseuWoW.vcproj | 6 ++ 10 files changed, 249 insertions(+), 46 deletions(-) create mode 100644 src/Client/MemoryDataHolder.cpp create mode 100644 src/Client/MemoryDataHolder.h diff --git a/bin/scripts/_enterworld.def b/bin/scripts/_enterworld.def index 0d7fa38..ce769e9 100644 --- a/bin/scripts/_enterworld.def +++ b/bin/scripts/_enterworld.def @@ -21,11 +21,10 @@ SAY [${@version_short}] login successful. EMOTE 126 // join some channels... -//JOINCHANNEL generalchat -//JOINCHANNEL help -//JOINCHANNEL tradee -//listchannel generalchat -// ... +JOINCHANNEL General +JOINCHANNEL LookingForGroup +// and a custom channel +JOINCHANNEL generlachat // Spell 836 = LoginEffect CASTSPELL 836 diff --git a/src/Client/MemoryDataHolder.cpp b/src/Client/MemoryDataHolder.cpp new file mode 100644 index 0000000..e6dca1d --- /dev/null +++ b/src/Client/MemoryDataHolder.cpp @@ -0,0 +1,143 @@ +#include +#include "MemoryDataHolder.h" +#include "DefScript/TypeStorage.h" + +namespace MemoryDataHolder +{ + class DataLoaderRunnable; + + ZThread::FastMutex mutex; + TypeStorage storage; + TypeStorage loaders; + + // instances of this class MUST be created with new-operator, or Destroy() will cause a crash! + class DataLoaderRunnable : public ZThread::Runnable + { + public: + DataLoaderRunnable() + { + _buf = NULL; + _threaded = false; + } + // the threaded part + void run() + { + uint32 size = GetFileSize(_name.c_str()); + // couldnt open file if size is 0 + if(!size) + { + logerror("DataLoaderRunnable: Error opening file: '%s'",_name.c_str()); + DoCallbacks(false); // call callback func, 'false' to indicate file coulsnt be loaded + Destroy(); + return; + } + _buf = new uint8[size]; + std::ifstream fh; + fh.open(_name.c_str(), std::ios_base::in | std::ios_base::binary); + if(!fh.is_open()) + { + logerror("DataLoaderRunnable: Error opening file: '%s'",_name.c_str()); + delete _buf; + _buf = NULL; + DoCallbacks(false); + Destroy(); + return; + } + fh.read((char*)_buf,size); + fh.close(); + storage.Assign(_name,&_buf); + loaders.UnlinkByPtr(this); // must be unlinked after the file is fully loaded, but before the callbacks are processed! + DoCallbacks(true); + Destroy(); + } + + inline void AddCallback(callback_func func, void *ptr = NULL) + { + _callbacks[func] = ptr; + } + inline void SetName(std::string name) + { + _name = name; + } + // if this class has done its work, delete self + inline void Destroy(void) + { + delete this; + } + inline uint8 *GetBuf(void) + { + return _buf; + } + inline void DoCallbacks(bool success = true) + { + for(std::map::iterator it = _callbacks.begin(); it != _callbacks.end(); it++) + { + (*(it->first))(it->second,success); + } + } + inline void SetThreaded(bool t) + { + _threaded = t; + } + inline bool IsThreaded(void) + { + return _threaded; + } + inline bool HasCallbackFunc(callback_func f) + { + return _callbacks.find(f) != _callbacks.end(); + } + + + private: + std::string _name; + std::map _callbacks; + uint8 *_buf; + bool _threaded; + }; + + + uint8 *GetFile(std::string s, bool threaded = false, callback_func func = NULL,void *ptr = NULL) + { + mutex.acquire(); // we need excusive access, other threads might unload the requested file during checking + if(uint8 **buf = storage.GetNoCreate(s)) + { + // the file was requested some other time, is still present in memory and the pointer can simply be returned + mutex.release(); // everything ok, mutex can be unloaded safely before returning + return *buf; + } + else + { + DataLoaderRunnable *r = loaders.GetNoCreate(s); + if(r == NULL) + { + // no loader thread is working on that file... + r = new DataLoaderRunnable(); + loaders.Assign(s,r); + r->AddCallback(func,ptr); // not threadsafe! + // after assigning/registering a new loader to the file, the mutex can be released safely + mutex.release(); + r->SetName(s); + r->SetThreaded(threaded); + if(threaded) + { + ZThread::Thread t(r); // start thread + } + else + { + r->run(); // will exit after the whole file is loaded and the (one) callback is run + return r->GetBuf(); + } + } + else // if a loader is already existing, add callbacks to that loader. + { + r->AddCallback(func,ptr); + mutex.release(); + } + } + return NULL; + } + + + +}; diff --git a/src/Client/MemoryDataHolder.h b/src/Client/MemoryDataHolder.h new file mode 100644 index 0000000..a5af5d3 --- /dev/null +++ b/src/Client/MemoryDataHolder.h @@ -0,0 +1,14 @@ +#ifndef MEMORYDATAHOLDER_H +#define MEMORYDATAHOLDER_H + +#include "common.h" + +namespace MemoryDataHolder +{ + typedef void (*callback_func)(void*,bool); + + + uint8 *GetFile(std::string&,bool,callback_func,void*); +}; + +#endif diff --git a/src/Client/World/Channel.cpp b/src/Client/World/Channel.cpp index 22b3e3c..ffa541e 100644 --- a/src/Client/World/Channel.cpp +++ b/src/Client/World/Channel.cpp @@ -137,12 +137,13 @@ void Channel::HandleNotifyOpcode(WorldPacket &packet) // Player joined channel you are on case JOINED: packet >> guid; - if(guid){ - name = _worldSession->plrNameCache.GetName(guid); + if(guid) + { + name = _worldSession->GetOrRequestPlayerName(guid); if (name.empty()) { - _worldSession->SendQueryPlayerName(guid); - name = "Unknown Entity"; + _worldSession->_DelayWorldPacket(packet,_worldSession->GetLagMS() * 1.2f); + return; } } @@ -152,13 +153,14 @@ void Channel::HandleNotifyOpcode(WorldPacket &packet) // Player leaved channel you are on case LEFT: packet >> guid; - if(guid){ - name = _worldSession->plrNameCache.GetName(guid); - if (name.empty()) - { - _worldSession->SendQueryPlayerName(guid); - name = "Unknown Entity"; - } + if(guid) + { + name = _worldSession->GetOrRequestPlayerName(guid); + if (name.empty()) + { + _worldSession->_DelayWorldPacket(packet,_worldSession->GetLagMS() * 1.2f); + return; + } } log("%s left channel %s", name.c_str(), channel.c_str()); @@ -222,28 +224,32 @@ void Channel::HandleListRequest(WorldPacket& recvPacket) std::string name; recvPacket >> unk >> name >> flags >> size; - // store list of GUIDs in: @ChannelList - DefList *l = _worldSession->GetInstance()->GetScripts()->lists.Get("@ChannelList"); - l->clear(); for(uint32 i = 0; i < size; i++) { recvPacket >> guid >> mode; + // all player names in this packet must be known before + if(_worldSession->GetOrRequestPlayerName(guid).empty()) + { + _worldSession->_DelayWorldPacket(recvPacket, _worldSession->GetLagMS() * 1.2f); + return; + } cpl[guid] = mode; - l->push_back(DefScriptTools::toString(guid)); } + // store list of GUIDs in: @ChannelList - see below + DefList *l = _worldSession->GetInstance()->GetScripts()->lists.Get("@ChannelList"); + l->clear(); + std::string pname; bool muted,mod; logcustom(0,WHITE,"Player channel list, %u players:",size); for(ChannelPlayerList::iterator i = cpl.begin(); i != cpl.end(); i++) { - pname = _worldSession->plrNameCache.GetName(i->first); + pname = _worldSession->GetOrRequestPlayerName(i->first); // all names should be known now mode = i->second; if(pname.empty()) - { - pname=""; - _worldSession->SendQueryPlayerName(i->first); - } + pname = ""; + muted = mode & MEMBER_FLAG_MUTED; mod = mode & MEMBER_FLAG_MODERATOR; @@ -251,6 +257,9 @@ void Channel::HandleListRequest(WorldPacket& recvPacket) pname += " "; // for better formatting logcustom(0,WHITE,"%s ["I64FMT"] %s %s",pname.c_str(),i->first,muted?"(muted)":"",mod?"(moderator)":""); + + // DefScript binding + l->push_back(DefScriptTools::toString(guid)); } } diff --git a/src/Client/World/ObjMgr.cpp b/src/Client/World/ObjMgr.cpp index 0948a76..8c5bc31 100644 --- a/src/Client/World/ObjMgr.cpp +++ b/src/Client/World/ObjMgr.cpp @@ -84,15 +84,20 @@ ItemProto *ObjMgr::GetItemProtoByPos(uint32 pos) void ObjMgr::AddNonexistentItem(uint32 id) { - _noitem.push_back(id); + _noitem.insert(id); } bool ObjMgr::ItemNonExistent(uint32 id) { - for(std::vector::iterator i=_noitem.begin(); i != _noitem.end(); i++) - { - if(*i == id) - return true; - } - return false; + return _noitem.find(id) == _noitem.end(); +} + +void ObjMgr::AddRequestedPlayerGUID(uint32 loguid) +{ + _reqpnames.insert(loguid); +} + +bool ObjMgr::IsRequestedPlayerGUID(uint32 loguid) +{ + return _reqpnames.find(loguid) != _reqpnames.end(); } diff --git a/src/Client/World/ObjMgr.h b/src/Client/World/ObjMgr.h index a085a4d..279a712 100644 --- a/src/Client/World/ObjMgr.h +++ b/src/Client/World/ObjMgr.h @@ -2,7 +2,7 @@ #define _OBJMGR_H #include "common.h" -#include +#include #include "Object.h" #include "Item.h" @@ -29,6 +29,13 @@ public: void AddNonexistentItem(uint32); bool ItemNonExistent(uint32); + // player names related + void AddRequestedPlayerGUID(uint32); + bool IsRequestedPlayerGUID(uint32); + inline void AddRequestedPlayerGUID(uint64 guid) { AddRequestedPlayerGUID(GUID_LOPART(guid)); } + inline bool IsRequestedPlayerGUID(uint64 guid) { return IsRequestedPlayerGUID(GUID_LOPART(guid)); } + + // Object functions void Add(Object*); void Remove(uint64); // remove all objects with that guid (should be only 1 object in total anyway) @@ -38,7 +45,8 @@ public: private: ItemProtoList _iproto; ObjectMap _obj; - std::vector _noitem; + std::set _noitem; + std::set _reqpnames; PseuInstance *_instance; }; diff --git a/src/Client/World/UpdateData.cpp b/src/Client/World/UpdateData.cpp index 2063a1a..c446cac 100644 --- a/src/Client/World/UpdateData.cpp +++ b/src/Client/World/UpdateData.cpp @@ -378,12 +378,8 @@ void WorldSession::_QueryObjectInfo(uint64 guid) } case TYPEID_PLAYER: { - std::string name = plrNameCache.GetName(guid); - if(name.empty()) - { - SendQueryPlayerName(guid); - } - else + std::string name = GetOrRequestPlayerName(obj->GetGUID()); + if(!name.empty()) { ((WorldObject*)obj)->SetName(name); } diff --git a/src/Client/World/WorldSession.cpp b/src/Client/World/WorldSession.cpp index c85abc6..46961fa 100644 --- a/src/Client/World/WorldSession.cpp +++ b/src/Client/World/WorldSession.cpp @@ -335,6 +335,27 @@ void WorldSession::_DoTimedActions(void) } } +std::string WorldSession::GetOrRequestPlayerName(uint64 guid) +{ + if(!guid || GUID_HIPART(guid) != HIGHGUID_PLAYER) + { + logerror("WorldSession::GetOrRequestObjectName: "I64FMT" is not player",guid); + return ""; // TODO: temporary, to find bugs with this, if there are any + } + std::string name = plrNameCache.GetName(guid); + if(name.empty()) + { + if(!objmgr.IsRequestedPlayerGUID(guid)) + { + objmgr.AddRequestedPlayerGUID(guid); + SendQueryPlayerName(guid); + } + } + return name; +} + + + /////////////////////////////////////////////////////////////// @@ -530,10 +551,9 @@ void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket) std::string plrname; if(source_guid) { - plrname=plrNameCache.GetName(source_guid); + plrname = GetOrRequestPlayerName(source_guid); if(plrname.empty()) { - SendQueryPlayerName(source_guid); _DelayWorldPacket(recvPacket, GetLagMS() * 1.2f); // guess time how long it will take until we got player name from the server return; // handle later } @@ -709,8 +729,8 @@ void WorldSession::_HandleNameQueryResponseOpcode(WorldPacket& recvPacket) if(plrNameCache.AddInfo(pguid,pname)) { logdetail("CACHE: Assigned new player name: '%s' = " I64FMTD ,pname.c_str(),pguid); - if(GetInstance()->GetConf()->debug > 1) - SendChatMessage(CHAT_MSG_SAY,0,"Player "+pname+" added to cache.",""); + //if(GetInstance()->GetConf()->debug > 1) + // SendChatMessage(CHAT_MSG_SAY,0,"Player "+pname+" added to cache.",""); } WorldObject *wo = (WorldObject*)objmgr.GetObj(pguid); if(wo) @@ -893,10 +913,9 @@ void WorldSession::_HandleEmoteOpcode(WorldPacket& recvPacket) // TODO: check if the emote came from a player or a mob, and query mob name if it was a mob if(guid) { - plrname=plrNameCache.GetName(guid); + plrname = GetOrRequestPlayerName(guid); if(plrname.empty()) { - SendQueryPlayerName(guid); _DelayWorldPacket(recvPacket, GetLagMS() * 1.2f); return; } diff --git a/src/Client/World/WorldSession.h b/src/Client/World/WorldSession.h index 4449c10..6aa0a58 100644 --- a/src/Client/World/WorldSession.h +++ b/src/Client/World/WorldSession.h @@ -42,6 +42,8 @@ typedef std::queue DelayedPacketQueue; class WorldSession { + friend class Channel; + public: WorldSession(PseuInstance *i); ~WorldSession(); @@ -66,6 +68,8 @@ public: inline MyCharacter *GetMyChar(void) { ASSERT(_myGUID > 0); return (MyCharacter*)objmgr.GetObj(_myGUID); } inline World *GetWorld(void) { return _world; } + std::string GetOrRequestPlayerName(uint64); + // CMSGConstructor void SendChatMessage(uint32 type, uint32 lang, std::string msg, std::string to=""); diff --git a/src/PseuWoW.vcproj b/src/PseuWoW.vcproj index 1856ad3..132797d 100644 --- a/src/PseuWoW.vcproj +++ b/src/PseuWoW.vcproj @@ -183,6 +183,12 @@ + + + +