From d87d09b959996e2d64f9fb0e16cd1837ed3520a0 Mon Sep 17 00:00:00 2001 From: g-cont Date: Tue, 29 Sep 2009 00:00:00 +0400 Subject: [PATCH] 29 Sep 2009 --- client/client.plg | 65 ------ client/global/dll_int.cpp | 26 ++- client/global/utils.cpp | 15 +- client/global/utils.h | 6 + client/hud/hud.cpp | 2 + client/hud/hud.h | 4 + client/hud/hud_msg.cpp | 9 + common/clgame_api.h | 21 +- common/entity_def.h | 1 - common/entity_state.h | 1 - common/gameinfo.h | 1 + engine/client/cl_demo.c | 13 +- engine/client/cl_frame.c | 138 ++++-------- engine/client/cl_game.c | 37 ++-- engine/client/cl_input.c | 3 +- engine/client/cl_main.c | 17 +- engine/client/cl_parse.c | 25 +-- engine/client/cl_view.c | 31 +-- engine/client/client.h | 27 ++- engine/common.h | 1 + engine/common/con_main.c | 33 +-- engine/common/con_utils.c | 47 +++++ engine/common/net_msg.c | 10 +- engine/common/net_msg.h | 1 - engine/engine.plg | 80 ------- engine/host.c | 16 ++ engine/server/server.h | 32 ++- engine/server/sv_client.c | 12 +- engine/server/sv_cmds.c | 131 +++++++----- engine/server/sv_frame.c | 20 +- engine/server/sv_game.c | 366 ++++++++++++++++++++------------ engine/server/sv_init.c | 177 ++++++++++++---- engine/server/sv_main.c | 16 +- engine/server/sv_phys.c | 2 + engine/server/sv_save.c | 380 ++++++++++++++++++++++++++++------ launch/filesystem.c | 12 +- launch/launch.h | 2 +- launch/launch.plg | 63 ++++++ launch/network.c | 11 +- launch/system.c | 3 + launch/utils.c | 2 +- physic/physic.plg | 16 ++ public/engine_api.h | 7 +- public/launch_api.h | 6 +- render/r_light.c | 11 +- render/r_local.h | 4 +- render/r_main.c | 57 ++--- render/r_mesh.c | 2 +- render/r_model.c | 6 +- render/r_sprite.c | 16 +- render/r_studio.c | 5 +- render/render.plg | 63 ++++++ server/ents/basefunc.cpp | 6 +- server/ents/baseweapon.cpp | 21 +- server/ents/baseweapon.h | 45 ++-- server/global/client.cpp | 101 +++++---- server/global/saverestore.cpp | 10 +- server/global/utils.cpp | 113 ++++++---- server/global/utils.h | 8 +- server/monsters/player.cpp | 11 +- server/server.plg | 87 +++++++- todo.log | 6 +- vsound/s_main.c | 4 +- 63 files changed, 1583 insertions(+), 881 deletions(-) delete mode 100644 client/client.plg create mode 100644 launch/launch.plg create mode 100644 physic/physic.plg create mode 100644 render/render.plg diff --git a/client/client.plg b/client/client.plg deleted file mode 100644 index bc01ce0c..00000000 --- a/client/client.plg +++ /dev/null @@ -1,65 +0,0 @@ - - -
-

Build Log

-

---------------------Configuration: client - Win32 Debug-------------------- -

-

Command Lines

-Creating temporary file "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1F7.tmp" with contents -[ -/nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "../common" /I "global" /I "hud" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR"..\temp\client\!debug/" /Fo"..\temp\client\!debug/" /Fd"..\temp\client\!debug/" /FD /c -"D:\Xash3D\src_main\client\global\dll_int.cpp" -] -Creating command line "cl.exe @C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1F7.tmp" -Creating temporary file "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1F8.tmp" with contents -[ -msvcrtd.lib /nologo /subsystem:windows /dll /incremental:yes /pdb:"..\temp\client\!debug/client.pdb" /debug /machine:I386 /nodefaultlib:"libc.lib" /def:".\client.def" /out:"..\temp\client\!debug/client.dll" /implib:"..\temp\client\!debug/client.lib" /pdbtype:sept /libpath:"..\common\libs" -"\Xash3D\src_main\temp\client\!debug\dll_int.obj" -"\Xash3D\src_main\temp\client\!debug\hud.obj" -"\Xash3D\src_main\temp\client\!debug\hud_ammo.obj" -"\Xash3D\src_main\temp\client\!debug\hud_ammohistory.obj" -"\Xash3D\src_main\temp\client\!debug\hud_battery.obj" -"\Xash3D\src_main\temp\client\!debug\hud_death.obj" -"\Xash3D\src_main\temp\client\!debug\hud_flashlight.obj" -"\Xash3D\src_main\temp\client\!debug\hud_geiger.obj" -"\Xash3D\src_main\temp\client\!debug\hud_health.obj" -"\Xash3D\src_main\temp\client\!debug\hud_icons.obj" -"\Xash3D\src_main\temp\client\!debug\hud_menu.obj" -"\Xash3D\src_main\temp\client\!debug\hud_message.obj" -"\Xash3D\src_main\temp\client\!debug\hud_motd.obj" -"\Xash3D\src_main\temp\client\!debug\hud_msg.obj" -"\Xash3D\src_main\temp\client\!debug\hud_saytext.obj" -"\Xash3D\src_main\temp\client\!debug\hud_scoreboard.obj" -"\Xash3D\src_main\temp\client\!debug\hud_sound.obj" -"\Xash3D\src_main\temp\client\!debug\hud_statusbar.obj" -"\Xash3D\src_main\temp\client\!debug\hud_text.obj" -"\Xash3D\src_main\temp\client\!debug\hud_train.obj" -"\Xash3D\src_main\temp\client\!debug\hud_warhead.obj" -"\Xash3D\src_main\temp\client\!debug\hud_zoom.obj" -"\Xash3D\src_main\temp\client\!debug\tempents.obj" -"\Xash3D\src_main\temp\client\!debug\triapi.obj" -"\Xash3D\src_main\temp\client\!debug\utils.obj" -"\Xash3D\src_main\temp\client\!debug\view.obj" -] -Creating command line "link.exe @C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1F8.tmp" -Creating temporary file "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1F9.bat" with contents -[ -@echo off -copy \Xash3D\src_main\temp\client\!debug\client.dll "D:\Xash3D\bin\client.dll" -] -Creating command line "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1F9.bat" -Compiling... -dll_int.cpp -Linking... -

Output Window

-Performing Custom Build Step on \Xash3D\src_main\temp\client\!debug\client.dll -Скопировано файлов: 1. - - - -

Results

