diff --git a/engine/client/cl_game.c b/engine/client/cl_game.c index 59d8a0c6..c9c78257 100644 --- a/engine/client/cl_game.c +++ b/engine/client/cl_game.c @@ -2265,11 +2265,64 @@ physent_t *pfnGetPhysent( int idx ) ============= pfnSetUpPlayerPrediction +FIXME: finalize ============= */ void pfnSetUpPlayerPrediction( int dopred, int bIncludeLocalClient ) { - // TODO: implement + entity_state_t *playerstate = cl.frames[cl.parsecountmod].playerstate; + predicted_player_t *player = cls.predicted_players; + cl_entity_t *clent; + int j, v12; + + for( j = 0; j < MAX_CLIENTS; j++, player++, playerstate++ ) + { + player->active = false; + + if( playerstate->messagenum != cl.parsecount ) + continue; // not present this frame + + if( !playerstate->modelindex ) + continue; + + // special for EF_NODRAW and local client? + if(( playerstate->effects & EF_NODRAW ) && !bIncludeLocalClient ) + { + // don't include local player? + if( cl.playernum != j ) + { + player->active = true; + player->movetype = playerstate->movetype; + player->solid = playerstate->solid; + player->usehull = playerstate->usehull; + + clent = CL_EDICT_NUM( j + 1 ); +// CL_ComputePlayerOrigin( v9 ); + VectorCopy( clent->origin, player->origin ); + VectorCopy( clent->angles, player->angles ); + } + else continue; + } + else + { + if( cl.playernum == j ) + continue; + + player->active = true; + player->movetype = playerstate->movetype; + player->solid = playerstate->solid; + player->usehull = playerstate->usehull; + + v12 = 17080 * cl.parsecountmod + 340 * j; + player->origin[0] = cl.frames[0].playerstate[0].origin[0] + v12; + player->origin[1] = cl.frames[0].playerstate[0].origin[1] + v12; + player->origin[2] = cl.frames[0].playerstate[0].origin[2] + v12; + + player->angles[0] = cl.frames[0].playerstate[0].angles[0] + v12; + player->angles[1] = cl.frames[0].playerstate[0].angles[1] + v12; + player->angles[2] = cl.frames[0].playerstate[0].angles[2] + v12; + } + } } /* diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 55f532e8..1f718169 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -284,6 +284,7 @@ void CL_CreateCmd( void ) // build list of all solid entities per next frame (exclude clients) CL_SetSolidEntities (); + CL_SetSolidPlayers ( cl.playernum ); VectorCopy( cl.refdef.cl_viewangles, angles ); VectorCopy( cl.frame.local.client.origin, cl.data.origin ); @@ -673,14 +674,16 @@ CL_Connect_f */ void CL_Connect_f( void ) { - char *server; + string server; if( Cmd_Argc() != 2 ) { Msg( "Usage: connect \n" ); return; } - + + Q_strncpy( server, Cmd_Argv( 1 ), sizeof( cls.servername )); + if( Host_ServerState()) { // if running a local server, kill it and reissue @@ -688,9 +691,8 @@ void CL_Connect_f( void ) SV_Shutdown( false ); } - server = Cmd_Argv( 1 ); NET_Config( true ); // allow remote - + Msg( "server %s\n", server ); CL_Disconnect(); @@ -907,9 +909,7 @@ CL_InternetServers_f void CL_InternetServers_f( void ) { netadr_t adr; - char part1query[12]; - char part2query[128]; - string fullquery; + char fullquery[512] = "\x31\xFF" "0.0.0.0:0\0" "\\gamedir\\"; MsgDev( D_INFO, "Scanning for servers on the internet area...\n" ); NET_Config( true ); // allow remote @@ -917,13 +917,9 @@ void CL_InternetServers_f( void ) if( !NET_StringToAdr( MASTERSERVER_ADR, &adr ) ) MsgDev( D_INFO, "Can't resolve adr: %s\n", MASTERSERVER_ADR ); - Q_snprintf( part1query, sizeof( part1query ), "%c%c0.0.0.0:0", 0x31, 0xFF ); - Q_snprintf( part2query, sizeof( part2query ), "\\gamedir\\%s_xash\\nap\\%d", GI->gamedir, 70 ); + Q_strcpy( &fullquery[21], GI->gamedir ); - Q_memcpy( fullquery, part1query, sizeof( part1query )); - Q_memcpy( fullquery + sizeof( part1query ), part2query, Q_strlen( part2query )); - - NET_SendPacket( NS_CLIENT, sizeof( part1query ) + Q_strlen( part2query ) + 1, fullquery, adr ); + NET_SendPacket( NS_CLIENT, Q_strlen( GI->gamedir ) + 22, fullquery, adr ); } /* @@ -1331,8 +1327,7 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) else if( !Q_strcmp( c, "print" )) { // print command from somewhere - args = BF_ReadString( msg ); - Msg( args ); + Msg( "remote: %s\n", BF_ReadString( msg )); } else if( !Q_strcmp( c, "ping" )) { @@ -1357,11 +1352,6 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) // dropped the connection but it is still getting packets from us CL_Disconnect(); } - else if( clgame.dllFuncs.pfnConnectionlessPacket( &from, args, buf, &len )) - { - // user out of band message (must be handled in CL_ConnectionlessPacket) - if( len > 0 ) Netchan_OutOfBand( NS_SERVER, from, len, buf ); - } else if( msg->pData[0] == 0xFF && msg->pData[1] == 0xFF && msg->pData[2] == 0xFF && msg->pData[3] == 0xFF && msg->pData[4] == 0x66 && msg->pData[5] == 0x0A ) { dataoffset = 6; @@ -1369,11 +1359,7 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) while( 1 ) { servadr.type = NA_IP; - servadr.ip[0] = msg->pData[dataoffset + 0]; - servadr.ip[1] = msg->pData[dataoffset + 1]; - servadr.ip[2] = msg->pData[dataoffset + 2]; - servadr.ip[3] = msg->pData[dataoffset + 3]; - + Q_memcpy( servadr.ip, &msg->pData[dataoffset], sizeof(servadr.ip)); servadr.port = *(word *)&msg->pData[dataoffset + 4]; if( !servadr.port ) @@ -1388,6 +1374,11 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) dataoffset += 6; } } + else if( clgame.dllFuncs.pfnConnectionlessPacket( &from, args, buf, &len )) + { + // user out of band message (must be handled in CL_ConnectionlessPacket) + if( len > 0 ) Netchan_OutOfBand( NS_SERVER, from, len, buf ); + } else MsgDev( D_ERROR, "bad connectionless packet from %s:\n%s\n", NET_AdrToString( from ), args ); } @@ -1516,16 +1507,21 @@ A file has been received via the fragmentation/reassembly layer, put it in the r see if we have finished downloading files. ==================== */ -void CL_ProcessFile( BOOL successfully_received, const char *filename ) +void CL_ProcessFile( qboolean successfully_received, const char *filename ) { - MsgDev( D_INFO, "Received %s, but file processing is not hooked up!!!\n", filename ); + if( successfully_received ) + MsgDev( D_INFO, "received %s\n", filename ); + else MsgDev( D_WARN, "failed to download %s", filename ); if( cls.downloadfileid == cls.downloadcount - 1 ) { - MsgDev( D_INFO, "All Files downloaded\n" ); - + MsgDev( D_INFO, "Download completed, resuming connection\n" ); + FS_Rescan(); BF_WriteByte( &cls.netchan.message, clc_stringcmd ); BF_WriteString( &cls.netchan.message, "continueloading" ); + cls.downloadfileid = 0; + cls.downloadcount = 0; + return; } cls.downloadfileid++; @@ -1607,7 +1603,7 @@ void CL_InitLocal( void ) cls.state = ca_disconnected; // register our variables - cl_predict = Cvar_Get( "cl_predict", "0", CVAR_ARCHIVE, "disables client movement prediction" ); + cl_predict = Cvar_Get( "cl_predict", "0", CVAR_ARCHIVE, "enable client movement prediction" ); cl_crosshair = Cvar_Get( "crosshair", "1", CVAR_ARCHIVE, "show weapon chrosshair" ); cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0, "disable delta-compression for usercommnds" ); cl_idealpitchscale = Cvar_Get( "cl_idealpitchscale", "0.8", 0, "how much to look up/down slopes and stairs when not using freelook" ); @@ -1621,7 +1617,7 @@ void CL_InitLocal( void ) // userinfo Cvar_Get( "password", "", CVAR_USERINFO, "player password" ); name = Cvar_Get( "name", Sys_GetCurrentUser(), CVAR_USERINFO|CVAR_ARCHIVE|CVAR_PRINTABLEONLY, "player name" ); - model = Cvar_Get( "model", "player", CVAR_USERINFO|CVAR_ARCHIVE, "player model ('player' it's a single player model)" ); + model = Cvar_Get( "model", "player", CVAR_USERINFO|CVAR_ARCHIVE, "player model ('player' is a singleplayer model)" ); topcolor = Cvar_Get( "topcolor", "0", CVAR_USERINFO|CVAR_ARCHIVE, "player top color" ); bottomcolor = Cvar_Get( "bottomcolor", "0", CVAR_USERINFO|CVAR_ARCHIVE, "player bottom color" ); rate = Cvar_Get( "rate", "25000", CVAR_USERINFO|CVAR_ARCHIVE, "player network rate" ); @@ -1668,11 +1664,11 @@ void CL_InitLocal( void ) Cmd_AddCommand ("physinfo", CL_Physinfo_f, "print current client physinfo" ); Cmd_AddCommand ("disconnect", CL_Disconnect_f, "disconnect from server" ); Cmd_AddCommand ("record", CL_Record_f, "record a demo" ); - Cmd_AddCommand ("playdemo", CL_PlayDemo_f, "playing a demo" ); + Cmd_AddCommand ("playdemo", CL_PlayDemo_f, "play a demo" ); Cmd_AddCommand ("killdemo", CL_DeleteDemo_f, "delete a specified demo file and demoshot" ); Cmd_AddCommand ("startdemos", CL_StartDemos_f, "start playing back the selected demos sequentially" ); Cmd_AddCommand ("demos", CL_Demos_f, "restart looping demos defined by the last startdemos command" ); - Cmd_AddCommand ("movie", CL_PlayVideo_f, "playing a movie" ); + Cmd_AddCommand ("movie", CL_PlayVideo_f, "play a movie" ); Cmd_AddCommand ("stop", CL_Stop_f, "stop playing or recording a demo" ); Cmd_AddCommand ("info", NULL, "collect info about local servers with specified protocol" ); Cmd_AddCommand ("escape", CL_Escape_f, "escape from game to menu" ); diff --git a/engine/client/cl_pmove.c b/engine/client/cl_pmove.c index ddab9808..224cfdfb 100644 --- a/engine/client/cl_pmove.c +++ b/engine/client/cl_pmove.c @@ -152,12 +152,11 @@ void CL_AddLinksToPmove( void ) if( !check || check == &clgame.entities[0] ) continue; - if( clgame.pmove->numvisent < MAX_PHYSENTS ) - { - pe = &clgame.pmove->visents[clgame.pmove->numvisent]; - if( CL_CopyEntityToPhysEnt( pe, check )) - clgame.pmove->numvisent++; - } + if( check->curstate.solid == SOLID_TRIGGER ) + continue; + + if( ( check->curstate.owner > 0) && cl.playernum == check->curstate.owner -1 ) + continue; // players will be added later if( check->player ) continue; @@ -167,6 +166,16 @@ void CL_AddLinksToPmove( void ) continue; solid = check->curstate.solid; + + if( solid == SOLID_NOT && ( check->curstate.skin == CONTENTS_NONE || check->curstate.modelindex == 0 )) + continue; + + if( clgame.pmove->numvisent < MAX_PHYSENTS ) + { + pe = &clgame.pmove->visents[clgame.pmove->numvisent]; + if( CL_CopyEntityToPhysEnt( pe, check )) + clgame.pmove->numvisent++; + } if( solid == SOLID_BSP || solid == SOLID_BBOX || solid == SOLID_SLIDEBOX || solid == SOLID_CUSTOM ) { @@ -711,24 +720,20 @@ CL_RunUsercmd Runs prediction code for user cmd ================= */ -void CL_RunUsercmd(local_state_t * from, local_state_t * to, usercmd_t * u, qboolean runfuncs, double * pfElapsed, unsigned int random_seed) +void CL_RunUsercmd( local_state_t *from, local_state_t *to, usercmd_t *u, qboolean runfuncs, double *pfElapsed, unsigned int random_seed ) { - usercmd_t cmd; - entity_state_t * fs; - entity_state_t * ts; - clientdata_t * fcd; - clientdata_t * tcd; - playermove_t *pmove = clgame.pmove; + usercmd_t cmd; + entity_state_t *fs, *ts; + clientdata_t *fcd, *tcd; + playermove_t *pmove = clgame.pmove; + local_state_t temp; + usercmd_t split; - while (u->msec > 50) + while( u->msec > 50 ) { - local_state_t temp; - usercmd_t split; - split = *u; - split.msec /= 2.0; - CL_RunUsercmd(from, &temp, &split, runfuncs, pfElapsed, random_seed); - + split.msec /= 2; + CL_RunUsercmd( from, &temp, &split, runfuncs, pfElapsed, random_seed ); from = &temp; u = &split; } @@ -841,12 +846,12 @@ Sets cl.predicted_origin and cl.predicted_angles */ void CL_PredictMovement( void ) { - double time; + double time; int frame = 1; int ack, outgoing_command; int current_command; int current_command_mod; - local_state_t *from, *to; + local_state_t *from = NULL, *to = NULL; if( cls.state != ca_active ) return; @@ -883,6 +888,9 @@ void CL_PredictMovement( void ) time = cl.frame.time; + CL_SetSolidEntities(); + CL_SetSolidPlayers( cl.playernum ); + while( 1 ) { // we've run too far forward @@ -903,14 +911,17 @@ void CL_PredictMovement( void ) cl.runfuncs[current_command_mod], &time, cls.netchan.incoming_acknowledged + frame ); - cl.runfuncs[current_command_mod] = FALSE; + cl.runfuncs[current_command_mod] = false; from = to; frame++; } - VectorCopy( to->playerstate.origin, cl.predicted_origin ); - VectorCopy( to->client.velocity, cl.predicted_velocity ); - VectorCopy( to->client.view_ofs, cl.predicted_viewofs ); - VectorCopy( to->client.punchangle, cl.predicted_punchangle ); + if( to ) + { + VectorCopy( to->playerstate.origin, cl.predicted_origin ); + VectorCopy( to->client.velocity, cl.predicted_velocity ); + VectorCopy( to->client.view_ofs, cl.predicted_viewofs ); + VectorCopy( to->client.punchangle, cl.predicted_punchangle ); + } } \ No newline at end of file diff --git a/engine/client/client.h b/engine/client/client.h index 94eb8a4c..a9f16fb8 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -241,6 +241,17 @@ typedef struct byte gammaTable[256]; } client_draw_t; +typedef struct cl_predicted_player_s +{ + int flags; + int movetype; + int solid; + int usehull; + qboolean active; + vec3_t origin; // predicted origin + vec3_t angles; +} predicted_player_t; + typedef struct { int gl_texturenum; // this is a real texnum @@ -431,6 +442,8 @@ typedef struct int next_client_entities; // next client_entity to use entity_state_t *packet_entities; // [num_client_entities] + predicted_player_t predicted_players[MAX_CLIENTS]; + scrshot_t scrshot_request; // request for screen shot scrshot_t scrshot_action; // in-action const float *envshot_vieworg; // envshot position diff --git a/engine/client/gl_image.c b/engine/client/gl_image.c index 4f59e815..9c8bc276 100644 --- a/engine/client/gl_image.c +++ b/engine/client/gl_image.c @@ -1228,6 +1228,8 @@ static void GL_UploadTexture( rgbdata_t *pic, gltexture_t *tex, qboolean subImag int texsize = 0, img_flags = 0, samples; GLint dataType = GL_UNSIGNED_BYTE; + ASSERT( pic != NULL && tex != NULL ); + if( pic->flags & IMAGE_DDS_FORMAT ) { // special case for DDS textures @@ -1235,8 +1237,6 @@ static void GL_UploadTexture( rgbdata_t *pic, gltexture_t *tex, qboolean subImag return; } - ASSERT( pic != NULL && tex != NULL ); - tex->srcWidth = tex->width = pic->width; tex->srcHeight = tex->height = pic->height; s = tex->srcWidth * tex->srcHeight; diff --git a/engine/client/s_main.c b/engine/client/s_main.c index 8b228b44..e42a055b 100644 --- a/engine/client/s_main.c +++ b/engine/client/s_main.c @@ -1652,7 +1652,7 @@ void S_Say_f( void ) { if( Cmd_Argc() == 1 ) { - Msg( "Usage: speak \n" ); return; } @@ -1829,10 +1829,15 @@ void S_Shutdown( void ) if( !dma.initialized ) return; Cmd_RemoveCommand( "play" ); + Cmd_RemoveCommand( "playvol" ); Cmd_RemoveCommand( "stopsound" ); Cmd_RemoveCommand( "music" ); Cmd_RemoveCommand( "soundlist" ); Cmd_RemoveCommand( "s_info" ); + Cmd_RemoveCommand( "+voicerecord" ); + Cmd_RemoveCommand( "-voicerecord" ); + Cmd_RemoveCommand( "spk" ); + Cmd_RemoveCommand( "speak" ); S_StopAllSounds (); S_FreeSounds (); diff --git a/engine/common/common.h b/engine/common/common.h index d40c66d1..d6762ef2 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -351,6 +351,7 @@ extern sysinfo_t SI; // void FS_Init( void ); void FS_Path( void ); +void FS_Rescan( void ); void FS_Shutdown( void ); void FS_ClearSearchPath( void ); void FS_AllowDirectPaths( qboolean enable ); diff --git a/engine/common/con_utils.c b/engine/common/con_utils.c index 5bf9219a..4d15b768 100644 --- a/engine/common/con_utils.c +++ b/engine/common/con_utils.c @@ -27,7 +27,7 @@ void DBG_AssertFunction( qboolean fExpr, const char* szExpr, const char* szFile, if( fExpr ) return; if( szMessage != NULL ) - MsgDev( at_error, "ASSERT FAILED:\n %s \n(%s@%d)\n%s", szExpr, szFile, szLine, szMessage ); + MsgDev( at_error, "ASSERT FAILED:\n %s \n(%s@%d)\n%s\n", szExpr, szFile, szLine, szMessage ); else MsgDev( at_error, "ASSERT FAILED:\n %s \n(%s@%d)\n", szExpr, szFile, szLine ); } #endif // DEBUG diff --git a/engine/common/console.c b/engine/common/console.c index 6bbfba19..e4f45245 100644 --- a/engine/common/console.c +++ b/engine/common/console.c @@ -311,13 +311,9 @@ void Con_CheckResize( void ) int charWidth = 8; if( con.curFont && con.curFont->hFontTexture ) - charWidth = con.curFont->charWidths['M']; + charWidth = con.curFont->charWidths['M'] - 1; - width = ( scr_width->integer / charWidth ) - 2; - - // NOTE: Con_CheckResize is totally wrong :-( - // g-cont. i've just used fixed width on all resolutions - width = 90; + width = ( scr_width->integer / charWidth ); if( width == con.linewidth ) return; @@ -759,10 +755,12 @@ void Con_Print( const char *txt ) if( txt[l] <= ' ') break; } - +#if 0 + // g-cont. experiment from SDLash3D // word wrap if( l != con.linewidth && ( con.x + l >= con.linewidth )) Con_Linefeed(); +#endif txt++; switch( c ) @@ -1007,6 +1005,7 @@ void Con_CompleteCommand( field_t *field ) { field_t temp; string filename; + qboolean nextcmd; autocomplete_list_t *list; int i; @@ -1016,6 +1015,8 @@ void Con_CompleteCommand( field_t *field ) // only look at the first token for completion purposes Cmd_TokenizeString( con.completionField->buffer ); + nextcmd = ( con.completionField->buffer[Q_strlen( con.completionField->buffer ) - 1] == ' ' ) ? true : false; + con.completionString = Cmd_Argv( 0 ); // skip backslash @@ -1046,7 +1047,7 @@ void Con_CompleteCommand( field_t *field ) Q_memcpy( &temp, con.completionField, sizeof( field_t )); - if( Cmd_Argc() == 2 ) + if(( Cmd_Argc() == 2 ) || (( Cmd_Argc() == 1 ) && nextcmd )) { qboolean result = false; diff --git a/engine/common/net_buffer.c b/engine/common/net_buffer.c index 15b736f3..883797be 100644 --- a/engine/common/net_buffer.c +++ b/engine/common/net_buffer.c @@ -48,13 +48,13 @@ void BF_InitMasks( void ) { endbit = startbit + nBitsLeft; - BitWriteMasks[startbit][nBitsLeft] = BIT( startbit ) - 1; - if( endbit < 32 ) BitWriteMasks[startbit][nBitsLeft] |= ~(BIT( endbit ) - 1 ); + BitWriteMasks[startbit][nBitsLeft] = (uint)BIT( startbit ) - 1; + if( endbit < 32 ) BitWriteMasks[startbit][nBitsLeft] |= ~((uint)BIT( endbit ) - 1 ); } } for( maskBit = 0; maskBit < 32; maskBit++ ) - ExtraMasks[maskBit] = BIT( maskBit ) - 1; + ExtraMasks[maskBit] = (uint)BIT( maskBit ) - 1; } void BF_InitExt( sizebuf_t *bf, const char *pDebugName, void *pData, int nBytes, int nMaxBits ) @@ -255,13 +255,13 @@ void BF_WriteBitAngle( sizebuf_t *bf, float fAngle, int numbits ) int d; // clamp the angle before receiving - if( fAngle > 360.0f ) fAngle -= 360.0f; - else if( fAngle < 0 ) fAngle += 360.0f; + fAngle = fmod( fAngle, 360.0f ); + if( fAngle < 0 ) fAngle += 360.0f; shift = ( 1 << numbits ); mask = shift - 1; - d = (int)( fAngle * shift ) / 360; + d = (int)(( fAngle * shift ) / 360.0f ); d &= mask; BF_WriteUBitLong( bf, (uint)d, numbits ); diff --git a/engine/common/net_encode.c b/engine/common/net_encode.c index a2f3d5e1..855259f1 100644 --- a/engine/common/net_encode.c +++ b/engine/common/net_encode.c @@ -885,63 +885,63 @@ int Delta_ClampIntegerField( int iValue, qboolean bSigned, int bits ) iValue = bound( 0, (byte)iValue, 1 ); break; case 2: - if( bSigned ) iValue = bound( -1, (short)iValue, 2 ); + if( bSigned ) iValue = bound( -2, (short)iValue, 1 ); else iValue = bound( 0, (word)iValue, 3 ); break; case 3: - if( bSigned ) iValue = bound( -3, (short)iValue, 4 ); + if( bSigned ) iValue = bound( -4, (short)iValue, 3 ); else iValue = bound( 0, (word)iValue, 7 ); break; case 4: - if( bSigned ) iValue = bound( -7, (short)iValue, 8 ); + if( bSigned ) iValue = bound( -8, (short)iValue, 7 ); else iValue = bound( 0, (word)iValue, 15 ); break; case 5: - if( bSigned ) iValue = bound( -15, (short)iValue, 16 ); + if( bSigned ) iValue = bound( -16, (short)iValue, 15 ); else iValue = bound( 0, (word)iValue, 31 ); break; case 6: - if( bSigned ) iValue = bound( -31, (short)iValue, 32 ); + if( bSigned ) iValue = bound( -32, (short)iValue, 31 ); else iValue = bound( 0, (word)iValue, 63 ); break; case 7: - if( bSigned ) iValue = bound( -63, (short)iValue, 64 ); + if( bSigned ) iValue = bound( -64, (short)iValue, 63 ); else iValue = bound( 0, (word)iValue, 127 ); break; case 8: - if( bSigned ) iValue = bound( -127, (short)iValue, 128 ); + if( bSigned ) iValue = bound( -128, (short)iValue, 127 ); else iValue = bound( 0, (word)iValue, 255 ); break; case 9: - if( bSigned ) iValue = bound( -255, (short)iValue, 256 ); + if( bSigned ) iValue = bound( -256, (short)iValue, 255 ); else iValue = bound( 0, (word)iValue, 511 ); break; case 10: - if( bSigned ) iValue = bound( -511, (short)iValue, 512 ); + if( bSigned ) iValue = bound( -512, (short)iValue, 511 ); else iValue = bound( 0, (word)iValue, 1023 ); break; case 11: - if( bSigned ) iValue = bound( -1023, (short)iValue, 1024 ); + if( bSigned ) iValue = bound( -1024, (short)iValue, 1023 ); else iValue = bound( 0, (word)iValue, 2047 ); break; case 12: - if( bSigned ) iValue = bound( -2047, (short)iValue, 2048 ); + if( bSigned ) iValue = bound( -2048, (short)iValue, 2047 ); else iValue = bound( 0, (word)iValue, 4095 ); break; case 13: - if( bSigned ) iValue = bound( -4095, (short)iValue, 4096 ); + if( bSigned ) iValue = bound( -4096, (short)iValue, 4095 ); else iValue = bound( 0, (word)iValue, 8191 ); break; case 14: - if( bSigned ) iValue = bound( -8191, (short)iValue, 8192 ); + if( bSigned ) iValue = bound( -8192, (short)iValue, 8191 ); else iValue = bound( 0, (word)iValue, 16383 ); break; case 15: - if( bSigned ) iValue = bound( -16383, (short)iValue, 16384 ); + if( bSigned ) iValue = bound( -16384, (short)iValue, 16383 ); else iValue = bound( 0, (word)iValue, 32767 ); break; case 16: - if( bSigned ) iValue = bound( -32767, (short)iValue, 32768 ); + if( bSigned ) iValue = bound( -32768, (short)iValue, 32767 ); else iValue = bound( 0, (word)iValue, 65535 ); break; } @@ -988,8 +988,8 @@ qboolean Delta_CompareField( delta_t *pField, void *from, void *to, float timeba fromF = Delta_ClampIntegerField( fromF, bSigned, pField->bits ); toF = Delta_ClampIntegerField( toF, bSigned, pField->bits ); - fromF *= pField->multiplier; - toF *= pField->multiplier; + if( pField->multiplier != 1.0f ) fromF *= pField->multiplier; + if( pField->multiplier != 1.0f ) toF *= pField->multiplier; } else if( pField->flags & DT_SHORT ) { @@ -1006,8 +1006,8 @@ qboolean Delta_CompareField( delta_t *pField, void *from, void *to, float timeba fromF = Delta_ClampIntegerField( fromF, bSigned, pField->bits ); toF = Delta_ClampIntegerField( toF, bSigned, pField->bits ); - fromF *= pField->multiplier; - toF *= pField->multiplier; + if( pField->multiplier != 1.0f ) fromF *= pField->multiplier; + if( pField->multiplier != 1.0f ) toF *= pField->multiplier; } else if( pField->flags & DT_INTEGER ) { @@ -1024,8 +1024,8 @@ qboolean Delta_CompareField( delta_t *pField, void *from, void *to, float timeba fromF = Delta_ClampIntegerField( fromF, bSigned, pField->bits ); toF = Delta_ClampIntegerField( toF, bSigned, pField->bits ); - fromF *= pField->multiplier; - toF *= pField->multiplier; + if( pField->multiplier != 1.0f ) fromF *= pField->multiplier; + if( pField->multiplier != 1.0f ) toF *= pField->multiplier; } else if( pField->flags & ( DT_FLOAT|DT_ANGLE )) { @@ -1044,10 +1044,22 @@ qboolean Delta_CompareField( delta_t *pField, void *from, void *to, float timeba } else if( pField->flags & DT_TIMEWINDOW_BIG ) { - val_a = (*(float *)((byte *)from + pField->offset )) * pField->multiplier; - val_b = (*(float *)((byte *)to + pField->offset )) * pField->multiplier; - val_a = (timebase * pField->multiplier) - val_a; - val_b = (timebase * pField->multiplier) - val_b; + val_a = (*(float *)((byte *)from + pField->offset )); + val_b = (*(float *)((byte *)to + pField->offset )); + + if( pField->multiplier != 1.0f ) + { + val_a *= pField->multiplier; + val_b *= pField->multiplier; + val_a = (timebase * pField->multiplier) - val_a; + val_b = (timebase * pField->multiplier) - val_b; + } + else + { + val_a = timebase - val_a; + val_b = timebase - val_b; + } + fromF = *((int *)&val_a); toF = *((int *)&val_b); } @@ -1091,21 +1103,21 @@ qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, void *to { iValue = *(byte *)((byte *)to + pField->offset ); iValue = Delta_ClampIntegerField( iValue, bSigned, pField->bits ); - iValue *= pField->multiplier; + if( pField->multiplier != 1.0f ) iValue *= pField->multiplier; BF_WriteBitLong( msg, iValue, pField->bits, bSigned ); } else if( pField->flags & DT_SHORT ) { iValue = *(word *)((byte *)to + pField->offset ); iValue = Delta_ClampIntegerField( iValue, bSigned, pField->bits ); - iValue *= pField->multiplier; + if( pField->multiplier != 1.0f ) iValue *= pField->multiplier; BF_WriteBitLong( msg, iValue, pField->bits, bSigned ); } else if( pField->flags & DT_INTEGER ) { iValue = *(uint *)((byte *)to + pField->offset ); iValue = Delta_ClampIntegerField( iValue, bSigned, pField->bits ); - iValue *= pField->multiplier; + if( pField->multiplier != 1.0f ) iValue *= pField->multiplier; BF_WriteBitLong( msg, iValue, pField->bits, bSigned ); } else if( pField->flags & DT_FLOAT ) @@ -1172,7 +1184,7 @@ qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, void *to, if( bChanged ) { iValue = BF_ReadBitLong( msg, pField->bits, bSigned ); - iValue /= pField->multiplier; + if( pField->multiplier != 1.0f ) iValue /= pField->multiplier; } else { @@ -1185,7 +1197,7 @@ qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, void *to, if( bChanged ) { iValue = BF_ReadBitLong( msg, pField->bits, bSigned ); - iValue /= pField->multiplier; + if( pField->multiplier != 1.0f ) iValue /= pField->multiplier; } else { @@ -1198,7 +1210,7 @@ qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, void *to, if( bChanged ) { iValue = BF_ReadBitLong( msg, pField->bits, bSigned ); - iValue /= pField->multiplier; + if( pField->multiplier != 1.0f ) iValue /= pField->multiplier; } else { @@ -1251,7 +1263,7 @@ qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, void *to, if( bChanged ) { iValue = BF_ReadBitLong( msg, pField->bits, bSigned ); - flValue = (float)(iValue * ( 1.0f / pField->multiplier )); + flValue = (float)((int)iValue) * ( 1.0f / pField->multiplier ); flTime = timebase + flValue; } else diff --git a/engine/common/netchan.h b/engine/common/netchan.h index f2b588a8..e2288db7 100644 --- a/engine/common/netchan.h +++ b/engine/common/netchan.h @@ -59,7 +59,7 @@ GNU General Public License for more details. // bytes will be stripped by the networking channel layer #define NET_MAX_MESSAGE PAD_NUMBER(( NET_MAX_PAYLOAD + HEADER_BYTES ), 16 ) -#define MASTERSERVER_ADR "hl1master.steampowered.com:27010" +#define MASTERSERVER_ADR "celest.in:27010" #define PORT_MASTER 27010 #define PORT_CLIENT 27005 #define PORT_SERVER 27015 diff --git a/engine/common/pm_trace.c b/engine/common/pm_trace.c index c44bb43f..5a9d7e99 100644 --- a/engine/common/pm_trace.c +++ b/engine/common/pm_trace.c @@ -297,7 +297,7 @@ pmtrace_t PM_PlayerTraceExt( playermove_t *pmove, vec3_t start, vec3_t end, int vec3_t temp, mins, maxs; int i, j, hullcount; qboolean rotated, transform_bbox; - hull_t *hull; + hull_t *hull = NULL; Q_memset( &trace_total, 0, sizeof( trace_total )); VectorCopy( end, trace_total.endpos ); @@ -503,9 +503,9 @@ int PM_TestPlayerPosition( playermove_t *pmove, vec3_t pos, pmtrace_t *ptrace, p { int i, j, hullcount; vec3_t pos_l, offset; + hull_t *hull = NULL; vec3_t mins, maxs; pmtrace_t trace; - hull_t *hull; physent_t *pe; trace = PM_PlayerTraceExt( pmove, pmove->origin, pmove->origin, 0, pmove->numphysent, pmove->physents, -1, pmFilter ); diff --git a/engine/custom.h b/engine/custom.h index a4b6d974..d7093818 100644 --- a/engine/custom.h +++ b/engine/custom.h @@ -50,6 +50,8 @@ typedef struct resourceinfo_s // or is it a server startup resource. #define RES_REQUESTED (1<<3) // Already requested a download of this one #define RES_PRECACHED (1<<4) // Already precached +#define RES_ALWAYS (1<<5) // Download always even if available on client +#define RES_CHECKFILE (1<<7) // Check file on client typedef struct resource_s { diff --git a/engine/server/server.h b/engine/server/server.h index 208454ca..a1e925a7 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -517,6 +517,7 @@ void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd, int random_seed ); qboolean SV_IsPlayerIndex( int idx ); void SV_InitClientMove( void ); void SV_UpdateServerInfo( void ); +void SV_EndRedirect( void ); // // sv_cmds.c diff --git a/engine/server/sv_client.c b/engine/server/sv_client.c index 04af965e..53aa2860 100644 --- a/engine/server/sv_client.c +++ b/engine/server/sv_client.c @@ -122,7 +122,7 @@ void SV_DirectConnect( netadr_t from ) // quick reject for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) { - if( cl->state == cs_free ) + if( cl->state == cs_free || cl->state == cs_zombie ) continue; if( NET_CompareBaseAdr( from, cl->netchan.remote_address ) && ( cl->netchan.qport == qport || from.port == cl->netchan.remote_address.port )) @@ -169,7 +169,7 @@ void SV_DirectConnect( netadr_t from ) // if there is already a slot for this ip, reuse it for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) { - if( cl->state == cs_free ) + if( cl->state == cs_free || cl->state == cs_zombie ) continue; if( NET_CompareBaseAdr( from, cl->netchan.remote_address ) && ( cl->netchan.qport == qport || from.port == cl->netchan.remote_address.port )) @@ -438,9 +438,17 @@ void SV_DropClient( sv_client_t *drop ) Mem_Free( drop->frames ); // fakeclients doesn't have frames drop->frames = NULL; + if( NET_CompareBaseAdr( drop->netchan.remote_address, host.rd.address ) ) + SV_EndRedirect(); + // throw away any residual garbage in the channel. Netchan_Clear( &drop->netchan ); + // clean client data on disconnect + Q_memset( drop->userinfo, 0, MAX_INFO_STRING ); + Q_memset( drop->physinfo, 0, MAX_INFO_STRING ); + drop->edict->v.frags = 0; + // send notification to all other clients SV_FullClientUpdate( drop, &sv.reliable_datagram ); @@ -502,7 +510,8 @@ void SV_FlushRedirect( netadr_t adr, int dest, char *buf ) void SV_EndRedirect( void ) { - host.rd.flush( host.rd.address, host.rd.target, host.rd.buffer ); + if( host.rd.flush ) + host.rd.flush( host.rd.address, host.rd.target, host.rd.buffer ); host.rd.target = 0; host.rd.buffer = NULL; @@ -1985,10 +1994,9 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) char *args; char *c, buf[MAX_SYSPATH]; int len = sizeof( buf ); - dword challenge; + uint challenge; int index, count = 0; - char query[512]; - word port; + char query[512], ostype = 'w'; BF_Clear( msg ); BF_ReadLong( msg );// skip the -1 marker @@ -2007,12 +2015,9 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) else if( !Q_strcmp( c, "connect" )) SV_DirectConnect( from ); else if( !Q_strcmp( c, "rcon" )) SV_RemoteCommand( from, msg ); else if( !Q_strcmp( c, "netinfo" )) SV_BuildNetAnswer( from ); - else if( msg->pData[0] == 0xFF && msg->pData[1] == 0xFF && msg->pData[2] == 0xFF && msg->pData[3] == 0xFF && msg->pData[4] == 0x4E && msg->pData[5] == 0x0A ) + else if( msg->pData[0] == 0xFF && msg->pData[1] == 0xFF && msg->pData[2] == 0xFF && msg->pData[3] == 0xFF && msg->pData[4] == 0x73 && msg->pData[5] == 0x0A ) { - challenge = *(dword *)&msg->pData[6]; - - port = Cvar_Get( "ip_hostport", "0", CVAR_INIT, "network server port" )->integer; - if( !port ) port = Cvar_Get( "port", va( "%i", PORT_SERVER ), CVAR_INIT, "network default port" )->integer; + Q_memcpy(&challenge, &msg->pData[6], sizeof(int)); for( index = 0; index < sv_maxclients->integer; index++ ) { @@ -2021,8 +2026,32 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) } Q_snprintf( query, sizeof( query ), - "0\n\\protocol\\7\\challenge\\%ld\\players\\%d\\max\\%d\\bots\\0\\gamedir\\%s_xash\\map\\%s\\password\\0\\os\\w\\lan\\0\\region\\255\\gameport\\%d\\specport\\27015\\dedicated\\1\\appid\\70\\type\\d\\secure\\0\\version\\1.1.2.1\\product\\valve\n", - challenge, count, sv_maxclients->integer, GI->gamefolder, sv.name, port ); + "0\n" + "\\protocol\\%d" // protocol version + "\\challenge\\%u" // challenge number that got after FF FF FF FF 73 0A + "\\players\\%d" // current player number + "\\max\\%d" // max_players + "\\bots\\0" // bot number? + "\\gamedir\\%s" // gamedir. _xash appended, because Xash3D is not compatible with GS in multiplayer + "\\map\\%s" // current map + "\\type\\d" // server type + "\\password\\0" // is password set + "\\os\\%c" // server OS? + "\\secure\\0" // server anti-cheat? VAC? + "\\lan\\0" // is LAN server? + "\\version\\%f" // server version + "\\region\\255" // server region + "\\product\\%s\n", // product? Where is the difference with gamedir? + PROTOCOL_VERSION, + challenge, + count, + sv_maxclients->integer, + GI->gamefolder, + sv.name, + ostype, + XASH_VERSION, + GI->gamefolder + ); NET_SendPacket( NS_SERVER, Q_strlen( query ), query, from ); } diff --git a/engine/server/sv_cmds.c b/engine/server/sv_cmds.c index ff40daf4..ea4a2a7c 100644 --- a/engine/server/sv_cmds.c +++ b/engine/server/sv_cmds.c @@ -109,7 +109,7 @@ qboolean SV_SetPlayer( void ) sv_client_t *cl; int i, idnum; - if( !svs.clients ) + if( !svs.clients || sv.background ) { Msg( "^3no server running.\n" ); return false; @@ -418,7 +418,7 @@ void SV_DeleteSave_f( void ) { if( Cmd_Argc() != 2 ) { - Msg( "Usage: delsave \n" ); + Msg( "Usage: killsave \n" ); return; } @@ -599,18 +599,18 @@ void SV_Kick_f( void ) { if( Cmd_Argc() != 2 ) { - Msg( "Usage: kick \n" ); - return; - } - - if( !svs.clients || sv.background ) - { - Msg( "^3no server running.\n" ); + Msg( "Usage: kick | \n" ); return; } if( !SV_SetPlayer( )) return; + if( NET_IsLocalAddress( svs.currentPlayer->netchan.remote_address )) + { + Msg( "The local player cannot be kicked!\n" ); + return; + } + SV_BroadcastPrintf( PRINT_HIGH, "%s was kicked\n", svs.currentPlayer->name ); SV_ClientPrintf( svs.currentPlayer, PRINT_HIGH, "You were kicked from the game\n" ); SV_DropClient( svs.currentPlayer ); @@ -626,8 +626,7 @@ SV_Kill_f */ void SV_Kill_f( void ) { - if( !SV_SetPlayer() || sv.background ) - return; + if( !SV_SetPlayer( )) return; if( !svs.currentPlayer || !SV_IsValidEdict( svs.currentPlayer->edict )) return; diff --git a/engine/server/sv_frame.c b/engine/server/sv_frame.c index e2b1ce20..6d404d82 100644 --- a/engine/server/sv_frame.c +++ b/engine/server/sv_frame.c @@ -507,7 +507,7 @@ void SV_WriteClientdataToMessage( sv_client_t *cl, sizebuf_t *msg ) { Q_memset( &nullwd, 0, sizeof( nullwd )); - for( i = 0; i < 32; i++ ) + for( i = 0; i < 64; i++ ) { if( cl->delta_sequence == -1 ) from_wd = &nullwd; else from_wd = &cl->frames[cl->delta_sequence & SV_UPDATE_MASK].weapondata[i]; diff --git a/engine/server/sv_game.c b/engine/server/sv_game.c index 0524487f..38dfc6f8 100644 --- a/engine/server/sv_game.c +++ b/engine/server/sv_game.c @@ -866,6 +866,12 @@ void SV_FreeEdict( edict_t *pEdict ) pEdict->v.takedamage = 0; pEdict->v.modelindex = 0; pEdict->v.nextthink = -1; + pEdict->v.colormap = 0; + pEdict->v.frame = 0; + pEdict->v.scale = 0; + pEdict->v.gravity = 0; + VectorClear( pEdict->v.angles ); + VectorClear( pEdict->v.origin ); pEdict->free = true; } diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 7890126b..3f55bc23 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -583,7 +583,7 @@ void Master_Add( void ) if( !NET_StringToAdr( MASTERSERVER_ADR, &adr )) MsgDev( D_INFO, "Can't resolve adr: %s\n", MASTERSERVER_ADR ); - NET_SendPacket( NS_SERVER, 2, "\x4D\xFF", adr ); + NET_SendPacket( NS_SERVER, 1, "q", adr ); } /* @@ -620,6 +620,14 @@ Informs all masters that this server is going down */ void Master_Shutdown( void ) { + netadr_t adr; + + NET_Config( true ); // allow remote + + if( !NET_StringToAdr( MASTERSERVER_ADR, &adr )) + MsgDev( D_INFO, "Can't resolve addr: %s\n", MASTERSERVER_ADR ); + + NET_SendPacket( NS_SERVER, 2, "\x62\x0A", adr ); } //============================================================================ @@ -785,10 +793,17 @@ void SV_Shutdown( qboolean reconnect ) // already freed if( !SV_Active( )) return; - if( host.type == HOST_DEDICATED ) MsgDev( D_INFO, "SV_Shutdown: %s\n", host.finalmsg ); - if( svs.clients ) SV_FinalMessage( host.finalmsg, reconnect ); + // rcon will be disconnected + SV_EndRedirect(); - Master_Shutdown(); + if( host.type == HOST_DEDICATED ) + MsgDev( D_INFO, "SV_Shutdown: %s\n", host.finalmsg ); + + if( svs.clients ) + SV_FinalMessage( host.finalmsg, reconnect ); + + if( public_server->integer && sv_maxclients->integer != 1 ) + Master_Shutdown(); if( !reconnect ) SV_UnloadProgs (); else SV_DeactivateServer (); diff --git a/engine/server/sv_pmove.c b/engine/server/sv_pmove.c index 4d2abad4..005e3cfc 100644 --- a/engine/server/sv_pmove.c +++ b/engine/server/sv_pmove.c @@ -67,7 +67,8 @@ qboolean SV_CopyEdictToPhysEnt( physent_t *pe, edict_t *ed ) if( ed->v.flags & ( FL_CLIENT|FL_FAKECLIENT )) { // client or bot - SV_GetTrueOrigin( svs.currentPlayer, (pe->info - 1), pe->origin ); + if( svs.currentPlayer ) + SV_GetTrueOrigin( svs.currentPlayer, (pe->info - 1), pe->origin ); Q_strncpy( pe->name, "player", sizeof( pe->name )); pe->player = pe->info; } @@ -141,7 +142,7 @@ qboolean SV_CopyEdictToPhysEnt( physent_t *pe, edict_t *ed ) void SV_GetTrueOrigin( sv_client_t *cl, int edictnum, vec3_t origin ) { - if( !cl->local_weapons || !cl->lag_compensation || !sv_unlag->integer ) + if( !cl->lag_compensation || !sv_unlag->integer ) return; // don't allow unlag in singleplayer @@ -158,7 +159,7 @@ void SV_GetTrueOrigin( sv_client_t *cl, int edictnum, vec3_t origin ) void SV_GetTrueMinMax( sv_client_t *cl, int edictnum, vec3_t mins, vec3_t maxs ) { - if( !cl->local_weapons || !cl->lag_compensation || !sv_unlag->integer ) + if( !cl->lag_compensation || !sv_unlag->integer ) return; // don't allow unlag in singleplayer @@ -235,7 +236,8 @@ void SV_AddLinksToPmove( areanode_t *node, const vec3_t pmove_mins, const vec3_t if( check->v.flags & FL_CLIENT ) { // trying to get interpolated values - SV_GetTrueMinMax( svs.currentPlayer, ( NUM_FOR_EDICT( check ) - 1), mins, maxs ); + if( svs.currentPlayer ) + SV_GetTrueMinMax( svs.currentPlayer, ( NUM_FOR_EDICT( check ) - 1), mins, maxs ); } if( !BoundsIntersect( pmove_mins, pmove_maxs, mins, maxs )) @@ -819,7 +821,7 @@ void SV_SetupMoveInterpolant( sv_client_t *cl ) return; // unlag disabled for current client - if( !cl->local_weapons || !cl->lag_compensation ) + if( !cl->lag_compensation ) return; has_update = true; @@ -976,7 +978,7 @@ void SV_RestoreMoveInterpolant( sv_client_t *cl ) return; // unlag disabled for current client - if( !cl->local_weapons || !cl->lag_compensation ) + if( !cl->lag_compensation ) return; for( i = 0, check = svs.clients; i < sv_maxclients->integer; i++, check++ ) diff --git a/mainui/basemenu.cpp b/mainui/basemenu.cpp index 15e13190..1b7130cd 100644 --- a/mainui/basemenu.cpp +++ b/mainui/basemenu.cpp @@ -1250,6 +1250,9 @@ void UI_AddServerToList( netadr_t adr, const char *info ) if( uiStatic.numServers == UI_MAX_SERVERS ) return; // full + if( stricmp( gMenu.m_gameinfo.gamefolder, Info_ValueForKey( info, "gamedir" ))) + return; + // ignore if duplicated for( i = 0; i < uiStatic.numServers; i++ ) { diff --git a/mainui/menu_internetgames.cpp b/mainui/menu_internetgames.cpp index 29d06147..d88bb7c7 100644 --- a/mainui/menu_internetgames.cpp +++ b/mainui/menu_internetgames.cpp @@ -124,12 +124,7 @@ static void UI_InternetGames_GetGamesList( void ) { if( i >= UI_MAX_SERVERS ) break; info = uiStatic.serverNames[i]; -#if 1 - // NOTE: Xash3D is support hot switching between games in multiplayer - // but this feature not detail tested and may be bugly - if( stricmp( gMenu.m_gameinfo.gamefolder, Info_ValueForKey( info, "gamedir" ))) - continue; // filter by game -#endif + StringConcat( uiInternetGames.gameDescription[i], Info_ValueForKey( info, "host" ), GAME_LENGTH ); StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, GAME_LENGTH ); StringConcat( uiInternetGames.gameDescription[i], Info_ValueForKey( info, "map" ), MAPNAME_LENGTH );