Movement processor, some fixes

This commit is contained in:
rajkosto 2010-02-15 12:52:58 +00:00
parent 5b4bed2502
commit aa6007ded5
14 changed files with 2222 additions and 56 deletions

View file

@ -0,0 +1,404 @@
// *************************************************************************************************
// --------------------------------------
// Copyright (C) 2006-2010 Rajko Stojadinovic
//
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
// *************************************************************************************************
#include "Common.h"
#include "CrashHandler.h"
#include "Log.h"
void OutputCrashLogLine(const char * format, ...)
{
std::string s = "ERRORS.LOG";
FILE * m_file = fopen(s.c_str(), "a");
if(!m_file) return;
va_list ap;
va_start(ap, format);
vfprintf(m_file, format, ap);
fprintf(m_file, "\n");
fclose(m_file);
va_end(ap);
}
#ifdef WIN32
#include "Threading/NativeMutex.h"
NativeMutex m_crashLock;
/* *
@file CrashHandler.h
Handles crashes/exceptions on a win32 based platform, writes a dump file,
for later bug fixing.
*/
# pragma warning( disable : 4311 )
#include <stdio.h>
#include <time.h>
//#include <windows.h>
#include "Log.h"
#include <tchar.h>
bool ON_CRASH_BREAK_DEBUGGER;
void StartCrashHandler()
{
// Firstly, check if there is a debugger present. There isn't any point in
// handling crashes internally if we have a debugger attached, that would
// just piss us off. :P
// Check for a debugger.
#ifndef X64
DWORD code;
__asm
{
MOV EAX, FS:[0x18]
MOV EAX, DWORD PTR [EAX + 0x30]
MOV ECX, DWORD PTR [EAX]
MOV [DWORD PTR code], ECX
}
if(code & 0x00010000)
{
// We got a debugger. We'll tell it to not exit on a crash but instead break into debugger.
ON_CRASH_BREAK_DEBUGGER = true;
}
else
{
// No debugger. On crash, we'll call OnCrash to save etc.
ON_CRASH_BREAK_DEBUGGER = false;
}
#else
ON_CRASH_BREAK_DEBUGGER = (IsDebuggerPresent() == TRUE) ? true : false;
#endif
}
///////////////////////////////////////////////////////////////////////////////
// GetExceptionDescription
// Translate the exception code into something human readable
static const TCHAR *GetExceptionDescription(DWORD ExceptionCode)
{
struct ExceptionNames
{
DWORD ExceptionCode;
TCHAR * ExceptionName;
};
#if 0 // from winnt.h
#define STATUS_WAIT_0 ((DWORD )0x00000000L)
#define STATUS_ABANDONED_WAIT_0 ((DWORD )0x00000080L)
#define STATUS_USER_APC ((DWORD )0x000000C0L)
#define STATUS_TIMEOUT ((DWORD )0x00000102L)
#define STATUS_PENDING ((DWORD )0x00000103L)
#define STATUS_SEGMENT_NOTIFICATION ((DWORD )0x40000005L)
#define STATUS_GUARD_PAGE_VIOLATION ((DWORD )0x80000001L)
#define STATUS_DATATYPE_MISALIGNMENT ((DWORD )0x80000002L)
#define STATUS_BREAKPOINT ((DWORD )0x80000003L)
#define STATUS_SINGLE_STEP ((DWORD )0x80000004L)
#define STATUS_ACCESS_VIOLATION ((DWORD )0xC0000005L)
#define STATUS_IN_PAGE_ERROR ((DWORD )0xC0000006L)
#define STATUS_INVALID_HANDLE ((DWORD )0xC0000008L)
#define STATUS_NO_MEMORY ((DWORD )0xC0000017L)
#define STATUS_ILLEGAL_INSTRUCTION ((DWORD )0xC000001DL)
#define STATUS_NONCONTINUABLE_EXCEPTION ((DWORD )0xC0000025L)
#define STATUS_INVALID_DISPOSITION ((DWORD )0xC0000026L)
#define STATUS_ARRAY_BOUNDS_EXCEEDED ((DWORD )0xC000008CL)
#define STATUS_FLOAT_DENORMAL_OPERAND ((DWORD )0xC000008DL)
#define STATUS_FLOAT_DIVIDE_BY_ZERO ((DWORD )0xC000008EL)
#define STATUS_FLOAT_INEXACT_RESULT ((DWORD )0xC000008FL)
#define STATUS_FLOAT_INVALID_OPERATION ((DWORD )0xC0000090L)
#define STATUS_FLOAT_OVERFLOW ((DWORD )0xC0000091L)
#define STATUS_FLOAT_STACK_CHECK ((DWORD )0xC0000092L)
#define STATUS_FLOAT_UNDERFLOW ((DWORD )0xC0000093L)
#define STATUS_INTEGER_DIVIDE_BY_ZERO ((DWORD )0xC0000094L)
#define STATUS_INTEGER_OVERFLOW ((DWORD )0xC0000095L)
#define STATUS_PRIVILEGED_INSTRUCTION ((DWORD )0xC0000096L)
#define STATUS_STACK_OVERFLOW ((DWORD )0xC00000FDL)
#define STATUS_CONTROL_C_EXIT ((DWORD )0xC000013AL)
#define STATUS_FLOAT_MULTIPLE_FAULTS ((DWORD )0xC00002B4L)
#define STATUS_FLOAT_MULTIPLE_TRAPS ((DWORD )0xC00002B5L)
#define STATUS_ILLEGAL_VLM_REFERENCE ((DWORD )0xC00002C0L)
#endif
ExceptionNames ExceptionMap[] =
{
{0x40010005, _T("a Control-C")},
{0x40010008, _T("a Control-Break")},
{0x80000002, _T("a Datatype Misalignment")},
{0x80000003, _T("a Breakpoint")},
{0xc0000005, _T("an Access Violation")},
{0xc0000006, _T("an In Page Error")},
{0xc0000017, _T("a No Memory")},
{0xc000001d, _T("an Illegal Instruction")},
{0xc0000025, _T("a Noncontinuable Exception")},
{0xc0000026, _T("an Invalid Disposition")},
{0xc000008c, _T("a Array Bounds Exceeded")},
{0xc000008d, _T("a Float Denormal Operand")},
{0xc000008e, _T("a Float Divide by Zero")},
{0xc000008f, _T("a Float Inexact Result")},
{0xc0000090, _T("a Float Invalid Operation")},
{0xc0000091, _T("a Float Overflow")},
{0xc0000092, _T("a Float Stack Check")},
{0xc0000093, _T("a Float Underflow")},
{0xc0000094, _T("an Integer Divide by Zero")},
{0xc0000095, _T("an Integer Overflow")},
{0xc0000096, _T("a Privileged Instruction")},
{0xc00000fD, _T("a Stack Overflow")},
{0xc0000142, _T("a DLL Initialization Failed")},
{0xe06d7363, _T("a Microsoft C++ Exception")},
};
for (int i = 0; i < sizeof(ExceptionMap) / sizeof(ExceptionMap[0]); i++)
if (ExceptionCode == ExceptionMap[i].ExceptionCode)
return ExceptionMap[i].ExceptionName;
return _T("an Unknown exception type");
}
void spEcho(const char * format, ...)
{
va_list ap;
va_start(ap, format);
vprintf(format, ap);
std::string s = "SHAREDPTR.LOG";
FILE * m_file = fopen(s.c_str(), "a");
if(!m_file)
{
va_end(ap);
return;
}
vfprintf(m_file, format, ap);
fclose(m_file);
va_end(ap);
}
void __cdecl PrintSharedPtrInformation(bool m_sharedPtrDestructed, long references)
{
if(!m_sharedPtrDestructed)
spEcho("Failure to call Destructor method on deletion.\n");
if(references)
spEcho("Destructor() called when it has %i references left in memory!\n", references);
spEcho("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
spEcho("Call Stack: \n");
CStackWalker sw;
sw.ShowCallstack(TRUE);
spEcho("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
}
void echo(const char * format, ...)
{
va_list ap;
va_start(ap, format);
vprintf(format, ap);
std::string s = "CRASH.LOG";
FILE * m_file = fopen(s.c_str(), "a");
if(!m_file)
{
va_end(ap);
return;
}
vfprintf(m_file, format, ap);
fclose(m_file);
va_end(ap);
}
void PrintCrashInformation(PEXCEPTION_POINTERS except)
{
echo("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
echo("Server has crashed. Reason was:\n");
echo(" %s at 0x%08X\n", GetExceptionDescription(except->ExceptionRecord->ExceptionCode),
(unsigned long)except->ExceptionRecord->ExceptionAddress);
#ifdef REPACK
echo("%s repack by %s has crashed. Visit %s for support.", REPACK, REPACK_AUTHOR, REPACK_WEBSITE);
#endif
echo("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
echo("Call Stack: \n");
CStackWalker sw;
sw.ShowCallstack();
echo("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
}
void CStackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName)
{
}
void CStackWalker::OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion)
{
}
void CStackWalker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr)
{
}
void CStackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry)
{
CHAR buffer[STACKWALK_MAX_NAMELEN];
if ( (eType != lastEntry) && (entry.offset != 0) )
{
if (entry.name[0] == 0)
strcpy(entry.name, "(function-name not available)");
if (entry.undName[0] != 0)
strcpy(entry.name, entry.undName);
if (entry.undFullName[0] != 0)
strcpy(entry.name, entry.undFullName);
/* if(!stricmp(entry.symTypeString, "-exported-"))
strcpy(entry.symTypeString, "dll");
for(uint32 i = 0; i < strlen(entry.symTypeString); ++i)
entry.symTypeString[i] = tolower(entry.symTypeString);*/
char * p = strrchr(entry.loadedImageName, '\\');
if(!p)
p = entry.loadedImageName;
else
++p;
if (entry.lineFileName[0] == 0)
{
//strcpy(entry.lineFileName, "(filename not available)");
//if (entry.moduleName[0] == 0)
//strcpy(entry.moduleName, "(module-name not available)");
//sprintf(buffer, "%s): %s: %s\n", (LPVOID) entry.offset, entry.moduleName, entry.lineFileName, entry.name);
//sprintf(buffer, "%s.
if(entry.name[0] == 0)
sprintf(entry.name, "%p", entry.offset);
sprintf(buffer, "%s!%s Line %u\n", p, entry.name, entry.lineNumber );
}
else
sprintf(buffer, "%s!%s Line %u\n", p, entry.name, entry.lineNumber);
//OnOutput(buffer);
/*if(p)
OnOutput(p);
else*/
OnOutput(buffer);
}
}
void CStackWalker::OnOutput(LPCSTR szText)
{
std::string s;
if(m_sharedptrlog)
s = "SHAREDPTR.LOG";
else
s = "CRASH.LOG";
FILE * m_file = fopen(s.c_str(), "a");
if(!m_file) return;
printf(" %s", szText);
fprintf(m_file, " %s", szText);
fclose(m_file);
}
bool died = false;
int __cdecl HandleCrash(PEXCEPTION_POINTERS pExceptPtrs)
{
if(pExceptPtrs == 0)
{
// Raise an exception :P
__try
{
RaiseException(EXCEPTION_BREAKPOINT, 0, 0, 0);
}
__except(HandleCrash(GetExceptionInformation()), EXCEPTION_CONTINUE_EXECUTION)
{
}
}
/* only allow one thread to crash. */
if(!m_crashLock.AttemptAcquire())
{
TerminateThread(GetCurrentThread(),-1);
// not reached
}
if(died)
{
TerminateProcess(GetCurrentProcess(),-1);
// not reached:P
}
died=true;
// Create the date/time string
time_t curtime = time(NULL);
tm * pTime = localtime(&curtime);
char filename[MAX_PATH];
TCHAR modname[MAX_PATH*2];
ZeroMemory(modname, sizeof(modname));
if(GetModuleFileName(0, modname, MAX_PATH*2-2) <= 0)
strcpy(modname, "UNKNOWN");
char * mname = strrchr(modname, '\\');
(void*)mname++; // Remove the last
sprintf(filename, "CrashDumps\\dump-%s-%u-%u-%u-%u-%u-%u-%u.dmp",
mname, pTime->tm_year+1900, pTime->tm_mon, pTime->tm_mday,
pTime->tm_hour, pTime->tm_min, pTime->tm_sec, GetCurrentThreadId());
HANDLE hDump = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, 0);
if(hDump == INVALID_HANDLE_VALUE)
{
// Create the directory first
CreateDirectory("CrashDumps", 0);
hDump = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, 0);
}
PrintCrashInformation(pExceptPtrs);
// beep
//printf("\x7");
printf("\nCreating crash dump file %s\n", filename);
if(hDump == INVALID_HANDLE_VALUE)
{
MessageBox(0, "Could not open crash dump file.", "Crash dump error.", MB_OK);
}
else
{
MINIDUMP_EXCEPTION_INFORMATION info;
info.ClientPointers = FALSE;
info.ExceptionPointers = pExceptPtrs;
info.ThreadId = GetCurrentThreadId();
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
hDump, MiniDumpWithIndirectlyReferencedMemory, &info, 0, 0);
CloseHandle(hDump);
}
SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS);
OnCrash(!ON_CRASH_BREAK_DEBUGGER);
return EXCEPTION_CONTINUE_SEARCH;
}
#endif

