* fixed: forgot to send packet in WS::SendWhoListRequest()
* added support for delayed packets. this fixes problems with e.g. unknown player names while handling a chat message. now the correct player name will always be displayed, even if not known before (e.g. whisper from other map, etc.) * fixed "gui" script cmd * added sendwho[,min,max,race,class,name,guild] script cmd
This commit is contained in:
parent
1bd487445a
commit
79eec7c55e
@ -56,6 +56,7 @@ void DefScriptPackage::_InitDefScriptInterface(void)
|
||||
AddFunc("bbgetpackedguid",&DefScriptPackage::SCBBGetPackedGuid);
|
||||
AddFunc("bbputpackedguid",&DefScriptPackage::SCBBPutPackedGuid);
|
||||
AddFunc("gui",&DefScriptPackage::SCGui);
|
||||
AddFunc("sendwho",DefScriptPackage::SCSendWho);
|
||||
}
|
||||
|
||||
DefReturnResult DefScriptPackage::SCshdn(CmdSet& Set)
|
||||
@ -970,10 +971,50 @@ DefReturnResult DefScriptPackage::SCGui(CmdSet &Set)
|
||||
}
|
||||
while(!ins->GetGUI() && !ins->GetGUI()->IsInitialized())
|
||||
Sleep(1);
|
||||
ins->GetGUI()->SetSceneState(SCENESTATE_GUISTART);
|
||||
// TODO: determine which SceneState to use here
|
||||
|
||||
// TODO: not sure if this piece of code will work as intended, needs some testing
|
||||
if(ins->GetWSession() && ins->GetWSession()->InWorld())
|
||||
ins->GetGUI()->SetSceneState(SCENESTATE_WORLD);
|
||||
else
|
||||
ins->GetGUI()->SetSceneState(SCENESTATE_GUISTART);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DefReturnResult DefScriptPackage::SCSendWho(CmdSet &Set)
|
||||
{
|
||||
WorldSession *ws = ((PseuInstance*)parentMethod)->GetWSession();
|
||||
if(!ws)
|
||||
{
|
||||
logerror("Invalid Script call: SCSendWhoListRequest: WorldSession not valid");
|
||||
DEF_RETURN_ERROR;
|
||||
}
|
||||
uint32 minlvl = (uint32)DefScriptTools::toUint64(Set.arg[0]);
|
||||
uint32 maxlvl = (uint32)DefScriptTools::toUint64(Set.arg[1]);
|
||||
uint32 racemask = (uint32)DefScriptTools::toUint64(Set.arg[2]);
|
||||
uint32 classmask = (uint32)DefScriptTools::toUint64(Set.arg[3]);
|
||||
std::string name = Set.arg[4];
|
||||
std::string guildname = Set.arg[5];
|
||||
// TODO: implement zonelist
|
||||
|
||||
// convert empty string (default: 0) to default expected by server (-1 = 0xFFFFFFFF = all)
|
||||
// and do some values cleanup
|
||||
if(!racemask)
|
||||
racemask = -1;
|
||||
if(!classmask)
|
||||
classmask = -1;
|
||||
if(!maxlvl)
|
||||
maxlvl = 100;
|
||||
else if(maxlvl > 255)
|
||||
maxlvl = 255;
|
||||
if(minlvl > 255)
|
||||
minlvl = 255;
|
||||
if(minlvl > maxlvl)
|
||||
minlvl = maxlvl;
|
||||
|
||||
ws->SendWhoListRequest(minlvl,maxlvl,racemask,classmask,name,guildname);
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
void DefScriptPackage::My_LoadUserPermissions(VarSet &vs)
|
||||
|
||||
@ -47,5 +47,6 @@ DefReturnResult SCGetOpcodeID(CmdSet&);
|
||||
DefReturnResult SCBBGetPackedGuid(CmdSet&);
|
||||
DefReturnResult SCBBPutPackedGuid(CmdSet&);
|
||||
DefReturnResult SCGui(CmdSet&);
|
||||
DefReturnResult SCSendWho(CmdSet&);
|
||||
|
||||
#endif
|
||||
|
||||
@ -173,6 +173,8 @@ void WorldSession::SendWhoListRequest(uint32 minlvl, uint32 maxlvl, uint32 racem
|
||||
}
|
||||
else
|
||||
pkt << uint32(0);
|
||||
|
||||
SendWorldPacket(pkt);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -19,7 +19,6 @@ struct OpcodeHandler
|
||||
void (WorldSession::*handler)(WorldPacket& recvPacket);
|
||||
};
|
||||
|
||||
|
||||
WorldSession::WorldSession(PseuInstance *in)
|
||||
{
|
||||
logdebug("-> Starting WorldSession 0x%X from instance 0x%X",this,in); // should never output a null ptr
|
||||
@ -32,6 +31,7 @@ WorldSession::WorldSession(PseuInstance *in)
|
||||
_world = new World(this);
|
||||
_sh.SetAutoCloseSockets(false);
|
||||
objmgr.SetInstance(in);
|
||||
_lag_ms = 0;
|
||||
//...
|
||||
|
||||
DEBUG(logdebug("WorldSession 0x%X constructor finished",this));
|
||||
@ -113,78 +113,84 @@ void WorldSession::Update(void)
|
||||
}
|
||||
}
|
||||
|
||||
DefScriptPackage *sc = GetInstance()->GetScripts();
|
||||
|
||||
OpcodeHandler *table = _GetOpcodeHandlerTable();
|
||||
|
||||
uint16 hpos;
|
||||
bool known=false;
|
||||
|
||||
// while there are packets on the queue, handle them
|
||||
while(pktQueue.size())
|
||||
{
|
||||
WorldPacket *packet = pktQueue.next();
|
||||
|
||||
for (hpos = 0; table[hpos].handler != NULL; hpos++)
|
||||
{
|
||||
if (table[hpos].opcode == packet->GetOpcode())
|
||||
{
|
||||
known=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool hideOpcode = false;
|
||||
|
||||
// TODO: Maybe make table or something with all the frequently opcodes
|
||||
if (packet->GetOpcode() == SMSG_MONSTER_MOVE)
|
||||
{
|
||||
hideOpcode = true;
|
||||
}
|
||||
|
||||
if( (known && GetInstance()->GetConf()->showopcodes==1)
|
||||
|| ((!known) && GetInstance()->GetConf()->showopcodes==2)
|
||||
|| (GetInstance()->GetConf()->showopcodes==3) )
|
||||
{
|
||||
if(!(GetInstance()->GetConf()->hidefreqopcodes && hideOpcode))
|
||||
logcustom(1,YELLOW,">> Opcode %u [%s] (%s, %u bytes)", packet->GetOpcode(), GetOpcodeName(packet->GetOpcode()), known ? "Known" : "UNKNOWN", packet->size());
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// call the opcode handler
|
||||
if(known)
|
||||
(this->*table[hpos].handler)(*packet);
|
||||
|
||||
// if there is a script attached to that opcode, call it now.
|
||||
// note: the pkt rpos needs to be reset in by the scripts!
|
||||
std::string scname = "opcode::";
|
||||
scname += stringToLower(GetOpcodeName(packet->GetOpcode()));
|
||||
if(sc->ScriptExists(scname))
|
||||
{
|
||||
std::string pktname = "PACKET::";
|
||||
pktname += GetOpcodeName(packet->GetOpcode());
|
||||
GetInstance()->GetScripts()->bytebuffers.Assign(pktname,packet);
|
||||
sc->RunScript(scname,NULL);
|
||||
GetInstance()->GetScripts()->bytebuffers.Unlink(pktname);
|
||||
}
|
||||
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
logerror("Exception while handling opcode %u!",packet->GetOpcode());
|
||||
logerror("Data: pktsize=%u, handler=0x%X queuesize=%u",packet->size(),table[hpos].handler,pktQueue.size());
|
||||
}
|
||||
|
||||
delete packet;
|
||||
known=false;
|
||||
HandleWorldPacket(pktQueue.next());
|
||||
}
|
||||
|
||||
// now check if there are packets that couldnt be handled earlier due to missing data
|
||||
_HandleDelayedPackets();
|
||||
|
||||
_DoTimedActions();
|
||||
|
||||
if(_world)
|
||||
_world->Update();
|
||||
}
|
||||
|
||||
// this func will delete the WorldPacket after it is handled!
|
||||
void WorldSession::HandleWorldPacket(WorldPacket *packet)
|
||||
{
|
||||
static DefScriptPackage *sc = GetInstance()->GetScripts();
|
||||
static OpcodeHandler *table = _GetOpcodeHandlerTable();
|
||||
|
||||
bool known = false;
|
||||
uint16 hpos;
|
||||
|
||||
for (hpos = 0; table[hpos].handler != NULL; hpos++)
|
||||
{
|
||||
if (table[hpos].opcode == packet->GetOpcode())
|
||||
{
|
||||
known=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool hideOpcode = false;
|
||||
|
||||
// TODO: Maybe make table or something with all the frequently opcodes
|
||||
if (packet->GetOpcode() == SMSG_MONSTER_MOVE)
|
||||
{
|
||||
hideOpcode = true;
|
||||
}
|
||||
|
||||
if( (known && GetInstance()->GetConf()->showopcodes==1)
|
||||
|| ((!known) && GetInstance()->GetConf()->showopcodes==2)
|
||||
|| (GetInstance()->GetConf()->showopcodes==3) )
|
||||
{
|
||||
if(!(GetInstance()->GetConf()->hidefreqopcodes && hideOpcode))
|
||||
logcustom(1,YELLOW,">> Opcode %u [%s] (%s, %u bytes)", packet->GetOpcode(), GetOpcodeName(packet->GetOpcode()), known ? "Known" : "UNKNOWN", packet->size());
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// call the opcode handler
|
||||
if(known)
|
||||
(this->*table[hpos].handler)(*packet);
|
||||
|
||||
// if there is a script attached to that opcode, call it now.
|
||||
// note: the pkt rpos needs to be reset in by the scripts!
|
||||
std::string scname = "opcode::";
|
||||
scname += stringToLower(GetOpcodeName(packet->GetOpcode()));
|
||||
if(sc->ScriptExists(scname))
|
||||
{
|
||||
std::string pktname = "PACKET::";
|
||||
pktname += GetOpcodeName(packet->GetOpcode());
|
||||
GetInstance()->GetScripts()->bytebuffers.Assign(pktname,packet);
|
||||
sc->RunScript(scname,NULL);
|
||||
GetInstance()->GetScripts()->bytebuffers.Unlink(pktname);
|
||||
}
|
||||
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
logerror("Exception while handling opcode %u!",packet->GetOpcode());
|
||||
logerror("Data: pktsize=%u, handler=0x%X queuesize=%u",packet->size(),table[hpos].handler,pktQueue.size());
|
||||
}
|
||||
|
||||
delete packet;
|
||||
}
|
||||
|
||||
|
||||
OpcodeHandler *WorldSession::_GetOpcodeHandlerTable() const
|
||||
{
|
||||
@ -243,6 +249,41 @@ OpcodeHandler *WorldSession::_GetOpcodeHandlerTable() const
|
||||
return table;
|
||||
}
|
||||
|
||||
void WorldSession::_DelayWorldPacket(WorldPacket& pkt, uint32 ms)
|
||||
{
|
||||
DEBUG(logdebug("DelayWorldPacket (%s, size: %u, ms: %u)",GetOpcodeName(pkt.GetOpcode()),pkt.size(),ms));
|
||||
// need to copy the packet, because the current packet will be deleted after it got handled
|
||||
WorldPacket *pktcopy = new WorldPacket(pkt.GetOpcode(),pkt.size());
|
||||
pktcopy->append(pkt.contents(),pkt.size());
|
||||
delayedPktQueue.push(DelayedWorldPacket(pktcopy,ms));
|
||||
DEBUG(logdebug("-> WP ptr = 0x%X",pktcopy));
|
||||
}
|
||||
|
||||
void WorldSession::_HandleDelayedPackets(void)
|
||||
{
|
||||
if(delayedPktQueue.size())
|
||||
{
|
||||
DelayedPacketQueue copy(delayedPktQueue);
|
||||
while(delayedPktQueue.size())
|
||||
delayedPktQueue.pop(); // clear original, since it might be filled up by newly delayed packets, which would cause endless loop
|
||||
while(copy.size())
|
||||
{
|
||||
DelayedWorldPacket d = copy.front();
|
||||
copy.c.pop_front(); // remove packet from front, std::queue seems not to have a func for it
|
||||
if(clock() >= d.when) // if its time to handle this packet, do so
|
||||
{
|
||||
DEBUG(logdebug("Handling delayed packet (%s [%u], size: %u, ptr: 0x%X)",GetOpcodeName(d.pkt->GetOpcode()),d.pkt->GetOpcode(),d.pkt->size(),d.pkt));
|
||||
HandleWorldPacket(d.pkt);
|
||||
}
|
||||
else
|
||||
{
|
||||
delayedPktQueue.push(d); // and if not, put it again onto the queue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WorldSession::SetTarget(uint64 guid)
|
||||
{
|
||||
SendSetSelection(guid);
|
||||
@ -482,7 +523,8 @@ void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket)
|
||||
if(plrname.empty())
|
||||
{
|
||||
SendQueryPlayerName(source_guid);
|
||||
plrname="Unknown Entity";
|
||||
_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);
|
||||
@ -668,8 +710,9 @@ void WorldSession::_HandlePongOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
uint32 pong;
|
||||
recvPacket >> pong;
|
||||
_lag_ms = clock() - pong;
|
||||
if(GetInstance()->GetConf()->notifyping)
|
||||
log("Recieved Ping reply: %u ms latency.",clock()-pong);
|
||||
log("Recieved Ping reply: %u ms latency.", _lag_ms);
|
||||
}
|
||||
void WorldSession::_HandleTradeStatusOpcode(WorldPacket& recvPacket)
|
||||
{
|
||||
@ -964,7 +1007,7 @@ void WorldSession::_HandleLoginVerifyWorldOpcode(WorldPacket& recvPacket)
|
||||
|
||||
ByteBuffer& operator>>(ByteBuffer& bb, WhoListEntry& e)
|
||||
{
|
||||
bb >> e.name >> e.level >> e.classId >> e.raceId, e.zoneId;
|
||||
bb >> e.name >> e.gname >> e.level >> e.classId >> e.raceId >> e.zoneId;
|
||||
return bb;
|
||||
}
|
||||
|
||||
@ -974,12 +1017,11 @@ void WorldSession::_HandleWhoOpcode(WorldPacket& recvPacket)
|
||||
recvPacket >> count >> unk;
|
||||
|
||||
log("Got WHO-List, %u players. (unk=%u)",count,unk);
|
||||
WhoListEntry wle;
|
||||
|
||||
if(count >= 1)
|
||||
{
|
||||
log(" Name |Level| Class | Race | Zone");
|
||||
log("--------------+-----+----------+----------+----------------");
|
||||
log(" Name |Level| Class | Race | Zone; Guild");
|
||||
log("--------------+-----+------------+--------------+----------------");
|
||||
if(count > 1)
|
||||
{
|
||||
_whoList.clear(); // need to clear current list only if requesting more then one player name
|
||||
@ -988,30 +1030,35 @@ void WorldSession::_HandleWhoOpcode(WorldPacket& recvPacket)
|
||||
|
||||
for(uint32 i = 0; i < count; i++)
|
||||
{
|
||||
WhoListEntry wle;
|
||||
recvPacket >> wle;
|
||||
|
||||
_whoList.push_back(wle);
|
||||
|
||||
// original WhoListEntry is saved, now do some formatting
|
||||
while(wle.name.length() < 12)
|
||||
wle.name += ' ';
|
||||
while(wle.name.length() < 13)
|
||||
wle.name.append(" ");
|
||||
|
||||
SCPDatabaseMgr& db = GetInstance()->dbmgr;
|
||||
std::string zonename = db.GetZoneName(wle.zoneId);
|
||||
std::string classname = db.GetClassName_(wle.classId);
|
||||
std::string racename = db.GetRaceName(wle.raceId);
|
||||
char classname[20], racename[20];
|
||||
std::string zonename;
|
||||
memset(classname,0,sizeof(classname));
|
||||
memset(racename,0,sizeof(racename));
|
||||
zonename = db.GetZoneName(wle.zoneId);
|
||||
strcpy(classname, db.GetClassName_(wle.classId).c_str());
|
||||
strcpy(racename, db.GetRaceName(wle.raceId).c_str());
|
||||
|
||||
while(classname.length() < 8)
|
||||
classname += ' ';
|
||||
while(racename.length() < 8)
|
||||
racename += ' ';
|
||||
for(uint8 i = strlen(classname); strlen(classname) < 10; i++)
|
||||
classname[i] = ' ';
|
||||
for(uint8 i = strlen(racename); strlen(racename) < 12; i++)
|
||||
racename[i] = ' ';
|
||||
char tmp[12];
|
||||
sprintf(tmp,"%u",wle.level);
|
||||
std::string lvl_str = tmp;
|
||||
while(lvl_str.length() < 3)
|
||||
lvl_str = " " + lvl_str;
|
||||
|
||||
log("%s | %s | %s | %s | %s", wle.name.c_str(), lvl_str.c_str(), classname.c_str(), racename.c_str(), zonename.c_str() );
|
||||
log("%s | %s | %s | %s | %s; %s", wle.name.c_str(), lvl_str.c_str(), classname, racename, zonename.c_str(), wle.gname.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
#ifndef _WORLDSESSION_H
|
||||
#define _WORLDSESSION_H
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "common.h"
|
||||
#include "PseuWoW.h"
|
||||
#include "Network/SocketHandler.h"
|
||||
@ -20,13 +22,23 @@ class World;
|
||||
struct WhoListEntry
|
||||
{
|
||||
std::string name;
|
||||
std::string gname;
|
||||
uint32 level;
|
||||
uint32 classId;
|
||||
uint32 raceId;
|
||||
uint32 zoneId;
|
||||
};
|
||||
|
||||
struct DelayedWorldPacket
|
||||
{
|
||||
DelayedWorldPacket() { pkt = NULL; when = clock(); }
|
||||
DelayedWorldPacket(WorldPacket *p, uint32 ms) { pkt = p; when = ms + clock(); }
|
||||
WorldPacket *pkt;
|
||||
clock_t when;
|
||||
};
|
||||
|
||||
typedef std::vector<WhoListEntry> WhoList;
|
||||
typedef std::queue<DelayedWorldPacket> DelayedPacketQueue;
|
||||
|
||||
class WorldSession
|
||||
{
|
||||
@ -35,23 +47,24 @@ public:
|
||||
~WorldSession();
|
||||
void Init(void);
|
||||
|
||||
PseuInstance *GetInstance(void) { return _instance; }
|
||||
SCPDatabaseMgr& GetDBMgr(void) { return GetInstance()->dbmgr; }
|
||||
inline PseuInstance *GetInstance(void) { return _instance; }
|
||||
inline SCPDatabaseMgr& GetDBMgr(void) { return GetInstance()->dbmgr; }
|
||||
|
||||
void AddToPktQueue(WorldPacket *pkt);
|
||||
void Update(void);
|
||||
void Start(void);
|
||||
bool MustDie(void) { return _mustdie; }
|
||||
void SetMustDie(void) { _mustdie = true; }
|
||||
inline bool MustDie(void) { return _mustdie; }
|
||||
inline void SetMustDie(void) { _mustdie = true; }
|
||||
void SendWorldPacket(WorldPacket&);
|
||||
bool InWorld(void) { return _logged; }
|
||||
inline bool InWorld(void) { return _logged; }
|
||||
inline uint32 GetLagMS(void) { return _lag_ms; }
|
||||
|
||||
void SetTarget(uint64 guid);
|
||||
uint64 GetTarget(void) { return GetMyChar()->GetTarget(); }
|
||||
uint64 GetGuid(void) { return _myGUID; }
|
||||
Channel *GetChannels(void) { return _channels; }
|
||||
MyCharacter *GetMyChar(void) { ASSERT(_myGUID > 0); return (MyCharacter*)objmgr.GetObj(_myGUID); }
|
||||
World *GetWorld(void) { return _world; }
|
||||
inline uint64 GetTarget(void) { return GetMyChar() ? GetMyChar()->GetTarget() : 0; }
|
||||
inline uint64 GetGuid(void) { return _myGUID; }
|
||||
inline Channel *GetChannels(void) { return _channels; }
|
||||
inline MyCharacter *GetMyChar(void) { ASSERT(_myGUID > 0); return (MyCharacter*)objmgr.GetObj(_myGUID); }
|
||||
inline World *GetWorld(void) { return _world; }
|
||||
|
||||
|
||||
// CMSGConstructor
|
||||
@ -64,6 +77,7 @@ public:
|
||||
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 HandleWorldPacket(WorldPacket*);
|
||||
|
||||
PlayerNameCache plrNameCache;
|
||||
ObjMgr objmgr;
|
||||
@ -75,7 +89,9 @@ private:
|
||||
void _OnEnterWorld(void); // = login
|
||||
void _OnLeaveWorld(void); // = logout
|
||||
void _DoTimedActions(void);
|
||||
|
||||
void _DelayWorldPacket(WorldPacket&, uint32);
|
||||
void _HandleDelayedPackets(void);
|
||||
|
||||
// Opcode Handlers
|
||||
void _HandleAuthChallengeOpcode(WorldPacket& recvPacket);
|
||||
void _HandleAuthResponseOpcode(WorldPacket& recvPacket);
|
||||
@ -117,12 +133,14 @@ private:
|
||||
PseuInstance *_instance;
|
||||
WorldSocket *_socket;
|
||||
ZThread::LockedQueue<WorldPacket*,ZThread::FastMutex> pktQueue;
|
||||
DelayedPacketQueue delayedPktQueue;
|
||||
bool _logged,_mustdie; // world status
|
||||
SocketHandler _sh; // handles the WorldSocket
|
||||
Channel *_channels;
|
||||
uint64 _myGUID;
|
||||
World *_world;
|
||||
WhoList _whoList;
|
||||
uint32 _lag_ms;
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
x
Reference in New Issue
Block a user