Dedicated build

This commit is contained in:
Alibek Omarov 2018-04-18 18:32:30 +03:00
parent 40094f2867
commit 5d13112e25
26 changed files with 1064 additions and 324 deletions

View File

@ -2769,7 +2769,7 @@ void CL_Init( void )
IN_TouchInit();
COM_ResetLibraryError();
if( !CL_LoadProgs( va( "%s/%s", GI->dll_path, GI->client_lib)))
if( !CL_LoadProgs( va( "%s/%s", GI->dll_path, SI.clientlib)))
Host_Error( "can't initialize client.dll\n" );
cls.initialized = true;

View File

@ -1238,72 +1238,6 @@ void Con_Print( const char *txt )
}
}
/*
=============
Con_Printf
=============
*/
void Con_Printf( char *szFmt, ... )
{
static char buffer[MAX_PRINT_MSG];
va_list args;
if( !host.allow_console )
return;
va_start( args, szFmt );
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
va_end( args );
Sys_Print( buffer );
}
/*
=============
Con_DPrintf
=============
*/
void Con_DPrintf( char *szFmt, ... )
{
static char buffer[MAX_PRINT_MSG];
va_list args;
if( host_developer.value < DEV_NORMAL )
return;
va_start( args, szFmt );
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
va_end( args );
if( buffer[0] == '0' && buffer[1] == '\n' && buffer[2] == '\0' )
return; // hlrally spam
Sys_Print( buffer );
}
/*
=============
Con_Reportf
=============
*/
void Con_Reportf( char *szFmt, ... )
{
static char buffer[MAX_PRINT_MSG];
va_list args;
if( host_developer.value < DEV_EXTENDED )
return;
va_start( args, szFmt );
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
va_end( args );
Sys_Print( buffer );
}
/*
================
Con_NPrint

View File

@ -718,56 +718,6 @@ float CL_GetSequenceDuration( cl_entity_t *ent, int sequence )
return 0.1f;
}
/*
====================
StudioGetAnim
====================
*/
void *R_StudioGetAnim( studiohdr_t *m_pStudioHeader, model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc )
{
mstudioseqgroup_t *pseqgroup;
cache_user_t *paSequences;
size_t filesize;
byte *buf;
pseqgroup = (mstudioseqgroup_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqgroupindex) + pseqdesc->seqgroup;
if( pseqdesc->seqgroup == 0 )
return ((byte *)m_pStudioHeader + pseqgroup->data + pseqdesc->animindex);
paSequences = (cache_user_t *)m_pSubModel->submodels;
if( paSequences == NULL )
{
paSequences = (cache_user_t *)Mem_Alloc( com_studiocache, MAXSTUDIOGROUPS * sizeof( cache_user_t ));
m_pSubModel->submodels = (void *)paSequences;
}
// check for already loaded
if( !Mod_CacheCheck(( cache_user_t *)&( paSequences[pseqdesc->seqgroup] )))
{
string filepath, modelname, modelpath;
COM_FileBase( m_pSubModel->name, modelname );
COM_ExtractFilePath( m_pSubModel->name, modelpath );
// NOTE: here we build real sub-animation filename because stupid user may rename model without recompile
Q_snprintf( filepath, sizeof( filepath ), "%s/%s%i%i.mdl", modelpath, modelname, pseqdesc->seqgroup / 10, pseqdesc->seqgroup % 10 );
buf = FS_LoadFile( filepath, &filesize, false );
if( !buf || !filesize ) Host_Error( "StudioGetAnim: can't load %s\n", filepath );
if( IDSEQGRPHEADER != *(uint *)buf ) Host_Error( "StudioGetAnim: %s is corrupted\n", filepath );
Con_Printf( "loading: %s\n", filepath );
paSequences[pseqdesc->seqgroup].data = Mem_Alloc( com_studiocache, filesize );
memcpy( paSequences[pseqdesc->seqgroup].data, buf, filesize );
Mem_Free( buf );
}
return ((byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex);
}
/*
====================
StudioFxTransform
@ -877,197 +827,6 @@ void R_StudioCalcBoneAdj( float dadt, float *adj, const byte *pcontroller1, cons
}
}
/*
====================
StudioCalcBoneQuaternion
====================
*/
void R_StudioCalcBoneQuaternion( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, vec4_t q )
{
vec3_t angles1;
vec3_t angles2;
int j, k;
for( j = 0; j < 3; j++ )
{
if( !panim || panim->offset[j+3] == 0 )
{
angles2[j] = angles1[j] = pbone->value[j+3]; // default;
}
else
{
mstudioanimvalue_t *panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j+3]);
k = frame;
// debug
if( panimvalue->num.total < panimvalue->num.valid )
k = 0;
// find span of values that includes the frame we want
while( panimvalue->num.total <= k )
{
k -= panimvalue->num.total;
panimvalue += panimvalue->num.valid + 1;
// debug
if( panimvalue->num.total < panimvalue->num.valid )
k = 0;
}
// bah, missing blend!
if( panimvalue->num.valid > k )
{
angles1[j] = panimvalue[k+1].value;
if( panimvalue->num.valid > k + 1 )
{
angles2[j] = panimvalue[k+2].value;
}
else
{
if( panimvalue->num.total > k + 1 )
angles2[j] = angles1[j];
else angles2[j] = panimvalue[panimvalue->num.valid+2].value;
}
}
else
{
angles1[j] = panimvalue[panimvalue->num.valid].value;
if( panimvalue->num.total > k + 1 )
angles2[j] = angles1[j];
else angles2[j] = panimvalue[panimvalue->num.valid+2].value;
}
angles1[j] = pbone->value[j+3] + angles1[j] * pbone->scale[j+3];
angles2[j] = pbone->value[j+3] + angles2[j] * pbone->scale[j+3];
}
if( pbone->bonecontroller[j+3] != -1 && adj != NULL )
{
angles1[j] += adj[pbone->bonecontroller[j+3]];
angles2[j] += adj[pbone->bonecontroller[j+3]];
}
}
if( !VectorCompare( angles1, angles2 ))
{
vec4_t q1, q2;
AngleQuaternion( angles1, q1, true );
AngleQuaternion( angles2, q2, true );
QuaternionSlerp( q1, q2, s, q );
}
else
{
AngleQuaternion( angles1, q, true );
}
}
/*
====================
StudioCalcBonePosition
====================
*/
void R_StudioCalcBonePosition( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, vec3_t pos )
{
vec3_t origin1;
vec3_t origin2;
int j, k;
for( j = 0; j < 3; j++ )
{
if( !panim || panim->offset[j] == 0 )
{
origin2[j] = origin1[j] = pbone->value[j]; // default;
}
else
{
mstudioanimvalue_t *panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j]);
k = frame;
// debug
if( panimvalue->num.total < panimvalue->num.valid )
k = 0;
// find span of values that includes the frame we want
while( panimvalue->num.total <= k )
{
k -= panimvalue->num.total;
panimvalue += panimvalue->num.valid + 1;
// debug
if( panimvalue->num.total < panimvalue->num.valid )
k = 0;
}
// bah, missing blend!
if( panimvalue->num.valid > k )
{
origin1[j] = panimvalue[k+1].value;
if( panimvalue->num.valid > k + 1 )
{
origin2[j] = panimvalue[k+2].value;
}
else
{
if( panimvalue->num.total > k + 1 )
origin2[j] = origin1[j];
else origin2[j] = panimvalue[panimvalue->num.valid+2].value;
}
}
else
{
origin1[j] = panimvalue[panimvalue->num.valid].value;
if( panimvalue->num.total > k + 1 )
origin2[j] = origin1[j];
else origin2[j] = panimvalue[panimvalue->num.valid+2].value;
}
origin1[j] = pbone->value[j] + origin1[j] * pbone->scale[j];
origin2[j] = pbone->value[j] + origin2[j] * pbone->scale[j];
}
if( pbone->bonecontroller[j] != -1 && adj != NULL )
{
origin1[j] += adj[pbone->bonecontroller[j]];
origin2[j] += adj[pbone->bonecontroller[j]];
}
}
if( !VectorCompare( origin1, origin2 ))
{
VectorLerp( origin1, s, origin2, pos );
}
else
{
VectorCopy( origin1, pos );
}
}
/*
====================
StudioSlerpBones
====================
*/
void R_StudioSlerpBones( int numbones, vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s )
{
int i;
s = bound( 0.0f, s, 1.0f );
for( i = 0; i < numbones; i++ )
{
QuaternionSlerp( q1[i], q2[i], s, q1[i] );
VectorLerp( pos1[i], s, pos2[i], pos1[i] );
}
}
/*
====================
StudioCalcRotations

View File

@ -977,13 +977,16 @@ void Cmd_ExecuteString( char *text )
if( host.apply_game_config )
return; // don't send nothing to server: we is a server!
#ifndef XASH_DEDICATED
// forward the command line to the server, so the entity DLL can parse it
if( host.type == HOST_NORMAL )
{
if( cls.state >= ca_connected )
Cmd_ForwardToServer();
}
else if( text[0] != '@' && host.type == HOST_NORMAL )
else
#endif
if( text[0] != '@' && host.type == HOST_NORMAL )
{
// commands with leading '@' are hidden system commands
Con_Printf( S_WARN "Unknown command \"%s\"\n", text );
@ -999,6 +1002,7 @@ things like godmode, noclip, etc, are commands directed to the server,
so when they are typed in at the console, they will need to be forwarded.
===================
*/
#ifndef XASH_DEDICATED
void Cmd_ForwardToServer( void )
{
char str[MAX_CMD_BUFFER];
@ -1032,6 +1036,7 @@ void Cmd_ForwardToServer( void )
MSG_WriteString( &cls.netchan.message, str );
}
#endif // XASH_DEDICATED
/*
============
@ -1141,7 +1146,9 @@ void Cmd_Init( void )
Cmd_AddCommand( "wait", Cmd_Wait_f, "make script execution wait for some rendered frames" );
Cmd_AddCommand( "cmdlist", Cmd_List_f, "display all console commands beginning with the specified prefix" );
Cmd_AddCommand( "stuffcmds", Cmd_StuffCmds_f, "execute commandline parameters (must be present in .rc script)" );
#ifndef XASH_DEDICATED
Cmd_AddCommand( "cmd", Cmd_ForwardToServer, "send a console commandline to the server" );
#endif
Cmd_AddCommand( "alias", Cmd_Alias_f, "create a script function. Without arguments show the list of all alias" );
Cmd_AddCommand( "unalias", Cmd_UnAlias_f, "remove a script function" );
Cmd_AddCommand( "if", Cmd_If_f, "compare and set condition bits" );

View File

@ -301,6 +301,8 @@ typedef struct sysinfo_s
string exeName; // exe.filename
string rcName; // .rc script name
string basedirName; // name of base directory
string gamedll;
string clientlib;
gameinfo_t *GameInfo; // current GameInfo
gameinfo_t *games[MAX_MODS]; // environment games (founded at each engine start)
int numgames;

View File

@ -464,6 +464,7 @@ qboolean Cmd_GetSoundList( const char *s, char *completedname, int length )
return true;
}
#ifndef XASH_DEDICATED
/*
=====================================
Cmd_GetItemsList
@ -510,6 +511,7 @@ qboolean Cmd_GetItemsList( const char *s, char *completedname, int length )
}
return true;
}
#endif
/*
=====================================
@ -817,8 +819,10 @@ autocomplete_list_t cmd_list[] =
{ "music", Cmd_GetMusicList, },
{ "movie", Cmd_GetMovieList },
{ "exec", Cmd_GetConfigList },
#ifndef XASH_DEDICATED
{ "give", Cmd_GetItemsList },
{ "drop", Cmd_GetItemsList },
#endif
{ "game", Cmd_GetGamesList },
{ "save", Cmd_GetSavesList },
{ "load", Cmd_GetSavesList },
@ -901,6 +905,7 @@ void Cmd_WriteOpenGLVariables( file_t *f )
Cvar_LookupVars( FCVAR_GLCONFIG, NULL, f, Cmd_WriteOpenGLCvar );
}
#ifndef XASH_DEDICATED
/*
===============
Host_WriteConfig
@ -946,6 +951,7 @@ void Host_WriteConfig( void )
}
else MsgDev( D_ERROR, "Couldn't write config.cfg.\n" );
}
#endif
/*
===============

View File

@ -44,11 +44,13 @@ void COM_ClearCustomizationList( customization_t *pHead, qboolean bCleanDecals )
if( pCurrent->bInUse && pCurrent->pInfo )
{
#ifndef XASH_DEDICATED
if( pCurrent->resource.type == t_decal )
{
if( bCleanDecals && CL_Active( ))
R_DecalRemoveAll( pCurrent->nUserData1 );
}
#endif
FS_FreeImage( pCurrent->pInfo );
}

View File

@ -90,12 +90,13 @@ static qboolean Cvar_UpdateInfo( convar_t *var, const char *value, qboolean noti
{
if( FBitSet( var->flags, FCVAR_USERINFO ))
{
if ( host.type == HOST_DEDICATED )
if ( Host_IsDedicated() )
{
// g-cont. this is a very strange behavior...
Info_SetValueForKey( SV_Serverinfo(), var->name, value, MAX_SERVERINFO_STRING ),
SV_BroadcastCommand( "fullserverinfo \"%s\"\n", SV_Serverinfo( ));
}
#ifndef XASH_DEDICATED
else
{
if( !Info_SetValueForKey( CL_Userinfo(), var->name, value, MAX_INFO_STRING ))
@ -104,6 +105,7 @@ static qboolean Cvar_UpdateInfo( convar_t *var, const char *value, qboolean noti
// time to update server copy of userinfo
CL_ServerCommand( true, "setinfo \"%s\" \"%s\"\n", var->name, value );
}
#endif
}
if( FBitSet( var->flags, FCVAR_SERVER ) && notify )

497
engine/common/dedicated.c Normal file
View File

@ -0,0 +1,497 @@
/*
dedicated.c - stubs for dedicated server
Copyright (C) 2018 a1batross, mittorn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifdef XASH_DEDICATED
#include "common.h"
#include "mathlib.h"
const char *svc_strings[256] =
{
"svc_bad",
"svc_nop",
"svc_disconnect",
"svc_changing",
"svc_version",
"svc_setview",
"svc_sound",
"svc_time",
"svc_print",
"svc_stufftext",
"svc_setangle",
"svc_serverdata",
"svc_lightstyle",
"svc_updateuserinfo",
"svc_deltatable",
"svc_clientdata",
"svc_stopsound",
"svc_updatepings",
"svc_particle",
"svc_restoresound",
"svc_spawnstatic",
"svc_event_reliable",
"svc_spawnbaseline",
"svc_temp_entity",
"svc_setpause",
"svc_signonnum",
"svc_centerprint",
"svc_event",
"svc_soundindex",
"svc_ambientsound",
"svc_intermission",
"svc_modelindex",
"svc_cdtrack",
"svc_serverinfo",
"svc_eventindex",
"svc_weaponanim",
"svc_bspdecal",
"svc_roomtype",
"svc_addangle",
"svc_usermessage",
"svc_packetentities",
"svc_deltapacketentities",
"svc_chokecount",
"svc_resourcelist",
"svc_deltamovevars",
"svc_customization",
"svc_unused46",
"svc_crosshairangle",
"svc_soundfade",
"svc_unused49",
"svc_unused50",
"svc_director",
"svc_studiodecal",
"svc_unused53",
"svc_unused54",
"svc_unused55",
"svc_unused56",
"svc_querycvarvalue",
"svc_querycvarvalue2",
"svc_unused59",
"svc_unused60",
"svc_unused61",
"svc_unused62",
"svc_unused63",
};
qboolean CL_Active( void )
{
return false;
}
qboolean CL_Initialized( void )
{
return false;
}
qboolean CL_IsInGame( void )
{
return true; // always active for dedicated servers
}
qboolean CL_IsInMenu( void )
{
return false;
}
qboolean CL_IsInConsole( void )
{
return false;
}
qboolean CL_IsIntermission( void )
{
return false;
}
qboolean CL_IsPlaybackDemo( void )
{
return false;
}
qboolean CL_IsRecordDemo( void )
{
return false;
}
qboolean CL_DisableVisibility( void )
{
return false;
}
qboolean CL_IsBackgroundDemo( void )
{
return false;
}
qboolean CL_IsBackgroundMap( void )
{
return false;
}
void CL_Init()
{
}
void Key_Init()
{
}
void IN_Init()
{
}
void CL_Drop()
{
}
void CL_ClearEdicts()
{
}
void Key_SetKeyDest(int key_dest)
{
}
void UI_SetActiveMenu( qboolean fActive )
{
}
void CL_WriteMessageHistory()
{
}
void Host_ClientBegin()
{
}
void Host_ClientFrame()
{
}
void Host_InputFrame()
{
Cbuf_Execute();
}
void VID_InitDefaultResolution()
{
}
void Con_Init()
{
}
void R_ClearAllDecals()
{
}
int R_CreateDecalList( struct decallist_s *pList )
{
return 0;
}
void S_StopSound(int entnum, int channel, const char *soundname)
{
}
int S_GetCurrentStaticSounds( soundlist_t *pout, int size )
{
return 0;
}
int CL_GetMaxClients()
{
return 0;
}
void IN_TouchInitConfig()
{
}
void CL_Disconnect()
{
}
void CL_Shutdown()
{
}
void R_ClearStaticEntities()
{
}
void Host_Credits()
{
}
qboolean UI_CreditsActive()
{
return false;
}
void GL_FreeImage( const char *name )
{
}
void S_StopBackgroundTrack()
{
}
void SCR_BeginLoadingPlaque( qboolean is_background )
{
}
int S_GetCurrentDynamicSounds( soundlist_t *pout, int size )
{
return 0;
}
void S_StopAllSounds( qboolean ambient )
{
}
void Con_NPrintf( int idx, char *fmt, ... )
{
}
void Con_NXPrintf( struct con_nprint_s *info, char *fmt, ... )
{
}
const byte *GL_TextureData( unsigned int texnum )
{
return NULL;
}
void SCR_CheckStartupVids()
{
}
imgfilter_t *R_FindTexFilter( const char *texname )
{
return NULL;
}
#include "sprite.h"
/*
====================
Mod_LoadSpriteModel
load sprite model
====================
*/
void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, uint texFlags )
{
dsprite_q1_t *pinq1;
dsprite_hl_t *pinhl;
dsprite_t *pin;
short *numi = NULL;
dframetype_t *pframetype;
msprite_t *psprite;
int i, size;
if( loaded ) *loaded = false;
pin = (dsprite_t *)buffer;
mod->type = mod_sprite;
i = pin->version;
if( pin->ident != IDSPRITEHEADER )
{
MsgDev( D_ERROR, "%s has wrong id (%x should be %x)\n", mod->name, pin->ident, IDSPRITEHEADER );
return;
}
if( i != SPRITE_VERSION_Q1 && i != SPRITE_VERSION_HL && i != SPRITE_VERSION_32 )
{
MsgDev( D_ERROR, "%s has wrong version number (%i should be %i or %i)\n", mod->name, i, SPRITE_VERSION_Q1, SPRITE_VERSION_HL );
return;
}
mod->mempool = Mem_AllocPool( va( "^2%s^7", mod->name ));
if( i == SPRITE_VERSION_Q1 || i == SPRITE_VERSION_32 )
{
pinq1 = (dsprite_q1_t *)buffer;
size = sizeof( msprite_t ) + ( pinq1->numframes - 1 ) * sizeof( psprite->frames );
psprite = Mem_Alloc( mod->mempool, size );
mod->cache.data = psprite; // make link to extradata
psprite->type = pinq1->type;
psprite->texFormat = SPR_ADDITIVE; //SPR_ALPHTEST;
psprite->numframes = mod->numframes = pinq1->numframes;
psprite->facecull = SPR_CULL_FRONT;
psprite->radius = pinq1->boundingradius;
psprite->synctype = pinq1->synctype;
mod->mins[0] = mod->mins[1] = -pinq1->bounds[0] * 0.5f;
mod->maxs[0] = mod->maxs[1] = pinq1->bounds[0] * 0.5f;
mod->mins[2] = -pinq1->bounds[1] * 0.5f;
mod->maxs[2] = pinq1->bounds[1] * 0.5f;
numi = NULL;
}
else if( i == SPRITE_VERSION_HL )
{
pinhl = (dsprite_hl_t *)buffer;
size = sizeof( msprite_t ) + ( pinhl->numframes - 1 ) * sizeof( psprite->frames );
psprite = Mem_Alloc( mod->mempool, size );
mod->cache.data = psprite; // make link to extradata
psprite->type = pinhl->type;
psprite->texFormat = pinhl->texFormat;
psprite->numframes = mod->numframes = pinhl->numframes;
psprite->facecull = pinhl->facetype;
psprite->radius = pinhl->boundingradius;
psprite->synctype = pinhl->synctype;
mod->mins[0] = mod->mins[1] = -pinhl->bounds[0] * 0.5f;
mod->maxs[0] = mod->maxs[1] = pinhl->bounds[0] * 0.5f;
mod->mins[2] = -pinhl->bounds[1] * 0.5f;
mod->maxs[2] = pinhl->bounds[1] * 0.5f;
numi = (short *)(pinhl + 1);
}
if( host.type == HOST_DEDICATED )
{
// skip frames loading
if( loaded ) *loaded = true; // done
psprite->numframes = 0;
return;
}
if( numi == NULL )
{
rgbdata_t *pal;
pal = FS_LoadImage( "#id.pal", (byte *)&i, 768 );
pframetype = (dframetype_t *)(pinq1 + 1);
FS_FreeImage( pal ); // palette installed, no reason to keep this data
}
else if( *numi == 256 )
{
byte *src = (byte *)(numi+1);
rgbdata_t *pal;
// install palette
switch( psprite->texFormat )
{
case SPR_INDEXALPHA:
pal = FS_LoadImage( "#gradient.pal", src, 768 );
break;
case SPR_ALPHTEST:
pal = FS_LoadImage( "#masked.pal", src, 768 );
break;
default:
pal = FS_LoadImage( "#normal.pal", src, 768 );
break;
}
pframetype = (dframetype_t *)(src + 768);
FS_FreeImage( pal ); // palette installed, no reason to keep this data
}
else
{
MsgDev( D_ERROR, "%s has wrong number of palette colors %i (should be 256)\n", mod->name, *numi );
return;
}
if( mod->numframes < 1 )
{
MsgDev( D_ERROR, "%s has invalid # of frames: %d\n", mod->name, mod->numframes );
return;
}
if( loaded ) *loaded = true; // done
}
/*
====================
Mod_UnloadSpriteModel
release sprite model and frames
====================
*/
void Mod_UnloadSpriteModel( model_t *mod )
{
msprite_t *psprite;
mspritegroup_t *pspritegroup;
mspriteframe_t *pspriteframe;
int i, j;
Assert( mod != NULL );
#ifndef XASH_DEDICATED
if( mod->type == mod_sprite )
{
if( host.type != HOST_DEDICATED )
{
psprite = mod->cache.data;
if( psprite )
{
// 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 );
}
}
}
}
}
}
#endif
Mem_FreePool( &mod->mempool );
memset( mod, 0, sizeof( *mod ));
}
#endif // XASH_DEDICATED

