14 Mar 2018

This commit is contained in:
g-cont 2018-03-14 00:00:00 +03:00 committed by Alibek Omarov
parent 556275f912
commit d67919a678
51 changed files with 544 additions and 441 deletions

View File

@ -61,19 +61,19 @@ BRUSH MODELS
#define LS_UNUSED 0xFE
#define LS_NONE 0xFF
// these limis not using by modelloader only for display 'mapstats' correctly
// these limis not using by modelloader but only for displaying 'mapstats' correctly
#ifdef SUPPORT_BSP2_FORMAT
#define MAX_MAP_MODELS 2048 // embedded models
#define MAX_MAP_ENTSTRING 0x200000 // 2 Mb should be enough
#define MAX_MAP_PLANES 131072 // can be increased without problems
#define MAX_MAP_NODES 262144 // because negative shorts are leafs
#define MAX_MAP_CLIPNODES 524288 // because negative shorts are contents
#define MAX_MAP_NODES 262144 // can be increased without problems
#define MAX_MAP_CLIPNODES 524288 // can be increased without problems
#define MAX_MAP_LEAFS 131072 // CRITICAL STUFF to run ad_sepulcher!!!
#define MAX_MAP_VERTS 524288 // unsigned short limit
#define MAX_MAP_FACES 262144 // unsigned short limit
#define MAX_MAP_MARKSURFACES 524288 // unsigned short limit
#define MAX_MAP_VERTS 524288 // can be increased without problems
#define MAX_MAP_FACES 262144 // can be increased without problems
#define MAX_MAP_MARKSURFACES 524288 // can be increased without problems
#else
#define MAX_MAP_MODELS 512 // embedded models
#define MAX_MAP_MODELS 768 // embedded models
#define MAX_MAP_ENTSTRING 0x80000 // 512 kB should be enough
#define MAX_MAP_PLANES 65536 // can be increased without problems
#define MAX_MAP_NODES 32767 // because negative shorts are leafs
@ -84,17 +84,15 @@ BRUSH MODELS
#define MAX_MAP_MARKSURFACES 65535 // unsigned short limit
#endif
#define MAX_MAP_BRUSHES 32768 // unsigned short limit
#define MAX_MAP_ENTITIES 8192 // can be increased up to 32768 if needed
#define MAX_MAP_ENTITIES 8192 // network limit
#define MAX_MAP_TEXINFO MAX_MAP_FACES // in theory each face may have personal texinfo
#define MAX_MAP_EDGES 0x100000 // can be increased but not needed
#define MAX_MAP_SURFEDGES 0x200000 // can be increased but not needed
#define MAX_MAP_TEXTURES 2048 // can be increased but not needed
#define MAX_MAP_EDGES 0x100000 // can be increased but not needs
#define MAX_MAP_SURFEDGES 0x200000 // can be increased but not needs
#define MAX_MAP_TEXTURES 2048 // can be increased but not needs
#define MAX_MAP_MIPTEX 0x2000000 // 32 Mb internal textures data
#define MAX_MAP_LIGHTING 0x2000000 // 32 Mb lightmap raw data (can contain deluxemaps)
#define MAX_MAP_VISIBILITY 0x1000000 // 16 Mb visdata
#define MAX_MAP_FACEINFO 8192 // can be increased but not needs
#define MAX_TOTAL_CLIPNODES 524288
// quake lump ordering
#define LUMP_ENTITIES 0

View File

@ -208,6 +208,7 @@ typedef struct mextrasurf_s
struct msurface_s *lightmapchain; // lightmapped polys
struct mextrasurf_s *detailchain; // for detail textures drawing
struct mextrasurf_s *mirrorchain; // for gl_texsort drawing
struct mextrasurf_s *lumachain; // draw fullbrights
struct cl_entity_s *parent; // upcast to owner entity
int mirrortexturenum; // gl texnum

View File

