mirror of
https://github.com/dhewm/dhewm3.git
synced 2024-11-23 12:53:09 +00:00
- D3XP debugger fixes
This commit is contained in:
parent
5ebda5eab5
commit
99ca9f0543
5 changed files with 334 additions and 77 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 ) {
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
Loading…
Reference in a new issue