View file

@ -0,0 +1,69 @@
// *************************************************************************************************
// --------------------------------------
// Copyright (C) 2006-2010 Rajko Stojadinovic
//
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
// *************************************************************************************************
#ifndef MXOSIM_CRASH_HANDLER_H
#define MXOSIM_CRASH_HANDLER_H
bool HookCrashReporter(bool logon);
void OutputCrashLogLine(const char* format, ...);
#ifdef WIN32
//#include <Windows.h>
#include "Common.h"
#include <DbgHelp.h>
#include "StackWalker.h"
class CStackWalker : public StackWalker
{
public:
void OnOutput(LPCSTR szText);
void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);
void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion);
void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry);
void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);
};
void StartCrashHandler();
void OnCrash(bool Terminate);
typedef struct _EXCEPTION_POINTERS EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;
int __cdecl HandleCrash(PEXCEPTION_POINTERS pExceptPtrs);
void __cdecl PrintSharedPtrInformation(bool m_sharedPtrDestructed, long references);
#define THREAD_TRY_EXECUTION __try
#define THREAD_HANDLE_CRASH __except(HandleCrash(GetExceptionInformation())) {}
#define THREAD_TRY_EXECUTION2 __try {
#define THREAD_HANDLE_CRASH2 } __except(HandleCrash(GetExceptionInformation())) {}
#else
// We dont wanna confuse nix ;p
#define THREAD_TRY_EXECUTION
#define THREAD_HANDLE_CRASH
#define THREAD_TRY_EXECUTION2 ;
#define THREAD_HANDLE_CRASH2 ;
#endif
#endif

