10 Mar 2018

This commit is contained in:
g-cont 2018-03-10 00:00:00 +03:00 committed by Alibek Omarov
parent 49c19a90ab
commit e96b555d6b
31 changed files with 557 additions and 203 deletions

View File

@ -19,6 +19,7 @@
#include "pm_defs.h"
#include "pmtrace.h"
#include "pm_shared.h"
#include "com_weapons.h"
#define DLLEXPORT __declspec( dllexport )
@ -27,6 +28,7 @@ void Game_AddObjects( void );
extern vec3_t v_origin;
int g_iAlive = 1;
int g_iLaserDot = 0;
extern "C"
{
@ -89,6 +91,8 @@ void DLLEXPORT HUD_TxferLocalOverrides( struct entity_state_s *state, const stru
{
VectorCopy( client->origin, state->origin );
g_iLaserDot = (client->flags & FL_LASERDOT) ? 1 : 0;
// Spectator
state->iuser1 = client->iuser1;
state->iuser2 = client->iuser2;
@ -504,6 +508,60 @@ void Beams( void )
}
#endif
TEMPENTITY *m_pLaserSpot = NULL;
void CL_UpdateLaserSpot( void )
{
cl_entity_t *player = gEngfuncs.GetLocalPlayer();
if( !player ) return;
if(( g_iLaserDot && cl_lw->value ) && !m_pLaserSpot )
{
// create laserspot
int m_iSpotModel = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/laserdot.spr" );
m_pLaserSpot = gEngfuncs.pEfxAPI->R_TempSprite( Vector( 0, 0, 0), Vector( 0, 0, 0), 1.0, m_iSpotModel, kRenderGlow, kRenderFxNoDissipation, 1.0, 9999, FTENT_SPRCYCLE );
if( !m_pLaserSpot ) return;
m_pLaserSpot->entity.curstate.rendercolor.r = 200;
m_pLaserSpot->entity.curstate.rendercolor.g = 12;
m_pLaserSpot->entity.curstate.rendercolor.b = 12;
// gEngfuncs.Con_Printf( "CLaserSpot::Create()\n" );
}
else if(( !g_iLaserDot || !cl_lw->value ) && m_pLaserSpot )
{
// destroy laserspot
// gEngfuncs.Con_Printf( "CLaserSpot::Killed()\n" );
m_pLaserSpot->die = 0.0f;
m_pLaserSpot = NULL;
return;
}
else if( !m_pLaserSpot )
{
// inactive
return;
}
assert( m_pLaserSpot != NULL );
Vector forward, vecSrc, vecEnd, origin, angles, view_ofs;
gEngfuncs.GetViewAngles( (float *)angles );
AngleVectors( angles, forward, NULL, NULL );
gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs );
vecSrc = player->origin + view_ofs;
vecEnd = vecSrc + forward * 8192.0f;
pmtrace_t *trace = gEngfuncs.PM_TraceLine( vecSrc, vecEnd, PM_TRACELINE_ANYVISIBLE, 2, -1 );
// update laserspot endpos
m_pLaserSpot->entity.origin = trace->endpos;
m_pLaserSpot->die = gEngfuncs.GetClientTime() + 0.1f;
}
/*
=========================
HUD_CreateEntities
@ -535,6 +593,8 @@ void DLLEXPORT HUD_CreateEntities( void )
#if defined( BEAM_TEST )
Beams();
#endif
// predictable laserdot
CL_UpdateLaserSpot();
// Add in any game specific objects
Game_AddObjects();

View File

@ -50,6 +50,7 @@
#define FL_ONTRAIN (1<<24) // Player is _controlling_ a train, so movement commands should be ignored on client during prediction.
#define FL_WORLDBRUSH (1<<25) // Not moveable/removeable brush entity (really part of the world, but represented as an entity for transparency or something)
#define FL_SPECTATOR (1<<26) // This client is a spectator, don't run touch functions, etc.
#define FL_LASERDOT (1<<27) // Predicted laser spot from rocket launcher
#define FL_CUSTOMENTITY (1<<29) // This is a custom entity
#define FL_KILLME (1<<30) // This entity is marked for death -- This allows the engine to kill ents at the appropriate time
@ -113,8 +114,6 @@
#define EF_LIGHT 64 // rocket flare glow sprite
#define EF_NODRAW 128 // don't draw entity
#define EF_WATERSIDES (1<<26) // Do not remove sides for func_water entity
#define EF_FULLBRIGHT (1<<27) // Just get fullbright
#define EF_NOSHADOW (1<<28) // ignore shadow for this entity

View File

@ -44,8 +44,6 @@ typedef struct event_api_s
void ( *EV_KillEvents )( int entnum, const char *eventname );
// Xash3D extension
unsigned short (*EV_IndexForEvent)( const char *name );
const char *(*EV_EventForIndex)( unsigned short index );
void ( *EV_PlayerTraceExt )( float *start, float *end, int traceFlags, int (*pfnIgnore)( struct physent_s *pe ), struct pmtrace_s *tr );
const char *(*EV_SoundForIndex)( int index );
struct msurface_s *( *EV_TraceSurface )( int ground, float *vstart, float *vend );

View File

@ -209,13 +209,13 @@ typedef struct render_api_s
// Misc renderer functions
void (*GL_DrawParticles)( const struct ref_viewpass_s *rvp, qboolean trans_pass, float frametime );
void (*EnvShot)( const float *vieworg, const char *name, qboolean skyshot, int shotsize ); // creates a cubemap or skybox into gfx\env folder
void (*EnvShot)( const float *vieworg, const char *name, qboolean skyshot, int shotsize ); // store skybox into gfx\env folder
int (*SPR_LoadExt)( const char *szPicName, unsigned int texFlags ); // extended version of SPR_Load
colorVec (*LightVec)( const float *start, const float *end, float *lightspot );
struct mstudiotex_s *( *StudioGetTexture )( struct cl_entity_s *e );
const struct ref_overview_s *( *GetOverviewParms )( void );
void (*R_Reserved0)( void ); // for potential interface expansion without broken compatibility
void (*R_Reserved1)( void );
const char *( *GetFileByIndex )( int fileindex );
void (*R_Reserved1)( void ); // for potential interface expansion without broken compatibility
void (*R_Reserved2)( void );
// static allocations
@ -245,8 +245,6 @@ typedef struct render_interface_s
void (*GL_BuildLightmaps)( void );
// setup map bounds for ortho-projection when we in dev_overview mode
void (*GL_OrthoBounds)( const float *mins, const float *maxs );
// handle decals which hit mod_studio or mod_sprite
void (*R_StudioDecalShoot)( int decalTexture, struct cl_entity_s *ent, const float *start, const float *pos, int flags, modelstate_t *state );
// prepare studio decals for save
int (*R_CreateStudioDecalList)( decallist_t *pList, int count );
// clear decals by engine request (e.g. for demo recording or vid_restart)

View File

@ -47,13 +47,21 @@ LINK_ENTITY_TO_CLASS( laser_spot, CLaserSpot );
//=========================================================
//=========================================================
CLaserSpot *CLaserSpot::CreateSpot( void )
CLaserSpot *CLaserSpot::CreateSpot( edict_t *pOwner )
{
CLaserSpot *pSpot = GetClassPtr( (CLaserSpot *)NULL );
pSpot->Spawn();
pSpot->pev->classname = MAKE_STRING("laser_spot");
if( pOwner )
{
// predictable laserspot
pSpot->pev->flags |= FL_SKIPLOCALHOST;
pOwner->v.flags |= FL_LASERDOT;
pSpot->pev->owner = pOwner;
}
return pSpot;
}
@ -79,6 +87,9 @@ void CLaserSpot::Spawn( void )
void CLaserSpot::Suspend( float flSuspendTime )
{
pev->effects |= EF_NODRAW;
if( !FNullEnt( pev->owner ))
pev->owner->v.flags &= ~FL_LASERDOT;
SetThink( Revive );
pev->nextthink = gpGlobals->time + flSuspendTime;
@ -91,9 +102,20 @@ void CLaserSpot::Revive( void )
{
pev->effects &= ~EF_NODRAW;
if( !FNullEnt( pev->owner ))
pev->owner->v.flags |= FL_LASERDOT;
SetThink( NULL );
}
void CLaserSpot :: Killed( entvars_t *pevAttacker, int iGib )
{
// tell the owner about laserspot
if( !FNullEnt( pev->owner ))
pev->owner->v.flags &= ~FL_LASERDOT;
CBaseEntity :: Killed( pevAttacker, iGib );
}
void CLaserSpot::Precache( void )
{
PRECACHE_MODEL("sprites/laserdot.spr");
@ -557,7 +579,7 @@ void CRpg::UpdateSpot( void )
{
if (!m_pSpot)
{
m_pSpot = CLaserSpot::CreateSpot();
m_pSpot = CLaserSpot::CreateSpot( m_pPlayer->edict());
}
UTIL_MakeVectors( m_pPlayer->pev->v_angle );

View File

@ -671,8 +671,8 @@ class CLaserSpot : public CBaseEntity
public:
void Suspend( float flSuspendTime );
void EXPORT Revive( void );
static CLaserSpot *CreateSpot( void );
void Killed( entvars_t *pevAttacker, int iGib );
static CLaserSpot *CreateSpot( edict_t *pOwner );
};
class CRpg : public CBasePlayerWeapon

View File

@ -60,7 +60,8 @@ qboolean CL_CheckFile( sizebuf_t *msg, resource_t *pResource )
return true;
}
if( FS_FileExists( filepath, false ))
// don't request downloads from local client it's silly
if( Host_IsLocalClient() || FS_FileExists( filepath, false ))
return true;
if( cls.demoplayback )

View File

@ -135,7 +135,7 @@ word CL_EventIndex( const char *name )
{
int i;
if( !name || !name[0] )
if( !COM_CheckString( name ))
return 0;
for( i = 1; i < MAX_EVENTS && cl.event_precache[i][0]; i++ )
@ -146,20 +146,6 @@ word CL_EventIndex( const char *name )
return 0;
}
/*
=============
CL_EventIndex
=============
*/
const char *CL_IndexEvent( word index )
{
if( index < 0 || index >= MAX_EVENTS )
return 0;
return cl.event_precache[index];
}
/*
=============
CL_RegisterEvent

View File

@ -868,12 +868,6 @@ int CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta )
// Clear loading plaque.
CL_SignonReply ();
}
else if( cls.state == ca_active )
{
// g-cont: now stair climbing interpolation
// is prepared for a new level and ready to use
cl.first_frame = false;
}
return playerbytes;
}

View File

@ -3566,9 +3566,7 @@ static event_api_t gEventApi =
pfnTraceTexture,
pfnStopAllSounds,
pfnKillEvents,
CL_EventIndex, // Xash3D added
CL_IndexEvent,
CL_PlayerTraceExt,
CL_PlayerTraceExt, // Xash3D added
CL_SoundFromIndex,
pfnTraceSurface,
pfnGetMoveVars,

View File

@ -174,7 +174,7 @@ void CL_CheckClientState( void )
cls.state = ca_active;
cls.changelevel = false; // changelevel is done
cls.changedemo = false; // changedemo is done
cl.first_frame = true;
cl.first_frame = true; // first rendering frame
SCR_MakeLevelShot(); // make levelshot if needs
Cvar_SetValue( "scr_loading", 0.0f ); // reset progress bar
@ -183,7 +183,6 @@ void CL_CheckClientState( void )
Con_DPrintf( "client connected at %.2f sec\n", Sys_DoubleTime() - cls.timestart );
if(( cls.demoplayback || cls.disable_servercount != cl.servercount ) && cl.video_prepped )
SCR_EndLoadingPlaque(); // get rid of loading plaque
cl.first_frame = true;
}
}
@ -2344,6 +2343,8 @@ qboolean CL_PrecacheResources( void )
Q_strncpy( host.draw_decals[pRes->nIndex], pRes->szFileName, sizeof( host.draw_decals[0] ));
break;
case t_generic:
Q_strncpy( cl.files_precache[pRes->nIndex], pRes->szFileName, sizeof( cl.files_precache[0] ));
cl.numfiles = Q_max( cl.numfiles, pRes->nIndex + 1 );
break;
case t_eventscript:
Q_strncpy( cl.event_precache[pRes->nIndex], pRes->szFileName, sizeof( cl.event_precache[0] ));
@ -2359,6 +2360,7 @@ qboolean CL_PrecacheResources( void )
// make sure modelcount is in-range
cl.nummodels = bound( 0, cl.nummodels, MAX_MODELS );
cl.numfiles = bound( 0, cl.numfiles, MAX_CUSTOM );
S_EndRegistration();
return true;

View File

@ -45,7 +45,7 @@ const char *svc_strings[svc_lastmsg+1] =
"svc_updateuserinfo",
"svc_deltatable",
"svc_clientdata",
"svc_studiodecal",
"svc_fileindex",
"svc_pings",
"svc_particle",
"svc_restoresound",
@ -1543,24 +1543,17 @@ prceache model from server
*/
void CL_PrecacheModel( sizebuf_t *msg )
{
const char *s;
int i;
int modelIndex;
i = MSG_ReadUBitLong( msg, MAX_MODEL_BITS );
s = MSG_ReadString( msg );
modelIndex = MSG_ReadUBitLong( msg, MAX_MODEL_BITS );
if( i < 0 || i >= MAX_MODELS )
Host_Error( "CL_PrecacheModel: bad modelindex %i\n", i );
if( modelIndex < 0 || modelIndex >= MAX_MODELS )
Host_Error( "CL_PrecacheModel: bad modelindex %i\n", modelIndex );
if( i == WORLD_INDEX )
cl.models[i] = Mod_LoadWorld( s, false );
else cl.models[i] = Mod_FindName( s, false );
cl.models[modelIndex] = Mod_ForName( MSG_ReadString( msg ), false, false );
if( i >= cl.nummodels )
{
cl.nummodels = i + 1;
cl.nummodels = Q_min( cl.nummodels, MAX_MODELS );
}
cl.nummodels = Q_max( cl.nummodels, modelIndex + 1 );
cl.nummodels = bound( 0, cl.nummodels, MAX_MODELS );
}
/*
@ -1609,6 +1602,28 @@ void CL_PrecacheEvent( sizebuf_t *msg )
CL_SetEventIndex( cl.event_precache[eventIndex], eventIndex );
}
/*
================
CL_PrecacheFile
prceache generic resource from server
================
*/
void CL_PrecacheFile( sizebuf_t *msg )
{
int fileIndex;
fileIndex = MSG_ReadUBitLong( msg, MAX_CUSTOM_BITS );
if( fileIndex < 0 || fileIndex >= MAX_CUSTOM )
Host_Error( "CL_PrecacheFile: bad fileindex %i\n", fileIndex );
Q_strncpy( cl.files_precache[fileIndex], MSG_ReadString( msg ), sizeof( cl.files_precache[0] ));
cl.numfiles = Q_max( cl.numfiles, fileIndex + 1 );
cl.numfiles = bound( 0, cl.numfiles, MAX_CUSTOM );
}
/*
================
CL_UpdateUserPings
@ -1969,53 +1984,6 @@ void CL_ParseDirector( sizebuf_t *msg )
clgame.dllFuncs.pfnDirectorMessage( iSize, pbuf );
}
/*
==============
CL_ParseStudioDecal
Studio Decal message. Used by engine in case
we need save\restore decals
==============
*/
void CL_ParseStudioDecal( sizebuf_t *msg )
{
modelstate_t state;
vec3_t start, pos;
int decalIndex, entityIndex;
int modelIndex = 0;
int i, flags;
MSG_ReadVec3Coord( msg, pos );
MSG_ReadVec3Coord( msg, start );
decalIndex = MSG_ReadWord( msg );
entityIndex = MSG_ReadWord( msg );
flags = MSG_ReadByte( msg );
state.sequence = MSG_ReadShort( msg );
state.frame = MSG_ReadShort( msg );
state.blending[0] = MSG_ReadByte( msg );
state.blending[1] = MSG_ReadByte( msg );
for( i = 0; i < 4; i++ )
state.controller[i] = MSG_ReadByte( msg );
for( i = 0; i < 16; i++ )
state.poseparam[i] = MSG_ReadByte( msg );
modelIndex = MSG_ReadWord( msg );
state.body = MSG_ReadByte( msg );
state.skin = MSG_ReadByte( msg );
state.scale = MSG_ReadWord( msg );
if( clgame.drawFuncs.R_StudioDecalShoot != NULL )
{
int decalTexture = CL_DecalIndex( decalIndex );
cl_entity_t *ent = CL_GetEntityByIndex( entityIndex );
if( ent && !ent->model && modelIndex != 0 )
ent->model = CL_ModelHandle( modelIndex );
clgame.drawFuncs.R_StudioDecalShoot( decalTexture, ent, start, pos, flags, &state );
}
}
/*
==============
CL_ParseScreenShake
@ -2347,12 +2315,12 @@ void CL_ParseServerMessage( sizebuf_t *msg, qboolean normal_message )
SCR_BeginLoadingPlaque( cl.background );
cls.changedemo = true;
}
CL_ClearState ();
CL_InitEdicts (); // re-arrange edicts
}
else MsgDev( D_INFO, "Server disconnected, reconnecting\n" );
CL_ClearState ();
CL_InitEdicts (); // re-arrange edicts
if( cls.demoplayback )
{
cl.background = (cls.demonum != -1) ? true : false;
@ -2403,8 +2371,8 @@ void CL_ParseServerMessage( sizebuf_t *msg, qboolean normal_message )
CL_ParseClientData( msg );
cl.frames[cl.parsecountmod].graphdata.client += MSG_GetNumBytesRead( msg ) - bufStart;
break;
case svc_studiodecal:
CL_ParseStudioDecal( msg );
case svc_fileindex:
CL_PrecacheFile( msg );
break;
case svc_pings:
CL_UpdateUserPings( msg );

View File

@ -319,6 +319,9 @@ void SCR_BeginLoadingPlaque( qboolean is_background )
if( cls.state == ca_disconnected || cls.disable_screen )
return; // already set
if( cls.key_dest == key_console )
return;
cls.draw_changelevel = !is_background;
SCR_UpdateScreen();
cls.disable_screen = host.realtime;

View File

@ -141,6 +141,9 @@ void CL_AddClientResources( void )
char filepath[MAX_QPATH];
int i;
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
return;
// check sprites first
for( i = 0; i < ARRAYSIZE( cl_default_sprites ); i++ )
{

View File

@ -143,7 +143,11 @@ void V_SetRefParams( ref_params_t *fd )
fd->demoplayback = cls.demoplayback;
fd->hardware = 1; // OpenGL
if( cl.first_frame ) fd->smoothing = true; // NOTE: currently this used to prevent ugly un-duck effect while level is changed
if( cl.first_frame )
{
cl.first_frame = false; // now can be unlocked
fd->smoothing = true; // NOTE: currently this used to prevent ugly un-duck effect while level is changed
}
else fd->smoothing = cl.local.pushmsec; // enable smoothing in multiplayer by server request (AMX uses)
// get pointers to movement vars and user cmd

View File

@ -267,9 +267,11 @@ typedef struct
char sound_precache[MAX_SOUNDS][MAX_QPATH];
char event_precache[MAX_EVENTS][MAX_QPATH];
char files_precache[MAX_CUSTOM][MAX_QPATH];
lightstyle_t lightstyles[MAX_LIGHTSTYLES];
model_t *models[MAX_MODELS+1]; // precached models (plus sentinel slot)
int nummodels;
int numfiles;
consistency_t consistency_list[MAX_MODELS];
int num_consistency;
@ -776,9 +778,8 @@ void CL_QueueEvent( int flags, int index, float delay, event_args_t *args );
void CL_PlaybackEvent( int flags, const edict_t *pInvoker, word eventindex, float delay, float *origin,
float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 );
void CL_RegisterEvent( int lastnum, const char *szEvName, pfnEventHook func );
word CL_EventIndex( const char *name );
const char *CL_IndexEvent( word index );
void CL_ResetEvent( event_info_t *ei );
word CL_EventIndex( const char *name );
void CL_FireEvents( void );
//

View File

@ -1402,6 +1402,19 @@ static uint pfnFileBufferCRC32( const void *buffer, const int length )
return modelCRC;
}
/*
=============
CL_GenericHandle
=============
*/
const char *CL_GenericHandle( int fileindex )
{
if( fileindex < 0 || fileindex >= MAX_CUSTOM )
return 0;
return cl.files_precache[fileindex];
}
static render_api_t gRenderAPI =
{
@ -1456,7 +1469,7 @@ static render_api_t gRenderAPI =
R_LightVec,
R_StudioGetTexture,
GL_GetOverviewParms,
NULL,
CL_GenericHandle,
NULL,
NULL,
R_Mem_Alloc,

View File

@ -147,6 +147,287 @@ long COM_RandomLong( long lLow, long lHigh )
return lLow + (n % x);
}
/*
===============================================================================
LZSS Compression
===============================================================================
*/
#define LZSS_ID (('S'<<24)|('S'<<16)|('Z'<<8)|('L'))
#define LZSS_LOOKSHIFT 4
#define LZSS_WINDOW_SIZE 4096
#define LZSS_LOOKAHEAD BIT( LZSS_LOOKSHIFT )
typedef struct
{
unsigned int id;
unsigned short size;
} lzss_header_t;
// expected to be sixteen bytes
typedef struct lzss_node_s
{
const byte *data;
struct lzss_node_s *prev;
struct lzss_node_s *next;
char pad[4];
} lzss_node_t;
typedef struct
{
lzss_node_t *start;
lzss_node_t *end;
} lzss_list_t;
typedef struct
{
lzss_list_t *hash_table;
lzss_node_t *hash_node;
int window_size;
} lzss_state_t;
qboolean LZSS_IsCompressed( const byte *source )
{
lzss_header_t *phdr = (lzss_header_t *)source;
if( phdr && phdr->id == LZSS_ID )
return true;
return false;
}
uint LZSS_GetActualSize( const byte *source )
{
lzss_header_t *phdr = (lzss_header_t *)source;
if( phdr && phdr->id == LZSS_ID )
return phdr->size;
return 0;
}
static void LZSS_BuildHash( lzss_state_t *state, const byte *source )
{
lzss_list_t *list;
lzss_node_t *node;
unsigned int targetindex = (uint)source & ( state->window_size - 1 );
node = &state->hash_node[targetindex];
if( node->data )
{
list = &state->hash_table[*node->data];
if( node->prev )
{
list->end = node->prev;
node->prev->next = NULL;
}
else
{
list->start = NULL;
list->end = NULL;
}
}
list = &state->hash_table[*source];
node->data = source;
node->prev = NULL;
node->next = list->start;
if( list->start )
list->start->prev = node;
else list->end = node;
list->start = node;
}
byte *LZSS_CompressNoAlloc( lzss_state_t *state, byte *pInput, int input_length, byte *pOutputBuf, uint *pOutputSize )
{
byte *pStart = pOutputBuf; // allocate the output buffer, compressed buffer is expected to be less, caller will free
byte *pEnd = pStart + input_length - sizeof( lzss_header_t ) - 8; // prevent compression failure
lzss_header_t *header = (lzss_header_t *)pStart;
byte *pOutput = pStart + sizeof( lzss_header_t );
const byte *pEncodedPosition = NULL;
byte *pLookAhead = pInput;
byte *pWindow = pInput;
int i, putCmdByte = 0;
byte *pCmdByte = NULL;
if( input_length <= sizeof( lzss_header_t ) + 8 )
return NULL;
// set LZSS header
header->id = LZSS_ID;
header->size = input_length;
// create the compression work buffers, small enough (~64K) for stack
state->hash_table = (lzss_list_t *)_alloca( 256 * sizeof( lzss_list_t ));
memset( state->hash_table, 0, 256 * sizeof( lzss_list_t ));
state->hash_node = (lzss_node_t *)_alloca( state->window_size * sizeof( lzss_node_t ));
memset( state->hash_node, 0, state->window_size * sizeof( lzss_node_t ));
while( input_length > 0 )
{
int lookAheadLength = input_length < LZSS_LOOKAHEAD ? input_length : LZSS_LOOKAHEAD;
lzss_node_t *hash = state->hash_table[pLookAhead[0]].start;
int encoded_length = 0;
pWindow = pLookAhead - state->window_size;
if( pWindow < pInput )
pWindow = pInput;
if( !putCmdByte )
{
pCmdByte = pOutput++;
*pCmdByte = 0;
}
putCmdByte = ( putCmdByte + 1 ) & 0x07;
while( hash != NULL )
{
int length = lookAheadLength;
int match_length = 0;
while( length-- && hash->data[match_length] == pLookAhead[match_length] )
match_length++;
if( match_length > encoded_length )
{
encoded_length = match_length;
pEncodedPosition = hash->data;
}
if( match_length == lookAheadLength )
break;
hash = hash->next;
}
if ( encoded_length >= 3 )
{
*pCmdByte = (*pCmdByte >> 1) | 0x80;
*pOutput++ = (( pLookAhead - pEncodedPosition - 1 ) >> LZSS_LOOKSHIFT );
*pOutput++ = (( pLookAhead - pEncodedPosition - 1 ) << LZSS_LOOKSHIFT ) | ( encoded_length - 1 );
}
else
{
*pCmdByte = ( *pCmdByte >> 1 );
*pOutput++ = *pLookAhead;
encoded_length = 1;
}
for( i = 0; i < encoded_length; i++ )
{
LZSS_BuildHash( state, pLookAhead++ );
}
input_length -= encoded_length;
if( pOutput >= pEnd )
{
// compression is worse, abandon
return NULL;
}
}
if( input_length != 0 )
{
// unexpected failure
Assert( 0 );
return NULL;
}
if( !putCmdByte )
{
pCmdByte = pOutput++;
*pCmdByte = 0x01;
}
else
{
*pCmdByte = (( *pCmdByte >> 1 ) | 0x80 ) >> ( 7 - putCmdByte );
}
// put two ints at end of buffer
*pOutput++ = 0;
*pOutput++ = 0;
if( pOutputSize )
*pOutputSize = pOutput - pStart;
return pStart;
}
byte *LZSS_Compress( byte *pInput, int inputLength, uint *pOutputSize )
{
byte *pStart = (byte *)malloc( inputLength );
byte *pFinal = NULL;
lzss_state_t state;
memset( &state, 0, sizeof( state ));
state.window_size = LZSS_WINDOW_SIZE;
pFinal = LZSS_CompressNoAlloc( &state, pInput, inputLength, pStart, pOutputSize );
if( !pFinal )
{
free( pStart );
return NULL;
}
return pStart;
}
uint LZSS_Decompress( const byte *pInput, byte *pOutput )
{
uint totalBytes = 0;
int getCmdByte = 0;
int cmdByte = 0;
uint actualSize = LZSS_GetActualSize( pInput );
if( !actualSize )
return 0;
pInput += sizeof( lzss_header_t );
while( 1 )
{
if( !getCmdByte )
cmdByte = *pInput++;
getCmdByte = ( getCmdByte + 1 ) & 0x07;
if( cmdByte & 0x01 )
{
int position = *pInput++ << LZSS_LOOKSHIFT;
int i, count;
byte *pSource;
position |= ( *pInput >> LZSS_LOOKSHIFT );
count = ( *pInput++ & 0x0F ) + 1;
if( count == 1 )
break;
pSource = pOutput - position - 1;
for( i = 0; i < count; i++ )
*pOutput++ = *pSource++;
totalBytes += count;
}
else
{
*pOutput++ = *pInput++;
totalBytes++;
}
cmdByte = cmdByte >> 1;
}
if( totalBytes != actualSize )
{
Assert( 0 );
return 0;
}
return totalBytes;
}
/*
============
COM_FileBase

View File

@ -866,7 +866,6 @@ struct pmtrace_s *PM_TraceLine( float *start, float *end, int flags, int usehull
void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float attn, int flags, int pitch );
void SV_StartMusic( const char *curtrack, const char *looptrack, long position );
void SV_CreateDecal( struct sizebuf_s *msg, const float *origin, int decalIndex, int entityIndex, int modelIndex, int flags, float scale );
void SV_CreateStudioDecal( struct sizebuf_s *bf, const float *v0, const float *v1, int decal, int ent, int model, int flags, struct modelstate_s *s );
void Log_Printf( const char *fmt, ... );
struct sizebuf_s *SV_GetReliableDatagram( void );
void SV_BroadcastCommand( const char *fmt, ... );
@ -945,6 +944,10 @@ void Cmd_AutoComplete( char *complete_string );
void COM_SetRandomSeed( long lSeed );
long COM_RandomLong( long lMin, long lMax );
float COM_RandomFloat( float fMin, float fMax );
qboolean LZSS_IsCompressed( const byte *source );
uint LZSS_GetActualSize( const byte *source );
byte *LZSS_Compress( byte *pInput, int inputLength, uint *pOutputSize );
uint LZSS_Decompress( const byte *pInput, byte *pOutput );
const byte *GL_TextureData( unsigned int texnum );
void GL_FreeImage( const char *name );
void VID_InitDefaultResolution( void );

View File

@ -1008,6 +1008,7 @@ void Con_Print( const char *txt )
{
static int cr_pending = 0;
static char buf[MAX_PRINT_MSG];
static qboolean inupdate;
static int bufpos = 0;
int c, mask = 0;
@ -1056,6 +1057,16 @@ void Con_Print( const char *txt )
break;
}
}
if( cls.state != ca_disconnected && cls.state < ca_active && !cl.video_prepped && !cls.disable_screen )
{
if( !inupdate )
{
inupdate = true;
SCR_UpdateScreen ();
inupdate = false;
}
}
}
/*

View File

@ -440,17 +440,9 @@ void Host_RestartDecals( void )
decalIndex = pfnDecalIndex( entry->name );
// BSP and studio decals has different messages
if( entry->flags & FDECAL_STUDIO )
{
// NOTE: studio decal trace start saved into impactPlaneNormal
SV_CreateStudioDecal( msg, entry->position, entry->impactPlaneNormal, decalIndex, entry->entityIndex,
modelIndex, entry->flags, &entry->studio_state );
}
else
{
// studiodecals will be restored at game-side
if( !FBitSet( entry->flags, FDECAL_STUDIO ))
SV_CreateDecal( msg, entry->position, decalIndex, entry->entityIndex, modelIndex, entry->flags, entry->scale );
}
}
Z_Free( host.decalList );

View File

@ -106,7 +106,8 @@ static void Mod_FreeModel( model_t *mod )
if( !mod || !mod->name[0] )
return;
Mod_FreeUserData( mod );
if( mod->name[0] != '*' )
Mod_FreeUserData( mod );
// select the properly unloader
switch( mod->type )
@ -405,6 +406,9 @@ void Mod_PurgeStudioCache( void )
{
int i;
// release previois map
Mod_FreeModel( mod_known ); // world is stuck on slot #0 always
// we should release all the world submodels
// and clear studio sequences
for( i = 1; i < mod_numknown; i++ )
@ -438,9 +442,6 @@ model_t *Mod_LoadWorld( const char *name, qboolean preload )
// free sequence files on studiomodels
Mod_PurgeStudioCache();
// release previois map
Mod_FreeModel( mod_known ); // world is stuck on slot #0 always
// load the newmap
world.loading = true;
pworld = Mod_FindName( name, false );

View File

@ -1105,6 +1105,68 @@ void NET_SendPacket( netsrc_t sock, size_t length, const void *data, netadr_t to
}
}
/*
====================
NET_BufferToBufferCompress
generic fast compression
====================
*/
qboolean NET_BufferToBufferCompress( char *dest, uint *destLen, char *source, uint sourceLen )
{
uint uCompressedLen = 0;
byte *pbOut = NULL;
memcpy( dest, source, sourceLen );
pbOut = LZSS_Compress( source, sourceLen, &uCompressedLen );
if( pbOut && uCompressedLen > 0 && uCompressedLen <= *destLen )
{
memcpy( dest, pbOut, uCompressedLen );
*destLen = uCompressedLen;
free( pbOut );
return true;
}
else
{
if( pbOut ) free( pbOut );
memcpy( dest, source, sourceLen );
*destLen = sourceLen;
return false;
}
}
/*
====================
NET_BufferToBufferDecompress
generic fast decompression
====================
*/
qboolean NET_BufferToBufferDecompress( char *dest, uint *destLen, char *source, uint sourceLen )
{
if( LZSS_IsCompressed( source ))
{
uint uDecompressedLen = LZSS_GetActualSize( source );
if( uDecompressedLen <= *destLen )
{
*destLen = LZSS_Decompress( source, dest );
}
else
{
return false;
}
}
else
{
memcpy( dest, source, sourceLen );
*destLen = sourceLen;
}
return true;
}
/*
====================
NET_IPSocket

View File

@ -51,6 +51,8 @@ qboolean NET_StringToAdr( const char *string, netadr_t *adr );
qboolean NET_CompareAdr( const netadr_t a, const netadr_t b );
qboolean NET_CompareBaseAdr( const netadr_t a, const netadr_t b );
qboolean NET_GetPacket( netsrc_t sock, netadr_t *from, byte *data, size_t *length );
qboolean NET_BufferToBufferCompress( char *dest, uint *destLen, char *source, uint sourceLen );
qboolean NET_BufferToBufferDecompress( char *dest, uint *destLen, char *source, uint sourceLen );
void NET_SendPacket( netsrc_t sock, size_t length, const void *data, netadr_t to );
void NET_ClearLagData( qboolean bClient, qboolean bServer );

View File

@ -35,7 +35,7 @@ GNU General Public License for more details.
#define svc_updateuserinfo 13 // [byte] playernum, [string] userinfo
#define svc_deltatable 14 // [table header][...]
#define svc_clientdata 15 // [...]
#define svc_studiodecal 16 // [float*3][float*3][short][short][byte]
#define svc_fileindex 16 // [index][filepath]
#define svc_pings 17 // [bit][idx][ping][packet_loss]
#define svc_particle 18 // [float*3][char*3][byte][byte]
#define svc_restoresound 19 // <see code>
@ -125,7 +125,8 @@ GNU General Public License for more details.
#define MAX_EDICTS_BYTES ((MAX_EDICTS + 7) / 8)
#define LAST_EDICT (MAX_EDICTS - 1)
#define MAX_CUSTOM 1024 // max custom resources per level
#define MAX_CUSTOM_BITS 10
#define MAX_CUSTOM (1<<MAX_CUSTOM_BITS)// 10 bits == 1024 generic file
#define MAX_USER_MESSAGES 197 // another 58 messages reserved for engine routines
#define MAX_DLIGHTS 32 // dynamic lights (rendered per one frame)
#define MAX_ELIGHTS 64 // entity only point lights

View File

@ -477,11 +477,14 @@ long _stdcall Sys_Crash( PEXCEPTION_POINTERS pInfo )
else host.status = HOST_CRASHED;
Con_Printf( "unhandled exception: %p at address %p\n", pInfo->ExceptionRecord->ExceptionAddress, pInfo->ExceptionRecord->ExceptionCode );
#ifdef NDEBUG
// no reason to call debugger in release build - just exit
Sys_Quit();
return EXCEPTION_CONTINUE_EXECUTION;
#endif
if( !host_developer.value )
{
// for non-development mode
Sys_Quit();
return EXCEPTION_CONTINUE_EXECUTION;
}
// all other states keep unchanged to let debugger find bug
Con_DestroyConsole();
}

View File

@ -202,7 +202,6 @@ typedef struct server_s
// statistics
int ignored_static_ents;
int ignored_studio_decals;
int ignored_world_decals;
int static_ents_overflow;
} server_t;

View File

@ -542,7 +542,7 @@ void SV_SendResources( sv_client_t *cl, sizebuf_t *msg )
MSG_WriteLong( msg, svs.spawncount );
MSG_WriteLong( msg, 0 );
if( sv_downloadurl.string && sv_downloadurl.string[0] && Q_strlen( sv_downloadurl.string ) < 256 )
if( COM_CheckString( sv_downloadurl.string ) && Q_strlen( sv_downloadurl.string ) < 256 )
{
MSG_BeginServerCmd( msg, svc_resourcelocation );
MSG_WriteString( msg, sv_downloadurl.string );

View File

@ -490,57 +490,6 @@ void SV_CreateDecal( sizebuf_t *msg, const float *origin, int decalIndex, int en
MSG_WriteWord( msg, scale * 4096 );
}
/*
=======================
SV_CreateStudioDecal
NOTE: static decals only accepted when game is loading
=======================
*/
void SV_CreateStudioDecal( sizebuf_t *msg, const float *origin, const float *start, int decalIndex, int entityIndex, int modelIndex, int flags, modelstate_t *state )
{
int i;
if( msg == &sv.signon && sv.state != ss_loading )
return;
// bad model or bad entity (e.g. changelevel)
if( !entityIndex || !modelIndex )
return;
Assert( origin != NULL );
Assert( start != NULL );
// this can happens if serialized map contain 4096 static decals...
if( MSG_GetNumBytesLeft( msg ) < 50 )
{
sv.ignored_studio_decals++;
return;
}
// static decals are posters, it's always reliable
MSG_BeginServerCmd( msg, svc_studiodecal );
MSG_WriteVec3Coord( msg, origin );
MSG_WriteVec3Coord( msg, start );
MSG_WriteWord( msg, decalIndex );
MSG_WriteWord( msg, entityIndex );
MSG_WriteByte( msg, flags );
// write model state
MSG_WriteShort( msg, state->sequence );
MSG_WriteShort( msg, state->frame );
MSG_WriteByte( msg, state->blending[0] );
MSG_WriteByte( msg, state->blending[1] );
for( i = 0; i < 4; i++ )
MSG_WriteByte( msg, state->controller[i] );
for( i = 0; i < 16; i++ )
MSG_WriteByte( msg, state->poseparam[i] );
MSG_WriteWord( msg, modelIndex );
MSG_WriteByte( msg, state->body );
MSG_WriteByte( msg, state->skin );
MSG_WriteWord( msg, state->scale );
}
/*
=======================
SV_CreateStaticEntity
@ -3016,13 +2965,13 @@ edict_t *pfnPEntityOfEntIndex( int iEntIndex )
{
edict_t *pEdict = EDICT_NUM( iEntIndex );
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
if( !iEntIndex || FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
return pEdict; // just get access to array
if( SV_IsValidEdict( pEdict ) && pEdict->pvPrivateData )
return pEdict;
// g-cont: clients can be acessed even without private data!
// g-cont: world and clients can be acessed even without private data!
if( SV_IsValidEdict( pEdict ) && SV_IsPlayerIndex( iEntIndex ))
return pEdict;
}

View File

@ -195,16 +195,17 @@ int SV_GenericIndex( const char *filename )
return 0;
}
if( sv.state != ss_loading )
{
// g-cont. can we downloading resources in-game ? need testing
Host_Error( "SV_PrecacheGeneric: ( %s ). Precache can only be done in spawn functions.", name );
return 0;
}
// register new generic resource
Q_strncpy( sv.files_precache[i], name, sizeof( sv.files_precache[i] ));
if( sv.state != ss_loading )
{
// send the update to everyone
MSG_BeginServerCmd( &sv.reliable_datagram, svc_fileindex );
MSG_WriteUBitLong( &sv.reliable_datagram, i, MAX_CUSTOM_BITS );
MSG_WriteString( &sv.reliable_datagram, name );
}
return i;
}
@ -542,8 +543,8 @@ void SV_ActivateServer( int runPhysics )
if( sv.ignored_static_ents )
Con_Printf( S_WARN "%i static entities was rejected due buffer overflow\n", sv.ignored_static_ents );
if( sv.ignored_studio_decals || sv.ignored_world_decals )
Con_Printf( S_WARN "%i static decals was rejected due buffer overflow\n", sv.ignored_studio_decals + sv.ignored_world_decals );
if( sv.ignored_world_decals )
Con_Printf( S_WARN "%i static decals was rejected due buffer overflow\n", sv.ignored_world_decals );
if( svs.maxclients > 1 )
{

View File

@ -447,15 +447,14 @@ void ReapplyDecal( SAVERESTOREDATA *pSaveData, decallist_t *entry, qboolean adja
if( SV_RestoreCustomDecal( entry, pEdict, adjacent ))
return; // decal was sucessfully restored at the game-side
// studio decals are handled at game-side
if( FBitSet( flags, FDECAL_STUDIO ))
return;
// NOTE: at this point all decal indexes is valid
decalIndex = pfnDecalIndex( entry->name );
if( FBitSet( flags, FDECAL_STUDIO ))
{
// NOTE: studio decal trace start saved into impactPlaneNormal
SV_CreateStudioDecal( &sv.signon, entry->position, entry->impactPlaneNormal, decalIndex, entityIndex, modelIndex, flags, &entry->studio_state );
}
else if( adjacent && entityIndex != 0 && !SV_IsValidEdict( pEdict ))
if( adjacent && entityIndex != 0 && !SV_IsValidEdict( pEdict ))
{
vec3_t testspot, testend;
trace_t tr;