-client.dll - 0 error(s), 0 warning(s) -
- - diff --git a/client/global/dll_int.cpp b/client/global/dll_int.cpp index 00815d28..42d88227 100644 --- a/client/global/dll_int.cpp +++ b/client/global/dll_int.cpp @@ -10,6 +10,7 @@ #include "hud.h" cl_enginefuncs_t g_engfuncs; +cl_globalvars_t *gpGlobals; CHud gHUD; // main DLL entry point @@ -42,7 +43,7 @@ static HUD_FUNCTIONS gFunctionTable = //======================================================================= // GetApi //======================================================================= -int CreateAPI( HUD_FUNCTIONS *pFunctionTable, cl_enginefuncs_t* pEngfuncsFromEngine ) +int CreateAPI( HUD_FUNCTIONS *pFunctionTable, cl_enginefuncs_t* pEngfuncsFromEngine, cl_globalvars_t *pGlobals ) { if( !pFunctionTable || !pEngfuncsFromEngine ) { @@ -52,6 +53,7 @@ int CreateAPI( HUD_FUNCTIONS *pFunctionTable, cl_enginefuncs_t* pEngfuncsFromEng // copy HUD_FUNCTIONS table to engine, copy engfuncs table from engine memcpy( pFunctionTable, &gFunctionTable, sizeof( HUD_FUNCTIONS )); memcpy( &g_engfuncs, pEngfuncsFromEngine, sizeof( cl_enginefuncs_t )); + gpGlobals = pGlobals; return TRUE; } @@ -72,6 +74,15 @@ void HUD_Init( void ) int HUD_Redraw( float flTime, int state ) { + static int oldstate; + + if( oldstate == CL_ACTIVE && state == CL_LOADING ) + { + // draw only once to prevent multiply GL_BLEND each frame + DrawImageBar( 100, "m_loading" ); // HACKHACK + } + oldstate = state; + switch( state ) { case CL_DISCONNECTED: @@ -94,18 +105,13 @@ int HUD_UpdateClientData( client_data_t *cdata, float flTime ) return gHUD.UpdateClientData( cdata, flTime ); } -void HUD_UpdateEntityVars( edict_t *ent, skyportal_t *sky, const entity_state_t *state, const entity_state_t *old ) +void HUD_UpdateEntityVars( edict_t *ent, skyportal_t *sky, const entity_state_t *state, const entity_state_t *prev ) { - int i; - float m_fLerp; - const entity_state_t *prev; - - if( state->ed_flags & ESF_NODELTA ) - prev = state; - else prev = old; + int i; + float m_fLerp; if( state->ed_type == ED_CLIENT && state->ed_flags & ESF_NO_PREDICTION ) - m_fLerp = 1.0f; // FIXME: use 0.0f ? + m_fLerp = 1.0f; else m_fLerp = GetLerpFrac(); // copy state to progs diff --git a/client/global/utils.cpp b/client/global/utils.cpp index ac6d0206..f2c55705 100644 --- a/client/global/utils.cpp +++ b/client/global/utils.cpp @@ -550,16 +550,17 @@ void DrawImageBar( float percent, const char *szSpriteName, int x, int y ) // void V_RenderPlaque( void ) { - const char *levelshot; + if( gHUD.m_iDrawPlaque ) + { + const char *levelshot; - levelshot = CVAR_GET_STRING( "cl_levelshot_name" ); - - // logo that shows up while upload next level - DrawImageRectangle( SPR_Load( levelshot )); - DrawImageBar( CVAR_GET_FLOAT( "scr_loading" ), "m_loading" ); + // logo that shows up while upload next level + levelshot = CVAR_GET_STRING( "cl_levelshot_name" ); + DrawImageRectangle( SPR_Load( levelshot )); + DrawImageBar( CVAR_GET_FLOAT( "scr_loading" ), "m_loading" ); + } if( !CVAR_GET_FLOAT( "scr_download" )) return; - DrawImageBar( CVAR_GET_FLOAT( "scr_download" ), "m_download", (ScreenWidth-128)/2, ScreenHeight-60 ); } diff --git a/client/global/utils.h b/client/global/utils.h index f756f94c..4128db8f 100644 --- a/client/global/utils.h +++ b/client/global/utils.h @@ -10,6 +10,8 @@ extern cl_enginefuncs_t g_engfuncs; #include "enginecallback.h" +extern cl_globalvars_t *gpGlobals; + extern int HUD_VidInit( void ); extern void HUD_Init( void ); extern int HUD_Redraw( float flTime, int state ); @@ -70,6 +72,10 @@ typedef struct dllfunction_s } #define HOOK_COMMAND( x, y ) (*g_engfuncs.pfnAddCommand)( x, __CmdFunc_##y, "user-defined command" ); +#define DECLARE_HUDCOMMAND( x ) void __CmdFunc_##x( void ) \ +{ \ + gHUD.UserCmd_##x( ); \ +} #define DECLARE_COMMAND( y, x ) void __CmdFunc_##x( void ) \ { \ gHUD.##y.UserCmd_##x( ); \ diff --git a/client/hud/hud.cpp b/client/hud/hud.cpp index bffc18c1..16581a5a 100644 --- a/client/hud/hud.cpp +++ b/client/hud/hud.cpp @@ -71,6 +71,7 @@ void CHud :: VidInit( void ) // Load Sprites // --------- + m_iDrawPlaque = 1; m_hsprCursor = 0; m_hHudError = 0; m_hHudFont = 0; @@ -239,6 +240,7 @@ int CHud :: Redraw( float flTime ) // make levelshot if needed MAKE_LEVELSHOT(); + m_iDrawPlaque = 1; // clear plaque stuff // draw screen fade before hud DrawScreenFade(); diff --git a/client/hud/hud.h b/client/hud/hud.h index 184827f9..3f14532a 100644 --- a/client/hud/hud.h +++ b/client/hud/hud.h @@ -667,6 +667,9 @@ public: int _cdecl MsgFunc_Particle( const char *pszName, int iSize, void *pbuf ); int _cdecl MsgFunc_TempEntity( const char *pszName, int iSize, void *pbuf ); + // user commansds + void _cdecl UserCmd_LoadingPlaque( void ); + // filled in VidInit struct { @@ -681,6 +684,7 @@ public: int m_iWeaponBits; int m_fPlayerDead; int m_iIntermission; + int m_iDrawPlaque; RainData Rain; // buz rain diff --git a/client/hud/hud_msg.cpp b/client/hud/hud_msg.cpp index 715f2773..fc399912 100644 --- a/client/hud/hud_msg.cpp +++ b/client/hud/hud_msg.cpp @@ -43,6 +43,7 @@ DECLARE_HUDMESSAGE( TempEntity ); DECLARE_HUDMESSAGE( ServerName ); DECLARE_HUDMESSAGE( ScreenShake ); DECLARE_HUDMESSAGE( Intermission ); +DECLARE_HUDCOMMAND( LoadingPlaque ); int CHud :: InitMessages( void ) { @@ -70,6 +71,8 @@ int CHud :: InitMessages( void ) HOOK_MESSAGE( ScreenFade ); HOOK_MESSAGE( ScreenShake ); + HOOK_COMMAND( "plaque", LoadingPlaque ); + viewEntityIndex = 0; // trigger_viewset stuff viewFlags = 0; m_flFOV = 0; @@ -99,6 +102,12 @@ int CHud :: InitMessages( void ) return 1; } +void CHud :: UserCmd_LoadingPlaque( void ) +{ + ALERT( at_console, "SCR_DisablePlaque()\n" ); + m_iDrawPlaque = 0; // disable plaque rendering +} + int CHud :: MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf ) { // clear all hud data diff --git a/common/clgame_api.h b/common/clgame_api.h index f2332932..aa55697b 100644 --- a/common/clgame_api.h +++ b/common/clgame_api.h @@ -16,6 +16,7 @@ typedef void (*pfnEventHook)( struct event_args_s *args ); #include "trace_def.h" #include "event_api.h" +#include "gameinfo.h" typedef struct { @@ -51,6 +52,24 @@ typedef struct client_data_s float mouse_sensitivity; // used for menus and zoomed weapons } client_data_t; +typedef struct cl_globalvars_s +{ + float time; // time from server + float frametime; + string_t mapname; + + BOOL deathmatch; + BOOL coop; + BOOL teamplay; + + int serverflags; + int maxClients; + int maxEntities; + int numEntities; // actual ents count + + dll_gameinfo_t GameInfo; // shared gameinfo +} cl_globalvars_t; + typedef struct cl_enginefuncs_s { // interface validator @@ -166,6 +185,6 @@ typedef struct void (*pfnStopPitchDrift)( void ); } HUD_FUNCTIONS; -typedef int (*CLIENTAPI)( HUD_FUNCTIONS *pFunctionTable, cl_enginefuncs_t* pEngfuncsFromEngine ); +typedef int (*CLIENTAPI)( HUD_FUNCTIONS *pFunctionTable, cl_enginefuncs_t* engfuncs, cl_globalvars_t *pGlobals ); #endif//CLGAME_API_H \ No newline at end of file diff --git a/common/entity_def.h b/common/entity_def.h index 00c91b00..48d0db69 100644 --- a/common/entity_def.h +++ b/common/entity_def.h @@ -74,7 +74,6 @@ typedef struct entvars_s int sequence; // ENG [all], NET [all], animation sequence int gaitsequence; // NET [player], movement animation sequence for player (0 for none) - int weaponanim; // NET [all], weaponmodel animation sequencs float frame; // NET [all], % playback position in animation sequences (0..255) float animtime; // NET [all], world time when frame was set float framerate; // NET [all], animation playback rate (-8x to 8x) diff --git a/common/entity_state.h b/common/entity_state.h index 7c8f0ae1..3284b206 100644 --- a/common/entity_state.h +++ b/common/entity_state.h @@ -88,7 +88,6 @@ typedef struct entity_state_s int gaitsequence; // client\nps\bot gaitsequence int viewmodel; // contains viewmodel index int weaponmodel; // contains weaponmodel index - int weaponanim; // weaponmodel sequence int weaponbody; // weaponmodel body int weaponskin; // weaponmodel skin float idealpitch; // client idealpitch diff --git a/common/gameinfo.h b/common/gameinfo.h index 9460e13c..a3bf1dfa 100644 --- a/common/gameinfo.h +++ b/common/gameinfo.h @@ -26,6 +26,7 @@ typedef struct dll_gameinfo_s string_t sp_entity; // e.g. info_player_start string_t dm_entity; // e.g. info_player_deathmatch + string_t coop_entity; // e.g. info_player_coop string_t ctf_entity; // e.g. info_player_ctf string_t team_entity; // e.g. info_player_team diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index 4aac3c3e..91ed8ded 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -34,7 +34,6 @@ void CL_WriteDemoHeader( const char *name ) { char buf_data[MAX_MSGLEN]; entity_state_t *state, nullstate; - edict_t *ent; sizebuf_t buf; int i, len; @@ -85,23 +84,21 @@ void CL_WriteDemoHeader( const char *name ) // baselines Mem_Set( &nullstate, 0, sizeof( nullstate )); - for( i = 0; i < clgame.numEntities; i++ ) + for( i = 0; i < clgame.globals->numEntities; i++ ) { - ent = EDICT_NUM( i ); - if( ent->free ) continue; - state = &ent->pvClientData->baseline; - if( !state->modelindex ) continue; + state = &cl.entity_baselines[i]; + if( !state->number ) continue; if( buf.cursize + 64 > buf.maxsize ) { // write it out - len = LittleLong (buf.cursize); + len = LittleLong( buf.cursize ); FS_Write( cls.demofile, &len, 4 ); FS_Write( cls.demofile, buf.data, buf.cursize ); buf.cursize = 0; } MSG_WriteByte( &buf, svc_spawnbaseline ); - MSG_WriteDeltaEntity( &nullstate, &ent->pvClientData->baseline, &buf, true, true ); + MSG_WriteDeltaEntity( &nullstate, state, &buf, true, true ); } MSG_WriteByte( &buf, svc_stufftext ); diff --git a/engine/client/cl_frame.c b/engine/client/cl_frame.c index b0846e06..284845b6 100644 --- a/engine/client/cl_frame.c +++ b/engine/client/cl_frame.c @@ -39,12 +39,12 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t entity_state_t *state; ent = EDICT_NUM( newnum ); - state = &cl_parse_entities[cl.parse_entities & (MAX_PARSE_ENTITIES-1)]; + state = &cl.entity_curstates[cl.parse_entities & (MAX_PARSE_ENTITIES-1)]; if( unchanged ) *state = *old; else MSG_ReadDeltaEntity( msg, old, state, newnum ); - if( state->number == -1 ) + if( state->number == ( MAX_EDICTS - 1 )) { CL_FreeEdict( ent ); return; // entity was delta removed @@ -52,12 +52,14 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t cl.parse_entities++; frame->num_entities++; - // some data changes will force no lerping - if( state->ed_flags & ESF_NODELTA ) + if( ent->free ) { - ent->pvClientData->serverframe = -99; + CL_InitEdict( ent ); } + // some data changes will force no lerping + if( state->ed_flags & ESF_NODELTA ) ent->pvClientData->serverframe = -99; + if( ent->pvClientData->serverframe != cl.frame.serverframe - 1 ) { // duplicate the current state so lerping doesn't hurt anything @@ -101,7 +103,7 @@ void CL_ParsePacketEntities( sizebuf_t *msg, frame_t *oldframe, frame_t *newfram } else { - oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; + oldstate = &cl.entity_curstates[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; oldnum = oldstate->number; } } @@ -115,7 +117,7 @@ void CL_ParsePacketEntities( sizebuf_t *msg, frame_t *oldframe, frame_t *newfram if( msg->error ) Host_Error("CL_ParsePacketEntities: end of message[%d > %d]\n", msg->readcount, msg->cursize ); - while( newnum >= clgame.numEntities ) CL_AllocEdict(); + while( newnum >= clgame.globals->numEntities ) CL_AllocEdict(); while( oldnum < newnum ) { @@ -130,7 +132,7 @@ void CL_ParsePacketEntities( sizebuf_t *msg, frame_t *oldframe, frame_t *newfram } else { - oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; + oldstate = &cl.entity_curstates[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; oldnum = oldstate->number; } } @@ -146,7 +148,7 @@ void CL_ParsePacketEntities( sizebuf_t *msg, frame_t *oldframe, frame_t *newfram } else { - oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; + oldstate = &cl.entity_curstates[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; oldnum = oldstate->number; } continue; @@ -155,10 +157,8 @@ void CL_ParsePacketEntities( sizebuf_t *msg, frame_t *oldframe, frame_t *newfram if( oldnum > newnum ) { // delta from baseline ? - edict_t *ent = EDICT_NUM( newnum ); - - Com_Assert( ent->free ); - CL_DeltaEntity( msg, newframe, newnum, &ent->pvClientData->baseline, false ); + entity_state_t *baseline = &cl.entity_baselines[newnum]; + CL_DeltaEntity( msg, newframe, newnum, baseline, false ); continue; } @@ -177,59 +177,12 @@ void CL_ParsePacketEntities( sizebuf_t *msg, frame_t *oldframe, frame_t *newfram } else { - oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; + oldstate = &cl.entity_curstates[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; oldnum = oldstate->number; } } - for( ; EDICT_NUM( clgame.numEntities - 1 )->free; clgame.numEntities-- ); -} - -/* -=============== -CL_LerpPoint - -Determines the fraction between the last two messages that the objects -should be put at. -=============== -*/ -static float CL_LerpPoint( void ) -{ - float f, frac; - - f = cl.mtime[0] - cl.mtime[1]; - - if( !f ) - { - cl.time = cl.mtime[0]; - return 1.0f; - } - - if( f > 0.1 ) - { - // dropped packet, or start of demo - cl.mtime[1] = cl.mtime[0] - 0.1f; - f = 0.1f; - } - - frac = (cl.time - cl.mtime[1]) / f; - if( frac < 0 ) - { - if( frac < -0.01f ) - { - cl.time = cl.mtime[1]; - } - frac = 0; - } - else if( frac > 1.0f ) - { - if( frac > 1.01f ) - { - cl.time = cl.mtime[0]; - } - frac = 1.0f; - } - return frac; + for( ; EDICT_NUM( clgame.globals->numEntities - 1 )->free; clgame.globals->numEntities-- ); } /* @@ -245,10 +198,10 @@ void CL_ParseFrame( sizebuf_t *msg ) Mem_Set( &cl.frame, 0, sizeof( cl.frame )); cl.frame.serverframe = MSG_ReadLong( msg ); + cl.frame.servertime = MSG_ReadLong( msg ); cl.serverframetime = MSG_ReadLong( msg ); cl.frame.deltaframe = MSG_ReadLong( msg ); cl.surpressCount = MSG_ReadByte( msg ); - cl.frame.servertime = cl.mtime[0]; // same as servertime // If the frame is delta compressed from data that we // no longer have available, we must suck up the rest of @@ -285,18 +238,18 @@ void CL_ParseFrame( sizebuf_t *msg ) len = MSG_ReadByte( msg ); MSG_ReadData( msg, &cl.frame.areabits, len ); + // read packet entities + cmd = MSG_ReadByte( msg ); + if( cmd != svc_packetentities ) Host_Error("CL_ParseFrame: not packetentities[%d]\n", cmd ); + CL_ParsePacketEntities( msg, cl.oldframe, &cl.frame ); + // read clientindex cmd = MSG_ReadByte( msg ); if( cmd != svc_playerinfo ) Host_Error( "CL_ParseFrame: not clientindex\n" ); idx = MSG_ReadByte( msg ); clent = EDICT_NUM( idx ); // get client if(( idx - 1 ) != cl.playernum ) - Host_Error("CL_ParseFrame: invalid playernum (%d should be %d)\n", idx-1, cl.playernum ); - - // read packet entities - cmd = MSG_ReadByte( msg ); - if( cmd != svc_packetentities ) Host_Error("CL_ParseFrame: not packetentities[%d]\n", cmd ); - CL_ParsePacketEntities( msg, cl.oldframe, &cl.frame ); + Host_Error( "CL_ParseFrame: invalid playernum (%d should be %d)\n", idx-1, cl.playernum ); // now we can reading delta player state if( cl.oldframe ) cl.frame.ps = MSG_ParseDeltaPlayer( &cl.oldframe->ps, &clent->pvClientData->current ); @@ -309,7 +262,10 @@ void CL_ParseFrame( sizebuf_t *msg ) { if( cls.state != ca_active ) { - cls.state = ca_active; + cls.state = ca_active; // client spawned + cl.force_refdef = true; + + Cvar_SetValue( "scr_loading", 0.0f ); // reset progress bar // getting a valid frame message ends the connection process VectorCopy( cl.frame.ps.origin, cl.predicted_origin ); VectorCopy( cl.frame.ps.viewangles, cl.predicted_angles ); @@ -333,30 +289,24 @@ CL_AddPacketEntities */ void CL_AddPacketEntities( frame_t *frame ) { - entity_state_t *s1; - edict_t *ent; - int pnum; + edict_t *ent; + int e, ed_type; - cl.time = bound( cl.frame.servertime - cl.serverframetime, cl.time, cl.frame.servertime ); - if( cl_paused->integer ) cl.lerpFrac = 1.0f; - else cl.lerpFrac = 1.0 - (cl.frame.servertime - cl.time) / (float)cl.serverframetime; - - for( pnum = 0; pnum < frame->num_entities; pnum++ ) + for( e = 0; e < clgame.globals->numEntities; e++ ) { - s1 = &cl_parse_entities[(frame->parse_entities + pnum)&(MAX_PARSE_ENTITIES-1)]; - ent = EDICT_NUM( s1->number ); - + ent = EDICT_NUM( e ); if( ent->free ) continue; + ed_type = ent->pvClientData->current.ed_type; CL_UpdateEntityFields( ent ); - if( re->AddRefEntity( ent, s1->ed_type )) + if( re->AddRefEntity( ent, ed_type )) { - if( s1->ed_type == ED_PORTAL && !VectorCompare( ent->v.origin, ent->v.oldorigin )) + if( ed_type == ED_PORTAL && !VectorCompare( ent->v.origin, ent->v.oldorigin )) cl.render_flags |= RDF_PORTALINVIEW; } // NOTE: skyportal entity never added to rendering - if( s1->ed_type == ED_SKYPORTAL ) cl.render_flags |= RDF_SKYPORTALINVIEW; + if( ed_type == ED_SKYPORTAL ) cl.render_flags |= RDF_SKYPORTALINVIEW; } if( cl.oldframe && !memcmp( cl.oldframe->areabits, cl.frame.areabits, sizeof( cl.frame.areabits ))) @@ -411,7 +361,7 @@ void CL_GetEntitySoundSpatialization( int entnum, vec3_t origin, vec3_t velocity // setup origin and velocity VectorCopy( ent->v.origin, origin ); - VectorScale( ent->v.velocity, 10, velocity ); + VectorCopy( ent->v.velocity, velocity ); // if a brush model, offset the origin if( VectorIsNull( origin )) @@ -434,19 +384,19 @@ client */ void CL_AddLoopingSounds( void ) { - entity_state_t *ent; - int num, i; + edict_t *ent; + int sound, e; if( cls.state != ca_active ) return; if( cl_paused->integer ) return; if( !cl.audio_prepped ) return; - for( i = 0; i < cl.frame.num_entities; i++ ) + for( e = 0; e < clgame.globals->numEntities; e++ ) { - num = (cl.frame.parse_entities + i)&(MAX_PARSE_ENTITIES-1); - ent = &cl_parse_entities[num]; + ent = EDICT_NUM( e ); + if( ent->free ) continue; - switch( ent->ed_type ) + switch( ent->pvClientData->current.ed_type ) { case ED_MOVER: case ED_AMBIENT: @@ -454,7 +404,9 @@ void CL_AddLoopingSounds( void ) default: continue; } - if( !ent->soundindex ) continue; - S_AddLoopingSound( ent->number, cl.sound_precache[ent->soundindex], 1.0f, ATTN_IDLE ); + sound = ent->pvClientData->current.soundindex; + if( !sound ) continue; + + S_AddLoopingSound( ent->serialnumber, cl.sound_precache[sound], 1.0f, ATTN_IDLE ); } } \ No newline at end of file diff --git a/engine/client/cl_game.c b/engine/client/cl_game.c index 1f0cc85b..132e7ea5 100644 --- a/engine/client/cl_game.c +++ b/engine/client/cl_game.c @@ -21,7 +21,7 @@ Render callback for studio models */ edict_t *CL_GetEdictByIndex( int index ) { - if( index < 0 || index > clgame.numEntities ) + if( index < 0 || index > clgame.globals->numEntities ) { if( index == VMODEL_ENTINDEX ) return &cl.viewent; if( index == WMODEL_ENTINDEX ) return NULL; @@ -163,12 +163,6 @@ void CL_FadeAlpha( float starttime, float endtime, rgba_t color ) void CL_DrawHUD( int state ) { - if( state == CL_LOADING ) - { - // fill unused entries with black color - SCR_FillRect( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, g_color_table[0] ); - } - if( state == CL_ACTIVE && !cl.video_prepped ) state = CL_LOADING; @@ -352,7 +346,7 @@ edict_t *CL_AllocEdict( void ) edict_t *pEdict; int i; - for( i = 0; i < clgame.numEntities; i++ ) + for( i = 0; i < clgame.globals->numEntities; i++ ) { pEdict = EDICT_NUM( i ); // the first couple seconds of client time can involve a lot of @@ -364,10 +358,10 @@ edict_t *CL_AllocEdict( void ) } } - if( i == clgame.maxEntities ) + if( i == clgame.globals->maxEntities ) Host_Error( "CL_AllocEdict: no free edicts\n" ); - clgame.numEntities++; + clgame.globals->numEntities++; pEdict = EDICT_NUM( i ); CL_InitEdict( pEdict ); @@ -379,12 +373,19 @@ void CL_InitEdicts( void ) edict_t *e; int i; - clgame.maxEntities = com.atoi( cl.configstrings[CS_MAXEDICTS] ); - clgame.maxClients = com.atoi( cl.configstrings[CS_MAXCLIENTS] ); - clgame.edicts = Mem_Realloc( cls.mempool, clgame.edicts, sizeof( edict_t ) * clgame.maxEntities ); + clgame.globals->maxEntities = com.atoi( cl.configstrings[CS_MAXEDICTS] ); + clgame.globals->maxClients = com.atoi( cl.configstrings[CS_MAXCLIENTS] ); + clgame.edicts = Mem_Realloc( cls.mempool, clgame.edicts, sizeof( edict_t ) * clgame.globals->maxEntities ); - for( i = 0, e = EDICT_NUM( 0 ); i < clgame.maxEntities; i++, e++ ) + for( i = 0, e = EDICT_NUM( 0 ); i < clgame.globals->maxEntities; i++, e++ ) e->free = true; // mark all edicts as freed + + clgame.globals->mapname = MAKE_STRING( cl.configstrings[CS_NAME] ); + + clgame.globals->deathmatch = Cvar_VariableInteger( "deathmatch" ); + clgame.globals->coop = Cvar_VariableInteger( "coop" ); + clgame.globals->teamplay = Cvar_VariableInteger( "teamplay" ); + clgame.globals->serverflags = 0; // FIXME: make CS_SERVERFLAGS } void CL_FreeEdicts( void ) @@ -392,7 +393,7 @@ void CL_FreeEdicts( void ) int i; edict_t *ent; - for( i = 0; i < clgame.numEntities; i++ ) + for( i = 0; i < clgame.globals->numEntities; i++ ) { ent = EDICT_NUM( i ); if( ent->free ) continue; @@ -401,7 +402,7 @@ void CL_FreeEdicts( void ) // clear globals StringTable_Clear( clgame.hStringTable ); - clgame.numEntities = 0; + clgame.globals->numEntities = 0; } /* @@ -1402,11 +1403,13 @@ void CL_UnloadProgs( void ) bool CL_LoadProgs( const char *name ) { static CLIENTAPI GetClientAPI; + static cl_globalvars_t gpGlobals; string libpath; if( clgame.hInstance ) CL_UnloadProgs(); // fill it in + clgame.globals = &gpGlobals; Com_BuildPath( name, libpath ); cls.mempool = Mem_AllocPool( "Client Edicts Zone" ); clgame.private = Mem_AllocPool( "Client Private Zone" ); @@ -1422,7 +1425,7 @@ bool CL_LoadProgs( const char *name ) return false; } - if( !GetClientAPI( &clgame.dllFuncs, &gEngfuncs )) + if( !GetClientAPI( &clgame.dllFuncs, &gEngfuncs, clgame.globals )) { MsgDev( D_ERROR, "CL_LoadProgs: can't init client API\n" ); return false; diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index e5b8081b..2951b166 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -713,8 +713,7 @@ void CL_WritePacket( void ) { bool noDelta = false; - if( cl_nodelta->integer ) noDelta = true; - if( !cl.frame.valid || cls.demowaiting || cls.netchan.incoming_sequence != cl.frame.serverframe ) + if( cl_nodelta->integer || !cl.frame.valid || cls.demowaiting ) noDelta = true; // begin a client move command diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index ff691d50..b3615e19 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -38,7 +38,6 @@ cvar_t *cl_particlelod; cvar_t *cl_shownet; cvar_t *cl_showmiss; -cvar_t *cl_showclamp; cvar_t *cl_mouselook; cvar_t *cl_paused; @@ -54,8 +53,6 @@ client_static_t cls; client_t cl; clgame_static_t clgame; -entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES]; - extern cvar_t *allow_download; //====================================================================== @@ -441,8 +438,9 @@ void CL_Changing_f( void ) if( cls.download ) return; S_StopAllSounds(); + cl.audio_prepped = false; // don't play ambients cls.state = ca_connected; // not active anymore, but not disconnected - Msg( "\nChanging map...\n" ); + Msg( "\nchanging map...\n" ); } @@ -459,9 +457,10 @@ void CL_Reconnect_f( void ) if( cls.download ) return; S_StopAllSounds (); + Cmd_ExecuteString( "plaque\n" ); // disable plaque draw on change map + if( cls.state == ca_connected ) { - Msg( "reconnecting...\n" ); cls.state = ca_connected; MSG_WriteByte( &cls.netchan.message, clc_stringcmd ); MSG_Print( &cls.netchan.message, "new" ); @@ -708,7 +707,7 @@ void CL_PrepVideo( void ) return; // no map loaded Cvar_SetValue( "scr_loading", 0.0f ); // reset progress bar - Msg( "CL_PrepRefresh: %s\n", cl.configstrings[CS_NAME] ); + MsgDev( D_LOAD, "CL_PrepRefresh: %s\n", cl.configstrings[CS_NAME] ); // let the render dll load the map FS_FileBase( cl.configstrings[CS_MODELS+1], mapname ); re->BeginRegistration( mapname, pe->VisData()); // load map @@ -737,9 +736,10 @@ void CL_PrepVideo( void ) re->EndRegistration( cl.configstrings[CS_SKYNAME] ); Cvar_SetValue( "scr_loading", 100.0f ); // all done - Con_ClearNotify(); // clear any lines of console text + if( host.developer <= 2 ) Con_ClearNotify(); // clear any lines of console text SCR_UpdateScreen(); cl.video_prepped = true; + cl.force_refdef = true; } /* @@ -1087,7 +1087,6 @@ void CL_InitLocal( void ) cl_shownet = Cvar_Get( "cl_shownet", "0", 0, "client show network packets" ); cl_showmiss = Cvar_Get( "cl_showmiss", "0", 0, "client show network errors" ); - cl_showclamp = Cvar_Get( "cl_showclamp", "0", CVAR_ARCHIVE, "show client clamping" ); cl_timeout = Cvar_Get( "cl_timeout", "120", 0, "connect timeout (in-seconds)" ); rcon_client_password = Cvar_Get( "rcon_password", "", 0, "remote control client password" ); @@ -1200,7 +1199,7 @@ void CL_Frame( int time ) SCR_MakeScreenShot(); // update audio - S_Update( cl.playernum + 1, cl.refdef.vieworg, vec3_origin, cl.refdef.forward, cl.refdef.up ); + S_Update( cl.playernum + 1, cl.refdef.simorg, cl.refdef.simvel, cl.refdef.forward, cl.refdef.up ); // advance local effects for next frame CL_RunDLights (); diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index d7957097..aafb1ebc 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -230,11 +230,11 @@ CL_ParseServerData */ void CL_ParseServerData( sizebuf_t *msg ) { - char *str; + string str, title; const char *levelshot_ext[] = { "tga", "jpg", "png" }; int i; - MsgDev( D_INFO, "Serverdata packet received.\n" ); + MsgDev( D_NOTE, "Serverdata packet received.\n" ); // wipe the client_t struct CL_ClearState(); @@ -248,9 +248,9 @@ void CL_ParseServerData( sizebuf_t *msg ) Host_Error( "Server use invalid protocol (%i should be %i)\n", i, PROTOCOL_VERSION ); cl.servercount = MSG_ReadLong( msg ); - cl.serverframetime = MSG_ReadLong( msg ); cl.playernum = MSG_ReadShort( msg ); - str = MSG_ReadString( msg ); + com.strncpy( str, MSG_ReadString( msg ), MAX_STRING ); + com.strncpy( title, MSG_ReadString( msg ), MAX_STRING ); // get splash name Cvar_Set( "cl_levelshot_name", va( "levelshots/%s", str )); @@ -266,6 +266,7 @@ void CL_ParseServerData( sizebuf_t *msg ) } // seperate the printfs so the server message can have a color Msg("\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n"); + Msg( "^2%s\n", title ); // need to prep refresh at next oportunity cl.video_prepped = false; @@ -281,19 +282,15 @@ void CL_ParseBaseline( sizebuf_t *msg ) { int newnum; entity_state_t nullstate; - edict_t *ent; + entity_state_t *baseline; Mem_Set( &nullstate, 0, sizeof( nullstate )); newnum = MSG_ReadBits( msg, NET_WORD ); - if( !clgame.numEntities ) CL_InitEdicts(); + if( !newnum ) CL_InitEdicts(); - // increase edicts - while( newnum >= clgame.numEntities ) CL_AllocEdict(); - ent = EDICT_NUM( newnum ); - - Com_Assert( ent->pvClientData == NULL ); - MSG_ReadDeltaEntity( msg, &nullstate, &ent->pvClientData->baseline, newnum ); + baseline = &cl.entity_baselines[newnum]; + MSG_ReadDeltaEntity( msg, &nullstate, baseline, newnum ); } void CL_ParseMoveVars( int number ) @@ -520,10 +517,6 @@ void CL_ParseServerMessage( sizebuf_t *msg ) case svc_print: Con_Print( va( "^6%s\n", MSG_ReadString( msg ))); break; - case svc_time: - cl.mtime[1] = cl.mtime[0]; - cl.mtime[0] = MSG_ReadLong( msg ); - break; case svc_frame: CL_ParseFrame( msg ); break; diff --git a/engine/client/cl_view.c b/engine/client/cl_view.c index 66d9ec51..44d32f5c 100644 --- a/engine/client/cl_view.c +++ b/engine/client/cl_view.c @@ -62,9 +62,9 @@ void V_SetupRefDef( void ) cl.refdef.health = clent->v.health; cl.refdef.movetype = clent->v.movetype; cl.refdef.idealpitch = clent->v.ideal_pitch; - cl.refdef.num_entities = clgame.numEntities; - cl.refdef.max_entities = clgame.maxEntities; - cl.refdef.maxclients = clgame.maxClients; + cl.refdef.num_entities = clgame.globals->numEntities; + cl.refdef.max_entities = clgame.globals->maxEntities; + cl.refdef.maxclients = clgame.globals->maxClients; cl.refdef.time = cl.time * 0.001f; cl.refdef.frametime = cls.frametime; cl.refdef.demoplayback = cls.demoplayback; @@ -101,8 +101,8 @@ apply pre-calculated values */ void V_AddViewModel( void ) { - if( cl.viewent.v.modelindex && !cl.refdef.nextView ) - re->AddRefEntity( &cl.viewent, ED_VIEWMODEL ); + if( cl.refdef.nextView ) return; // add viewmodel only at firstperson pass + re->AddRefEntity( &cl.viewent, ED_VIEWMODEL ); } /* @@ -134,16 +134,23 @@ void V_RenderView( void ) { if( !cl.video_prepped ) return; // still loading - if( !cl.frame.valid ) + cl.time = bound( cl.frame.servertime - cl.serverframetime, cl.time, cl.frame.servertime ); + if( cl_paused->integer ) cl.lerpFrac = 1.0f; + else cl.lerpFrac = 1.0 - (cl.frame.servertime - cl.time) / (float)cl.serverframetime; + + // update cl_globalvars + clgame.globals->time = cl.time * 0.001f; // clamped + clgame.globals->frametime = cl.serverframetime * 0.001f; // !!! + + if( cl.frame.valid && (cl.force_refdef || !cl_paused->integer )) { - SCR_FillRect( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, g_color_table[0] ); - return; + cl.force_refdef = false; + + V_ClearScene (); + CL_AddEntities (); + V_SetupRefDef (); } - V_ClearScene (); - CL_AddEntities (); - - V_SetupRefDef (); V_CalcRefDef (); } diff --git a/engine/client/client.h b/engine/client/client.h index 74b2c1cb..bcdbbb61 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -71,6 +71,11 @@ typedef struct field_s #define CMD_BACKUP 64 // allow a lot of command backups for very fast systems #define CMD_MASK (CMD_BACKUP - 1) +// the cl_parse_entities must be large enough to hold UPDATE_BACKUP frames of +// entities, so that when a delta compressed message arives from the server +// it can be un-deltad from the original +#define MAX_PARSE_ENTITIES 2048 + // // the client_t structure is wiped completely at every // server map change @@ -81,7 +86,7 @@ typedef struct bool video_prepped; // false if on new level or new ref dll bool audio_prepped; // false if on new level or new snd dll - + bool force_refdef; // vid has changed, so we can't use a paused refdef int parse_entities; // index (not anded off) into cl_parse_entities[] int cmd_number; @@ -125,6 +130,9 @@ typedef struct int serverframetime; // server frametime char configstrings[MAX_CONFIGSTRINGS][CS_SIZE]; + entity_state_t entity_curstates[MAX_PARSE_ENTITIES]; + entity_state_t entity_baselines[MAX_EDICTS]; // keep all baselines in one global array + // locally derived information from server state cmodel_t *models[MAX_MODELS]; cmodel_t *worldmodel; @@ -173,8 +181,6 @@ typedef enum struct cl_priv_s { int serverframe; // if not current, this ent isn't in the frame - - entity_state_t baseline; // delta from this if not from a previous frame entity_state_t current; entity_state_t prev; // will always be valid, but might just be a copy of current }; @@ -226,10 +232,9 @@ typedef struct char centerPrint[1024]; int centerPrintLines; - int maxClients; - int numEntities; - int maxEntities; + cl_globalvars_t *globals; user_message_t *msg[MAX_USER_MESSAGES]; + int numMessages; // actual count of user messages int hStringTable; // stringtable handle @@ -319,7 +324,6 @@ extern cvar_t *cl_run; extern cvar_t *cl_font; extern cvar_t *cl_anglespeedkey; extern cvar_t *cl_showmiss; -extern cvar_t *cl_showclamp; extern cvar_t *cl_particles; extern cvar_t *cl_particlelod; extern cvar_t *cl_testentities; @@ -331,13 +335,6 @@ extern cvar_t *scr_centertime; extern cvar_t *scr_showpause; extern cvar_t *con_font; -// the cl_parse_entities must be large enough to hold UPDATE_BACKUP frames of -// entities, so that when a delta compressed message arives from the server -// it can be un-deltad from the original -#define MAX_PARSE_ENTITIES 1024 - -extern entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES]; - //============================================================================= bool CL_CheckOrDownloadFile( const char *filename ); @@ -463,7 +460,7 @@ bool CL_RenderTrace( const vec3_t start, const vec3_t mins, const vec3_t maxs, c _inline edict_t *CL_EDICT_NUM( int n, const char *file, const int line ) { - if((n >= 0) && (n < clgame.maxEntities)) + if((n >= 0) && (n < clgame.globals->maxEntities)) return clgame.edicts + n; Host_Error( "CL_EDICT_NUM: bad number %i (called at %s:%i)\n", n, file, line ); return NULL; diff --git a/engine/common.h b/engine/common.h index 6ca89890..d7c12e2a 100644 --- a/engine/common.h +++ b/engine/common.h @@ -117,6 +117,7 @@ void Host_Main( void ); void Host_Free( void ); void Host_SetServerState( int state ); int Host_ServerState( void ); +int Host_CompareFileTime( long ft1, long ft2 ); void Host_AbortCurrentFrame( void ); void Host_WriteDefaultConfig( void ); void Host_WriteConfig( void ); diff --git a/engine/common/con_main.c b/engine/common/con_main.c index 51952723..9f99276d 100644 --- a/engine/common/con_main.c +++ b/engine/common/con_main.c @@ -245,11 +245,11 @@ void Con_Init( void ) // register our commands con_notifytime = Cvar_Get( "con_notifytime", "3", 0, "notify time to live" ); con_speed = Cvar_Get( "con_speed", "3", 0, "console moving speed" ); - con_font = Cvar_Get( "con_font", "default", CVAR_ARCHIVE, "path to console charset" ); + con_font = Cvar_Get( "con_font", "default", CVAR_ARCHIVE, "path to console charset" ); Field_Clear( &g_consoleField ); g_consoleField.widthInChars = g_console_field_width; - for ( i = 0 ; i < COMMAND_HISTORY ; i++ ) + for( i = 0; i < COMMAND_HISTORY; i++ ) { Field_Clear( &historyEditLines[i] ); historyEditLines[i].widthInChars = g_console_field_width; @@ -260,8 +260,9 @@ void Con_Init( void ) Cmd_AddCommand( "messagemode", Con_MessageMode_f, "input a chat message to say to everyone" ); Cmd_AddCommand( "messagemode2", Con_MessageMode2_f, "input a chat message to say to only your team" ); Cmd_AddCommand( "clear", Con_Clear_f, "clear console history" ); - con.initialized = true; + MsgDev( D_NOTE, "Console initialized.\n" ); + con.initialized = true; } @@ -554,24 +555,22 @@ Con_DrawConsole */ void Con_DrawConsole( void ) { - if(!host.developer) return; + if( !host.developer ) return; // check for console width changes from a vid mode change Con_CheckResize (); + if( cls.state == ca_connecting || cls.state == ca_connected ) + { + if( host.developer >= 4 ) con.displayFrac = 0.5f; // keep console open + else if( host.developer >= 2 ) Con_DrawNotify(); // draw notify lines + } + // if disconnected, render console full screen switch( cls.state ) { case ca_uninitialized: break; - case ca_connected: - case ca_connecting: - if( host.developer >= 2 ) - { - // -dev 1 probably nothing print while loading - Con_DrawSolidConsole( 0.5f ); - } - break; case ca_disconnected: if( cls.key_dest != key_menu ) { @@ -579,10 +578,18 @@ void Con_DrawConsole( void ) cls.key_dest = key_console; } break; + case ca_connected: + case ca_connecting: + if( host.developer ) + { + // force to show console always for -dev 3 and higher + if( con.displayFrac ) Con_DrawSolidConsole( con.displayFrac ); + } + break; case ca_active: case ca_cinematic: if( con.displayFrac ) Con_DrawSolidConsole( con.displayFrac ); - else if ( cls.state == ca_active ) Con_DrawNotify(); // draw notify lines + else if( cls.state == ca_active ) Con_DrawNotify(); // draw notify lines break; } } diff --git a/engine/common/con_utils.c b/engine/common/con_utils.c index a9d73096..e40d8c37 100644 --- a/engine/common/con_utils.c +++ b/engine/common/con_utils.c @@ -416,6 +416,51 @@ bool Cmd_GetMusicList( const char *s, char *completedname, int length ) return true; } +/* +===================================== +Cmd_GetSavesList + +Prints or complete movie filename +===================================== +*/ +bool Cmd_GetSavesList( const char *s, char *completedname, int length ) +{ + search_t *t; + string matchbuf; + int i, numsaves; + + t = FS_Search( va( "save/%s*.bin", s ), true ); + if( !t ) return false; + + FS_FileBase( t->filenames[0], matchbuf ); + if( completedname && length ) com.strncpy( completedname, matchbuf, length ); + if( t->numfilenames == 1 ) return true; + + for( i = 0, numsaves = 0; i < t->numfilenames; i++ ) + { + const char *ext = FS_FileExtension( t->filenames[i] ); + + if( com.stricmp( ext, "bin" )) continue; + FS_FileBase( t->filenames[i], matchbuf ); + Msg( "%16s\n", matchbuf ); + numsaves++; + } + Msg( "\n^3 %i saves found.\n", numsaves ); + Mem_Free( t ); + + // cut shortestMatch to the amount common with s + if( completedname && length ) + { + for( i = 0; matchbuf[i]; i++ ) + { + if( com.tolower( completedname[i] ) != com.tolower( matchbuf[i] )) + completedname[i] = 0; + } + } + + return true; +} + /* ===================================== Cmd_GetSoundList @@ -727,6 +772,8 @@ autocomplete_list_t cmd_list[] = { "give", Cmd_GetItemsList }, { "drop", Cmd_GetItemsList }, { "game", Cmd_GetGamesList }, +{ "save", Cmd_GetSavesList }, +{ "load", Cmd_GetSavesList }, { "map", Cmd_GetMapList }, { NULL }, // termiantor }; diff --git a/engine/common/net_msg.c b/engine/common/net_msg.c index 60e5cacb..3ce47737 100644 --- a/engine/common/net_msg.c +++ b/engine/common/net_msg.c @@ -42,7 +42,6 @@ static net_field_t ent_fields[] = { ES_FIELD(skin), NET_BYTE, false }, // 255 skins { ES_FIELD(body), NET_BYTE, false }, // 255 bodies { ES_FIELD(weaponmodel), NET_WORD, false }, // p_model index, not name -{ ES_FIELD(weaponanim), NET_WORD, false }, // 1024 sequences { ES_FIELD(weaponbody), NET_BYTE, false }, // 255 bodies { ES_FIELD(weaponskin), NET_BYTE, false }, // 255 skins { ES_FIELD(contents), NET_LONG, false }, // full range contents @@ -666,9 +665,10 @@ void _MSG_WriteDeltaEntity( entity_state_t *from, entity_state_t *to, sizebuf_t if( to == NULL ) { if( from == NULL ) return; + // a NULL to is a delta remove message MSG_WriteBits( msg, from->number, NWDesc[NET_WORD].name, NET_WORD ); - MSG_WriteBits( msg, -99, NWDesc[NET_LONG].name, NET_LONG ); + MSG_WriteBits( msg, 0xFFFF, NWDesc[NET_LONG].name, NET_LONG ); return; } @@ -730,12 +730,12 @@ void MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state_t * *to = *from; to->number = number; - if(*(int *)&msg->data[msg->readcount] == -99 ) + if(*(int *)&msg->data[msg->readcount] == 0xFFFF ) { // check for a remove MSG_ReadLong( msg ); - Mem_Set( to, 0, sizeof(*to)); - to->number = -1; + Mem_Set( to, 0, sizeof( *to )); + to->number = MAX_EDICTS - 1; // entity was removed return; } for( i = 0, field = ent_fields; field->name; i++, field++ ) diff --git a/engine/common/net_msg.h b/engine/common/net_msg.h index 28e25019..98617d3d 100644 --- a/engine/common/net_msg.h +++ b/engine/common/net_msg.h @@ -68,7 +68,6 @@ enum svc_ops_e svc_setview, // [short] entity number svc_print, // [byte] id [string] null terminated string svc_crosshairangle, // [short][short][short] - svc_time, // [long] sv.time }; // client to server diff --git a/engine/engine.plg b/engine/engine.plg index cd9d6393..45d2c2f7 100644 --- a/engine/engine.plg +++ b/engine/engine.plg @@ -6,86 +6,6 @@ --------------------Configuration: engine - Win32 Debug--------------------

