- D3XP debugger fixes

This commit is contained in:
HarrievG 2021-05-13 10:23:36 +02:00 committed by Daniel Gibson
parent 5ebda5eab5
commit 99ca9f0543
5 changed files with 334 additions and 77 deletions

View file

@ -1146,3 +1146,65 @@ 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

@ -1312,7 +1312,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;
@ -1323,6 +1323,9 @@ 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;
@ -1350,7 +1353,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;
@ -2436,14 +2439,17 @@ void idGameLocal::RunTimeGroup2() {
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

@ -319,6 +319,7 @@ public:
idEntityPtr<idEntity> lastGUIEnt; // last entity with a GUI, used by Cmd_NextGUI_f
int lastGUI; // last GUI on the lastGUIEnt
int editors;
#ifdef _D3XP
idEntityPtr<idEntity> portalSkyEnt;
@ -365,13 +366,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()
@ -176,135 +178,166 @@ void idInterpreter::Reset( void ) {
doneProcessing = true;
}
/*
================
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 ) {
bool idInterpreter::GetRegisterValue(const char* name, idStr& out, int scopeDepth) {
varEval_t reg;
idVarDef *d;
char funcObject[ 1024 ];
char *funcName;
const idVarDef *scope;
const idTypeDef *field;
const idScriptObject *obj;
const function_t *func;
idVarDef* d;
char funcObject[1024];
char* funcName;
const idVarDef* scope = NULL;
const idVarDef* scopeObj;
const idTypeDef* field;
const function_t* func;
out.Empty();
if ( scopeDepth == -1 ) {
if (scopeDepth == -1) {
scopeDepth = callStackDepth;
}
if ( scopeDepth == callStackDepth ) {
if (scopeDepth == callStackDepth) {
func = currentFunction;
} else {
func = callStack[ scopeDepth ].f;
}
if ( !func ) {
else {
func = callStack[scopeDepth].f;
}
if (!func) {
return false;
}
idStr::Copynz( funcObject, func->Name(), sizeof( funcObject ) );
funcName = strstr( funcObject, "::" );
if ( funcName ) {
idStr::Copynz(funcObject, func->Name(), sizeof(funcObject));
funcName = strstr(funcObject, "::");
if (funcName) {
*funcName = '\0';
scope = gameLocal.program.GetDef( NULL, funcObject, &def_namespace );
scopeObj = gameLocal.program.GetDef(NULL, funcObject, &def_namespace);
funcName += 2;
} else {
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);
d = gameLocal.program.GetDef( NULL, name, scope );
if ( !d ) {
d = gameLocal.program.GetDef( NULL, name, &def_namespace );
if ( !d ) {
return false;
// 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;
}
}
}
reg = GetVariable( d );
switch( d->Type() ) {
if (!d)
{
out = "???";
return false;
}
reg = GetVariable(d);
switch (d->Type()) {
case ev_float:
if ( reg.floatPtr ) {
out = va("%g", *reg.floatPtr );
} else {
if (reg.floatPtr) {
out = va("%g", *reg.floatPtr);
}
else {
out = "0";
}
return true;
break;
case ev_vector:
if ( reg.vectorPtr ) {
out = va( "%g,%g,%g", reg.vectorPtr->x, reg.vectorPtr->y, reg.vectorPtr->z );
} else {
if (reg.vectorPtr) {
out = va("%g,%g,%g", reg.vectorPtr->x, reg.vectorPtr->y, reg.vectorPtr->z);
}
else {
out = "0,0,0";
}
return true;
break;
case ev_boolean:
if ( reg.intPtr ) {
out = va( "%d", *reg.intPtr );
} else {
if (reg.intPtr) {
out = va("%d", *reg.intPtr);
}
else {
out = "0";
}
return true;
break;
case ev_field:
if ( scope == &def_namespace ) {
{
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;
}
switch ( field->Type() ) {
obj = &entity->scriptObject;
if (!obj) {
return false;
}
switch (field->Type()) {
case ev_boolean:
out = va( "%d", *( reinterpret_cast<int *>( &obj->data[ reg.ptrOffset ] ) ) );
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 ] ) ) );
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;
}
break;
}
case ev_string:
if ( reg.stringPtr ) {
if (reg.stringPtr) {
out = "\"";
out += reg.stringPtr;
out += "\"";
} else {
}
else {
out = "\"\"";
}
return true;
@ -313,7 +346,6 @@ bool idInterpreter::GetRegisterValue( const char *name, idStr &out, int scopeDep
return false;
}
}
/*
================
idInterpreter::GetCallstackDepth
@ -969,6 +1001,20 @@ 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 +1879,99 @@ 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

@ -1921,3 +1921,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);
}