* 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!
This commit is contained in:
false_genesis 2008-01-05 17:58:43 +00:00
parent 40cef66995
commit 442670af16
10 changed files with 249 additions and 46 deletions

View File

@ -21,11 +21,10 @@ SAY [${@version_short}] login successful.
EMOTE 126 EMOTE 126
// join some channels... // join some channels...
//JOINCHANNEL generalchat JOINCHANNEL General
//JOINCHANNEL help JOINCHANNEL LookingForGroup
//JOINCHANNEL tradee // and a custom channel
//listchannel generalchat JOINCHANNEL generlachat
// ...
// Spell 836 = LoginEffect // Spell 836 = LoginEffect
CASTSPELL 836 CASTSPELL 836

View File

@ -0,0 +1,143 @@
#include <fstream>
#include "MemoryDataHolder.h"
#include "DefScript/TypeStorage.h"
namespace MemoryDataHolder
{
class DataLoaderRunnable;
ZThread::FastMutex mutex;
TypeStorage<uint8*> storage;
TypeStorage<DataLoaderRunnable> 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<callback_func,void*>::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<callback_func, void*> _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;
}
};

View File

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

View File

@ -137,12 +137,13 @@ void Channel::HandleNotifyOpcode(WorldPacket &packet)
// Player joined channel you are on // Player joined channel you are on
case JOINED: case JOINED:
packet >> guid; packet >> guid;
if(guid){ if(guid)
name = _worldSession->plrNameCache.GetName(guid); {
name = _worldSession->GetOrRequestPlayerName(guid);
if (name.empty()) if (name.empty())
{ {
_worldSession->SendQueryPlayerName(guid); _worldSession->_DelayWorldPacket(packet,_worldSession->GetLagMS() * 1.2f);
name = "Unknown Entity"; return;
} }
} }
@ -152,13 +153,14 @@ void Channel::HandleNotifyOpcode(WorldPacket &packet)
// Player leaved channel you are on // Player leaved channel you are on
case LEFT: case LEFT:
packet >> guid; packet >> guid;
if(guid){ if(guid)
name = _worldSession->plrNameCache.GetName(guid); {
if (name.empty()) name = _worldSession->GetOrRequestPlayerName(guid);
{ if (name.empty())
_worldSession->SendQueryPlayerName(guid); {
name = "Unknown Entity"; _worldSession->_DelayWorldPacket(packet,_worldSession->GetLagMS() * 1.2f);
} return;
}
} }
log("%s left channel %s", name.c_str(), channel.c_str()); log("%s left channel %s", name.c_str(), channel.c_str());
@ -222,28 +224,32 @@ void Channel::HandleListRequest(WorldPacket& recvPacket)
std::string name; std::string name;
recvPacket >> unk >> name >> flags >> size; 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++) for(uint32 i = 0; i < size; i++)
{ {
recvPacket >> guid >> mode; 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; 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; std::string pname;
bool muted,mod; bool muted,mod;
logcustom(0,WHITE,"Player channel list, %u players:",size); logcustom(0,WHITE,"Player channel list, %u players:",size);
for(ChannelPlayerList::iterator i = cpl.begin(); i != cpl.end(); i++) 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; mode = i->second;
if(pname.empty()) if(pname.empty())
{ pname = "<unknown>";
pname="<unknown>";
_worldSession->SendQueryPlayerName(i->first);
}
muted = mode & MEMBER_FLAG_MUTED; muted = mode & MEMBER_FLAG_MUTED;
mod = mode & MEMBER_FLAG_MODERATOR; mod = mode & MEMBER_FLAG_MODERATOR;
@ -251,6 +257,9 @@ void Channel::HandleListRequest(WorldPacket& recvPacket)
pname += " "; // for better formatting pname += " "; // for better formatting
logcustom(0,WHITE,"%s ["I64FMT"] %s %s",pname.c_str(),i->first,muted?"(muted)":"",mod?"(moderator)":""); logcustom(0,WHITE,"%s ["I64FMT"] %s %s",pname.c_str(),i->first,muted?"(muted)":"",mod?"(moderator)":"");
// DefScript binding
l->push_back(DefScriptTools::toString(guid));
} }
} }

View File

@ -84,15 +84,20 @@ ItemProto *ObjMgr::GetItemProtoByPos(uint32 pos)
void ObjMgr::AddNonexistentItem(uint32 id) void ObjMgr::AddNonexistentItem(uint32 id)
{ {
_noitem.push_back(id); _noitem.insert(id);
} }
bool ObjMgr::ItemNonExistent(uint32 id) bool ObjMgr::ItemNonExistent(uint32 id)
{ {
for(std::vector<uint32>::iterator i=_noitem.begin(); i != _noitem.end(); i++) return _noitem.find(id) == _noitem.end();
{ }
if(*i == id)
return true; void ObjMgr::AddRequestedPlayerGUID(uint32 loguid)
} {
return false; _reqpnames.insert(loguid);
}
bool ObjMgr::IsRequestedPlayerGUID(uint32 loguid)
{
return _reqpnames.find(loguid) != _reqpnames.end();
} }

