/* ================ Host_EndGame ================ */ void Host_EndGame( const char *message, ... ) { va_list argptr; static char string[MAX_SYSPATH]; va_start( argptr, message ); Q_vsprintf( string, message, argptr ); va_end( argptr ); MsgDev( D_INFO, "Host_EndGame: %s\n", string ); if( SV_Active()) { Q_snprintf( host.finalmsg, sizeof( host.finalmsg ), "Host_EndGame: %s", string ); SV_Shutdown( false ); return; } if( host.type == HOST_DEDICATED ) Sys_Break( "Host_EndGame: %s\n", string ); // dedicated servers exit SV_Shutdown( false ); CL_Disconnect(); // recreate world if needs CL_ClearEdicts (); // release all models Mod_ClearAll( true ); Host_AbortCurrentFrame (); }
/* ================ Host_Error This shuts down both the client and server ================ */ void Host_Error (const char *error, ...) { static char hosterrorstring1[MAX_INPUTLINE]; // THREAD UNSAFE static char hosterrorstring2[MAX_INPUTLINE]; // THREAD UNSAFE static qboolean hosterror = false; va_list argptr; // turn off rcon redirect if it was active when the crash occurred // to prevent loops when it is a networking problem Con_Rcon_Redirect_Abort(); va_start (argptr,error); dpvsnprintf (hosterrorstring1,sizeof(hosterrorstring1),error,argptr); va_end (argptr); Con_Printf("Host_Error: %s\n", hosterrorstring1); // LordHavoc: if crashing very early, or currently shutting down, do // Sys_Error instead if (host_framecount < 3 || host_shuttingdown) Sys_Error ("Host_Error: %s", hosterrorstring1); if (hosterror) Sys_Error ("Host_Error: recursively entered (original error was: %s new error is: %s)", hosterrorstring2, hosterrorstring1); hosterror = true; strlcpy(hosterrorstring2, hosterrorstring1, sizeof(hosterrorstring2)); CL_Parse_DumpPacket(); CL_Parse_ErrorCleanUp(); //PR_Crash(); // print out where the crash happened, if it was caused by QC (and do a cleanup) PRVM_Crash(SVVM_prog); PRVM_Crash(CLVM_prog); #ifdef CONFIG_MENU PRVM_Crash(MVM_prog); #endif cl.csqc_loaded = false; Cvar_SetValueQuick(&csqc_progcrc, -1); Cvar_SetValueQuick(&csqc_progsize, -1); SV_LockThreadMutex(); Host_ShutdownServer (); SV_UnlockThreadMutex(); if (cls.state == ca_dedicated) Sys_Error ("Host_Error: %s",hosterrorstring2); // dedicated servers exit CL_Disconnect (); cls.demonum = -1; hosterror = false; Host_AbortCurrentFrame(); }
/* ===================== CL_ParseServerMessage ===================== */ void CL_ParseServerMessage( sizebuf_t *msg ) { char *s; int i, j, cmd; int param1, param2; int bufStart; cls_message_debug.parsing = true; // begin parsing starting_count = BF_GetNumBytesRead( msg ); // updates each frame // parse the message while( 1 ) { if( BF_CheckOverflow( msg )) { Host_Error( "CL_ParseServerMessage: overflow!\n" ); return; } // mark start position bufStart = BF_GetNumBytesRead( msg ); // end of message if( BF_GetNumBitsLeft( msg ) < 8 ) break; cmd = BF_ReadByte( msg ); // record command for debugging spew on parse problem CL_Parse_RecordCommand( cmd, bufStart ); // other commands switch( cmd ) { case svc_bad: Host_Error( "svc_bad\n" ); break; case svc_nop: // this does nothing break; case svc_disconnect: MsgDev( D_INFO, "Disconnected from server\n" ); CL_Drop (); Host_AbortCurrentFrame (); break; case svc_changing: if( BF_ReadOneBit( msg )) { cls.changelevel = true; S_StopAllSounds(); if( cls.demoplayback ) { SCR_BeginLoadingPlaque( cl.background ); cls.changedemo = true; } } else MsgDev( D_INFO, "Server disconnected, reconnecting\n" ); CL_ClearState (); CL_InitEdicts (); // re-arrange edicts if( cls.demoplayback ) { cl.background = (cls.demonum != -1) ? true : false; cls.state = ca_connected; } else cls.state = ca_connecting; cls.connect_time = MAX_HEARTBEAT; // CL_CheckForResend() will fire immediately break; case svc_setview: cl.refdef.viewentity = BF_ReadWord( msg ); break; case svc_sound: CL_ParseSoundPacket( msg, false ); break; case svc_time: // shuffle timestamps cl.mtime[1] = cl.mtime[0]; cl.mtime[0] = BF_ReadFloat( msg ); break; case svc_print: i = BF_ReadByte( msg ); MsgDev( D_INFO, "^6%s", BF_ReadString( msg )); if( i == PRINT_CHAT ) S_StartLocalSound( "common/menu2.wav", VOL_NORM, false ); break; case svc_stufftext: CL_ParseStuffText( msg ); break; case svc_lightstyle: CL_ParseLightStyle( msg ); break; case svc_setangle: CL_ParseSetAngle( msg ); break; case svc_serverdata: Cbuf_Execute(); // make sure any stuffed commands are done CL_ParseServerData( msg ); break; case svc_addangle: CL_ParseAddAngle( msg ); break; case svc_clientdata: CL_ParseClientData( msg ); break; case svc_packetentities: CL_ParsePacketEntities( msg, false ); break; case svc_deltapacketentities: CL_ParsePacketEntities( msg, true ); break; case svc_updatepings: CL_UpdateUserPings( msg ); break; case svc_usermessage: CL_RegisterUserMessage( msg ); break; case svc_particle: CL_ParseParticles( msg ); break; case svc_restoresound: CL_ParseRestoreSoundPacket( msg ); break; case svc_spawnstatic: CL_ParseStaticEntity( msg ); break; case svc_ambientsound: CL_ParseSoundPacket( msg, true ); break; case svc_crosshairangle: CL_ParseCrosshairAngle( msg ); break; case svc_spawnbaseline: CL_ParseBaseline( msg ); break; case svc_temp_entity: CL_ParseTempEntity( msg ); break; case svc_setpause: cl.refdef.paused = ( BF_ReadOneBit( msg ) != 0 ); break; case svc_deltamovevars: CL_ParseMovevars( msg ); break; case svc_customization: CL_ParseCustomization( msg ); break; case svc_centerprint: CL_CenterPrint( BF_ReadString( msg ), 0.25f ); break; case svc_event: CL_ParseEvent( msg ); break; case svc_event_reliable: CL_ParseReliableEvent( msg ); break; case svc_updateuserinfo: CL_UpdateUserinfo( msg ); break; case svc_intermission: cl.refdef.intermission = true; break; case svc_modelindex: CL_PrecacheModel( msg ); break; case svc_soundindex: CL_PrecacheSound( msg ); break; case svc_soundfade: CL_ParseSoundFade( msg ); break; case svc_cdtrack: param1 = BF_ReadByte( msg ); param1 = bound( 1, param1, MAX_CDTRACKS ); // tracknum param2 = BF_ReadByte( msg ); param2 = bound( 1, param2, MAX_CDTRACKS ); // loopnum S_StartBackgroundTrack( clgame.cdtracks[param1-1], clgame.cdtracks[param2-1], 0 ); break; case svc_serverinfo: CL_ServerInfo( msg ); break; case svc_eventindex: CL_PrecacheEvent( msg ); break; case svc_deltatable: Delta_ParseTableField( msg ); break; case svc_weaponanim: param1 = BF_ReadByte( msg ); // iAnim param2 = BF_ReadByte( msg ); // body CL_WeaponAnim( param1, param2 ); break; case svc_bspdecal: CL_ParseStaticDecal( msg ); break; case svc_roomtype: param1 = BF_ReadShort( msg ); Cvar_SetFloat( "room_type", param1 ); break; case svc_chokecount: i = BF_ReadByte( msg ); j = cls.netchan.incoming_acknowledged - 1; for( ; i > 0 && j > cls.netchan.outgoing_sequence - CL_UPDATE_BACKUP; j-- ) { if( cl.frames[j & CL_UPDATE_MASK].receivedtime != -3.0 ) { cl.frames[j & CL_UPDATE_MASK].receivedtime = -2.0; i--; } } break; case svc_resourcelist: CL_ParseResourceList( msg ); break; case svc_director: CL_ParseDirector( msg ); break; case svc_studiodecal: CL_ParseStudioDecal( msg ); break; case svc_querycvarvalue: CL_ParseCvarValue( msg ); break; case svc_querycvarvalue2: CL_ParseCvarValue2( msg ); break; default: CL_ParseUserMessage( msg, cmd ); break; } } cls_message_debug.parsing = false; // done // we don't know if it is ok to save a demo message until // after we have parsed the frame if( !cls.demoplayback ) { if( cls.demorecording && !cls.demowaiting ) { CL_WriteDemoMessage( false, starting_count, msg ); } else if( cls.state != ca_active ) { CL_WriteDemoMessage( true, starting_count, msg ); } } }
/* ================= Host_Error ================= */ void Host_Error( const char *error, ... ) { static char hosterror1[MAX_SYSPATH]; static char hosterror2[MAX_SYSPATH]; static qboolean recursive = false; va_list argptr; if( host.mouse_visible && !CL_IsInMenu( )) { // hide VGUI mouse #ifdef XASH_SDL SDL_ShowCursor( false ); #endif host.mouse_visible = false; } va_start( argptr, error ); Q_vsprintf( hosterror1, error, argptr ); va_end( argptr ); CL_WriteMessageHistory (); // before Q_error call if( host.framecount < 3 ) { Sys_Error( "Host_InitError: %s", hosterror1 ); } else if( host.framecount == host.errorframe ) { Sys_Error( "Host_MultiError: %s", hosterror2 ); return; } else { if( host.developer > 0 ) { UI_SetActiveMenu( false ); Key_SetKeyDest( key_console ); Msg( "^1Host_Error: ^7%s", hosterror1 ); } else MSGBOX2( hosterror1 ); } // host is shutting down. don't invoke infinite loop if( host.state == HOST_SHUTDOWN ) return; if( recursive ) { Msg( "Host_RecursiveError: %s", hosterror2 ); Sys_Error( hosterror1 ); return; // don't multiple executes } recursive = true; Q_strncpy( hosterror2, hosterror1, MAX_SYSPATH ); host.errorframe = host.framecount; // to avoid multple calls per frame Q_sprintf( host.finalmsg, "Server crashed: %s", hosterror1 ); // clear cmd buffer to prevent execution of any commands Cbuf_Clear(); SV_Shutdown( false ); CL_Drop(); // drop clients // recreate world if required CL_ClearEdicts (); // release all models Mod_ClearAll( false ); recursive = false; Host_AbortCurrentFrame(); }