View file

@ -395,16 +395,18 @@ void GameClient::PSSChanged( uint8 oldPSS,uint8 newPSS )
sObjMgr.getGOPtr(m_playerGoId)->SpawnSelf();
m_worldLoaded = true;
}
m_characterSpawned = true;
sObjMgr.getGOPtr(m_playerGoId)->PopulateWorld();
if (m_characterSpawned == false)
{
sObjMgr.getGOPtr(m_playerGoId)->PopulateWorld();
m_characterSpawned = true;
}
}
}
void GameClient::MoveMsgsToQueue()
{
std::sort(m_packetsToAck.begin(),m_packetsToAck.end());
//first we send out all the 03
for (queueType::iterator it=m_queuedStates.begin();it!=m_queuedStates.end();++it)
for (stateQueueType::iterator it=m_queuedStates.begin();it!=m_queuedStates.end();++it)
{
//consume an ack if we can
if (m_packetsToAck.size() > 0)
@ -412,11 +414,11 @@ void GameClient::MoveMsgsToQueue()
uint16 theClientSeq = m_packetsToAck.front();
m_packetsToAck.pop_front();
AddPacketToQueue(theClientSeq,true,*it);
AddPacketToQueue(theClientSeq,true,it->stateData,it->noResend);
}
else
{
AddPacketToQueue(*it);
AddPacketToQueue(it->stateData,it->noResend);
}
}
//all queued 03s have been transferred to packet queue, clear the 03 queue
@ -551,8 +553,11 @@ void GameClient::FlushQueue()
//mark packet as sent
it->sent=true;
it->msTimeSent=getMSTime();
++it;
//if packet is non resendable, remove it
if (it->noResends==true)
it=m_sendQueue.erase(it);
else
++it;
}
}

View file