View File

@ -2,7 +2,7 @@
#define _OBJMGR_H #define _OBJMGR_H
#include "common.h" #include "common.h"
#include <list> #include <set>
#include "Object.h" #include "Object.h"
#include "Item.h" #include "Item.h"
@ -29,6 +29,13 @@ public:
void AddNonexistentItem(uint32); void AddNonexistentItem(uint32);
bool ItemNonExistent(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 // Object functions
void Add(Object*); void Add(Object*);
void Remove(uint64); // remove all objects with that guid (should be only 1 object in total anyway) void Remove(uint64); // remove all objects with that guid (should be only 1 object in total anyway)
@ -38,7 +45,8 @@ public:
private: private:
ItemProtoList _iproto; ItemProtoList _iproto;
ObjectMap _obj; ObjectMap _obj;
std::vector<uint32> _noitem; std::set<uint32> _noitem;
std::set<uint32> _reqpnames;
PseuInstance *_instance; PseuInstance *_instance;
}; };

View File

@ -378,12 +378,8 @@ void WorldSession::_QueryObjectInfo(uint64 guid)
} }
case TYPEID_PLAYER: case TYPEID_PLAYER:
{ {
std::string name = plrNameCache.GetName(guid); std::string name = GetOrRequestPlayerName(obj->GetGUID());
if(name.empty()) if(!name.empty())
{
SendQueryPlayerName(guid);
}
else
{ {
((WorldObject*)obj)->SetName(name); ((WorldObject*)obj)->SetName(name);
} }

View File

@ -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 "<ERR: OBJECT>"; // 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; std::string plrname;
if(source_guid) if(source_guid)
{ {
plrname=plrNameCache.GetName(source_guid); plrname = GetOrRequestPlayerName(source_guid);
if(plrname.empty()) 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 _DelayWorldPacket(recvPacket, GetLagMS() * 1.2f); // guess time how long it will take until we got player name from the server
return; // handle later return; // handle later
} }
@ -709,8 +729,8 @@ void WorldSession::_HandleNameQueryResponseOpcode(WorldPacket& recvPacket)
if(plrNameCache.AddInfo(pguid,pname)) if(plrNameCache.AddInfo(pguid,pname))
{ {
logdetail("CACHE: Assigned new player name: '%s' = " I64FMTD ,pname.c_str(),pguid); logdetail("CACHE: Assigned new player name: '%s' = " I64FMTD ,pname.c_str(),pguid);
if(GetInstance()->GetConf()->debug > 1) //if(GetInstance()->GetConf()->debug > 1)
SendChatMessage(CHAT_MSG_SAY,0,"Player "+pname+" added to cache.",""); // SendChatMessage(CHAT_MSG_SAY,0,"Player "+pname+" added to cache.","");
} }
WorldObject *wo = (WorldObject*)objmgr.GetObj(pguid); WorldObject *wo = (WorldObject*)objmgr.GetObj(pguid);
if(wo) 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 // TODO: check if the emote came from a player or a mob, and query mob name if it was a mob
if(guid) if(guid)
{ {
plrname=plrNameCache.GetName(guid); plrname = GetOrRequestPlayerName(guid);
if(plrname.empty()) if(plrname.empty())
{ {
SendQueryPlayerName(guid);
_DelayWorldPacket(recvPacket, GetLagMS() * 1.2f); _DelayWorldPacket(recvPacket, GetLagMS() * 1.2f);
return; return;
} }

View File

@ -42,6 +42,8 @@ typedef std::queue<DelayedWorldPacket> DelayedPacketQueue;
class WorldSession class WorldSession
{ {
friend class Channel;
public: public:
WorldSession(PseuInstance *i); WorldSession(PseuInstance *i);
~WorldSession(); ~WorldSession();
@ -66,6 +68,8 @@ public:
inline MyCharacter *GetMyChar(void) { ASSERT(_myGUID > 0); return (MyCharacter*)objmgr.GetObj(_myGUID); } inline MyCharacter *GetMyChar(void) { ASSERT(_myGUID > 0); return (MyCharacter*)objmgr.GetObj(_myGUID); }
inline World *GetWorld(void) { return _world; } inline World *GetWorld(void) { return _world; }
std::string GetOrRequestPlayerName(uint64);
// CMSGConstructor // CMSGConstructor
void SendChatMessage(uint32 type, uint32 lang, std::string msg, std::string to=""); void SendChatMessage(uint32 type, uint32 lang, std::string msg, std::string to="");

View File

@ -183,6 +183,12 @@
<File <File
RelativePath=".\Client\main.h"> RelativePath=".\Client\main.h">
</File> </File>
<File
RelativePath=".\Client\MemoryDataHolder.cpp">
</File>
<File
RelativePath=".\Client\MemoryDataHolder.h">
</File>
<File <File
RelativePath=".\Client\PseuWoW.cpp"> RelativePath=".\Client\PseuWoW.cpp">
</File> </File>