View File

@ -1386,6 +1386,27 @@ void FS_LoadGameInfo( const char *rootfolder )
Sys_Error( "Couldn't find game directory '%s'\n", fs_gamedir );
SI.GameInfo = SI.games[i];
if( !Sys_GetParmFromCmdLine( "-dll", SI.gamedll ) )
{
#ifdef XASH_INTERNAL_GAMELIBS
Q_strncpy( SI.gamedll, "server", sizeof( SI.gamedll ) );
#elif defined(_WIN32)
Q_strncpy( SI.gamedll, GI->game_dll, sizeof( SI.gamedll ) );
#elif defined(__APPLE__)
Q_strncpy( SI.gamedll, GI->game_dll_osx, sizeof( SI.gamedll ) );
#else
Q_strncpy( SI.gamedll, GI->game_dll_linux, sizeof( SI.gamedll ) );
#endif
}
if( !Sys_GetParmFromCmdLine( "-clientlib", SI.clientlib ) )
{
#ifdef __ANDROID__
Q_strncpy( SI.clientlib, CLIENTDLL, sizeof( SI.clientlib ) );
#else
Q_strncpy( SI.clientlib, GI->client_lib, sizeof( SI.clientlib ) );
#endif
}
FS_Rescan(); // create new filesystem
Host_InitDecals (); // reload decals

