* updated+fixed object update. (still not working on ascent)

* added conf option "DumpPackets" to dump wrong packets for later analysis
This commit is contained in:
false_genesis 2008-03-27 23:53:17 +00:00
parent df3927cbbf
commit fce0efcfc2
10 changed files with 245 additions and 84 deletions

View File

@ -122,4 +122,14 @@ useMaps=0
// Sometimes they even cause problems, like make the console window beep...
SkipAddonChat=1
// Dump invalid packets or those which caused an error/exception for further analyis.
// Directory is "./packetdumps/"
// Note that packet dumps are valid for 1 session only, the counter gets reset when the WorldSession is destroyed.
// This means they get overwritten if not saved!
// 0 - no packet dumping
// 1 - dump packets that caused an excpetion or object update error
// 2 - like [1] + all packets with opcodes not handled by the core
// (doesn't matter if they have scripts attached or not, they will be dumped always)
DumpPackets=1

View File

@ -414,6 +414,7 @@ void PseuInstanceConf::ApplyFromVarSet(VarSet &v)
rmcontrolhost=v.Get("RMCONTROLHOST");
useMaps=(bool)atoi(v.Get("USEMAPS").c_str());
skipaddonchat=(bool)atoi(v.Get("SKIPADDONCHAT").c_str());
dumpPackets=(uint8)atoi(v.Get("DUMPPACKETS").c_str());
// clientversion is a bit more complicated to add
{

View File

@ -56,6 +56,7 @@ class PseuInstanceConf
std::string rmcontrolhost;
bool useMaps;
bool skipaddonchat;
uint8 dumpPackets;
// gui related
bool enablegui;

View File

@ -2,39 +2,16 @@
#define MOVEMENTMGR_H
#include "common.h"
#include "UpdateData.h"
#define MOVE_HEARTBEAT_DELAY 500
enum MovementFlags
{
MOVEMENTFLAG_NONE = 0x00000000,
MOVEMENTFLAG_FORWARD = 0x00000001,
MOVEMENTFLAG_BACKWARD = 0x00000002,
MOVEMENTFLAG_STRAFE_LEFT = 0x00000004,
MOVEMENTFLAG_STRAFE_RIGHT = 0x00000008,
MOVEMENTFLAG_LEFT = 0x00000010,
MOVEMENTFLAG_RIGHT = 0x00000020,
MOVEMENTFLAG_PITCH_UP = 0x00000040,
MOVEMENTFLAG_PITCH_DOWN = 0x00000080,
MOVEMENTFLAG_WALK = 0x00000100,
MOVEMENTFLAG_ONTRANSPORT = 0x00000200,
MOVEMENTFLAG_UNK1 = 0x00000400,
MOVEMENTFLAG_FLY_UNK1 = 0x00000800,
MOVEMENTFLAG_JUMPING = 0x00001000,
MOVEMENTFLAG_UNK4 = 0x00002000,
MOVEMENTFLAG_FALLING = 0x00004000,
// 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000
MOVEMENTFLAG_SWIMMING = 0x00200000, // appears with fly flag also
MOVEMENTFLAG_FLY_UP = 0x00400000,
MOVEMENTFLAG_CAN_FLY = 0x00800000,
MOVEMENTFLAG_FLYING = 0x01000000,
MOVEMENTFLAG_UNK5 = 0x02000000,
MOVEMENTFLAG_SPLINE = 0x04000000, // probably wrong name
MOVEMENTFLAG_SPLINE2 = 0x08000000,
MOVEMENTFLAG_WATERWALKING = 0x10000000,
MOVEMENTFLAG_SAFE_FALL = 0x20000000, // active rogue safe fall spell (passive)
MOVEMENTFLAG_UNK3 = 0x40000000,
// --
// -- MovementFlags and MovementInfo can be found in UpdateData.h
// --
enum MovementFlagsEx
{
// custom flags
MOVEMENTFLAG_ANY_MOVE = (MOVEMENTFLAG_BACKWARD | MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_STRAFE_LEFT | MOVEMENTFLAG_STRAFE_RIGHT
| MOVEMENTFLAG_LEFT | MOVEMENTFLAG_RIGHT)

View File

@ -37,10 +37,11 @@ void WorldSession::_HandleCompressedUpdateObjectOpcode(WorldPacket& recvPacket)
void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
{
uint8 utype;
uint8 unk8;
uint8 hasTransport;
uint32 usize, ublocks;
uint64 uguid;
recvPacket >> ublocks >> unk8;
recvPacket >> ublocks >> hasTransport;
logdev("UpdateObject: hasTransport = %u", hasTransport);
while(recvPacket.rpos() < recvPacket.size())
{
recvPacket >> utype;
@ -210,6 +211,16 @@ void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
logerror("UPDATE_OBJECT: Got unk updatetype 0x%X",utype);
logerror("UPDATE_OBJECT: Read %u / %u bytes, skipped rest",recvPacket.rpos(),recvPacket.size());
logerror("%s",toHexDump((uint8*)recvPacket.contents(),recvPacket.size(),true).c_str());
char buf[100];
sprintf(buf,"Got unk updatetype=0x%X, read %u / %u bytes",utype,recvPacket.rpos(),recvPacket.size());
if(GetInstance()->GetConf()->dumpPackets)
{
char buf[100];
sprintf(buf,"Got unk updatetype=0x%X, read %u / %u bytes",utype,recvPacket.rpos(),recvPacket.size());
DumpPacket(recvPacket, recvPacket.rpos(),buf);
}
return;
}
} // switch
@ -219,66 +230,94 @@ void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
void WorldSession::_MovementUpdate(uint8 objtypeid, uint64 uguid, WorldPacket& recvPacket)
{
uint8 flags,unk8;
uint32 unk32,flags2,time,transtime,higuid;
float unkfx,unkfy,unkfz,x,y,z,o,tx,ty,tz,to;
uint64 transguid;
MovementInfo mi; // TODO: use a reference to a MovementInfo in Unit/Player class once implemented
uint8 flags;
float unkfx,unkfy,unkfz;
// uint64 fullguid; // see below
float speedWalk, speedRun, speedSwimBack, speedSwim, speedWalkBack, speedTurn, speedFly, speedFlyBack;
uint32 unk32;
Object *obj = (Object*)objmgr.GetObj(uguid);
Unit *u = (Unit*)obj; // only use for Unit:: functions!!
recvPacket >> flags;
flags2 = 0; // not sure if its correct to set it to 0 (needs some starting flag?)
if(flags & UPDATEFLAG_LIVING)
Unit *u = NULL;
if(obj)
{
recvPacket >> flags2 >> unk8 >> time;
if(obj->IsUnit())
u = (Unit*)obj; // only use for Unit:: functions!!
else
logdev("MovementUpdate: object "I64FMT" is not Unit (typeId=%u)",obj->GetGUID(),obj->GetTypeId());
}
else
{
logerror("MovementUpdate for unknown object "I64FMT" typeid=%u",uguid,objtypeid);
}
logdev("MovementUpdate TypeID=%u GUID="I64FMT" pObj=%X flags=%u flags2=%u",objtypeid,uguid,obj,flags,flags2);
recvPacket >> flags;
mi.flags = 0; // not sure if its correct to set it to 0 (needs some starting flag?)
if(flags & UPDATEFLAG_LIVING)
{
recvPacket >> mi.flags >> mi.unk1 >> mi.time;
}
else
{
logdev("MovementUpdate: UPDATEFLAG_LIVING *NOT* set! (no MovementInfo)");
}
logdev("MovementUpdate: TypeID=%u GUID="I64FMT" pObj=%X flags=%u mi.flags=%u",objtypeid,uguid,obj,flags,mi.flags);
if(flags & UPDATEFLAG_HASPOSITION)
{
if(flags & UPDATEFLAG_TRANSPORT)
{
recvPacket >> unkfx >> unkfy >> unkfz >> o; // 3x (float)0 followed by orientation
logdev("TRANSPORT_FLOATS @ flags: x=%f y=%f z=%f o=%f",unkfx,unkfy,unkfz,o);
recvPacket >> unkfx >> unkfy >> unkfz >> mi.o; // 3x (float)0 followed by orientation
logdev("TRANSPORT_FLOATS @ flags: x=%f y=%f z=%f o=%f", unkfx, unkfy, unkfz, mi.o);
}
else
{
recvPacket >> x >> y >> z >> o;
logdev("FLOATS: x=%f y=%f z=%f o=%f",x,y,z,o);
recvPacket >> mi.x >> mi.y >> mi.z >> mi.o;
logdev("FLOATS: x=%f y=%f z=%f o=%f",mi.x, mi.y, mi.z ,mi.o);
if(obj->IsWorldObject())
((WorldObject*)obj)->SetPosition(x,y,z,o);
((WorldObject*)obj)->SetPosition(mi.x, mi.y, mi.z, mi.o);
}
}
if(flags & UPDATEFLAG_LIVING)
{
if(flags2 & FLAGS2_TRANSPORT)
if(mi.flags & MOVEMENTFLAG_ONTRANSPORT)
{
recvPacket >> transguid >> tx >> ty >> tz >> to;
recvPacket >> unk32; // added in 2.0.3
logdev("TRANSPORT_FLOATS @ flags2: x=%f y=%f z=%f o=%f",tx,ty,tz,to);
recvPacket >> mi.t_guid >> mi.t_x >> mi.t_y >> mi.t_z >> mi.t_o;
recvPacket >> mi.t_time; // added in 2.0.3
logdev("TRANSPORT @ mi.flags: guid="I64FMT" x=%f y=%f z=%f o=%f", mi.t_guid, mi.t_x, mi.t_y, mi.t_z, mi.t_o);
}
recvPacket >> unk32;
if(mi.flags & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_UNK5))
{
recvPacket >> mi.s_angle;
logdev("MovementUpdate: MOVEMENTFLAG_SWIMMING is set, angle = %f!", mi.s_angle);
}
/*
// not sure if this is/was correct, MaNGOS doesnt use it anymore
if(flags2 & 0x2000) // 0x2000 = ??
{
recvPacket >> unkf >> unkf >> unkf >> unkf;
}
*/
recvPacket >> mi.fallTime;
logdev("MovementUpdate: FallTime = %u", mi.fallTime);
recvPacket >> speedWalk >> speedRun >> speedSwimBack >> speedSwim;
if(mi.flags & MOVEMENTFLAG_JUMPING)
{
recvPacket >> mi.j_unk >> mi.j_sinAngle >> mi.j_cosAngle >> mi.j_xyspeed;
logdev("MovementUpdate: MOVEMENTFLAG_JUMPING is set, unk=%f sinA=%f cosA=%f xyspeed=%f = %u", mi.j_unk, mi.j_sinAngle, mi.j_cosAngle, mi.j_xyspeed);
}
if(mi.flags & MOVEMENTFLAG_SPLINE)
{
recvPacket >> mi.u_unk1;
logdev("MovementUpdate: MOVEMENTFLAG_SPLINE is set, got %u", mi.u_unk1);
}
recvPacket >> speedWalk >> speedRun >> speedSwimBack >> speedSwim; // speedRun can also be mounted speed if player is mounted
recvPacket >> speedWalkBack >> speedFly >> speedFlyBack >> speedTurn; // fly added in 2.0.x
logdev("MovementUpdate: Got speeds, walk=%f run=%f turn=%f", speedWalk, speedRun, speedTurn);
if(u)
{
u->SetPosition(x,y,z,o);
u->SetPosition(mi.x, mi.y, mi.z, mi.o);
u->SetSpeed(MOVE_WALK,speedWalk);
u->SetSpeed(MOVE_RUN,speedRun);
u->SetSpeed(MOVE_SWIMBACK,speedSwimBack);
@ -288,33 +327,39 @@ void WorldSession::_MovementUpdate(uint8 objtypeid, uint64 uguid, WorldPacket& r
u->SetSpeed(MOVE_FLY,speedFly);
u->SetSpeed(MOVE_FLYBACK,speedFlyBack);
}
else
// TODO: correct this one as soon as its meaning is known OR if it appears often and needs to be fixed
if(mi.flags & MOVEMENTFLAG_SPLINE2)
{
logerror("WorldSession::_MovementUpdate for unknown guid "I64FMT" typeid=%u",uguid,objtypeid);
logerror("MovementUpdate: MOVEMENTFLAG_SPLINE2 is set, if you see this message please report it!");
return;
}
}
if(flags & UPDATEFLAG_ALL)
if(flags & UPDATEFLAG_LOWGUID)
{
recvPacket >> unk32;
logdev("MovementUpdate: UPDATEFLAG_LOWGUID is set, got %X", unk32);
}
if(flags & UPDATEFLAG_HIGHGUID)
{
recvPacket >> higuid; // 2.0.6 - high guid was there, unk for 2.0.12
recvPacket >> unk32; // 2.0.6 - high guid was there, unk for 2.0.12
// not sure if this is correct, MaNGOS sends 0 always.
//obj->SetUInt32Value(OBJECT_FIELD_GUID+1,higuid); // note that this sets only the high part of the guid
logdev("MovementUpdate: UPDATEFLAG_HIGHGUID is set, got %X", unk32);
}
if(flags & UPDATEFLAG_FULLGUID)
{
// unused in mangos? but what if its needed?
// recvPacket >> fullguid;
uint64 unkguid = recvPacket.GetPackedGuid(); // MaNGOS sends uint8(0) always, but its probably be a packed guid
logdev("MovementUpdate: UPDATEFLAG_FULLGUID is set, got "I64FMT, unkguid);
}
if(flags & UPDATEFLAG_TRANSPORT)
{
recvPacket >> transtime; // whats this used for?
recvPacket >> unk32; // whats this used for?
logdev("MovementUpdate: UPDATEFLAG_TRANSPORT is set, got %u", unk32);
}
}

View File

@ -13,20 +13,79 @@ enum OBJECT_UPDATE_TYPE
enum OBJECT_UPDATE_FLAGS
{
UPDATEFLAG_SELF = 0x01,
UPDATEFLAG_TRANSPORT = 0x02,
UPDATEFLAG_FULLGUID = 0x04,
UPDATEFLAG_HIGHGUID = 0x08,
UPDATEFLAG_ALL = 0x10,
UPDATEFLAG_LIVING = 0x20,
UPDATEFLAG_HASPOSITION = 0x40
UPDATEFLAG_NONE = 0x00,
UPDATEFLAG_SELF = 0x01,
UPDATEFLAG_TRANSPORT = 0x02,
UPDATEFLAG_FULLGUID = 0x04,
UPDATEFLAG_LOWGUID = 0x08,
UPDATEFLAG_HIGHGUID = 0x10,
UPDATEFLAG_LIVING = 0x20,
UPDATEFLAG_HASPOSITION = 0x40
};
// not sure about those flags, mangos hasnt a description for it either
enum FLAGS2_UPDATE_FLAGS
enum MovementFlags
{
FLAGS2_TRANSPORT = 0x200,
FLAGS2_SPIRITHEALER = 0x10000000,
MOVEMENTFLAG_NONE = 0x00000000,
MOVEMENTFLAG_FORWARD = 0x00000001,
MOVEMENTFLAG_BACKWARD = 0x00000002,
MOVEMENTFLAG_STRAFE_LEFT = 0x00000004,
MOVEMENTFLAG_STRAFE_RIGHT = 0x00000008,
MOVEMENTFLAG_LEFT = 0x00000010,
MOVEMENTFLAG_RIGHT = 0x00000020,
MOVEMENTFLAG_PITCH_UP = 0x00000040,
MOVEMENTFLAG_PITCH_DOWN = 0x00000080,
MOVEMENTFLAG_WALK = 0x00000100,
MOVEMENTFLAG_ONTRANSPORT = 0x00000200,
MOVEMENTFLAG_UNK1 = 0x00000400,
MOVEMENTFLAG_FLY_UNK1 = 0x00000800,
MOVEMENTFLAG_JUMPING = 0x00001000,
MOVEMENTFLAG_UNK4 = 0x00002000,
MOVEMENTFLAG_FALLING = 0x00004000,
// 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000
MOVEMENTFLAG_SWIMMING = 0x00200000, // appears with fly flag also
MOVEMENTFLAG_FLY_UP = 0x00400000,
MOVEMENTFLAG_CAN_FLY = 0x00800000,
MOVEMENTFLAG_FLYING = 0x01000000,
MOVEMENTFLAG_UNK5 = 0x02000000,
MOVEMENTFLAG_SPLINE = 0x04000000, // probably wrong name
MOVEMENTFLAG_SPLINE2 = 0x08000000,
MOVEMENTFLAG_WATERWALKING = 0x10000000,
MOVEMENTFLAG_SAFE_FALL = 0x20000000, // active rogue safe fall spell (passive)
MOVEMENTFLAG_UNK3 = 0x40000000
};
struct MovementInfo
{
// common
uint32 flags;
uint8 unk1;
uint32 time;
float x, y, z, o;
// transport
uint64 t_guid;
float t_x, t_y, t_z, t_o;
uint32 t_time;
// swimming and unk
float s_angle;
// last fall time
uint32 fallTime;
// jumping
float j_unk, j_sinAngle, j_cosAngle, j_xyspeed;
// spline
float u_unk1;
MovementInfo()
{
flags = time = t_time = fallTime = 0;
unk1 = 0;
x = y = z = o = t_x = t_y = t_z = t_o = s_angle = j_unk = j_sinAngle = j_cosAngle = j_xyspeed = u_unk1 = 0.0f;
t_guid = 0;
}
void SetMovementFlags(uint32 _flags)
{
flags = _flags;
}
};
bool IsFloatField(uint8, uint32);

View File

@ -189,6 +189,11 @@ void WorldSession::HandleWorldPacket(WorldPacket *packet)
logcustom(1,YELLOW,">> Opcode %u [%s] (%s, %u bytes)", packet->GetOpcode(), GetOpcodeName(packet->GetOpcode()), (known ? (disabledOpcode ? "Disabled" : "Known") : "UNKNOWN"), packet->size());
}
if( (!known) && GetInstance()->GetConf()->dumpPackets > 1)
{
DumpPacket(*packet);
}
try
{
// if there is a script attached to that opcode, call it now.
@ -213,14 +218,18 @@ void WorldSession::HandleWorldPacket(WorldPacket *packet)
}
catch (ByteBufferException bbe)
{
char errbuf[200];
sprintf(errbuf,"attempt to \"%s\" %u bytes at position %u out of total %u bytes. (wpos=%u)", bbe.action, bbe.readsize, bbe.rpos, bbe.cursize, bbe.wpos);
logerror("Exception while handling opcode %u [%s]!",packet->GetOpcode(),GetOpcodeName(packet->GetOpcode()));
logerror("WorldSession: ByteBufferException");
logerror("ByteBuffer reported: attempt to \"%s\" %u bytes at position %u out of total %u bytes. (wpos=%u)",
bbe.action, bbe.readsize, bbe.rpos, bbe.cursize, bbe.wpos);
logerror("ByteBuffer reported: %s", errbuf);
// copied from below
logerror("Data: pktsize=%u, handler=0x%X queuesize=%u",packet->size(),table[hpos].handler,pktQueue.size());
logerror("Packet Hexdump:");
logerror("%s",toHexDump((uint8*)packet->contents(),packet->size(),true).c_str());
if(GetInstance()->GetConf()->dumpPackets)
DumpPacket(*packet, bbe.rpos, errbuf);
}
catch (...)
{
@ -228,6 +237,9 @@ void WorldSession::HandleWorldPacket(WorldPacket *packet)
logerror("Data: pktsize=%u, handler=0x%X queuesize=%u",packet->size(),table[hpos].handler,pktQueue.size());
logerror("Packet Hexdump:");
logerror("%s",toHexDump((uint8*)packet->contents(),packet->size(),true).c_str());
if(GetInstance()->GetConf()->dumpPackets)
DumpPacket(*packet, packet->rpos(), "unknown exception");
}
delete packet;
@ -367,6 +379,55 @@ void WorldSession::_DoTimedActions(void)
}
}
std::string WorldSession::DumpPacket(WorldPacket& pkt, int errpos, char *errstr)
{
static std::map<uint32,uint32> opstore;
std::stringstream s;
s << "TIMESTAMP: " << getDateString() << "\n";
s << "OPCODE: " << pkt.GetOpcode() << " " << GetOpcodeName(pkt.GetOpcode()) << "\n";
s << "SIZE: " << pkt.size() << "\n";
if(errpos > 0)
s << "ERROR-AT: " << errpos << "\n";
if(errstr)
s << "ERROR: " << errstr << "\n";
if(pkt.size())
{
s << "DATA-HEX:\n";
s << toHexDump((uint8*)pkt.contents(),pkt.size(),true,32);
s << "\n";
s << "DATA-TEXT:\n";
for(uint32 i = 0; i < pkt.size(); i++)
{
s << (isprint(pkt[i]) ? (char)pkt[i] : '.');
if((i+1) % 32 == 0)
s << "\n";
}
s << "\n";
}
s << "\n";
CreateDir("packetdumps");
if(opstore.find(pkt.GetOpcode()) == opstore.end())
opstore[pkt.GetOpcode()] = 0;
else
opstore[pkt.GetOpcode()]++;
std::fstream fh;
std::stringstream fn;
fn << "./packetdumps/" << GetOpcodeName(pkt.GetOpcode()) << "_" << opstore[pkt.GetOpcode()] << ".txt";
fh.open(fn.str().c_str(), std::ios_base::out);
if(!fh.is_open())
{
logerror("Packet dump failed! (%s)",fn.str().c_str());
return fn.str();
}
fh << s.str();
fh.close();
logdetail("Packet successfully dumped to '%s'", fn.str().c_str());
return fn.str();
}
std::string WorldSession::GetOrRequestPlayerName(uint64 guid)
{
if(!guid || GUID_HIPART(guid) != HIGHGUID_PLAYER)

View File

@ -71,6 +71,7 @@ public:
inline World *GetWorld(void) { return _world; }
std::string GetOrRequestPlayerName(uint64);
std::string DumpPacket(WorldPacket& pkt, int errpos = -1, char *errstr = NULL);
// CMSGConstructor

View File

@ -87,7 +87,7 @@ uint64 toInt(std::string str)
return strtoul(str.c_str(),NULL,10);
}
std::string toHexDump(uint8* array,uint32 size,bool spaces)
std::string toHexDump(uint8* array, uint32 size, bool spaces, uint32 per_line)
{
std::stringstream ss;
char buf[5];
@ -101,6 +101,12 @@ std::string toHexDump(uint8* array,uint32 size,bool spaces)
else
ss << "00"; // little hacklike fix
if(per_line && !((i+1) % per_line))
{
ss << "\n";
continue;
}
if(spaces)
ss << ' ';
}

View File

@ -14,7 +14,7 @@ std::string stringToLower(std::string);
std::string toString(uint64);
std::string getDateString(void);
uint64 toInt(std::string);
std::string toHexDump(uint8* array,uint32 size,bool spaces=true);
std::string toHexDump(uint8* array,uint32 size,bool spaces=true,uint32 per_line=0);
std::deque<std::string> GetFileList(std::string);
bool FileExists(std::string);
bool CreateDir(const char*);