Command Lines

-Creating temporary file "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP22B.tmp" with contents -[ -/nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "common" /I "server" /I "client" /I "uimenu" /I "../public" /I "../common" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR"..\temp\engine\!debug/" /Fo"..\temp\engine\!debug/" /Fd"..\temp\engine\!debug/" /FD /c -"D:\Xash3D\src_main\engine\server\sv_phys.c" -] -Creating command line "cl.exe @C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP22B.tmp" -Creating temporary file "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP22C.tmp" with contents -[ -user32.lib msvcrtd.lib /nologo /subsystem:windows /dll /incremental:yes /pdb:"..\temp\engine\!debug/engine.pdb" /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"..\temp\engine\!debug/engine.dll" /implib:"..\temp\engine\!debug/engine.lib" /pdbtype:sept -"\Xash3D\src_main\temp\engine\!debug\cinematic.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_cmds.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_demo.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_effects.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_frame.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_game.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_input.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_main.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_parse.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_phys.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_scrn.obj" -"\Xash3D\src_main\temp\engine\!debug\cl_view.obj" -"\Xash3D\src_main\temp\engine\!debug\com_library.obj" -"\Xash3D\src_main\temp\engine\!debug\con_keys.obj" -"\Xash3D\src_main\temp\engine\!debug\con_main.obj" -"\Xash3D\src_main\temp\engine\!debug\con_utils.obj" -"\Xash3D\src_main\temp\engine\!debug\engfuncs.obj" -"\Xash3D\src_main\temp\engine\!debug\engine.obj" -"\Xash3D\src_main\temp\engine\!debug\host.obj" -"\Xash3D\src_main\temp\engine\!debug\infostring.obj" -"\Xash3D\src_main\temp\engine\!debug\input.obj" -"\Xash3D\src_main\temp\engine\!debug\net_chan.obj" -"\Xash3D\src_main\temp\engine\!debug\net_huff.obj" -"\Xash3D\src_main\temp\engine\!debug\net_msg.obj" -"\Xash3D\src_main\temp\engine\!debug\sv_client.obj" -"\Xash3D\src_main\temp\engine\!debug\sv_cmds.obj" -"\Xash3D\src_main\temp\engine\!debug\sv_frame.obj" -"\Xash3D\src_main\temp\engine\!debug\sv_game.obj" -"\Xash3D\src_main\temp\engine\!debug\sv_init.obj" -"\Xash3D\src_main\temp\engine\!debug\sv_main.obj" -"\Xash3D\src_main\temp\engine\!debug\sv_move.obj" -"\Xash3D\src_main\temp\engine\!debug\sv_phys.obj" -"\Xash3D\src_main\temp\engine\!debug\sv_save.obj" -"\Xash3D\src_main\temp\engine\!debug\sv_world.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_advanced.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_audio.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_controls.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_credits.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_defaults.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_demos.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_gameoptions.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_gotosite.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_ingame.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_loadgame.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_main.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_menu.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_mods.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_multiplayer.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_network.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_options.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_performance.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_playersetup.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_qmenu.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_quit.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_savegame.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_singleplayer.obj" -"\Xash3D\src_main\temp\engine\!debug\ui_video.obj" -] -Creating command line "link.exe @C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP22C.tmp" -Creating temporary file "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP22D.bat" with contents -[ -@echo off -copy \Xash3D\src_main\temp\engine\!debug\engine.dll "D:\Xash3D\bin\engine.dll" -] -Creating command line "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP22D.bat" -Compiling... -sv_phys.c -Linking... -

Output Window