View File

@ -116,11 +116,13 @@ void Host_EndGame( qboolean abort, const char *message, ... )
MsgDev( D_INFO, "Host_EndGame: %s\n", string );
SV_Shutdown( "\n" );
#ifndef XASH_DEDICATED
CL_Disconnect();
// recreate world if needs
CL_ClearEdicts ();
#endif
// release all models
Mod_FreeAll();
@ -412,17 +414,20 @@ double Host_CalcFPS( void )
double fps = 0.0;
// NOTE: we should play demos with same fps as it was recorded
#ifndef XASH_DEDICATED
if( CL_IsPlaybackDemo() || CL_IsRecordDemo( ))
fps = CL_GetDemoFramerate();
else if( Host_IsLocalGame( ))
else
#endif
if( Host_IsLocalGame( ))
fps = host_maxfps->value;
else
{
fps = host_maxfps->value;
if( fps == 0.0 ) fps = HOST_FPS; // default for multiplayer
fps = bound( MIN_FPS, fps, MAX_FPS );
}
#ifndef XASH_DEDICATED
// probably left part of this condition is redundant :-)
if( host.type != HOST_DEDICATED && Host_IsLocalGame( ) && !CL_IsTimeDemo( ))
{
@ -434,6 +439,7 @@ double Host_CalcFPS( void )
else fps = 60.0; // default
}
}
#endif
return fps;
}
@ -962,8 +968,10 @@ void EXPORT Host_Shutdown( void )
if( host.status != HOST_ERR_FATAL ) host.status = HOST_SHUTDOWN; // prepare host to normal shutdown
if( !host.change_game ) Q_strncpy( host.finalmsg, "Server shutdown", sizeof( host.finalmsg ));
#ifndef XASH_DEDICATED
if( host.type == HOST_NORMAL )
Host_WriteConfig();
#endif
SV_Shutdown( "" );
CL_Shutdown();