@ -759,9 +759,6 @@ qboolean CL_DemoReadMessage( byte *buffer, size_t *length )
return false;
}
// HACKHACK: changedemo issues
if( !cls.netchan.remote_address.type ) cls.netchan.remote_address.type = NA_LOOPBACK;
if(( !cl.background && ( cl.paused || cls.key_dest != key_game )) || cls.key_dest == key_console )
{
demo.starttime += host.frametime;

View File

@ -1193,14 +1193,31 @@ static qboolean CL_LoadHudSprite( const char *szSpriteName, model_t *m_pSprite,
Assert( m_pSprite != NULL );
buf = FS_LoadFile( szSpriteName, &size, false );
if( !buf ) return false;
Q_strncpy( m_pSprite->name, szSpriteName, sizeof( m_pSprite->name ));
// it's hud sprite, make difference names to prevent free shared textures
if( type == SPR_CLIENT || type == SPR_HUDSPRITE )
SetBits( m_pSprite->flags, MODEL_CLIENT );
m_pSprite->numtexinfo = texFlags; // store texFlags into numtexinfo
if( FS_FileSize( szSpriteName, false ) == -1 )
{
if( cls.state != ca_active && cl.maxclients > 1 )
{
// trying to download sprite from server
CL_AddClientResource( szSpriteName, t_model );
m_pSprite->needload = NL_NEEDS_LOADED;
return true;
}
else
{
Mod_UnloadSpriteModel( m_pSprite );
return false;
}
}
buf = FS_LoadFile( szSpriteName, &size, false );
ASSERT( buf != NULL );
if( type == SPR_MAPSPRITE )
Mod_LoadMapSprite( m_pSprite, buf, size, &loaded );
@ -1214,6 +1231,8 @@ static qboolean CL_LoadHudSprite( const char *szSpriteName, model_t *m_pSprite,
return false;
}
m_pSprite->needload = NL_PRESENT;
return true;
}
@ -1227,7 +1246,7 @@ tent sprites or overview images
*/
static model_t *CL_LoadSpriteModel( const char *filename, uint type, uint texFlags )
{
char name[64];
char name[MAX_QPATH];
model_t *mod;
int i;
@ -1245,10 +1264,14 @@ static model_t *CL_LoadSpriteModel( const char *filename, uint type, uint texFla
{
if( !Q_stricmp( mod->name, name ))
{
if( mod->mempool )
mod->needload = NL_PRESENT;
else mod->needload = NL_NEEDS_LOADED;
if( mod->needload == NL_NEEDS_LOADED )
{
if( CL_LoadHudSprite( name, mod, type, texFlags ))
return mod;
}
// prolonge registration
mod->needload = NL_PRESENT;
return mod;
}
}
@ -1265,11 +1288,7 @@ static model_t *CL_LoadSpriteModel( const char *filename, uint type, uint texFla
// load new map sprite
if( CL_LoadHudSprite( name, mod, type, texFlags ))
{
mod->needload = NL_PRESENT;
return mod;
}
return NULL;
}
@ -1331,9 +1350,27 @@ CL_GetSpritePointer
*/
const model_t *CL_GetSpritePointer( HSPRITE hSprite )
{
model_t *mod;
if( hSprite <= 0 || hSprite >= MAX_CLIENT_SPRITES )
return NULL; // bad image
return &clgame.sprites[hSprite];
mod = &clgame.sprites[hSprite];
if( mod->needload == NL_NEEDS_LOADED )
{
int type = FBitSet( mod->flags, MODEL_CLIENT ) ? SPR_HUDSPRITE : SPR_MAPSPRITE;
if( CL_LoadHudSprite( mod->name, mod, type, mod->numtexinfo ))
return mod;
}
if( mod->mempool )
{
mod->needload = NL_PRESENT;
return mod;
}
return NULL;
}
/*
@ -3755,7 +3792,7 @@ qboolean CL_LoadProgs( const char *name )
clgame.mempool = Mem_AllocPool( "Client Edicts Zone" );
clgame.entities = NULL;
clgame.hInstance = COM_LoadLibrary( name, false );
clgame.hInstance = COM_LoadLibrary( name, false, false );
if( !clgame.hInstance ) return false;
// clear exports

View File

@ -370,11 +370,11 @@ static HIMAGE pfnPIC_Load( const char *szPicName, const byte *image_buf, long im
}
// add default parms to image
flags |= TF_IMAGE;
SetBits( flags, TF_IMAGE );
host.decal_loading = true; // allow decal images for menu
Image_SetForceFlags( IL_LOAD_DECAL ); // allow decal images for menu
tx = GL_LoadTexture( szPicName, image_buf, image_size, flags, NULL );
host.decal_loading = false;
Image_ClearForceFlags();
return tx;
}
@ -842,7 +842,7 @@ int pfnCheckGameDll( void )
if( SV_Initialized( )) return true;
if(( hInst = COM_LoadLibrary( GI->game_dll, true )) != NULL )
if(( hInst = COM_LoadLibrary( GI->game_dll, true, false )) != NULL )
{
COM_FreeLibrary( hInst );
return true;
@ -885,13 +885,6 @@ pfnStartBackgroundTrack
static void pfnStartBackgroundTrack( const char *introTrack, const char *mainTrack )
{
S_StartBackgroundTrack( introTrack, mainTrack, 0, false );
// HACKHACK to remove glitches from background track while new game is started.
if( !introTrack && !mainTrack )
{
S_Activate( 0, host.hWnd );
S_Activate( 1, host.hWnd );
}
}
// engine callbacks
@ -1008,20 +1001,13 @@ qboolean UI_LoadProgs( void )
// setup globals
gameui.globals = &gpGlobals;
if(!( gameui.hInstance = COM_LoadLibrary( va( "%s/menu.dll", GI->dll_path ), false )))
if(( gameui.hInstance = COM_LoadLibrary( va( "%s/menu.dll", GI->dll_path ), false, false )) == NULL )
{
FS_AllowDirectPaths( true );
if(!( gameui.hInstance = COM_LoadLibrary( "../menu.dll", false )))
{
FS_AllowDirectPaths( false );
if(( gameui.hInstance = COM_LoadLibrary( "menu.dll", false, true )) == NULL )
return false;
}
FS_AllowDirectPaths( false );
}
if(!( GetMenuAPI = (MENUAPI)COM_GetProcAddress( gameui.hInstance, "GetMenuAPI" )))
if(( GetMenuAPI = (MENUAPI)COM_GetProcAddress( gameui.hInstance, "GetMenuAPI" )) == NULL )
{
COM_FreeLibrary( gameui.hInstance );
MsgDev( D_NOTE, "UI_LoadProgs: can't init menu API\n" );

View File

@ -36,6 +36,7 @@ CVAR_DEFINE_AUTO( cl_allow_upload, "1", FCVAR_ARCHIVE, "allow to uploading resou
CVAR_DEFINE_AUTO( cl_download_ingame, "1", FCVAR_ARCHIVE, "allow to downloading resources while client is active" );
CVAR_DEFINE_AUTO( cl_logofile, "lambda", FCVAR_ARCHIVE, "player logo name" );
CVAR_DEFINE_AUTO( cl_logocolor, "orange", FCVAR_ARCHIVE, "player logo color" );
CVAR_DEFINE_AUTO( cl_test_bandwidth, "1", FCVAR_ARCHIVE, "test network bandwith before connection" );
convar_t *rcon_client_password;
convar_t *rcon_address;
convar_t *cl_timeout;
@ -1103,11 +1104,10 @@ void CL_CheckForResend( void )
cls.connect_retry++;
Con_Printf( "Connecting to %s...\n", cls.servername );
#if 0
Netchan_OutOfBandPrint( NS_CLIENT, adr, "getchallenge\n" );
#else
Netchan_OutOfBandPrint( NS_CLIENT, adr, "bandwidth %i %i\n", PROTOCOL_VERSION, cls.max_fragment_size );
#endif
if( cl_test_bandwidth.value )
Netchan_OutOfBandPrint( NS_CLIENT, adr, "bandwidth %i %i\n", PROTOCOL_VERSION, cls.max_fragment_size );
else Netchan_OutOfBandPrint( NS_CLIENT, adr, "getchallenge\n" );
}
resource_t *CL_AddResource( resourcetype_t type, const char *name, int size, qboolean bFatalIfMissing, int index )
@ -1285,11 +1285,13 @@ void CL_ClearState( void )
Cvar_FullSet( "cl_background", "0", FCVAR_READ_ONLY );
cl.maxclients = 1; // allow to drawing player in menu
cl.mtime[0] = cl.mtime[1] = 1.0f; // because level starts from 1.0f second
cls.signon = 0;
cl.resourcesneeded.pNext = cl.resourcesneeded.pPrev = &cl.resourcesneeded;
cl.resourcesonhand.pNext = cl.resourcesonhand.pPrev = &cl.resourcesonhand;
CL_CreateResourceList();
CL_ClearSpriteTextures(); // now all hud sprites are invalid
cl.local.interp_amount = 0.1f;
cl.local.scr_fov = 90.0f;
@ -1974,7 +1976,7 @@ void CL_ReadNetMessage( void )
// can't be a valid sequenced packet
if( cls.state < ca_connected ) continue;
if( MSG_GetMaxBytes( &net_message ) < 8 )
if( !cls.demoplayback && MSG_GetMaxBytes( &net_message ) < 8 )
{
MsgDev( D_WARN, "%s: runt packet\n", NET_AdrToString( net_from ));
continue;
@ -2414,9 +2416,6 @@ qboolean CL_PrecacheResources( void )
if( cl.models[pRes->nIndex] == NULL )
{
if( pRes->ucFlags != 0 )
MsgDev( D_WARN, "model %s not found and not available\n", pRes->szFileName );
if( FBitSet( pRes->ucFlags, RES_FATALIFMISSING ))
{
S_EndRegistration();
@ -2518,6 +2517,7 @@ void CL_InitLocal( void )
Cvar_RegisterVariable( &cl_download_ingame );
Cvar_RegisterVariable( &cl_logofile );
Cvar_RegisterVariable( &cl_logocolor );
Cvar_RegisterVariable( &cl_test_bandwidth );
// register our variables
cl_crosshair = Cvar_Get( "crosshair", "1", FCVAR_ARCHIVE, "show weapon chrosshair" );

View File

@ -752,7 +752,6 @@ void CL_BatchResourceRequest( void )
CL_RegisterResources( &msg );
}
Msg( "download request %d bytes\n", MSG_GetNumBytesWritten( &msg ));
Netchan_CreateFragments( &cls.netchan, &msg );
Netchan_FragSend( &cls.netchan );
}
@ -1079,21 +1078,17 @@ void CL_ParseServerData( sizebuf_t *msg )
cls.timestart = Sys_DoubleTime();
cls.demowaiting = false; // server is changed
CL_ClearSpriteTextures(); // now all hud sprites are invalid
// wipe the client_t struct
if( !cls.changelevel && !cls.changedemo )
CL_ClearState ();
cls.state = ca_connected;
// Re-init hud video, especially if we changed game directories
clgame.dllFuncs.pfnVidInit();
// parse protocol version number
cls.serverProtocol = MSG_ReadLong( msg );
i = MSG_ReadLong( msg );
if( cls.serverProtocol != PROTOCOL_VERSION )
Host_Error( "Server use invalid protocol (%i should be %i)\n", cls.serverProtocol, PROTOCOL_VERSION );
if( i != PROTOCOL_VERSION )
Host_Error( "Server use invalid protocol (%i should be %i)\n", i, PROTOCOL_VERSION );
cl.servercount = MSG_ReadLong( msg );
cl.checksum = MSG_ReadLong( msg );
@ -1108,8 +1103,18 @@ void CL_ParseServerData( sizebuf_t *msg )
Q_strncpy( gamefolder, MSG_ReadString( msg ), MAX_QPATH );
host.features = (uint)MSG_ReadLong( msg );
// receive the player hulls
for( i = 0; i < MAX_MAP_HULLS * 3; i++ )
{
host.player_mins[i/3][i%3] = MSG_ReadChar( msg );
host.player_maxs[i/3][i%3] = MSG_ReadChar( msg );
}
if( clgame.maxModels > MAX_MODELS )
MsgDev( D_WARN, "server model limit is above client model limit %i > %i\n", clgame.maxModels, MAX_MODELS );
Con_Printf( S_WARN "server model limit is above client model limit %i > %i\n", clgame.maxModels, MAX_MODELS );
// Re-init hud video, especially if we changed game directories
clgame.dllFuncs.pfnVidInit();
if( Con_FixedFont( ))
{
@ -1118,13 +1123,6 @@ void CL_ParseServerData( sizebuf_t *msg )
Con_Print( va( "%c%s\n\n", 2, clgame.maptitle ));
}
// receive the player hulls
for( i = 0; i < MAX_MAP_HULLS * 3; i++ )
{
host.player_mins[i/3][i%3] = MSG_ReadChar( msg );
host.player_maxs[i/3][i%3] = MSG_ReadChar( msg );
}
// multiplayer game?
if( cl.maxclients > 1 )
{
@ -2226,14 +2224,15 @@ void CL_ParseUserMessage( sizebuf_t *msg, int svc_num )
{
clgame.msg[i].func( clgame.msg[i].name, iSize, pbuf );
// HACKHACK: run final credits for Half-Life
// because hl1 doesn't have call END_SECTION
#ifdef HACKS_RELATED_HLMODS
// run final credits for Half-Life because hl1 doesn't have call END_SECTION
if( !Q_stricmp( clgame.msg[i].name, "HudText" ) && !Q_stricmp( GI->gamefolder, "valve" ))
{
// it's a end, so we should run credits
if( !Q_strcmp( (char *)pbuf, "END3" ))
Host_Credits();
}
#endif
}
else
{

View File

@ -124,8 +124,8 @@ void CL_AddClientResource( const char *filename, int type )
break;
}
if( p == &cl.resourcesneeded )
return; // already existed ?
if( p != &cl.resourcesneeded )
return; // already in list?
pResource = Mem_Alloc( cls.mempool, sizeof( resource_t ));
@ -150,7 +150,8 @@ void CL_AddClientResources( void )
char filepath[MAX_QPATH];
int i;
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
// don't request resources from localhost or in quake-compatibility mode
if( cl.maxclients <= 1 || FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
return;
// check sprites first
@ -223,7 +224,6 @@ int CL_FxBlend( cl_entity_t *e )
case kRenderFxPulseFast:
blend = e->curstate.renderamt + 0x10 * sin( cl.time * 8 + offset );
break;
// JAY: HACK for now -- not time based
case kRenderFxFadeSlow:
if( RP_NORMALPASS( ))
{
@ -2891,7 +2891,7 @@ void CL_AddModelEffects( cl_entity_t *ent )
dl->color.r = dl->color.g = dl->color.b = 200;
VectorCopy( ent->origin, dl->origin );
// HACKHACK: get radius from head entity
// XASH SPECIFIC: get radius from head entity
if( ent->curstate.rendermode != kRenderNormal )
dl->radius = Q_max( 0, ent->curstate.renderamt - 55 );
else dl->radius = 200;
@ -3040,10 +3040,12 @@ int CL_DecalIndex( int id )
{
id = bound( 0, id, MAX_DECALS - 1 );
host.decal_loading = true;
if( cl.decal_index[id] == 0 )
{
Image_SetForceFlags( IL_LOAD_DECAL );
cl.decal_index[id] = GL_LoadTexture( host.draw_decals[id], NULL, 0, TF_DECAL, NULL );
host.decal_loading = false;
Image_ClearForceFlags();
}
return cl.decal_index[id];
}

View File

@ -71,7 +71,7 @@ void SCR_CreateStartupVids( void )
{
file_t *f;
f = FS_Open( "media/StartupVids.txt", "w", false );
f = FS_Open( DEFAULT_VIDEOLIST_PATH, "w", false );
if( !f ) return;
// make standard video playlist: sierra, valve
@ -86,17 +86,17 @@ void SCR_CheckStartupVids( void )
char *afile, *pfile;
string token;
if( Sys_CheckParm( "-nointro" ) || host.allow_console || cls.demonum != -1 || GameState->nextstate != STATE_RUNFRAME )
if( Sys_CheckParm( "-nointro" ) || host_developer.value || cls.demonum != -1 || GameState->nextstate != STATE_RUNFRAME )
{
// don't run movies where we in developer-mode
cls.movienum = -1;
return;
}
if( !FS_FileExists( "media/StartupVids.txt", false ))
if( !FS_FileExists( DEFAULT_VIDEOLIST_PATH, false ))
SCR_CreateStartupVids();
afile = FS_LoadFile( "media/StartupVids.txt", NULL, false );
afile = FS_LoadFile( DEFAULT_VIDEOLIST_PATH, NULL, false );
if( !afile ) return; // something bad happens
pfile = afile;
@ -107,7 +107,7 @@ void SCR_CheckStartupVids( void )
if( ++c > MAX_MOVIES - 1 )
{
MsgDev( D_WARN, "Host_StartMovies: max %i movies in StartupVids\n", MAX_MOVIES );
Con_Printf( S_WARN "too many movies (%d) specified in %s\n", MAX_MOVIES, DEFAULT_VIDEOLIST_PATH );
break;
}
}
@ -115,13 +115,9 @@ void SCR_CheckStartupVids( void )
Mem_Free( afile );
// run cinematic
if( !SV_Active() && cls.movienum != -1 && cls.state != ca_cinematic )
{
cls.movienum = 0;
SCR_NextMovie ();
Cbuf_Execute();
}
else cls.movienum = -1;
cls.movienum = 0;
SCR_NextMovie ();
Cbuf_Execute();
}
/*

View File

@ -20,7 +20,6 @@ GNU General Public License for more details.
#include "cdll_int.h"
#include "menu_int.h"
#include "cl_entity.h"
#include "com_model.h"
#include "mod_local.h"
#include "pm_defs.h"
#include "pm_movevars.h"
@ -581,7 +580,6 @@ typedef struct
byte datagram_buf[MAX_DATAGRAM];
netchan_t netchan;
int serverProtocol; // in case we are doing some kind of version hack
int challenge; // from the server to use for connecting
float packet_loss;

View File

@ -1390,7 +1390,7 @@ void R_DrawAliasModel( cl_entity_t *e )
// init time
R_AliasSetupTimings();
// HACKHACK: keep the angles unchanged
// angles will be modify below keep original
VectorCopy( e->angles, angles );
R_AliasLerpMovement( e );
@ -1490,7 +1490,7 @@ void R_DrawAliasModel( cl_entity_t *e )
R_LoadIdentity();
}
// HACKHACK: keep the angles unchanged
// restore original angles
VectorCopy( angles, e->angles );
}

View File

@ -1190,7 +1190,7 @@ void R_BeamDraw( BEAM *pbeam, float frametime )
{
cl_entity_t *pStart;
// HACKHACK: get brightness from head entity
// XASH SPECIFIC: get brightness from head entity
pStart = R_BeamGetEntity( pbeam->startEntity );
if( pStart && pStart->curstate.rendermode != kRenderNormal )
pbeam->brightness = CL_FxBlend( pStart ) / 255.0f;

View File

@ -1332,10 +1332,6 @@ int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags, i
// set some image flags
Image_SetForceFlags( picFlags );
// HACKHACK: get rid of black vertical line on a 'BlackMesa map'
if( !Q_strcmp( name, "#lab1_map1.mip" ) || !Q_strcmp( name, "#lab1_map2.mip" ))
flags |= TF_NEAREST;
pic = FS_LoadImage( name, buf, size );
if( !pic ) return 0; // couldn't loading image
@ -1659,23 +1655,23 @@ int GL_CreateTexture( const char *name, int width, int height, const void *buffe
r_empty.flags = IMAGE_HAS_COLOR | (( flags & TF_HAS_ALPHA ) ? IMAGE_HAS_ALPHA : 0 );
r_empty.buffer = (byte *)buffer;
if( flags & TF_TEXTURE_1D )
if( FBitSet( flags, TF_TEXTURE_1D ))
{
r_empty.height = 1;
r_empty.size = r_empty.width * 4;
}
else if( flags & TF_TEXTURE_3D )
else if( FBitSet( flags, TF_TEXTURE_3D ))
{
if( !GL_Support( GL_TEXTURE_3D_EXT ))
return 0;
r_empty.depth = r_empty.width; // HACKHACK
r_empty.depth = r_empty.width; // assume 3D texture as cube
r_empty.size = r_empty.width * r_empty.height * r_empty.depth * 4;
}
else if( flags & TF_CUBEMAP )
else if( FBitSet( flags, TF_CUBEMAP ))
{
flags &= ~TF_CUBEMAP; // will be set later
r_empty.flags |= IMAGE_CUBEMAP;
SetBits( r_empty.flags, IMAGE_CUBEMAP );
ClearBits( flags, TF_CUBEMAP ); // will be set later
r_empty.size *= 6;
}

View File

@ -17,7 +17,6 @@ GNU General Public License for more details.
#define GL_LOCAL_H
#include "gl_export.h"
#include "com_model.h"
#include "cl_entity.h"
#include "render_api.h"
#include "protocol.h"

View File

@ -650,13 +650,15 @@ static void R_CheckFog( void )
return;
}
// special hack fog Spirit 1.9 that used direct calls of glFog-functions
#ifdef HACKS_RELATED_HLMODS
// special condition for Spirit 1.9 that used direct calls of glFog-functions
if(( !RI.fogEnabled && !RI.fogCustom ) && pglIsEnabled( GL_FOG ) && VectorIsNull( RI.fogColor ))
{
// fill the fog color from GL-state machine
pglGetFloatv( GL_FOG_COLOR, RI.fogColor );
RI.fogSkybox = true;
}
#endif
RI.fogEnabled = false;
if( RI.onlyClientDraw || cl.local.waterlevel < 3 || !RI.drawWorld || !RI.viewleaf )

View File

@ -392,7 +392,7 @@ void CL_DrawParticles( double frametime )
{
size = PART_SIZE; // get initial size of particle
// HACKHACK a scale up to keep particles from disappearing
// scale up to keep particles from disappearing
size += (p->org[0] - RI.vieworg[0]) * RI.cull_vforward[0];
size += (p->org[1] - RI.vieworg[1]) * RI.cull_vforward[1];
size += (p->org[2] - RI.vieworg[2]) * RI.cull_vforward[2];

View File

@ -32,11 +32,11 @@ static int nColinElim; // stats
static vec2_t world_orthocenter;
static vec2_t world_orthohalf;
static uint r_blocklights[BLOCK_SIZE_MAX*BLOCK_SIZE_MAX*3];
static glpoly_t *fullbright_polys[MAX_TEXTURES];
static qboolean draw_fullbrights = false;
static mextrasurf_t *fullbright_surfaces[MAX_TEXTURES];
static mextrasurf_t *detail_surfaces[MAX_TEXTURES];
static int rtable[MOD_FRAMES][MOD_FRAMES];
static qboolean draw_alpha_surfaces = false;
static qboolean draw_fullbrights = false;
static qboolean draw_details = false;
static msurface_t *skychain = NULL;
static gllightmapstate_t gl_lms;
@ -731,8 +731,7 @@ void DrawGLPoly( glpoly_t *p, float xScale, float yScale )
if( !p ) return;
// special hack for non-lightmapped surfaces
if( p->flags & SURF_DRAWTILED )
if( FBitSet( p->flags, SURF_DRAWTILED ))
GL_ResetFogColor();
if( p->flags & SURF_CONVEYOR )
@ -781,8 +780,7 @@ void DrawGLPoly( glpoly_t *p, float xScale, float yScale )
pglEnd();
// special hack for non-lightmapped surfaces
if( p->flags & SURF_DRAWTILED )
if( FBitSet( p->flags, SURF_DRAWTILED ))
GL_SetupFogColorForSurfaces();
}
@ -969,8 +967,8 @@ R_RenderFullbrights
*/
void R_RenderFullbrights( void )
{
glpoly_t *p;
int i;
mextrasurf_t *es, *p;
int i;
if( !draw_fullbrights )
return;
@ -984,13 +982,16 @@ void R_RenderFullbrights( void )
for( i = 1; i < MAX_TEXTURES; i++ )
{
if( !fullbright_polys[i] )
continue;
es = fullbright_surfaces[i];
if( !es ) continue;
GL_Bind( GL_TEXTURE0, i );
for( p = fullbright_polys[i]; p; p = p->next )
DrawGLPoly( p, 0.0f, 0.0f );
fullbright_polys[i] = NULL;
for( p = es; p; p = p->lumachain )
DrawGLPoly( p->surf->polys, 0.0f, 0.0f );
fullbright_surfaces[i] = NULL;
es->lumachain = NULL;
}
pglDisable( GL_BLEND );
@ -1072,18 +1073,17 @@ void R_RenderBrushPoly( msurface_t *fa, int cull_type )
GL_Bind( GL_TEXTURE0, t->gl_texturenum );
if( fa->flags & SURF_DRAWTURB )
if( FBitSet( fa->flags, SURF_DRAWTURB ))
{
// warp texture, no lightmaps
EmitWaterPolys( fa, (cull_type == CULL_BACKSIDE));
return;
}
if( t->fb_texturenum && fa->polys )
if( t->fb_texturenum )
{
// HACKHACK: store fullbrights in poly->next (only for non-water surfaces)
fa->polys->next = fullbright_polys[t->fb_texturenum];
fullbright_polys[t->fb_texturenum] = fa->polys;
fa->info->lumachain = fullbright_surfaces[t->fb_texturenum];
fullbright_surfaces[t->fb_texturenum] = fa->info;
draw_fullbrights = true;
}
@ -1417,9 +1417,18 @@ void R_SetRenderMode( cl_entity_t *e )
case kRenderTransAlpha:
pglEnable( GL_ALPHA_TEST );
pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
{
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
pglColor4f( 1.0f, 1.0f, 1.0f, tr.blend );
pglEnable( GL_BLEND );
}
else
{
pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
pglDisable( GL_BLEND );
}
pglAlphaFunc( GL_GREATER, 0.25f );
pglDisable( GL_BLEND );
break;
default:
pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
@ -1440,6 +1449,7 @@ void R_DrawBrushModel( cl_entity_t *e )
{
int i, k, num_sorted;
vec3_t origin_l, oldorigin;
int old_rendermode;
vec3_t mins, maxs;
int cull_type;
msurface_t *psurf;
@ -1471,11 +1481,15 @@ void R_DrawBrushModel( cl_entity_t *e )
return;
memset( gl_lms.lightmap_surfaces, 0, sizeof( gl_lms.lightmap_surfaces ));
old_rendermode = e->curstate.rendermode;
gl_lms.dynamic_surfaces = NULL;
if( rotated ) R_RotateForEntity( e );
else R_TranslateForEntity( e );
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ) && FBitSet( clmodel->flags, MODEL_TRANSPARENT ))
e->curstate.rendermode = kRenderTransAlpha;
e->visframe = tr.realframecount; // visible
if( rotated ) Matrix4x4_VectorITransform( RI.objectMatrix, RI.cullorigin, tr.modelorg );
@ -1554,6 +1568,7 @@ void R_DrawBrushModel( cl_entity_t *e )
if( e->curstate.rendermode == kRenderTransAdd )
R_AllowFog( true );
e->curstate.rendermode = old_rendermode;
pglDisable( GL_ALPHA_TEST );
pglAlphaFunc( GL_GREATER, 0.0f );
pglDisable( GL_BLEND );
@ -1863,7 +1878,7 @@ void R_DrawWorld( void )
VectorCopy( RI.cullorigin, tr.modelorg );
memset( gl_lms.lightmap_surfaces, 0, sizeof( gl_lms.lightmap_surfaces ));
memset( fullbright_polys, 0, sizeof( fullbright_polys ));
memset( fullbright_surfaces, 0, sizeof( fullbright_surfaces ));
memset( detail_surfaces, 0, sizeof( detail_surfaces ));
gl_lms.dynamic_surfaces = NULL;

View File

@ -312,9 +312,9 @@ void Mod_LoadMapSprite( model_t *mod, const void *buffer, size_t size, qboolean
if( loaded ) *loaded = false;
Q_snprintf( texname, sizeof( texname ), "#%s", mod->name );
host.overview_loading = true;
Image_SetForceFlags( IL_OVERVIEW );
pix = FS_LoadImage( texname, buffer, size );
host.overview_loading = false;
Image_ClearForceFlags();
if( !pix ) return; // bad image or something else
mod->type = mod_sprite;
@ -428,31 +428,33 @@ void Mod_UnloadSpriteModel( model_t *mod )
Assert( mod != NULL );
if( mod->type != mod_sprite )
return; // not a sprite
psprite = mod->cache.data;
if( !psprite ) return; // already freed
// release all textures
for( i = 0; i < psprite->numframes; i++ )
if( mod->type == mod_sprite )
{
if( host.type == HOST_DEDICATED )
break; // nothing to release
if( psprite->frames[i].type == SPR_SINGLE )
if( host.type != HOST_DEDICATED )
{
pspriteframe = psprite->frames[i].frameptr;
GL_FreeTexture( pspriteframe->gl_texturenum );
}
else
{
pspritegroup = (mspritegroup_t *)psprite->frames[i].frameptr;
psprite = mod->cache.data;
for( j = 0; j < pspritegroup->numframes; j++ )
if( psprite )
{
pspriteframe = pspritegroup->frames[i];
GL_FreeTexture( pspriteframe->gl_texturenum );
// release all textures
for( i = 0; i < psprite->numframes; i++ )
{
if( psprite->frames[i].type == SPR_SINGLE )
{
pspriteframe = psprite->frames[i].frameptr;
GL_FreeTexture( pspriteframe->gl_texturenum );
}
else
{
pspritegroup = (mspritegroup_t *)psprite->frames[i].frameptr;
for( j = 0; j < pspritegroup->numframes; j++ )
{
pspriteframe = pspritegroup->frames[i];
GL_FreeTexture( pspriteframe->gl_texturenum );
}
}
}
}
}
}

View File

@ -161,8 +161,12 @@ int R_GetEntityRenderMode( cl_entity_t *ent )
int i;
if(( phdr = Mod_StudioExtradata( ent->model )) == NULL )
{
// forcing to choose right sorting type
if(( ent->model && ent->model->type == mod_brush ) && FBitSet( ent->model->flags, MODEL_TRANSPARENT ))
return kRenderTransAlpha;
return ent->curstate.rendermode;
}
ptexture = (mstudiotexture_t *)((byte *)phdr + phdr->textureindex);
for( i = 0; i < phdr->numtextures; i++, ptexture++ )
@ -3026,7 +3030,9 @@ void GL_StudioSetRenderMode( int rendermode )
===============
GL_StudioDrawShadow
NOTE: this code sucessfully working with ShadowHack only in Release build
g-cont: don't modify this code it's 100% matched with
original GoldSrc code and used in some mods to enable
studio shadows with some asm tricks
===============
*/
static void GL_StudioDrawShadow( void )
@ -3655,7 +3661,7 @@ void R_DrawViewModel( void )
if( !RI.currententity->model )
return;
// hack the depth range to prevent view model from poking into walls
// adjust the depth range to prevent view model from poking into walls
pglDepthRange( gldepthmin, gldepthmin + 0.3f * ( gldepthmax - gldepthmin ));
RI.currentmodel = RI.currententity->model;
@ -3719,8 +3725,7 @@ static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture
tx = Mem_Alloc( mod->mempool, sizeof( *tx ) + size );
mod->textures[i] = tx;
// parse ranges and store it
// HACKHACK: store ranges into anim_min, anim_max etc
// store ranges into anim_min, anim_max etc
if( !Q_strnicmp( ptexture->name, "DM_Base", 7 ))
{
Q_strncpy( tx->name, "DM_Base", sizeof( tx->name ));
@ -3731,14 +3736,14 @@ static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture
}
else
{
Q_strncpy( tx->name, "DM_User", sizeof( tx->name )); // custom remapped
Q_strncpy( tx->name, "DM_User", sizeof( tx->name )); // custom remapped
Q_strncpy( val, ptexture->name + 7, 4 );
tx->anim_min = bound( 0, Q_atoi( val ), 255 ); // topcolor start
tx->anim_min = bound( 0, Q_atoi( val ), 255 ); // topcolor start
Q_strncpy( val, ptexture->name + 11, 4 );
tx->anim_max = bound( 0, Q_atoi( val ), 255 ); // topcolor end
tx->anim_max = bound( 0, Q_atoi( val ), 255 ); // topcolor end
// bottomcolor start always equal is (topcolor end + 1)
Q_strncpy( val, ptexture->name + 15, 4 );
tx->anim_total = bound( 0, Q_atoi( val ), 255 ); // bottomcolor end
tx->anim_total = bound( 0, Q_atoi( val ), 255 ); // bottomcolor end
}
tx->width = ptexture->width;

View File

@ -1246,8 +1246,7 @@ void VID_CheckChanges( void )
{
if( !VID_SetMode( ))
{
Con_Printf( S_ERROR "can't initialize video subsystem\n" );
Host_NewInstance( va("#%s", GI->gamefolder ), "stopped" );
Sys_Error( "Can't re-initialize video subsystem\n" );
}
else
{
@ -1664,8 +1663,7 @@ qboolean R_Init( void )
GL_RemoveCommands();
R_Free_OpenGL();
Con_Printf( S_ERROR "can't initialize video subsystem\n" );
Host_NewInstance( va( "#%s", GI->gamefolder ), "stopped" );
Sys_Error( "Can't initialize video subsystem\nProbably driver was not installed" );
return false;
}

View File

@ -16,7 +16,6 @@ GNU General Public License for more details.
#include "common.h"
#include "client.h"
#include "gl_local.h"
#include "com_model.h"
#include "wadfile.h"
#define SKYCLOUDS_QUALITY 12
@ -314,7 +313,7 @@ void R_AddSkyBoxSurface( msurface_t *fa )
if( clgame.movevars.skyangle )
{
// HACK: force full sky to draw when it has angle
// force full sky to draw when it has angle
for( i = 0; i < 6; i++ )
{
RI.skyMins[0][i] = RI.skyMins[1][i] = -1.0f;

View File

@ -777,7 +777,7 @@ void DSP_Process( int idsp, portable_samplepair_t *pbfront, int sampleCount )
if( dsp_off->value )
return;
// HACKHACK: don't process while in menu
// don't process DSP while in menu
if( cls.key_dest == key_menu || !sampleCount )
return;

View File

@ -695,7 +695,6 @@ float SND_GetGain( channel_t *ch, qboolean fplayersound, qboolean flooping, floa
{
// player weapon sounds get extra gain - this compensates
// for npc distance effect weapons which mix louder as L+R into L, R
// Hack.
if( ch->entchannel == CHAN_WEAPON )
gain = gain * dB_To_Gain( SND_GAIN_PLAYER_WEAPON_DB );
}

View File

@ -303,7 +303,7 @@ qboolean AVI_GetAudioInfo( movie_state_t *Avi, wavdata_t *snd_info )
else snd_info->width = 2; // assume compressed audio is always 16 bit
snd_info->size = snd_info->rate * snd_info->width * snd_info->channels;
snd_info->loopStart = 0; // HACKHACK: use loopStart as streampos
snd_info->loopStart = 0; // using loopStart as streampos
return true;
}
@ -316,7 +316,7 @@ qboolean AVI_SeekPosition( movie_state_t *Avi, dword offset )
if( offset < Avi->cpa_blockoffset ) // well, shit. we can't seek backwards... restart
{
if( Avi->cpa_blockoffset - offset < 500000 )
return false; // don't bother if it's gonna catch up soon (cheap hack! works!)
return false; // don't bother if it's gonna catch up soon
Avi->cpa_blocknum = 0; // start at 0, eh.
Avi->cpa_blockpos = 0;

View File

@ -44,6 +44,11 @@ GNU General Public License for more details.
// path to folders where placed all sounds
#define DEFAULT_SOUNDPATH "sound/"
// playlist for startup videos
#define DEFAULT_VIDEOLIST_PATH "media/StartupVids.txt"
#define CVAR_GLCONFIG_DESCRIPTION "enable or disable %s"
#define DEFAULT_BSP_BUILD_ERROR "%s can't be loaded in this build. Please rebuild engine with enabled SUPPORT_BSP2_FORMAT\n"
#endif//COM_STRINGS_H

View File

@ -163,7 +163,7 @@ long COM_RandomLong( long lLow, long lHigh )
typedef struct
{
unsigned int id;
unsigned short size;
unsigned int size;
} lzss_header_t;
// expected to be sixteen bytes

View File

@ -32,9 +32,13 @@ HACKHACK - unexpected behavior on some input params (or something like)
BUGBUG - code doesn't working properly in most cases!
TESTTEST - this code may be unstable and needs to be more tested
g-cont: - notes from engine author
XASH SPECIFIC - sort of hack that works only in Xash3D not in GoldSrc
===================================================================================================================================
*/
// configuration
#define HACKS_RELATED_HLMODS // some HL-mods works differently under Xash and can't be fixed without some hacks at least at current time
// disable some warnings
#pragma warning(disable : 4244) // MIPS
#pragma warning(disable : 4018) // signed/unsigned mismatch
@ -369,8 +373,6 @@ typedef struct host_parm_s
qboolean change_game; // initialize when game is changed
qboolean mouse_visible; // vgui override cursor control
qboolean shutdown_issued; // engine is shutting down
qboolean decal_loading; // nasty hack to tell imagelib about decal
qboolean overview_loading; // another nasty hack to tell imagelib about ovierview
qboolean force_draw_version; // used when fraps is loaded
qboolean write_to_clipboard; // put image to clipboard instead of disk
qboolean apply_game_config; // when true apply only to game cvars and ignore all other commands
@ -497,6 +499,8 @@ typedef enum
IL_ALLOW_OVERWRITE = BIT(2), // allow to overwrite stored images
IL_DONTFLIP_TGA = BIT(3), // Steam background completely ignore tga attribute 0x20 (stupid lammers!)
IL_DDS_HARDWARE = BIT(4), // DXT compression is support
IL_LOAD_DECAL = BIT(5), // special mode for load gradient decals
IL_OVERVIEW = BIT(6), // overview required some unque operations
} ilFlags_t;
// goes into rgbdata_t->encode
@ -600,6 +604,7 @@ void Image_PaletteHueReplace( byte *palSrc, int newHue, int start, int end, int
void Image_PaletteTranslate( byte *palSrc, int top, int bottom, int pal_size );
void Image_SetForceFlags( uint flags ); // set image force flags on loading
size_t Image_DXTGetLinearSize( int type, int width, int height, int depth );
void Image_ClearForceFlags( void );
/*
========================================================================

View File

@ -44,6 +44,8 @@ qboolean Cmd_GetMapList( const char *s, char *completedname, int length )
search_t *t;
file_t *f;
string message;
string compiler;
string generator;
string matchbuf;
byte buf[MAX_SYSPATH]; // 1 kb
int i, nummaps;
@ -67,6 +69,8 @@ qboolean Cmd_GetMapList( const char *s, char *completedname, int length )
if( Q_stricmp( ext, "bsp" )) continue;
Q_strncpy( message, "^1error^7", sizeof( message ));
Q_strncpy( compiler, "", sizeof( compiler ));
Q_strncpy( generator, "", sizeof( generator ));
f = FS_Open( t->filenames[i], "rb", con_gamemaps->value );
if( f )
@ -120,6 +124,16 @@ qboolean Cmd_GetMapList( const char *s, char *completedname, int length )
// get the message contents
pfile = COM_ParseFile( pfile, message );
}
else if( !Q_strcmp( token, "generator" ) || !Q_strcmp( token, "_compiler" ))
{
// get the message contents
pfile = COM_ParseFile( pfile, compiler );
}
else if( !Q_strcmp( token, "generator" ) || !Q_strcmp( token, "_generator" ))
{
// get the message contents
pfile = COM_ParseFile( pfile, generator );
}
}
Mem_Free( ents );
}
@ -148,7 +162,7 @@ qboolean Cmd_GetMapList( const char *s, char *completedname, int length )
default: Q_strncpy( buf, "??", sizeof( buf )); break;
}
Con_Printf( "%16s (%s) ^3%s^7\n", matchbuf, buf, message );
Con_Printf( "%16s (%s) ^3%s^7 ^2%s %s^7\n", matchbuf, buf, message, compiler, generator );
nummaps++;
}

View File

@ -716,26 +716,28 @@ int FS_CheckNastyPath( const char *path, qboolean isgamedir )
// all: never allow an empty path, as for gamedir it would access the parent directory and a non-gamedir path it is just useless
if( !COM_CheckString( path )) return 2;
if( fs_ext_path ) return 0; // allow any path
// Mac: don't allow Mac-only filenames - : is a directory separator
// instead of /, but we rely on / working already, so there's no reason to
// support a Mac-only path
// Amiga and Windows: : tries to go to root of drive
if( Q_strstr( path, ":" ) && !fs_ext_path ) return 1; // non-portable attempt to go to root of drive
if( Q_strstr( path, ":" )) return 1; // non-portable attempt to go to root of drive
// Amiga: // is parent directory
if( Q_strstr( path, "//" ) && !fs_ext_path ) return 1; // non-portable attempt to go to parent directory
if( Q_strstr( path, "//" )) return 1; // non-portable attempt to go to parent directory
// all: don't allow going to parent directory (../ or /../)
if( Q_strstr( path, ".." ) && !fs_ext_path ) return 2; // attempt to go outside the game directory
if( Q_strstr( path, ".." )) return 2; // attempt to go outside the game directory
// Windows and UNIXes: don't allow absolute paths
if( path[0] == '/' && !fs_ext_path ) return 2; // attempt to go outside the game directory
if( path[0] == '/' ) return 2; // attempt to go outside the game directory
// all: forbid trailing slash on gamedir
if( isgamedir && !fs_ext_path && path[Q_strlen( path )-1] == '/' ) return 2;
if( isgamedir && path[Q_strlen( path )-1] == '/' ) return 2;
// all: forbid leading dot on any filename for any reason
if( Q_strstr( path, "/." ) && !fs_ext_path ) return 2; // attempt to go outside the game directory
if( Q_strstr( path, "/." )) return 2; // attempt to go outside the game directory
// after all these checks we're pretty sure it's a / separated filename
// and won't do much if any harm
@ -2315,12 +2317,12 @@ dll_user_t *FS_FindLibrary( const char *dllname, qboolean directpath )
int start = 0;
// check for bad exports
if( !dllname || !*dllname )
if( !COM_CheckString( dllname ))
return NULL;
fs_ext_path = directpath;
// HACKHACK: remove absoulte path to valve folder
// HACKHACK remove absoulte path to valve folder
if( !Q_strnicmp( dllname, "..\\valve\\", 9 ) || !Q_strnicmp( dllname, "../valve/", 9 ))
start += 9;

View File

@ -852,8 +852,6 @@ void Host_FreeCommon( void )
Netchan_Shutdown();
HPAK_FlushHostQueue();
FS_Shutdown();
Mem_FreePool( &host.mempool );
}
/*
@ -943,8 +941,8 @@ int EXPORT Host_Main( const char *progname, int bChangeGame, pfnChangeGame func
oldtime = Sys_DoubleTime() - 0.1;
if( host.type == HOST_DEDICATED && !SV_Active( ))
MsgDev( D_INFO, "type 'map <mapname>' to run server... (TAB-autocomplete is working too)\n" );
if( host.type == HOST_DEDICATED && GameState->nextstate == STATE_RUNFRAME )
Con_Printf( "type 'map <mapname>' to run server... (TAB-autocomplete is working too)\n" );
// main window message loop
while( !host.crashed )
@ -981,6 +979,7 @@ void EXPORT Host_Shutdown( void )
NET_Shutdown();
Host_FreeCommon();
Con_DestroyConsole();
Mem_FreePool( &host.mempool );
// restore filter
if( host.oldFilter ) SetUnhandledExceptionFilter( host.oldFilter );

View File

@ -87,7 +87,7 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, size_t filesize )
if( !Image_ValidSize( name ))
return false;
// special hack for loading qfont
// special case for loading qfont (menu font)
if( !Q_strncmp( name, "#XASH_SYSTEMFONT_001", 20 ))
{
// NOTE: same as system font we can use 4-bit bmps only
@ -120,7 +120,7 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, size_t filesize )
image.flags |= IMAGE_HAS_ALPHA;
}
if( host.overview_loading && bhdr.bitsPerPixel == 8 )
if( Image_CheckFlag( IL_OVERVIEW ) && bhdr.bitsPerPixel == 8 )
{
// convert green background into alpha-layer, make opacity for all other entries
for( i = 0; i < bhdr.colors; i++ )

View File

@ -247,8 +247,9 @@ rgbdata_t *FS_LoadImage( const char *filename, const byte *buffer, size_t size )
}
}
// HACKHACK: skip any checks, load file from buffer
if( filename[0] == '#' && buffer && size ) goto load_internal;
// special mode: skip any checks, load file from buffer
if( filename[0] == '#' && buffer && size )
goto load_internal;
// now try all the formats in the selected list
for( format = image.loadformats; format && format->formatstring; format++)

View File

@ -118,9 +118,6 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, size_t filesize )
}
}
// HACKHACK: detect luma textures by name
if( Q_stristr( name, "_luma" )) image.flags |= IMAGE_HAS_LUMA;
columns = targa_header.width;
rows = targa_header.height;

View File

@ -207,10 +207,10 @@ Image_CheckFlag
*/
qboolean Image_CheckFlag( int bit )
{
if( image.force_flags & bit )
if( FBitSet( image.force_flags, bit ))
return true;
if( image.cmd_flags & bit )
if( FBitSet( image.cmd_flags, bit ))
return true;
return false;
@ -223,7 +223,17 @@ Image_SetForceFlags
*/
void Image_SetForceFlags( uint flags )
{
image.force_flags = flags;
SetBits( image.force_flags, flags );
}
/*
=================
Image_ClearForceFlags
=================
*/
void Image_ClearForceFlags( void )
{
image.force_flags = 0;
}
/*
@ -233,7 +243,7 @@ Image_AddCmdFlags
*/
void Image_AddCmdFlags( uint flags )
{
image.cmd_flags |= flags;
SetBits( image.cmd_flags, flags );
}
qboolean Image_ValidSize( const char *name )
@ -1160,11 +1170,8 @@ byte *Image_CreateLumaInternal( byte *fin, int width, int height, int type, int
byte *out;
int i;
if(!( flags & IMAGE_HAS_LUMA ))
{
MsgDev( D_WARN, "Image_MakeLuma: image doesn't has luma pixels\n" );
if( !FBitSet( flags, IMAGE_HAS_LUMA ))
return (byte *)fin;
}
switch( type )
{
@ -1174,29 +1181,9 @@ byte *Image_CreateLumaInternal( byte *fin, int width, int height, int type, int
for( i = 0; i < width * height; i++ )
*out++ = fin[i] >= 224 ? fin[i] : 0;
break;
case PF_RGB_24:
case PF_BGR_24:
// clearing any gray pixels
for( i = 0; i < width * height; i++ )
{
if( fin[i*3+0] < 32 ) fin[i*3+0] = 0;
if( fin[i*3+1] < 32 ) fin[i*3+1] = 0;
if( fin[i*3+2] < 32 ) fin[i*3+2] = 0;
}
return (byte *)fin;
case PF_RGBA_32:
case PF_BGRA_32:
// clearing any gray pixels
for( i = 0; i < width * height; i++ )
{
if( fin[i*4+0] < 32 ) fin[i*4+0] = 0;
if( fin[i*4+1] < 32 ) fin[i*4+1] = 0;
if( fin[i*4+2] < 32 ) fin[i*4+2] = 0;
}
return (byte *)fin;
default:
// another formats does ugly result :(
MsgDev( D_WARN, "Image_MakeLuma: unsupported format %s\n", PFDesc[type].name );
Con_Printf( S_ERROR "Image_MakeLuma: unsupported format %s\n", PFDesc[type].name );
return (byte *)fin;
}
@ -1210,7 +1197,7 @@ qboolean Image_AddIndexedImageToPack( const byte *in, int width, int height )
if( Image_CheckFlag( IL_KEEP_8BIT ))
expand_to_rgba = false;
else if( host.type == HOST_NORMAL && ( image.flags & ( IMAGE_HAS_LUMA|IMAGE_QUAKESKY )))
else if( FBitSet( image.flags, IMAGE_HAS_LUMA|IMAGE_QUAKESKY ))
expand_to_rgba = false;
image.size = mipsize;
@ -1519,11 +1506,11 @@ qboolean Image_Process( rgbdata_t **pix, int width, int height, uint flags, imgf
return false; // no operation specfied
}
if( flags & IMAGE_MAKE_LUMA )
if( FBitSet( flags, IMAGE_MAKE_LUMA ))
{
out = Image_CreateLumaInternal( pic->buffer, pic->width, pic->height, pic->type, pic->flags );
if( pic->buffer != out ) memcpy( pic->buffer, image.tempbuffer, pic->size );
pic->flags &= ~IMAGE_HAS_LUMA;
ClearBits( pic->flags, IMAGE_HAS_LUMA );
}
if( flags & IMAGE_REMAP )

View File

@ -382,7 +382,7 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, size_t filesize )
if( Q_strrchr( name, '{' ))
{
// NOTE: decals with 'blue base' can be interpret as colored decals
if(( !host.decal_loading ) || ( pal[765] == 0 && pal[766] == 0 && pal[767] == 255 ))
if( !Image_CheckFlag( IL_LOAD_DECAL ) || ( pal[765] == 0 && pal[766] == 0 && pal[767] == 255 ))
{
rendermode = LUMP_MASKED;
image.flags |= IMAGE_ONEBIT_ALPHA;

View File

@ -147,7 +147,7 @@ static void FinalizeSections( MEMORYMODULE *module )
{
// change memory access flags
if( !VirtualProtect((LPVOID)section->Misc.PhysicalAddress, size, protect, &oldProtect ))
Sys_Error( "FinalizeSections: error protecting memory page\n" );
Sys_Error( "error protecting memory page\n" );
}
}
}
@ -268,7 +268,7 @@ static int BuildImportTable( MEMORYMODULE *module )
void *handle;
libname = (LPCSTR)CALCULATE_ADDRESS( codeBase, importDesc->Name );
handle = COM_LoadLibraryExt( libname, false, true );
handle = COM_LoadLibrary( libname, false, true );
if( handle == NULL )
{
@ -753,7 +753,7 @@ table_error:
if( f ) FS_Close( f );
if( p_Names ) Mem_Free( p_Names );
FreeNameFuncGlobals( hInst );
MsgDev( D_ERROR, "LoadLibrary: %s\n", errorstring );
Con_Printf( S_ERROR "LoadLibrary: %s\n", errorstring );
return false;
}
@ -765,7 +765,7 @@ COM_LoadLibrary
smart dll loader - can loading dlls from pack or wad files
================
*/
void *COM_LoadLibraryExt( const char *dllname, int build_ordinals_table, qboolean directpath )
void *COM_LoadLibrary( const char *dllname, int build_ordinals_table, qboolean directpath )
{
dll_user_t *hInst;
@ -776,7 +776,7 @@ void *COM_LoadLibraryExt( const char *dllname, int build_ordinals_table, qboolea
{
if( hInst->encrypted )
{
MsgDev( D_ERROR, "Sys_LoadLibrary: couldn't load encrypted library %s\n", dllname );
Con_Printf( S_ERROR "LoadLibrary: couldn't load encrypted library %s\n", dllname );
return NULL;
}
@ -786,7 +786,7 @@ void *COM_LoadLibraryExt( const char *dllname, int build_ordinals_table, qboolea
if( !hInst->hInstance )
{
MsgDev( D_NOTE, "Sys_LoadLibrary: Loading %s - failed\n", dllname );
Con_DPrintf( "LoadLibrary: Loading %s - failed\n", dllname );
COM_FreeLibrary( hInst );
return NULL;
}
@ -796,22 +796,17 @@ void *COM_LoadLibraryExt( const char *dllname, int build_ordinals_table, qboolea
{
if( !LibraryLoadSymbols( hInst ))
{
MsgDev( D_NOTE, "Sys_LoadLibrary: Loading %s - failed\n", dllname );
Con_DPrintf( "LoadLibrary: Loading %s - failed\n", dllname );
COM_FreeLibrary( hInst );
return NULL;
}
}
MsgDev( D_NOTE, "Sys_LoadLibrary: Loading %s - ok\n", dllname );
Con_DPrintf( "LoadLibrary: Loading %s - ok\n", dllname );
return hInst;
}
void *COM_LoadLibrary( const char *dllname, int build_ordinals_table )
{
return COM_LoadLibraryExt( dllname, build_ordinals_table, false );
}
void *COM_GetProcAddress( void *hInstance, const char *name )
{
dll_user_t *hInst = (dll_user_t *)hInstance;

View File

@ -151,8 +151,7 @@ typedef struct dll_user_s
} dll_user_t;
dll_user_t *FS_FindLibrary( const char *dllname, qboolean directpath );
void *COM_LoadLibrary( const char *dllname, int build_ordinals_table );
void *COM_LoadLibraryExt( const char *dllname, int build_ordinals_table, qboolean directpath );
void *COM_LoadLibrary( const char *dllname, int build_ordinals_table, qboolean directpath );
void *COM_GetProcAddress( void *hInstance, const char *name );
const char *COM_NameForFunction( void *hInstance, dword function );
dword COM_FunctionFromName( void *hInstance, const char *pName );

View File

@ -124,7 +124,7 @@ typedef struct
dmiptexlump_t *textures;
size_t texdatasize;
// intermediate arrays (pointers will lost after loading, bet keep the data)
// intermediate arrays (pointers will lost after loading, but keep the data)
color24 *deluxedata_out; // deluxemap data pointer
byte *shadowdata_out; // occlusion data pointer
dclipnode32_t *clipnodes_out; // temporary 32-bit array to hold clipnodes
@ -134,7 +134,7 @@ typedef struct
int lightmap_samples; // samples per lightmap (1 or 3)
int version; // model version
qboolean isworld;
qboolean vis_errors; // don't spam about vis
qboolean vis_errors; // don't spam about vis decompression errors
} dbspmodel_t;
typedef struct
@ -431,9 +431,11 @@ void Mod_PrintWorldStats_f( void )
Con_Printf( "World size ( %g %g %g ) units\n", world.size[0], world.size[1], world.size[2] );
Con_Printf( "Supports transparency world water: %s\n", FBitSet( world.flags, FWORLD_WATERALPHA ) ? "Yes" : "No" );
Con_Printf( "Lighting: %s\n", FBitSet( w->flags, MODEL_COLORED_LIGHTING ) ? "colored" : "monochrome" );
Con_Printf( "World total leafs: %d\n", worldmodel->numleafs + 1 );
Con_Printf( "original name: ^1%s\n", worldmodel->name );
Con_Printf( "internal name: %s\n", (world.message[0]) ? va( "^2%s", world.message ) : "none" );
Con_Printf( "map compiler: %s\n", (world.compiler[0]) ? va( "^3%s", world.compiler ) : "unknown" );
Con_Printf( "map editor: %s\n", (world.generator[0]) ? va( "^2%s", world.generator ) : "unknown" );
}
/*
@ -1379,13 +1381,14 @@ static void Mod_SetupSubmodels( dbspmodel_t *bmod )
{
Mod_FindModelOrigin( ents, va( "*%i", i ), bm->origin );
// HACKHACK: c2a1 issues
if( !Q_stricmp( loadmodel->name, "maps/c2a1.bsp" ) && ( i == 11 ))
SetBits( mod->flags, MODEL_HAS_ORIGIN );
// flag 2 is indicated model with origin brush!
// mark models that have origin brushes
if( !VectorIsNull( bm->origin ))
SetBits( mod->flags, MODEL_HAS_ORIGIN );
#ifdef HACKS_RELATED_HLMODS
// c2a1 doesn't have origin brush it's just placed at center of the level
if( !Q_stricmp( loadmodel->name, "maps/c2a1.bsp" ) && ( i == 11 ))
SetBits( mod->flags, MODEL_HAS_ORIGIN );
#endif
}
// sets the model flags
@ -1528,6 +1531,7 @@ static void Mod_LoadEntities( dbspmodel_t *bmod )
if( !bmod->isworld ) return;
pfile = (char *)loadmodel->entities;
world.generator[0] = '\0';
world.compiler[0] = '\0';
world.message[0] = '\0';
bmod->wadlist.count = 0;
@ -1585,6 +1589,8 @@ static void Mod_LoadEntities( dbspmodel_t *bmod )
Q_strncpy( world.message, token, sizeof( world.message ));
else if( !Q_stricmp( keyname, "compiler" ) || !Q_stricmp( keyname, "_compiler" ))
Q_strncpy( world.compiler, token, sizeof( world.compiler ));
else if( !Q_stricmp( keyname, "generator" ) || !Q_stricmp( keyname, "_generator" ))
Q_strncpy( world.generator, token, sizeof( world.generator ));
}
return; // all done
}
@ -2606,7 +2612,7 @@ qboolean Mod_LoadBmodelLumps( const byte *mod_base, qboolean isworld )
#ifndef SUPPORT_BSP2_FORMAT
if( header->version == QBSP2_VERSION )
{
MsgDev( D_ERROR, "%s can't be loaded in this build. Please rebuild engine with enabled SUPPORT_BSP2_FORMAT\n", loadmodel->name );
Con_Printf( S_ERROR DEFAULT_BSP_BUILD_ERROR, loadmodel->name );
return false;
}
#endif
@ -2698,7 +2704,7 @@ qboolean Mod_TestBmodelLumps( const char *name, const byte *mod_base, qboolean s
if( header->version == QBSP2_VERSION )
{
if( !FBitSet( flags, LUMP_SILENT ))
MsgDev( D_ERROR, "%s can't be loaded in this build. Please rebuild engine with enabled SUPPORT_BSP2_FORMAT\n", name );
Con_Printf( S_ERROR DEFAULT_BSP_BUILD_ERROR, name );
return false;
}
#endif

View File

@ -19,7 +19,6 @@ GNU General Public License for more details.
#include "common.h"
#include "edict.h"
#include "eiface.h"
#include "com_model.h"
// 1/32 epsilon to keep floating point happy
#define DIST_EPSILON (1.0f / 32.0f)
@ -110,6 +109,7 @@ typedef struct
// mapstats info
char message[2048]; // just for debug
char compiler[256]; // map compiler
char generator[256]; // map editor
// translucent sorted array
sortedface_t *draw_surfaces; // used for sorting translucent surfaces

View File

@ -261,12 +261,7 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
byte *buf;
model_info_t *p;
if( !mod )
{
if( crash ) Host_Error( "Mod_ForName: NULL model\n" );
else MsgDev( D_ERROR, "Mod_ForName: NULL model\n" );
return NULL;
}
ASSERT( mod != NULL );
// check if already loaded (or inline bmodel)
if( mod->mempool || mod->name[0] == '*' )
@ -287,8 +282,8 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
{
memset( mod, 0, sizeof( model_t ));
if( crash ) Host_Error( "Mod_ForName: %s couldn't load\n", tempname );
else MsgDev( D_ERROR, "Mod_ForName: %s couldn't load\n", tempname );
if( crash ) Host_Error( "%s couldn't load\n", tempname );
else Con_Printf( S_ERROR "%s couldn't load\n", tempname );
return NULL;
}
@ -317,8 +312,8 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
break;
default:
Mem_Free( buf );
if( crash ) Host_Error( "Mod_ForName: %s unknown format\n", tempname );
else MsgDev( D_ERROR, "Mod_ForName: %s unknown format\n", tempname );
if( crash ) Host_Error( "%s has unknown format\n", tempname );
else Con_Printf( S_ERROR "%s has unknown format\n", tempname );
return NULL;
}
@ -327,8 +322,8 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
Mod_FreeModel( mod );
Mem_Free( buf );
if( crash ) Host_Error( "Mod_ForName: %s couldn't load\n", tempname );
else MsgDev( D_ERROR, "Mod_ForName: %s couldn't load\n", tempname );
if( crash ) Host_Error( "%s couldn't load\n", tempname );
else Con_Printf( S_ERROR "%s couldn't load\n", tempname );
return NULL;
}

View File

@ -367,7 +367,7 @@ void Netchan_OutOfBand( int net_socket, netadr_t adr, int length, byte *data )
// write the packet header
MSG_Init( &send, "SequencePacket", send_buf, sizeof( send_buf ));
MSG_WriteLong( &send, -1 ); // -1 sequence means out of band
MSG_WriteLong( &send, NET_HEADER_OUTOFBANDPACKET ); // -1 sequence means out of band
MSG_WriteBytes( &send, data, length );
if( !CL_IsPlaybackDemo( ))
@ -580,6 +580,21 @@ static void Netchan_CreateFragments_( netchan_t *chan, sizebuf_t *msg )
wait = (fragbufwaiting_t *)Mem_Alloc( net_mempool, sizeof( fragbufwaiting_t ));
if( !LZSS_IsCompressed( MSG_GetData( msg )))
{
uint uCompressedSize = 0;
uint uSourceSize = MSG_GetNumBytesWritten( msg );
byte *pbOut = LZSS_Compress( msg->pData, uSourceSize, &uCompressedSize );
if( pbOut && uCompressedSize > 0 && uCompressedSize < uSourceSize )
{
Con_DPrintf( "Compressing split packet (%d -> %d bytes)\n", uSourceSize, uCompressedSize );
memcpy( msg->pData, pbOut, uCompressedSize );
MSG_SeekToBit( msg, uCompressedSize << 3, SEEK_SET );
}
if( pbOut ) free( pbOut );
}
remaining = MSG_GetNumBytesWritten( msg );
pos = 0; // current position in bytes
@ -727,6 +742,20 @@ void Netchan_CreateFileFragmentsFromBuffer( netchan_t *chan, char *filename, byt
chunksize = chan->pfnBlockSize( chan->client );
else chunksize = FRAGMENT_MAX_SIZE; // fallback
if( !LZSS_IsCompressed( pbuf ))
{
uint uCompressedSize = 0;
byte *pbOut = LZSS_Compress( pbuf, size, &uCompressedSize );
if( pbOut && uCompressedSize > 0 && uCompressedSize < size )
{
Con_DPrintf( "Compressing filebuffer (%s -> %s)\n", Q_memprint( size ), Q_memprint( uCompressedSize ));
memcpy( pbuf, pbOut, uCompressedSize );
size = uCompressedSize;
}
if( pbOut ) free( pbOut );
}
wait = (fragbufwaiting_t *)Mem_Alloc( net_mempool, sizeof( fragbufwaiting_t ));
remaining = size;
pos = 0;
@ -793,7 +822,11 @@ int Netchan_CreateFileFragments( netchan_t *chan, const char *filename )
int remaining;
int bufferid = 1;
int filesize = 0;
char compressedfilename[MAX_OSPATH];
int compressedFileTime;
int fileTime;
qboolean firstfragment = true;
qboolean bCompressed = false;
fragbufwaiting_t *wait, *p;
fragbuf_t *buf;
@ -807,6 +840,37 @@ int Netchan_CreateFileFragments( netchan_t *chan, const char *filename )
chunksize = chan->pfnBlockSize( chan->client );
else chunksize = FRAGMENT_MAX_SIZE; // fallback
Q_strncpy( compressedfilename, filename, sizeof( compressedfilename ));
COM_ReplaceExtension( compressedfilename, ".ztmp" );
compressedFileTime = FS_FileTime( compressedfilename, false );
fileTime = FS_FileTime( filename, false );
if( compressedFileTime >= fileTime )
{
// if compressed file already created and newer than source
if( FS_FileSize( compressedfilename, false ) != -1 )
bCompressed = true;
}
else
{
uint uCompressedSize;
byte *uncompressed;
byte *compressed;
uncompressed = FS_LoadFile( filename, &filesize, false );
compressed = LZSS_Compress( uncompressed, filesize, &uCompressedSize );
if( compressed )
{
Con_DPrintf( "compressed file %s (%s -> %s)\n", filename, Q_memprint( filesize ), Q_memprint( uCompressedSize ));
FS_WriteFile( compressedfilename, compressed, uCompressedSize );
filesize = uCompressedSize;
bCompressed = true;
free( compressed );
}
Mem_Free( uncompressed );
}
wait = (fragbufwaiting_t *)Mem_Alloc( net_mempool, sizeof( fragbufwaiting_t ));
remaining = filesize;
pos = 0;
@ -835,6 +899,7 @@ int Netchan_CreateFileFragments( netchan_t *chan, const char *filename )
buf->isfile = true;
buf->size = send;
buf->foffset = pos;
buf->iscompressed = bCompressed;
Q_strncpy( buf->filename, filename, sizeof( buf->filename ));
pos += send;
@ -918,6 +983,24 @@ qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *l
Mem_Free( p );
p = n;
}
if( LZSS_IsCompressed( MSG_GetData( msg )))
{
uint uDecompressedLen = LZSS_GetActualSize( MSG_GetData( msg ));
byte buf[NET_MAX_MESSAGE];
if( uDecompressedLen <= sizeof( buf ))
{
size = LZSS_Decompress( MSG_GetData( msg ), buf );
memcpy( msg->pData, buf, size );
}
else
{
// g-cont. this should not happens
Con_Printf( S_ERROR "buffer to small to decompress message\n" );
return false;
}
}
chan->incomingbufs[FRAG_NORMAL_STREAM] = NULL;
@ -1024,6 +1107,16 @@ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg )
p = n;
}
if( LZSS_IsCompressed( buffer ))
{
uint uncompressedSize = LZSS_GetActualSize( buffer ) + 1;
byte *uncompressedBuffer = Mem_Alloc( net_mempool, uncompressedSize );
nsize = LZSS_Decompress( buffer, uncompressedBuffer );
Mem_Free( buffer );
buffer = uncompressedBuffer;
}
// customization files goes int tempbuffer
if( filename[0] == '!' )
{
@ -1035,7 +1128,7 @@ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg )
else
{
// g-cont. it's will be stored downloaded files directly into game folder
FS_WriteFile( filename, buffer, pos );
FS_WriteFile( filename, buffer, nsize );
Mem_Free( buffer );
}
@ -1309,7 +1402,16 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
byte filebuffer[NET_MAX_FRAGMENT];
file_t *file;
file = FS_Open( pbuf->filename, "rb", false );
if( pbuf->iscompressed )
{
char compressedfilename[MAX_OSPATH];
Q_strncpy( compressedfilename, pbuf->filename, sizeof( compressedfilename ));
COM_ReplaceExtension( compressedfilename, ".ztmp" );
file = FS_Open( compressedfilename, "rb", false );
}
else file = FS_Open( pbuf->filename, "rb", false );
FS_Seek( file, pbuf->foffset, SEEK_SET );
FS_Read( file, filebuffer, pbuf->size );

View File

@ -18,7 +18,7 @@ GNU General Public License for more details.
#include "netchan.h"
#include "mathlib.h"
//#define NET_USE_FRAGMENTS // disabled until revision of netchan will be done
//#define NET_USE_FRAGMENTS
#define PORT_ANY -1
#define MAX_LOOPBACK 4
@ -26,13 +26,7 @@ GNU General Public License for more details.
#define MAX_ROUTEABLE_PACKET 1400
#define SPLIT_SIZE ( MAX_ROUTEABLE_PACKET - sizeof( SPLITPACKET ))
#define NET_MAX_FRAGMENTS 32
#ifdef NET_USE_FRAGMENTS
#define MAX_UDP_PACKET 4010 // 9 bytes SPLITHEADER + 4000 payload?
#else
#define MAX_UDP_PACKET NET_MAX_MESSAGE
#endif
#define NET_MAX_FRAGMENTS ( NET_MAX_FRAGMENT / SPLIT_SIZE )
// wsock32.dll exports
static int (_stdcall *pWSACleanup)( void );
@ -115,7 +109,7 @@ typedef struct
int current_sequence;
int split_count;
int total_size;
char buffer[MAX_UDP_PACKET];
char buffer[NET_MAX_FRAGMENT];
} LONGPACKET;
// use this to pick apart the network stream, must be packed
@ -124,7 +118,7 @@ typedef struct
{
int net_id;
int sequence_number;
byte packet_id;
short packet_id;
} SPLITPACKET;
#pragma pack(pop)
@ -776,33 +770,32 @@ receive long packet from network
*/
qboolean NET_GetLong( byte *pData, int size, int *outSize )
{
uint packet_number;
uint packet_count;
int i, sequence_number;
int i, sequence_number, offset;
SPLITPACKET *pHeader = (SPLITPACKET *)pData;
uint packet_payload_size;
byte packet_id;
int packet_number;
int packet_count;
short packet_id;
if( size < sizeof( SPLITPACKET ))
{
MsgDev( D_ERROR, "invalid split packet length %i\n", size );
Con_Printf( S_ERROR "invalid split packet length %i\n", size );
return false;
}
sequence_number = pHeader->sequence_number;
packet_id = pHeader->packet_id;
packet_count = packet_id & 0xF;
packet_number = (uint)packet_id >> 4;
packet_count = ( packet_id & 0xFF );
packet_number = ( packet_id >> 8 );
if( packet_number >= NET_MAX_FRAGMENTS || packet_count > NET_MAX_FRAGMENTS )
{
MsgDev( D_ERROR, "malformed packet number (%i/%i)\n", packet_number + 1, packet_count );
Con_Printf( S_ERROR "malformed packet number (%i/%i)\n", packet_number + 1, packet_count );
return false;
}
if( net.split.current_sequence == -1 || sequence_number != net.split.current_sequence )
{
net.split.current_sequence = pHeader->sequence_number;
net.split.current_sequence = sequence_number;
net.split.split_count = packet_count;
net.split.total_size = 0;
@ -814,70 +807,45 @@ qboolean NET_GetLong( byte *pData, int size, int *outSize )
Con_Printf( "<-- Split packet restart %i count %i seq\n", net.split.split_count, sequence_number );
}
packet_payload_size = size - sizeof( SPLITPACKET );
size -= sizeof( SPLITPACKET );
if( net.split_flags[packet_number] == sequence_number )
if( net.split_flags[packet_number] != sequence_number )
{
MsgDev( D_REPORT, "NET_GetLong: Ignoring duplicated split packet %i of %i ( %i bytes )\n",
packet_number + 1, packet_count, packet_payload_size );
}
else
{
if( packet_number == packet_count - 1 )
net.split.total_size = packet_payload_size + SPLIT_SIZE * ( packet_count - 1 );
if( packet_number == ( packet_count - 1 ))
net.split.total_size = size + SPLIT_SIZE * ( packet_count - 1 );
net.split.split_count--;
net.split_flags[packet_number] = sequence_number;
if( net_showpackets && net_showpackets->value == 4.0f )
Con_Printf( "<-- Split packet %i of %i, %i bytes %i seq\n",
packet_number + 1, packet_count, packet_payload_size, sequence_number );
Con_Printf( "<-- Split packet %i of %i, %i bytes %i seq\n", packet_number + 1, packet_count, size, sequence_number );
}
else
{
Con_DPrintf( "NET_GetLong: Ignoring duplicated split packet %i of %i ( %i bytes )\n", packet_number + 1, packet_count, size );
}
if( SPLIT_SIZE * packet_number + packet_payload_size > MAX_UDP_PACKET )
offset = (packet_number * SPLIT_SIZE);
memcpy( net.split.buffer + offset, pData + sizeof( SPLITPACKET ), size );
// have we received all of the pieces to the packet?
if( net.split.split_count <= 0 )
{
net.split.current_sequence = -1; // Clear packet
if( net.split.total_size > sizeof( net.split.buffer ))
{
MsgDev( D_ERROR, "malformed packet size (%i, %i)\n", SPLIT_SIZE * packet_number, packet_payload_size );
net.split.current_sequence = -1;
Con_Printf( "Split packet too large! %d bytes\n", net.split.total_size );
return false;
}
memcpy( &net.split.buffer[SPLIT_SIZE * packet_number], pHeader + 1, packet_payload_size );
}
if( net.split.split_count > 0 )
return false;
if( packet_count > 0 )
{
for( i = 0; i < packet_count; i++ )
{
if( net.split_flags[i] != net.split.current_sequence )
{
MsgDev( D_ERROR, "split packet without all %i parts, part %i had wrong sequence %i/%i\n",
packet_count, i + 1, net.split_flags[i], net.split.current_sequence );
net.split.current_sequence = -1; // no more parts can be attached, clear it
return false;
}
}
}
net.split.current_sequence = -1;
if( net.split.total_size <= MAX_UDP_PACKET )
{
memcpy( pData, net.split.buffer, net.split.total_size );
*outSize = net.split.total_size;
return true;
}
else
{
MsgDev( D_ERROR, "split packet too large! %d bytes\n", net.split.total_size );
*outSize = 0;
return FALSE;
}
return false;
}
/*
@ -889,11 +857,11 @@ queue normal and lagged packets
*/
qboolean NET_QueuePacket( netsrc_t sock, netadr_t *from, byte *data, size_t *length )
{
struct sockaddr addr;
int addr_len;
int net_socket;
byte buf[MAX_UDP_PACKET];
byte buf[NET_MAX_FRAGMENT];
int ret = SOCKET_ERROR;
int net_socket;
int addr_len;
struct sockaddr addr;
*length = 0;
@ -908,14 +876,14 @@ qboolean NET_QueuePacket( netsrc_t sock, netadr_t *from, byte *data, size_t *len
{
NET_SockadrToNetadr( &addr, from );
if( ret < MAX_UDP_PACKET )
if( ret < NET_MAX_FRAGMENT )
{
// Transfer data
memcpy( data, buf, ret );
*length = ret;
// check for split message
if( *(int *)data == -2 )
if( *(int *)data == NET_HEADER_SPLITPACKET )
{
return NET_GetLong( data, ret, length );
}
@ -997,7 +965,7 @@ int NET_SendLong( netsrc_t sock, int net_socket, const char *buf, int len, int f
pPacket = (SPLITPACKET *)packet;
pPacket->sequence_number = net.sequence_number;
pPacket->net_id = -2;
pPacket->net_id = NET_HEADER_SPLITPACKET;
packet_number = 0;
total_sent = 0;
packet_count = (len + SPLIT_SIZE - 1) / SPLIT_SIZE;
@ -1005,7 +973,7 @@ int NET_SendLong( netsrc_t sock, int net_socket, const char *buf, int len, int f
while( len > 0 )
{
size = Q_min( SPLIT_SIZE, len );
pPacket->packet_id = (packet_number << 4) + packet_count;
pPacket->packet_id = (packet_number << 8) + packet_count;
memcpy( packet + sizeof( SPLITPACKET ), buf + ( packet_number * SPLIT_SIZE ), size );
if( net_showpackets && net_showpackets->value == 3.0f )
@ -1026,18 +994,17 @@ int NET_SendLong( netsrc_t sock, int net_socket, const char *buf, int len, int f
total_sent += size;
len -= size;
packet_number++;
Sleep( 1 );
}
return total_sent;
}
else
#endif
{
// no fragmenantion for client connection
return pSendTo( net_socket, buf, len, flags, to, tolen );
}
#else
return pSendTo( net_socket, buf, len, flags, to, tolen );
#endif
}
/*

View File

@ -31,6 +31,12 @@ typedef enum
#define MAX_INIT_MSG 0x20000 // max length of possible message
// net packets type
#define NET_HEADER_OUTOFBANDPACKET -1
#define NET_HEADER_SPLITPACKET -2
#define NET_HEADER_COMPRESSEDPACKET -3
#include "netadr.h"
extern convar_t *net_showpackets;

View File

@ -123,6 +123,7 @@ typedef struct fragbuf_s
byte frag_message_buf[NET_MAX_FRAGMENT]; // the actual data sits here
qboolean isfile; // is this a file buffer?
qboolean isbuffer; // is this file buffer from memory ( custom decal, etc. ).
qboolean iscompressed; // is compressed file, we should using filename.ztmp
char filename[MAX_OSPATH]; // name of the file to save out on remote host
int foffset; // offset in file from which to read data
int size; // size of data to read at that offset

View File

@ -175,7 +175,7 @@ GNU General Public License for more details.
#define MAX_RESOURCE_BITS 13 // 13 bits 8192 resource (4096 models + 2048 sounds + 1024 events + 1024 files)
#define FRAGMENT_MIN_SIZE 1200 // default MTU
#define FRAGMENT_MAX_SIZE 64000 // minimal acceptable value without testing network bandwith
#define FRAGMENT_MAX_SIZE 64000 // maximal fragment size
#define FRAGMENT_LOCAL_SIZE FRAGMENT_MAX_SIZE // local connection
extern const char *svc_strings[svc_lastmsg+1];

View File

@ -81,8 +81,9 @@ wavdata_t *FS_LoadSound( const char *filename, const byte *buffer, size_t size )
}
}
// HACKHACK: skip any checks, load file from buffer
if( filename[0] == '#' && buffer && size ) goto load_internal;
// special mode: skip any checks, load file from buffer
if( filename[0] == '#' && buffer && size )
goto load_internal;
// now try all the formats in the selected list
for( format = sound.loadformats; format && format->formatstring; format++)

View File

@ -45,6 +45,8 @@ extern int SV_UPDATE_BACKUP;
#define MAP_HAS_LANDMARK BIT( 2 )
#define MAP_INVALID_VERSION BIT( 3 )
#define SV_SPAWN_TIME 0.1
// group flags
#define GROUP_OP_AND 0
#define GROUP_OP_NAND 1
@ -100,10 +102,9 @@ typedef enum
// instanced baselines container
typedef struct
{
int count;
const char *classnames[MAX_CUSTOM_BASELINES];
entity_state_t baselines[MAX_CUSTOM_BASELINES];
} sv_baselines_t;
const char *classname;
entity_state_t baseline;
} sv_baseline_t;
typedef struct
{
@ -116,7 +117,7 @@ typedef struct
// like as entity_state_t in Quake
typedef struct
{
char model[64]; // name of static-entity model for right precache
char model[MAX_QPATH]; // name of static-entity model for right precache
vec3_t origin;
vec3_t angles;
byte sequence;
@ -147,11 +148,11 @@ typedef struct server_s
struct sv_client_s *current_client; // current client who network message sending on
int hostflags; // misc server flags: predicting etc
CRC32_t worldmapCRC;
int progsCRC;
CRC32_t worldmapCRC; // check crc for catch cheater maps
int progsCRC; // this is used with feature ENGINE_QUAKE_COMPATIBLE
string name; // map name
string startspot; // player_start name on nextmap
char name[MAX_QPATH]; // map name
char startspot[MAX_QPATH];
double lastchecktime;
int lastcheck; // number of last checked client
@ -174,8 +175,9 @@ typedef struct server_s
int num_consistency; // typically check model bounds on this
int num_resources;
sv_baselines_t instanced; // instanced baselines
sv_baseline_t instanced[MAX_CUSTOM_BASELINES]; // instanced baselines
int last_valid_baseline;// all the entities with number more than that was created in-game and doesn't have the baseline
int num_instanced;
// unreliable data to send to clients.
sizebuf_t datagram;
@ -239,13 +241,13 @@ typedef struct sv_client_s
double cl_updaterate; // client requested updaterate
double timebase; // client timebase
double lastservertime; // check if server time was not changed so no resaon to send update
double connection_started;
char hashedcdkey[34]; // MD5 hash is 32 hex #'s, plus trailing 0
customization_t customdata; // player customization linked list
resource_t resourcesonhand;
resource_t resourcesneeded; // <mapname.res> from client (server downloading)
file_t *upload;
usercmd_t lastcmd; // for filling in big drops
double connecttime;
@ -270,9 +272,7 @@ typedef struct sv_client_s
byte datagram_buf[MAX_DATAGRAM];
client_frame_t *frames; // updates can be delta'd from here
event_state_t events;
double connection_started;
event_state_t events; // delta-updated events cycle
int challenge; // challenge of this user, randomly generated
int userid; // identifying number on server
@ -345,35 +345,27 @@ typedef struct
edict_t *msg_ent; // user message member entity
vec3_t msg_org; // user message member origin
// catched user messages (nasty hack)
int gmsgHudText; // -1 if not catched (e.g. mod not registered this message)
void *hInstance; // pointer to game.dll
qboolean config_executed; // should to execute config.cfg once time to restore FCVAR_ARCHIVE that specified in hl.dll
union
{
edict_t *edicts; // acess by edict number
void *vp; // acess by offset in bytes
};
edict_t *edicts; // solid array of server entities
int numEntities; // actual entities count
movevars_t movevars; // curstate
movevars_t oldmovevars; // oldstate
movevars_t movevars; // movement variables curstate
movevars_t oldmovevars; // movement variables oldstate
playermove_t *pmove; // pmove state
sv_interp_t interp[MAX_CLIENTS]; // interpolate clients
sv_pushed_t pushed[MAX_PUSHED_ENTS]; // no reason to keep array for all edicts
// 256 it should be enough for any game situation
globalvars_t *globals; // server globals
DLL_FUNCTIONS dllFuncs; // dll exported funcs
NEW_DLL_FUNCTIONS dllFuncs2; // new dll exported funcs (may be NULL)
physics_interface_t physFuncs; // physics interface functions (Xash3D extension)
byte *mempool; // server premamnent pool: edicts etc
byte *stringspool; // for engine strings
SAVERESTOREDATA SaveData; // shared struct, used for save data
} svgame_static_t;
typedef struct
@ -445,8 +437,6 @@ extern convar_t sv_skyangle;
extern convar_t sv_consistency;
extern convar_t sv_password;
extern convar_t sv_uploadmax;
extern convar_t sv_spawntime;
extern convar_t sv_changetime;
extern convar_t deathmatch;
extern convar_t hostname;
extern convar_t skill;

View File

@ -286,17 +286,17 @@ static void SV_EmitPacketEntities( sv_client_t *cl, client_frame_t *to, sizebuf_
int offset = 0;
// trying to reduce message by select optimal baseline
if( !sv_instancedbaseline.value || !sv.instanced.count || sv.last_valid_baseline > newnum )
if( !sv_instancedbaseline.value || !sv.num_instanced || sv.last_valid_baseline > newnum )
{
offset = SV_FindBestBaseline( cl, newindex, &baseline, newent, to, player );
}
else
{
for( i = 0; i < sv.instanced.count; i++ )
for( i = 0; i < sv.num_instanced; i++ )
{
if( !Q_strcmp( classname, sv.instanced.classnames[i] ))
if( !Q_strcmp( classname, sv.instanced[i].classname ))
{
baseline = &sv.instanced.baselines[i];
baseline = &sv.instanced[i].baseline;
offset = -i;
break;
}
@ -649,7 +649,6 @@ SV_SendClientDatagram
*/
void SV_SendClientDatagram( sv_client_t *cl )
{
static int message_peak = 0;
byte msg_buf[MAX_DATAGRAM];
sizebuf_t msg;
@ -686,12 +685,6 @@ void SV_SendClientDatagram( sv_client_t *cl )
MSG_Clear( &cl->datagram );
if( MSG_GetNumBytesWritten( &msg ) > message_peak )
{
Msg( "max bytes %d for datagram\n", MSG_GetNumBytesWritten( &msg ));
message_peak = MSG_GetNumBytesWritten( &msg );
}
if( MSG_CheckOverflow( &msg ))
{
// must have room left for the packet header

View File

@ -852,7 +852,7 @@ edict_t *SV_AllocEdict( void )
}
if( i >= GI->max_edicts )
Sys_Error( "ED_AllocEdict: no free edicts (max is %d)\n", GI->max_edicts );
Host_Error( "ED_AllocEdict: no free edicts (max is %d)\n", GI->max_edicts );
svgame.numEntities++;
e = EDICT_NUM( i );
@ -922,7 +922,7 @@ edict_t* SV_AllocPrivateData( edict_t *ent, string_t className )
return NULL;
}
SetBits( ent->v.flags, FL_CUSTOMENTITY ); // sort of hack
SetBits( ent->v.flags, FL_CUSTOMENTITY ); // it's a custom entity but not a beam!
}
SpawnEdict( &ent->v );
@ -940,7 +940,8 @@ create specified entity, alloc private data
edict_t* SV_CreateNamedEntity( edict_t *ent, string_t className )
{
edict_t *ed = SV_AllocPrivateData( ent, className );
// for some reasons this flag should be immediately cleared
if( ed ) ClearBits( ed->v.flags, FL_CUSTOMENTITY );
return ed;
@ -1616,9 +1617,6 @@ edict_t* pfnFindClientInPVS( edict_t *pEdict )
VectorAdd( pEdict->v.origin, pEdict->v.view_ofs, view );
}
if( FBitSet( pEdict->v.effects, EF_INVLIGHT ))
view[2] -= 1.0f; // HACKHACK for barnacle
leaf = Mod_PointInLeaf( view, sv.worldmodel->nodes );
if( CHECKVISBIT( clientpvs, leaf->cluster ))
@ -1732,6 +1730,7 @@ static void pfnMakeStatic( edict_t *ent )
Con_Printf( S_WARN "MAX_STATIC_ENTITIES limit exceeded (%d)\n", MAX_STATIC_ENTITIES );
sv.static_ents_overflow = true;
}
sv.ignored_static_ents++; // continue overflowed entities
return;
}
@ -2465,13 +2464,6 @@ void pfnMessageEnd( void )
if( !svgame.msg_started ) Host_Error( "MessageEnd: called with no active message\n" );
svgame.msg_started = false;
// HACKHACK: clearing HudText in background mode
if( sv.background && svgame.msg_index >= 0 && svgame.msg[svgame.msg_index].number == svgame.gmsgHudText )
{
MSG_Clear( &sv.multicast );
return;
}
if( MSG_CheckOverflow( &sv.multicast ))
{
Con_Printf( S_ERROR "MessageEnd: %s has overflow multicast buffer\n", name );
@ -2921,7 +2913,7 @@ pfnPEntityOfEntOffset
*/
edict_t* pfnPEntityOfEntOffset( int iEntOffset )
{
return (&((edict_t *)svgame.vp)[iEntOffset]);
return (edict_t *)((byte *)svgame.edicts + iEntOffset);
}
/*
@ -2932,7 +2924,7 @@ pfnEntOffsetOfPEntity
*/
int pfnEntOffsetOfPEntity( const edict_t *pEdict )
{
return ((byte *)pEdict - (byte *)svgame.vp);
return (byte *)pEdict - (byte *)svgame.edicts;
}
/*
@ -3085,10 +3077,6 @@ int pfnRegUserMsg( const char *pszName, int iSize )
svgame.msg[i].number = svc_lastmsg + i;
svgame.msg[i].size = iSize;
// catch some user messages
if( !Q_strcmp( pszName, "HudText" ))
svgame.gmsgHudText = svc_lastmsg + i;
if( sv.state == ss_active )
{
// tell the client about new user message
@ -3966,15 +3954,15 @@ pfnCreateInstancedBaseline
*/
int pfnCreateInstancedBaseline( int classname, struct entity_state_s *baseline )
{
if( !baseline || sv.instanced.count >= MAX_CUSTOM_BASELINES )
if( !baseline || sv.num_instanced >= MAX_CUSTOM_BASELINES )
return 0;
// g-cont. must sure that classname is really allocated
sv.instanced.classnames[sv.instanced.count] = SV_CopyString( STRING( classname ));
sv.instanced.baselines[sv.instanced.count] = *baseline;
sv.instanced.count++;
sv.instanced[sv.num_instanced].classname = SV_CopyString( STRING( classname ));
sv.instanced[sv.num_instanced].baseline = *baseline;
sv.num_instanced++;
return sv.instanced.count;
return sv.num_instanced;
}
/*
@ -4363,9 +4351,11 @@ ed should be a properly initialized empty edict.
qboolean SV_ParseEdict( char **pfile, edict_t *ent )
{
KeyValueData pkvd[256]; // per one entity
qboolean adjust_origin = false;
int i, numpairs = 0;
char *classname = NULL;
char token[2048];
vec3_t origin;
// go through all the dictionary pairs
while( 1 )
@ -4427,7 +4417,6 @@ qboolean SV_ParseEdict( char **pfile, edict_t *ent )
if( FBitSet( ent->v.flags, FL_CUSTOMENTITY ))
{
ClearBits( ent->v.flags, FL_CUSTOMENTITY );
if( numpairs < 256 )
{
pkvd[numpairs].szClassName = "custom";
@ -4436,8 +4425,22 @@ qboolean SV_ParseEdict( char **pfile, edict_t *ent )
pkvd[numpairs].fHandled = false;
numpairs++;
}
// clear it now - no longer used
ClearBits( ent->v.flags, FL_CUSTOMENTITY );
}
#ifdef HACKS_RELATED_HLMODS
// chemical existence have broked changelevels
if( !Q_stricmp( GI->gamedir, "ce" ))
{
if( !Q_stricmp( sv.name, "ce08_01" ) && !Q_stricmp( classname, "info_player_start" ))
adjust_origin = true;
if( !Q_stricmp( sv.name, "ce08_02" ) && !Q_stricmp( classname, "info_player_start_force" ))
adjust_origin = true;
}
#endif
for( i = 0; i < numpairs; i++ )
{
if( !Q_strcmp( pkvd[i].szKeyName, "angle" ))
@ -4457,6 +4460,16 @@ qboolean SV_ParseEdict( char **pfile, edict_t *ent )
else pkvd[i].szValue = copystring( "0 0 0" ); // technically an error
}
#ifdef HACKS_RELATED_HLMODS
if( adjust_origin && !Q_strcmp( pkvd[i].szKeyName, "origin" ))
{
char *pstart = pkvd[i].szValue;
COM_ParseVector( &pstart, origin, 3 );
Mem_Free( pkvd[i].szValue ); // release old value, so we don't need these
copystring( va( "%g %g %g", origin[0], origin[1], origin[2] - 16.0f ));
}
#endif
if( !Q_strcmp( pkvd[i].szKeyName, "light" ))
{
Mem_Free( pkvd[i].szKeyName );
@ -4644,7 +4657,7 @@ qboolean SV_LoadProgs( const char *name )
svgame.pmove = &gpMove;
svgame.globals = &gpGlobals;
svgame.mempool = Mem_AllocPool( "Server Edicts Zone" );
svgame.hInstance = COM_LoadLibrary( name, true );
svgame.hInstance = COM_LoadLibrary( name, true, false );
if( !svgame.hInstance ) return false;
// make sure what new dll functions is cleared
@ -4743,9 +4756,6 @@ qboolean SV_LoadProgs( const char *name )
for( i = 0, e = svgame.edicts; i < GI->max_edicts; i++, e++ )
e->free = true; // mark all edicts as freed
// clear user messages
svgame.gmsgHudText = -1;
Cvar_FullSet( "host_gameloaded", "1", FCVAR_READ_ONLY );
svgame.stringspool = Mem_AllocPool( "Server Strings" );

View File

@ -87,7 +87,10 @@ int SV_SoundIndex( const char *filename )
return 0;
if( filename[0] == '!' )
Host_Error( "SV_SoundIndex: '%s' do not precache sentence names!\n", filename );
{
Con_Printf( S_WARN "'%s' do not precache sentence names!\n", filename );
return 0;
}
if( *filename == '\\' || *filename == '/' )
filename++;
@ -415,11 +418,11 @@ void SV_CreateBaseline( void )
}
MSG_WriteUBitLong( &sv.signon, LAST_EDICT, MAX_ENTITY_BITS ); // end of baselines
MSG_WriteUBitLong( &sv.signon, sv.instanced.count, 6 );
MSG_WriteUBitLong( &sv.signon, sv.num_instanced, 6 );
for( entnum = 0; entnum < sv.instanced.count; entnum++ )
for( entnum = 0; entnum < sv.num_instanced; entnum++ )
{
base = &sv.instanced.baselines[entnum];
base = &sv.instanced[entnum].baseline;
MSG_WriteDeltaEntity( &nullstate, base, &sv.signon, true, false, 1.0f, 0 );
}
}
@ -481,16 +484,11 @@ void SV_ActivateServer( int runPhysics )
// parse user-specified resources
SV_CreateGenericResources();
sv.frametime = SV_SPAWN_TIME;
if( runPhysics )
{
sv.frametime = bound( 0.1, sv_spawntime.value, 0.8 );
numFrames = (svs.maxclients <= 1) ? 2 : 8;
}
else
{
sv.frametime = bound( 0.001, sv_changetime.value, 0.1 );
numFrames = 1;
}
else numFrames = 1;
// run some frames to allow everything to settle
for( i = 0; i < numFrames; i++ )

View File

@ -98,9 +98,6 @@ CVAR_DEFINE_AUTO( sv_skydir_z, "1", FCVAR_MOVEVARS|FCVAR_UNLOGGED, "sky rotation
CVAR_DEFINE_AUTO( sv_skyangle, "0", FCVAR_MOVEVARS|FCVAR_UNLOGGED, "skybox rotational angle (in degrees)" );
CVAR_DEFINE_AUTO( sv_skyspeed, "0", 0, "skybox rotational speed" );
CVAR_DEFINE( sv_spawntime, "host_spawntime", "0.1", FCVAR_ARCHIVE, "host.frametime on spawn new map (force to 0.8 if have problems)" );
CVAR_DEFINE( sv_changetime, "host_changetime", "0.001", FCVAR_ARCHIVE, "host.frametime on changelevel (force to 0.1 if have player stucks)" );
CVAR_DEFINE_AUTO( showtriggers, "0", FCVAR_LATCH, "debug cvar shows triggers" );
CVAR_DEFINE_AUTO( sv_airmove, "1", FCVAR_SERVER, "obsolete, compatibility issues" );
CVAR_DEFINE_AUTO( sv_version, "", FCVAR_READ_ONLY, "engine version string" );
@ -839,8 +836,6 @@ void SV_Init( void )
sv_hostmap = Cvar_Get( "hostmap", GI->startmap, 0, "keep name of last entered map" );
Cvar_RegisterVariable (&sv_password);
Cvar_RegisterVariable (&sv_lan);
Cvar_RegisterVariable (&sv_spawntime);
Cvar_RegisterVariable (&sv_changetime);
Cvar_RegisterVariable (&violence_ablood);
Cvar_RegisterVariable (&violence_hblood);
Cvar_RegisterVariable (&violence_agibs);
@ -947,7 +942,13 @@ before Sys_Quit or Sys_Error
void SV_Shutdown( const char *finalmsg )
{
// already freed
if( !SV_Initialized( )) return;
if( !SV_Initialized( ))
{
// drop the client if want to load a new map
if( CL_IsPlaybackDemo( ))
CL_Drop();
return;
}
if( COM_CheckString( finalmsg ))
Con_Printf( "%s", finalmsg );