-Performing Custom Build Step on \Xash3D\src_main\temp\engine\!debug\engine.dll -Скопировано файлов: 1. diff --git a/engine/host.c b/engine/host.c index c2d10583..131c5b70 100644 --- a/engine/host.c +++ b/engine/host.c @@ -33,6 +33,19 @@ cvar_t *host_registered; // these cvars will be duplicated on each client across network int Host_ServerState( void ) { return Cvar_VariableInteger( "host_serverstate" ); } +int Host_CompareFileTime( long ft1, long ft2 ) +{ + if( ft1 < ft2 ) + { + return -1; + } + else if( ft1 > ft2 ) + { + return 1; + } + return 0; +} + void Host_InitPhysic( void ) { static physic_imp_t pi; @@ -659,6 +672,9 @@ Host_Shutdown */ void Host_Free( void ) { + if( host.state == HOST_SHUTDOWN ) + return; + host.state = HOST_SHUTDOWN; // prepare host to normal shutdown com.strncpy( host.finalmsg, "Server shutdown\n", MAX_STRING ); diff --git a/engine/server/server.h b/engine/server/server.h index 5c40383a..fc7bd403 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -60,8 +60,9 @@ typedef struct server_s sv_state_t state; // precache commands are only valid during load bool loadgame; // client begins should reuse existing entity + bool changelevel; // chnage map, reconnect clients, transfer entities, merge globals - int time; // always sv.framenum * 50 msec + int time; // sv.time += sv.frametime int frametime; int framenum; int net_framenum; @@ -70,6 +71,7 @@ typedef struct server_s int lastchecktime; // for monster ai string name; // map name, or cinematic name + string startspot; // player_start name on nextmap cmodel_t *models[MAX_MODELS]; cmodel_t *worldmodel; @@ -175,6 +177,9 @@ struct sv_priv_s vec3_t moved_angles; // push old angles physbody_t *physbody; // ptr to phys body + size_t pvdata_size; // member size of alloceed pvPrivateData + // (used by SV_CopyEdict) + // baselines entity_state_t s; // this is a player_state too }; @@ -228,6 +233,9 @@ typedef struct byte *private; // server.dll private pool byte *temppool; // for parse, save and restore edicts + edict_t *saved_edicts; // holds the client edicts during changelevel + int num_saved_edicts; + // library exports table word *ordinals; dword *funcs; @@ -288,7 +296,6 @@ extern cvar_t *sv_rollspeed; extern cvar_t *sv_maxspeed; extern cvar_t *sv_maxclients; extern cvar_t *sv_physics; -extern cvar_t *sv_showclamp; extern sv_client_t *sv_client; //=========================================================== @@ -316,10 +323,12 @@ void Master_Packet (void); // // sv_init.c // -void SV_InitGame (void); -void SV_Map( char *levelstring, char *savename ); -void SV_SpawnServer( const char *server, const char *savename ); -int SV_FindIndex (const char *name, int start, int end, bool create); +void SV_InitGame( void ); +void SV_ActivateServer( void ); +void SV_DeactivateServer( void ); +void SV_LevelInit( const char *newmap, const char *oldmap, const char *savename ); +void SV_SpawnServer( const char *server, const char *startspot ); +int SV_FindIndex( const char *name, int start, int end, bool create ); void SV_ClassifyEdict( edict_t *ent ); // @@ -365,7 +374,7 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ); void SV_SetIdealPitch( sv_client_t *cl ); // -// sv_ccmds.c +// sv_cmds.c // void SV_Status_f( void ); void SV_Newgame_f( void ); @@ -384,8 +393,11 @@ void SV_LoadProgs( const char *name ); void SV_UnloadProgs( void ); void SV_FreeEdicts( void ); void SV_InitEdict( edict_t *pEdict ); +bool SV_CopyEdict( edict_t *out, edict_t *in ); void SV_ConfigString( int index, const char *val ); void SV_SetModel( edict_t *ent, const char *name ); +void SV_PopClients( void ); +void SV_PushClients( void ); void SV_CreatePhysBody( edict_t *ent ); void SV_SetPhysForce( edict_t *ent ); void SV_SetMassCentre( edict_t *ent); @@ -396,6 +408,7 @@ void SV_SpawnEntities( const char *mapname, script_t *entities ); edict_t* SV_AllocPrivateData( edict_t *ent, string_t className ); string_t SV_AllocString( const char *szValue ); const char *SV_GetString( string_t iString ); +bool SV_MapIsValid( const char *filename, const char *spawn_entity ); void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float attn, int flags, int pitch ); _inline edict_t *SV_EDICT_NUM( int n, const char * file, const int line ) @@ -425,9 +438,12 @@ void SV_TouchTriggers (edict_t *ent); // // sv_save.c // -void SV_WriteSaveFile( const char *name, bool autosave ); +void SV_MergeLevelFile( const char *name ); +void SV_ChangeLevel( bool bUseLandmark, const char *mapname, const char *start ); +void SV_WriteSaveFile( const char *name, bool autosave, bool bUseLandmark ); void SV_ReadSaveFile( const char *name ); void SV_ReadLevelFile( const char *name ); +const char *SV_GetLatestSave( void ); //============================================================ // diff --git a/engine/server/sv_client.c b/engine/server/sv_client.c index caaf2506..422c064e 100644 --- a/engine/server/sv_client.c +++ b/engine/server/sv_client.c @@ -560,7 +560,7 @@ void SV_PutClientInServer( edict_t *ent ) ent->pvServerData->s.ed_type = ED_CLIENT; // init edict type ent->free = false; - if( !sv.loadgame ) + if( !sv.changelevel && !sv.loadgame ) { // fisrt entering svgame.dllFuncs.pfnClientPutInServer( ent ); @@ -582,6 +582,10 @@ void SV_PutClientInServer( edict_t *ent ) ent->pvServerData->physbody = pe->CreatePlayer( ent, SV_GetModelPtr( ent ), ent->v.origin, ent->v.m_pmatrix ); Mem_EmptyPool( svgame.temppool ); // all tempstrings can be freed now + // clear any temp states + sv.changelevel = false; + sv.loadgame = false; + MsgDev( D_INFO, "level loaded at %g sec\n", (Sys_Milliseconds() - svs.timestart) * 0.001f ); } @@ -617,9 +621,9 @@ void SV_New_f( sv_client_t *cl ) MSG_WriteByte( &cl->netchan.message, svc_serverdata ); MSG_WriteLong( &cl->netchan.message, PROTOCOL_VERSION); MSG_WriteLong( &cl->netchan.message, svs.spawncount ); - MSG_WriteLong( &cl->netchan.message, sv.frametime ); MSG_WriteShort( &cl->netchan.message, playernum ); MSG_WriteString( &cl->netchan.message, sv.configstrings[CS_NAME] ); + MSG_WriteString( &cl->netchan.message, STRING( EDICT_NUM( 0 )->v.message )); // Map Message // game server if( sv.state == ss_active ) @@ -632,7 +636,7 @@ void SV_New_f( sv_client_t *cl ) // begin fetching configstrings MSG_WriteByte( &cl->netchan.message, svc_stufftext ); - MSG_WriteString( &cl->netchan.message, va("cmd configstrings %i %i\n", svs.spawncount, 0 )); + MSG_WriteString( &cl->netchan.message, va( "cmd configstrings %i %i\n", svs.spawncount, 0 )); } } @@ -1066,7 +1070,7 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) Cmd_TokenizeString( s ); c = Cmd_Argv( 0 ); - MsgDev( D_INFO, "SV_ConnectionlessPacket: %s : %s\n", NET_AdrToString(from), c); + MsgDev( D_INFO, "SV_ConnectionlessPacket: %s : %s\n", NET_AdrToString( from ), c ); if( !com.strcmp( c, "ping" )) SV_Ping( from ); else if( !com.strcmp( c, "ack" )) SV_Ack( from ); diff --git a/engine/server/sv_cmds.c b/engine/server/sv_cmds.c index 51d501e0..675be4c9 100644 --- a/engine/server/sv_cmds.c +++ b/engine/server/sv_cmds.c @@ -193,6 +193,7 @@ For development work void SV_Map_f( void ) { string filename; + char *spawn_entity; if( Cmd_Argc() != 2 ) { @@ -200,29 +201,41 @@ void SV_Map_f( void ) return; } - com.snprintf( filename, MAX_STRING, "%s.bsp", Cmd_Argv(1)); - if( !FS_FileExists( va("maps/%s", filename ))) + // determine spawn entity classname + if( Cvar_VariableInteger( "deathmatch" )) + spawn_entity = GI->dm_entity; + else if( Cvar_VariableInteger( "coop" )) + spawn_entity = GI->coop_entity; + else if( Cvar_VariableInteger( "teamplay" )) + spawn_entity = GI->team_entity; + else spawn_entity = GI->sp_entity; + + com.strncpy( filename, Cmd_Argv( 1 ), sizeof( filename )); + if( !SV_MapIsValid( filename, spawn_entity )) { - Msg( "Can't loading %s\n", filename ); + Msg( "SV_NewMap: invalid map %s\n", filename ); return; } - SV_InitGame(); // reset previous state + sv.loadgame = false; // set right state + sv.changelevel = false; + + if( com.strcmp( sv.name, filename )) + SV_InitGame (); - SV_BroadcastCommand( "changing\n" ); - SV_SendClientMessages(); SV_SpawnServer( filename, NULL ); - SV_BroadcastCommand( "reconnect\n" ); - - // archive server state - com.strncpy( svs.mapname, filename, sizeof( svs.mapname ) - 1 ); + SV_LevelInit( filename, NULL, NULL ); + SV_ActivateServer (); } void SV_Newgame_f( void ) { - // FIXME: do some clear operations - // FIXME: parse newgame script - Cbuf_ExecuteText(EXEC_APPEND, va("map %s\n", GI->startmap )); + com.strncpy( host.finalmsg, "end game", MAX_STRING ); + SV_Shutdown( false ); // completely shutdown server, disconncet clients and unload progs + + // FIXME: parse newgame script or somewhat + + Cbuf_ExecuteText( EXEC_APPEND, va( "map %s\n", GI->startmap )); } /* @@ -241,18 +254,20 @@ void SV_Load_f( void ) return; } - com.snprintf( filename, MAX_STRING, "%s.bin", Cmd_Argv( 1 )); - if(!FS_FileExists( va( "save/%s", filename ))) + com.strncpy( filename, Cmd_Argv( 1 ), sizeof( filename )); + if(WAD_Check( va( "save/%s.bin", filename )) != 1 ) { - Msg("Can't loading %s\n", filename ); + Msg( "Can't loading %s\n", filename ); return; } + sv.loadgame = true; // set right state + sv.changelevel = false; + SV_ReadSaveFile( filename ); - SV_BroadcastCommand( "changing\n" ); - SV_SendClientMessages(); - SV_SpawnServer( svs.mapname, filename ); - SV_BroadcastCommand( "reconnect\n" ); + SV_SpawnServer( svs.mapname, NULL ); + SV_LevelInit( svs.mapname, NULL, filename ); + SV_ActivateServer(); } /* @@ -265,10 +280,10 @@ void SV_Save_f( void ) { if( Cmd_Argc() != 2 ) { - Msg ("Usage: save \n"); + Msg( "Usage: save \n" ); return; } - SV_WriteSaveFile( Cmd_Argv( 1 ), false ); + SV_WriteSaveFile( Cmd_Argv( 1 ), false, true ); } /* @@ -298,7 +313,7 @@ SV_AutoSave_f */ void SV_AutoSave_f( void ) { - SV_WriteSaveFile( "autosave", true ); + SV_WriteSaveFile( "autosave", true, true ); } /* @@ -310,52 +325,37 @@ Saves the state of the map just being exited and goes to a new map. */ void SV_ChangeLevel_f( void ) { - string filename; + char *spawn_entity; int c = Cmd_Argc(); - if( c != 2 && c != 3 ) + // determine spawn entity classname + if( Cvar_VariableInteger( "deathmatch" )) + spawn_entity = GI->dm_entity; + else if( Cvar_VariableInteger( "coop" )) + spawn_entity = GI->coop_entity; + else if( Cvar_VariableInteger( "teamplay" )) + spawn_entity = GI->team_entity; + else spawn_entity = GI->sp_entity; + + if( !SV_MapIsValid( Cmd_Argv( 1 ), spawn_entity )) { - Msg ("Usage: changelevel [landmark]\n"); + Msg( "SV_ChangeLevel: invalid map %s\n", Cmd_Argv( 1 )); return; } - com.snprintf( filename, MAX_STRING, "%s.bsp", Cmd_Argv(1)); - if(!FS_FileExists(va("maps/%s", filename ))) + if( sv.state != ss_active ) { - Msg("Can't loading %s\n", filename ); + // just load map + Cbuf_AddText( va( "map %s\n", Cmd_Argv( 1 ))); return; } - if( sv.state == ss_active ) + switch( c ) { - bool *savedFree; - sv_client_t *cl; - int i; - - // clear all the client free flags before saving so that - // when the level is re-entered, the clients will spawn - // at spawn points instead of occupying body shells - savedFree = Z_Malloc( sv_maxclients->integer * sizeof( bool )); - for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) - { - savedFree[i] = cl->edict->free; - cl->edict->free = true; - } - SV_WriteSaveFile( "autosave", true ); - // we must restore these for clients to transfer over correctly - for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) - cl->edict->free = savedFree[i]; - Mem_Free( savedFree ); + case 2: SV_ChangeLevel( false, Cmd_Argv( 1 ), NULL ); break; + case 3: SV_ChangeLevel( true, Cmd_Argv( 1 ), Cmd_Argv( 2 )); break; + default: Msg( "Usage: changelevel [landmark]\n" ); break; } - - SV_InitGame(); // reset previous state - SV_BroadcastCommand("changing\n"); - SV_SendClientMessages(); - SV_SpawnServer( filename, NULL ); - SV_BroadcastCommand ("reconnect\n"); - - // archive server state - com.strncpy( svs.mapname, filename, sizeof( svs.mapname ) - 1 ); } /* @@ -377,6 +377,21 @@ void SV_Restart_f( void ) Cbuf_AddText( va( "map %s\n", filename )); } +void SV_Reload_f( void ) +{ + const char *save; + string loadname; + + if( sv.state != ss_active ) return; + save = SV_GetLatestSave(); + if( save ) + { + FS_FileBase( save, loadname ); + Cbuf_AddText( va( "load %s\n", loadname )); + } + else Cbuf_AddText( "newgame\n" ); // begin new game +} + /* ================== SV_Kick_f @@ -564,6 +579,7 @@ void SV_InitOperatorCommands( void ) Cmd_AddCommand( "newgame", SV_Newgame_f, "begin new game" ); Cmd_AddCommand( "changelevel", SV_ChangeLevel_f, "changing level" ); Cmd_AddCommand( "restart", SV_Restart_f, "restarting current level" ); + Cmd_AddCommand( "reload", SV_Reload_f, "continue from latest save or restart level" ); if( host.type == HOST_DEDICATED ) { @@ -591,6 +607,7 @@ void SV_KillOperatorCommands( void ) Cmd_RemoveCommand( "newgame" ); Cmd_RemoveCommand( "changelevel" ); Cmd_RemoveCommand( "restart" ); + Cmd_RemoveCommand( "reload" ); Cmd_RemoveCommand( "sectorlist" ); if( host.type == HOST_DEDICATED ) diff --git a/engine/server/sv_frame.c b/engine/server/sv_frame.c index 74bd0a2f..5a1d37f9 100644 --- a/engine/server/sv_frame.c +++ b/engine/server/sv_frame.c @@ -141,13 +141,17 @@ void SV_EmitPacketEntities( client_frame_t *from, client_frame_t *to, sizebuf_t if( newnum == oldnum ) { + bool newentity = false; + // delta update from old position // because the force parm is false, this will not result // in any bytes being emited if the entity has not changed at all // note that players are always 'newentities', this updates their oldorigin always // and prevents warping - MSG_WriteDeltaEntity( oldent, newent, msg, false, - (newent->ed_type == ED_CLIENT) || (newent->ed_type == ED_PORTAL)); + if( newent->ed_type == ED_CLIENT ) newentity = true; + if( newent->ed_type == ED_PORTAL ) newentity = true; + + MSG_WriteDeltaEntity( oldent, newent, msg, false, newentity ); oldindex++; newindex++; continue; @@ -358,11 +362,9 @@ void SV_WriteFrameToClient( sv_client_t *cl, sizebuf_t *msg ) } } - MSG_WriteByte( msg, svc_time ); - MSG_WriteLong( msg, sv.time ); // send a servertime before each frame - MSG_WriteByte( msg, svc_frame ); MSG_WriteLong( msg, sv.framenum ); + MSG_WriteLong( msg, sv.time ); // send a servertime each frame MSG_WriteLong( msg, sv.frametime ); MSG_WriteLong( msg, lastframe ); // what we are delta'ing from MSG_WriteByte( msg, cl->surpressCount ); // rate dropped packets @@ -372,14 +374,14 @@ void SV_WriteFrameToClient( sv_client_t *cl, sizebuf_t *msg ) MSG_WriteByte( msg, frame->areabits_size ); // never more than 255 bytes MSG_WriteData( msg, frame->areabits, frame->areabits_size ); + // delta encode the entities + SV_EmitPacketEntities( oldframe, frame, msg ); + // just send an client index // it's safe, because NUM_FOR_EDICT always equal ed->serialnumber, // thats shared across network MSG_WriteByte( msg, svc_playerinfo ); MSG_WriteByte( msg, frame->index ); - - // delta encode the entities - SV_EmitPacketEntities( oldframe, frame, msg ); } @@ -559,6 +561,8 @@ void SV_SendClientMessages( void ) sv_client_t *cl; int i; + if( sv.state == ss_dead ) return; + // send a message to each connected client for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) { diff --git a/engine/server/sv_game.c b/engine/server/sv_game.c index fd85b712..71821663 100644 --- a/engine/server/sv_game.c +++ b/engine/server/sv_game.c @@ -561,6 +561,126 @@ static bool SV_EntitiesIn( int mode, vec3_t v1, vec3_t v2 ) return true; } +bool SV_MapIsValid( const char *filename, const char *spawn_entity ) +{ + file_t *f; + string entfilename; + int ver = -1, lumpofs = 0, lumplen = 0; + script_t *ents = NULL; + byte buf[MAX_SYSPATH]; // 1 kb + bool result = false; + + f = FS_Open( va( "maps/%s.bsp", filename ), "rb" ); + + if( f ) + { + string check_entity; + + Mem_Set( buf, 0, MAX_SYSPATH ); + FS_Read( f, buf, MAX_SYSPATH ); + + if( !memcmp( buf, "IBSP", 4 ) || !memcmp( buf, "RBSP", 4 ) || !memcmp( buf, "FBSP", 4 )) + { + dheader_t *header = (dheader_t *)buf; + ver = LittleLong(((int *)buf)[1]); + + switch( ver ) + { + case Q3IDBSP_VERSION: // quake3 arena + case RTCWBSP_VERSION: // return to castle wolfenstein + case RFIDBSP_VERSION: // raven or qfusion bsp + lumpofs = LittleLong( header->lumps[LUMP_ENTITIES].fileofs ); + lumplen = LittleLong( header->lumps[LUMP_ENTITIES].filelen ); + break; + default: + FS_Close( f ); + return false; + } + } + else + { + FS_Close( f ); + return false; + } + + com.strncpy( entfilename, va( "maps/%s.ent", filename ), sizeof( entfilename )); + ents = Com_OpenScript( entfilename, NULL, 0 ); + + if( !ents && lumplen >= 10 ) + { + char *entities = NULL; + + FS_Seek( f, lumpofs, SEEK_SET ); + entities = (char *)Z_Malloc( lumplen + 1 ); + FS_Read( f, entities, lumplen ); + ents = Com_OpenScript( "ents", entities, lumplen + 1 ); + Mem_Free( entities ); // no reason to keep it + } + + if( ents ) + { + // if there are entities to parse, a missing message key just + // means there is no title, so clear the message string now + token_t token; + + check_entity[0] = 0; + while( Com_ReadToken( ents, SC_ALLOW_NEWLINES|SC_PARSE_GENERIC, &token )) + { + if( !com.strcmp( token.string, "classname" )) + { + // check classname for spawn entity + Com_ReadString( ents, false, check_entity ); + if( !com.stricmp( spawn_entity, check_entity )) + { + result = true; + break; + } + } + } + Com_CloseScript( ents ); + } + if( f ) FS_Close( f ); + } + return result; +} + +void SV_PushClients( void ) +{ + edict_t *in, *out; + int i; + + svgame.num_saved_edicts = 0; + + // hold the clients in other place + for( i = 0; i < sv_maxclients->integer; i++ ) + { + in = EDICT_NUM( i + 1 ); + out = svgame.saved_edicts + i; + + if( SV_CopyEdict( out, in )) + svgame.num_saved_edicts++; + } +} + +void SV_PopClients( void ) +{ + edict_t *in, *out; + int i; + + // copy clients back to sv.edicts + for( i = 0; i < svgame.num_saved_edicts; i++ ) + { + in = svgame.saved_edicts + i; + out = EDICT_NUM( i + 1 ); + + if( SV_CopyEdict( out, in )) + svgame.globals->numClients++; + if( svgame.globals->numClients > sv_maxclients->integer ) + break; + } + svgame.num_saved_edicts = 0; +} + void SV_InitEdict( edict_t *pEdict ) { Com_Assert( pEdict == NULL ); @@ -625,6 +745,41 @@ edict_t *SV_AllocEdict( void ) return pEdict; } +bool SV_CopyEdict( edict_t *out, edict_t *in ) +{ + size_t pvdata_size = 0; + + if( in == NULL ) + return false; // failed to copy + if( in->free ) return false; // we can't proceed freed edicts + + // important! we save copy off, not in sv.edicts + if( out == NULL ) Host_Error( "SV_CopyEdict: dest == NULL\n" ); + + if( in->pvServerData ) + { + if( out->pvServerData == NULL ) + out->pvServerData = (sv_priv_t *)Mem_Alloc( svgame.mempool, sizeof( sv_priv_t )); + Mem_Copy( out->pvServerData, in->pvServerData, sizeof( sv_priv_t )); + pvdata_size = in->pvServerData->pvdata_size; + } + if( in->pvPrivateData ) + { + if( pvdata_size > 0 ) + { + out->pvPrivateData = (void *)Mem_Realloc( svgame.mempool, out->pvPrivateData, pvdata_size ); + Mem_Copy( out->pvPrivateData, in->pvPrivateData, pvdata_size ); + } + else MsgDev( D_ERROR, "SV_CopyEdict: can't copy pvPrivateData\n" ); + } + + Mem_Copy( &out->v, &in->v, sizeof( entvars_t )); // copy entvars + out->serialnumber = in->serialnumber; // copy serialnumber + out->v.pContainingEntity = out; // merge contain entity + + return true; +} + edict_t* SV_AllocPrivateData( edict_t *ent, string_t className ) { const char *pszClassName; @@ -664,7 +819,7 @@ edict_t* SV_AllocPrivateData( edict_t *ent, string_t className ) void SV_FreeEdicts( void ) { - int i; + int i = 0; edict_t *ent; for( i = 0; i < svgame.globals->numEntities; i++ ) @@ -673,19 +828,6 @@ void SV_FreeEdicts( void ) if( ent->free ) continue; SV_FreeEdict( ent ); } - - if( !sv.loadgame ) - { - // leave unchanged, because we wan't load it twice - StringTable_Clear( svgame.hStringTable ); - svgame.dllFuncs.pfnServerDeactivate(); - } - - svgame.globals->maxEntities = GI->max_edicts; - svgame.globals->maxClients = sv_maxclients->integer; - svgame.globals->numEntities = svgame.globals->maxClients + 1; // clients + world - svgame.globals->numClients = 0; - svgame.globals->mapname = 0; } /* @@ -837,10 +979,11 @@ pfnChangeLevel */ void pfnChangeLevel( const char* s1, const char* s2 ) { - string changelevel_cmd; + // make sure we don't issue two changelevels + if( sv.changelevel ) return; - com.snprintf( changelevel_cmd, MAX_STRING, "changelevel %s %s\n", s1, s2 ); - Cbuf_ExecuteText( EXEC_APPEND, changelevel_cmd ); + if( !s2 ) Cbuf_AddText( va( "changelevel %s\n", s1 )); // Quake changlevel + else Cbuf_AddText( va( "changelevel %s %s\n", s1, s2 )); // Half-Life changelevel } /* @@ -1174,12 +1317,14 @@ pfnEntitiesInPVS edict_t* pfnEntitiesInPVS( edict_t *pplayer ) { edict_t *pEdict, *chain; - int i, numents; + int i; chain = NULL; - numents = svgame.globals->numEntities; - for( i = svgame.globals->maxClients; i < numents; i++ ) + if( !pplayer || pplayer->free ) + return chain; + + for( i = svgame.globals->maxClients; i < svgame.globals->numEntities; i++ ) { pEdict = EDICT_NUM( i ); if( pEdict->free ) continue; @@ -1202,12 +1347,14 @@ pfnEntitiesInPHS edict_t* pfnEntitiesInPHS( edict_t *pplayer ) { edict_t *pEdict, *chain; - int i, numents; + int i; chain = NULL; - numents = svgame.globals->numEntities; - for( i = svgame.globals->maxClients; i < numents; i++ ) + if( !pplayer || pplayer->free ) + return chain; + + for( i = svgame.globals->maxClients; i < svgame.globals->numEntities; i++ ) { pEdict = EDICT_NUM( i ); if( pEdict->free ) continue; @@ -1832,11 +1979,11 @@ pfnMessageBegin ============= */ -void pfnMessageBegin( int msg_dest, int msg_type, const float *pOrigin, edict_t *ed ) +void pfnMessageBegin( int msg_dest, int msg_num, const float *pOrigin, edict_t *ed ) { - // some users can send message with engine index + // some malicious users can send message with engine index // reduce number to avoid overflow problems or cheating - svgame.msg_index = bound( svc_bad, msg_type, svc_nop ); + svgame.msg_index = bound( svc_bad, msg_num, svc_nop ); if( svgame.msg_index >= 0 && svgame.msg_index < MAX_USER_MESSAGES ) svgame.msg_name = sv.configstrings[CS_USER_MESSAGES + svgame.msg_index]; @@ -1848,7 +1995,7 @@ void pfnMessageBegin( int msg_dest, int msg_type, const float *pOrigin, edict_t if( pOrigin ) VectorCopy( pOrigin, svgame.msg_org ); else VectorClear( svgame.msg_org ); - if( svgame.msg_sizes[msg_type] == -1 ) + if( svgame.msg_sizes[msg_num] == -1 ) { // variable sized messages sent size as first byte svgame.msg_size_index = sv.multicast.cursize; @@ -1889,17 +2036,23 @@ void pfnMessageEnd( void ) else if( svgame.msg_size_index != -1 ) { // variable sized message - if( svgame.msg_realsize >= 255 ) + if( svgame.msg_realsize > 255 ) { MsgDev( D_ERROR, "SV_Message: %s too long (more than 255 bytes)\n", name ); MSG_Clear( &sv.multicast ); return; } + else if( svgame.msg_realsize <= 0 ) + { + MsgDev( D_ERROR, "SV_Message: %s writes NULL message\n", name ); + MSG_Clear( &sv.multicast ); + return; + } sv.multicast.data[svgame.msg_size_index] = svgame.msg_realsize; } else { - // this never happen + // this should never happen MsgDev( D_ERROR, "SV_Message: %s have encountered error\n", name ); MSG_Clear( &sv.multicast ); return; @@ -1978,7 +2131,8 @@ pfnWriteCoord */ void pfnWriteCoord( float flValue ) { - union { float f; int l; } dat; + ftol_t dat; + dat.f = flValue; _MSG_WriteBits( &sv.multicast, dat.l, svgame.msg_name, NET_FLOAT, __FILE__, __LINE__ ); svgame.msg_realsize += 4; @@ -2010,7 +2164,7 @@ void pfnWriteString( const char *sz ) MSG_WriteString( &sv.multicast, sz ); total_size = sv.multicast.cursize - cur_size; - // some messages with constant string length can be marked as known sized + // NOTE: some messages with constant string length can be marked as known sized svgame.msg_realsize += total_size; } @@ -2022,7 +2176,8 @@ pfnWriteEntity */ void pfnWriteEntity( int iValue ) { - if( iValue < 0 || iValue > svgame.globals->numEntities ) + // edict -1 it's a viewmodel entity + if( iValue < -1 || iValue > svgame.globals->numEntities ) Host_Error( "MSG_WriteEntity: invalid entnumber %d\n", iValue ); MSG_WriteShort( &sv.multicast, iValue ); svgame.msg_realsize += 2; @@ -2081,9 +2236,12 @@ pfnPvAllocEntPrivateData void *pfnPvAllocEntPrivateData( edict_t *pEdict, long cb ) { Com_Assert( pEdict == NULL ); + Com_Assert( pEdict->free ); + Com_Assert( pEdict->pvServerData == NULL ); // to avoid multiple alloc pEdict->pvPrivateData = (void *)Mem_Realloc( svgame.private, pEdict->pvPrivateData, cb ); + pEdict->pvServerData->pvdata_size = cb; return pEdict->pvPrivateData; } @@ -2190,6 +2348,8 @@ pfnPEntityOfEntIndex */ edict_t* pfnPEntityOfEntIndex( int iEntIndex ) { + if( iEntIndex < 0 || iEntIndex >= svgame.globals->numEntities ) + return NULL; // out of range return EDICT_NUM( iEntIndex ); } @@ -2538,18 +2698,19 @@ pfnCompareFileTime */ int pfnCompareFileTime( const char *filename1, const char *filename2, int *iCompare ) { - int time1 = FS_FileTime( filename1 ); - int time2 = FS_FileTime( filename2 ); + int bRet = 0; - if( iCompare ) + *iCompare = 0; + + if( filename1 && filename2 ) { - if( time1 > time2 ) - *iCompare = 1; - else if( time1 < time2 ) - *iCompare = -1; - else *iCompare = 0; + long ft1 = FS_FileTime( filename1 ); + long ft2 = FS_FileTime( filename2 ); + + *iCompare = Host_CompareFileTime( ft1, ft2 ); + bRet = 1; } - return (time1 != time2); + return bRet; } /* @@ -2596,88 +2757,18 @@ vaild map must contain one info_player_deatchmatch */ int pfnIsMapValid( char *filename ) { - file_t *f; - string entfilename; - int ver = -1, lumpofs = 0, lumplen = 0; - script_t *ents = NULL; - byte buf[MAX_SYSPATH]; // 1 kb - bool result = false; - - f = FS_Open( va( "maps/%s.bsp", filename ), "rb" ); + char *spawn_entity; - if( f ) - { - string dm_entity; + // determine spawn entity classname + if( Cvar_VariableInteger( "deathmatch" )) + spawn_entity = GI->dm_entity; + else if( Cvar_VariableInteger( "coop" )) + spawn_entity = GI->coop_entity; + else if( Cvar_VariableInteger( "teamplay" )) + spawn_entity = GI->team_entity; + else spawn_entity = GI->sp_entity; - Mem_Set( buf, 0, MAX_SYSPATH ); - FS_Read( f, buf, MAX_SYSPATH ); - - if( !memcmp( buf, "IBSP", 4 ) || !memcmp( buf, "RBSP", 4 ) || !memcmp( buf, "FBSP", 4 )) - { - dheader_t *header = (dheader_t *)buf; - ver = LittleLong(((int *)buf)[1]); - - switch( ver ) - { - case Q3IDBSP_VERSION: // quake3 arena - case RTCWBSP_VERSION: // return to castle wolfenstein - case RFIDBSP_VERSION: // raven or qfusion bsp - lumpofs = LittleLong( header->lumps[LUMP_ENTITIES].fileofs ); - lumplen = LittleLong( header->lumps[LUMP_ENTITIES].filelen ); - break; - default: - FS_Close( f ); - return false; - } - } - else - { - FS_Close( f ); - return false; - } - - com.strncpy( entfilename, va( "maps/%s.ent", filename ), sizeof( entfilename )); - ents = Com_OpenScript( entfilename, NULL, 0 ); - - if( !ents && lumplen >= 10 ) - { - char *entities = NULL; - - FS_Seek( f, lumpofs, SEEK_SET ); - entities = (char *)Z_Malloc( lumplen + 1 ); - FS_Read( f, entities, lumplen ); - ents = Com_OpenScript( "ents", entities, lumplen + 1 ); - Mem_Free( entities ); // no reason to keep it - } - - if( ents ) - { - // if there are entities to parse, a missing message key just - // means there is no title, so clear the message string now - token_t token; - - dm_entity[0] = 0; - while( Com_ReadToken( ents, SC_ALLOW_NEWLINES|SC_PARSE_GENERIC, &token )) - { - if( !com.strcmp( token.string, "{" )) continue; - else if( !com.strcmp( token.string, "}" )) break; - else if( !com.strcmp( token.string, "classname" )) - { - // check classname for deathmath entity - Com_ReadString( ents, false, dm_entity ); - if( !com.stricmp( GI->dm_entity, dm_entity )) - { - // FIXME: use count of spawnpoints as returned result ? - result = true; - break; - } - } - } - Com_CloseScript( ents ); - } - if( f ) FS_Close( f ); - } - return result; + return SV_MapIsValid( filename, spawn_entity ); } /* @@ -3175,12 +3266,11 @@ void SV_SpawnEntities( const char *mapname, script_t *entities ) MsgDev( D_NOTE, "SV_SpawnEntities()\n" ); ent = EDICT_NUM( 0 ); - SV_InitEdict( ent ); - ent->v.model = MAKE_STRING( sv.configstrings[CS_MODELS] ); + if( ent->free ) SV_InitEdict( ent ); + ent->v.model = MAKE_STRING( sv.configstrings[CS_MODELS+1] ); ent->v.modelindex = 1; // world model ent->v.solid = SOLID_BSP; ent->v.movetype = MOVETYPE_PUSH; - ent->free = false; SV_ConfigString( CS_GRAVITY, sv_gravity->string ); SV_ConfigString( CS_MAXVELOCITY, sv_maxvelocity->string ); @@ -3195,37 +3285,42 @@ void SV_SpawnEntities( const char *mapname, script_t *entities ) SV_ConfigString( CS_MAXEDICTS, va( "%i", GI->max_edicts )); svgame.globals->mapname = MAKE_STRING( sv.name ); + svgame.globals->startspot = MAKE_STRING( sv.startspot ); svgame.globals->time = sv.time * 0.001f; // spawn the rest of the entities on the map SV_LoadFromFile( entities ); // set client fields on player ents - for( i = 0; i < svgame.globals->maxClients; i++ ) + if( !sv.loadgame && !sv.changelevel ) { - // setup all clients - ent = EDICT_NUM( i + 1 ); - SV_InitEdict( ent ); - ent->pvServerData->client = svs.clients + i; - ent->pvServerData->client->edict = ent; - svgame.globals->numClients++; + for( i = 0; i < svgame.globals->maxClients; i++ ) + { + // setup all clients + ent = EDICT_NUM( i + 1 ); + SV_InitEdict( ent ); + ent->pvServerData->client = svs.clients + i; + ent->pvServerData->client->edict = ent; + svgame.globals->numClients++; + } } MsgDev( D_INFO, "Total %i entities spawned\n", svgame.globals->numEntities ); } void SV_UnloadProgs( void ) { - sv.loadgame = false; - SV_FreeEdicts(); + SV_DeactivateServer (); - svgame.dllFuncs.pfnGameShutdown(); + svgame.dllFuncs.pfnGameShutdown (); - Sys_FreeNameFuncGlobals(); + Sys_FreeNameFuncGlobals (); Com_FreeLibrary( svgame.hInstance ); Mem_FreePool( &svgame.mempool ); Mem_FreePool( &svgame.private ); Mem_FreePool( &svgame.temppool ); svgame.hInstance = NULL; + + Mem_Set( &svgame, 0, sizeof( svgame )); } void SV_LoadProgs( const char *name ) @@ -3276,6 +3371,7 @@ void SV_LoadProgs( const char *name ) svgame.globals->maxEntities = GI->max_edicts; svgame.globals->maxClients = sv_maxclients->integer; svgame.edicts = Mem_Alloc( svgame.mempool, sizeof( edict_t ) * svgame.globals->maxEntities ); + svgame.saved_edicts = Mem_Alloc( svgame.mempool, sizeof( edict_t ) * svgame.globals->maxClients ); svgame.globals->numEntities = svgame.globals->maxClients + 1; // clients + world svgame.globals->numClients = 0; for( i = 0, e = svgame.edicts; i < svgame.globals->maxEntities; i++, e++ ) diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index fd9f410e..a84e3e56 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -144,6 +144,96 @@ void SV_CheckForSavegame( const char *savename ) } } +/* +================ +SV_ActivateServer + +activate server on changed map, run physics +================ +*/ +void SV_ActivateServer( void ) +{ + int i; + + // Activate the DLL server code + svgame.dllFuncs.pfnServerActivate( svgame.edicts, svgame.globals->numEntities, svgame.globals->maxClients ); + + // all precaches are complete + sv.state = ss_active; + Host_SetServerState( sv.state ); + + // create a baseline for more efficient communications + SV_CreateBaseline(); + + // run two frames to allow everything to settle + for( i = 0; i < 2; i++ ) + { + sv.frametime = 100; + SV_Physics(); + } + + // tell what kind of server has been started. + if( svgame.globals->maxClients > 1 ) + { + MsgDev( D_INFO, "%i player server started\n", svgame.globals->maxClients ); + } + else + { + MsgDev( D_INFO, "Game started\n" ); + } + + // set serverinfo variable + Cvar_FullSet( "mapname", sv.name, CVAR_SERVERINFO|CVAR_INIT ); + + pe->EndRegistration (); // free unused models +} + +/* +================ +SV_DeactivateServer + +deactivate server, free edicts stringtables etc +================ +*/ +void SV_DeactivateServer( void ) +{ + SV_FreeEdicts (); + + Cvar_SetValue( "paused", 0 ); + + // leave unchanged, because we wan't load it twice + if( !sv.loadgame ) StringTable_Clear( svgame.hStringTable ); + + svgame.dllFuncs.pfnServerDeactivate(); + + svgame.globals->maxEntities = GI->max_edicts; + svgame.globals->maxClients = sv_maxclients->integer; + svgame.globals->numEntities = svgame.globals->maxClients + 1; // clients + world + svgame.globals->numClients = 0; + svgame.globals->mapname = 0; +} + +/* +================ +SV_LevelInit + +Spawn all entities +================ +*/ +void SV_LevelInit( const char *newmap, const char *oldmap, const char *savename ) +{ + if( sv.loadgame ) + { + if( savename ) SV_ReadLevelFile( savename ); + else SV_SpawnEntities( newmap, pe->GetEntityScript( )); + } + else if( sv.changelevel ) + { + SV_ReadSaveFile( savename ); // initialize StringTable and globals + SV_MergeLevelFile( savename );// combine moveable entities with newmap + } + else SV_SpawnEntities( newmap, pe->GetEntityScript()); +} /* ================ @@ -154,24 +244,43 @@ clients along with it. ================ */ -void SV_SpawnServer( const char *server, const char *savename ) +void SV_SpawnServer( const char *server, const char *startspot ) { uint i, checksum; + int current_skill; + int loadgame, changelevel; - Msg( "SpawnServer [%s]\n", server ); + Msg( "SpawnServer [^2%s^7]\n", server ); + + if( sv.state == ss_dead && !sv.loadgame ) + SV_InitGame(); // the game is just starting + + SV_BroadcastCommand( "changing\n" ); + + if( sv.state == ss_active ) + { + SV_BroadcastCommand( "reconnect\n" ); + SV_SendClientMessages(); + SV_DeactivateServer (); // server is shutting down ... + } svs.timestart = Sys_Milliseconds(); svs.spawncount++; // any partially connected client will be restarted + + // save state + loadgame = sv.loadgame; + changelevel = sv.changelevel; + sv.state = ss_dead; Host_SetServerState( sv.state ); + Mem_Set( &sv, 0, sizeof( sv )); // wipe the entire per-level structure - // wipe the entire per-level structure - Mem_Set( &sv, 0, sizeof( sv )); + // restore state + sv.loadgame = loadgame; + sv.changelevel = changelevel; - // save name for levels that don't set message - com.strncpy( sv.configstrings[CS_NAME], server, CS_SIZE ); + // initialize multicast buffer MSG_Init( &sv.multicast, sv.multicast_buf, sizeof( sv.multicast_buf )); - com.strcpy( sv.name, server ); // leave slots at start for clients only for( i = 0; i < sv_maxclients->integer; i++ ) @@ -182,12 +291,23 @@ void SV_SpawnServer( const char *server, const char *savename ) svs.clients[i].lastframe = -1; } - sv.time = 1000; - - com.strncpy( sv.name, server, MAX_STRING ); - FS_FileBase(server, sv.configstrings[CS_NAME]); + // make cvars consistant + if( Cvar_VariableInteger( "coop" )) Cvar_SetValue( "deathmatch", 0 ); + current_skill = Q_rint( Cvar_VariableValue( "skill" )); + if( current_skill < 0 ) current_skill = 0; + if( current_skill > 3 ) current_skill = 3; - com.sprintf( sv.configstrings[CS_MODELS+1], "maps/%s", server ); + Cvar_SetValue( "skill", (float)current_skill ); + + sv.time = 1000; + + FS_FileBase( server, sv.name ); // make sure what server name doesn't contain path and extension + com.strncpy( svs.mapname, sv.name, sizeof( svs.mapname )); + com.strncpy( sv.configstrings[CS_NAME], sv.name, CS_SIZE); + if( startspot ) com.strncpy( sv.startspot, startspot, sizeof( sv.startspot )); + else sv.startspot[0] = '\0'; + + com.sprintf( sv.configstrings[CS_MODELS+1], "maps/%s.bsp", sv.name ); sv.worldmodel = sv.models[1] = pe->BeginRegistration( sv.configstrings[CS_MODELS+1], false, &checksum ); com.sprintf( sv.configstrings[CS_MAPCHECKSUM], "%i", checksum ); com.strncpy( sv.configstrings[CS_SKYNAME], "", 64 ); @@ -201,40 +321,9 @@ void SV_SpawnServer( const char *server, const char *savename ) sv.models[i+1] = pe->RegisterModel(sv.configstrings[CS_MODELS+1+i] ); } - // - // spawn the rest of the entities on the map - // - - // precache and static commands can be issued during - // map initialization + // precache and static commands can be issued during map initialization sv.state = ss_loading; Host_SetServerState( sv.state ); - - // check for a savegame - SV_CheckForSavegame( savename ); - - if( sv.loadgame ) SV_ReadLevelFile( savename ); - else SV_SpawnEntities( sv.name, pe->GetEntityScript()); - - svgame.dllFuncs.pfnServerActivate( EDICT_NUM( 0 ), svgame.globals->numEntities, svgame.globals->maxClients ); - - // run two frames to allow everything to settle - for( i = 0; i < 2; i++ ) - { - sv.frametime = 100; - SV_Physics(); - } - - // all precaches are complete - sv.state = ss_active; - Host_SetServerState( sv.state ); - - // create a baseline for more efficient communications - SV_CreateBaseline(); - - // set serverinfo variable - Cvar_FullSet( "mapname", sv.name, CVAR_SERVERINFO|CVAR_INIT ); - pe->EndRegistration(); // free unused models } /* diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index fc1f0987..a935af50 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -32,7 +32,6 @@ cvar_t *sv_friction; cvar_t *sv_physics; cvar_t *hostname; cvar_t *sv_maxclients; -cvar_t *sv_showclamp; cvar_t *public_server; // should heartbeats be sent cvar_t *sv_reconnect_limit;// minimum seconds between connect messages @@ -281,8 +280,7 @@ void SV_RunGameFrame( void ) // never get more than one tic behind if( sv.time < svs.realtime ) { - if( sv_showclamp->integer ) - MsgDev( D_INFO, "sv highclamp\n" ); + MsgDev( D_NOTE, "sv.highclamp\n" ); svs.realtime = sv.time; } } @@ -315,8 +313,7 @@ void SV_Frame( int time ) // never let the time get too far off if( sv.time - svs.realtime > sv.frametime ) { - if( sv_showclamp->integer ) - MsgDev( D_INFO, "sv lowclamp\n" ); + MsgDev( D_NOTE, "sv.lowclamp\n" ); svs.realtime = sv.time - sv.frametime; } NET_Sleep( sv.time - svs.realtime ); @@ -460,7 +457,6 @@ void SV_Init( void ) sv_accelerate = Cvar_Get( "sv_accelerate", DEFAULT_ACCEL, 0, "rate at which a player accelerates to sv_maxspeed" ); sv_friction = Cvar_Get( "sv_friction", DEFAULT_FRICTION, 0, "how fast you slow down" ); sv_physics = Cvar_Get( "cm_physic", "1", CVAR_ARCHIVE|CVAR_LATCH, "change physic model: 0 - Classic Quake Physic, 1 - Physics Engine" ); - sv_showclamp = Cvar_Get( "sv_showclamp", "1", 0, "show server time clamping" ); sv_maxclients = Cvar_Get( "sv_maxclients", "1", CVAR_SERVERINFO|CVAR_LATCH, "server clients limit" ); public_server = Cvar_Get ("public", "0", 0, "change server type from private to public" ); @@ -514,8 +510,6 @@ void SV_FinalMessage( char *message, bool reconnect ) Netchan_Transmit( &cl->netchan, msg.cursize, msg.data ); } - - /* ================ SV_Shutdown @@ -534,9 +528,9 @@ void SV_Shutdown( bool reconnect ) if( svs.clients ) SV_FinalMessage( host.finalmsg, reconnect ); Master_Shutdown(); - if( reconnect ) - SV_FreeEdicts(); - else SV_UnloadProgs(); + + if( !reconnect ) SV_UnloadProgs (); + else SV_DeactivateServer (); // free current level Mem_Set( &sv, 0, sizeof( sv )); diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index ec8ed5a7..3fb1987d 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -1222,6 +1222,8 @@ void SV_Physics_Follow( edict_t *ent ) if(!SV_RunThink( ent )) return; e = ent->v.aiment; + if( !e || e->free ) return; + if(VectorCompare( e->v.angles, ent->v.punchangle )) { // quick case for no rotation diff --git a/engine/server/sv_save.c b/engine/server/sv_save.c index eb21fbc2..f61dc417 100644 --- a/engine/server/sv_save.c +++ b/engine/server/sv_save.c @@ -21,6 +21,11 @@ typedef struct save_header_s typedef struct game_header_s { int mapCount; // svs.mapcount + int serverflags; // svgame.serverflags + int total_secrets; // total secrets count + int found_secrets; // number of secrets found + int total_monsters; // total monsters count + int killed_monsters; // number of monsters killed char mapName[CS_SIZE]; // svs.mapname string comment; // svs.comment } game_header_t; @@ -36,6 +41,11 @@ static TYPEDESCRIPTION gSaveHeader[] = static TYPEDESCRIPTION gGameHeader[] = { DEFINE_FIELD( game_header_t, mapCount, FIELD_INTEGER ), + DEFINE_FIELD( game_header_t, serverflags, FIELD_INTEGER ), + DEFINE_FIELD( game_header_t, total_secrets, FIELD_INTEGER ), + DEFINE_FIELD( game_header_t, found_secrets, FIELD_INTEGER ), + DEFINE_FIELD( game_header_t, total_monsters, FIELD_INTEGER ), + DEFINE_FIELD( game_header_t, killed_monsters, FIELD_INTEGER ), DEFINE_ARRAY( game_header_t, mapName, FIELD_CHARACTER, CS_SIZE ), DEFINE_ARRAY( game_header_t, comment, FIELD_CHARACTER, MAX_STRING ), }; @@ -157,11 +167,12 @@ static void SV_SaveEngineData( wfile_t *f ) SV_AddSaveLump( f, LUMP_GAMECVARS, cvbuffer, numpairs * sizeof( dkeyvalue_t ), true ); } -static void SV_SaveServerData( wfile_t *f ) +static void SV_SaveServerData( wfile_t *f, const char *name, bool bUseLandMark ) { SAVERESTOREDATA *pSaveData; string_t hash_strings[4095]; int i, numstrings; + int level_flags = 0; ENTITYTABLE *pTable; save_header_t shdr; game_header_t ghdr; @@ -176,6 +187,22 @@ static void SV_SaveServerData( wfile_t *f ) svgame.SaveData.time = svgame.globals->time; pSaveData = svgame.globals->pSaveData = &svgame.SaveData; + // initialize the ENTITYTABLE + pSaveData->tableCount = svgame.globals->numEntities; + pSaveData->pTable = Mem_Alloc( svgame.temppool, pSaveData->tableCount * sizeof( ENTITYTABLE )); + + for( i = 0; i < svgame.globals->numEntities; i++ ) + { + pTable = &pSaveData->pTable[i]; + + pTable->pent = EDICT_NUM( i ); + // setup some flags + if( pTable->pent->v.flags & FL_CLIENT ) pTable->flags |= FENTTABLE_PLAYER; + if( pTable->pent->free ) pTable->flags |= FENTTABLE_REMOVED; + } + + pSaveData->fUseLandmark = bUseLandMark; + // initialize level connections svgame.dllFuncs.pfnBuildLevelList(); @@ -187,25 +214,13 @@ static void SV_SaveServerData( wfile_t *f ) // initialize game header ghdr.mapCount = svs.spawncount; - com.strncpy( ghdr.mapName, svs.mapname, CS_SIZE ); - Mem_Copy( ghdr.comment, svs.comment, MAX_STRING ); - - // initialize ENTITYTABLE - pSaveData->tableCount = svgame.globals->numEntities; - pSaveData->pTable = Mem_Alloc( svgame.temppool, pSaveData->tableCount * sizeof( ENTITYTABLE )); - - for( i = 0; i < svgame.globals->numEntities; i++ ) - { - edict_t *pent = EDICT_NUM( i ); - - pTable = &pSaveData->pTable[i]; - - pTable->pent = pent; - - // setup some flags - if( pent->v.flags & FL_CLIENT ) pTable->flags |= FENTTABLE_PLAYER; - if( pent->free ) pTable->flags |= FENTTABLE_REMOVED; - } + ghdr.serverflags = svgame.globals->serverflags; + ghdr.total_secrets = svgame.globals->total_secrets; + ghdr.found_secrets = svgame.globals->found_secrets; + ghdr.total_monsters = svgame.globals->total_monsters; + ghdr.killed_monsters = svgame.globals->killed_monsters; + com.strncpy( ghdr.mapName, sv.name, CS_SIZE ); + Mem_Copy( ghdr.comment, svs.comment, MAX_STRING ); // can't use strncpy! // write save header svgame.dllFuncs.pfnSaveWriteFields( pSaveData, "Save Header", &shdr, gSaveHeader, ARRAYSIZE( gSaveHeader )); @@ -215,6 +230,12 @@ static void SV_SaveServerData( wfile_t *f ) { LEVELLIST *pList = &pSaveData->levelList[i]; svgame.dllFuncs.pfnSaveWriteFields( pSaveData, "ADJACENCY", pList, gAdjacency, ARRAYSIZE( gAdjacency )); + + if( sv.changelevel && !com.strcmp( pList->mapName, name )) + { + level_flags = (1<pTable[pSaveData->currentIndex]; - if( !pent->free && pent->v.classname ) + if( sv.changelevel ) { - svgame.dllFuncs.pfnSave( pent, pSaveData ); - if( pTable->classname && pTable->size ) - pTable->id = pent->serialnumber; + bool bSave = false; + + // check for client ents + if( pTable->flags & (FENTTABLE_PLAYER|FENTTABLE_GLOBAL)) + bSave = true; + + if( pTable->flags & FENTTABLE_MOVEABLE && pTable->flags & level_flags ) + bSave = true; + + if( bSave ) + { + svgame.dllFuncs.pfnSave( pent, pSaveData ); + if( pTable->classname && pTable->size ) + pTable->id = pent->serialnumber; + else pTable->flags |= FENTTABLE_REMOVED; + } + else pTable->flags |= FENTTABLE_REMOVED; + + } + else + { + // savegame + if( !pent->free && pent->v.classname ) + { + svgame.dllFuncs.pfnSave( pent, pSaveData ); + if( pTable->classname && pTable->size ) + pTable->id = pent->serialnumber; + else pTable->flags |= FENTTABLE_REMOVED; + } else pTable->flags |= FENTTABLE_REMOVED; } - else pTable->flags |= FENTTABLE_REMOVED; - pSaveData->currentIndex++; // move pointer } @@ -281,7 +326,7 @@ static void SV_SaveServerData( wfile_t *f ) SV_WriteSaveFile ============= */ -void SV_WriteSaveFile( const char *name, bool autosave ) +void SV_WriteSaveFile( const char *name, bool autosave, bool bUseLandmark ) { wfile_t *savfile = NULL; char path[MAX_SYSPATH]; @@ -303,7 +348,7 @@ void SV_WriteSaveFile( const char *name, bool autosave ) if( !savfile ) { - MsgDev(D_ERROR, "SV_WriteSaveFile: failed to open %s\n", path ); + MsgDev( D_ERROR, "SV_WriteSaveFile: failed to open %s\n", path ); return; } @@ -312,17 +357,18 @@ void SV_WriteSaveFile( const char *name, bool autosave ) com.strncpy( svs.comment + CS_SIZE, timestamp( TIME_DATE_ONLY ), CS_TIME ); com.strncpy( svs.comment + CS_SIZE + CS_TIME, timestamp( TIME_NO_SECONDS ), CS_TIME ); com.strncpy( svs.comment + CS_SIZE + (CS_TIME * 2), svs.mapname, CS_SIZE ); - MsgDev( D_INFO, "Saving game..." ); + if( !autosave ) MsgDev( D_INFO, "Saving game..." ); // write lumps SV_SaveEngineData( savfile ); - SV_SaveServerData( savfile ); + SV_SaveServerData( savfile, name, bUseLandmark ); StringTable_Save( svgame.hStringTable, savfile ); // must be last WAD_Close( savfile ); - Cbuf_AddText( va( "saveshot %s\n", name )); // write saveshot for preview - MsgDev( D_INFO, "done.\n" ); + // write saveshot for preview, but autosave + if( !autosave ) Cbuf_AddText( va( "saveshot %s\n", name )); + if( !autosave ) MsgDev( D_INFO, "done.\n" ); } void SV_ReadComment( wfile_t *l ) @@ -396,7 +442,7 @@ void SV_ReadAreaPortals( wfile_t *l ) int size; in = WAD_Read( l, LUMP_AREASTATE, &size, TYPE_BINDATA ); - pe->SetAreaPortals( in, size ); // CM_ReadPortalState + pe->SetAreaPortals( in, size ); // CM_ReadPortalState(); } void SV_ReadGlobals( wfile_t *l ) @@ -415,14 +461,25 @@ void SV_ReadGlobals( wfile_t *l ) // read the game header svgame.dllFuncs.pfnSaveReadFields( pSaveData, "Game Header", &ghdr, gGameHeader, ARRAYSIZE( gGameHeader )); - - svs.spawncount = ghdr.mapCount; // restore spawncount - Mem_Copy( svs.comment, ghdr.comment, MAX_STRING ); - com.strncpy( svs.mapname, ghdr.mapName, MAX_STRING ); + svgame.globals->serverflags= ghdr.serverflags; // across transition flags (e.g. Q1 runes) + + if( sv.loadgame && !sv.changelevel ) + { + Msg( "SV_ReadGlobals()\n" ); + svs.spawncount = ghdr.mapCount; // restore spawncount + svgame.globals->total_secrets = ghdr.total_secrets; + svgame.globals->found_secrets = ghdr.found_secrets; + svgame.globals->total_monsters = ghdr.total_monsters; + svgame.globals->killed_monsters = ghdr.killed_monsters; + Mem_Copy( svs.comment, ghdr.comment, MAX_STRING ); + com.strncpy( svs.mapname, ghdr.mapName, MAX_STRING ); + } // restore global state svgame.dllFuncs.pfnRestoreGlobalState( pSaveData ); - svgame.dllFuncs.pfnServerDeactivate(); + +// FIXME: this is needs ? +// svgame.dllFuncs.pfnServerDeactivate(); } void SV_RestoreEdict( edict_t *ent ) @@ -438,42 +495,79 @@ void SV_ReadEntities( wfile_t *l ) LEVELLIST *pList; save_header_t shdr; edict_t *ent; - int i; + int i, level_flags = 0; + int num_moveables = 0; // initialize world properly ent = EDICT_NUM( 0 ); - SV_InitEdict( ent ); - ent->v.model = MAKE_STRING( sv.configstrings[CS_MODELS] ); + if( ent->free ) SV_InitEdict( ent ); + ent->v.model = MAKE_STRING( sv.configstrings[CS_MODELS+1] ); ent->v.modelindex = 1; // world model ent->v.solid = SOLID_BSP; ent->v.movetype = MOVETYPE_PUSH; - ent->free = false; // SAVERESTOREDATA partially initialized, continue filling pSaveData = svgame.globals->pSaveData = &svgame.SaveData; SV_ReadBuffer( l, LUMP_ADJACENCY ); - + + if( sv.loadgame ) + { + pSaveData->fUseLandmark = true; + } + else if( sv.changelevel ) + { + if( com.strlen( sv.startspot )) + pSaveData->fUseLandmark = true; + else pSaveData->fUseLandmark = false; // can be changed later + } + // read save header svgame.dllFuncs.pfnSaveReadFields( pSaveData, "Save Header", &shdr, gSaveHeader, ARRAYSIZE( gSaveHeader )); - - SV_ConfigString( CS_MAXCLIENTS, va( "%i", sv_maxclients->integer )); - com.strncpy( sv.name, shdr.mapName, MAX_STRING ); - svgame.globals->mapname = MAKE_STRING( sv.name ); - svgame.globals->time = shdr.time; - sv.time = svgame.globals->time * 1000; pSaveData->connectionCount = shdr.numConnections; + if( sv.loadgame ) + { + SV_ConfigString( CS_MAXCLIENTS, va( "%i", sv_maxclients->integer )); + com.strncpy( sv.name, shdr.mapName, MAX_STRING ); + svgame.globals->mapname = MAKE_STRING( sv.name ); + + // holds during changelevel, no needs to save\restore + svgame.globals->startspot = MAKE_STRING( sv.startspot ); + svgame.globals->time = shdr.time; + sv.time = svgame.globals->time * 1000; + } + // read ADJACENCY sections for( i = 0; i < pSaveData->connectionCount; i++ ) { pList = &pSaveData->levelList[i]; svgame.dllFuncs.pfnSaveReadFields( pSaveData, "ADJACENCY", pList, gAdjacency, ARRAYSIZE( gAdjacency )); + + if( sv.changelevel && !com.strcmp( pList->mapName, sv.name )) + { + level_flags = (1<szCurrentMap, pList->mapName ); + com.strcpy( pSaveData->szLandmarkName, pList->landmarkName ); + VectorCopy( pSaveData->vecLandmarkOffset, pList->vecLandmarkOrigin ); + pSaveData->time = shdr.time; + } } // initialize ENTITYTABLE pSaveData->tableCount = shdr.numEntities; pSaveData->pTable = Mem_Alloc( svgame.temppool, pSaveData->tableCount * sizeof( ENTITYTABLE )); - while( svgame.globals->numEntities < shdr.numEntities ) SV_AllocEdict(); // allocate edicts + + if( sv.loadgame ) // allocate edicts + while( svgame.globals->numEntities < shdr.numEntities ) SV_AllocEdict(); + else if( sv.changelevel ) + { + // NOTE: we don't need allocate too many ents + // just set it number to match with old map and use + // SV_InitEdict istead of SV_AllocEdict, first SV_Physics call + // will be fixup entities count to actual + svgame.globals->numEntities = pSaveData->tableCount; + } // set client fields on player ents for( i = 0; i < svgame.globals->maxClients; i++ ) @@ -496,17 +590,48 @@ void SV_ReadEntities( wfile_t *l ) pTable = &pSaveData->pTable[i]; svgame.dllFuncs.pfnSaveReadFields( pSaveData, "ETABLE", pTable, gETable, ARRAYSIZE( gETable )); - if( pTable->flags & FENTTABLE_REMOVED ) SV_FreeEdict( pent ); - else pent = SV_AllocPrivateData( pent, pTable->classname ); + if( sv.loadgame ) + { + if( pTable->flags & FENTTABLE_REMOVED ) SV_FreeEdict( pent ); + else pent = SV_AllocPrivateData( pent, pTable->classname ); + } + else if( sv.changelevel ) + { + bool bAlloc = false; + + // check for client or global entity + if( pTable->flags & (FENTTABLE_PLAYER|FENTTABLE_GLOBAL)) + bAlloc = true; - if( pTable->id != pent->serialnumber ) + if( pTable->flags & FENTTABLE_MOVEABLE && pTable->flags & level_flags ) + bAlloc = true; + + if( !pTable->id || !pTable->classname ) + bAlloc = false; + + if( bAlloc ) + { + if( pent->free ) SV_InitEdict( pent ); + pent = SV_AllocPrivateData( pent, pTable->classname ); + num_moveables++; + } + } + + if( sv.loadgame && ( pTable->id != pent->serialnumber )) MsgDev( D_ERROR, "ETABLE id( %i ) != edict->id( %i )\n", pTable->id, pent->serialnumber ); pTable->pent = pent; } + Msg( "total %i moveables, %i entities\n", num_moveables, svgame.globals->numEntities ); + + if( sv.changelevel ) + { + // spawn all the entities of the newmap + SV_SpawnEntities( sv.name, pe->GetEntityScript()); + } + SV_ReadBuffer( l, LUMP_BASEENTS ); - pSaveData->fUseLandmark = true; // and read entities ... for( i = 0; i < pSaveData->tableCount; i++ ) @@ -514,15 +639,34 @@ void SV_ReadEntities( wfile_t *l ) edict_t *pent = EDICT_NUM( i ); pTable = &pSaveData->pTable[i]; - // ignore removed edicts - if( !pent->free && pTable->classname ) + if( sv.loadgame ) { - svgame.dllFuncs.pfnRestore( pent, pSaveData, false ); - SV_RestoreEdict( pent ); + // ignore removed edicts + if( !pent->free && pTable->classname ) + { + svgame.dllFuncs.pfnRestore( pent, pSaveData, false ); + SV_RestoreEdict( pent ); + } + } + else if( sv.changelevel ) + { + bool bRestore = false; + bool bGlobal = (pTable->flags & FENTTABLE_GLOBAL) ? true : false; + + if( pTable->flags & (FENTTABLE_PLAYER|FENTTABLE_GLOBAL)) bRestore = true; + if( pTable->flags & FENTTABLE_MOVEABLE && pTable->flags & level_flags ) + bRestore = true; + if( !pTable->id || !pTable->classname ) bRestore = false; + + if( bRestore ) + { + MsgDev( D_INFO, "Transfering %s ( *%i )\n", STRING( pTable->classname ), i ); + svgame.dllFuncs.pfnRestore( pent, pSaveData, bGlobal ); + } } pSaveData->currentIndex++; } - + // do cleanup operations Mem_Set( &svgame.SaveData, 0, sizeof( SAVERESTOREDATA )); svgame.globals->pSaveData = NULL; @@ -538,7 +682,7 @@ void SV_ReadSaveFile( const char *name ) char path[MAX_SYSPATH]; wfile_t *savfile; - com.sprintf( path, "save/%s", name ); + com.sprintf( path, "save/%s.bin", name ); savfile = WAD_Open( path, "rb" ); if( !savfile ) @@ -547,15 +691,17 @@ void SV_ReadSaveFile( const char *name ) return; } - sv.loadgame = true; // to avoid clearing StringTables in SV_Shutdown StringTable_Delete( svgame.hStringTable ); // remove old string table svgame.hStringTable = StringTable_Load( savfile, name ); - SV_ReadCvars( savfile ); - - SV_InitGame(); // start a new game fresh with new cvars - // SV_Shutdown will be clear svs ans sv struct, so load it here - sv.loadgame = true; // restore state + if( sv.loadgame && !sv.changelevel ) + { + SV_ReadCvars( savfile ); + SV_InitGame(); // start a new game fresh with new cvars + + sv.loadgame = true; // restore state + } + SV_ReadGlobals( savfile ); WAD_Close( savfile ); } @@ -570,7 +716,7 @@ void SV_ReadLevelFile( const char *name ) char path[MAX_SYSPATH]; wfile_t *savfile; - com.sprintf( path, "save/%s", name ); + com.sprintf( path, "save/%s.bin", name ); savfile = WAD_Open( path, "rb" ); if( !savfile ) @@ -585,6 +731,71 @@ void SV_ReadLevelFile( const char *name ) WAD_Close( savfile ); } +/* +============= +SV_MergeLevelFile +============= +*/ +void SV_MergeLevelFile( const char *name ) +{ + char path[MAX_SYSPATH]; + wfile_t *savfile; + + com.sprintf( path, "save/%s.bin", name ); + savfile = WAD_Open( path, "rb" ); + + if( !savfile ) + { + MsgDev( D_ERROR, "SV_MergeLevel: can't open %s\n", path ); + return; + } + + SV_ReadEntities( savfile ); + WAD_Close( savfile ); +} + +/* +============= +SV_ChangeLevel +============= +*/ +void SV_ChangeLevel( bool bUseLandmark, const char *mapname, const char *start ) +{ + string level; + string oldlevel; + string _startspot; + char *startspot; + + if( sv.state != ss_active ) + { + Msg( "SV_ChangeLevel: server not running\n"); + return; + } + + sv.loadgame = false; + sv.changelevel = true; + + if( bUseLandmark ) + { + com.strncpy( _startspot, start, MAX_STRING ); + startspot = _startspot; + } + else startspot = NULL; + + com.strncpy( level, mapname, MAX_STRING ); + com.strncpy( oldlevel, sv.name, MAX_STRING ); + + // NOTE: we must save state even landmark is missed + // so transfer client weapons and env_global states + SV_WriteSaveFile( level, true, bUseLandmark ); + + SV_SpawnServer( mapname, startspot ); + + SV_LevelInit( level, oldlevel, level ); + + SV_ActivateServer (); +} + bool SV_GetComment( char *comment, int savenum ) { wfile_t *savfile; @@ -610,4 +821,39 @@ bool SV_GetComment( char *comment, int savenum ) WAD_Close( savfile ); return true; +} + +const char *SV_GetLatestSave( void ) +{ + search_t *f = FS_Search( "save/*.bin", true ); + int i, found = 0; + long newest = 0, ft; + string savename; + + if( !f ) return NULL; + + for( i = 0; i < f->numfilenames; i++ ) + { + if( WAD_Check( f->filenames[i] ) != 1 ) + continue; // corrupted or somewhat + + ft = FS_FileTime( va( "%s/%s", GI->gamedir, f->filenames[i] )); + + // found a match? + if( ft > 0 ) + { + // should we use the matche? + if( !found || Host_CompareFileTime( newest, ft ) < 0 ) + { + newest = ft; + com.strncpy( savename, f->filenames[i], MAX_STRING ); + found = 1; + } + } + } + Mem_Free( f ); // release search + + if( found ) + return va( "%s", savename ); // move to static memory + return NULL; } \ No newline at end of file diff --git a/launch/filesystem.c b/launch/filesystem.c index 39896962..a2c339e2 100644 --- a/launch/filesystem.c +++ b/launch/filesystem.c @@ -1359,6 +1359,7 @@ void FS_CreateGameInfo( const char *filename ) com.strncat( buffer, "\nsp_spawn\t\t\"info_player_start\"", MAX_SYSPATH ); com.strncat( buffer, "\ndm_spawn\t\t\"info_player_deathmatch\"", MAX_SYSPATH ); com.strncat( buffer, "\nctf_spawn\t\t\"info_player_ctf\"", MAX_SYSPATH ); + com.strncat( buffer, "\ncoop_spawn\t\t\"info_player_coop\"", MAX_SYSPATH ); com.strncat( buffer, "\nteam_spawn\t\"info_player_team\"", MAX_SYSPATH ); com.strncat( buffer, "\nplayermins\t\"-32 -32 -32\"", MAX_SYSPATH ); com.strncat( buffer, "\nplayermaxs\t\"32 32 32\"", MAX_SYSPATH ); @@ -1400,6 +1401,7 @@ static bool FS_ParseGameInfo( const char *filename, gameinfo_t *GameInfo ) com.strncpy( GameInfo->sp_entity, "info_player_start", MAX_STRING ); com.strncpy( GameInfo->dm_entity, "info_player_deathmatch", MAX_STRING ); com.strncpy( GameInfo->ctf_entity, "info_player_ctf", MAX_STRING ); + com.strncpy( GameInfo->coop_entity, "info_player_coop", MAX_STRING ); com.strncpy( GameInfo->team_entity, "info_player_team", MAX_STRING ); com.strncpy( GameInfo->startmap, "newmap", MAX_STRING ); @@ -1441,6 +1443,10 @@ static bool FS_ParseGameInfo( const char *filename, gameinfo_t *GameInfo ) { PS_GetString( script, false, GameInfo->ctf_entity, sizeof( GameInfo->ctf_entity )); } + else if( !com.stricmp( token.string, "coop_spawn" )) + { + PS_GetString( script, false, GameInfo->coop_entity, sizeof( GameInfo->coop_entity )); + } else if( !com.stricmp( token.string, "team_spawn" )) { PS_GetString( script, false, GameInfo->team_entity, sizeof( GameInfo->team_entity )); @@ -1456,7 +1462,7 @@ static bool FS_ParseGameInfo( const char *filename, gameinfo_t *GameInfo ) else if( !com.stricmp( token.string, "max_edicts" )) { PS_GetInteger( script, false, &GameInfo->max_edicts ); - GameInfo->max_edicts = bound( 600, GameInfo->max_edicts, 32768 ); + GameInfo->max_edicts = bound( 600, GameInfo->max_edicts, 32000 ); // reserve some edicts for tempents } else if( !com.stricmp( token.string, "viewmode" )) { @@ -2694,11 +2700,11 @@ FS_FileTime return time of creation file in seconds ================== */ -fs_offset_t FS_FileTime (const char *filename) +fs_offset_t FS_FileTime( const char *filename ) { struct stat buf; - if( stat( filename, &buf) == -1 ) + if( stat( filename, &buf ) == -1 ) return -1; return buf.st_mtime; diff --git a/launch/launch.h b/launch/launch.h index c344cedb..e04d5a7b 100644 --- a/launch/launch.h +++ b/launch/launch.h @@ -181,7 +181,7 @@ bool REG_SetValue( HKEY hKey, const char *SubKey, const char *Value, char *pBuff // void NET_Init( void ); void NET_Shutdown( void ); -void NET_Sleep( float time ); +void NET_Sleep( int msec ); void NET_Config( bool net_enable ); bool NET_IsLocalAddress( netadr_t adr ); char *NET_AdrToString( const netadr_t a ); diff --git a/launch/launch.plg b/launch/launch.plg new file mode 100644 index 00000000..67742955 --- /dev/null +++ b/launch/launch.plg @@ -0,0 +1,63 @@ + + +
+