@ -59,14 +59,14 @@ public:
void HandleEncrypted(ByteBuffer &srcData);
void HandleOther(ByteBuffer &otherData);
void HandleOrdered(ByteBuffer &orderedData);
void QueueState(msgBaseClassPtr theData)
void QueueState(msgBaseClassPtr theData,bool immediateOnly=false)
{
msgBaseClassPtr &realPtr = theData;
shared_ptr<ObjectUpdateMsg> amIObjectUpdate = dynamic_pointer_cast<ObjectUpdateMsg>(realPtr);
if (amIObjectUpdate != NULL)
amIObjectUpdate->setReceiver(this);
m_queuedStates.push_back(realPtr);
m_queuedStates.push_back(queuedState(realPtr,immediateOnly));
}
void QueueCommand(msgBaseClassPtr theCmd)
{
@ -136,12 +136,23 @@ private:
typedef deque<msgBaseClassPtr> queueType;
queueType m_queuedCommands;
queueType m_queuedStates;
struct queuedState
{
queuedState(msgBaseClassPtr theState, bool immediateOnly=false)
{
stateData = theState;
noResend=immediateOnly;
}
bool noResend;
msgBaseClassPtr stateData;
};
typedef deque<queuedState> stateQueueType;
stateQueueType m_queuedStates;
struct PacketInQueue
{
//the packet will own the data pointer
PacketInQueue(uint8 thePSS, uint16 serverSeq, uint16 clientSeq, bool ackPacket, msgBaseClassPtr dataToSend)
PacketInQueue(uint8 thePSS, uint16 serverSeq, uint16 clientSeq, bool ackPacket, msgBaseClassPtr dataToSend, bool immediateOnly=false)
{
clientPSS = thePSS;
server_sequence = serverSeq;
@ -151,6 +162,7 @@ private:
sent=false;
msTimeSent=0;
resentCounter=0;
noResends=immediateOnly;
}
~PacketInQueue() {}
@ -162,10 +174,11 @@ private:
bool sent;
uint32 msTimeSent;
uint32 resentCounter;
bool noResends;
};
typedef list<PacketInQueue> sendQueueList;
sendQueueList m_sendQueue;
void AddPacketToQueue(uint16 clientSeq, bool ackPacket, msgBaseClassPtr dataToSend)
void AddPacketToQueue(uint16 clientSeq, bool ackPacket, msgBaseClassPtr dataToSend, bool immediateOnly=false)
{
//if its a static packet of 0 bytes and no ack, no reason to send it
if (ackPacket == false)
@ -191,11 +204,11 @@ private:
{
DEBUG_LOG(format("(%s) Queue SSeq: %d CSeq: %d Ack: %d No Data") % Address() % theServerSeq % clientSeq % ackPacket);
}
m_sendQueue.push_back(PacketInQueue(m_clientPSS,theServerSeq,clientSeq,ackPacket,dataToSend));
m_sendQueue.push_back(PacketInQueue(m_clientPSS,theServerSeq,clientSeq,ackPacket,dataToSend,immediateOnly));
}
void AddPacketToQueue(msgBaseClassPtr dataToSend)
void AddPacketToQueue(msgBaseClassPtr dataToSend, bool immediateOnly=false)
{
AddPacketToQueue(m_lastClientSequence,false,dataToSend);
AddPacketToQueue(m_lastClientSequence,false,dataToSend,immediateOnly);
}
void MoveMsgsToQueue();

View file

@ -219,13 +219,13 @@ void GameServer::CheckAndResend()
}
}
void GameServer::AnnounceStateUpdate( class GameClient* clFrom,msgBaseClassPtr theMsg )
void GameServer::AnnounceStateUpdate( class GameClient* clFrom,msgBaseClassPtr theMsg, bool immediateOnly )
{
for (GClientList::iterator it=m_clients.begin();it!=m_clients.end();++it)
{
if (it->second!=clFrom)
{
it->second->QueueState(theMsg);
it->second->QueueState(theMsg,immediateOnly);
}
}
}

View file

@ -44,7 +44,7 @@ public:
class GameClient *GetClientWithSessionId(uint32 sessionId);
void CheckAndResend();
void Broadcast(const ByteBuffer &message);
void AnnounceStateUpdate(class GameClient* clFrom,msgBaseClassPtr theMsg);
void AnnounceStateUpdate(class GameClient* clFrom,msgBaseClassPtr theMsg, bool immediateOnly=false);
void AnnounceCommand(class GameClient* clFrom,msgBaseClassPtr theCmd);
ObjectMgr &getObjMgr() { return m_objMgr; }

View file

