* 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:
False.Genesis 2007-12-09 21:46:52 +00:00
parent 1bd487445a
commit 79eec7c55e
5 changed files with 201 additions and 92 deletions

View File

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

View File

@ -47,5 +47,6 @@ DefReturnResult SCGetOpcodeID(CmdSet&);
DefReturnResult SCBBGetPackedGuid(CmdSet&);
DefReturnResult SCBBPutPackedGuid(CmdSet&);
DefReturnResult SCGui(CmdSet&);
DefReturnResult SCSendWho(CmdSet&);
#endif

View File

@ -173,6 +173,8 @@ void WorldSession::SendWhoListRequest(uint32 minlvl, uint32 maxlvl, uint32 racem
}
else
pkt << uint32(0);
SendWorldPacket(pkt);
}

View File

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

View File

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