Build Log

+

+--------------------Configuration: launch - Win32 Debug-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP13EA.tmp" with contents +[ +/nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "imagelib" /I "../public" /I "../common" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR"..\temp\launch\!debug/" /Fo"..\temp\launch\!debug/" /Fd"..\temp\launch\!debug/" /FD /GZ /c +"D:\Xash3D\src_main\launch\system.c" +] +Creating command line "cl.exe @C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP13EA.tmp" +Creating temporary file "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP13EB.tmp" with contents +[ +zlib.lib png.lib jpg.lib user32.lib gdi32.lib shell32.lib advapi32.lib winmm.lib /nologo /dll /incremental:yes /pdb:"..\temp\launch\!debug/launch.pdb" /debug /machine:I386 /nodefaultlib:"libc.lib" /out:"..\temp\launch\!debug/launch.dll" /implib:"..\temp\launch\!debug/launch.lib" /pdbtype:sept /libpath:"./imagelib" +"\Xash3D\src_main\temp\launch\!debug\cmd.obj" +"\Xash3D\src_main\temp\launch\!debug\console.obj" +"\Xash3D\src_main\temp\launch\!debug\cpuinfo.obj" +"\Xash3D\src_main\temp\launch\!debug\crclib.obj" +"\Xash3D\src_main\temp\launch\!debug\cvar.obj" +"\Xash3D\src_main\temp\launch\!debug\export.obj" +"\Xash3D\src_main\temp\launch\!debug\filesystem.obj" +"\Xash3D\src_main\temp\launch\!debug\img_bmp.obj" +"\Xash3D\src_main\temp\launch\!debug\img_dds.obj" +"\Xash3D\src_main\temp\launch\!debug\img_jpg.obj" +"\Xash3D\src_main\temp\launch\!debug\img_main.obj" +"\Xash3D\src_main\temp\launch\!debug\img_pcx.obj" +"\Xash3D\src_main\temp\launch\!debug\img_png.obj" +"\Xash3D\src_main\temp\launch\!debug\img_tga.obj" +"\Xash3D\src_main\temp\launch\!debug\img_utils.obj" +"\Xash3D\src_main\temp\launch\!debug\img_vtf.obj" +"\Xash3D\src_main\temp\launch\!debug\img_wad.obj" +"\Xash3D\src_main\temp\launch\!debug\memlib.obj" +"\Xash3D\src_main\temp\launch\!debug\network.obj" +"\Xash3D\src_main\temp\launch\!debug\parselib.obj" +"\Xash3D\src_main\temp\launch\!debug\patch.obj" +"\Xash3D\src_main\temp\launch\!debug\stdlib.obj" +"\Xash3D\src_main\temp\launch\!debug\system.obj" +"\Xash3D\src_main\temp\launch\!debug\utils.obj" +] +Creating command line "link.exe @C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP13EB.tmp" +Creating temporary file "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP13EC.bat" with contents +[ +@echo off +copy \Xash3D\src_main\temp\launch\!debug\launch.dll "D:\Xash3D\bin\launch.dll" +] +Creating command line "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP13EC.bat" +Compiling... +system.c +Linking... +

