Fix umpteen fails in the BSP monitoring state management. Probably introduce 1 or 2 new ones.

This commit is contained in:
jdolan 2013-11-19 21:15:06 -05:00
parent 58c425637e
commit a6934fb21b
2 changed files with 151 additions and 124 deletions

View File

@ -152,7 +152,6 @@ static void saxEndElement( message_info_t *data, const xmlChar *name ) {
#ifdef _DEBUG
Sys_Printf( "Received error msg .. shutting down..\n" );
#endif
g_pParentWnd->GetWatchBSP()->Reset();
// tell there has been an error
if ( g_pParentWnd->GetWatchBSP()->HasBSPPlugin() ) {
g_BSPFrontendTable.m_pfnEndListen( 2 );
@ -248,14 +247,93 @@ static xmlSAXHandler saxParser = {
// ------------------------------------------------------------------------------------------------
CWatchBSP::~CWatchBSP(){
Reset();
if ( m_pCmd ) {
g_ptr_array_free( m_pCmd, true );
m_pCmd = NULL;
}
if ( m_sBSPName ) {
delete[] m_sBSPName;
g_free( m_sBSPName );
m_sBSPName = NULL;
}
Net_Shutdown();
}
void CWatchBSP::RunQuake() {
// build the command line
Str cmd;
cmd = g_pGameDescription->mExecutablesPath.GetBuffer();
// this is game dependant
if ( !strcmp( ValueForKey( g_qeglobals.d_project_entity, "gamemode" ),"mp" ) ) {
// MP
cmd += g_pGameDescription->mMultiplayerEngine.GetBuffer();
}
else
{
// SP
cmd += g_pGameDescription->mEngine.GetBuffer();
}
#ifdef _WIN32
// NOTE: we are using unix pathnames and CreateProcess doesn't like / in the program path
// FIXME: This isn't true anymore, doesn't it?
FindReplace( cmd, "/", "\\" );
#endif
Str cmdline;
if ( g_pGameDescription->idTech2 ) {
cmdline = "+exec radiant.cfg +map ";
cmdline += m_sBSPName;
}
else
// NOTE: idTech3 specific - there used to be some logic depending on engine breed here
{
cmdline = "+set sv_pure 0 ";
// TTimo: a check for vm_* but that's all fine
//cmdline = "+set sv_pure 0 +set vm_ui 0 +set vm_cgame 0 +set vm_game 0 ";
if ( *ValueForKey( g_qeglobals.d_project_entity, "gamename" ) != '\0' ) {
cmdline += "+set fs_game ";
cmdline += ValueForKey( g_qeglobals.d_project_entity, "gamename" );
cmdline += " ";
}
//!\todo Read the start-map args from a config file.
if ( g_pGameDescription->mGameFile == "wolf.game" ) {
if ( !strcmp( ValueForKey( g_qeglobals.d_project_entity, "gamemode" ),"mp" ) ) {
// MP
cmdline += "+devmap ";
cmdline += m_sBSPName;
}
else
{
// SP
cmdline += "+set nextmap \"spdevmap ";
cmdline += m_sBSPName;
cmdline += "\"";
}
}
else
{
cmdline += "+devmap ";
cmdline += m_sBSPName;
}
}
Sys_Printf( "%s %s\n", cmd.GetBuffer(), cmdline.GetBuffer() );
// execute now
if ( !Q_Exec( cmd.GetBuffer(), (char *)cmdline.GetBuffer(), g_pGameDescription->mEnginePath.GetBuffer(), false ) ) {
CString msg;
msg = "Failed to execute the following command: ";
msg += cmd; msg += cmdline;
Sys_Printf( msg );
gtk_MessageBox( g_pParentWnd->m_pWidget, msg, "BSP monitoring", MB_OK | MB_ICONERROR );
}
}
void CWatchBSP::Reset(){
if ( m_pInSocket ) {
Net_Disconnect( m_pInSocket );
@ -269,6 +347,11 @@ void CWatchBSP::Reset(){
xmlFreeParserInputBuffer( m_xmlInputBuffer );
m_xmlInputBuffer = NULL;
}
if ( m_xmlParserCtxt ) {
xmlFreeParserCtxt( m_xmlParserCtxt );
m_xmlParserCtxt = NULL;
}
m_eState = EIdle;
}
@ -294,14 +377,21 @@ bool CWatchBSP::SetupListening(){
}
void CWatchBSP::DoEBeginStep() {
Reset();
if ( !SetupListening() ) {
CString msg;
msg = "Failed to get a listening socket on port 39000.\nTry running with BSP monitoring disabled if you can't fix this.\n";
Sys_Printf( msg );
gtk_MessageBox( g_pParentWnd->m_pWidget, msg, "BSP monitoring", MB_OK | MB_ICONERROR );
Reset();
return;
}
// re-initialise the debug window
if ( m_iCurrentStep == 0 ) {
g_DbgDlg.Init();
}
// set the timer for timeouts and step cancellation
g_timer_reset( m_pTimer );
g_timer_start( m_pTimer );
@ -309,20 +399,19 @@ void CWatchBSP::DoEBeginStep() {
if ( !m_bBSPPlugin ) {
Sys_Printf( "=== running BSP command ===\n%s\n", g_ptr_array_index( m_pCmd, m_iCurrentStep ) );
if ( !Q_Exec( NULL, (char *)g_ptr_array_index( m_pCmd, m_iCurrentStep ), NULL, true ) ) {
if ( !Q_Exec( NULL, (char *) g_ptr_array_index( m_pCmd, m_iCurrentStep ), NULL, true ) ) {
CString msg;
msg = "Failed to execute the following command: ";
msg += (char *)g_ptr_array_index( m_pCmd, m_iCurrentStep );
msg += (char *) g_ptr_array_index( m_pCmd, m_iCurrentStep );
msg += "\nCheck that the file exists and that you don't run out of system resources.\n";
Sys_Printf( msg );
gtk_MessageBox( g_pParentWnd->m_pWidget, msg, "BSP monitoring", MB_OK | MB_ICONERROR );
Reset();
return;
}
// re-initialise the debug window
if ( m_iCurrentStep == 0 ) {
g_DbgDlg.Init();
}
}
m_eState = EBeginStep;
}
@ -342,19 +431,20 @@ void CWatchBSP::RoutineProcessing(){
case EBeginStep:
// timeout: if we don't get an incoming connection fast enough, go back to idle
if ( g_timer_elapsed( m_pTimer, NULL ) > g_PrefsDlg.m_iTimeout ) {
gtk_MessageBox( g_pParentWnd->m_pWidget, "The connection timed out, assuming the BSP process failed\nMake sure you are using a networked version of Q3Map?\nOtherwise you need to disable BSP Monitoring in prefs.", "BSP process monitoring", MB_OK );
gtk_MessageBox( g_pParentWnd->m_pWidget, "The connection timed out, assuming the BSP process failed\nMake sure you are using a networked version of Q3Map?\nOtherwise you need to disable BSP Monitoring in prefs.", "BSP process monitoring", MB_OK );
Reset();
if ( m_bBSPPlugin ) {
// status == 1 : didn't get the connection
g_BSPFrontendTable.m_pfnEndListen( 1 );
}
return;
break;
}
#ifdef _DEBUG
// some debug checks
if ( !m_pListenSocket ) {
Sys_Printf( "ERROR: m_pListenSocket == NULL in CWatchBSP::RoutineProcessing EBeginStep state\n" );
return;
Reset();
break;
}
#endif
// we are not connected yet, accept any incoming connection
@ -364,16 +454,17 @@ void CWatchBSP::RoutineProcessing(){
// prepare the message info struct for diving in
memset( &m_message_info, 0, sizeof( message_info_s ) );
// a dumb flag to make sure we init the push parser context when first getting a msg
m_bNeedCtxtInit = true;
m_eState = EWatching;
}
break;
case EWatching:
#ifdef _DEBUG
// some debug checks
if ( !m_pInSocket ) {
Sys_Printf( "ERROR: m_pInSocket == NULL in CWatchBSP::RoutineProcessing EWatching state\n" );
return;
Reset();
break;
}
#endif
// select() will identify if the socket needs an update
@ -390,32 +481,22 @@ void CWatchBSP::RoutineProcessing(){
Sys_Printf( "WARNING: SOCKET_ERROR in CWatchBSP::RoutineProcessing\n" );
Sys_Printf( "Terminating the connection.\n" );
Reset();
return;
break;
}
#ifdef _DEBUG
if ( ret == -1 ) {
// we are non-blocking?? we should never get timeout errors
Sys_Printf( "WARNING: unexpected timeout expired in CWatchBSP::Processing\n" );
Sys_Printf( "Terminating the connection.\n" );
Reset();
return;
}
#endif
if ( ret == 1 ) {
// the socket has been identified, there's something (message or disconnection)
// see if there's anything in input
ret = Net_Receive( m_pInSocket, &msg );
if ( ret > 0 ) {
// unsigned int size = msg.size; //++timo just a check
strcpy( m_xmlBuf, NMSG_ReadString( &msg ) );
if ( m_bNeedCtxtInit ) {
m_xmlParserCtxt = NULL;
g_strlcpy( m_xmlBuf, NMSG_ReadString( &msg ), sizeof( m_xmlBuf) );
if ( m_xmlParserCtxt == NULL ) {
m_xmlParserCtxt = xmlCreatePushParserCtxt( &saxParser, &m_message_info, m_xmlBuf, strlen( m_xmlBuf ), NULL );
if ( m_xmlParserCtxt == NULL ) {
Sys_FPrintf( SYS_ERR, "Failed to create the XML parser (incoming stream began with: %s)\n", m_xmlBuf );
Reset();
break;
}
m_bNeedCtxtInit = false;
}
else
{
@ -430,103 +511,29 @@ void CWatchBSP::RoutineProcessing(){
m_pInSocket = NULL;
Sys_Printf( "Connection closed.\n" );
if ( m_bBSPPlugin ) {
Reset();
// let the BSP plugin know that the job is done
g_BSPFrontendTable.m_pfnEndListen( 0 );
return;
}
Reset();
// move to next step or finish
m_iCurrentStep++;
if ( m_iCurrentStep < m_pCmd->len ) {
printf("BEGIN AGAIN\n");
DoEBeginStep();
break;
}
else
{
// release the GPtrArray and the strings
if ( m_pCmd != NULL ) {
for ( m_iCurrentStep = 0; m_iCurrentStep < m_pCmd->len; m_iCurrentStep++ )
{
delete[] (char *)g_ptr_array_index( m_pCmd, m_iCurrentStep );
}
g_ptr_array_free( m_pCmd, false );
}
m_pCmd = NULL;
// launch the engine .. OMG
if ( g_PrefsDlg.m_bRunQuake ) {
// do we enter sleep mode before?
if ( g_PrefsDlg.m_bDoSleep ) {
Sys_Printf( "Going into sleep mode..\n" );
g_pParentWnd->OnSleep();
}
Sys_Printf( "Running engine...\n" );
Str cmd;
// build the command line
cmd = g_pGameDescription->mExecutablesPath.GetBuffer();
// this is game dependant
if ( !strcmp( ValueForKey( g_qeglobals.d_project_entity, "gamemode" ),"mp" ) ) {
// MP
cmd += g_pGameDescription->mMultiplayerEngine.GetBuffer();
}
else
{
// SP
cmd += g_pGameDescription->mEngine.GetBuffer();
}
#ifdef _WIN32
// NOTE: we are using unix pathnames and CreateProcess doesn't like / in the program path
// FIXME: This isn't true anymore, doesn't it?
FindReplace( cmd, "/", "\\" );
#endif
Str cmdline;
if ( g_pGameDescription->idTech2 ) {
cmdline = "+exec radiant.cfg +map ";
cmdline += m_sBSPName;
}
else
// NOTE: idTech3 specific - there used to be some logic depending on engine breed here
{
cmdline = "+set sv_pure 0 ";
// TTimo: a check for vm_* but that's all fine
//cmdline = "+set sv_pure 0 +set vm_ui 0 +set vm_cgame 0 +set vm_game 0 ";
if ( *ValueForKey( g_qeglobals.d_project_entity, "gamename" ) != '\0' ) {
cmdline += "+set fs_game ";
cmdline += ValueForKey( g_qeglobals.d_project_entity, "gamename" );
cmdline += " ";
}
//!\todo Read the start-map args from a config file.
if ( g_pGameDescription->mGameFile == "wolf.game" ) {
if ( !strcmp( ValueForKey( g_qeglobals.d_project_entity, "gamemode" ),"mp" ) ) {
// MP
cmdline += "+devmap ";
cmdline += m_sBSPName;
}
else
{
// SP
cmdline += "+set nextmap \"spdevmap ";
cmdline += m_sBSPName;
cmdline += "\"";
}
}
else
{
cmdline += "+devmap ";
cmdline += m_sBSPName;
}
}
Sys_Printf( "%s %s\n", cmd.GetBuffer(), cmdline.GetBuffer() );
// execute now
if ( !Q_Exec( cmd.GetBuffer(), (char *)cmdline.GetBuffer(), g_pGameDescription->mEnginePath.GetBuffer(), false ) ) {
CString msg;
msg = "Failed to execute the following command: ";
msg += cmd; msg += cmdline;
Sys_Printf( msg );
gtk_MessageBox( g_pParentWnd->m_pWidget, msg, "BSP monitoring", MB_OK | MB_ICONERROR );
}
// launch the engine .. OMG
if ( g_PrefsDlg.m_bRunQuake ) {
// do we enter sleep mode before?
if ( g_PrefsDlg.m_bDoSleep ) {
Sys_Printf( "Going into sleep mode..\n" );
g_pParentWnd->OnSleep();
}
Reset();
Sys_Printf( "Running engine...\n" );
RunQuake();
}
}
}
@ -537,21 +544,39 @@ void CWatchBSP::RoutineProcessing(){
}
void CWatchBSP::DoMonitoringLoop( GPtrArray *pCmd, char *sBSPName ){
if ( m_sBSPName ) {
delete[] m_sBSPName;
}
m_sBSPName = sBSPName;
guint i;
if ( m_eState != EIdle ) {
Sys_Printf( "WatchBSP got a monitoring request while not idling...\n" );
// prompt the user, should we cancel the current process and go ahead?
if ( gtk_MessageBox( g_pParentWnd->m_pWidget, "I am already monitoring a BSP process.\nDo you want me to override and start a new compilation?",
"BSP process monitoring", MB_YESNO ) == IDYES ) {
// disconnect and set EIdle state
Reset();
"BSP process monitoring", MB_YESNO ) == IDNO ) {
return;
}
}
m_pCmd = pCmd;
Reset();
if ( m_pCmd ) {
g_ptr_array_free( m_pCmd, true );
m_pCmd = NULL;
}
if ( m_sBSPName ) {
g_free( m_sBSPName );
m_sBSPName = NULL;
}
m_pCmd = g_ptr_array_new_full( pCmd->len, g_free ) ;
for ( i = 0; i < pCmd->len; i++ ) {
g_ptr_array_add( m_pCmd, g_strdup( (char *) pCmd->pdata[i] ) );
}
m_iCurrentStep = 0;
m_sBSPName = g_strdup(sBSPName);
DoEBeginStep();
}

View File

@ -61,6 +61,8 @@ char *m_sBSPName;
xmlParserInputBufferPtr m_xmlInputBuffer;
xmlParserInputPtr m_xmlInput;
xmlParserCtxtPtr m_xmlParserCtxt;
// run the game engine after successful compile
void RunQuake();
// call this to switch the set listening mode
bool SetupListening();
// start a new EBeginStep
@ -71,7 +73,7 @@ bool m_bNeedCtxtInit;
message_info_s m_message_info;
public:
CWatchBSP() { m_bBSPPlugin = false; m_pListenSocket = NULL; m_pInSocket = NULL; m_eState = EIdle; m_pTimer = g_timer_new(); m_sBSPName = NULL; m_xmlInputBuffer = NULL; m_bNeedCtxtInit = true; }
CWatchBSP() { m_bBSPPlugin = false; m_pListenSocket = NULL; m_pInSocket = NULL; m_eState = EIdle; m_pTimer = g_timer_new(); m_sBSPName = NULL; m_pCmd = NULL; m_iCurrentStep = 0; m_xmlInputBuffer = NULL; m_xmlParserCtxt = NULL; }
virtual ~CWatchBSP();
bool HasBSPPlugin() const
{ return m_bBSPPlugin; }