View File

@ -130,6 +130,7 @@ qboolean Info_IsValid( const char *s )
return true;
}
#ifndef XASH_DEDICATED
/*
==============
Info_WriteVars
@ -177,6 +178,7 @@ void Info_WriteVars( file_t *f )
s++;
}
}
#endif // XASH_DEDICATED
/*
===============

109
engine/common/launcher.c Normal file
View File

@ -0,0 +1,109 @@
/*
launcher.c - direct xash3d launcher
Copyright (C) 2015 Mittorn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifdef SINGLE_BINARY
#include <stdlib.h>
#include <string.h>
#ifdef XASH_SDLMAIN
#include "SDL.h"
#endif
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
typedef void (*pfnChangeGame)( const char *progname );
char szGameDir[128]; // safe place to keep gamedir
int g_iArgc;
void Host_Shutdown( void );
void Launcher_ChangeGame( const char *progname );
void *Com_LoadLibrary( char *, int );
int Host_Main( int szArgc, char **szArgv, const char *szGameDir, int chg, pfnChangeGame callback );
char **g_pszArgv;
void Launcher_ChangeGame( const char *progname )
{
strncpy( szGameDir, progname, sizeof( szGameDir ) - 1 );
Host_Shutdown( );
exit( Host_Main( g_iArgc, g_pszArgv, szGameDir, 1, &Launcher_ChangeGame ) );
}
#ifdef XASH_NOCONHOST
#include <windows.h>
int __stdcall WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdLine, int nShow)
{
int szArgc;
char **szArgv;
LPWSTR* lpArgv = CommandLineToArgvW(GetCommandLineW(), &szArgc);
int size, i = 0;
szArgv = (char**)malloc(szArgc*sizeof(char*));
for (; i < szArgc; ++i)
{
size = wcslen(lpArgv[i]) + 1;
szArgv[i] = (char*)malloc(size);
wcstombs(szArgv[i], lpArgv[i], size);
}
LocalFree(lpArgv);
main( szArgc, szArgv );
}
#endif
int main( int argc, char** argv )
{
char gamedir_buf[32] = "";
const char *gamedir = getenv("XASH3D_GAMEDIR");
if( !gamedir )
{
gamedir = "valve";
}
else
{
strncpy( gamedir_buf, gamedir, 32 );
gamedir = gamedir_buf;
}
#ifdef __EMSCRIPTEN__
#ifdef EMSCRIPTEN_LIB_FS
// For some unknown reason emscripten refusing to load libraries later
Com_LoadLibrary("menu", 0 );
Com_LoadLibrary("server", 0 );
Com_LoadLibrary("client", 0 );
#endif
#ifdef XASH_DEDICATED
// NodeJS support for debug
EM_ASM(try{
FS.mkdir('/xash');
FS.mount(NODEFS, { root: '.'}, '/xash' );
FS.chdir('/xash');
}catch(e){};);
#endif
#endif
g_iArgc = argc;
g_pszArgv = argv;
#if TARGET_OS_IPHONE
{
void IOS_LaunchDialog( void );
IOS_LaunchDialog();
}
#endif
return Host_Main( g_iArgc, g_pszArgv, gamedir, 0, &Launcher_ChangeGame );
}
#endif

View File

@ -1778,11 +1778,13 @@ static void Mod_LoadTextures( dbspmodel_t *bmod )
if( bmod->isworld )
{
#ifndef XASH_DEDICATED
// release old sky layers first
GL_FreeTexture( tr.solidskyTexture );
GL_FreeTexture( tr.alphaskyTexture );
tr.solidskyTexture = 0;
tr.alphaskyTexture = 0;
#endif
}
if( !bmod->texdatasize )
@ -1805,8 +1807,10 @@ static void Mod_LoadTextures( dbspmodel_t *bmod )
loadmodel->textures[i] = tx;
Q_strncpy( tx->name, "*default", sizeof( tx->name ));
#ifndef XASH_DEDICATED
tx->gl_texturenum = tr.defaultTexture;
tx->width = tx->height = 16;
#endif
continue; // missed
}
@ -1851,6 +1855,7 @@ static void Mod_LoadTextures( dbspmodel_t *bmod )
if( remaining >= 770 ) custom_palette = true;
}
#ifndef XASH_DEDICATED
// check for multi-layered sky texture (quake1 specific)
if( bmod->isworld && !Q_strncmp( mt->name, "sky", 3 ) && (( mt->width / mt->height ) == 2 ))
{
@ -1943,6 +1948,7 @@ static void Mod_LoadTextures( dbspmodel_t *bmod )
if( src ) Mem_Free( src );
}
}
#endif
}
// sequence the animations and detail textures
@ -2224,8 +2230,10 @@ static void Mod_LoadSurfaces( dbspmodel_t *bmod )
next_lightofs = 99999999;
}
#ifndef XASH_DEDICATED // TODO: Do we need subdivide on server?
if( FBitSet( out->flags, SURF_DRAWTURB ))
GL_SubdivideSurface( out ); // cut up polygon for warps
#endif
}
// now we have enough data to trying determine samplecount per lightmap pixel
@ -2794,6 +2802,7 @@ void Mod_UnloadBrushModel( model_t *mod )
if( mod->name[0] != '*' )
{
#ifndef XASH_DEDICATED
for( i = 0; i < mod->numtextures; i++ )
{
tx = mod->textures[i];
@ -2803,6 +2812,7 @@ void Mod_UnloadBrushModel( model_t *mod )
GL_FreeTexture( tx->gl_texturenum ); // main texture
GL_FreeTexture( tx->fb_texturenum ); // luma texture
}
#endif
Mem_FreePool( &mod->mempool );
}

View File

@ -396,6 +396,247 @@ static void Mod_StudioCalcRotations( int boneused[], int numbones, const byte *p
if( pseqdesc->motiontype & STUDIO_Z ) pos[pseqdesc->motionbone][2] = 0.0f;
}
/*
====================
StudioCalcBoneQuaternion
====================
*/
void R_StudioCalcBoneQuaternion( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, vec4_t q )
{
vec3_t angles1;
vec3_t angles2;
int j, k;
for( j = 0; j < 3; j++ )
{
if( !panim || panim->offset[j+3] == 0 )
{
angles2[j] = angles1[j] = pbone->value[j+3]; // default;
}
else
{
mstudioanimvalue_t *panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j+3]);
k = frame;
// debug
if( panimvalue->num.total < panimvalue->num.valid )
k = 0;
// find span of values that includes the frame we want
while( panimvalue->num.total <= k )
{
k -= panimvalue->num.total;
panimvalue += panimvalue->num.valid + 1;
// debug
if( panimvalue->num.total < panimvalue->num.valid )
k = 0;
}
// bah, missing blend!
if( panimvalue->num.valid > k )
{
angles1[j] = panimvalue[k+1].value;
if( panimvalue->num.valid > k + 1 )
{
angles2[j] = panimvalue[k+2].value;
}
else
{
if( panimvalue->num.total > k + 1 )
angles2[j] = angles1[j];
else angles2[j] = panimvalue[panimvalue->num.valid+2].value;
}
}
else
{
angles1[j] = panimvalue[panimvalue->num.valid].value;
if( panimvalue->num.total > k + 1 )
angles2[j] = angles1[j];
else angles2[j] = panimvalue[panimvalue->num.valid+2].value;
}
angles1[j] = pbone->value[j+3] + angles1[j] * pbone->scale[j+3];
angles2[j] = pbone->value[j+3] + angles2[j] * pbone->scale[j+3];
}
if( pbone->bonecontroller[j+3] != -1 && adj != NULL )
{
angles1[j] += adj[pbone->bonecontroller[j+3]];
angles2[j] += adj[pbone->bonecontroller[j+3]];
}
}
if( !VectorCompare( angles1, angles2 ))
{
vec4_t q1, q2;
AngleQuaternion( angles1, q1, true );
AngleQuaternion( angles2, q2, true );
QuaternionSlerp( q1, q2, s, q );
}
else
{
AngleQuaternion( angles1, q, true );
}
}
/*
====================
StudioCalcBonePosition
====================
*/
void R_StudioCalcBonePosition( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, vec3_t pos )
{
vec3_t origin1;
vec3_t origin2;
int j, k;
for( j = 0; j < 3; j++ )
{
if( !panim || panim->offset[j] == 0 )
{
origin2[j] = origin1[j] = pbone->value[j]; // default;
}
else
{
mstudioanimvalue_t *panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j]);
k = frame;
// debug
if( panimvalue->num.total < panimvalue->num.valid )
k = 0;
// find span of values that includes the frame we want
while( panimvalue->num.total <= k )
{
k -= panimvalue->num.total;
panimvalue += panimvalue->num.valid + 1;
// debug
if( panimvalue->num.total < panimvalue->num.valid )
k = 0;
}
// bah, missing blend!
if( panimvalue->num.valid > k )
{
origin1[j] = panimvalue[k+1].value;
if( panimvalue->num.valid > k + 1 )
{
origin2[j] = panimvalue[k+2].value;
}
else
{
if( panimvalue->num.total > k + 1 )
origin2[j] = origin1[j];
else origin2[j] = panimvalue[panimvalue->num.valid+2].value;
}
}
else
{
origin1[j] = panimvalue[panimvalue->num.valid].value;
if( panimvalue->num.total > k + 1 )
origin2[j] = origin1[j];
else origin2[j] = panimvalue[panimvalue->num.valid+2].value;
}
origin1[j] = pbone->value[j] + origin1[j] * pbone->scale[j];
origin2[j] = pbone->value[j] + origin2[j] * pbone->scale[j];
}
if( pbone->bonecontroller[j] != -1 && adj != NULL )
{
origin1[j] += adj[pbone->bonecontroller[j]];
origin2[j] += adj[pbone->bonecontroller[j]];
}
}
if( !VectorCompare( origin1, origin2 ))
{
VectorLerp( origin1, s, origin2, pos );
}
else
{
VectorCopy( origin1, pos );
}
}
/*
====================
StudioSlerpBones
====================
*/
void R_StudioSlerpBones( int numbones, vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s )
{
int i;
s = bound( 0.0f, s, 1.0f );
for( i = 0; i < numbones; i++ )
{
QuaternionSlerp( q1[i], q2[i], s, q1[i] );
VectorLerp( pos1[i], s, pos2[i], pos1[i] );
}
}
/*
====================
StudioGetAnim
====================
*/
void *R_StudioGetAnim( studiohdr_t *m_pStudioHeader, model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc )
{
mstudioseqgroup_t *pseqgroup;
cache_user_t *paSequences;
size_t filesize;
byte *buf;
pseqgroup = (mstudioseqgroup_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqgroupindex) + pseqdesc->seqgroup;
if( pseqdesc->seqgroup == 0 )
return ((byte *)m_pStudioHeader + pseqgroup->data + pseqdesc->animindex);
paSequences = (cache_user_t *)m_pSubModel->submodels;
if( paSequences == NULL )
{
paSequences = (cache_user_t *)Mem_Alloc( com_studiocache, MAXSTUDIOGROUPS * sizeof( cache_user_t ));
m_pSubModel->submodels = (void *)paSequences;
}
// check for already loaded
if( !Mod_CacheCheck(( cache_user_t *)&( paSequences[pseqdesc->seqgroup] )))
{
string filepath, modelname, modelpath;
COM_FileBase( m_pSubModel->name, modelname );
COM_ExtractFilePath( m_pSubModel->name, modelpath );
// NOTE: here we build real sub-animation filename because stupid user may rename model without recompile
Q_snprintf( filepath, sizeof( filepath ), "%s/%s%i%i.mdl", modelpath, modelname, pseqdesc->seqgroup / 10, pseqdesc->seqgroup % 10 );
buf = FS_LoadFile( filepath, &filesize, false );
if( !buf || !filesize ) Host_Error( "StudioGetAnim: can't load %s\n", filepath );
if( IDSEQGRPHEADER != *(uint *)buf ) Host_Error( "StudioGetAnim: %s is corrupted\n", filepath );
Con_Printf( "loading: %s\n", filepath );
paSequences[pseqdesc->seqgroup].data = Mem_Alloc( com_studiocache, filesize );
memcpy( paSequences[pseqdesc->seqgroup].data, buf, filesize );
Mem_Free( buf );
}
return ((byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex);
}
/*
====================
StudioSetupBones
@ -806,6 +1047,7 @@ void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded )
phdr = R_StudioLoadHeader( mod, buffer );
if( !phdr ) return; // bad model
#ifndef XASH_DEDICATED
if( phdr->numtextures == 0 )
{
studiohdr_t *thdr;
@ -821,8 +1063,8 @@ void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded )
MsgDev( D_WARN, "Mod_LoadStudioModel: %s missing textures file\n", mod->name );
if( buffer2 ) Mem_Free( buffer2 );
}
else
{
else
{
Mod_StudioLoadTextures( mod, thdr );
// give space for textures and skinrefs
@ -857,6 +1099,13 @@ void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded )
phdr = (studiohdr_t *)loadmodel->cache.data; // get the new pointer on studiohdr
phdr->length = phdr->texturedataindex; // update model size
}
#else
// just copy model into memory
loadmodel->cache.data = Mem_Alloc( loadmodel->mempool, phdr->length );
memcpy( loadmodel->cache.data, buffer, phdr->length );
phdr = loadmodel->cache.data;
#endif
// setup bounding box
if( !VectorCompare( vec3_origin, phdr->bbmin ))
@ -898,7 +1147,9 @@ void Mod_UnloadStudioModel( model_t *mod )
if( mod->type != mod_studio )
return; // not a studio
#ifndef XASH_DEDICATED
Mod_StudioUnloadTextures( mod->cache.data );
#endif
Mem_FreePool( &mod->mempool );
memset( mod, 0, sizeof( *mod ));
}

View File

@ -77,7 +77,7 @@ static void Mod_FreeUserData( model_t *mod )
if( !mod->name[0] || mod->name[0] == '*' )
return;
if( host.type == HOST_DEDICATED )
if( Host_IsDedicated() )
{
if( svgame.physFuncs.Mod_ProcessUserData != NULL )
{
@ -85,6 +85,7 @@ static void Mod_FreeUserData( model_t *mod )
svgame.physFuncs.Mod_ProcessUserData( mod, false, NULL );
}
}
#ifndef XASH_DEDICATED
else
{
if( clgame.drawFuncs.Mod_ProcessUserData != NULL )
@ -93,6 +94,7 @@ static void Mod_FreeUserData( model_t *mod )
clgame.drawFuncs.Mod_ProcessUserData( mod, false, NULL );
}
}
#endif
}
/*
@ -115,15 +117,17 @@ static void Mod_FreeModel( model_t *mod )
case mod_sprite:
Mod_UnloadSpriteModel( mod );
break;
#ifndef XASH_DEDICATED
case mod_alias:
Mod_UnloadAliasModel( mod );
break;
#endif
case mod_studio:
Mod_UnloadStudioModel( mod );
break;
case mod_brush:
Mod_UnloadBrushModel( mod );
break;
case mod_alias:
Mod_UnloadAliasModel( mod );
break;
}
memset( mod, 0, sizeof( *mod ));
@ -302,9 +306,12 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
case IDSPRITEHEADER:
Mod_LoadSpriteModel( mod, buf, &loaded, 0 );
break;
// TODO: Load alias models on dedicated too?
#ifndef XASH_DEDICATED
case IDALIASHEADER:
Mod_LoadAliasModel( mod, buf, &loaded );
break;
#endif
case Q1BSP_VERSION:
case HLBSP_VERSION:
case QBSP2_VERSION:
@ -332,7 +339,7 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
if( world.loading )
SetBits( mod->flags, MODEL_WORLD ); // mark worldmodel
if( host.type == HOST_DEDICATED )
if( Host_IsDedicated() )
{
if( svgame.physFuncs.Mod_ProcessUserData != NULL )
{
@ -340,6 +347,7 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
svgame.physFuncs.Mod_ProcessUserData( mod, true, buf );
}
}
#ifndef XASH_DEDICATED
else
{
if( clgame.drawFuncs.Mod_ProcessUserData != NULL )
@ -348,6 +356,7 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
clgame.drawFuncs.Mod_ProcessUserData( mod, true, buf );
}
}
#endif
}
p = &mod_crcinfo[mod - mod_known];

View File

@ -1180,6 +1180,7 @@ Netchan_UpdateProgress
*/
void Netchan_UpdateProgress( netchan_t *chan )
{
#ifndef XASH_DEDICATED
fragbuf_t *p;
int i, c = 0;
int total = 0;
@ -1256,6 +1257,7 @@ void Netchan_UpdateProgress( netchan_t *chan )
}
scr_download->value = bestpercent;
#endif // XASH_DEDICATED
}
/*

View File

@ -1798,6 +1798,7 @@ Can go from either a baseline or a previous packet_entity
*/
qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state_t *to, int number, qboolean player, float timebase )
{
#ifndef XASH_DEDICATED
delta_info_t *dt = NULL;
delta_t *pField;
int i, fRemoveType;
@ -1877,7 +1878,7 @@ qboolean MSG_ReadDeltaEntity( sizebuf_t *msg, entity_state_t *from, entity_state
{
Delta_ReadField( msg, pField, from, to, timebase );
}
#endif // XASH_DEDICATED
// message parsed
return true;
}

View File

@ -29,6 +29,7 @@ draw line from particles
*/
void PM_ParticleLine( const vec3_t start, const vec3_t end, int pcolor, float life, float zvel )
{
#ifndef XASH_DEDICATED
float len, curdist;
vec3_t diff, pos;
@ -43,6 +44,7 @@ void PM_ParticleLine( const vec3_t start, const vec3_t end, int pcolor, float li
CL_Particle( pos, pcolor, life, 0, zvel );
curdist += 2.0f;
}
#endif // XASH_DEDICATED
}
/*
@ -67,6 +69,7 @@ PM_DrawBBox
*/
void PM_DrawBBox( const vec3_t mins, const vec3_t maxs, const vec3_t origin, int pcolor, float life )
{
#ifndef XASH_DEDICATED
vec3_t p[8], tmp;
float gap = BOX_GAP;
int i;
@ -85,4 +88,5 @@ void PM_DrawBBox( const vec3_t mins, const vec3_t maxs, const vec3_t origin, int
{
PM_DrawRectangle( p[boxpnt[i][1]], p[boxpnt[i][0]], p[boxpnt[i][2]], p[boxpnt[i][3]], pcolor, life );
}
#endif // XASH_DEDICATED
}

View File

@ -461,7 +461,9 @@ pmtrace_t PM_PlayerTraceExt( playermove_t *pmove, vec3_t start, vec3_t end, int
// run custom sweep callback
if( pmove->server || Host_IsLocalClient( ))
SV_ClipPMoveToEntity( pe, start, mins, maxs, end, &trace_bbox );
#ifndef XASH_DEDICATED
else CL_ClipPMoveToEntity( pe, start, mins, maxs, end, &trace_bbox );
#endif
}
else if( hullcount == 1 )
{
@ -628,7 +630,9 @@ int PM_TestPlayerPosition( playermove_t *pmove, vec3_t pos, pmtrace_t *ptrace, p
// run custom sweep callback
if( pmove->server || Host_IsLocalClient( ))
SV_ClipPMoveToEntity( pe, pos, mins, maxs, pos, &trace );
#ifndef XASH_DEDICATED
else CL_ClipPMoveToEntity( pe, pos, mins, maxs, pos, &trace );
#endif
// if we inside the custom hull
if( trace.allsolid )

View File

@ -221,3 +221,76 @@ void Sys_PrintLog( const char *pMsg )
fprintf( s_ld.logfile, "%s %s", logtime, pMsg );
fflush( s_ld.logfile );
}
/*
=============================================================================
CONSOLE PRINT
=============================================================================
*/
/*
=============
Con_Printf
=============
*/
void Con_Printf( char *szFmt, ... )
{
static char buffer[MAX_PRINT_MSG];
va_list args;
if( !host.allow_console )
return;
va_start( args, szFmt );
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
va_end( args );
Sys_Print( buffer );
}
/*
=============
Con_DPrintf
=============
*/
void Con_DPrintf( char *szFmt, ... )
{
static char buffer[MAX_PRINT_MSG];
va_list args;
if( host_developer.value < DEV_NORMAL )
return;
va_start( args, szFmt );
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
va_end( args );
if( buffer[0] == '0' && buffer[1] == '\n' && buffer[2] == '\0' )
return; // hlrally spam
Sys_Print( buffer );
}
/*
=============
Con_Reportf
=============
*/
void Con_Reportf( char *szFmt, ... )
{
static char buffer[MAX_PRINT_MSG];
va_list args;
if( host_developer.value < DEV_EXTENDED )
return;
va_start( args, szFmt );
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
va_end( args );
Sys_Print( buffer );
}

View File

@ -584,11 +584,13 @@ void SV_RestartAmbientSounds( void )
SV_StartSound( pfnPEntityOfEntIndex( si->entnum ), CHAN_STATIC, si->name, si->volume, si->attenuation, 0, si->pitch );
}
#ifndef XASH_DEDICATED // TODO: ???
// restart soundtrack
if( S_StreamGetCurrentState( curtrack, looptrack, &position ))
{
SV_StartMusic( curtrack, looptrack, position );
}
#endif
}
/*

View File

@ -645,9 +645,10 @@ qboolean SV_InitGame( void )
return true; // already initialized ?
// first initialize?
if( !SV_LoadProgs( GI->game_dll ))
COM_ResetLibraryError();
if( !SV_LoadProgs( SI.gamedll ))
{
Con_Printf( S_ERROR "can't initialize %s\n", GI->game_dll );
Con_Printf( S_ERROR "can't initialize %s: %s\n", SI.gamedll, COM_GetLibraryError() );
return false; // failed to loading server.dll
}

View File

@ -21,7 +21,9 @@ GNU General Public License for more details.
#include "gl_export.h"
typedef int (*PHYSICAPI)( int, server_physics_api_t*, physics_interface_t* );
#ifndef XASH_DEDICATED
extern triangleapi_t gTriApi;
#endif
/*
pushmove objects do not obey gravity, and do not interact with each other or trigger fields,
@ -2004,10 +2006,17 @@ static server_physics_api_t gPhysicsAPI =
SV_GetHeadNode,
SV_ServerState,
Host_Error,
#ifndef XASH_DEDICATED
&gTriApi, // ouch!
pfnDrawConsoleString,
pfnDrawSetTextColor,
pfnDrawConsoleStringLen,
#else
NULL, // ouch! ouch!
NULL, // ouch! ouch!
NULL, // ouch! ouch!
NULL, // ouch! ouch!
#endif
Con_NPrintf,
Con_NXPrintf,
SV_GetLightStyle,

View File

@ -323,6 +323,27 @@ void SV_AddLaddersToPmove( areanode_t *node, const vec3_t pmove_mins, const vec3
SV_AddLaddersToPmove( node->children[1], pmove_mins, pmove_maxs );
}
static void pfnParticle( float *origin, int color, float life, int zpos, int zvel )
{
int v;
if( !origin )
{
MsgDev( D_ERROR, "SV_StartParticle: NULL origin. Ignored\n" );
return;
}
MSG_WriteByte( &sv.reliable_datagram, svc_particle );
MSG_WriteVec3Coord( &sv.reliable_datagram, origin );
MSG_WriteChar( &sv.reliable_datagram, 0 ); // no x-vel
MSG_WriteChar( &sv.reliable_datagram, 0 ); // no y-vel
v = bound( -128, (zpos * zvel) * 16.0f, 127 );
MSG_WriteChar( &sv.reliable_datagram, v ); // write z-vel
MSG_WriteByte( &sv.reliable_datagram, 1 );
MSG_WriteByte( &sv.reliable_datagram, color );
MSG_WriteByte( &sv.reliable_datagram, bound( 0, life * 8, 255 ));
}
static int pfnTestPlayerPosition( float *pos, pmtrace_t *ptrace )
{
return PM_TestPlayerPosition( svgame.pmove, pos, ptrace, NULL );
@ -564,7 +585,7 @@ void SV_InitClientMove( void )
// common utilities
svgame.pmove->PM_Info_ValueForKey = Info_ValueForKey;
svgame.pmove->PM_Particle = CL_Particle; // for local system only
svgame.pmove->PM_Particle = pfnParticle;
svgame.pmove->PM_TestPlayerPosition = pfnTestPlayerPosition;
svgame.pmove->Con_NPrintf = Con_NPrintf;
svgame.pmove->Con_DPrintf = Con_DPrintf;

View File

@ -1118,8 +1118,10 @@ static void SaveClientState( SAVERESTOREDATA *pSaveData, const char *level, int
{
// sounds won't going across transition
header.soundCount = S_GetCurrentDynamicSounds( soundInfo, MAX_CHANNELS );
#ifndef XASH_DEDICATED
// music not reqiured to save position: it's just continue playing on a next level
S_StreamGetCurrentState( header.introTrack, header.mainTrack, &header.trackPosition );
#endif
}
// save viewentity to allow camera works after save\restore
@ -2098,8 +2100,10 @@ void SV_SaveGame( const char *pName )
SaveBuildComment( comment, sizeof( comment ));
result = SaveGameSlot( savename, comment );
#ifndef XASH_DEDICATED
if( result && !FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
CL_HudMessage( "GAMESAVED" ); // defined in titles.txt
#endif
}
/*