Output Window

+Performing Custom Build Step on \Xash3D\src_main\temp\launch\!debug\launch.dll +Скопировано файлов: 1. + + + +

Results

+launch.dll - 0 error(s), 0 warning(s) +
+ + diff --git a/launch/network.c b/launch/network.c index 8eae8528..e53182f0 100644 --- a/launch/network.c +++ b/launch/network.c @@ -602,17 +602,14 @@ void NET_Config( bool multiplayer ) } // sleeps msec or until net socket is ready -void NET_Sleep( float time ) +void NET_Sleep( int msec ) { struct timeval timeout; fd_set fdset; int i = 0; - long sec = (int)time; - long usec = (time - sec) * 1000; if( Sys.app_name == HOST_NORMAL ) - return; // we're not a dedicated server, just run full speed - if( !sec && !usec ) return; // smaller than timer resoultion + return; // we're not a server, just run full speed FD_ZERO( &fdset ); @@ -622,8 +619,8 @@ void NET_Sleep( float time ) i = ip_sockets[NS_SERVER]; } - timeout.tv_sec = sec; - timeout.tv_usec = usec; + timeout.tv_sec = msec / 1000; + timeout.tv_usec = (msec % 1000) * 1000; pSelect( i+1, &fdset, NULL, NULL, &timeout ); } diff --git a/launch/system.c b/launch/system.c index cacef250..f248a196 100644 --- a/launch/system.c +++ b/launch/system.c @@ -843,6 +843,7 @@ void Sys_Error(const char *error, ...) Con_ShowConsole( true ); if( Sys.developer >= D_ERROR ) Sys_Print( text ); // print error message else Sys_Print( "Internal engine error\n" ); // don't confuse non-developers with technique stuff + Sys.Free(); // kill video Sys_WaitForQuit(); Sys_Exit(); @@ -861,6 +862,8 @@ void Sys_Break(const char *error, ...) Sys.app_state = SYS_ERROR; Con_ShowConsole( true ); Sys_Print( text ); + Sys.Free(); // kill video + Sys_WaitForQuit(); Sys_Exit(); } diff --git a/launch/utils.c b/launch/utils.c index c056e431..35ac68ed 100644 --- a/launch/utils.c +++ b/launch/utils.c @@ -344,7 +344,7 @@ const char *StringTable_GetString( int handle, string_t index ) string_t StringTable_SetString( int handle, const char *string ) { - int i, len, table_size, data_size; + int i, len, table_size, data_size; if( !StringTable_CheckHandle( handle, false )) return -1; diff --git a/physic/physic.plg b/physic/physic.plg new file mode 100644 index 00000000..3835ce2a --- /dev/null +++ b/physic/physic.plg @@ -0,0 +1,16 @@ + + +
+

Build Log

+

+--------------------Configuration: physic - Win32 Debug-------------------- +

+

Command Lines

+ + + +

Results

+physic.dll - 0 error(s), 0 warning(s) +
+ + diff --git a/public/engine_api.h b/public/engine_api.h index 51ca5684..d6807215 100644 --- a/public/engine_api.h +++ b/public/engine_api.h @@ -10,16 +10,15 @@ // // engine constant limits, touching networking protocol modify with precaution // -#define MAX_DLIGHTS 32 // dynamic lights (per one frame) +#define MAX_DLIGHTS 32 // dynamic lights (rendered per one frame) #define MAX_LIGHTSTYLES 256 // can't be blindly increased -#define MAX_DECALS 256 // server decal indexes +#define MAX_DECALS 256 // server decal indexes (different decalnames, not a render limit) #define MAX_USER_MESSAGES 200 // another 56 messages reserved for engine routines #define MAX_CLASSNAMES 512 // maxcount of various edicts classnames #define MAX_SOUNDS 512 // openal software limit #define MAX_MODELS 4096 // total count of brush & studio various models per one map #define MAX_PARTICLES 32768 // pre one frame -#define MAX_EDICTS 65535 // absolute limit that never be reached, (do not edit!) -#define MAX_VERTS_ON_POLY 10 // decal vertices +#define MAX_EDICTS 32768 // absolute limit that never be reached, (do not edit!) /* ============================================================================== diff --git a/public/launch_api.h b/public/launch_api.h index 412698ca..554fe75b 100644 --- a/public/launch_api.h +++ b/public/launch_api.h @@ -237,14 +237,14 @@ typedef struct gameinfo_s string sp_entity; // e.g. info_player_start string dm_entity; // e.g. info_player_deathmatch + string coop_entity; // e.g. info_player_coop string ctf_entity; // e.g. info_player_ctf string team_entity; // e.g. info_player_team vec3_t client_mins[2]; // 0 - normal, 1 - ducked vec3_t client_maxs[2]; // 0 - normal, 1 - ducked - int max_edicts; // min edicts is 600, max edicts is 32768 - string imglib_mode; // image formats to using (optional) + int max_edicts; // min edicts is 600, max edicts is 32000 } gameinfo_t; typedef struct sysinfo_s @@ -460,7 +460,7 @@ typedef struct stdilib_api_s // network.c funcs void (*NET_Init)( void ); void (*NET_Shutdown)( void ); - void (*NET_Sleep)( float time ); + void (*NET_Sleep)( int msec ); void (*NET_Config)( bool net_enable ); char *(*NET_AdrToString)( netadr_t a ); bool (*NET_IsLocalAddress)( netadr_t adr ); diff --git a/render/r_light.c b/render/r_light.c index 3686a86d..4d3695d4 100644 --- a/render/r_light.c +++ b/render/r_light.c @@ -308,14 +308,19 @@ void R_LightForOrigin( const vec3_t origin, vec3_t dir, vec4_t ambient, vec4_t d int *gridBounds; mgridlight_t **lightarray; - VectorSet( ambientLocal, 0, 0, 0 ); - VectorSet( diffuseLocal, 0, 0, 0 ); - if( !r_worldmodel || !r_worldbrushmodel->lightgrid || !r_worldbrushmodel->numlightgridelems ) { + // get fullbright + VectorSet( ambientLocal, 255, 255, 255 ); + VectorSet( diffuseLocal, 255, 255, 255 ); VectorSet( dir, 0.5f, 0.2f, -1.0f ); goto dynamic; } + else + { + VectorSet( ambientLocal, 0, 0, 0 ); + VectorSet( diffuseLocal, 0, 0, 0 ); + } lightarray = r_worldbrushmodel->lightarray; gridSize = r_worldbrushmodel->gridSize; diff --git a/render/r_local.h b/render/r_local.h index fbe11803..fab8ccc2 100644 --- a/render/r_local.h +++ b/render/r_local.h @@ -44,7 +44,7 @@ extern byte *r_temppool; #define Host_Error com.error typedef unsigned int elem_t; -typedef enum { RT_MODEL, RT_SPRITE, RT_PORTALSURFACE, NUM_RTYPES } refEntityType_t; +typedef enum { RT_NONE, RT_MODEL, RT_SPRITE, RT_PORTALSURFACE, NUM_RTYPES } refEntityType_t; /* skins will be outline flood filled and mip mapped @@ -129,7 +129,7 @@ enum #define SHADOW_PLANAR 1 #define SHADOW_MAPPING 2 -#define MAX_ENTITIES 2048 +#define MAX_ENTITIES 2048 // per one frame #define MAX_POLY_VERTS 3000 #define MAX_POLYS 2048 diff --git a/render/r_main.c b/render/r_main.c index 48a94e60..001ab01d 100644 --- a/render/r_main.c +++ b/render/r_main.c @@ -40,10 +40,10 @@ refinst_t RI, prevRI; ref_params_t r_lastRefdef; static int r_numnullentities; -static ref_entity_t *r_nullentities[MAX_EDICTS]; +static ref_entity_t *r_nullentities[MAX_ENTITIES]; ref_model_t *cl_models[MAX_MODELS]; // client replacement modeltable static int r_numbmodelentities; -static ref_entity_t *r_bmodelentities[MAX_EDICTS]; +static ref_entity_t *r_bmodelentities[MAX_MODELS]; static byte r_entVisBits[MAX_EDICTS/8]; @@ -61,20 +61,17 @@ msurface_t *r_debug_surface; char r_speeds_msg[MAX_RSPEEDSMSGSIZE]; -// -// screen size info -// -unsigned int r_numEntities; -ref_entity_t r_entities[MAX_ENTITIES]; -ref_entity_t *r_worldent = &r_entities[0]; +uint r_numEntities; +ref_entity_t r_entities[MAX_ENTITIES]; +ref_entity_t *r_worldent = &r_entities[0]; -unsigned int r_numDlights; -dlight_t r_dlights[MAX_DLIGHTS]; +uint r_numDlights; +dlight_t r_dlights[MAX_DLIGHTS]; -unsigned int r_numPolys; -poly_t r_polys[MAX_POLYS]; +uint r_numPolys; +poly_t r_polys[MAX_POLYS]; -lightstyle_t r_lightStyles[MAX_LIGHTSTYLES]; +lightstyle_t r_lightStyles[MAX_LIGHTSTYLES]; int r_viewcluster, r_oldviewcluster; @@ -1352,8 +1349,8 @@ static void R_CullEntities( void ) case RT_SPRITE: culled = ( e->radius <= 0 ) || ( e->spriteshader == NULL ); break; - default: - break; + case RT_NONE: + default: break; } if( !culled ) r_entVisBits[i>>3] |= ( 1<<( i&7 )); @@ -1457,8 +1454,8 @@ add: if( !shadowmap ) R_AddSpritePolyToList( e ); break; - default: - break; + case RT_NONE: + default: break; } } } @@ -1787,7 +1784,7 @@ R_ClearScene */ void R_ClearScene( void ) { - r_numEntities = 1; + r_numEntities = 2; // world and viewmodel r_numDlights = 0; r_numPolys = 0; RI.previousentity = NULL; @@ -2238,13 +2235,22 @@ bool R_AddEntityToScene( edict_t *pRefEntity, int ed_type ) ref_entity_t *refent; bool result = false; - if( !pRefEntity || !pRefEntity->v.modelindex ) - return false; // if set to invisible, skip - if( r_numEntities >= MAX_ENTITIES ) return false; + // NULL or overflow + if( !pRefEntity || (r_numEntities >= MAX_ENTITIES)) + return false; - refent = &r_entities[r_numEntities]; + if( pRefEntity->serialnumber == VMODEL_ENTINDEX ) + { + // viewmodel always uses this slot for properly store + // and playing client-side animation + refent = &r_entities[1]; - if( pRefEntity->v.effects & EF_NODRAW ) + // client lost weapon or change weapon + if( !pRefEntity->v.modelindex ) refent->rtype = RT_NONE; // completely ignore to draw + } + else refent = &r_entities[r_numEntities]; + + if( !pRefEntity->v.modelindex || pRefEntity->v.effects & EF_NODRAW ) return true; // done // filter ents @@ -2288,7 +2294,10 @@ bool R_AddEntityToScene( edict_t *pRefEntity, int ed_type ) result = R_AddGenericEntity( pRefEntity, refent ); break; } - r_numEntities++; + + // viewmodel already reserve slot + if( pRefEntity->serialnumber != VMODEL_ENTINDEX ) + r_numEntities++; // never adding child entity without parent // only studio models can have attached childrens diff --git a/render/r_mesh.c b/render/r_mesh.c index 220735b4..af071ed5 100644 --- a/render/r_mesh.c +++ b/render/r_mesh.c @@ -1031,7 +1031,7 @@ static bool R_DrawPortalSurface( void ) } } - if( ( i == r_numEntities ) && !captureTexture ) + if(( i == r_numEntities ) && !captureTexture ) return false; setup_and_render: diff --git a/render/r_model.c b/render/r_model.c index ae219b87..1216f9e0 100644 --- a/render/r_model.c +++ b/render/r_model.c @@ -149,7 +149,7 @@ byte *Mod_ClusterPVS( int cluster, ref_model_t *model ) { mbrushmodel_t *bmodel = ( mbrushmodel_t * )model->extradata; - if( cluster == -1 || !bmodel->vis ) + if( !model || !bmodel || !bmodel->vis || cluster < 0 || cluster >= bmodel->vis->numclusters ) return mod_novis; return ( (byte *)bmodel->vis->data + cluster*bmodel->vis->rowsize ); } @@ -2021,15 +2021,15 @@ void R_BeginRegistration( const char *mapname, const dvis_t *visData ) if( com.strcmp( r_models[0].name, fullname )) { Mod_FreeModel( &r_models[0] ); - R_NewMap (); } else { // update progress bar Cvar_SetValue( "scr_loading", 50.0f ); if( ri.UpdateScreen ) ri.UpdateScreen(); - R_StudioFreeAllExtradata (); // load game issues } + + R_NewMap (); if( r_lighting_packlightmaps->integer ) { diff --git a/render/r_sprite.c b/render/r_sprite.c index 495ebd72..342fc023 100644 --- a/render/r_sprite.c +++ b/render/r_sprite.c @@ -335,9 +335,10 @@ float R_GetSpriteFrameInterpolant( ref_entity_t *ent, mspriteframe_t **oldframe, { if( m_fDoInterp ) { - if( psprite->frames[ent->prev.sequence].type != FRAME_SINGLE ) + if( ent->prev.sequence >= psprite->numframes || psprite->frames[ent->prev.sequence].type != FRAME_SINGLE ) { // this can be happens when rendering switched between single and angled frames + // or change model on replace delta-entity ent->prev.sequence = ent->sequence = frame; ent->animtime = RI.refdef.time; lerpFrac = 1.0f; @@ -367,6 +368,14 @@ float R_GetSpriteFrameInterpolant( ref_entity_t *ent, mspriteframe_t **oldframe, lerpFrac = 1.0f; } + if( ent->prev.sequence >= psprite->numframes ) + { + // reset interpolation on change model + ent->prev.sequence = ent->sequence = frame; + ent->animtime = RI.refdef.time; + lerpFrac = 0.0f; + } + // get the interpolated frames if( oldframe ) *oldframe = psprite->frames[ent->prev.sequence].frameptr; if( curframe ) *curframe = psprite->frames[frame].frameptr; @@ -412,9 +421,10 @@ float R_GetSpriteFrameInterpolant( ref_entity_t *ent, mspriteframe_t **oldframe, if( m_fDoInterp ) { - if( psprite->frames[ent->prev.sequence].type != FRAME_ANGLED ) + if( ent->prev.sequence >= psprite->numframes || psprite->frames[ent->prev.sequence].type != FRAME_ANGLED ) { // this can be happens when rendering switched between single and angled frames + // or change model on replace delta-entity ent->prev.sequence = ent->sequence = frame; ent->animtime = RI.refdef.time; lerpFrac = 1.0f; @@ -504,7 +514,7 @@ bool R_DrawSpriteModel( const meshbuffer_t *mb ) lerp = bound( 0, lerp, 1 ); ilerp = 1.0f - lerp; - if( ilerp != 0 && oldframe->shader > 0 && oldframe->shader < MAX_SHADERS ) // FIXME + if( ilerp != 0 ) { e->renderamt = renderamt * ilerp; // merge prevframe alpha rb->shaderkey = r_shaders[oldframe->shader].sortkey; diff --git a/render/r_studio.c b/render/r_studio.c index a3a8c3c7..80712fa5 100644 --- a/render/r_studio.c +++ b/render/r_studio.c @@ -130,7 +130,8 @@ void R_StudioAllocExtradata( edict_t *in, ref_entity_t *e ) } else { - R_StudioFrameAdvance( e, 0 ); + if( !studio->m_fSequenceFinished ) + R_StudioFrameAdvance( e, 0 ); if( studio->m_fSequenceFinished ) { @@ -1928,7 +1929,7 @@ void R_StudioDrawDebug( void ) GL_SetState( GLSTATE_NO_DEPTH_TEST|GLSTATE_SRCBLEND_SRC_ALPHA|GLSTATE_DSTBLEND_ONE_MINUS_SRC_ALPHA ); pglDepthRange( 0, 0 ); - for( i = 0; i < r_numEntities; i++ ) + for( i = 1; i < r_numEntities; i++ ) { RI.previousentity = RI.currententity; RI.currententity = &r_entities[i]; diff --git a/render/render.plg b/render/render.plg new file mode 100644 index 00000000..d34554db --- /dev/null +++ b/render/render.plg @@ -0,0 +1,63 @@ + + +
+

