From d295e30b3f8f8bce5fd3bfa18f79fdc5b94067ff Mon Sep 17 00:00:00 2001 From: false_genesis Date: Tue, 19 Feb 2008 20:01:50 +0000 Subject: [PATCH] * added possibility to disable handling of incoming opcodes by the core (they will still be handled if a script is assigned!) * script command: switchopcodehandler, true(on)/false(off) * added script events _onworldsessioncreate/delete * added new conf option: HideDisabledOpcodes=1/0 * added possibility to spoof worldpackets --- bin/conf/PseuWoW.conf.default | 4 + bin/scripts/__core_eventstubs.def | 17 ++++ src/Client/DefScriptInterface.cpp | 135 +++++++++++++++++++++---- src/Client/DefScriptInterfaceInclude.h | 3 + src/Client/PseuWoW.cpp | 1 + src/Client/PseuWoW.h | 1 + src/Client/World/CacheHandler.cpp | 3 + src/Client/World/WorldSession.cpp | 38 +++++-- src/Client/World/WorldSession.h | 9 ++ 9 files changed, 183 insertions(+), 28 deletions(-) diff --git a/bin/conf/PseuWoW.conf.default b/bin/conf/PseuWoW.conf.default index e1796d7..39b0bea 100644 --- a/bin/conf/PseuWoW.conf.default +++ b/bin/conf/PseuWoW.conf.default @@ -35,6 +35,10 @@ showopcodes=3 // 0 - No hidefreqopcodes=1 +// Hide disabled (= unhandled, but known) opcodes? +// 1 - Yes +// 0 - No +HideDisabledOpcodes=0 // the IP or hostname the realm server is running on realmlist=localhost diff --git a/bin/scripts/__core_eventstubs.def b/bin/scripts/__core_eventstubs.def index db1754a..109fa57 100644 --- a/bin/scripts/__core_eventstubs.def +++ b/bin/scripts/__core_eventstubs.def @@ -94,3 +94,20 @@ SAY Forget it, ${@0}, you have only permission ${@1} but need ${@2} to run the s LOG Player '${@0}' (p:${@1}) wanted to execute '${@3}' (p:${@2}) EMOTE 66 // say NO! + + +// ----==== INTERNAL/MISC ====---- + +#script=_onworldsessioncreate +// no args. called when an instance of the WorldSession class is created + +//- script content here + + +#script=_onworldsessiondelete +// no args. called when an instance of the WorldSession class is deleted + +//- script content here + + + diff --git a/src/Client/DefScriptInterface.cpp b/src/Client/DefScriptInterface.cpp index 18eea79..3dd2845 100644 --- a/src/Client/DefScriptInterface.cpp +++ b/src/Client/DefScriptInterface.cpp @@ -58,6 +58,9 @@ void DefScriptPackage::_InitDefScriptInterface(void) AddFunc("gui",&DefScriptPackage::SCGui); AddFunc("sendwho",&DefScriptPackage::SCSendWho); AddFunc("getobjectdist",&DefScriptPackage::SCGetObjectDistance); + AddFunc("switchopcodehandler",&DefScriptPackage::SCSwitchOpcodeHandler); + AddFunc("opcodedisabled",&DefScriptPackage::SCOpcodeDisabled); + AddFunc("spoofworldpacket",&DefScriptPackage::SCSpoofWorldPacket); } DefReturnResult DefScriptPackage::SCshdn(CmdSet& Set) @@ -278,16 +281,18 @@ DefReturnResult DefScriptPackage::SCcastspell(CmdSet& Set) return true; } -DefReturnResult DefScriptPackage::SCqueryitem(CmdSet& Set){ - uint32 id = atoi(Set.defaultarg.c_str()); - if(!id) - return false; - +DefReturnResult DefScriptPackage::SCqueryitem(CmdSet& Set) +{ if(!(((PseuInstance*)parentMethod)->GetWSession())) { logerror("Invalid Script call: SCqueryitem: WorldSession not valid"); DEF_RETURN_ERROR; } + + uint32 id = atoi(Set.defaultarg.c_str()); + if(!id) + return false; + ((PseuInstance*)parentMethod)->GetWSession()->SendQueryItem(id,0); return true; } @@ -295,9 +300,8 @@ DefReturnResult DefScriptPackage::SCqueryitem(CmdSet& Set){ DefReturnResult DefScriptPackage::SCtarget(CmdSet& Set) { // TODO: special targets: _self _pet _nearest ... - DefReturnResult r; - - if(!(((PseuInstance*)parentMethod)->GetWSession())) + WorldSession *ws = ((PseuInstance*)parentMethod)->GetWSession(); + if(!ws) { logerror("Invalid Script call: SCtarget: WorldSession not valid"); DEF_RETURN_ERROR; @@ -309,21 +313,30 @@ DefReturnResult DefScriptPackage::SCtarget(CmdSet& Set) return true; } - // TODO: search through all objects. for now only allow to target player - uint64 guid = (((PseuInstance*)parentMethod)->GetWSession()->plrNameCache.GetGuid(Set.defaultarg)); - - if( guid && ((PseuInstance*)parentMethod)->GetWSession()->objmgr.GetObj(guid) ) // object must be near + std::string what = stringToLower(Set.arg[0]); + uint64 guid = 0; + if(what == "guid") { - ((PseuInstance*)parentMethod)->GetWSession()->SendSetSelection(guid); // will also set the target for myCharacter - r.ret=toString(guid); + guid = DefScriptTools::toUint64(Set.defaultarg); + } + else if(what.empty() || what == "player") + { + // TODO: search through all objects. for now only allow to target player + guid = ws->plrNameCache.GetGuid(Set.defaultarg); + } + + Object *obj = ws->objmgr.GetObj(guid); + if(obj && obj->IsUnit() || obj->IsCorpse()) // only units and corpses are targetable + { + ws->SendSetSelection(guid); // will also set the target for myCharacter + return toString(guid); } else { logdetail("Target '%s' not found!",Set.defaultarg.c_str()); return false; } - - return r; + return ""; } DefReturnResult DefScriptPackage::SCloadscp(CmdSet& Set) @@ -899,10 +912,16 @@ DefReturnResult DefScriptPackage::SCSendWorldPacket(CmdSet &Set) ByteBuffer *bb = bytebuffers.GetNoCreate(_NormalizeVarName(Set.defaultarg,Set.myname)); if(bb) { - uint32 opcode = (uint32)DefScriptTools::toNumber(Set.arg[0]); - if(opcode) // prevent sending CMSG_NULL_ACTION + uint16 opc = (uint16)DefScriptTools::toUint64(Set.arg[0]); + if(!opc) { - WorldPacket wp(opcode, bb->size()); + opc = (uint16)GetOpcodeID(Set.arg[0].c_str()); + if(opc == uint16(-1)) + return false; + } + if(opc) // prevent sending CMSG_NULL_ACTION + { + WorldPacket wp(opc, bb->size()); if(bb->size()) wp.append(bb->contents(), bb->size()); ws->SendWorldPacket(wp); @@ -1064,6 +1083,84 @@ DefReturnResult DefScriptPackage::SCGetObjectDistance(CmdSet &Set) return ""; } +DefReturnResult DefScriptPackage::SCSwitchOpcodeHandler(CmdSet &Set) +{ + WorldSession *ws = ((PseuInstance*)parentMethod)->GetWSession(); + if(!ws) + { + logerror("Invalid Script call: SCRemoveOpcodeHandler: WorldSession not valid"); + DEF_RETURN_ERROR; + } + uint16 opc = (uint16)DefScriptTools::toUint64(Set.arg[0]); + bool switchon = DefScriptTools::isTrue(Set.defaultarg); + if(!opc) // ok we cant turn off MSG_NULL_ACTION with this, but who needs it anyway... + { + opc = (uint16)GetOpcodeID(Set.arg[0].c_str()); + if(opc == uint16(-1)) + return false; + } + else if(opc >= MAX_OPCODE_ID) + { + logerror("Can't enable/disable opcode handling of %u", opc); + return false; + } + if(switchon) + ws->EnableOpcode(opc); + else + ws->DisableOpcode(opc); + + logdebug("Opcode handler for %s (%u) %s",GetOpcodeName(opc), opc, switchon ? "enabled" : "disabled"); + return true; +} + +DefReturnResult DefScriptPackage::SCOpcodeDisabled(CmdSet &Set) +{ + WorldSession *ws = ((PseuInstance*)parentMethod)->GetWSession(); + if(!ws) + { + logerror("Invalid Script call: SCOpcodeDisabled: WorldSession not valid"); + DEF_RETURN_ERROR; + } + uint16 opc = (uint16)DefScriptTools::toUint64(Set.defaultarg); + if(!opc) + { + opc = (uint16)GetOpcodeID(Set.arg[0].c_str()); + if(opc == uint16(-1)) + return false; + } + else if(opc >= MAX_OPCODE_ID) + { + logerror("SCOpcodeDisabled: Opcode %u out of range", opc); + return false; // we can NEVER handle out of range opcode, but since its not disabled, return false + } + return ws->IsOpcodeDisabled(opc); +} + +DefReturnResult DefScriptPackage::SCSpoofWorldPacket(CmdSet &Set) +{ + WorldSession *ws = ((PseuInstance*)parentMethod)->GetWSession(); + if(!ws) + { + logerror("Invalid Script call: SCSpoofWorldPacket: WorldSession not valid"); + DEF_RETURN_ERROR; + } + ByteBuffer *bb = bytebuffers.GetNoCreate(_NormalizeVarName(Set.defaultarg,Set.myname)); + if(bb) + { + uint32 opcode = (uint32)DefScriptTools::toNumber(Set.arg[0]); + if(opcode) // ok, here again CMSG_NULL_ACTION doesnt work, but who cares + { + WorldPacket *wp = new WorldPacket(opcode, bb->size()); // will be deleted by the opcode handler later + if(bb->size()) + wp->append(bb->contents(), bb->size()); + logdebug("Spoofing WorldPacket with opcode %s (%u), size %u",GetOpcodeName(opcode),opcode,wp->size()); + ws->AddToPktQueue(wp); // handle this packet as if it was sent by the server + return true; + } + } + return false; +} + void DefScriptPackage::My_LoadUserPermissions(VarSet &vs) { static char *prefix = "USERS::"; diff --git a/src/Client/DefScriptInterfaceInclude.h b/src/Client/DefScriptInterfaceInclude.h index c18da95..5e8d228 100644 --- a/src/Client/DefScriptInterfaceInclude.h +++ b/src/Client/DefScriptInterfaceInclude.h @@ -49,5 +49,8 @@ DefReturnResult SCBBPutPackedGuid(CmdSet&); DefReturnResult SCGui(CmdSet&); DefReturnResult SCSendWho(CmdSet&); DefReturnResult SCGetObjectDistance(CmdSet&); +DefReturnResult SCSwitchOpcodeHandler(CmdSet&); +DefReturnResult SCOpcodeDisabled(CmdSet&); +DefReturnResult SCSpoofWorldPacket(CmdSet&); #endif diff --git a/src/Client/PseuWoW.cpp b/src/Client/PseuWoW.cpp index eeaa764..8c980db 100644 --- a/src/Client/PseuWoW.cpp +++ b/src/Client/PseuWoW.cpp @@ -404,6 +404,7 @@ void PseuInstanceConf::ApplyFromVarSet(VarSet &v) networksleeptime=atoi(v.Get("NETWORKSLEEPTIME").c_str()); showopcodes=atoi(v.Get("SHOWOPCODES").c_str()); hidefreqopcodes=(bool)atoi(v.Get("HIDEFREQOPCODES").c_str()); + hideDisabledOpcodes=(bool)atoi(v.Get("HIDEDISABLEDOPCODES").c_str()); enablecli=(bool)atoi(v.Get("ENABLECLI").c_str()); allowgamecmd=(bool)atoi(v.Get("ALLOWGAMECMD").c_str()); enablechatai=(bool)atoi(v.Get("ENABLECHATAI").c_str()); diff --git a/src/Client/PseuWoW.h b/src/Client/PseuWoW.h index 034a462..6eb8215 100644 --- a/src/Client/PseuWoW.h +++ b/src/Client/PseuWoW.h @@ -45,6 +45,7 @@ class PseuInstanceConf uint16 networksleeptime; uint8 showopcodes; bool hidefreqopcodes; + bool hideDisabledOpcodes; bool allowgamecmd; bool enablecli; bool enablechatai; diff --git a/src/Client/World/CacheHandler.cpp b/src/Client/World/CacheHandler.cpp index 15dfedd..52f7089 100644 --- a/src/Client/World/CacheHandler.cpp +++ b/src/Client/World/CacheHandler.cpp @@ -140,6 +140,7 @@ bool PlayerNameCache::ReadFromFile(void) } printf("\n"); delete nameptr; + fh.flush(); fh.close(); if(success) log("PlayerNameCache successfully loaded."); @@ -409,6 +410,7 @@ void ItemProtoCache_WriteDataToCache(WorldSession *session) fh.write((char*)buf.contents(),buf.size()); counter++; } + fh.flush(); fh.close(); log("ItemProtoCache: Saved %u Item Prototypes",counter); } @@ -523,6 +525,7 @@ void CreatureTemplateCache_WriteDataToCache(WorldSession *session) fh.write((char*)buf.contents(),buf.size()); counter++; } + fh.flush(); fh.close(); log("CreatureTemplateCache: Saved %u Creature Templates",counter); } diff --git a/src/Client/World/WorldSession.cpp b/src/Client/World/WorldSession.cpp index a35c155..686024a 100644 --- a/src/Client/World/WorldSession.cpp +++ b/src/Client/World/WorldSession.cpp @@ -3,7 +3,6 @@ #include "Auth/Sha1.h" #include "Auth/BigNumber.h" #include "Auth/AuthCrypt.h" -#include "Opcodes.h" #include "WorldPacket.h" #include "WorldSocket.h" #include "RealmSocket.h" @@ -34,11 +33,16 @@ WorldSession::WorldSession(PseuInstance *in) _lag_ms = 0; //... + in->GetScripts()->RunScriptIfExists("_onworldsessioncreate"); + DEBUG(logdebug("WorldSession 0x%X constructor finished",this)); } WorldSession::~WorldSession() { + _instance->GetScripts()->RunScriptIfExists("_onworldsessiondelete"); + + logdebug("~WorldSession(): %u packets left unhandled, and %u delayed. deleting.",pktQueue.size(),delayedPktQueue.size()); WorldPacket *packet; // clear the queue while(pktQueue.size()) @@ -46,6 +50,13 @@ WorldSession::~WorldSession() packet = pktQueue.next(); delete packet; } + // clear the delayed queue + while(delayedPktQueue.size()) + { + packet = delayedPktQueue.back().pkt; + delayedPktQueue.c.pop_back(); + delete packet; + } if(_channels) delete _channels; @@ -156,27 +167,30 @@ void WorldSession::HandleWorldPacket(WorldPacket *packet) } bool hideOpcode = false; + bool disabledOpcode = IsOpcodeDisabled(packet->GetOpcode()); + if(disabledOpcode && GetInstance()->GetConf()->hideDisabledOpcodes) + hideOpcode = true; // TODO: Maybe make table or something with all the frequently opcodes - if (packet->GetOpcode() == SMSG_MONSTER_MOVE) + if (GetInstance()->GetConf()->hidefreqopcodes) { - hideOpcode = true; + switch(packet->GetOpcode()) + { + case 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()); + if(!hideOpcode) + logcustom(1,YELLOW,">> Opcode %u [%s] (%s, %u bytes)", packet->GetOpcode(), GetOpcodeName(packet->GetOpcode()), (known ? (disabledOpcode ? "Disabled" : "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 by the scripts! std::string scname = "opcode::"; @@ -190,6 +204,12 @@ void WorldSession::HandleWorldPacket(WorldPacket *packet) GetInstance()->GetScripts()->bytebuffers.Unlink(pktname); } + // call the opcode handler + if(known && !disabledOpcode) + { + packet->rpos(0); + (this->*table[hpos].handler)(*packet); + } } catch (ByteBufferException bbe) { diff --git a/src/Client/World/WorldSession.h b/src/Client/World/WorldSession.h index 13b56ae..de1e753 100644 --- a/src/Client/World/WorldSession.h +++ b/src/Client/World/WorldSession.h @@ -2,6 +2,7 @@ #define _WORLDSESSION_H #include +#include #include "common.h" #include "PseuWoW.h" @@ -11,6 +12,7 @@ #include "SharedDefines.h" #include "ObjMgr.h" #include "CacheHandler.h" +#include "Opcodes.h" class WorldSocket; class WorldPacket; @@ -84,10 +86,16 @@ public: void HandleWorldPacket(WorldPacket*); + inline void DisableOpcode(uint16 opcode) { _disabledOpcodes[opcode] = true; } + inline void EnableOpcode(uint16 opcode) { _disabledOpcodes[opcode] = false; } + inline bool IsOpcodeDisabled(uint16 opcode) { return _disabledOpcodes[opcode]; } + PlayerNameCache plrNameCache; ObjMgr objmgr; + private: + OpcodeHandler *_GetOpcodeHandlerTable(void) const; // Helpers @@ -148,6 +156,7 @@ private: World *_world; WhoList _whoList; uint32 _lag_ms; + std::bitset _disabledOpcodes; }; #endif