* added possibility to disable handling of incoming opcodes by the core (they will still be handled if a script is assigned!)

* script command: switchopcodehandler,<opcode> true(on)/false(off)
* added script events _onworldsessioncreate/delete
* added new conf option: HideDisabledOpcodes=1/0
* added possibility to spoof worldpackets
This commit is contained in:
false_genesis 2008-02-19 20:01:50 +00:00
parent c87f175ad6
commit d295e30b3f
9 changed files with 183 additions and 28 deletions

View File

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

View File

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

View File

@ -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::";

View File

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

View File

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

View File

@ -45,6 +45,7 @@ class PseuInstanceConf
uint16 networksleeptime;
uint8 showopcodes;
bool hidefreqopcodes;
bool hideDisabledOpcodes;
bool allowgamecmd;
bool enablecli;
bool enablechatai;

View File

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

View File

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

View File

@ -2,6 +2,7 @@
#define _WORLDSESSION_H
#include <queue>
#include <bitset>
#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<MAX_OPCODE_ID> _disabledOpcodes;
};
#endif