Build Log

+

+--------------------Configuration: render - Win32 Debug-------------------- +

+

Command Lines

+Creating temporary file "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1778.tmp" with contents +[ +/nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "../public" /I "../common" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR"..\temp\render\!debug/" /Fo"..\temp\render\!debug/" /Fd"..\temp\render\!debug/" /FD /c +"D:\Xash3D\src_main\render\r_shader.c" +] +Creating command line "cl.exe @C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1778.tmp" +Creating temporary file "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1779.tmp" with contents +[ +msvcrtd.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /incremental:yes /pdb:"..\temp\render\!debug/render.pdb" /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /out:"..\temp\render\!debug/render.dll" /implib:"..\temp\render\!debug/render.lib" /pdbtype:sept +"\Xash3D\src_main\temp\render\!debug\cin.obj" +"\Xash3D\src_main\temp\render\!debug\r_aliasq.obj" +"\Xash3D\src_main\temp\render\!debug\r_backend.obj" +"\Xash3D\src_main\temp\render\!debug\r_bloom.obj" +"\Xash3D\src_main\temp\render\!debug\r_cin.obj" +"\Xash3D\src_main\temp\render\!debug\r_cull.obj" +"\Xash3D\src_main\temp\render\!debug\r_draw.obj" +"\Xash3D\src_main\temp\render\!debug\r_image.obj" +"\Xash3D\src_main\temp\render\!debug\r_light.obj" +"\Xash3D\src_main\temp\render\!debug\r_main.obj" +"\Xash3D\src_main\temp\render\!debug\r_math.obj" +"\Xash3D\src_main\temp\render\!debug\r_mesh.obj" +"\Xash3D\src_main\temp\render\!debug\r_model.obj" +"\Xash3D\src_main\temp\render\!debug\r_opengl.obj" +"\Xash3D\src_main\temp\render\!debug\r_poly.obj" +"\Xash3D\src_main\temp\render\!debug\r_program.obj" +"\Xash3D\src_main\temp\render\!debug\r_register.obj" +"\Xash3D\src_main\temp\render\!debug\r_shader.obj" +"\Xash3D\src_main\temp\render\!debug\r_shadow.obj" +"\Xash3D\src_main\temp\render\!debug\r_sky.obj" +"\Xash3D\src_main\temp\render\!debug\r_sprite.obj" +"\Xash3D\src_main\temp\render\!debug\r_studio.obj" +"\Xash3D\src_main\temp\render\!debug\r_surf.obj" +] +Creating command line "link.exe @C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1779.tmp" +Creating temporary file "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP177A.bat" with contents +[ +@echo off +copy \Xash3D\src_main\temp\render\!debug\render.dll "D:\Xash3D\bin\render.dll" +] +Creating command line "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP177A.bat" +Compiling... +r_shader.c +Linking... + Creating library ..\temp\render\!debug/render.lib and object ..\temp\render\!debug/render.exp +

Output Window

+Performing Custom Build Step on \Xash3D\src_main\temp\render\!debug\render.dll +Скопировано файлов: 1. + + + +

Results

