mirror of
https://github.com/vcmi/vcmi.git
synced 2025-06-17 00:07:41 +02:00
New, experimental crashhandler for windows (creates minidumps).
Several minor fixes and improvements.
This commit is contained in:
@ -3,7 +3,17 @@
|
|||||||
#include "CConsoleHandler.h"
|
#include "CConsoleHandler.h"
|
||||||
#include <boost/function.hpp>
|
#include <boost/function.hpp>
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CConsoleHandler.cpp, part of VCMI engine
|
||||||
|
*
|
||||||
|
* Authors: listed in file AUTHORS in main folder
|
||||||
|
*
|
||||||
|
* License: GNU General Public License v2.0 or later
|
||||||
|
* Full text of license available in license.txt file, in main folder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
typedef std::string TColor;
|
typedef std::string TColor;
|
||||||
@ -17,6 +27,8 @@
|
|||||||
#define CONSOLE_GRAY "\x1b[0;40;39m"
|
#define CONSOLE_GRAY "\x1b[0;40;39m"
|
||||||
#else
|
#else
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <dbghelp.h>
|
||||||
|
#pragma comment(lib, "dbghelp.lib")
|
||||||
|
|
||||||
typedef WORD TColor;
|
typedef WORD TColor;
|
||||||
#define _kill_thread(a) TerminateThread(a,0)
|
#define _kill_thread(a) TerminateThread(a,0)
|
||||||
@ -33,16 +45,101 @@
|
|||||||
|
|
||||||
TColor defColor;
|
TColor defColor;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
void printWinError()
|
||||||
|
{
|
||||||
|
//Get error code
|
||||||
|
int error = GetLastError();
|
||||||
|
if(!error)
|
||||||
|
{
|
||||||
|
tlog0 << "No Win error information set.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tlog1 << "Error " << error << " encountered:\n";
|
||||||
|
|
||||||
|
//Get error description
|
||||||
|
char* pTemp = NULL;
|
||||||
|
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||||
|
NULL, error, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), (LPSTR)&pTemp, 1, NULL);
|
||||||
|
tlog1 << pTemp << std::endl;
|
||||||
|
LocalFree( pTemp );
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* exceptionName(DWORD exc)
|
||||||
|
{
|
||||||
|
#define EXC_CASE(EXC) case EXCEPTION_##EXC : return "EXCEPTION_" #EXC
|
||||||
|
switch (exc)
|
||||||
|
{
|
||||||
|
EXC_CASE(ACCESS_VIOLATION);
|
||||||
|
EXC_CASE(DATATYPE_MISALIGNMENT);
|
||||||
|
EXC_CASE(BREAKPOINT);
|
||||||
|
EXC_CASE(SINGLE_STEP);
|
||||||
|
EXC_CASE(ARRAY_BOUNDS_EXCEEDED);
|
||||||
|
EXC_CASE(FLT_DENORMAL_OPERAND);
|
||||||
|
EXC_CASE(FLT_DIVIDE_BY_ZERO);
|
||||||
|
EXC_CASE(FLT_INEXACT_RESULT);
|
||||||
|
EXC_CASE(FLT_INVALID_OPERATION);
|
||||||
|
EXC_CASE(FLT_OVERFLOW);
|
||||||
|
EXC_CASE(FLT_STACK_CHECK);
|
||||||
|
EXC_CASE(FLT_UNDERFLOW);
|
||||||
|
EXC_CASE(INT_DIVIDE_BY_ZERO);
|
||||||
|
EXC_CASE(INT_OVERFLOW);
|
||||||
|
EXC_CASE(PRIV_INSTRUCTION);
|
||||||
|
EXC_CASE(IN_PAGE_ERROR);
|
||||||
|
EXC_CASE(ILLEGAL_INSTRUCTION);
|
||||||
|
EXC_CASE(NONCONTINUABLE_EXCEPTION);
|
||||||
|
EXC_CASE(STACK_OVERFLOW);
|
||||||
|
EXC_CASE(INVALID_DISPOSITION);
|
||||||
|
EXC_CASE(GUARD_PAGE);
|
||||||
|
EXC_CASE(INVALID_HANDLE);
|
||||||
|
default:
|
||||||
|
return "UNKNOWN EXCEPTION";
|
||||||
|
}
|
||||||
|
#undef EXC_CASE
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
LONG WINAPI onUnhandledException(EXCEPTION_POINTERS* exception)
|
||||||
|
{
|
||||||
|
tlog1 << "Disaster happened.\n";
|
||||||
|
|
||||||
|
PEXCEPTION_RECORD einfo = exception->ExceptionRecord;
|
||||||
|
tlog1 << "Reason: 0x" << std::hex << einfo->ExceptionCode << " - " << exceptionName(einfo->ExceptionCode);
|
||||||
|
tlog1 << " at " << std::setfill('0') << std::setw(4) << exception->ContextRecord->SegCs << ":" << (void*)einfo->ExceptionAddress << std::endl;;
|
||||||
|
|
||||||
|
if (einfo->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
|
||||||
|
{
|
||||||
|
tlog1 << "Attempt to " << (einfo->ExceptionInformation[0] == 1 ? "write to " : "read from ")
|
||||||
|
<< "0x" << std::setw(8) << (void*)einfo->ExceptionInformation[1] << std::endl;;
|
||||||
|
}
|
||||||
|
const DWORD threadId = ::GetCurrentThreadId();
|
||||||
|
tlog1 << "Thread ID: " << threadId << " [" << std::dec << std::setw(0) << threadId << "]\n";
|
||||||
|
|
||||||
|
//exception info to be placed in the dump
|
||||||
|
MINIDUMP_EXCEPTION_INFORMATION meinfo = {threadId, exception, TRUE};
|
||||||
|
|
||||||
|
//create file where dump will be placed
|
||||||
|
char *mname = NULL;
|
||||||
|
char buffer[MAX_PATH + 1];
|
||||||
|
HMODULE hModule = NULL;
|
||||||
|
GetModuleFileNameA(hModule, buffer, MAX_PATH);
|
||||||
|
mname = strrchr(buffer, '\\');
|
||||||
|
if (mname != 0)
|
||||||
|
mname++;
|
||||||
|
else
|
||||||
|
mname = buffer;
|
||||||
|
|
||||||
|
strcat(mname, "_crashinfo.dmp");
|
||||||
|
HANDLE dfile = CreateFileA(mname, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
|
||||||
|
tlog1 << "Crash info will be put in " << dfile << std::endl;
|
||||||
|
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), dfile, MiniDumpWithDataSegs, &meinfo, 0, 0);
|
||||||
|
MessageBoxA(0, "VCMI has crashed. We are sorry. File with information about encountered problem has been created.", "VCMI Crashhandler", MB_OK | MB_ICONERROR);
|
||||||
|
return EXCEPTION_EXECUTE_HANDLER;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* CConsoleHandler.cpp, part of VCMI engine
|
|
||||||
*
|
|
||||||
* Authors: listed in file AUTHORS in main folder
|
|
||||||
*
|
|
||||||
* License: GNU General Public License v2.0 or later
|
|
||||||
* Full text of license available in license.txt file, in main folder
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
void CConsoleHandler::setColor(int level)
|
void CConsoleHandler::setColor(int level)
|
||||||
{
|
{
|
||||||
@ -100,6 +197,7 @@ CConsoleHandler::CConsoleHandler()
|
|||||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||||
GetConsoleScreenBufferInfo(handleOut,&csbi);
|
GetConsoleScreenBufferInfo(handleOut,&csbi);
|
||||||
defColor = csbi.wAttributes;
|
defColor = csbi.wAttributes;
|
||||||
|
SetUnhandledExceptionFilter(onUnhandledException);
|
||||||
#else
|
#else
|
||||||
defColor = "\x1b[0m";
|
defColor = "\x1b[0m";
|
||||||
#endif
|
#endif
|
||||||
|
@ -57,7 +57,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
std::string NAME = NAME_VER + std::string(" (client)"); //application name
|
std::string NAME_AFFIX = "client";
|
||||||
|
std::string NAME = NAME_VER + std::string(" (") + NAME_AFFIX + ')'; //application name
|
||||||
SDL_Surface *screen = NULL, //main screen surface
|
SDL_Surface *screen = NULL, //main screen surface
|
||||||
*screen2 = NULL,//and hlp surface (used to store not-active interfaces layer)
|
*screen2 = NULL,//and hlp surface (used to store not-active interfaces layer)
|
||||||
*screenBuf = screen; //points to screen (if only advmapint is present) or screen2 (else) - should be used when updating controls which are not regularly redrawed
|
*screenBuf = screen; //points to screen (if only advmapint is present) or screen2 (else) - should be used when updating controls which are not regularly redrawed
|
||||||
@ -392,6 +393,12 @@ void processCommand(const std::string &message, CClient *&client)
|
|||||||
}
|
}
|
||||||
tlog0<<"\rExtracting done :)\n";
|
tlog0<<"\rExtracting done :)\n";
|
||||||
}
|
}
|
||||||
|
else if(cn=="crash")
|
||||||
|
{
|
||||||
|
int *ptr = NULL;
|
||||||
|
*ptr = 666;
|
||||||
|
//disaster!
|
||||||
|
}
|
||||||
else if(client && client->serv && client->serv->connected) //send to server
|
else if(client && client->serv && client->serv->connected) //send to server
|
||||||
{
|
{
|
||||||
PlayerMessage pm(LOCPLINT->playerID,message);
|
PlayerMessage pm(LOCPLINT->playerID,message);
|
||||||
|
@ -309,7 +309,7 @@ CSimpleWindow * CMessage::genWindow(std::string text, int player, int Lmar, int
|
|||||||
std::vector<std::string> * brtext = breakText(text,32,true,true);
|
std::vector<std::string> * brtext = breakText(text,32,true,true);
|
||||||
std::vector<std::vector<SDL_Surface*> > * txtg = drawText(brtext, fontHeight);
|
std::vector<std::vector<SDL_Surface*> > * txtg = drawText(brtext, fontHeight);
|
||||||
std::pair<int,int> txts = getMaxSizes(txtg, fontHeight);
|
std::pair<int,int> txts = getMaxSizes(txtg, fontHeight);
|
||||||
ret->bitmap = drawBox1(txts.first+Lmar+Rmar,txts.second+Tmar+Bmar,0);
|
ret->bitmap = drawBox1(txts.first+Lmar+Rmar,txts.second+Tmar+Bmar,player);
|
||||||
ret->pos.h=ret->bitmap->h;
|
ret->pos.h=ret->bitmap->h;
|
||||||
ret->pos.w=ret->bitmap->w;
|
ret->pos.w=ret->bitmap->w;
|
||||||
int curh = ret->bitmap->h/2 - (fontHeight*txtg->size())/2;
|
int curh = ret->bitmap->h/2 - (fontHeight*txtg->size())/2;
|
||||||
|
@ -278,23 +278,16 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
|
|||||||
if(details.result == TryMoveHero::TELEPORTATION || details.start == details.end)
|
if(details.result == TryMoveHero::TELEPORTATION || details.start == details.end)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//initializing objects and performing first step of move
|
|
||||||
int3 hp = details.start;
|
int3 hp = details.start;
|
||||||
if (details.result != TryMoveHero::SUCCESS) //hero failed to move
|
|
||||||
|
if(makingTurn && ho->tempOwner == playerID) //we are moving our hero
|
||||||
{
|
{
|
||||||
if(details.result != TryMoveHero::FAILED)
|
if (details.result != TryMoveHero::SUCCESS && details.result != TryMoveHero::FAILED) //hero didn't change tile but visit succeeded
|
||||||
{
|
{
|
||||||
adventureInt->paths.erase(ho);
|
adventureInt->paths.erase(ho);
|
||||||
adventureInt->terrain.currentPath = NULL;
|
adventureInt->terrain.currentPath = NULL;
|
||||||
}
|
}
|
||||||
|
else if(adventureInt->terrain.currentPath) //&& hero is moving
|
||||||
ho->isStanding = true;
|
|
||||||
stillMoveHero.setn(STOP_MOVE);
|
|
||||||
LOCPLINT->totalRedraw();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (adventureInt->terrain.currentPath) //&& hero is moving
|
|
||||||
{
|
{
|
||||||
//remove one node from the path (the one we went)
|
//remove one node from the path (the one we went)
|
||||||
adventureInt->terrain.currentPath->nodes.erase(adventureInt->terrain.currentPath->nodes.end()-1);
|
adventureInt->terrain.currentPath->nodes.erase(adventureInt->terrain.currentPath->nodes.end()-1);
|
||||||
@ -304,8 +297,17 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
|
|||||||
adventureInt->terrain.currentPath = NULL;
|
adventureInt->terrain.currentPath = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (details.result != TryMoveHero::SUCCESS) //hero failed to move
|
||||||
|
{
|
||||||
|
ho->isStanding = true;
|
||||||
|
stillMoveHero.setn(STOP_MOVE);
|
||||||
|
LOCPLINT->totalRedraw();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//initializing objects and performing first step of move
|
||||||
if(details.end.x+1 == details.start.x && details.end.y+1 == details.start.y) //tl
|
if(details.end.x+1 == details.start.x && details.end.y+1 == details.start.y) //tl
|
||||||
{
|
{
|
||||||
//ho->moveDir = 1;
|
//ho->moveDir = 1;
|
||||||
|
@ -361,9 +361,6 @@ void Graphics::loadHeroAnims()
|
|||||||
loadHeroAnim("AB01_.DEF", rotations, &Graphics::boatAnims);
|
loadHeroAnim("AB01_.DEF", rotations, &Graphics::boatAnims);
|
||||||
loadHeroAnim("AB02_.DEF", rotations, &Graphics::boatAnims);
|
loadHeroAnim("AB02_.DEF", rotations, &Graphics::boatAnims);
|
||||||
loadHeroAnim("AB03_.DEF", rotations, &Graphics::boatAnims);
|
loadHeroAnim("AB03_.DEF", rotations, &Graphics::boatAnims);
|
||||||
VLC->dobjinfo->gobjs[8][0]->handler = boatAnims[0];
|
|
||||||
VLC->dobjinfo->gobjs[8][1]->handler = boatAnims[1];
|
|
||||||
VLC->dobjinfo->gobjs[8][2]->handler = boatAnims[2];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::loadHeroAnim( const std::string &name, const std::vector<std::pair<int,int> > &rotations, std::vector<CDefEssential *> Graphics::*dst )
|
void Graphics::loadHeroAnim( const std::string &name, const std::vector<std::pair<int,int> > &rotations, std::vector<CDefEssential *> Graphics::*dst )
|
||||||
|
2
global.h
2
global.h
@ -20,6 +20,8 @@ typedef boost::int8_t si8; //signed int 8 bits (1 byte)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define NAME_VER ("VCMI 0.72d")
|
#define NAME_VER ("VCMI 0.72d")
|
||||||
|
extern std::string NAME; //full name
|
||||||
|
extern std::string NAME_AFFIX; //client / server
|
||||||
#define CONSOLE_LOGGING_LEVEL 5
|
#define CONSOLE_LOGGING_LEVEL 5
|
||||||
#define FILE_LOGGING_LEVEL 6
|
#define FILE_LOGGING_LEVEL 6
|
||||||
|
|
||||||
|
@ -1058,6 +1058,9 @@ void CGDwelling::newTurn() const
|
|||||||
if(cb->getDate(1) != 1) //not first day of week
|
if(cb->getDate(1) != 1) //not first day of week
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
//town growths are handled separately
|
||||||
|
if(ID == TOWNI_TYPE)
|
||||||
|
return;
|
||||||
|
|
||||||
bool change = false;
|
bool change = false;
|
||||||
|
|
||||||
|
@ -909,13 +909,17 @@ void Mapa::loadHero( CGObjectInstance * &nobj, unsigned char * bufor, int &i )
|
|||||||
nhi->name = readString(bufor,i);
|
nhi->name = readString(bufor,i);
|
||||||
if(version>AB)
|
if(version>AB)
|
||||||
{
|
{
|
||||||
if(readChar(bufor,i))//true if hore's experience is greater than 0
|
if(readChar(bufor,i))//true if hero's experience is greater than 0
|
||||||
{ nhi->exp = readNormalNr(bufor,i); i+=4; }
|
{ nhi->exp = readNormalNr(bufor,i); i+=4; }
|
||||||
else
|
else
|
||||||
nhi->exp = 0xffffffff;
|
nhi->exp = 0xffffffff;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ nhi->exp = readNormalNr(bufor,i); i+=4; }
|
{
|
||||||
|
nhi->exp = readNormalNr(bufor,i); i+=4;
|
||||||
|
if(!nhi->exp) //0 means "not set" in <=AB maps
|
||||||
|
nhi->exp = 0xffffffff;
|
||||||
|
}
|
||||||
|
|
||||||
bool portrait=bufor[i]; ++i;
|
bool portrait=bufor[i]; ++i;
|
||||||
if (portrait)
|
if (portrait)
|
||||||
|
@ -431,6 +431,10 @@ void CMapHandler::init()
|
|||||||
timeHandler th;
|
timeHandler th;
|
||||||
th.getDif();
|
th.getDif();
|
||||||
|
|
||||||
|
CGI->dobjinfo->gobjs[8][0]->handler = graphics->boatAnims[0];
|
||||||
|
CGI->dobjinfo->gobjs[8][1]->handler = graphics->boatAnims[1];
|
||||||
|
CGI->dobjinfo->gobjs[8][2]->handler = graphics->boatAnims[2];
|
||||||
|
|
||||||
// Size of visible terrain.
|
// Size of visible terrain.
|
||||||
mapW = conf.go()->ac.advmapW;
|
mapW = conf.go()->ac.advmapW;
|
||||||
mapH = conf.go()->ac.advmapH;
|
mapH = conf.go()->ac.advmapH;
|
||||||
|
@ -202,6 +202,13 @@ void CGameHandler::changeSecSkill( int ID, int which, int val, bool abs/*=false*
|
|||||||
sss.val = val;
|
sss.val = val;
|
||||||
sss.abs = abs;
|
sss.abs = abs;
|
||||||
sendAndApply(&sss);
|
sendAndApply(&sss);
|
||||||
|
|
||||||
|
if(which == 7) //Wisdom
|
||||||
|
{
|
||||||
|
const CGHeroInstance *h = getHero(ID);
|
||||||
|
if(h && h->visitedTown)
|
||||||
|
giveSpells(h->visitedTown, h);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::changePrimSkill(int ID, int which, int val, bool abs)
|
void CGameHandler::changePrimSkill(int ID, int which, int val, bool abs)
|
||||||
@ -661,6 +668,9 @@ void CGameHandler::newTurn()
|
|||||||
|
|
||||||
BOOST_FOREACH(CGHeroInstance *h, (*i).second.heroes)
|
BOOST_FOREACH(CGHeroInstance *h, (*i).second.heroes)
|
||||||
{
|
{
|
||||||
|
if(h->visitedTown)
|
||||||
|
giveSpells(h->visitedTown, h);
|
||||||
|
|
||||||
NewTurn::Hero hth;
|
NewTurn::Hero hth;
|
||||||
hth.id = h->id;
|
hth.id = h->id;
|
||||||
hth.move = h->maxMovePoints(gs->map->getTile(h->getPosition(false)).tertype != TerrainTile::water);
|
hth.move = h->maxMovePoints(gs->map->getTile(h->getPosition(false)).tertype != TerrainTile::water);
|
||||||
@ -1273,6 +1283,13 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
|
|||||||
|
|
||||||
tlog5 << "Player " <<int(asker) << " wants to move hero "<< hid << " from "<< h->pos << " to " << dst << std::endl;
|
tlog5 << "Player " <<int(asker) << " wants to move hero "<< hid << " from "<< h->pos << " to " << dst << std::endl;
|
||||||
int3 hmpos = dst + int3(-1,0,0);
|
int3 hmpos = dst + int3(-1,0,0);
|
||||||
|
|
||||||
|
if(!gs->map->isInTheMap(hmpos))
|
||||||
|
{
|
||||||
|
tlog1 << "Destination tile os out of the map!\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
TerrainTile t = gs->map->terrain[hmpos.x][hmpos.y][hmpos.z];
|
TerrainTile t = gs->map->terrain[hmpos.x][hmpos.y][hmpos.z];
|
||||||
int cost = gs->getMovementCost(h,h->getPosition(false),CGHeroInstance::convertPosition(dst,false),h->movement);
|
int cost = gs->getMovementCost(h,h->getPosition(false),CGHeroInstance::convertPosition(dst,false),h->movement);
|
||||||
|
|
||||||
@ -2934,4 +2951,6 @@ bool CGameHandler::buildBoat( ui32 objid )
|
|||||||
no.subID = 1;
|
no.subID = 1;
|
||||||
no.pos = tile + int3(1,0,0);
|
no.pos = tile + int3(1,0,0);
|
||||||
sendAndApply(&no);
|
sendAndApply(&no);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
@ -25,7 +25,8 @@
|
|||||||
#include "../lib/Interprocess.h"
|
#include "../lib/Interprocess.h"
|
||||||
#include "../lib/VCMI_Lib.h"
|
#include "../lib/VCMI_Lib.h"
|
||||||
#include "CGameHandler.h"
|
#include "CGameHandler.h"
|
||||||
std::string NAME = NAME_VER + std::string(" (server)");
|
std::string NAME_AFFIX = "server";
|
||||||
|
std::string NAME = NAME_VER + std::string(" (") + NAME_AFFIX + ')'; //application name
|
||||||
using namespace boost;
|
using namespace boost;
|
||||||
using namespace boost::asio;
|
using namespace boost::asio;
|
||||||
using namespace boost::asio::ip;
|
using namespace boost::asio::ip;
|
||||||
|
Reference in New Issue
Block a user