@ -26,12 +26,33 @@
#include "Common.h"
#include <cmath>
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327
#endif
class LocationVector
{
public:
LocationVector(double X, double Y, double Z) : x(X), y(Y), z(Z) {}
LocationVector() : x(0), y(0), z(0) {}
LocationVector(double X, double Y, double Z, uint8 O) : x(x), y(Y), z(Z), rot(MxoToDoubleRot(O)) {}
LocationVector(double X, double Y, double Z) : x(X), y(Y), z(Z), rot(0) {}
LocationVector() : x(0), y(0), z(0), rot(0) {}
private:
inline double MxoToDoubleRot(uint8 mxoRot)
{
double normalizedRot = (double(mxoRot)/double(256)); //range from 0 to 1
normalizedRot-=0.5f; //range from -0.5 to 0.5
normalizedRot*=2*M_PI; //range from -pi to +pi
return normalizedRot;
}
inline uint8 DoubleToMxoRot(double rot)
{
//start range in -pi to +pi
double normalizedRot = rot/(2*M_PI); //range from -0.5 to 0.5
normalizedRot+=0.5f; //range from 0 to 1
normalizedRot*=255; //range from 0 to 255
return uint8(normalizedRot);
}
public:
// (dx * dx + dy * dy + dz * dz)
double DistanceSq(const LocationVector & comp)
{
@ -97,13 +118,46 @@ public:
double delta_y = Y - y;
return sqrt(delta_x*delta_x + delta_y*delta_y);
}
// atan2(dx / dy)
double CalcAngTo(const LocationVector & dest)
{
double dx = dest.x - x;
double dy = dest.y - y;
if(dy != 0.0f)
return atan2(dy, dx);
else
return 0.0f;
}
inline uint8 CalcAngToMxo(const LocationVector & dest)
{
return DoubleToMxoRot(CalcAngTo(dest));
}
double CalcAngFrom(const LocationVector & src)
{
double dx = x - src.x;
double dy = y - src.y;
if(dy != 0.0f)
return atan2(dy, dx);
else
return 0.0f;
}
inline uint8 CalcAngFromMxo(const LocationVector & dest)
{
return DoubleToMxoRot(CalcAngFrom(dest));
}
void ChangeCoords(double X, double Y, double Z)
{
x = X;
y = Y;
z = Z;
}
void ChangeCoords(double X, double Y, double Z, uint8 O)
{
x = X;
y = Y;
z = Z;
rot = O;
}
// add/subtract/equality vectors
LocationVector & operator += (const LocationVector & add)
@ -111,6 +165,7 @@ public:
x += add.x;
y += add.y;
z += add.z;
rot += add.rot;
return *this;
}
@ -119,6 +174,7 @@ public:
x -= sub.x;
y -= sub.y;
z -= sub.z;
rot -= sub.rot;
return *this;
}
@ -127,6 +183,7 @@ public:
x = eq.x;
y = eq.y;
z = eq.z;
rot = eq.rot;
return *this;
}
@ -137,7 +194,14 @@ public:
else
return false;
}
uint8 getMxoRot()
{
return DoubleToMxoRot(rot);
}
void setMxoRot(uint8 theRot)
{
rot=MxoToDoubleRot(theRot);
}
bool fromDoubleBuf(ByteBuffer &sourceBuf)
{
if (sourceBuf.remaining() < sizeof(double)*3)
@ -198,6 +262,7 @@ public:
double x;
double y;
double z;
double rot;
};
#endif

View file

@ -192,4 +192,39 @@ void Master::_UnhookSignals()
signal(SIGBREAK, 0);
#endif
}
}
#ifdef WIN32
NativeMutex m_crashedMutex;
// Crash Handler
void OnCrash( bool Terminate )
{
ERROR_LOG( "Advanced crash handler initialized." );
if( !m_crashedMutex.AttemptAcquire() )
TerminateThread( GetCurrentThread(), 0 );
try
{
ERROR_LOG( "Waiting for all database queries to finish..." );
sDatabase.EndThreads();
}
catch(...)
{
ERROR_LOG( "Threw an exception while attempting to save all data." );
}
ERROR_LOG( "Closing." );
// Terminate Entire Application
if( Terminate )
{
HANDLE pH = OpenProcess( PROCESS_TERMINATE, TRUE, GetCurrentProcessId() );
TerminateProcess( pH, 1 );
CloseHandle( pH );
}
}
#endif

View file

