This commit is contained in:
HarrievG 2021-05-11 22:45:24 +02:00 committed by Daniel Gibson
parent a8ef0f67fe
commit 7a2ccee330
31 changed files with 1038 additions and 499 deletions

1
.gitignore vendored
View file

@ -12,3 +12,4 @@
/neo/out*
/neo/build*
/neo/CMakeSettings.json

View file

@ -862,6 +862,9 @@ if (TOOLS AND MFC_FOUND AND MSVC)
# Script editor
file(GLOB src_script_editor "tools/script/*.cpp")
add_globbed_headers(src_script_editor "tools/script")
# Script Debugger
file(GLOB src_script_debugger "tools/debugger/*.cpp")
add_globbed_headers(src_script_debugger "tools/debugger")
# sound editor?
file(GLOB src_sound_editor "tools/sound/*.cpp")
add_globbed_headers(src_sound_editor "tools/sound")
@ -881,6 +884,7 @@ if (TOOLS AND MFC_FOUND AND MSVC)
${src_map_editor}
${src_script_editor}
${src_sound_editor}
${src_script_debugger}
"tools/edit_public.h"
"tools/edit_gui_common.h"
)

View file

@ -244,7 +244,7 @@ void idInternalCVar::UpdateValue( void ) {
clamped = true;
}
}
if ( clamped || !idStr::IsNumeric( value ) || idStr::FindChar( value, '.' ) ) {
if ( clamped || !idStr::IsNumeric( value ) || (idStr::FindChar( value, '.' )!=-1) ) {
valueString = idStr( integerValue );
value = valueString.c_str();
}

View file

@ -142,6 +142,7 @@ public:
virtual void ActivateTool( bool active );
virtual void WriteConfigToFile( const char *filename );
virtual void WriteFlaggedCVarsToFile( const char *filename, int flags, const char *setCmd );
virtual void DebuggerCheckBreakpoint(idInterpreter* interpreter, idProgram* program, int instructionPointer);
virtual void BeginRedirect( char *buffer, int buffersize, void (*flush)( const char * ) );
virtual void EndRedirect( void );
virtual void SetRefreshOnPrint( bool set );
@ -382,12 +383,17 @@ void idCommonLocal::VPrintf( const char *fmt, va_list args ) {
// remove any color codes
idStr::RemoveColors( msg );
// echo to dedicated console and early console
Sys_Printf( "%s", msg );
#ifdef ID_ALLOW_TOOLS
// print to script debugger server
// DebuggerServerPrint( msg );
if (com_editors & EDITOR_DEBUGGER)
DebuggerServerPrint(msg);
else
#endif
// only echo to dedicated console and early console when debugger is not running so no
// deadlocks occur if engine functions called from the debuggerthread trace stuff..
Sys_Printf("%s", msg);
#if 0 // !@#
#if defined(_DEBUG) && defined(WIN32)
if ( strlen( msg ) < 512 ) {
@ -1134,8 +1140,7 @@ Com_ScriptDebugger_f
static void Com_ScriptDebugger_f( const idCmdArgs &args ) {
// Make sure it wasnt on the command line
if ( !( com_editors & EDITOR_DEBUGGER ) ) {
common->Printf( "Script debugger is currently disabled\n" );
// DebuggerClientLaunch();
DebuggerClientLaunch();
}
}
@ -2020,6 +2025,7 @@ void Com_LocalizeMaps_f( const idCmdArgs &args ) {
strCount += LocalizeMap(args.Argv(2), strTable, listHash, excludeList, write);
} else {
idStrList files;
//wow, what now? a hardcoded path?
GetFileList("z:/d3xp/d3xp/maps/game", "*.map", files);
for ( int i = 0; i < files.Num(); i++ ) {
idStr file = fileSystem->OSPathToRelativePath(files[i]);
@ -2666,7 +2672,7 @@ void idCommonLocal::LoadGameDLL( void ) {
gameImport.AASFileManager = ::AASFileManager;
gameImport.collisionModelManager = ::collisionModelManager;
gameExport = *GetGameAPI( &gameImport );
gameExport = *GetGameAPI( &gameImport);
if ( gameExport.version != GAME_API_VERSION ) {
Sys_DLL_Unload( gameDLL );
@ -3164,8 +3170,10 @@ void idCommonLocal::InitGame( void ) {
// initialize the user interfaces
uiManager->Init();
#if defined(ID_ALLOW_TOOLS)
// startup the script debugger
// DebuggerServerInit();
DebuggerServerInit();
#endif;
PrintLoadingMessage( common->GetLanguageDict()->GetString( "#str_04350" ) );
@ -3202,8 +3210,10 @@ void idCommonLocal::ShutdownGame( bool reloading ) {
sw->StopAllSounds();
}
#if defined(ID_ALLOW_TOOLS)
// shutdown the script debugger
// DebuggerServerShutdown();
DebuggerServerShutdown();
#endif
idAsyncNetwork::client.Shutdown();
@ -3298,6 +3308,10 @@ bool idCommonLocal::GetAdditionalFunction(idCommon::FunctionType ft, idCommon::F
}
}
void idCommonLocal::DebuggerCheckBreakpoint(idInterpreter* interpreter, idProgram* program, int instructionPointer)
{
DebuggerServerCheckBreakpoint(interpreter, program, instructionPointer);
}
idGameCallbacks gameCallbacks;

View file

@ -111,6 +111,8 @@ struct MemInfo_t {
};
class idLangDict;
class idInterpreter;
class idProgram;
class idCommon {
public:
@ -158,6 +160,9 @@ public:
// Writes cvars with the given flags to a file.
virtual void WriteFlaggedCVarsToFile( const char *filename, int flags, const char *setCmd ) = 0;
// Debbugger hook to check if a breakpoint has been hit
virtual void DebuggerCheckBreakpoint(idInterpreter* interpreter, idProgram* program, int instructionPointer) = 0;
// Begins redirection of console output to the given buffer.
virtual void BeginRedirect( char *buffer, int buffersize, void (*flush)( const char * ) ) = 0;

View file

@ -31,6 +31,7 @@ If you have questions concerning this license or the applicable additional terms
#include "idlib/BitMsg.h"
#include "idlib/Dict.h"
#include "idlib/containers/StrList.h"
#include "framework/UsercmdGen.h"
#include "renderer/RenderWorld.h"
#include "sound/sound.h"
@ -109,10 +110,10 @@ public:
virtual void SetPersistentPlayerInfo( int clientNum, const idDict &playerInfo ) = 0;
// Loads a map and spawns all the entities.
virtual void InitFromNewMap( const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, bool isServer, bool isClient, int randseed ) = 0;
virtual void InitFromNewMap( const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, bool isServer, bool isClient, int randseed, int activeEditors ) = 0;
// Loads a map from a savegame file.
virtual bool InitFromSaveGame( const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, idFile *saveGameFile ) = 0;
virtual bool InitFromSaveGame( const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, idFile *saveGameFile, int activeEditors ) = 0;
// Saves the current game state, the session may have written some data to the file already.
virtual void SaveGame( idFile *saveGameFile ) = 0;
@ -127,7 +128,7 @@ public:
virtual void SpawnPlayer( int clientNum ) = 0;
// Runs a game frame, may return a session command for level changing, etc
virtual gameReturn_t RunFrame( const usercmd_t *clientCmds ) = 0;
virtual gameReturn_t RunFrame( const usercmd_t *clientCmds , int activeEditors) = 0;
// Makes rendering and sound system calls to display for a given clientNum.
virtual bool Draw( int clientNum ) = 0;
@ -232,6 +233,11 @@ enum {
class idEntity;
class idMD5Anim;
class idThread;
class function_t;
class idProgram;
class idInterpreter;
typedef struct prstack_s prstack_t;
// FIXME: this interface needs to be reworked but it properly separates code for the time being
class idGameEdit {
@ -294,7 +300,7 @@ public:
virtual void EntitySetColor( idEntity *ent, const idVec3 color );
// Player methods.
virtual bool PlayerIsValid() const;
virtual bool PlayerIsValid( ) const;
virtual void PlayerGetOrigin( idVec3 &org ) const;
virtual void PlayerGetAxis( idMat3 &axis ) const;
virtual void PlayerGetViewAngles( idAngles &angles ) const;
@ -311,6 +317,35 @@ public:
virtual void MapRemoveEntity( const char *name ) const;
virtual void MapEntityTranslate( const char *name, const idVec3 &v ) const;
// In game script Debugging Support
// IdProgram
virtual void GetLoadedScripts( idStrList ** result );
virtual bool IsLineCode( const char* filename, int linenumber) const;
virtual const char * GetFilenameForStatement( idProgram* program, int index ) const;
virtual int GetLineNumberForStatement( idProgram* program, int index ) const;
// idInterpreter
virtual bool CheckForBreakPointHit( const idInterpreter* interpreter, const function_t* function1, const function_t* function2, int depth ) const;
virtual bool ReturnedFromFunction( const idProgram* program, const idInterpreter* interpreter, int index ) const;
virtual bool GetRegisterValue( const idInterpreter* interpreter, const char* name, idStr& out, int scopeDepth ) const;
virtual const idThread* GetThread( const idInterpreter* interpreter ) const;
virtual int GetInterpreterCallStackDepth( const idInterpreter* interpreter );
virtual const function_t* GetInterpreterCallStackFunction( const idInterpreter* interpreter, int stackDepth = -1 );
// IdThread
virtual const char * ThreadGetName( const idThread* thread ) const;
virtual int ThreadGetNum( const idThread* thread ) const;
virtual bool ThreadIsDoneProcessing( const idThread* thread ) const;
virtual bool ThreadIsWaiting( const idThread* thread ) const;
virtual bool ThreadIsDying( const idThread* thread ) const;
virtual int GetTotalScriptThreads( ) const;
virtual const idThread* GetThreadByIndex( int index ) const;
// MSG helpers
virtual void MSG_WriteThreadInfo( idBitMsg* msg, const idThread* thread, const idInterpreter* interpreter );
virtual void MSG_WriteCallstackFunc( idBitMsg* msg, const prstack_t* stack, const idProgram* program, int instructionPtr );
virtual void MSG_WriteInterpreterInfo( idBitMsg* msg, const idInterpreter* interpreter, const idProgram* program, int instructionPtr );
virtual void MSG_WriteScriptList( idBitMsg* msg );
};
extern idGameEdit * gameEdit;

View file

@ -1646,7 +1646,7 @@ void idSessionLocal::ExecuteMapChange( bool noFadeWipe ) {
// load and spawn all other entities ( from a savegame possibly )
if ( loadingSaveGame && savegameFile ) {
if ( game->InitFromSaveGame( fullMapName + ".map", rw, sw, savegameFile ) == false ) {
if ( game->InitFromSaveGame( fullMapName + ".map", rw, sw, savegameFile, com_editors ) == false ) {
// If the loadgame failed, restart the map with the player persistent data
loadingSaveGame = false;
fileSystem->CloseFile( savegameFile );
@ -1655,11 +1655,11 @@ void idSessionLocal::ExecuteMapChange( bool noFadeWipe ) {
common->Warning( "WARNING: Loading savegame failed, will restart the map with the player persistent data!" );
game->SetServerInfo( mapSpawnData.serverInfo );
game->InitFromNewMap( fullMapName + ".map", rw, sw, idAsyncNetwork::server.IsActive(), idAsyncNetwork::client.IsActive(), Sys_Milliseconds() );
game->InitFromNewMap( fullMapName + ".map", rw, sw, idAsyncNetwork::server.IsActive(), idAsyncNetwork::client.IsActive(), Sys_Milliseconds(),com_editors );
}
} else {
game->SetServerInfo( mapSpawnData.serverInfo );
game->InitFromNewMap( fullMapName + ".map", rw, sw, idAsyncNetwork::server.IsActive(), idAsyncNetwork::client.IsActive(), Sys_Milliseconds() );
game->InitFromNewMap( fullMapName + ".map", rw, sw, idAsyncNetwork::server.IsActive(), idAsyncNetwork::client.IsActive(), Sys_Milliseconds(), com_editors);
}
if ( !idAsyncNetwork::IsActive() && !loadingSaveGame ) {
@ -1681,7 +1681,7 @@ void idSessionLocal::ExecuteMapChange( bool noFadeWipe ) {
if ( !idAsyncNetwork::IsActive() && !loadingSaveGame ) {
// run a few frames to allow everything to settle
for ( i = 0; i < 10; i++ ) {
game->RunFrame( mapSpawnData.mapSpawnUsercmd );
game->RunFrame( mapSpawnData.mapSpawnUsercmd, com_editors);
}
}
@ -2785,7 +2785,7 @@ void idSessionLocal::RunGameTic() {
// run the game logic every player move
int start = Sys_Milliseconds();
gameReturn_t ret = game->RunFrame( &cmd );
gameReturn_t ret = game->RunFrame( &cmd, com_editors);
int end = Sys_Milliseconds();
time_gameFrame += end - start; // note time used for com_speeds

View file

@ -2442,7 +2442,7 @@ void idAsyncServer::RunFrame( void ) {
DuplicateUsercmds( gameFrame, gameTime );
// advance game
gameReturn_t ret = game->RunFrame( userCmds[gameFrame & ( MAX_USERCMD_BACKUP - 1 ) ] );
gameReturn_t ret = game->RunFrame( userCmds[gameFrame & ( MAX_USERCMD_BACKUP - 1 ) ], com_editors );
idAsyncNetwork::ExecuteSessionCommand( ret.sessionCommand );

View file

@ -1146,3 +1146,64 @@ void idGameEdit::MapEntityTranslate( const char *name, const idVec3 &v ) const {
}
}
}
/***********************************************************************
Debugger
***********************************************************************/
bool idGameEdit::IsLineCode(const char* filename, int linenumber) const
{
static idStr fileStr = idStr(MAX_PATH);
idProgram* program = &gameLocal.program;
for (int i = 0; i < program->NumStatements(); i++)
{
fileStr = program->GetFilename(program->GetStatement(i).file);
fileStr.BackSlashesToSlashes();
if (strcmp(filename, fileStr.c_str()) == 0
&& program->GetStatement(i).linenumber == linenumber
)
{
return true;
}
}
return false;
}
void idGameEdit::GetLoadedScripts( idStrList** result )
{
(*result)->Clear();
idProgram* program = &gameLocal.program;
for (int i = 0; i < program->NumFilenames(); i++)
{
(*result)->AddUnique( idStr(program->GetFilename( i )) );
}
}
void idGameEdit::MSG_WriteScriptList( idBitMsg* msg)
{
idProgram* program = &gameLocal.program;
msg->WriteInt( program->NumFilenames() );
for (int i = 0; i < program->NumFilenames(); i++)
{
idStr file = program->GetFilename(i);
//fix this. it seams that scripts triggered by the runtime are stored with a wrong path
//the use // instead of '\'
file.BackSlashesToSlashes();
msg->WriteString(file);
}
}
const char* idGameEdit::GetFilenameForStatement(idProgram* program, int index) const
{
return program->GetFilenameForStatement(index);
}
int idGameEdit::GetLineNumberForStatement(idProgram* program, int index) const
{
return program->GetLineNumberForStatement(index);
}

View file

@ -1192,7 +1192,7 @@ void idGameLocal::MapPopulate( void ) {
idGameLocal::InitFromNewMap
===================
*/
void idGameLocal::InitFromNewMap( const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, bool isServer, bool isClient, int randseed ) {
void idGameLocal::InitFromNewMap( const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, bool isServer, bool isClient, int randseed, int activeEditors) {
this->isServer = isServer;
this->isClient = isClient;
@ -1204,6 +1204,8 @@ void idGameLocal::InitFromNewMap( const char *mapName, idRenderWorld *renderWorl
Printf( "----- Game Map Init -----\n" );
//exposing editor flag so debugger does not miss any script calls during load/startup
editors = activeEditors;
gamestate = GAMESTATE_STARTUP;
gameRenderWorld = renderWorld;
@ -1230,7 +1232,7 @@ void idGameLocal::InitFromNewMap( const char *mapName, idRenderWorld *renderWorl
idGameLocal::InitFromSaveGame
=================
*/
bool idGameLocal::InitFromSaveGame( const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, idFile *saveGameFile ) {
bool idGameLocal::InitFromSaveGame( const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, idFile *saveGameFile, int activeEditors ) {
int i;
int num;
idEntity *ent;
@ -1242,6 +1244,8 @@ bool idGameLocal::InitFromSaveGame( const char *mapName, idRenderWorld *renderWo
Printf( "----- Game Map Init SaveGame -----\n" );
//exposing editor flag so debugger does not miss any script calls during load/startup
editors = activeEditors;
gamestate = GAMESTATE_STARTUP;
gameRenderWorld = renderWorld;
@ -2215,14 +2219,17 @@ void idGameLocal::SortActiveEntityList( void ) {
idGameLocal::RunFrame
================
*/
gameReturn_t idGameLocal::RunFrame( const usercmd_t *clientCmds ) {
idEntity * ent;
int num;
float ms;
idTimer timer_think, timer_events, timer_singlethink;
gameReturn_t ret;
idPlayer *player;
const renderView_t *view;
gameReturn_t idGameLocal::RunFrame( const usercmd_t *clientCmds, int activeEditors ) {
idEntity * ent;
int num;
float ms;
idTimer timer_think, timer_events, timer_singlethink;
gameReturn_t ret;
idPlayer *player;
const renderView_t *view;
//exposing editor flag so debugger does not miss any script calls during load/startup
editors = activeEditors;
#ifdef _DEBUG
if ( isMultiplayer ) {

View file

@ -293,7 +293,7 @@ public:
idEntityPtr<idEntity> lastGUIEnt; // last entity with a GUI, used by Cmd_NextGUI_f
int lastGUI; // last GUI on the lastGUIEnt
int editors; // Mirrored editors flags from common to determine which editors are running
// ---------------------- Public idGame Interface -------------------
idGameLocal();
@ -308,13 +308,13 @@ public:
virtual const idDict & GetPersistentPlayerInfo( int clientNum );
virtual void SetPersistentPlayerInfo( int clientNum, const idDict &playerInfo );
virtual void InitFromNewMap( const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, bool isServer, bool isClient, int randSeed );
virtual bool InitFromSaveGame( const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, idFile *saveGameFile );
virtual void InitFromNewMap( const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, bool isServer, bool isClient, int randSeed, int activeEditors);
virtual bool InitFromSaveGame( const char *mapName, idRenderWorld *renderWorld, idSoundWorld *soundWorld, idFile *saveGameFile, int activeEditors);
virtual void SaveGame( idFile *saveGameFile );
virtual void MapShutdown( void );
virtual void CacheDictionaryMedia( const idDict *dict );
virtual void SpawnPlayer( int clientNum );
virtual gameReturn_t RunFrame( const usercmd_t *clientCmds );
virtual gameReturn_t RunFrame( const usercmd_t *clientCmds , int activeEditors);
virtual bool Draw( int clientNum );
virtual escReply_t HandleESC( idUserInterface **gui );
virtual idUserInterface *StartMenu( void );

View file

@ -33,6 +33,8 @@ If you have questions concerning this license or the applicable additional terms
#include "script/Script_Interpreter.h"
#include "framework/FileSystem.h"
/*
================
idInterpreter::idInterpreter()
@ -183,7 +185,6 @@ idInterpreter::GetRegisterValue
Returns a string representation of the value of the register. This is
used primarily for the debugger and debugging
//FIXME: This is pretty much wrong. won't access data in most situations.
================
*/
bool idInterpreter::GetRegisterValue( const char *name, idStr &out, int scopeDepth ) {
@ -191,17 +192,17 @@ bool idInterpreter::GetRegisterValue( const char *name, idStr &out, int scopeDep
idVarDef *d;
char funcObject[ 1024 ];
char *funcName;
const idVarDef *scope;
const idVarDef *scope = NULL;
const idVarDef *scopeObj;
const idTypeDef *field;
const idScriptObject *obj;
const function_t *func;
out.Empty();
if ( scopeDepth == -1 ) {
scopeDepth = callStackDepth;
}
}
if ( scopeDepth == callStackDepth ) {
func = currentFunction;
} else {
@ -215,35 +216,44 @@ bool idInterpreter::GetRegisterValue( const char *name, idStr &out, int scopeDep
funcName = strstr( funcObject, "::" );
if ( funcName ) {
*funcName = '\0';
scope = gameLocal.program.GetDef( NULL, funcObject, &def_namespace );
funcName += 2;
scopeObj = gameLocal.program.GetDef( NULL, funcObject, &def_namespace );
funcName += 2;
if ( scopeObj )
{
scope = gameLocal.program.GetDef( NULL, funcName, scopeObj );
}
} else {
funcName = funcObject;
scope = &def_namespace;
scope = gameLocal.program.GetDef( NULL, func->Name(), &def_namespace );
scopeObj = NULL;
}
// Get the function from the object
d = gameLocal.program.GetDef( NULL, funcName, scope );
if ( !d ) {
if ( !scope )
{
return false;
}
// Get the variable itself and check various namespaces
d = gameLocal.program.GetDef( NULL, name, d );
if ( !d ) {
if ( scope == &def_namespace ) {
return false;
}
d = gameLocal.program.GetDef( NULL, name, scope );
if ( !d ) {
d = gameLocal.program.GetDef( NULL, name, &def_namespace );
if ( !d ) {
return false;
d = gameLocal.program.GetDef( NULL, name, scope );
// Check the objects for it if it wasnt local to the function
if ( !d )
{
for ( ; scopeObj && scopeObj->TypeDef()->SuperClass(); scopeObj = scopeObj->TypeDef()->SuperClass()->def )
{
d = gameLocal.program.GetDef( NULL, name, scopeObj );
if ( d )
{
break;
}
}
}
}
if ( !d )
{
out = "???";
return false;
}
reg = GetVariable( d );
switch( d->Type() ) {
case ev_float:
@ -256,7 +266,7 @@ bool idInterpreter::GetRegisterValue( const char *name, idStr &out, int scopeDep
break;
case ev_vector:
if ( reg.vectorPtr ) {
if ( reg.vectorPtr ) {
out = va( "%g,%g,%g", reg.vectorPtr->x, reg.vectorPtr->y, reg.vectorPtr->z );
} else {
out = "0,0,0";
@ -274,30 +284,55 @@ bool idInterpreter::GetRegisterValue( const char *name, idStr &out, int scopeDep
break;
case ev_field:
{
idEntity* entity;
idScriptObject* obj;
if ( scope == &def_namespace ) {
// should never happen, but handle it safely anyway
return false;
}
field = scope->TypeDef()->GetParmType( reg.ptrOffset )->FieldType();
obj = *reinterpret_cast<const idScriptObject **>( &localstack[ callStack[ callStackDepth ].stackbase ] );
if ( !field || !obj ) {
field = d->TypeDef()->FieldType();
entity = GetEntity ( *((int*)&localstack[ localstackBase ]) );
if ( !entity || !field )
{
return false;
}
obj = &entity->scriptObject;
if ( !obj ) {
return false;
}
switch ( field->Type() ) {
case ev_boolean:
out = va( "%d", *( reinterpret_cast<int *>( &obj->data[ reg.ptrOffset ] ) ) );
return true;
case ev_boolean:
out = va( "%d", *( reinterpret_cast<int *>( &obj->data[ reg.ptrOffset ] ) ) );
return true;
case ev_float:
out = va( "%g", *( reinterpret_cast<float *>( &obj->data[ reg.ptrOffset ] ) ) );
return true;
case ev_float:
out = va( "%g", *( reinterpret_cast<float *>( &obj->data[ reg.ptrOffset ] ) ) );
return true;
case ev_string: {
const char* str;
str = reinterpret_cast<const char*>( &obj->data[ reg.ptrOffset ] );
if ( !str ) {
out = "\"\"";
} else {
out = "\"";
out += str;
out += "\"";
}
return true;
}
default:
return false;
default:
return false;
}
break;
}
case ev_string:
if ( reg.stringPtr ) {
@ -969,6 +1004,19 @@ bool idInterpreter::Execute( void ) {
// next statement
st = &gameLocal.program.GetStatement( instructionPointer );
if (gameLocal.editors & EDITOR_DEBUGGER ) {
common->DebuggerCheckBreakpoint ( this, &gameLocal.program, instructionPointer );
} else if ( g_debugScript.GetBool ( ) ) {
static int lastLineNumber = -1;
if ( lastLineNumber != gameLocal.program.GetStatement ( instructionPointer ).linenumber ) {
gameLocal.Printf ( "%s (%d)\n",
gameLocal.program.GetFilename ( gameLocal.program.GetStatement ( instructionPointer ).file ),
gameLocal.program.GetStatement ( instructionPointer ).linenumber
);
lastLineNumber = gameLocal.program.GetStatement ( instructionPointer ).linenumber;
}
}
switch( st->op ) {
case OP_RETURN:
LeaveFunction( st->a );
@ -1833,3 +1881,98 @@ bool idInterpreter::Execute( void ) {
return threadDying;
}
bool idGameEdit::CheckForBreakPointHit(const idInterpreter* interpreter, const function_t* function1, const function_t* function2, int depth) const
{
return ( ( interpreter->GetCurrentFunction ( ) == function1 ||
interpreter->GetCurrentFunction ( ) == function2)&&
( interpreter->GetCallstackDepth ( ) <= depth) );
}
bool idGameEdit::ReturnedFromFunction(const idProgram* program, const idInterpreter* interpreter, int index) const
{
return ( const_cast<idProgram*>(program)->GetStatement(index).op == OP_RETURN && interpreter->GetCallstackDepth ( ) <= 1 );
}
bool idGameEdit::GetRegisterValue(const idInterpreter* interpreter, const char* name, idStr& out, int scopeDepth) const
{
return const_cast<idInterpreter*>(interpreter)->GetRegisterValue(name, out, scopeDepth);
}
const idThread* idGameEdit::GetThread(const idInterpreter* interpreter) const
{
return interpreter->GetThread();
}
void idGameEdit::MSG_WriteCallstackFunc(idBitMsg* msg, const prstack_t* stack, const idProgram * program, int instructionPtr)
{
const statement_t* st;
const function_t* func;
func = stack->f;
// If the function is unknown then just fill in with default data.
if ( !func )
{
msg->WriteString ( "<UNKNOWN>" );
msg->WriteString ( "<UNKNOWN>" );
msg->WriteInt ( 0 );
return;
}
else
{
msg->WriteString ( va("%s( )", func->Name() ) );
}
if (stack->s == -1) //this is a fake stack created by debugger, use intruction pointer for retrieval.
st = &const_cast<idProgram*>( program )->GetStatement( instructionPtr );
else // Use the calling statement as the filename and linenumber where the call was made from
st = &const_cast<idProgram*>( program )->GetStatement ( stack->s );
if ( st )
{
idStr qpath = const_cast<idProgram*>( program )->GetFilename( st->file );
if (idStr::FindChar( qpath, ':' ) != -1)
qpath = fileSystem->OSPathToRelativePath( qpath.c_str() );
qpath.BackSlashesToSlashes ( );
msg->WriteString( qpath );
msg->WriteInt( st->linenumber );
}
else
{
msg->WriteString ( "<UNKNOWN>" );
msg->WriteInt ( 0 );
}
}
void idGameEdit::MSG_WriteInterpreterInfo(idBitMsg* msg, const idInterpreter* interpreter, const idProgram* program, int instructionPtr)
{
int i;
prstack_s temp;
msg->WriteShort((int)interpreter->GetCallstackDepth( ) );
// write out the current function
temp.f = interpreter->GetCurrentFunction( );
temp.s = -1;
temp.stackbase = 0;
MSG_WriteCallstackFunc( msg, &temp, program, instructionPtr);
// Run through all of the callstack and write each to the msg
for (i = interpreter->GetCallstackDepth() - 1; i > 0; i--)
{
MSG_WriteCallstackFunc( msg, interpreter->GetCallstack( ) + i, program, instructionPtr);
}
}
int idGameEdit::GetInterpreterCallStackDepth(const idInterpreter* interpreter)
{
return interpreter->GetCallstackDepth();
}
const function_t* idGameEdit::GetInterpreterCallStackFunction( const idInterpreter* interpreter, int stackDepth/* = -1*/)
{
return interpreter->GetCallstack( )[ stackDepth > -1 ? stackDepth :interpreter->GetCallstackDepth( ) ].f;
}

View file

@ -34,7 +34,7 @@ If you have questions concerning this license or the applicable additional terms
#include "idlib/containers/HashIndex.h"
#include "idlib/math/Vector.h"
#include "GameBase.h"
//#include "GameBase.h"
class idEventDef;
class idVarDef;

View file

@ -28,11 +28,11 @@ If you have questions concerning this license or the applicable additional terms
#include "sys/platform.h"
#include "gamesys/SysCvar.h"
#include "Player.h"
#include "Camera.h"
#include "game/gamesys/SysCvar.h"
#include "game/Player.h"
#include "game/Camera.h"
#include "script/Script_Thread.h"
#include "Script_Thread.h"
const idEventDef EV_Thread_Execute( "<execute>", NULL );
const idEventDef EV_Thread_SetCallback( "<script_setcallback>", NULL );
@ -1841,3 +1841,49 @@ void idThread::Event_InfluenceActive( void ) {
idThread::ReturnInt( false );
}
}
int idGameEdit::ThreadGetNum(const idThread* thread) const
{
return const_cast<idThread*>(thread)->GetThreadNum();
}
const char* idGameEdit::ThreadGetName(const idThread* thread) const
{
return const_cast<idThread*>(thread)->GetThreadName();
}
int idGameEdit::GetTotalScriptThreads() const
{
return idThread::GetThreads().Num();
}
const idThread* idGameEdit::GetThreadByIndex(int index) const
{
return idThread::GetThreads()[index];
}
bool idGameEdit::ThreadIsDoneProcessing(const idThread* thread) const
{
return const_cast<idThread*>(thread)->IsDoneProcessing();
}
bool idGameEdit::ThreadIsWaiting(const idThread* thread) const
{
return const_cast<idThread*>(thread)->IsWaiting();
}
bool idGameEdit::ThreadIsDying(const idThread* thread) const
{
return const_cast<idThread*>(thread)->IsDying();
}
void idGameEdit::MSG_WriteThreadInfo(idBitMsg* msg, const idThread* thread, const idInterpreter* interpreter)
{
msg->WriteString(const_cast<idThread*>(thread)->GetThreadName());
msg->WriteInt(const_cast<idThread*>(thread)->GetThreadNum());
msg->WriteBits((int)(thread == interpreter->GetThread()), 1);
msg->WriteBits((int)const_cast<idThread*>(thread)->IsDoneProcessing(), 1);
msg->WriteBits((int)const_cast<idThread*>(thread)->IsWaiting(), 1);
msg->WriteBits((int)const_cast<idThread*>(thread)->IsDying(), 1);
}

View file

@ -35,7 +35,7 @@ If you have questions concerning this license or the applicable additional terms
#include <unistd.h>
#endif
#include <SDL_endian.h>
#include <SDL2\SDL_endian.h>
#include "sys/platform.h"
#include "idlib/math/Vector.h"

View file

@ -149,17 +149,16 @@ END
// Dialog
//
IDD_DBG_ABOUT DIALOGEX 0, 0, 222, 71
IDD_DBG_ABOUT DIALOGEX 0, 0, 250, 80
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP |
WS_CAPTION | WS_SYSMENU
CAPTION "About Script Debugger"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Script Debugger",IDC_STATIC,35,7,81,8
LTEXT "Version 0.01",IDC_STATIC,35,17,41,8
LTEXT "Original version by Raven",IDC_STATIC,35,
28,134,8
DEFPUSHBUTTON "OK",IDOK,165,50,50,14
LTEXT "Version 1.0",IDC_STATIC,35,17,41,8
LTEXT "Dhewm3 version by Harrie van Ginneken", IDC_STATIC, 35, 38, 134, 8
DEFPUSHBUTTON "OK",IDOK,165,60,50,14
ICON 5098,IDC_STATIC,7,7,20,20
END

View file

@ -269,8 +269,6 @@ FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "GUI Editor",IDC_STATIC,35,7,62,8
LTEXT "Version 0.15",IDC_STATIC,35,17,41,8
LTEXT "Original version by Raven",IDC_STATIC,35,
28,134,8
DEFPUSHBUTTON "OK",IDOK,165,50,50,14
ICON IDI_GUIED,IDC_STATIC,7,7,20,20
END

View file

@ -629,7 +629,30 @@ Sys_DLL_GetProcAddress
=====================
*/
void *Sys_DLL_GetProcAddress( uintptr_t dllHandle, const char *procName ) {
return (void *)GetProcAddress( (HINSTANCE)dllHandle, procName );
void * adr = (void*)GetProcAddress((HINSTANCE)dllHandle, procName);
if (!adr)
{
DWORD e = GetLastError();
LPVOID msgBuf = nullptr;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
e,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&msgBuf,
0, NULL);
idStr errorStr = va("[%i (0x%X)]\t%s", e, e, msgBuf);
if (errorStr.Length())
common->Warning("GetProcAddress( %i %s) Failed ! %s", dllHandle, procName, errorStr.c_str());
::LocalFree(msgBuf);
}
return adr;
}
/*
@ -969,7 +992,7 @@ int main(int argc, char *argv[]) {
// Launch the script debugger
if ( strstr( GetCommandLine(), "+debugger" ) ) {
// DebuggerClientInit( lpCmdLine );
DebuggerClientInit(GetCommandLine());
return 0;
}

View file

@ -392,7 +392,8 @@ void rvOpenFileDialog::SetFilter ( const char* s )
if ( semi != -1 )
{
filter = filters.Left ( semi );
filters = filters.Right ( filters.Length ( ) - semi );
filters = filters.Right ( filters.Length ( ) - (semi + 1));
filters.Strip(' ');
}
else
{

View file

@ -37,8 +37,8 @@ If you have questions concerning this license or the applicable additional terms
rvDebuggerApp::rvDebuggerApp
================
*/
rvDebuggerApp::rvDebuggerApp ( ) :
mOptions ( "Software\\id Software\\DOOM3\\Tools\\Debugger" )
rvDebuggerApp::rvDebuggerApp ( ) //:
//mOptions ( "Software\\id Software\\DOOM3\\Tools\\Debugger" )
{
mInstance = NULL;
mDebuggerWindow = NULL;

View file

@ -29,7 +29,7 @@ If you have questions concerning this license or the applicable additional terms
#define DEBUGGERAPP_H_
#include "../../sys/win32/win_local.h"
#include "../../framework/sync/Msg.h"
//#include "../../framework/sync/Msg.h"
#ifndef REGISTRYOPTIONS_H_
#include "../common/RegistryOptions.h"
@ -49,13 +49,15 @@ If you have questions concerning this license or the applicable additional terms
// These were changed to static by ID so to make it easy we just throw them
// in this header
const int MAX_MSGLEN = 1400;
// we need a lot to be able to list all threads in mars_city1
const int MAX_MSGLEN = 8600;
class rvDebuggerApp
{
public:
rvDebuggerApp ( );
~rvDebuggerApp();
bool Initialize ( HINSTANCE hInstance );
int Run ( void );

View file

@ -28,6 +28,8 @@ If you have questions concerning this license or the applicable additional terms
#ifndef DEBUGGERBREAKPOINT_H_
#define DEBUGGERBREAKPOINT_H_
class idProgram;
class rvDebuggerBreakpoint
{
public:
@ -46,7 +48,6 @@ protected:
int mID;
int mLineNumber;
idStr mFilename;
private:
static int mNextID;

View file

@ -73,7 +73,7 @@ bool rvDebuggerClient::Initialize ( void )
}
// Server must be running on the local host on port 28980
Sys_StringToNetAdr ( "localhost", &mServerAdrt, true );
Sys_StringToNetAdr ( "localhost", &mServerAdr, true );
mServerAdr.port = 27980;
// Attempt to let the server know we are here. The server may not be running so this
@ -110,25 +110,29 @@ Process all incomding messages from the debugger server
bool rvDebuggerClient::ProcessMessages ( void )
{
netadr_t adrFrom;
msg_t msg;
idBitMsg msg;
byte buffer[MAX_MSGLEN];
MSG_Init( &msg, buffer, sizeof( buffer ) );
msg.SetSize(MAX_MSGLEN);
msg.BeginReading();
int msgSize;
// Check for pending udp packets on the debugger port
while ( mPort.GetPacket ( adrFrom, msg.data, msg.cursize, msg.maxsize ) )
while ( mPort.GetPacket ( adrFrom, buffer,msgSize, MAX_MSGLEN) )
{
unsigned short command;
short command;
msg.Init(buffer, sizeof(buffer));
msg.SetSize(msgSize);
msg.BeginReading();
// Only accept packets from the debugger server for security reasons
if ( !Sys_CompareNetAdrBase ( adrFrom, mServerAdr ) )
{
continue;
}
command = msg.ReadShort ( );
command = (unsigned short) MSG_ReadShort ( &msg );
// Is this what we are waiting for?
// Is this what we are waiting for?
if ( command == mWaitFor )
{
mWaitFor = DBMSG_UNKNOWN;
@ -168,17 +172,39 @@ bool rvDebuggerClient::ProcessMessages ( void )
case DBMSG_INSPECTVARIABLE:
HandleInspectVariable ( &msg );
break;
case DBMSG_REMOVEBREAKPOINT:
HandleRemoveBreakpoint( &msg );
break;
case DBMSG_INSPECTSCRIPTS:
HandleInspectScripts( &msg );
break;
}
// Give the window a chance to process the message
msg.readcount = 0;
msg.bit = 0;
msg.SetReadCount(0);
msg.SetReadBit(0);
gDebuggerApp.GetWindow().ProcessNetMessage ( &msg );
}
return true;
}
void rvDebuggerClient::HandleRemoveBreakpoint(idBitMsg* msg)
{
long lineNumber;
char filename[MAX_PATH];
// Read the breakpoint info
lineNumber = msg->ReadInt();
msg->ReadString(filename, MAX_PATH);
rvDebuggerBreakpoint* bp = FindBreakpoint(filename, lineNumber);
if(bp)
RemoveBreakpoint(bp->GetID());
}
/*
================
rvDebuggerClient::HandleBreak
@ -187,19 +213,22 @@ Handle the DBMSG_BREAK message send from the server. This message is handled
by caching the file and linenumber where the break occured.
================
*/
void rvDebuggerClient::HandleBreak ( msg_t* msg )
void rvDebuggerClient::HandleBreak ( idBitMsg* msg )
{
char filename[MAX_PATH];
mBreak = true;
// Line number
mBreakLineNumber = MSG_ReadInt ( msg );
mBreakLineNumber = msg->ReadInt ( );
// Filename
MSG_ReadString ( msg, filename, MAX_PATH );
msg->ReadString ( filename, MAX_PATH );
mBreakFilename = filename;
int ptr32b = msg->ReadInt();
mBreakProgram = (idProgram*)ptr32b;
// Clear the variables
mVariables.Clear ( );
@ -211,6 +240,26 @@ void rvDebuggerClient::HandleBreak ( msg_t* msg )
WaitFor ( DBMSG_INSPECTTHREADS, 2000 );
}
/*
================
rvDebuggerClient::InspectScripts
Instructs the client to inspect the loaded scripts
================
*/
void rvDebuggerClient::InspectScripts ( void )
{
idBitMsg msg;
byte buffer[MAX_MSGLEN];
msg.Init(buffer, sizeof(buffer));
msg.BeginWriting();
msg.WriteShort((short)DBMSG_INSPECTSCRIPTS);
SendPacket(msg.GetData(), msg.GetSize());
}
/*
================
rvDebuggerClient::InspectVariable
@ -222,15 +271,41 @@ will in turn respond back to the client with the variable value
*/
void rvDebuggerClient::InspectVariable ( const char* name, int callstackDepth )
{
msg_t msg;
byte buffer[MAX_MSGLEN];
idBitMsg msg;
byte buffer[MAX_MSGLEN];
MSG_Init( &msg, buffer, sizeof( buffer ) );
MSG_WriteShort ( &msg, (int)DBMSG_INSPECTVARIABLE );
MSG_WriteShort ( &msg, (short)(mCallstack.Num()-callstackDepth) );
MSG_WriteString ( &msg, name );
msg.Init( buffer, sizeof( buffer ) );
msg.BeginWriting();
msg.WriteShort ( (short)DBMSG_INSPECTVARIABLE );
msg.WriteShort ( (short)(mCallstack.Num()-callstackDepth) );
msg.WriteString ( name );
SendPacket ( msg.data, msg.cursize );
SendPacket ( msg.GetData(), msg.GetSize());
}
/*
================
rvDebuggerClient::HandleInspectScripts
Handle the message DBMSG_INSPECTSCRIPTS being sent from the server. This message
is handled by adding the script entries to a list for later lookup.
================
*/
void rvDebuggerClient::HandleInspectScripts( idBitMsg* msg )
{
int totalScripts;
mServerScripts.Clear();
// Read all of the callstack entries specfied in the message
for (totalScripts = msg->ReadInt(); totalScripts > 0; totalScripts--)
{
char temp[1024];
// Script Name
msg->ReadString(temp, 1024);
mServerScripts.Append(temp);
}
}
/*
@ -241,29 +316,29 @@ Handle the message DBMSG_INSPECTCALLSTACK being sent from the server. This mess
is handled by adding the callstack entries to a list for later lookup.
================
*/
void rvDebuggerClient::HandleInspectCallstack ( msg_t* msg )
void rvDebuggerClient::HandleInspectCallstack ( idBitMsg* msg )
{
int depth;
ClearCallstack ( );
// Read all of the callstack entries specfied in the message
for ( depth = (short)MSG_ReadShort ( msg ) ; depth > 0; depth -- )
for ( depth = (short)msg->ReadShort ( ) ; depth > 0; depth -- )
{
rvDebuggerCallstack* entry = new rvDebuggerCallstack;
char temp[1024];
// Function name
MSG_ReadString ( msg, temp, 1024 );
entry->mFunction = temp;
msg->ReadString ( temp, 1024 );
entry->mFunction = idStr(temp);
// Filename
MSG_ReadString ( msg, temp, 1024 );
entry->mFilename = temp;
msg->ReadString ( temp, 1024 );
entry->mFilename = idStr(temp);
// Line Number
entry->mLineNumber = MSG_ReadInt ( msg );
entry->mLineNumber = msg->ReadInt ( );
// Add to list
mCallstack.Append ( entry );
@ -278,31 +353,31 @@ Handle the message DBMSG_INSPECTTHREADS being sent from the server. This messag
is handled by adding the list of threads to a list for later lookup.
================
*/
void rvDebuggerClient::HandleInspectThreads ( msg_t* msg )
void rvDebuggerClient::HandleInspectThreads ( idBitMsg* msg )
{
int count;
ClearThreads ( );
// Loop over the number of threads in the message
for ( count = (short)MSG_ReadShort ( msg ) ; count > 0; count -- )
for ( count = (short)msg->ReadShort ( ) ; count > 0; count -- )
{
rvDebuggerThread* entry = new rvDebuggerThread;
char temp[1024];
// Thread name
MSG_ReadString ( msg, temp, 1024 );
msg->ReadString ( temp, 1024 );
entry->mName = temp;
// Thread ID
entry->mID = MSG_ReadInt ( msg );
entry->mID = msg->ReadInt ( );
// Thread state
entry->mCurrent = MSG_ReadBits ( msg, 1 ) ? true : false;
entry->mDoneProcessing = MSG_ReadBits ( msg, 1 ) ? true : false;
entry->mWaiting = MSG_ReadBits ( msg, 1 ) ? true : false;
entry->mDying = MSG_ReadBits ( msg, 1 ) ? true : false;
entry->mCurrent = msg->ReadBits ( 1 ) ? true : false;
entry->mDoneProcessing = msg->ReadBits ( 1 ) ? true : false;
entry->mWaiting = msg->ReadBits ( 1 ) ? true : false;
entry->mDying = msg->ReadBits ( 1 ) ? true : false;
// Add thread to list
mThreads.Append ( entry );
@ -317,15 +392,15 @@ Handle the message DBMSG_INSPECTVARIABLE being sent from the server. This messa
is handled by adding the inspected variable to a dictionary for later lookup
================
*/
void rvDebuggerClient::HandleInspectVariable ( msg_t* msg )
void rvDebuggerClient::HandleInspectVariable ( idBitMsg* msg )
{
char var[1024];
char value[1024];
int callDepth;
callDepth = (short)MSG_ReadShort ( msg );
MSG_ReadString ( msg, var, 1024 );
MSG_ReadString ( msg, value, 1024 );
callDepth = (short)msg->ReadShort ( );
msg->ReadString ( var, 1024 );
msg->ReadString ( value, 1024 );
mVariables.Set ( va("%d:%s", mCallstack.Num()-callDepth, var), value );
}
@ -463,13 +538,14 @@ Send a message with no data to the debugger server
*/
void rvDebuggerClient::SendMessage ( EDebuggerMessage dbmsg )
{
msg_t msg;
idBitMsg msg;
byte buffer[MAX_MSGLEN];
MSG_Init( &msg, buffer, sizeof( buffer ) );
MSG_WriteShort ( &msg, (int)dbmsg );
msg.Init ( buffer, sizeof( buffer ) );
msg.BeginWriting ( );
msg.WriteShort ( (short)dbmsg );
SendPacket ( msg.data, msg.cursize );
SendPacket ( msg.GetData(), msg.GetSize() );
}
/*
@ -504,7 +580,7 @@ Send an individual breakpoint over to the debugger server
*/
void rvDebuggerClient::SendAddBreakpoint ( rvDebuggerBreakpoint& bp, bool onceOnly )
{
msg_t msg;
idBitMsg msg;
byte buffer[MAX_MSGLEN];
if ( !mConnected )
@ -512,14 +588,15 @@ void rvDebuggerClient::SendAddBreakpoint ( rvDebuggerBreakpoint& bp, bool onceOn
return;
}
MSG_Init( &msg, buffer, sizeof( buffer ) );
MSG_WriteShort ( &msg, (int)DBMSG_ADDBREAKPOINT );
MSG_WriteBits ( &msg, onceOnly?1:0, 1 );
MSG_WriteInt ( &msg, (unsigned long) bp.GetLineNumber ( ) );
MSG_WriteInt ( &msg, bp.GetID ( ) );
MSG_WriteString ( &msg, bp.GetFilename() );
msg.Init( buffer, sizeof( buffer ) );
msg.BeginWriting();
msg.WriteShort ( (short)DBMSG_ADDBREAKPOINT );
msg.WriteBits ( onceOnly?1:0, 1 );
msg.WriteInt ( (unsigned long) bp.GetLineNumber ( ) );
msg.WriteInt ( bp.GetID ( ) );
msg.WriteString ( bp.GetFilename() );
SendPacket ( msg.data, msg.cursize );
SendPacket ( msg.GetData(), msg.GetSize() );
}
/*
@ -531,7 +608,7 @@ Sends a remove breakpoint message to the debugger server
*/
void rvDebuggerClient::SendRemoveBreakpoint ( rvDebuggerBreakpoint& bp )
{
msg_t msg;
idBitMsg msg;
byte buffer[MAX_MSGLEN];
if ( !mConnected )
@ -539,11 +616,12 @@ void rvDebuggerClient::SendRemoveBreakpoint ( rvDebuggerBreakpoint& bp )
return;
}
MSG_Init( &msg, buffer, sizeof( buffer ) );
MSG_WriteShort ( &msg, (int)DBMSG_REMOVEBREAKPOINT );
MSG_WriteInt ( &msg, bp.GetID() );
msg.Init ( buffer, sizeof( buffer ) );
msg.BeginWriting( );
msg.WriteShort ( (short)DBMSG_REMOVEBREAKPOINT );
msg.WriteInt ( bp.GetID() );
SendPacket ( msg.data, msg.cursize );
SendPacket ( msg.GetData(), msg.GetSize() );
}
/*

View file

@ -28,6 +28,9 @@ If you have questions concerning this license or the applicable additional terms
#ifndef DEBUGGERCLIENT_H_
#define DEBUGGERCLIENT_H_
#include "DebuggerBreakpoint.h"
#include "idlib/containers/StrList.h"
class rvDebuggerCallstack
{
public:
@ -49,9 +52,6 @@ public:
bool mDoneProcessing;
};
#ifndef DEBUGGERBREAKPOINT_H_
#include "DebuggerBreakpoint.h"
#endif
typedef idList<rvDebuggerCallstack*> rvDebuggerCallstackList;
typedef idList<rvDebuggerThread*> rvDebuggerThreadList;
@ -75,12 +75,14 @@ public:
int GetActiveBreakpointID ( void );
const char* GetBreakFilename ( void );
int GetBreakLineNumber ( void );
idProgram* GetBreakProgram ( void );
rvDebuggerCallstackList& GetCallstack ( void );
rvDebuggerThreadList& GetThreads ( void );
const char* GetVariableValue ( const char* name, int stackDepth );
idStrList& GetServerScripts ( void );
void InspectVariable ( const char* name, int callstackDepth );
void InspectScripts ( void );
void Break ( void );
void Resume ( void );
void StepInto ( void );
@ -110,6 +112,7 @@ protected:
int mBreakID;
int mBreakLineNumber;
idStr mBreakFilename;
idProgram* mBreakProgram;
idDict mVariables;
@ -119,6 +122,8 @@ protected:
EDebuggerMessage mWaitFor;
idStrList mServerScripts;
private:
void ClearCallstack ( void );
@ -127,10 +132,13 @@ private:
void UpdateWatches ( void );
// Network message handlers
void HandleBreak ( msg_t* msg );
void HandleInspectCallstack ( msg_t* msg );
void HandleInspectThreads ( msg_t* msg );
void HandleInspectVariable ( msg_t* msg );
void HandleBreak ( idBitMsg* msg );
void HandleInspectScripts ( idBitMsg* msg );
void HandleInspectCallstack ( idBitMsg* msg );
void HandleInspectThreads ( idBitMsg* msg );
void HandleInspectVariable ( idBitMsg* msg );
void HandleGameDLLHandle ( idBitMsg* msg );
void HandleRemoveBreakpoint ( idBitMsg* msg );
};
/*
@ -183,6 +191,17 @@ ID_INLINE int rvDebuggerClient::GetBreakLineNumber ( void )
return mBreakLineNumber;
}
/*
================
rvDebuggerClient::GetBreakProgram
================
*/
ID_INLINE idProgram* rvDebuggerClient::GetBreakProgram(void)
{
return mBreakProgram;
}
/*
================
rvDebuggerClient::GetCallstack
@ -286,4 +305,14 @@ ID_INLINE void rvDebuggerClient::SendPacket ( void* data, int size )
mPort.SendPacket ( mServerAdr, data, size );
}
/*
================
rvDebuggerClient::GetServerScripts
================
*/
ID_INLINE idStrList& rvDebuggerClient::GetServerScripts( void )
{
return mServerScripts;
}
#endif // DEBUGGERCLIENT_H_

View file

@ -46,6 +46,7 @@ enum EDebuggerMessage
DBMSG_INSPECTTHREADS,
DBMSG_STEPOVER,
DBMSG_STEPINTO,
DBMSG_INSPECTSCRIPTS
};
#endif // DEBUGGER_MESSAGES_H_

View file

@ -31,7 +31,6 @@ If you have questions concerning this license or the applicable additional terms
#include "DebuggerApp.h"
#include "DebuggerScript.h"
#include "../../game/script/Script_Program.h"
#include "../../ui/Window.h"
#include "../../ui/UserInterfaceLocal.h"
@ -57,6 +56,7 @@ rvDebuggerScript::~rvDebuggerScript ( void )
Unload ( );
}
/*
================
rvDebuggerScript::Unload
@ -72,10 +72,6 @@ void rvDebuggerScript::Unload ( void )
{
delete mInterface;
}
else
{
delete mProgram;
}
mContents = NULL;
mProgram = NULL;
@ -91,7 +87,7 @@ appropriate for the file being loaded. If the script cant be compiled
the loading of the script fails
================
*/
bool rvDebuggerScript::Load ( const char* filename )
bool rvDebuggerScript::Load ( const char* filename)
{
void* buffer;
int size;
@ -116,60 +112,7 @@ bool rvDebuggerScript::Load ( const char* filename )
// Cleanup
fileSystem->FreeFile ( buffer );
// Now compile the script so we can tell what a valid line is, etc.. If its
// a gui file then we need to parse it using the userinterface system rather
// than the normal script compiler.
try
{
// Parse the script using the script compiler
mProgram = new idProgram;
mProgram->BeginCompilation ( );
mProgram->CompileFile ( SCRIPT_DEFAULT );
//BSM Nerve: Loads a game specific main script file
idStr gamedir = cvarSystem->GetCVarString( "fs_game" );
if(gamedir.Length() > 0) {
idStr scriptFile = va("script/%s_main.script", gamedir.c_str());
if(fileSystem->ReadFile(scriptFile.c_str(), NULL) > 0) {
mProgram.CompileFile(scriptFile.c_str());
}
}
// Make sure the file isnt already compiled before trying to compile it again
for ( int f = mProgram->NumFilenames() - 1; f >= 0; f -- )
{
idStr qpath;
qpath = fileSystem->OSPathToRelativePath ( mProgram->GetFilename ( f ) );
qpath.BackSlashesToSlashes ( );
if ( !qpath.Cmp ( filename ) )
{
break;
}
}
if ( f < 0 )
{
mProgram->CompileText ( filename, mContents, false );
}
mProgram->FinishCompilation ( );
}
catch ( idException& )
{
// Failed to parse the script so fail to load the file
delete mProgram;
mProgram = NULL;
delete[] mContents;
mContents = NULL;
// TODO: Should cache the error for the dialog box
return false;
}
return true;
}
@ -194,21 +137,8 @@ Determines whether or not the given line number within the script is a valid lin
*/
bool rvDebuggerScript::IsLineCode ( int linenumber )
{
int i;
assert ( mProgram );
// Run through all the statements in the program and see if any match the
// linenumber that we are checking.
for ( i = 0; i < mProgram->NumStatements ( ); i ++ )
{
if ( mProgram->GetStatement ( i ).linenumber == linenumber )
{
return true;
}
}
return false;
//we let server decide.
return true;
}
/*

View file

@ -43,21 +43,22 @@ public:
const char* GetFilename ( void );
const char* GetContents ( void );
idProgram* GetProgram ( void );
#if 0// Test code
idProgram& GetProgram ( void );
#endif
bool IsLineCode ( int linenumber );
bool IsFileModified ( bool updateTime = false );
protected:
void Unload ( void );
idProgram* mProgram;
idUserInterfaceLocal* mInterface;
char* mContents;
idStr mFilename;
ID_TIME_T mModifiedTime;
ID_TIME_T mModifiedTime;
};
ID_INLINE const char* rvDebuggerScript::GetFilename ( void )
@ -70,9 +71,10 @@ ID_INLINE const char* rvDebuggerScript::GetContents ( void )
return mContents?mContents:"";
}
ID_INLINE idProgram& rvDebuggerScript::GetProgram ( void )
ID_INLINE idProgram* rvDebuggerScript::GetProgram ( void )
{
return *mProgram;
return mProgram;
}
#endif // DEBUGGERSCRIPT_H_

View file

@ -28,14 +28,6 @@ If you have questions concerning this license or the applicable additional terms
#include "tools/edit_gui_common.h"
#include "../../game/gamesys/Event.h"
#include "../../game/gamesys/Class.h"
#include "../../game/script/Script_Program.h"
#include "../../game/script/Script_Interpreter.h"
#include "../../game/script/Script_Thread.h"
#include "../../game/script/Script_Compiler.h"
#include "../../framework/sync/Msg.h"
#include "DebuggerApp.h"
#include "DebuggerServer.h"
@ -144,15 +136,17 @@ Process all incoming network messages from the debugger client
bool rvDebuggerServer::ProcessMessages ( void )
{
netadr_t adrFrom;
msg_t msg;
idBitMsg msg;
byte buffer[MAX_MSGLEN];
MSG_Init( &msg, buffer, sizeof( buffer ) );
// Check for pending udp packets on the debugger port
while ( mPort.GetPacket ( adrFrom, msg.data, msg.cursize, msg.maxsize ) )
int msgSize;
while ( mPort.GetPacket ( adrFrom, buffer, msgSize, MAX_MSGLEN) )
{
unsigned short command;
short command;
msg.Init(buffer, sizeof(buffer));
msg.SetSize(msgSize);
msg.BeginReading();
// Only accept packets from the debugger server for security reasons
if ( !Sys_CompareNetAdrBase ( adrFrom, mClientAdr ) )
@ -160,23 +154,26 @@ bool rvDebuggerServer::ProcessMessages ( void )
continue;
}
command = (unsigned short) MSG_ReadShort ( &msg );
command = msg.ReadShort( );
switch ( command )
{
case DBMSG_CONNECT:
mConnected = true;
SendMessage ( DBMSG_CONNECTED );
break;
case DBMSG_CONNECTED:
mConnected = true;
com_editors |= EDITOR_DEBUGGER;
break;
case DBMSG_DISCONNECT:
ClearBreakpoints ( );
Resume ( );
mConnected = false;
com_editors &= ~EDITOR_DEBUGGER;
break;
case DBMSG_ADDBREAKPOINT:
@ -188,7 +185,7 @@ bool rvDebuggerServer::ProcessMessages ( void )
break;
case DBMSG_RESUME:
Resume ( );
HandleResume ( &msg );
break;
case DBMSG_BREAK:
@ -197,11 +194,11 @@ bool rvDebuggerServer::ProcessMessages ( void )
case DBMSG_STEPOVER:
mBreakStepOver = true;
mBreakStepOverDepth = mBreakInterpreter->GetCallstackDepth ( );
mBreakStepOverFunc1 = mBreakInterpreter->GetCallstack()[mBreakInterpreter->GetCallstackDepth()].f;
if ( mBreakInterpreter->GetCallstackDepth() > 0 )
mBreakStepOverDepth = gameEdit->GetInterpreterCallStackDepth(mBreakInterpreter);
mBreakStepOverFunc1 = gameEdit->GetInterpreterCallStackFunction(mBreakInterpreter);
if (mBreakStepOverDepth)
{
mBreakStepOverFunc2 = mBreakInterpreter->GetCallstack()[mBreakInterpreter->GetCallstackDepth()-1].f;
mBreakStepOverFunc2 = gameEdit->GetInterpreterCallStackFunction(mBreakInterpreter,mBreakStepOverDepth - 1);
}
else
{
@ -226,6 +223,10 @@ bool rvDebuggerServer::ProcessMessages ( void )
case DBMSG_INSPECTTHREADS:
HandleInspectThreads ( &msg );
break;
case DBMSG_INSPECTSCRIPTS:
HandleInspectScripts( &msg );
break;
}
}
@ -241,13 +242,14 @@ Send a message with no data to the debugger server.
*/
void rvDebuggerServer::SendMessage ( EDebuggerMessage dbmsg )
{
msg_t msg;
idBitMsg msg;
byte buffer[MAX_MSGLEN];
MSG_Init( &msg, buffer, sizeof( buffer ) );
MSG_WriteShort ( &msg, (int)dbmsg );
msg.Init( buffer, sizeof( buffer ) );
msg.BeginWriting();
msg.WriteShort ( (short)dbmsg );
SendPacket ( msg.data, msg.cursize );
SendPacket ( msg.GetData(), msg.GetSize() );
}
/*
@ -255,11 +257,12 @@ void rvDebuggerServer::SendMessage ( EDebuggerMessage dbmsg )
rvDebuggerServer::HandleAddBreakpoint
Handle the DBMSG_ADDBREAKPOINT message being sent by the debugger client. This
message is handled by adding a new breakpoint to the breakpoint list with the
message is handled by first checking if it is valid
and is added as a new breakpoint to the breakpoint list with the
data supplied in the message.
================
*/
void rvDebuggerServer::HandleAddBreakpoint ( msg_t* msg )
void rvDebuggerServer::HandleAddBreakpoint ( idBitMsg* msg )
{
bool onceOnly = false;
long lineNumber;
@ -267,14 +270,28 @@ void rvDebuggerServer::HandleAddBreakpoint ( msg_t* msg )
char filename[MAX_PATH];
// Read the breakpoint info
onceOnly = MSG_ReadBits ( msg, 1 ) ? true : false;
lineNumber = MSG_ReadInt ( msg );
id = MSG_ReadInt ( msg );
onceOnly = msg->ReadBits ( 1 ) ? true : false;
lineNumber = msg->ReadInt ( );
id = msg->ReadInt ( );
msg->ReadString ( filename, MAX_PATH );
//check for statement on requested breakpoint location
if (!gameEdit->IsLineCode(filename, lineNumber))
{
idBitMsg msgOut;
byte buffer[MAX_MSGLEN];
msgOut.Init(buffer, sizeof(buffer));
msgOut.BeginWriting();
msgOut.WriteShort((short)DBMSG_REMOVEBREAKPOINT);
msgOut.WriteInt(lineNumber);
msgOut.WriteString(filename);
SendPacket(msgOut.GetData(), msgOut.GetSize());
return;
}
MSG_ReadString ( msg, filename, MAX_PATH );
// Since breakpoints are used by both threads we need to
// protect them with a crit section
EnterCriticalSection ( &mCriticalSection );
mBreakpoints.Append ( new rvDebuggerBreakpoint ( filename, lineNumber, id ) );
LeaveCriticalSection ( &mCriticalSection );
@ -289,13 +306,13 @@ message is handled by removing the breakpoint that matches the given id from the
list.
================
*/
void rvDebuggerServer::HandleRemoveBreakpoint ( msg_t* msg )
void rvDebuggerServer::HandleRemoveBreakpoint ( idBitMsg* msg )
{
int i;
int id;
// ID that we are to remove
id = MSG_ReadInt ( msg );
id = msg->ReadInt ( );
// Since breakpoints are used by both threads we need to
// protect them with a crit section
@ -317,47 +334,16 @@ void rvDebuggerServer::HandleRemoveBreakpoint ( msg_t* msg )
/*
================
rvDebuggerServer::MSG_WriteCallstackFunc
rvDebuggerServer::HandleResume
Writes a single callstack entry to the given message
Resume the game thread.
================
*/
void rvDebuggerServer::MSG_WriteCallstackFunc ( msg_t* msg, const prstack_t* stack )
void rvDebuggerServer::HandleResume(idBitMsg* msg)
{
const statement_t* st;
const function_t* func;
func = stack->f;
// If the function is unknown then just fill in with default data.
if ( !func )
{
MSG_WriteString ( msg, "<UNKNOWN>" );
MSG_WriteString ( msg, "<UNKNOWN>" );
MSG_WriteInt ( msg, 0 );
return;
}
else
{
MSG_WriteString ( msg, va("%s( ??? )", func->Name() ) );
}
// Use the calling statement as the filename and linenumber where
// the call was made from
st = &mBreakProgram->GetStatement ( stack->s );
if ( st )
{
idStr qpath;
OSPathToRelativePath(mBreakProgram->GetFilename( st->file ), qpath);
qpath.BackSlashesToSlashes ( );
MSG_WriteString ( msg, qpath );
MSG_WriteInt ( msg, st->linenumber );
}
else
{
MSG_WriteString ( msg, "<UNKNOWN>" );
MSG_WriteInt ( msg, 0 );
}
//Empty msg
Resume();
}
/*
@ -368,31 +354,18 @@ Handle an incoming inspect callstack message by sending a message
back to the client with the callstack data.
================
*/
void rvDebuggerServer::HandleInspectCallstack ( msg_t* in_msg )
void rvDebuggerServer::HandleInspectCallstack ( idBitMsg* msg )
{
msg_t msg;
idBitMsg msgOut;
byte buffer[MAX_MSGLEN];
int i;
prstack_t temp;
MSG_Init( &msg, buffer, sizeof( buffer ) );
MSG_WriteShort ( &msg, (int)DBMSG_INSPECTCALLSTACK );
msgOut.Init(buffer, sizeof( buffer ) );
msgOut.BeginWriting();
msgOut.WriteShort ( (short)DBMSG_INSPECTCALLSTACK );
MSG_WriteShort ( &msg, (int)mBreakInterpreter->GetCallstackDepth ( ) );
gameEdit->MSG_WriteInterpreterInfo(&msgOut, mBreakInterpreter, mBreakProgram, mBreakInstructionPointer);
// write out the current function
temp.f = mBreakInterpreter->GetCurrentFunction ( );
temp.s = 0;
temp.stackbase = 0;
MSG_WriteCallstackFunc ( &msg, &temp );
// Run through all of the callstack and write each to the msg
for ( i = mBreakInterpreter->GetCallstackDepth ( ) - 1; i > 0; i -- )
{
MSG_WriteCallstackFunc ( &msg, mBreakInterpreter->GetCallstack ( ) + i );
}
SendPacket ( msg.data, msg.cursize );
SendPacket (msgOut.GetData(), msgOut.GetSize() );
}
/*
@ -402,35 +375,51 @@ rvDebuggerServer::HandleInspectThreads
Send the list of the current threads in the interpreter back to the debugger client
================
*/
void rvDebuggerServer::HandleInspectThreads ( msg_t* in_msg )
void rvDebuggerServer::HandleInspectThreads ( idBitMsg* msg )
{
msg_t msg;
byte buffer[MAX_MSGLEN];
int i;
idBitMsg msgOut;
byte buffer[MAX_MSGLEN];
int i;
// Initialize the message
MSG_Init( &msg, buffer, sizeof( buffer ) );
MSG_WriteShort ( &msg, (int)DBMSG_INSPECTTHREADS );
msgOut.Init( buffer, sizeof( buffer ) );
msgOut.SetAllowOverflow(true);
msgOut.BeginWriting();
msgOut.WriteShort ( (short)DBMSG_INSPECTTHREADS );
// Write the number of threads to the message
MSG_WriteShort ( &msg, (int)idThread::GetThreads().Num() );
msgOut.WriteShort ((short)gameEdit->GetTotalScriptThreads() );
// Loop through all of the threads and write their name and number to the message
for ( i = 0; i < idThread::GetThreads().Num(); i ++ )
for ( i = 0; i < gameEdit->GetTotalScriptThreads(); i ++ )
{
idThread* thread = idThread::GetThreads()[i];
MSG_WriteString ( &msg, thread->GetThreadName ( ) );
MSG_WriteInt ( &msg, thread->GetThreadNum ( ) );
MSG_WriteBits ( &msg, (int)(thread == mBreakInterpreter->GetThread ( )), 1 );
MSG_WriteBits ( &msg, (int)thread->IsDoneProcessing(), 1 );
MSG_WriteBits ( &msg, (int)thread->IsWaiting(), 1 );
MSG_WriteBits ( &msg, (int)thread->IsDying(), 1 );
gameEdit->MSG_WriteThreadInfo(&msgOut,gameEdit->GetThreadByIndex(i), mBreakInterpreter);
}
// Send off the inspect threads packet to the debugger client
SendPacket ( msg.data, msg.cursize );
SendPacket (msgOut.GetData(), msgOut.GetSize() );
}
/*
================
rvDebuggerServer::HandleInspectScripts
Send the list of the current loaded scripts in the interpreter back to the debugger client
================
*/
void rvDebuggerServer::HandleInspectScripts( idBitMsg* msg )
{
idBitMsg msgOut;
byte buffer[MAX_MSGLEN];
// Initialize the message
msgOut.Init(buffer, sizeof(buffer));
msgOut.BeginWriting();
msgOut.WriteShort((short)DBMSG_INSPECTSCRIPTS);
gameEdit->MSG_WriteScriptList( &msgOut );
SendPacket(msgOut.GetData(), msgOut.GetSize());
}
/*
@ -440,7 +429,7 @@ rvDebuggerServer::HandleInspectVariable
Respondes to a request from the debugger client to inspect the value of a given variable
================
*/
void rvDebuggerServer::HandleInspectVariable ( msg_t* in_msg )
void rvDebuggerServer::HandleInspectVariable ( idBitMsg* msg )
{
char varname[256];
int scopeDepth;
@ -450,28 +439,29 @@ void rvDebuggerServer::HandleInspectVariable ( msg_t* in_msg )
return;
}
scopeDepth = (short)MSG_ReadShort ( in_msg );
MSG_ReadString ( in_msg, varname, 256 );
scopeDepth = (short)msg->ReadShort ( );
msg->ReadString ( varname, 256 );
idStr varvalue;
msg_t msg;
idBitMsg msgOut;
byte buffer[MAX_MSGLEN];
// Initialize the message
MSG_Init( &msg, buffer, sizeof( buffer ) );
MSG_WriteShort ( &msg, (int)DBMSG_INSPECTVARIABLE );
msgOut.Init( buffer, sizeof( buffer ) );
msgOut.BeginWriting();
msgOut.WriteShort ( (short)DBMSG_INSPECTVARIABLE );
if ( !mBreakInterpreter->GetRegisterValue ( varname, varvalue, scopeDepth ) )
if (!gameEdit->GetRegisterValue(mBreakInterpreter, varname, varvalue, scopeDepth ) )
{
varvalue = "???";
}
MSG_WriteShort ( &msg, (short)scopeDepth );
MSG_WriteString ( &msg, varname );
MSG_WriteString ( &msg, varvalue );
msgOut.WriteShort ( (short)scopeDepth );
msgOut.WriteString ( varname );
msgOut.WriteString ( varvalue );
SendPacket ( msg.data, msg.cursize );
SendPacket (msgOut.GetData(), msgOut.GetSize() );
}
/*
@ -484,7 +474,6 @@ Check to see if any breakpoints have been hit. This includes "break next",
*/
void rvDebuggerServer::CheckBreakpoints ( idInterpreter* interpreter, idProgram* program, int instructionPointer )
{
const statement_t* st;
const char* filename;
int i;
@ -492,23 +481,24 @@ void rvDebuggerServer::CheckBreakpoints ( idInterpreter* interpreter, idProgram*
return;
}
// Grab the current statement and the filename that it came from
st = &program->GetStatement ( instructionPointer );
filename = program->GetFilename ( st->file );
filename = gameEdit->GetFilenameForStatement(program, instructionPointer);
int linenumber = gameEdit->GetLineNumberForStatement(program, instructionPointer);
// Operate on lines, not statements
if ( mLastStatementLine == st->linenumber && mLastStatementFile == st->file )
if ( mLastStatementLine == linenumber && mLastStatementFile == filename)
{
return;
}
// Save the last visited line and file so we can prevent
// double breaks on lines with more than one statement
mLastStatementFile = idStr( st->file );
mLastStatementLine = st->linenumber;
mLastStatementFile = idStr(filename);
mLastStatementLine = linenumber;
// Reset stepping when the last function on the callstack is returned from
if ( st->op == OP_RETURN && interpreter->GetCallstackDepth ( ) <= 1 )
if (gameEdit->ReturnedFromFunction(program, interpreter,instructionPointer))
{
mBreakStepOver = false;
mBreakStepInto = false;
@ -517,6 +507,7 @@ void rvDebuggerServer::CheckBreakpoints ( idInterpreter* interpreter, idProgram*
// See if we are supposed to break on the next script line
if ( mBreakNext )
{
HandleInspectScripts(nullptr);
Break ( interpreter, program, instructionPointer );
return;
}
@ -524,9 +515,8 @@ void rvDebuggerServer::CheckBreakpoints ( idInterpreter* interpreter, idProgram*
// Only break on the same callstack depth and thread as the break over
if ( mBreakStepOver )
{
if ( ( interpreter->GetCurrentFunction ( ) == mBreakStepOverFunc1 ||
interpreter->GetCurrentFunction ( ) == mBreakStepOverFunc2 )&&
( interpreter->GetCallstackDepth ( ) <= mBreakStepOverDepth ) )
//virtual bool CheckForBreakpointHit(interpreter,function1,function2,depth)
if (gameEdit->CheckForBreakPointHit(interpreter, mBreakStepOverFunc1, mBreakStepOverFunc2, mBreakStepOverDepth))
{
Break ( interpreter, program, instructionPointer );
return;
@ -536,6 +526,7 @@ void rvDebuggerServer::CheckBreakpoints ( idInterpreter* interpreter, idProgram*
// See if we are supposed to break on the next line
if ( mBreakStepInto )
{
HandleInspectScripts(nullptr);
// Break
Break ( interpreter, program, instructionPointer );
return;
@ -553,13 +544,13 @@ void rvDebuggerServer::CheckBreakpoints ( idInterpreter* interpreter, idProgram*
rvDebuggerBreakpoint* bp = mBreakpoints[i];
// Skip if not match of the line number
if ( st->linenumber != bp->GetLineNumber ( ) )
if ( linenumber != bp->GetLineNumber ( ) )
{
continue;
}
// Skip if no match of the filename
if ( idStr::Icmp ( bp->GetFilename(), qpath ) )
if ( idStr::Icmp ( bp->GetFilename(), qpath.c_str() ) )
{
continue;
}
@ -567,6 +558,7 @@ void rvDebuggerServer::CheckBreakpoints ( idInterpreter* interpreter, idProgram*
// Pop out of the critical section so we dont get stuck
LeaveCriticalSection ( &mCriticalSection );
HandleInspectScripts(nullptr);
// We hit a breakpoint, so break
Break ( interpreter, program, instructionPointer );
@ -589,9 +581,8 @@ the game has been halted
*/
void rvDebuggerServer::Break ( idInterpreter* interpreter, idProgram* program, int instructionPointer )
{
msg_t msg;
idBitMsg msg;
byte buffer[MAX_MSGLEN];
const statement_t* st;
const char* filename;
// Clear all the break types
@ -600,12 +591,10 @@ void rvDebuggerServer::Break ( idInterpreter* interpreter, idProgram* program, i
mBreakNext = false;
// Grab the current statement and the filename that it came from
st = &program->GetStatement ( instructionPointer );
filename = program->GetFilename ( st->file );
idStr qpath;
OSPathToRelativePath(filename, qpath);
qpath.BackSlashesToSlashes ( );
filename = gameEdit->GetFilenameForStatement(program,instructionPointer);
int linenumber = gameEdit->GetLineNumberForStatement(program, instructionPointer);
idStr fileStr = filename;
fileStr.BackSlashesToSlashes();
// Give the mouse cursor back to the world
Sys_GrabMouseCursor( false );
@ -617,11 +606,13 @@ void rvDebuggerServer::Break ( idInterpreter* interpreter, idProgram* program, i
mBreakInstructionPointer = instructionPointer;
// Inform the debugger of the breakpoint hit
MSG_Init( &msg, buffer, sizeof( buffer ) );
MSG_WriteShort ( &msg, (int)DBMSG_BREAK );
MSG_WriteInt ( &msg, st->linenumber );
MSG_WriteString ( &msg, qpath );
SendPacket ( msg.data, msg.cursize );
msg.Init( buffer, sizeof( buffer ) );
msg.BeginWriting();
msg.WriteShort ( (short)DBMSG_BREAK );
msg.WriteInt ( linenumber );
msg.WriteString ( fileStr.c_str() );
msg.WriteInt( (int)mBreakProgram );
SendPacket ( msg.GetData(), msg.GetSize() );
// Suspend the game thread. Since this will be called from within the main game thread
// execution wont return until after the thread is resumed
@ -642,6 +633,7 @@ void rvDebuggerServer::Break ( idInterpreter* interpreter, idProgram* program, i
SetFocus ( win32.hWnd );
// Give the mouse cursor back to the game
// HVG_Note : there be dragons here. somewhere.
Sys_GrabMouseCursor( true );
// Clear all commands that were generated before we went into suspended mode. This is
@ -703,12 +695,13 @@ void rvDebuggerServer::Print ( const char* text )
return;
}
msg_t msg;
idBitMsg msg;
byte buffer[MAX_MSGLEN];
MSG_Init( &msg, buffer, sizeof( buffer ) );
MSG_WriteShort ( &msg, (int)DBMSG_PRINT );
MSG_WriteString ( &msg, text );
msg.Init( buffer, sizeof( buffer ) );
msg.BeginWriting();
msg.WriteShort ( (short)DBMSG_PRINT );
msg.WriteString ( text );
SendPacket ( msg.data, msg.cursize );
SendPacket ( msg.GetData(), msg.GetSize() );
}

View file

@ -28,20 +28,15 @@ If you have questions concerning this license or the applicable additional terms
#ifndef DEBUGGERSERVER_H_
#define DEBUGGERSERVER_H_
#ifndef DEBUGGERMESSAGES_H_
#include "DebuggerMessages.h"
#endif
#ifndef DEBUGGERBREAKPOINT_H_
#include "DebuggerBreakpoint.h"
#endif
#include "framework/Game.h"
#ifndef __GAME_LOCAL_H__
#include "../../game/Game.h"
#endif
class idInterpreter;
class idProgram;
class function_t;
typedef struct prstack_s prstack_t;
class rvDebuggerServer
{
@ -50,22 +45,40 @@ public:
rvDebuggerServer ( );
~rvDebuggerServer ( );
bool Initialize ( void );
void Shutdown ( void );
bool Initialize ( void );
void Shutdown ( void );
bool ProcessMessages ( void );
bool ProcessMessages ( void );
bool IsConnected ( void );
bool IsConnected ( void );
void CheckBreakpoints ( idInterpreter* interpreter, idProgram* program, int instructionPointer );
void CheckBreakpoints ( idInterpreter* interpreter, idProgram* program, int instructionPointer );
void Print ( const char* text );
void Print ( const char* text );
void OSPathToRelativePath( const char *osPath, idStr &qpath );
void OSPathToRelativePath ( const char *osPath, idStr &qpath );
protected:
bool GameSuspended ( void );
private:
void ClearBreakpoints ( void );
void Break ( idInterpreter* interpreter, idProgram* program, int instructionPointer );
void Resume ( void );
void SendMessage ( EDebuggerMessage dbmsg );
void SendPacket ( void* data, int datasize );
// Message handlers
void HandleAddBreakpoint ( idBitMsg * msg );
void HandleRemoveBreakpoint ( idBitMsg * msg );
void HandleResume ( idBitMsg * msg );
void HandleInspectVariable ( idBitMsg * msg );
void HandleInspectCallstack ( idBitMsg * msg );
void HandleInspectThreads ( idBitMsg * msg );
void HandleInspectScripts ( idBitMsg * msg );
////
// protected member variables
bool mConnected;
netadr_t mClientAdr;
idPort mPort;
@ -87,27 +100,9 @@ protected:
idStr mLastStatementFile;
int mLastStatementLine;
uintptr_t mGameDLLHandle;
idStrList mScriptFileList;
private:
void ClearBreakpoints ( void );
void Break ( idInterpreter* interpreter, idProgram* program, int instructionPointer );
void Resume ( void );
void SendMessage ( EDebuggerMessage dbmsg );
void SendPacket ( void* data, int datasize );
// Message handlers
void HandleAddBreakpoint ( msg_t* msg );
void HandleRemoveBreakpoint ( msg_t* msg );
void HandleResume ( msg_t* msg );
void HandleInspectVariable ( msg_t* msg );
void HandleInspectCallstack ( msg_t* msg );
void HandleInspectThreads ( msg_t* msg );
// MSG helper routines
void MSG_WriteCallstackFunc ( msg_t* msg, const prstack_t* stack );
};
/*
@ -130,4 +125,14 @@ ID_INLINE void rvDebuggerServer::SendPacket ( void* data, int size )
mPort.SendPacket ( mClientAdr, data, size );
}
/*
================
rvDebuggerServer::GameSuspended
================
*/
ID_INLINE bool rvDebuggerServer::GameSuspended( void )
{
return mBreak;
}
#endif // DEBUGGERSERVER_H_

View file

@ -35,7 +35,7 @@ If you have questions concerning this license or the applicable additional terms
#include "DebuggerQuickWatchDlg.h"
#include "DebuggerFindDlg.h"
#define DEBUGGERWINDOWCLASS "QUAKE4_DEBUGGER_WINDOW"
#define DEBUGGERWINDOWCLASS "DHEWM3_DEBUGGER_WINDOW"
#define ID_DBG_WINDOWMIN 18900
#define ID_DBG_WINDOWMAX 19900
@ -49,6 +49,7 @@ If you have questions concerning this license or the applicable additional terms
#define IDC_DBG_WATCH 31007
#define IDC_DBG_THREADS 31008
#define IDC_DBG_TOOLBAR 31009
#define IDC_DBG_SCRIPTLIST 31010
#define ID_DBG_FILE_MRU1 10000
@ -167,7 +168,7 @@ bool rvDebuggerWindow::Create ( HINSTANCE instance )
UpdateTitle ( );
Printf ( "Quake 4 Script Debugger v0.1\n\n" );
Printf ( "Dhewm3 Script Debugger v1.0\n\n" );
ShowWindow ( mWnd, SW_SHOW );
UpdateWindow ( mWnd );
@ -347,6 +348,20 @@ LRESULT CALLBACK rvDebuggerWindow::ScriptWndProc ( HWND wnd, UINT msg, WPARAM wp
break;
}
case WM_SIZE:
{
float scaling_factor = Win_GetWindowScalingFactor(wnd);
int s18 = int(18 * scaling_factor);
int s10 = int(10 * scaling_factor);
RECT rect;
window->mMarginSize = window->mZoomScaleDem ? ((long)(s18 * (float)window->mZoomScaleNum / (float)window->mZoomScaleDem)) : s18;
GetWindowRect(window->mWndToolbar, &rect);
MoveWindow(window->mWndMargin, 0, 0, window->mMarginSize, window->mSplitterRect.top - (rect.bottom - rect.top), TRUE);
SendMessage(window->mWndScript, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(s18, s10));
}
}
return CallWindowProc ( wndproc, wnd, msg, wparam, lparam );
@ -384,14 +399,20 @@ LRESULT CALLBACK rvDebuggerWindow::MarginWndProc ( HWND wnd, UINT msg, WPARAM wp
case WM_PAINT:
{
HDC dc;
float scaling_factor = Win_GetWindowScalingFactor(wnd);
int s2 = int(2 * scaling_factor);
int s4 = int(4 * scaling_factor);
int s22 = int(22 * scaling_factor);
int width,height;
int size = window->mMarginSize - 2;
window->ResizeImageList(width,height);
PAINTSTRUCT ps;
RECT rect;
GetClientRect ( wnd, &rect );
dc = BeginPaint ( wnd, &ps );
FillRect ( dc, &rect, GetSysColorBrush ( COLOR_3DFACE ) );
FillRect ( dc, &rect, GetSysColorBrush ( COLOR_3DSHADOW ) );
if ( window->mScripts.Num ( ) )
{
@ -407,7 +428,7 @@ LRESULT CALLBACK rvDebuggerWindow::MarginWndProc ( HWND wnd, UINT msg, WPARAM wp
c = SendMessage ( window->mWndScript, EM_LINEINDEX, bp->GetLineNumber ( ) - 1, 0 );
SendMessage ( window->mWndScript, EM_POSFROMCHAR, (WPARAM)&pos, c );
ImageList_DrawEx ( window->mImageList, 2, dc, rect.left, pos.y, size, size, CLR_NONE, CLR_NONE, ILD_NORMAL );
ImageList_DrawEx ( window->mTmpImageList, 2, dc, rect.left, pos.y, width, height, CLR_NONE, CLR_NONE, ILD_NORMAL );
}
}
@ -421,7 +442,7 @@ LRESULT CALLBACK rvDebuggerWindow::MarginWndProc ( HWND wnd, UINT msg, WPARAM wp
c = SendMessage ( window->mWndScript, EM_LINEINDEX, window->mClient->GetBreakLineNumber() - 1, 0 );
SendMessage ( window->mWndScript, EM_POSFROMCHAR, (WPARAM)&pos, c );
ImageList_DrawEx ( window->mImageList, 3, dc, rect.left, pos.y, size, size, CLR_NONE, CLR_NONE, ILD_NORMAL );
ImageList_DrawEx ( window->mTmpImageList, 3, dc, rect.left, pos.y, width, height, CLR_NONE, CLR_NONE, ILD_NORMAL );
}
}
@ -434,17 +455,19 @@ LRESULT CALLBACK rvDebuggerWindow::MarginWndProc ( HWND wnd, UINT msg, WPARAM wp
c = SendMessage ( window->mWndScript, EM_LINEINDEX, window->mClient->GetCallstack()[window->mCurrentStackDepth]->mLineNumber - 1, 0 );
SendMessage ( window->mWndScript, EM_POSFROMCHAR, (WPARAM)&pos, c );
ImageList_DrawEx ( window->mImageList, 1, dc, rect.left, pos.y, size, size, CLR_NONE, CLR_NONE, ILD_NORMAL );
ImageList_DrawEx ( window->mTmpImageList, 1, dc, rect.left, pos.y, width, height, CLR_NONE, CLR_NONE, ILD_NORMAL );
}
}
}
RECT tmp = rect;
rect.right-=2;
rect.left = rect.right + 1;
HPEN pen = CreatePen ( PS_SOLID, 1, GetSysColor ( COLOR_3DSHADOW ) );
rect.right -= s2;
rect.left = rect.right + s2;
HPEN pen = CreatePen ( PS_SOLID, s2, GetSysColor ( COLOR_BACKGROUND ) );
HPEN old = (HPEN)SelectObject ( dc, pen );
MoveToEx ( dc, rect.right, rect.top, NULL );
LineTo ( dc, rect.right, rect.bottom );
SelectObject ( dc, old );
DeleteObject ( pen );
EndPaint ( wnd, &ps );
@ -466,7 +489,7 @@ void rvDebuggerWindow::UpdateTitle ( void )
{
idStr title;
title = "Quake 4 Script Debugger - ";
title = "Dhewm3 Script Debugger - ";
if ( mClient->IsConnected ( ) )
{
@ -487,7 +510,10 @@ void rvDebuggerWindow::UpdateTitle ( void )
if ( mScripts.Num ( ) )
{
title += " - [";
title += idStr( mScripts[mActiveScript]->GetFilename() ).StripPath ( );
if (mActiveScript != -1)
title += idStr( mScripts[mActiveScript]->GetFilename() ).StripPath ( );
else
title += "Load Error";
title += "]";
}
@ -590,6 +616,33 @@ void rvDebuggerWindow::UpdateCallstack ( void )
}
}
void rvDebuggerWindow::UpdateScriptList(void)
{
LVITEM item;
ListView_DeleteAllItems(mWndScriptList);
ZeroMemory(&item, sizeof(item));
item.mask = LVIF_TEXT | LVIF_IMAGE;
idStrList& scripts = mClient->GetServerScripts();
for (int i = 0; i < scripts.Num(); i++)
{
item.iItem = ListView_GetItemCount(mWndScriptList);
item.pszText = "";
//find in activeScripts
item.iImage = 0;
for (int j = 0; j < mScripts.Num(); j++)
{
if (!idStr::Icmp(mScripts[j]->GetFilename(), scripts[i]))
{
item.iImage = 1;
break;
}
}
ListView_InsertItem(mWndScriptList, &item);
ListView_SetItemText(mWndScriptList, item.iItem, 1, (LPSTR)scripts[i].c_str());
}
}
/*
================
rvDebuggerWindow::UpdateWatch
@ -737,6 +790,32 @@ int rvDebuggerWindow::HandleInitMenu ( WPARAM wParam, LPARAM lParam )
return 0;
}
void rvDebuggerWindow::ResizeImageList(int& widthOut, int& heightOut)
{
//mTmpImageList
float scaling_factor = Win_GetWindowScalingFactor(mWnd);
int s16 = int(16 * scaling_factor);
TEXTMETRIC tm;
HDC dc;
dc = GetDC(mWndScript);
GetTextMetrics(dc, &tm);
int height = mZoomScaleDem ? (tm.tmHeight * (float)mZoomScaleNum / (float)mZoomScaleDem) : 16;
int width = mZoomScaleDem ? (s16 * (float)mZoomScaleNum / (float)mZoomScaleDem) : 16;
ImageList_Destroy(mTmpImageList);
mTmpImageList = ImageList_Create(width, height, ILC_COLOR | ILC_MASK , 0, 2);
ImageList_AddIcon(mTmpImageList, (HICON)LoadImage(mInstance, MAKEINTRESOURCE(IDI_DBG_EMPTY), IMAGE_ICON, width, height, LR_DEFAULTSIZE | LR_DEFAULTCOLOR));
ImageList_AddIcon(mTmpImageList, (HICON)LoadImage(mInstance, MAKEINTRESOURCE(IDI_DBG_CURRENT), IMAGE_ICON, width, height, LR_DEFAULTSIZE | LR_DEFAULTCOLOR));
ImageList_AddIcon(mTmpImageList, (HICON)LoadImage(mInstance, MAKEINTRESOURCE(IDI_DBG_BREAKPOINT), IMAGE_ICON, width, height, LR_DEFAULTSIZE | LR_DEFAULTCOLOR));
ImageList_AddIcon(mTmpImageList, (HICON)LoadImage(mInstance, MAKEINTRESOURCE(IDI_DBG_CURRENTLINE), IMAGE_ICON, width, height, LR_DEFAULTSIZE | LR_DEFAULTCOLOR));
widthOut = width;
heightOut = height;
}
/*
================
rvDebuggerWindow::HandleCreate
@ -760,7 +839,7 @@ int rvDebuggerWindow::HandleCreate ( WPARAM wparam, LPARAM lparam )
// Create the script window
LoadLibrary ( "Riched20.dll" );
mWndScript = CreateWindow ( "RichEdit20A", "", WS_CHILD|WS_BORDER|ES_NOHIDESEL|ES_READONLY|ES_MULTILINE|ES_WANTRETURN|ES_AUTOVSCROLL|ES_AUTOHSCROLL|WS_VSCROLL|WS_HSCROLL, 0, 0, 100, 100, mWnd, (HMENU) IDC_DBG_SCRIPT, mInstance, 0 );
SendMessage ( mWndScript, EM_SETEVENTMASK, 0, ENM_SCROLL|ENM_CHANGE );
SendMessage ( mWndScript, EM_SETEVENTMASK, 0, ENM_SCROLL | ENM_CHANGE | ENM_UPDATE | ENM_SCROLLEVENTS | ENM_REQUESTRESIZE) ;
SendMessage ( mWndScript, EM_SETWORDBREAKPROC, 0, (LPARAM) ScriptWordBreakProc );
mOldScriptProc = (WNDPROC)GetWindowLong ( mWndScript, GWL_WNDPROC );
SetWindowLong ( mWndScript, GWL_USERDATA, (LONG)this );
@ -782,6 +861,7 @@ int rvDebuggerWindow::HandleCreate ( WPARAM wparam, LPARAM lparam )
SendMessage ( mWndOutput, WM_SETFONT, (WPARAM)CreateFontIndirect ( &lf ), 0 );
SendMessage ( mWndOutput, EM_SETMARGINS, EC_LEFTMARGIN|EC_RIGHTMARGIN, MAKELONG(18,10) );
SendMessage ( mWndOutput, EM_SETBKGNDCOLOR, 0, GetSysColor ( COLOR_3DFACE ) );
SendMessage ( mWndOutput, EM_SETEVENTMASK, 0, ENM_SCROLL | ENM_CHANGE | ENM_UPDATE | ENM_SCROLLEVENTS);
mWndConsole = CreateWindow ( "RichEdit20A", "", WS_CHILD|ES_READONLY|ES_MULTILINE|ES_WANTRETURN|ES_AUTOVSCROLL|ES_AUTOHSCROLL|WS_VSCROLL|WS_HSCROLL, 0, 0, 100, 100, mWnd, (HMENU) IDC_DBG_CONSOLE, mInstance, 0 );
SendMessage ( mWndConsole, WM_SETFONT, (WPARAM)CreateFontIndirect ( &lf ), 0 );
@ -816,13 +896,24 @@ int rvDebuggerWindow::HandleCreate ( WPARAM wparam, LPARAM lparam )
TabCtrl_InsertItem ( mWndTabs, 3, &item );
item.pszText = "Threads";
TabCtrl_InsertItem ( mWndTabs, 4, &item );
item.pszText = "Scripts";
TabCtrl_InsertItem ( mWndTabs, 5, &item );
mWndCallstack = CreateWindow ( WC_LISTVIEW, "", LVS_REPORT|WS_CHILD|LVS_SHAREIMAGELISTS, 0, 0, 0, 0, mWnd, (HMENU)IDC_DBG_CALLSTACK, mInstance, NULL );
mWndWatch = CreateWindow ( WC_LISTVIEW, "", LVS_REPORT|WS_CHILD|LVS_EDITLABELS|LVS_OWNERDRAWFIXED, 0, 0, 0, 0, mWnd, (HMENU)IDC_DBG_WATCH, mInstance, NULL );
mWndThreads = CreateWindow ( WC_LISTVIEW, "", LVS_REPORT|WS_CHILD|LVS_SHAREIMAGELISTS, 0, 0, 0, 0, mWnd, (HMENU)IDC_DBG_THREADS, mInstance, NULL );
mWndScriptList = CreateWindow( WC_LISTVIEW, "", LVS_REPORT|WS_CHILD|LVS_SHAREIMAGELISTS, 0, 0, 0, 0, mWnd, (HMENU)IDC_DBG_SCRIPTLIST, mInstance, NULL );
LVCOLUMN col;
col.mask = LVCF_WIDTH|LVCF_TEXT;
col.cx = 20;
col.pszText = "";
ListView_InsertColumn ( mWndScriptList, 0, &col);
col.cx = 150;
col.pszText = "Filename";
ListView_InsertColumn ( mWndScriptList, 1, &col );
col.cx = 20;
col.pszText = "";
ListView_InsertColumn ( mWndCallstack, 0, &col );
@ -863,13 +954,19 @@ int rvDebuggerWindow::HandleCreate ( WPARAM wparam, LPARAM lparam )
ImageList_AddIcon ( mImageList, (HICON)LoadImage ( mInstance, MAKEINTRESOURCE(IDI_DBG_CURRENT), IMAGE_ICON, 16, 16, LR_DEFAULTSIZE|LR_DEFAULTCOLOR) );
ImageList_AddIcon ( mImageList, (HICON)LoadImage ( mInstance, MAKEINTRESOURCE(IDI_DBG_BREAKPOINT), IMAGE_ICON, 16, 16, LR_DEFAULTSIZE|LR_DEFAULTCOLOR) );
ImageList_AddIcon ( mImageList, (HICON)LoadImage ( mInstance, MAKEINTRESOURCE(IDI_DBG_CURRENTLINE), IMAGE_ICON, 16, 16, LR_DEFAULTSIZE|LR_DEFAULTCOLOR) );
int w, h;
ResizeImageList(w, h);
ListView_SetImageList ( mWndScriptList, mTmpImageList, LVSIL_SMALL );
ListView_SetImageList ( mWndThreads, mImageList, LVSIL_SMALL );
ListView_SetImageList ( mWndCallstack, mImageList, LVSIL_SMALL );
EnableWindows ( FALSE );
EnableWindow ( mWndScriptList, true );
ListView_SetExtendedListViewStyle ( mWndCallstack, LVS_EX_FULLROWSELECT );
ListView_SetExtendedListViewStyle ( mWndThreads, LVS_EX_FULLROWSELECT );
ListView_SetExtendedListViewStyle ( mWndScriptList, LVS_EX_FULLROWSELECT );
gDebuggerApp.GetOptions().GetColumnWidths ( "cw_callstack", mWndCallstack );
gDebuggerApp.GetOptions().GetColumnWidths ( "cw_threads", mWndThreads );
@ -920,6 +1017,10 @@ int rvDebuggerWindow::HandleCreate ( WPARAM wparam, LPARAM lparam )
AddWatch ( s );
}
RECT t;
GetClientRect(mWndScript, &t);
SendMessage(mWndScript, WM_SIZE, 0, MAKELPARAM(t.right - t.left, t.bottom - t.top));
return 0;
}
@ -1055,7 +1156,7 @@ int rvDebuggerWindow::HandleCommand ( WPARAM wparam, LPARAM lparam )
mZoomScaleNum = num;
mZoomScaleDem = dem;
GetClientRect ( mWndScript, &t );
SendMessage ( mWnd, WM_SIZE, 0, MAKELPARAM(t.right-t.left,t.bottom-t.top) );
SendMessage ( mWndScript, WM_SIZE, 0, MAKELPARAM(t.right-t.left ,t.bottom-t.top) );
}
else
{
@ -1202,8 +1303,13 @@ LRESULT CALLBACK rvDebuggerWindow::WndProc ( HWND wnd, UINT msg, WPARAM wparam,
case WM_SIZE:
{
float scaling_factor = Win_GetWindowScalingFactor(wnd);
int s18 = int(18 * scaling_factor);
int s4 = int(4 * scaling_factor);
int s10 = int(10 * scaling_factor);
RECT rect;
window->mMarginSize = window->mZoomScaleDem ? ((long)(18.0f * (float)window->mZoomScaleNum / (float)window->mZoomScaleDem)):18;
window->mMarginSize = window->mZoomScaleDem ? ((long)(s18 * (float)window->mZoomScaleNum / (float)window->mZoomScaleDem)): s18;
window->mSplitterRect.left = 0;
window->mSplitterRect.right = LOWORD(lparam);
@ -1215,7 +1321,7 @@ LRESULT CALLBACK rvDebuggerWindow::WndProc ( HWND wnd, UINT msg, WPARAM wparam,
SetRect ( &rect, 0, window->mSplitterRect.bottom, LOWORD(lparam), HIWORD(lparam) );
MoveWindow ( window->mWndTabs, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE );
SendMessage ( window->mWndTabs, TCM_ADJUSTRECT, FALSE, (LPARAM)&rect );
rect.bottom -= 4 ;
rect.bottom -= s4;
MoveWindow ( window->mWndBorder, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE );
InflateRect ( &rect, -1, -1 );
MoveWindow ( window->mWndOutput, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE );
@ -1223,6 +1329,13 @@ LRESULT CALLBACK rvDebuggerWindow::WndProc ( HWND wnd, UINT msg, WPARAM wparam,
MoveWindow ( window->mWndCallstack, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE );
MoveWindow ( window->mWndWatch, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE );
MoveWindow ( window->mWndThreads, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE );
MoveWindow ( window->mWndScriptList, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE );
SendMessage(window->mWndScript, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(s18, s10));
SendMessage(window->mWndCallstack, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(s18, s10));
SendMessage(window->mWndOutput, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(s18, s10));
SendMessage(window->mWndConsole, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(s18, s10));
break;
}
@ -1258,7 +1371,17 @@ LRESULT CALLBACK rvDebuggerWindow::WndProc ( HWND wnd, UINT msg, WPARAM wparam,
}
break;
}
case WM_MOUSEWHEEL:
{
HDC dc = GetDC(wnd);
DrawFocusRect(dc, &window->mSplitterRect);
ReleaseDC(wnd, dc);
RECT client;
GetClientRect(wnd, &client);
SendMessage(wnd, WM_SIZE, 0, MAKELPARAM(client.right - client.left, client.bottom - client.top));
}
case WM_LBUTTONUP:
if ( window->mSplitterDrag )
{
@ -1454,6 +1577,31 @@ LRESULT CALLBACK rvDebuggerWindow::WndProc ( HWND wnd, UINT msg, WPARAM wparam,
}
}
break;
case IDC_DBG_SCRIPTLIST:
if ( hdr->code == NM_DBLCLK )
{
int sel = ListView_GetNextItem(hdr->hwndFrom, -1, LVNI_SELECTED);
if (sel != -1)
{
LVITEM item = { 0 };
char temp[1024] = { 0 };
item.mask = LVIF_TEXT;
item.pszText = temp;
item.cchTextMax = sizeof(temp) - 1;
item.iSubItem = 1;
item.iItem = sel;
ListView_GetItem(hdr->hwndFrom, &item);
if (strlen(item.pszText) > 0)
{
window->OpenScript(item.pszText);
window->UpdateScriptList();
}
}
}
break;
case IDC_DBG_TABS:
if ( hdr->code == TCN_SELCHANGE )
{
@ -1462,6 +1610,7 @@ LRESULT CALLBACK rvDebuggerWindow::WndProc ( HWND wnd, UINT msg, WPARAM wparam,
ShowWindow ( window->mWndCallstack, SW_HIDE );
ShowWindow ( window->mWndWatch, SW_HIDE );
ShowWindow ( window->mWndThreads, SW_HIDE );
ShowWindow ( window->mWndScriptList, SW_HIDE );
switch ( TabCtrl_GetCurSel ( hdr->hwndFrom ) )
{
case 0:
@ -1483,6 +1632,9 @@ LRESULT CALLBACK rvDebuggerWindow::WndProc ( HWND wnd, UINT msg, WPARAM wparam,
case 4:
ShowWindow ( window->mWndThreads, SW_SHOW );
break;
case 5:
ShowWindow(window->mWndScriptList, SW_SHOW);
break;
}
}
break;
@ -1535,14 +1687,19 @@ rvDebuggerWindow::ProcessNetMessage
Process an incoming network message
================
*/
void rvDebuggerWindow::ProcessNetMessage ( msg_t* msg )
void rvDebuggerWindow::ProcessNetMessage ( idBitMsg* msg )
{
unsigned short command;
short command;
command = (unsigned short)MSG_ReadShort ( msg );
command = msg->ReadShort( );
switch ( command )
{
case DBMSG_REMOVEBREAKPOINT:
MessageBeep(MB_ICONEXCLAMATION);
InvalidateRect(mWndScript, NULL, FALSE);
break;
case DBMSG_RESUMED:
UpdateTitle ( );
UpdateToolbar ( );
@ -1554,9 +1711,9 @@ void rvDebuggerWindow::ProcessNetMessage ( msg_t* msg )
char temp2[1024];
int i;
MSG_ReadShort ( msg );
MSG_ReadString ( msg, temp, 1024 );
MSG_ReadString ( msg, temp2, 1024 );
msg->ReadShort ( );
msg->ReadString ( temp, 1024 );
msg->ReadString ( temp2, 1024 );
if ( mTooltipVar.Icmp ( temp ) == 0 )
{
mTooltipValue = temp2;
@ -1625,7 +1782,7 @@ void rvDebuggerWindow::ProcessNetMessage ( msg_t* msg )
case DBMSG_PRINT:
SendMessage ( mWndConsole, EM_SETSEL, -1, -1 );
SendMessage ( mWndConsole, EM_REPLACESEL, 0, (LPARAM)(const char*)(msg->data) + msg->readcount );
SendMessage ( mWndConsole, EM_REPLACESEL, 0, (LPARAM)(const char*)(msg->GetData()) + msg->GetReadCount() );
SendMessage ( mWndConsole, EM_SCROLLCARET, 0, 0 );
break;
@ -1637,13 +1794,17 @@ void rvDebuggerWindow::ProcessNetMessage ( msg_t* msg )
mClient->InspectVariable ( mTooltipVar, mCurrentStackDepth );
UpdateWatch ( );
EnableWindows ( TRUE );
OpenScript ( mClient->GetBreakFilename(), mClient->GetBreakLineNumber() - 1 );
OpenScript ( mClient->GetBreakFilename(), mClient->GetBreakLineNumber() - 1, mClient->GetBreakProgram());
UpdateTitle ( );
UpdateToolbar ( );
SetForegroundWindow ( mWnd );
break;
}
case DBMSG_INSPECTSCRIPTS:
{
UpdateScriptList ( );
break;
}
case DBMSG_INSPECTCALLSTACK:
{
UpdateCallstack ( );
@ -1719,7 +1880,7 @@ Opens the script with the given filename and will scroll to the given line
number if one is specified
================
*/
bool rvDebuggerWindow::OpenScript ( const char* filename, int lineNumber )
bool rvDebuggerWindow::OpenScript ( const char* filename, int lineNumber, idProgram* program )
{
int i;
@ -1748,7 +1909,6 @@ bool rvDebuggerWindow::OpenScript ( const char* filename, int lineNumber )
// Load the script
if ( !script->Load ( filename ) )
{
delete script;
SetCursor ( LoadCursor ( NULL, IDC_ARROW ) );
return false;
}
@ -1777,7 +1937,7 @@ bool rvDebuggerWindow::OpenScript ( const char* filename, int lineNumber )
// Move to a specific line number?
if ( lineNumber != -1 )
{
int c;
long c;
// Put the caret on the line number specified and scroll it into position.
// This is a bit of a hack since we set the selection twice, but setting the
@ -1785,10 +1945,10 @@ bool rvDebuggerWindow::OpenScript ( const char* filename, int lineNumber )
// and then scroll before going back to (c,c).
// NOTE: We scroll to the line before the one we want so its more visible
SetFocus ( mWndScript );
c = SendMessage ( mWndScript, EM_LINEINDEX, lineNumber - 1, 0 );
c = SendMessage ( mWndScript, EM_LINEINDEX, (long)lineNumber - 1, 0 );
SendMessage ( mWndScript, EM_SETSEL, c, c + 1 );
SendMessage ( mWndScript, EM_SCROLLCARET, 0, 0 );
c = SendMessage ( mWndScript, EM_LINEINDEX, lineNumber, 0 );
c = SendMessage ( mWndScript, EM_LINEINDEX, (long)lineNumber, 0 );
SendMessage ( mWndScript, EM_SETSEL, c, c );
}
else
@ -2193,7 +2353,7 @@ then the last text used will be searched for.
*/
bool rvDebuggerWindow::FindNext ( const char* text )
{
int start;
long start;
FINDTEXT ft;
if ( text )
@ -2230,7 +2390,7 @@ bool rvDebuggerWindow::FindNext ( const char* text )
}
}
SendMessage ( mWndScript, EM_SETSEL, start, start + mFind.Length() );
SendMessage ( mWndScript, EM_SETSEL, start, start + (long)mFind.Length() );
SendMessage ( mWndScript, EM_SCROLLCARET, 0, 0 );
return true;
@ -2247,7 +2407,7 @@ then the last text used will be searched for.
*/
bool rvDebuggerWindow::FindPrev ( const char* text )
{
int start;
long start;
FINDTEXT ft;
if ( text )

View file

@ -52,38 +52,56 @@ public:
rvDebuggerWindow ( );
~rvDebuggerWindow ( );
bool Create ( HINSTANCE hInstance );
bool Create ( HINSTANCE hInstance );
static bool Activate ( void );
static bool Activate ( void );
void ProcessNetMessage ( msg_t* msg );
void ProcessNetMessage ( idBitMsg * msg );
void Printf ( const char* format, ... );
void Printf ( const char* format, ... );
HWND GetWindow ( void );
HWND GetWindow ( void );
void AddWatch ( const char* name, bool update = true );
void AddWatch ( const char* name, bool update = true );
HINSTANCE GetInstance ( void );
HINSTANCE GetInstance ( void );
protected:
private:
bool RegisterClass ( void );
void CreateToolbar ( void );
bool InitRecentFiles ( void );
bool FindPrev ( const char* text = NULL );
bool FindNext ( const char* text = NULL );
int HandleInitMenu ( WPARAM wParam, LPARAM lParam );
int HandleCommand ( WPARAM wParam, LPARAM lParam );
int HandleCreate ( WPARAM wparam, LPARAM lparam );
int HandleActivate ( WPARAM wparam, LPARAM lparam );
int HandleDrawItem ( WPARAM wparam, LPARAM lparam );
void HandleTooltipGetDispInfo( WPARAM wparam, LPARAM lparam );
void UpdateWatch ( void );
void UpdateWindowMenu ( void );
void UpdateScript ( void );
void UpdateToolbar ( void );
void UpdateTitle ( void );
void UpdateCallstack ( void );
void UpdateRecentFiles ( void );
bool OpenScript ( const char* filename, int lineNumber = -1 );
void EnableWindows ( bool state );
void ResizeImageList ( int& widthOut, int& heightOut);
static LRESULT CALLBACK WndProc ( HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam );
static LRESULT CALLBACK MarginWndProc ( HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam );
static LRESULT CALLBACK ScriptWndProc ( HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam );
static INT_PTR CALLBACK AboutDlgProc ( HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam );
static int CALLBACK ScriptWordBreakProc( LPTSTR text, int current, int max, int action );
int GetSelectedText ( idStr& text );
bool FindPrev ( const char* text = NULL );
bool FindNext ( const char* text = NULL );
void ToggleBreakpoint ( void );
void UpdateScriptList ( void );
void UpdateWatch ( void );
void UpdateWindowMenu ( void );
void UpdateScript ( void );
void UpdateToolbar ( void );
void UpdateTitle ( void );
void UpdateCallstack ( void );
void UpdateRecentFiles ( void );
bool OpenScript ( const char* filename, int lineNumber = -1, idProgram* program = nullptr );
void EnableWindows ( bool state );
int GetSelectedText ( idStr& text );
void ToggleBreakpoint ( void );
HWND mWnd;
HWND mWndScript;
@ -93,6 +111,7 @@ protected:
HWND mWndBorder;
HWND mWndConsole;
HWND mWndCallstack;
HWND mWndScriptList;
HWND mWndWatch;
HWND mWndThreads;
HWND mWndToolTips;
@ -108,6 +127,7 @@ protected:
HINSTANCE mInstance;
HIMAGELIST mImageList;
HIMAGELIST mTmpImageList;
RECT mSplitterRect;
bool mSplitterDrag;
@ -129,25 +149,6 @@ protected:
rvDebuggerClient* mClient;
rvDebuggerWatchList mWatches;
private:
bool RegisterClass ( void );
void CreateToolbar ( void );
bool InitRecentFiles ( void );
int HandleInitMenu ( WPARAM wParam, LPARAM lParam );
int HandleCommand ( WPARAM wParam, LPARAM lParam );
int HandleCreate ( WPARAM wparam, LPARAM lparam );
int HandleActivate ( WPARAM wparam, LPARAM lparam );
int HandleDrawItem ( WPARAM wparam, LPARAM lparam );
void HandleTooltipGetDispInfo ( WPARAM wparam, LPARAM lparam );
static LRESULT CALLBACK WndProc ( HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam );
static LRESULT CALLBACK MarginWndProc ( HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam );
static LRESULT CALLBACK ScriptWndProc ( HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam );
static INT_PTR CALLBACK AboutDlgProc ( HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam );
static int CALLBACK ScriptWordBreakProc ( LPTSTR text, int current, int max, int action );
};
/*