+render.dll - 0 error(s), 0 warning(s) +
+ + diff --git a/server/ents/basefunc.cpp b/server/ents/basefunc.cpp index c28f64ea..eb446058 100644 --- a/server/ents/basefunc.cpp +++ b/server/ents/basefunc.cpp @@ -701,10 +701,10 @@ void CFuncTeleport :: Touch( CBaseEntity *pOther ) return; if( IsLockedByMaster( pOther )) return; - pTarget = UTIL_FindEntityByTargetname( pTarget, STRING(pev->target) ); - if ( !pTarget ) return; + pTarget = UTIL_FindEntityByTargetname( pTarget, STRING( pev->target )); + if( !pTarget ) return; - CBaseEntity *pLandmark = UTIL_FindEntityByTargetname( NULL, STRING(pev->message) ); + CBaseEntity *pLandmark = UTIL_FindEntityByTargetname( NULL, STRING( pev->message )); if ( pLandmark ) { Vector vecOriginOffs = pTarget->pev->origin - pLandmark->pev->origin; diff --git a/server/ents/baseweapon.cpp b/server/ents/baseweapon.cpp index 5271d54e..248f6d9d 100644 --- a/server/ents/baseweapon.cpp +++ b/server/ents/baseweapon.cpp @@ -737,7 +737,7 @@ int CBasePlayerWeapon :: PlaySequence( Activity activity, float fps ) if(!m_pPlayer->pev->viewmodel) return -1; UTIL_SetModel( ENT(pev), STRING( m_pPlayer->pev->viewmodel )); int iSequence = LookupActivity( activity ); - if(iSequence != -1) SendWeaponAnim(iSequence, fps); + if( iSequence != -1 ) SendWeaponAnim( iSequence, fps ); else DevMsg("Warning: %s not found\n", activity_map[activity - 1].name); return iSequence; @@ -866,7 +866,7 @@ int CBasePlayerWeapon :: SetAnimation( Activity activity, float fps ) iSequence = LookupSequence( pAnimsList[i] ); if( iSequence != -1 ) { - SendWeaponAnim (iSequence, fps ); // names method + SendWeaponAnim( iSequence, fps ); // names method return iSequence; } } @@ -879,7 +879,8 @@ int CBasePlayerWeapon :: SetAnimation( Activity activity, float fps ) //========================================================= void CBasePlayerWeapon :: SendWeaponAnim( int sequence, float fps ) { - float framerate = 1.0f; // fps multiplier + float framerate = 1.0f; // fps multiplier + m_iSequence = sequence; // member current sequence if( fps ) { @@ -888,7 +889,7 @@ void CBasePlayerWeapon :: SendWeaponAnim( int sequence, float fps ) { dstudioseqdesc_t *pseqdesc; - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + sequence; + pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + m_iSequence; framerate = fps / pseqdesc->fps; } } @@ -897,12 +898,11 @@ void CBasePlayerWeapon :: SendWeaponAnim( int sequence, float fps ) pev->body = (pev->body % NUM_HANDS) + NUM_HANDS * m_iBody; MESSAGE_BEGIN( MSG_ONE, gmsg.WeaponAnim, NULL, m_pPlayer->pev ); - WRITE_BYTE( sequence ); + WRITE_BYTE( m_iSequence ); WRITE_BYTE( pev->body ); WRITE_BYTE( framerate * 16 ); MESSAGE_END(); - m_pPlayer->pev->weaponanim = sequence; SetNextIdle( SequenceDuration( )); } @@ -1320,7 +1320,7 @@ void CBasePlayerWeapon :: PlayAttackSound( int firemode ) if(sfxcnt()) { int sfxsound = RANDOM_LONG(0, sfxcnt() - 1); - EMIT_SOUND(ENT(pev), CHAN_BODY, STRING(SfxSound(sfxsound)), 1.0, ATTN_NORM); + EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, STRING(SfxSound(sfxsound)), 1.0, ATTN_NORM); } } else //play normal random fire sound @@ -1328,7 +1328,7 @@ void CBasePlayerWeapon :: PlayAttackSound( int firemode ) if(sndcnt()) { int firesound = RANDOM_LONG(0, sndcnt() - 1); - EMIT_SOUND(ENT(pev), CHAN_BODY, STRING(FireSound(firesound)), 1.0, ATTN_NORM); + EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, STRING(FireSound(firesound)), 1.0, ATTN_NORM); } } } @@ -1983,7 +1983,8 @@ BOOL CBasePlayerWeapon :: AddPrimaryAmmo( int iCount, char *szName, int iMaxClip if (iIdAmmo > 0) { m_iPrimaryAmmoType = iIdAmmo; - if (m_pPlayer->HasPlayerItem( this )) EMIT_SOUND(ENT(pev), CHAN_ITEM, "weapons/glock/clip_in.wav", 1, ATTN_NORM); + if( m_pPlayer->HasPlayerItem( this )) + EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_ITEM, "weapons/glock/clip_in.wav", 1, ATTN_NORM ); } return iIdAmmo > 0 ? TRUE : FALSE; } @@ -1997,7 +1998,7 @@ BOOL CBasePlayerWeapon :: AddSecondaryAmmo( int iCount, char *szName, int iMax ) if (iIdAmmo > 0) { m_iSecondaryAmmoType = iIdAmmo; - EMIT_SOUND(ENT(pev), CHAN_ITEM, "weapons/glock/clip_in.wav", 1, ATTN_NORM); + EMIT_SOUND( ENT( m_pPlayer->pev ), CHAN_ITEM, "weapons/glock/clip_in.wav", 1, ATTN_NORM ); } return iIdAmmo > 0 ? TRUE : FALSE; } diff --git a/server/ents/baseweapon.h b/server/ents/baseweapon.h index 50606185..59310eb0 100644 --- a/server/ents/baseweapon.h +++ b/server/ents/baseweapon.h @@ -16,14 +16,14 @@ class CLaserSpot; // weapon flags -#define ITEM_FLAG_SELECTONEMPTY 1 //this weapon can choose without ammo -#define ITEM_FLAG_NOAUTORELOAD 2 //only manual reload -#define ITEM_FLAG_NOAUTOSWITCHEMPTY 4 //don't switch from this weapon -#define ITEM_FLAG_LIMITINWORLD 8 //limit in world -#define ITEM_FLAG_EXHAUSTIBLE 16 // A player can totally exhaust their ammo supply and lose this weapon -#define ITEM_FLAG_NODUPLICATE 32 // player can't give this weapon again -#define ITEM_FLAG_USEAUTOAIM 64 // weapon uses autoaim -#define ITEM_FLAG_HIDEAMMO 128 // weapon uses autoaim +#define ITEM_FLAG_SELECTONEMPTY 1 // this weapon can choose without ammo +#define ITEM_FLAG_NOAUTORELOAD 2 // only manual reload +#define ITEM_FLAG_NOAUTOSWITCHEMPTY 4 // don't switch from this weapon +#define ITEM_FLAG_LIMITINWORLD 8 // limit in world +#define ITEM_FLAG_EXHAUSTIBLE 16 // A player can totally exhaust their ammo supply and lose this weapon +#define ITEM_FLAG_NODUPLICATE 32 // player can't give this weapon again +#define ITEM_FLAG_USEAUTOAIM 64 // weapon uses autoaim +#define ITEM_FLAG_HIDEAMMO 128 // hide ammo in round // suit definitions #define BARNEY_SUIT 0 // just in case @@ -32,17 +32,17 @@ class CLaserSpot; #define PLAYER_HAS_SUIT (m_pPlayer->pev->weapons & ITEM_SUIT) #define PLAYER_DRAW_SUIT (pev->body & GORDON_SUIT) -#define MAX_SHOOTSOUNDS 3 // max of four random shoot sounds +#define MAX_SHOOTSOUNDS 3 // max of random shoot sounds enum { NONE = 0, - AMMO1, //fire primary ammo - AMMO2, //fire seondary ammo - LASER_DOT, //enable laser dot - ZOOM, //enable zoom - FLASHLIGHT, //enable flashlight - SWITCHMODE, //play two beetwen anims and change body - SWING, //crowbar swing + AMMO1, // fire primary ammo + AMMO2, // fire seondary ammo + LASER_DOT, // enable laser dot + ZOOM, // enable zoom + FLASHLIGHT, // enable flashlight + SWITCHMODE, // play two beetwen anims and change body + SWING, // crowbar swing }; #define BATTACK_FIREMODE0 0 //both attack firemode 0 @@ -154,13 +154,13 @@ public: void SendWeaponAnim( int sequence, float fps = 0 ); float SetNextAttack( float delay ) { return m_pPlayer->m_flNextAttack = gpGlobals->time + delay; } float SetNextIdle( float delay ) { return m_flTimeWeaponIdle = gpGlobals->time + delay; } - float SequenceDuration( void ) { return CBaseAnimating :: SequenceDuration( m_pPlayer->pev->weaponanim ); } + float SequenceDuration( void ) { return CBaseAnimating :: SequenceDuration( m_iSequence ); } int GetNumBodies( void ) { - dstudiohdr_t *pstudiohdr = (dstudiohdr_t *)(GET_MODEL_PTR( ENT(pev) )); - if (pstudiohdr) + dstudiohdr_t *pstudiohdr = (dstudiohdr_t *)(GET_MODEL_PTR( ENT( pev ))); + if( pstudiohdr ) { - dstudiobodyparts_t *pbodypart = (dstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + 2; + dstudiobodyparts_t *pbodypart = (dstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex) + NUM_HANDS; return pbodypart->nummodels; } return 0; @@ -176,10 +176,10 @@ public: CBasePlayer *m_pPlayer; CBasePlayerWeapon *m_pNext; - int m_iId; //Weapon unical Id (0 - MAX_WEAPONS) // WEAPON_??? + int m_iId; // Weapon unique Id (0 - MAX_WEAPONS) //don't save this - CLaserSpot *m_pSpot; //LTD spot + CLaserSpot *m_pSpot; // LTD spot //virtual methods for ItemInfo acess int iItemPosition(void) { return ItemInfoArray[ m_iId ].iPosition; } @@ -346,6 +346,7 @@ public: int m_cActiveRocket; // how many rockets is now active ? int m_iOnControl; // controllable rocket is on control now int m_iStepReload; // reload state + int m_iSequence; // current weaponmodel sequence int m_iClip; // current clip state int m_iBody; // viewmodel body int m_iSkin; // viewmodel skin diff --git a/server/global/client.cpp b/server/global/client.cpp index 1bd0e657..ccfc5a7d 100644 --- a/server/global/client.cpp +++ b/server/global/client.cpp @@ -739,9 +739,9 @@ void PlayerPostThink( edict_t *pEntity ) void BuildLevelList( void ) { // retrieve the pointer to the save data - SAVERESTOREDATA *pSaveData = (SAVERESTOREDATA *)gpGlobals->pSaveData; + SAVERESTOREDATA *pSaveData = (SAVERESTOREDATA *)gpGlobals->pSaveData; - if ( pSaveData ) + if( pSaveData ) pSaveData->connectionCount = BuildChangeList( pSaveData->levelList, MAX_LEVEL_CONNECTIONS ); } @@ -750,100 +750,125 @@ void BuildLevelList( void ) //======================================================================= int AddTransitionToList( LEVELLIST *pLevelList, int listCount, const char *pMapName, const char *pLandmarkName, edict_t *pentLandmark ) { - int i; + int i; - if ( !pLevelList || !pMapName || !pLandmarkName || !pentLandmark ) return 0; + if( !pLevelList || !pMapName ) return 0; - for ( i = 0; i < listCount; i++ ) + for( i = 0; i < listCount; i++ ) { - if ( pLevelList[i].pentLandmark == pentLandmark && !strcmp( pLevelList[i].mapName, pMapName )) + if( pLevelList[i].pentLandmark == pentLandmark && !strcmp( pLevelList[i].mapName, pMapName )) return 0; } + strcpy( pLevelList[listCount].mapName, pMapName ); strcpy( pLevelList[listCount].landmarkName, pLandmarkName ); pLevelList[listCount].pentLandmark = pentLandmark; - pLevelList[listCount].vecLandmarkOrigin = VARS(pentLandmark)->origin; + + if ( FNullEnt( pentLandmark )) + pLevelList[listCount].vecLandmarkOrigin = Vector( 0, 0, 0 ); + else pLevelList[listCount].vecLandmarkOrigin = VARS( pentLandmark )->origin; return 1; } int BuildChangeList( LEVELLIST *pLevelList, int maxList ) { - edict_t *pentLandmark; - int i, count; + edict_t *pentLandmark; + int i, count; count = 0; - // Find all of the possible level changes on this BSP + // find all of the possible level changes on this BSP CBaseEntity *pChangelevel = UTIL_FindEntityByClassname( NULL, "trigger_changelevel" ); - if ( !pChangelevel ) return NULL; + if( !pChangelevel ) return 0; while ( pChangelevel ) { - // Find the corresponding landmark + // find the corresponding landmark pentLandmark = UTIL_FindLandmark( pChangelevel->pev->message ); - if ( pentLandmark ) + if( pentLandmark ) { - // Build a list of unique transitions - DevMsg("Map name %s, landmark name %s\n", STRING(pChangelevel->pev->netname), STRING(pChangelevel->pev->message)); - if ( AddTransitionToList( pLevelList, count, (char *)STRING(pChangelevel->pev->netname), (char *)STRING(pChangelevel->pev->message), pentLandmark )) + // build a list of unique transitions + ALERT( at_aiconsole, "Map name %s, landmark name %s\n", STRING( pChangelevel->pev->netname ), STRING( pChangelevel->pev->message )); + if( AddTransitionToList( pLevelList, count, STRING( pChangelevel->pev->netname ), STRING( pChangelevel->pev->message ), pentLandmark )) { count++; - if ( count >= maxList )break;//List is FULL!!! + if( count >= maxList ) break; // list is FULL!!! + } + } + else + { + // build a list of unique transitions (direct mode, when landmark not used) + ALERT( at_aiconsole, "Map name %s\n", STRING( pChangelevel->pev->netname )); + if( AddTransitionToList( pLevelList, count, STRING( pChangelevel->pev->netname ), "", NULL )) + { + count++; + if( count >= maxList ) break; // list is FULL!!! } } pChangelevel = UTIL_FindEntityByClassname( pChangelevel, "trigger_changelevel" ); } - if ( gpGlobals->pSaveData && ((SAVERESTOREDATA *)gpGlobals->pSaveData)->pTable ) + if( gpGlobals->pSaveData && ((SAVERESTOREDATA *)gpGlobals->pSaveData)->pTable ) { CSave saveHelper( (SAVERESTOREDATA *)gpGlobals->pSaveData ); for ( i = 0; i < count; i++ ) { - int j, entityCount = 0; - CBaseEntity *pEntList[ MAX_TRANSITION_ENTITY ]; - int entityFlags[ MAX_TRANSITION_ENTITY ]; + int entityCount = 0; + CBaseEntity *pEntList[MAX_TRANSITION_ENTITY]; + int entityFlags[MAX_TRANSITION_ENTITY]; // Follow the linked list of entities in the PVS of the transition landmark - edict_t *pent = UTIL_EntitiesInPVS( pLevelList[i].pentLandmark ); + edict_t *pent = UTIL_EntitiesInPVS( pLevelList[i].pentLandmark ); + + if( FNullEnt( pent )) + { + // landmark is absent so use Classic Changelel: + // transfer client and him attached items + pent = UTIL_FindClientTransitions( INDEXENT( 1 )); + } // Build a list of valid entities in this linked list (we're going to use pent->v.chain again) - while ( !FNullEnt( pent ) ) + while ( !FNullEnt( pent )) { CBaseEntity *pEntity = CBaseEntity::Instance(pent); - if ( pEntity ) + if( pEntity ) { int caps = pEntity->ObjectCaps(); - if ( !(caps & FCAP_DONT_SAVE) ) - { - int flags = 0; - // If this entity can be moved or is global, mark it - if ( caps & FCAP_ACROSS_TRANSITION ) flags |= FENTTABLE_MOVEABLE; - if ( pEntity->pev->globalname && !pEntity->IsDormant() ) flags |= FENTTABLE_GLOBAL; - if ( flags ) + if(!( caps & FCAP_DONT_SAVE )) + { + int flags = 0; + + if( caps & FCAP_ACROSS_TRANSITION ) flags |= FENTTABLE_MOVEABLE; + if( pEntity->pev->globalname && !pEntity->IsDormant() ) flags |= FENTTABLE_GLOBAL; + if( flags ) { - pEntList[ entityCount ] = pEntity; - entityFlags[ entityCount ] = flags; + pEntList[entityCount] = pEntity; + entityFlags[entityCount] = flags; entityCount++; - if ( entityCount > MAX_TRANSITION_ENTITY ) Msg("ERROR: Too many entities across a transition!" ); + if( entityCount >= MAX_TRANSITION_ENTITY ) + { + ALERT( at_error, "Too many entities across a transition!" ); + break; + } } } } pent = pent->v.chain; } - for ( j = 0; j < entityCount; j++ ) + for ( int j = 0; j < entityCount; j++ ) { // Check to make sure the entity isn't screened out by a trigger_transition - if ( entityFlags[j] && UTIL_FindTransition( pEntList[j], pLevelList[i].landmarkName ) ) + if( entityFlags[j] && UTIL_FindTransition( pEntList[j], pLevelList[i].landmarkName )) { // Mark entity table with 1<pev->solid == SOLID_TRIGGER ) { - if( !stricmp( classname, "trigger_teleport" )) + if( !stricmp( classname, "trigger_teleport" )) // FIXME return ED_AMBIENT; else if( pClass->pev->movetype == MOVETYPE_TOSS ) return ED_NORMAL; // it's item or weapon diff --git a/server/global/saverestore.cpp b/server/global/saverestore.cpp index 0f077291..a56019b1 100644 --- a/server/global/saverestore.cpp +++ b/server/global/saverestore.cpp @@ -481,7 +481,6 @@ void CSave :: WriteVector( const char *pname, const float *value, int count ) void CSave :: WritePositionVector( const char *pname, const Vector &value ) { - if( m_pdata && m_pdata->fUseLandmark ) { Vector tmp = value - m_pdata->vecLandmarkOffset; @@ -584,12 +583,6 @@ int CSave :: WriteFields( const char *cname, const char *pname, void *pBaseData, #if 0 ALERT( at_console, "CSave::WriteFields( %s [%i fields])\n", pname, fieldCount ); - - if( !strcmp( pname, "Save Header" ) || !strcmp( pname, "ADJACENCY" ) || !strcmp( pname, "Game Header" )) - { - for( i = 0; i < fieldCount; i++ ) - ALERT( at_console, "FIELD: %s [%s][0x%x]\n", pFields[i].fieldName, gNames[pFields[i].fieldType], pFields[i].flags ); - } #endif // precalculate the number of empty fields emptyCount = 0; @@ -849,7 +842,8 @@ int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCou else { *((CBaseEntity **)pOutputData) = NULL; - if (entityIndex != -1) ALERT(at_console, "## Restore: invalid entitynum %d\n", entityIndex); + if( entityIndex != -1 ) + ALERT( at_console, "## Restore: invalid entitynum %d\n", entityIndex ); } break; case FIELD_EDICT: diff --git a/server/global/utils.cpp b/server/global/utils.cpp index 78ca354e..085eb5f5 100644 --- a/server/global/utils.cpp +++ b/server/global/utils.cpp @@ -571,38 +571,42 @@ void UTIL_FindHullIntersection( const Vector &vecSrc, TraceResult &tr, float *mi edict_t *UTIL_FindLandmark( string_t iLandmarkName ) { - return UTIL_FindLandmark( STRING( iLandmarkName)); + return UTIL_FindLandmark( STRING( iLandmarkName )); } edict_t *UTIL_FindLandmark( const char *pLandmarkName ) { CBaseEntity *pLandmark; + if( FStringNull( pLandmarkName ) || FStrEq( pLandmarkName, "" )) + return NULL; // landmark not specified + pLandmark = UTIL_FindEntityByTargetname( NULL, pLandmarkName ); - while ( pLandmark ) + while( pLandmark ) { // Found the landmark - if ( FClassnameIs( pLandmark->pev, "info_landmark" ) ) - return ENT(pLandmark->pev); - else pLandmark = UTIL_FindEntityByTargetname( pLandmark, pLandmarkName ); + if( FClassnameIs( pLandmark->pev, "info_landmark" )) + return ENT( pLandmark->pev ); + else pLandmark = UTIL_FindEntityByTargetname( pLandmark, pLandmarkName ); } - Msg("ERROR: Can't find landmark %s\n", pLandmarkName ); + + Msg( "ERROR: Can't find landmark %s\n", pLandmarkName ); return NULL; } int UTIL_FindTransition( CBaseEntity *pEntity, string_t iVolumeName ) { - return UTIL_FindTransition( pEntity, (char *)STRING( iVolumeName )); + return UTIL_FindTransition( pEntity, STRING( iVolumeName )); } -int UTIL_FindTransition( CBaseEntity *pEntity, char *pVolumeName ) +int UTIL_FindTransition( CBaseEntity *pEntity, const char *pVolumeName ) { CBaseEntity *pVolume; - if ( pEntity->ObjectCaps() & FCAP_FORCE_TRANSITION ) return 1; + if( pEntity->ObjectCaps() & FCAP_FORCE_TRANSITION ) return 1; - // If you're following another entity, follow it through the transition (weapons follow the player) - if ( pEntity->pev->movetype == MOVETYPE_FOLLOW && pEntity->pev->aiment != NULL) + // if you're following another entity, follow it through the transition (weapons follow the player) + if( pEntity->pev->movetype == MOVETYPE_FOLLOW && pEntity->pev->aiment != NULL ) { pEntity = CBaseEntity::Instance( pEntity->pev->aiment ); } @@ -610,19 +614,50 @@ int UTIL_FindTransition( CBaseEntity *pEntity, char *pVolumeName ) int inVolume = 1; // Unless we find a trigger_transition, everything is in the volume pVolume = UTIL_FindEntityByTargetname( NULL, pVolumeName ); - while ( pVolume ) + while( pVolume ) { - if ( FClassnameIs( pVolume->pev, "trigger_transition" ) ) + if( FClassnameIs( pVolume->pev, "trigger_transition" )) { - if ( pVolume->Intersects( pEntity ) ) // It touches one, it's in the volume + if( pVolume->Intersects( pEntity )) // it touches one, it's in the volume return 1; - else inVolume = 0; // Found a trigger_transition, but I don't intersect it + else inVolume = 0; // found a trigger_transition, but I don't intersect it } pVolume = UTIL_FindEntityByTargetname( pVolume, pVolumeName ); } return inVolume; } +/* +======================================================================== + UTIL_FindClientTransitions - returns list of client attached entites + e.g. weapons, items and other followed entities +======================================================================== +*/ +edict_t *UTIL_FindClientTransitions( edict_t *pClient ) +{ + edict_t *pEdict, *chain; + int i; + + chain = NULL; + pClient->v.chain = chain; // client is always add to tail of chain + chain = pClient; + + if( !pClient || pClient->free ) + return chain; + + for( i = 0; i < gpGlobals->numEntities; i++ ) + { + pEdict = INDEXENT( i ); + if( pEdict->free ) continue; + if( pEdict->v.movetype == MOVETYPE_FOLLOW && pEdict->v.aiment == pClient ) + { + pEdict->v.chain = chain; + chain = pEdict; + } + } + return chain; +} + //======================================================================== // UTIL_ClearPTR - clear all pointers before changelevel //======================================================================== @@ -630,10 +665,10 @@ void UTIL_ClearPTR( void ) { CBaseEntity *pEntity = NULL; - for ( int i = 1; i <= gpGlobals->maxEntities; i++ ) + for( int i = 1; i < gpGlobals->numEntities; i++ ) { edict_t *pEntityEdict = INDEXENT( i ); - if ( pEntityEdict && !pEntityEdict->free && !FStringNull(pEntityEdict->v.globalname) ) + if( pEntityEdict && !pEntityEdict->free && !FStringNull( pEntityEdict->v.globalname )) { pEntity = CBaseEntity::Instance( pEntityEdict ); } @@ -647,53 +682,49 @@ void UTIL_ClearPTR( void ) //======================================================================== void UTIL_ChangeLevel( string_t mapname, string_t spotname ) { - UTIL_ChangeLevel((char *)STRING( mapname ), (char *)STRING( spotname )); + UTIL_ChangeLevel( STRING( mapname ), STRING( spotname )); } void UTIL_ChangeLevel( const char *szNextMap, const char *szNextSpot ) { edict_t *pentLandmark; - LEVELLIST levels[16]; - ASSERT(!FStrEq(szNextMap, "")); + ASSERT( !FStrEq( szNextMap, "" )); - // Don't work in deathmatch - if ( IsMultiplayer()) return; - // Some people are firing these multiple times in a frame, disable - if ( NewLevel ) return; + // don't work in deathmatch + if( IsMultiplayer()) return; + + // some people are firing these multiple times in a frame, disable + if( NewLevel ) return; CBaseEntity *pPlayer = UTIL_PlayerByIndex( 1 ); - if (!UTIL_FindTransition( pPlayer, (char *)szNextSpot )) + if( !UTIL_FindTransition( pPlayer, szNextSpot )) { DevMsg( "Player isn't in the transition volume %s, aborting\n", szNextSpot ); return; } - // This object will get removed in the call to CHANGE_LEVEL, copy the params into "safe" memory - strcpy(st_szNextMap, szNextMap); - st_szNextSpot[0] = 0; // Init landmark to NULL + // this object will get removed in the call to CHANGE_LEVEL, copy the params into "safe" memory + strcpy( st_szNextMap, szNextMap ); + st_szNextSpot[0] = 0; // Init landmark to NULL // look for a landmark entity pentLandmark = UTIL_FindLandmark( szNextSpot ); - if ( !FNullEnt( pentLandmark ) ) + if( !FNullEnt( pentLandmark )) { - strcpy(st_szNextSpot, szNextSpot); - gpGlobals->spotOffset = VARS(pentLandmark)->origin; + strcpy( st_szNextSpot, szNextSpot ); + gpGlobals->spotOffset = VARS( pentLandmark )->origin; } - //try to found bsp file before loading nextlevel - char path[128]; - - sprintf(path, "maps/%s.bsp", st_szNextMap); - - if( FILE_EXISTS( path )) + // map must exist and contain info_player_start + if( IS_MAP_VALID( st_szNextMap )) { UTIL_ClearPTR(); - DevMsg( "CHANGE LEVEL: %s %s\n", st_szNextMap, st_szNextSpot ); + ALERT( at_aiconsole, "CHANGE LEVEL: %s %s\n", st_szNextMap, st_szNextSpot ); CHANGE_LEVEL( st_szNextMap, st_szNextSpot ); } - else Msg("Warning! Map %s not found!\n", st_szNextMap ); - NewLevel = TRUE;//bit who indiactes new level + else ALERT( at_warning, "map %s not found!\n", st_szNextMap ); + NewLevel = TRUE; // UTIL_ChangeLevel is called } //======================================================================== @@ -1893,7 +1924,7 @@ CBaseEntity *UTIL_FindEntityGeneric( const char *szWhatever, Vector &vecSrc, flo // returns a CBaseEntity pointer to a player by index. Only returns if the player is spawned and connected // otherwise returns NULL // Index is 1 based -CBaseEntity *UTIL_PlayerByIndex( int playerIndex ) +CBaseEntity *UTIL_PlayerByIndex( int playerIndex ) { CBaseEntity *pPlayer = NULL; diff --git a/server/global/utils.h b/server/global/utils.h index 54fbd163..7eac7260 100644 --- a/server/global/utils.h +++ b/server/global/utils.h @@ -328,6 +328,7 @@ extern CBaseEntity *UTIL_FindEntityByTarget(CBaseEntity *pStartEntity, const cha extern CBaseEntity *UTIL_FindEntityGeneric(const char *szName, Vector &vecSrc, float flRadius ); extern CBaseEntity *UTIL_FindGlobalEntity( string_t classname, string_t globalname ); extern CBaseEntity *UTIL_FindPlayerInSphere( const Vector &vecCenter, float flRadius ); +extern edict_t *UTIL_FindClientTransitions( edict_t *pClient ); extern CBasePlayer *UTIL_FindPlayerInPVS( edict_t *pent ); // returns a CBaseEntity pointer to a player by index. Only returns if the player is spawned and connected @@ -335,8 +336,9 @@ extern CBasePlayer *UTIL_FindPlayerInPVS( edict_t *pent ); // Index is 1 based extern CBaseEntity *UTIL_PlayerByIndex( int playerIndex ); -#define UTIL_EntitiesInPVS(pent) (*g_engfuncs.pfnEntitiesInPVS)(pent) -extern void UTIL_MakeVectors (const Vector &vecAngles); + +#define UTIL_EntitiesInPVS( pent ) (*g_engfuncs.pfnEntitiesInPVS)(pent) +extern void UTIL_MakeVectors( const Vector &vecAngles ); // Pass in an array of pointers and an array size, it fills the array and returns the number inserted extern int UTIL_MonstersInSphere( CBaseEntity **pList, int listMax, const Vector ¢er, float radius ); @@ -787,7 +789,7 @@ void UTIL_WatchTarget( CBaseEntity *pWatcher, CBaseEntity *pTarget); void UTIL_FindBreakable( CBaseEntity *Brush ); edict_t *UTIL_FindLandmark( string_t iLandmarkName ); edict_t *UTIL_FindLandmark( const char *pLandmarkName ); -int UTIL_FindTransition( CBaseEntity *pEntity, char *pVolumeName ); +int UTIL_FindTransition( CBaseEntity *pEntity, const char *pVolumeName ); int UTIL_FindTransition( CBaseEntity *pEntity, string_t iVolumeName ); void UTIL_FireTargets( const char *targetName, CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value = 0); void UTIL_FireTargets( int targetName, CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value = 0); diff --git a/server/monsters/player.cpp b/server/monsters/player.cpp index 67215386..91471c39 100644 --- a/server/monsters/player.cpp +++ b/server/monsters/player.cpp @@ -3426,15 +3426,16 @@ int CBasePlayer::Restore( CRestore &restore ) // default to normal spawn edict_t* pentSpawnSpot = EntSelectSpawnPoint( this ); - pev->origin = VARS(pentSpawnSpot)->origin + Vector(0,0,1); - pev->angles = VARS(pentSpawnSpot)->angles; + pev->origin = VARS( pentSpawnSpot )->origin + Vector( 0, 0, 1 ); + pev->viewangles = pev->angles = VARS( pentSpawnSpot )->angles; } + pev->viewangles.z = 0; // clear out roll pev->angles = pev->viewangles; pev->fixangle = TRUE; // turn this way immediately // Copied from spawn() for now - m_bloodColor = BLOOD_COLOR_RED; + m_bloodColor = BLOOD_COLOR_RED; g_ulModelIndexPlayer = pev->modelindex; @@ -3442,11 +3443,11 @@ int CBasePlayer::Restore( CRestore &restore ) { // Use the crouch HACK FixPlayerCrouchStuck( edict() ); - UTIL_SetSize(pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX); + UTIL_SetSize( pev, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX ); } else { - UTIL_SetSize(pev, VEC_HULL_MIN, VEC_HULL_MAX); + UTIL_SetSize( pev, VEC_HULL_MIN, VEC_HULL_MAX ); } RenewItems(); diff --git a/server/server.plg b/server/server.plg index 8edb93a2..86abd44a 100644 --- a/server/server.plg +++ b/server/server.plg @@ -3,9 +3,94 @@
 

Build Log

---------------------Configuration: server - Win32 Release-------------------- +--------------------Configuration: server - Win32 Debug--------------------

Command Lines

+Creating temporary file "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1780.tmp" with contents +[ +/nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "ents" /I "game" /I "global" /I "monsters" /I "../common" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR"..\temp\server\!debug/" /Fo"..\temp\server\!debug/" /Fd"..\temp\server\!debug/" /FD /c +"D:\Xash3D\src_main\server\global\dll_int.cpp" +] +Creating command line "cl.exe @C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1780.tmp" +Creating temporary file "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1781.tmp" with contents +[ +msvcrtd.lib /nologo /subsystem:windows /dll /incremental:yes /pdb:"..\temp\server\!debug/server.pdb" /debug /machine:I386 /nodefaultlib:"libc.lib" /def:".\server.def" /out:"..\temp\server\!debug/server.dll" /implib:"..\temp\server\!debug/server.lib" /pdbtype:sept +"\Xash3D\src_main\temp\server\!debug\ai_sound.obj" +"\Xash3D\src_main\temp\server\!debug\animating.obj" +"\Xash3D\src_main\temp\server\!debug\animation.obj" +"\Xash3D\src_main\temp\server\!debug\apache.obj" +"\Xash3D\src_main\temp\server\!debug\barnacle.obj" +"\Xash3D\src_main\temp\server\!debug\barney.obj" +"\Xash3D\src_main\temp\server\!debug\basebrush.obj" +"\Xash3D\src_main\temp\server\!debug\baseentity.obj" +"\Xash3D\src_main\temp\server\!debug\basefunc.obj" +"\Xash3D\src_main\temp\server\!debug\basefx.obj" +"\Xash3D\src_main\temp\server\!debug\baseinfo.obj" +"\Xash3D\src_main\temp\server\!debug\baseitem.obj" +"\Xash3D\src_main\temp\server\!debug\baselogic.obj" +"\Xash3D\src_main\temp\server\!debug\basemonster.obj" +"\Xash3D\src_main\temp\server\!debug\basemover.obj" +"\Xash3D\src_main\temp\server\!debug\baseother.obj" +"\Xash3D\src_main\temp\server\!debug\basepath.obj" +"\Xash3D\src_main\temp\server\!debug\basephys.obj" +"\Xash3D\src_main\temp\server\!debug\baserockets.obj" +"\Xash3D\src_main\temp\server\!debug\basetank.obj" +"\Xash3D\src_main\temp\server\!debug\basetrigger.obj" +"\Xash3D\src_main\temp\server\!debug\baseutil.obj" +"\Xash3D\src_main\temp\server\!debug\baseweapon.obj" +"\Xash3D\src_main\temp\server\!debug\baseworld.obj" +"\Xash3D\src_main\temp\server\!debug\client.obj" +"\Xash3D\src_main\temp\server\!debug\combat.obj" +"\Xash3D\src_main\temp\server\!debug\decals.obj" +"\Xash3D\src_main\temp\server\!debug\defaultai.obj" +"\Xash3D\src_main\temp\server\!debug\dll_int.obj" +"\Xash3D\src_main\temp\server\!debug\flyingmonster.obj" +"\Xash3D\src_main\temp\server\!debug\game.obj" +"\Xash3D\src_main\temp\server\!debug\gamerules.obj" +"\Xash3D\src_main\temp\server\!debug\generic.obj" +"\Xash3D\src_main\temp\server\!debug\globals.obj" +"\Xash3D\src_main\temp\server\!debug\gman.obj" +"\Xash3D\src_main\temp\server\!debug\hassassin.obj" +"\Xash3D\src_main\temp\server\!debug\headcrab.obj" +"\Xash3D\src_main\temp\server\!debug\hgrunt.obj" +"\Xash3D\src_main\temp\server\!debug\leech.obj" +"\Xash3D\src_main\temp\server\!debug\legacy.obj" +"\Xash3D\src_main\temp\server\!debug\lights.obj" +"\Xash3D\src_main\temp\server\!debug\multiplay_gamerules.obj" +"\Xash3D\src_main\temp\server\!debug\nodes.obj" +"\Xash3D\src_main\temp\server\!debug\osprey.obj" +"\Xash3D\src_main\temp\server\!debug\parent.obj" +"\Xash3D\src_main\temp\server\!debug\player.obj" +"\Xash3D\src_main\temp\server\!debug\rat.obj" +"\Xash3D\src_main\temp\server\!debug\roach.obj" +"\Xash3D\src_main\temp\server\!debug\saverestore.obj" +"\Xash3D\src_main\temp\server\!debug\scientist.obj" +"\Xash3D\src_main\temp\server\!debug\scripted.obj" +"\Xash3D\src_main\temp\server\!debug\sfx.obj" +"\Xash3D\src_main\temp\server\!debug\singleplay_gamerules.obj" +"\Xash3D\src_main\temp\server\!debug\sound.obj" +"\Xash3D\src_main\temp\server\!debug\spectator.obj" +"\Xash3D\src_main\temp\server\!debug\squadmonster.obj" +"\Xash3D\src_main\temp\server\!debug\talkmonster.obj" +"\Xash3D\src_main\temp\server\!debug\teamplay_gamerules.obj" +"\Xash3D\src_main\temp\server\!debug\turret.obj" +"\Xash3D\src_main\temp\server\!debug\utils.obj" +"\Xash3D\src_main\temp\server\!debug\weapon_generic.obj" +"\Xash3D\src_main\temp\server\!debug\zombie.obj" +] +Creating command line "link.exe @C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1781.tmp" +Creating temporary file "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1782.bat" with contents +[ +@echo off +copy \Xash3D\src_main\temp\server\!debug\server.dll "D:\Xash3D\bin\server.dll" +] +Creating command line "C:\DOCUME~1\MIKE~1.MIK\LOCALS~1\Temp\RSP1782.bat" +Compiling... +dll_int.cpp +Linking... +

Output Window

+Performing Custom Build Step on \Xash3D\src_main\temp\server\!debug\server.dll +Скопировано файлов: 1. diff --git a/todo.log b/todo.log index 17833f20..f030a8a8 100644 --- a/todo.log +++ b/todo.log @@ -151,4 +151,8 @@ Beta 13.12.09 124. fixup studio events on client-side OK 125. sort & implement engfuncs on server.dll 126. implement trace from Quake3 -127. debug sv.edicts and cl.edicts management +127. debug sv.edicts and cl.edicts management OK +128. fixup sprites lerping OK +129. fixup sound orientation OK +130. don't show console on changelevel OK +131. support for doom3-style parsing diff --git a/vsound/s_main.c b/vsound/s_main.c index dc33907a..0a8c0e3a 100644 --- a/vsound/s_main.c +++ b/vsound/s_main.c @@ -583,8 +583,8 @@ void S_Update( int clientnum, const vec3_t position, const vec3_t velocity, cons al_state.clientnum = clientnum; // set up listener - VectorSet( s_listener.position, position[1], position[2], -position[0]); - VectorSet( s_listener.velocity, velocity[1], velocity[2], -velocity[0]); + VectorSet( s_listener.position, position[1], position[2], -position[0] ); + VectorSet( s_listener.velocity, velocity[1], velocity[2], -velocity[0] ); // set listener orientation matrix s_listener.orientation[0] = at[1];