@ -27,6 +27,7 @@
#include "MessageTypes.h"
#include "Log.h"
#include "GameClient.h"
#include "Timer.h"
PlayerObject::PlayerObject( GameClient &parent,uint64 charUID ) :m_parent(parent),m_characterUID(charUID),m_spawnedInWorld(false)
{
@ -34,7 +35,7 @@ PlayerObject::PlayerObject( GameClient &parent,uint64 charUID ) :m_parent(parent
{
scoped_ptr<QueryResult> result(sDatabase.Query(format("SELECT `handle`,\
`firstName`, `lastName`, `background`,\
`x`, `y`, `z`,\
`x`, `y`, `z`, `rot`, \
`healthC`, `healthM`, `innerStrC`, `innerStrM`,\
`level`, `profession`, `alignment`, `pvpflag`, `exp`, `cash`, `district`\
FROM `characters` WHERE `charId` = '%1%' LIMIT 1") % m_characterUID) );
@ -52,17 +53,19 @@ PlayerObject::PlayerObject( GameClient &parent,uint64 charUID ) :m_parent(parent
m_pos.ChangeCoords( field[4].GetDouble(),
field[5].GetDouble(),
field[6].GetDouble());
m_healthC = field[7].GetUInt16();
m_healthM = field[8].GetUInt16();
m_innerStrC = field[9].GetUInt16();
m_innerStrM = field[10].GetUInt16();
m_lvl = field[11].GetUInt8();
m_prof = field[12].GetUInt8();
m_alignment = field[13].GetUInt8();
m_pvpflag = field[14].GetBool();
m_exp = field[15].GetUInt64();
m_cash = field[16].GetUInt64();
m_district = field[17].GetUInt8();
m_pos.rot = field[7].GetDouble();
m_savedPos = m_pos;
m_healthC = field[8].GetUInt16();
m_healthM = field[9].GetUInt16();
m_innerStrC = field[10].GetUInt16();
m_innerStrM = field[11].GetUInt16();
m_lvl = field[12].GetUInt8();
m_prof = field[13].GetUInt8();
m_alignment = field[14].GetUInt8();
m_pvpflag = field[15].GetBool();
m_exp = field[16].GetUInt64();
m_cash = field[17].GetUInt64();
m_district = field[18].GetUInt8();
}
//grab data from rsi table
{
@ -124,6 +127,7 @@ PlayerObject::PlayerObject( GameClient &parent,uint64 charUID ) :m_parent(parent
m_goId=0;
INFO_LOG(format("Player object for %1% constructed") % m_handle);
testCount=0;
m_lastStore = getTime();
}
void PlayerObject::initGoId(uint32 theGoId)
@ -138,8 +142,10 @@ PlayerObject::~PlayerObject()
{
INFO_LOG(format("Player object for %1%:%2% deconstructing") % m_handle % m_goId);
sGame.AnnounceStateUpdate(&m_parent,make_shared<DeletePlayerMsg>(m_goId));
m_spawnedInWorld=false;
//commit position changes
saveDataToDB();
}
}
@ -151,6 +157,36 @@ uint8 PlayerObject::getRsiData( byte* outputBuf,uint32 maxBufLen ) const
return m_rsi->ToBytes(outputBuf,maxBufLen);
}
void PlayerObject::checkAndStore()
{
if (getTime() - m_lastStore > 60) //every 60 seconds
{
saveDataToDB();
m_lastStore = getTime();
}
}
void PlayerObject::saveDataToDB()
{
if (m_savedPos == m_pos)
return;
bool storeSuccess = sDatabase.Execute(format("UPDATE `characters` SET `x` = '%1%', `y` = '%2%', `z` = '%3%', `rot` = '%4%' WHERE `charId` = '%5%'")
% m_pos.x
% m_pos.y
% m_pos.z
% m_pos.rot
% m_characterUID );
if (!storeSuccess)
WARNING_LOG(format("%1%:%2% failed to save data to database") % m_handle % m_goId );
else
{
m_savedPos = m_pos;
m_parent.QueueCommand(boost::make_shared<SystemChatMsg>( (format("Character data for %1% has been written to the database.") % m_handle).str() ));
}
}
void PlayerObject::InitializeWorld()
{
m_parent.QueueCommand(make_shared<LoadWorldCmd>((LoadWorldCmd::mxoLocation)m_district,"SatiSky"));
@ -219,8 +255,8 @@ void PlayerObject::PopulateWorld()
void PlayerObject::HandleStateUpdate( ByteBuffer &srcData )
{
srcData.rpos(0);
DEBUG_LOG(format("(%1%) 03 data: %2%") % m_parent.Address() % Bin2Hex(srcData) );
checkAndStore();
uint8 zeroThree;
if (srcData.remaining() < sizeof(zeroThree))
return;
@ -236,14 +272,108 @@ void PlayerObject::HandleStateUpdate( ByteBuffer &srcData )
WARNING_LOG(format("Client %1% Player %2%:%3% trying to update someone else's object view %4%") % m_parent.Address() % m_handle % m_goId % viewIdToUpdate);
return;
}
//otherwise just propagate update to all other players
ByteBuffer theStateData;
theStateData.append(&srcData.contents()[srcData.rpos()],srcData.remaining());
sGame.AnnounceStateUpdate(&m_parent,make_shared<StateUpdateMsg>(m_goId,theStateData));
size_t restOfDataPos = srcData.rpos();
uint8 shouldBeOne;
if (srcData.remaining() < sizeof(shouldBeOne))
return;
srcData >> shouldBeOne;
if (shouldBeOne != 1)
{
WARNING_LOG(format("Client %1% Player %2%:%3% 03 doesn't have number 1 after viewId") % m_parent.Address() % m_handle % m_goId);
return;
}
uint8 updateType;
if (srcData.remaining() < sizeof(updateType))
return;
srcData >> updateType;
bool validUpdate=false;
switch (updateType)
{
//change angle
case 0x04:
{
uint8 theRotByte;
if (srcData.remaining() < sizeof(theRotByte))
return;
srcData >> theRotByte;
m_pos.setMxoRot(theRotByte);
validUpdate=true;
break;
}
//change angle with extra param
case 0x06:
{
uint8 theAnimation;
if (srcData.remaining() < sizeof(theAnimation))
return;
srcData >> theAnimation;
//we will just ignore the animation for now
uint8 theRotByte;
if (srcData.remaining() < sizeof(theRotByte))
return;
srcData >> theRotByte;
m_pos.setMxoRot(theRotByte);
validUpdate=true;
break;
}
//update xyz
case 0x08:
{
validUpdate = m_pos.fromFloatBuf(srcData);
break;
}
//update xyz, extra byte before xyz
case 0x0A:
case 0x0C:
{
uint8 extraByte;
if (srcData.remaining() < sizeof(extraByte))
return;
srcData >> extraByte;
validUpdate = m_pos.fromFloatBuf(srcData);
break;
}
//update xyz, extra 2 bytes before xyz
case 0x0E:
{
uint8 extraByte1,extraByte2;
if (srcData.remaining() < sizeof(uint8)*2)
return;
srcData >> extraByte1;
srcData >> extraByte2;
validUpdate = m_pos.fromFloatBuf(srcData);
break;
}
//sometimes happens, no info inside
case 0x02:
{
validUpdate = true;
break;
}
}
if (validUpdate)
{
//propagate state to all other players
srcData.rpos(restOfDataPos);
ByteBuffer theStateData;
theStateData.append(&srcData.contents()[srcData.rpos()],srcData.remaining());
sGame.AnnounceStateUpdate(&m_parent,make_shared<StateUpdateMsg>(m_goId,theStateData),true);
}
else
{
srcData.rpos(0);
DEBUG_LOG(format("(%1%) %2%:%3% 03 data: %4%") % m_parent.Address() % m_handle % m_goId % Bin2Hex(srcData) );
}
}
void PlayerObject::HandleCommand( ByteBuffer &srcCmd )
{
checkAndStore();
uint8 firstByte;
if (srcCmd.remaining() < sizeof(firstByte) )
return;

View file

@ -59,6 +59,9 @@ public:
uint8 getAlignment() const {return m_alignment;}
bool getPvpFlag() const {return m_pvpflag;}
void checkAndStore();
void saveDataToDB();
vector<msgBaseClassPtr> getCurrentStatePackets();
private:
class GameClient &m_parent;
@ -73,7 +76,7 @@ private:
uint32 m_goId;
uint64 m_exp,m_cash;
uint8 m_district;
LocationVector m_pos;
LocationVector m_pos,m_savedPos;
shared_ptr<class RsiData> m_rsi;
uint16 m_healthC,m_healthM,m_innerStrC,m_innerStrM;
uint8 m_prof,m_lvl,m_alignment;
@ -81,6 +84,7 @@ private:
uint32 testCount;
bool m_spawnedInWorld;
uint32 m_lastStore;
};
#endif

View file

@ -21,7 +21,7 @@
OutputDirectory="..\$(ConfigurationName)"
IntermediateDirectory="..\$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
CharacterSet="0"
>
<Tool
Name="VCPreBuildEventTool"
@ -62,7 +62,7 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib libmysql.lib cryptlib.lib Sockets.lib"
AdditionalDependencies="Dbghelp.lib ws2_32.lib libmysql.lib cryptlib.lib Sockets.lib"
OutputFile="..\Binaries\RealityD.exe"
LinkIncremental="2"
AdditionalLibraryDirectories="..\..\Dependencies\CryptoPP\Win32\Output\Debug;..\..\Dependencies\MySQL\lib\32;..\..\Dependencies\Sockets\Project.net\lib\D;..\..\Dependencies\ZThread\lib\D"
@ -100,7 +100,7 @@
OutputDirectory="..\$(ConfigurationName)"
IntermediateDirectory="..\$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
CharacterSet="0"
WholeProgramOptimization="1"
>
<Tool
@ -139,7 +139,7 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="ws2_32.lib libmysql.lib cryptlib.lib Sockets.lib"
AdditionalDependencies="Dbghelp.lib ws2_32.lib libmysql.lib cryptlib.lib Sockets.lib"
OutputFile="..\Binaries\Reality.exe"
LinkIncremental="1"
AdditionalLibraryDirectories="..\..\Dependencies\CryptoPP\Win32\Output\Release;..\..\Dependencies\MySQL\lib\32;..\..\Dependencies\Sockets\Project.net\lib\R;..\..\Dependencies\ZThread\lib\R"
@ -184,7 +184,11 @@
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\CryptoTest.h"
RelativePath=".\CrashHandler.cpp"
>
</File>
<File
RelativePath=".\CrashHandler.h"
>
</File>
<File
@ -200,11 +204,11 @@
>
</File>
<File
RelativePath=".\seqchecktest.h"
RelativePath=".\StackWalker.cpp"
>
</File>
<File
RelativePath=".\SubPacketsTest.h"
RelativePath=".\StackWalker.h"
>
</File>
</Filter>
@ -575,6 +579,18 @@
<Filter
Name="Tests"
>
<File
RelativePath=".\CryptoTest.h"
>
</File>
<File
RelativePath=".\seqchecktest.h"
>
</File>
<File
RelativePath=".\SubPacketsTest.h"
>
</File>
</Filter>
</Files>
<Globals>

View file

@ -19,12 +19,12 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<CharacterSet>NotSet</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
@ -59,7 +59,7 @@
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>ws2_32.lib;libmysql.lib;cryptlib.lib;Sockets.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Dbghelp.lib;ws2_32.lib;libmysql.lib;cryptlib.lib;Sockets.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>..\Binaries\RealityD.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\Dependencies10\CryptoPP\Win32\Output\Debug;..\..\Dependencies10\MySQL\lib\32;..\..\Dependencies10\Sockets\Project.net\lib\D;..\..\Dependencies10\ZThread\lib\D;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
@ -83,7 +83,7 @@
</DebugInformationFormat>
</ClCompile>
<Link>
<AdditionalDependencies>ws2_32.lib;libmysql.lib;cryptlib.lib;Sockets.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Dbghelp.lib;ws2_32.lib;libmysql.lib;cryptlib.lib;Sockets.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>..\Binaries\Reality.exe</OutputFile>
<AdditionalLibraryDirectories>..\..\Dependencies10\CryptoPP\Win32\Output\Release;..\..\Dependencies10\MySQL\lib\32;..\..\Dependencies10\Sockets\Project.net\lib\R;..\..\Dependencies10\ZThread\lib\R;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
@ -98,9 +98,11 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="CrashHandler.h" />
<ClInclude Include="CryptoTest.h" />
<ClInclude Include="Master.h" />
<ClInclude Include="seqchecktest.h" />
<ClInclude Include="StackWalker.h" />
<ClInclude Include="SubPacketsTest.h" />
<ClInclude Include="DotConfPP\dotconfpp.h" />
<ClInclude Include="DotConfPP\mempool.h" />
@ -154,6 +156,7 @@
<ClInclude Include="ConsoleThread.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="CrashHandler.cpp" />
<ClCompile Include="Main.cpp" />
<ClCompile Include="Master.cpp" />
<ClCompile Include="DotConfPP\dotconfpp.cpp" />
@ -162,6 +165,7 @@
<ClCompile Include="Config.cpp" />
<ClCompile Include="Log.cpp" />
<ClCompile Include="MersenneTwister.cpp" />
<ClCompile Include="StackWalker.cpp" />
<ClCompile Include="Util.cpp" />
<ClCompile Include="Database\Database.cpp" />
<ClCompile Include="GameClient.cpp" />

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,201 @@
// *************************************************************************************************
// --------------------------------------
// Copyright (C) 2006-2010 Rajko Stojadinovic
//
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
// *************************************************************************************************
// #pragma once is supported starting with _MCS_VER 1000,
// so we need not to check the version (because we only support _MSC_VER >= 1100)!
#pragma once
//#include <windows.h>
// special defines for VC5/6 (if no actual PSDK is installed):
#if _MSC_VER < 1300
typedef unsigned __int64 DWORD64, *PDWORD64;
#if defined(_WIN64)
typedef unsigned __int64 SIZE_T, *PSIZE_T;
#else
typedef unsigned long SIZE_T, *PSIZE_T;
#endif
#endif // _MSC_VER < 1300
class __declspec(dllexport) StackWalkerInternal; // forward
class __declspec(dllexport) StackWalker
{
public:
typedef enum StackWalkOptions
{
// No addition info will be retrived
// (only the address is available)
RetrieveNone = 0,
// Try to get the symbol-name
RetrieveSymbol = 1,
// Try to get the line for this symbol
RetrieveLine = 2,
// Try to retrieve the module-infos
RetrieveModuleInfo = 4,
// Also retrieve the version for the DLL/EXE
RetrieveFileVersion = 8,
// Contains all the abouve
RetrieveVerbose = 0xF,
// Generate a "good" symbol-search-path
SymBuildPath = 0x10,
// Also use the public Microsoft-Symbol-Server
SymUseSymSrv = 0x20,
// Contains all the abouve "Sym"-options
SymAll = 0x30,
// Contains all options (default)
OptionsAll = 0x3F
} StackWalkOptions;
StackWalker(
int options = OptionsAll, // 'int' is by design, to combine the enum-flags
LPCSTR szSymPath = NULL,
DWORD dwProcessId = GetCurrentProcessId(),
HANDLE hProcess = GetCurrentProcess()
);
StackWalker(DWORD dwProcessId, HANDLE hProcess);
virtual ~StackWalker();
typedef BOOL (__stdcall *PReadProcessMemoryRoutine)(
HANDLE hProcess,
DWORD64 qwBaseAddress,
PVOID lpBuffer,
DWORD nSize,
LPDWORD lpNumberOfBytesRead,
LPVOID pUserData // optional data, which was passed in "ShowCallstack"
);
BOOL LoadModules();
BOOL m_sharedptrlog;
BOOL ShowCallstack(BOOL issharedptrlog = FALSE,
HANDLE hThread = GetCurrentThread(),
const CONTEXT *context = NULL,
PReadProcessMemoryRoutine readMemoryFunction = NULL,
LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback
);
#if _MSC_VER >= 1300
// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public"
// in older compilers in order to use it... starting with VC7 we can declare it as "protected"
protected:
#endif
enum { STACKWALK_MAX_NAMELEN = 1024 }; // max name length for found symbols
protected:
// Entry for each Callstack-Entry
typedef struct CallstackEntry
{
DWORD64 offset; // if 0, we have no valid entry
CHAR name[STACKWALK_MAX_NAMELEN];
CHAR undName[STACKWALK_MAX_NAMELEN];
CHAR undFullName[STACKWALK_MAX_NAMELEN];
DWORD64 offsetFromSmybol;
DWORD offsetFromLine;
DWORD lineNumber;
CHAR lineFileName[STACKWALK_MAX_NAMELEN];
DWORD symType;
LPCSTR symTypeString;
CHAR moduleName[STACKWALK_MAX_NAMELEN];
DWORD64 baseOfImage;
CHAR loadedImageName[STACKWALK_MAX_NAMELEN];
} CallstackEntry;
typedef enum CallstackEntryType {firstEntry, nextEntry, lastEntry};
virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);
virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion);
virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry);
virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);
virtual void OnOutput(LPCSTR szText);
StackWalkerInternal *m_sw;
HANDLE m_hProcess;
DWORD m_dwProcessId;
BOOL m_modulesLoaded;
LPSTR m_szSymPath;
int m_options;
static BOOL __stdcall myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead);
friend StackWalkerInternal;
};
// The "ugly" assembler-implementation is needed for systems before XP
// If you have a new PSDK and you only compile for XP and later, then you can use
// the "RtlCaptureContext"
// Currently there is no define which determines the PSDK-Version...
// So we just use the compiler-version (and assumes that the PSDK is
// the one which was installed by the VS-IDE)
// INFO: If you want, you can use the RtlCaptureContext if you only target XP and later...
// But I currently use it in x64/IA64 environments...
//#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400)
#if defined(_M_IX86)
#ifdef CURRENT_THREAD_VIA_EXCEPTION
// TODO: The following is not a "good" implementation,
// because the callstack is only valid in the "__except" block...
#define GET_CURRENT_CONTEXT(c, contextFlags) \
do { \
memset(&c, 0, sizeof(CONTEXT)); \
EXCEPTION_POINTERS *pExp = NULL; \
__try { \
throw 0; \
} __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \
if (pExp != NULL) \
memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \
c.ContextFlags = contextFlags; \
} while(0);
#else
// The following should be enough for walking the callstack...
#define GET_CURRENT_CONTEXT(c, contextFlags) \
do { \
memset(&c, 0, sizeof(CONTEXT)); \
c.ContextFlags = contextFlags; \
__asm call x \
__asm x: pop eax \
__asm mov c.Eip, eax \
__asm mov c.Ebp, ebp \
__asm mov c.Esp, esp \
} while(0);
#endif
#else
// The following is defined for x86 (XP and higher), x64 and IA64:
#define GET_CURRENT_CONTEXT(c, contextFlags) \
do { \
memset(&c, 0, sizeof(CONTEXT)); \
c.ContextFlags = contextFlags; \
RtlCaptureContext(&c); \
} while(0);
#endif