Compare commits

..

1 Commits

Author SHA1 Message Date
Alibek Omarov
989958e185 scripts: cirrus: enable configure log temporarily 2025-02-09 17:50:21 +03:00
45 changed files with 1412 additions and 1289 deletions

View File

@@ -148,7 +148,8 @@ def configure(conf):
conf.write_config_header('backtrace-supported.h')
@TaskGen.feature('frandomseed')
@TaskGen.after_method('propagate_uselib_vars')
@TaskGen.after_method('process_source')
@TaskGen.before_method('apply_link')
def process_frandom_seed(ctx):
tasks = getattr(ctx, 'compiled_tasks', [])

View File

@@ -38,9 +38,6 @@ Uploaded to github by Oleg Cherkasky - https://github.com/gunrunners-paradise/Ct
## Deathmatch Classic
Available in Valve's Half-Life repository - https://github.com/ValveSoftware/halflife/tree/master/dmc
## Delta Particles
Available on ModDB - https://www.moddb.com/mods/half-life-delta/downloads/delta-particles-full-sources-maps-and-c-code
## Earth Special Forces
Alpha 2.0 - https://www.gamers-desire.de/details/2830

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,6 @@
# Xash3D FWGS Engine <img align="right" width="128" height="128" src="https://github.com/FWGS/xash3d-fwgs/raw/master/game_launch/icon-xash-material.png" alt="Xash3D FWGS icon" />
[![GitHub Actions Status](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml/badge.svg)](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml) [![FreeBSD Build Status](https://img.shields.io/cirrus/github/FWGS/xash3d-fwgs?label=freebsd%20build)](https://cirrus-ci.com/github/FWGS/xash3d-fwgs) \
[![Discord Server](https://img.shields.io/discord/355697768582610945?logo=Discord&label=International%20Discord%20chat)](http://fwgsdiscord.mentality.rip/) [![Russian speakers Telegram Chat](https://img.shields.io/badge/Russian_speakers_Telegram_chat-gray?logo=Telegram)](https://t.me/flyingwithgauss) \
[![Download Daily Build](https://img.shields.io/badge/downloads-testing-orange)](https://github.com/FWGS/xash3d-fwgs/releases/tag/continuous)
[![builds.sr.ht status](https://builds.sr.ht/~a1batross/xash3d-fwgs.svg)](https://builds.sr.ht/~a1batross/xash3d-fwgs?) [![GitHub Actions Status](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml/badge.svg)](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml) [![FreeBSD Build Status](https://img.shields.io/cirrus/github/FWGS/xash3d-fwgs?label=freebsd%20build)](https://cirrus-ci.com/github/FWGS/xash3d-fwgs) [![Discord Server](https://img.shields.io/discord/355697768582610945.svg)](http://fwgsdiscord.mentality.rip/) \
[![Download Stable](https://img.shields.io/badge/download-stable-yellow)](https://github.com/FWGS/xash3d-fwgs/releases/latest) [![Download Testing](https://img.shields.io/badge/downloads-testing-orange)](https://github.com/FWGS/xash3d-fwgs/releases/tag/continuous)
Xash3D ([pronounced](https://ipa-reader.com/?text=ks%C9%91%CA%82) `[ksɑʂ]`) FWGS is a game engine, aimed to provide compatibility with Half-Life Engine and extend it, as well as to give game developers well known workflow.

View File

@@ -90,12 +90,12 @@ typedef struct netadr_s
static inline netadrtype_t NET_NetadrType( const netadr_t *a )
{
if( a->type == NA_IP6 || a->type == NA_MULTICAST_IP6 )
return (netadrtype_t)a->type;
return a->type;
if( a->ip6_0[0] || a->ip6_0[1] )
return NA_UNDEFINED;
return (netadrtype_t)a->type;
return a->type;
}
static inline void NET_NetadrSetType( netadr_t *a, netadrtype_t type )

View File

@@ -13,19 +13,13 @@
#endif // _WIN32
#include <sys/types.h> // off_t
#ifdef STDINT_H
#include STDINT_H
#else // !STDINT_H
#include <stdint.h>
#endif // !STDINT_H
#include <assert.h>
typedef uint8_t byte;
typedef float vec_t;
typedef vec_t vec2_t[2];
#ifndef vec3_t // SDK renames it to Vector
typedef vec_t vec3_t[3];
#endif
typedef vec_t vec4_t[4];
typedef vec_t quat_t[4];
typedef byte rgba_t[4]; // unsigned byte colorpack
@@ -50,7 +44,6 @@ typedef int qboolean;
#define BIT( n ) ( 1U << ( n ))
#define BIT64( n ) ( 1ULL << ( n ))
#define SetBits( iBitVector, bits ) ((iBitVector) = (iBitVector) | (bits))
#define ClearBits( iBitVector, bits ) ((iBitVector) = (iBitVector) & ~(bits))
#define FBitSet( iBitVector, bit ) ((iBitVector) & (bit))
@@ -67,8 +60,6 @@ typedef int qboolean;
#define IsColorString( p ) ( p && *( p ) == '^' && *(( p ) + 1) && *(( p ) + 1) >= '0' && *(( p ) + 1 ) <= '9' )
#define ColorIndex( c ) ((( c ) - '0' ) & 7 )
#undef EXPORT
#if defined( __GNUC__ )
#if defined( __i386__ )
#define EXPORT __attribute__(( visibility( "default" ), force_align_arg_pointer ))

View File

@@ -1766,7 +1766,7 @@ static cvar_t *GAME_EXPORT pfnCvar_RegisterClientVariable( const char *szName, c
|| !Q_stricmp( szName, "sensitivity" ))
flags |= FCVAR_PRIVILEGED;
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_CLIENTDLL, Cvar_BuildAutoDescription( szName, flags|FCVAR_CLIENTDLL ));
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_CLIENTDLL, NULL );
}
static int GAME_EXPORT Cmd_AddClientCommand( const char *cmd_name, xcommand_t function )

View File

@@ -691,7 +691,7 @@ pfnCvar_RegisterVariable
*/
static cvar_t *GAME_EXPORT pfnCvar_RegisterGameUIVariable( const char *szName, const char *szValue, int flags )
{
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_GAMEUIDLL, Cvar_BuildAutoDescription( szName, flags|FCVAR_GAMEUIDLL ));
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_GAMEUIDLL, NULL );
}
static int GAME_EXPORT Cmd_AddGameUICommand( const char *cmd_name, xcommand_t function )

View File

@@ -92,11 +92,6 @@ static char *pfnParseFileSafe( char *data, char *buf, const int size, unsigned i
return COM_ParseFileSafe( data, buf, size, flags, len, NULL );
}
static void GAME_EXPORT pfnSetCustomClientID( const char *id )
{
// deprecated
}
static const mobile_engfuncs_t gMobileEngfuncs =
{
MOBILITY_API_VERSION,
@@ -111,7 +106,7 @@ static const mobile_engfuncs_t gMobileEngfuncs =
pfnDrawScaledCharacter,
Sys_Warn,
Sys_GetNativeObject,
pfnSetCustomClientID,
ID_SetCustomClientID,
pfnParseFileSafe
};

View File

@@ -83,10 +83,7 @@ static void CL_ParseNewMovevars( sizebuf_t *msg )
R_SetupSky( clgame.movevars.skyName );
clgame.oldmovevars = clgame.movevars;
// FIXME: set world wave height when entities will be allocated
if( clgame.entities )
clgame.entities->curstate.scale = clgame.movevars.waveHeight;
clgame.entities->curstate.scale = clgame.movevars.waveHeight;
// keep features an actual!
clgame.oldmovevars.features = clgame.movevars.features = host.features;

View File

@@ -1215,6 +1215,7 @@ void OSK_Draw( void );
//
void ID_Init( void );
const char *ID_GetMD5( void );
void GAME_EXPORT ID_SetCustomClientID( const char *id );
extern rgba_t g_color_table[8];
extern triangleapi_t gTriApi;

View File

@@ -19,8 +19,8 @@ GNU General Public License for more details.
#if !XASH_WIN32
#include <dirent.h>
#endif
static char id_md5[33];
static char id_customid[MAX_STRING];
/*
==========================================================
@@ -590,9 +590,25 @@ static void ID_Check( void )
const char *ID_GetMD5( void )
{
if( id_customid[0] )
return id_customid;
return id_md5;
}
/*
===============
ID_SetCustomClientID
===============
*/
void GAME_EXPORT ID_SetCustomClientID( const char *id )
{
if( !id )
return;
Q_strncpy( id_customid, id, sizeof( id_customid ) );
}
void ID_Init( void )
{
MD5Context_t hash = { 0 };

View File

@@ -1130,8 +1130,8 @@ void Touch_Init( void )
Cmd_AddRestrictedCommand( "touch_loaddefaults", Touch_LoadDefaults_f, "generate config from defaults" );
Cmd_AddRestrictedCommand( "touch_roundall", Touch_RoundAll_f, "round all buttons coordinates to grid" );
Cmd_AddRestrictedCommand( "touch_exportconfig", Touch_ExportConfig_f, "export config keeping aspect ratio" );
Cmd_AddRestrictedCommand( "touch_set_stroke", Touch_Stroke_f, "set global stroke width and color" );
Cmd_AddRestrictedCommand( "touch_setclientonly", Touch_SetClientOnly_f, "when 1, only client buttons are shown" );
Cmd_AddCommand( "touch_set_stroke", Touch_Stroke_f, "set global stroke width and color" );
Cmd_AddCommand( "touch_setclientonly", Touch_SetClientOnly_f, "when 1, only client buttons are shown" );
Cmd_AddRestrictedCommand( "touch_reloadconfig", Touch_ReloadConfig_f, "load config, not saving changes" );
Cmd_AddRestrictedCommand( "touch_writeconfig", Touch_WriteConfig, "save current config" );
Cmd_AddRestrictedCommand( "touch_deleteprofile", Touch_DeleteProfile_f, "delete profile by name" );

View File

@@ -103,16 +103,10 @@ Cvar_BuildAutoDescription
build cvar auto description that based on the setup flags
============
*/
const char *Cvar_BuildAutoDescription( const char *szName, int flags )
static const char *Cvar_BuildAutoDescription( int flags )
{
static char desc[256];
if( FBitSet( flags, FCVAR_GLCONFIG ))
{
Q_snprintf( desc, sizeof( desc ), CVAR_GLCONFIG_DESCRIPTION, szName );
return desc;
}
desc[0] = '\0';
if( FBitSet( flags, FCVAR_EXTDLL ))
@@ -447,7 +441,7 @@ convar_t *Cvar_Get( const char *name, const char *value, int flags, const char *
Cvar_DirectSet( var, value );
}
if( FBitSet( var->flags, FCVAR_ALLOCATED ) && Q_strcmp( var_desc, var->desc ))
if( FBitSet( var->flags, FCVAR_ALLOCATED ) && var_desc != NULL && Q_strcmp( var_desc, var->desc ))
{
if( !FBitSet( flags, FCVAR_GLCONFIG ))
Con_Reportf( "%s change description from %s to %s\n", var->name, var->desc, var_desc );
@@ -460,6 +454,10 @@ convar_t *Cvar_Get( const char *name, const char *value, int flags, const char *
}
// allocate a new cvar
if( !var_desc )
var_desc = Cvar_BuildAutoDescription( flags );
var = Mem_Malloc( cvar_pool, sizeof( *var ));
var->name = copystringpool( cvar_pool, name );
var->string = copystringpool( cvar_pool, value );
@@ -1206,7 +1204,7 @@ static void Cvar_List_f( void )
if( FBitSet( var->flags, FCVAR_EXTENDED|FCVAR_ALLOCATED ))
Con_Printf( " %-*s %s ^3%s^7\n", 32, var->name, value, var->desc );
else Con_Printf( " %-*s %s ^3%s^7\n", 32, var->name, value, Cvar_BuildAutoDescription( var->name, var->flags ));
else Con_Printf( " %-*s %s ^3%s^7\n", 32, var->name, value, Cvar_BuildAutoDescription( var->flags ));
count++;
}

View File

@@ -44,7 +44,6 @@ void Cvar_DirectSet( convar_t *var, const char *value );
void Cvar_DirectSetValue( convar_t *var, float value );
void Cvar_Set( const char *var_name, const char *value );
void Cvar_SetValue( const char *var_name, float value );
const char *Cvar_BuildAutoDescription( const char *szName, int flags ) RETURNS_NONNULL;
float Cvar_VariableValue( const char *var_name );
int Cvar_VariableInteger( const char *var_name );
const char *Cvar_VariableString( const char *var_name ) RETURNS_NONNULL;

View File

@@ -258,7 +258,8 @@ static qboolean FS_DetermineReadOnlyRootDirectory( char *out, size_t size )
void FS_CheckConfig( void )
{
if( fs_mount_lv.value || fs_mount_hd.value || fs_mount_addon.value || fs_mount_l10n.value )
// only used to prevent rescan after reading config.cfg when user hasn't enabled any addon directories
if( fs_mount_lv.value || fs_mount_hd.value || fs_mount_addon.value || fs_mount_l10n.value || Q_stricmp( ui_language.string, "english" ))
FS_Rescan_f();
}
@@ -318,6 +319,7 @@ void FS_Init( const char *basedir )
Cvar_RegisterVariable( &fs_mount_lv );
Cvar_RegisterVariable( &fs_mount_addon );
Cvar_RegisterVariable( &fs_mount_l10n );
Cvar_RegisterVariable( &ui_language );
if( !Sys_GetParmFromCmdLine( "-dll", host.gamedll ))
host.gamedll[0] = 0;

View File

@@ -140,8 +140,7 @@ static void Sys_PrintUsage( const char *exename )
"\nCommon options:\n"
O("-dev [level] ", "set log verbosity 0-2")
O("-log [file name] ", "write log to \"engine.log\" or [file name] if specified")
O("-logtime ", "enable writing timestamps to the log file")
O("-log ", "write log to \"engine.log\"")
O("-nowriteconfig ", "disable config save")
O("-noch ", "disable crashhandler")
#if XASH_WIN32 // !!!!
@@ -698,17 +697,17 @@ static qboolean Host_Autosleep( double dt, double scale )
static double timewindow; // allocate a time window for sleeps
static int counter; // for debug
static double realsleeptime;
const double sleeptime = sleep * 0.000001;
const double sleeptime = sleep * 0.001;
if( dt < targetframetime * scale )
{
// if we have allocated time window, try to sleep
if( timewindow > realsleeptime )
{
// Platform_Sleep isn't guaranteed to sleep an exact amount of microseconds
// Platform_Sleep isn't guaranteed to sleep an exact amount of milliseconds
// so we measure the real sleep time and use it to decrease the window
double t1 = Sys_DoubleTime(), t2;
Platform_NanoSleep( sleep * 1000 ); // in usec!
Platform_Sleep( sleep ); // in msec!
t2 = Sys_DoubleTime();
realsleeptime = t2 - t1;

View File

@@ -382,7 +382,8 @@ static void Mod_StudioCalcRotations( int boneused[], int numbones, const byte *p
for( j = numbones - 1; j >= 0; j-- )
{
i = boneused[j];
R_StudioCalcBones( frame, s, &pbone[i], &panim[i], adj, pos[i], q[i] );
R_StudioCalcBoneQuaternion( frame, s, &pbone[i], &panim[i], adj, q[i] );
R_StudioCalcBonePosition( frame, s, &pbone[i], &panim[i], adj, pos[i] );
}
if( pseqdesc->motiontype & STUDIO_X ) pos[pseqdesc->motionbone][0] = 0.0f;
@@ -723,7 +724,7 @@ void Mod_StudioComputeBounds( void *buffer, vec3_t mins, vec3_t maxs, qboolean i
{
for( k = 0; k < pseqdesc->numframes; k++ )
{
R_StudioCalcBones( k, 0, &pbones[j], panim, NULL, pos, NULL );
R_StudioCalcBonePosition( k, 0, &pbones[j], panim, NULL, pos );
Mod_StudioBoundVertex( vert_mins, vert_maxs, &bone_count, pos );
}
}

View File

@@ -721,6 +721,39 @@ qboolean NET_CompareBaseAdr( const netadr_t a, const netadr_t b )
return false;
}
/*
====================
NET_CompareClassBAdr
Compare local masks
====================
*/
qboolean NET_CompareClassBAdr( const netadr_t a, const netadr_t b )
{
netadrtype_t type_a = NET_NetadrType( &a );
netadrtype_t type_b = NET_NetadrType( &b );
if( type_a != type_b )
return false;
if( type_a == NA_LOOPBACK )
return true;
if( type_a == NA_IP )
{
if( a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] )
return true;
}
// NOTE: we don't check for IPv6 here
// this check is very dumb and only used for LAN restriction
// Actual check is in IsReservedAdr
// for real mask compare use NET_CompareAdrByMask
return false;
}
/*
====================
NET_CompareAdrByMask
@@ -1512,7 +1545,7 @@ static int NET_SendLong( netsrc_t sock, int net_socket, const char *buf, size_t
total_sent += size;
len -= size;
packet_number++;
Platform_NanoSleep( 100 * 1000 );
Platform_Sleep( 1 );
}
return total_sent;

View File

@@ -64,6 +64,7 @@ void NET_Config( qboolean net_enable, qboolean changeport );
const char *NET_AdrToString( const netadr_t a ) RETURNS_NONNULL;
const char *NET_BaseAdrToString( const netadr_t a ) RETURNS_NONNULL;
qboolean NET_IsReservedAdr( netadr_t a );
qboolean NET_CompareClassBAdr( const netadr_t a, const netadr_t b );
qboolean NET_StringToAdr( const char *string, netadr_t *adr );
qboolean NET_StringToFilterAdr( const char *s, netadr_t *adr, uint *prefixlen );
net_gai_state_t NET_StringToAdrNB( const char *string, netadr_t *adr, qboolean v6only );

View File

@@ -31,14 +31,15 @@ GNU General Public License for more details.
#define XASH_COLORIZE_CONSOLE 0
#endif
static struct logdata_s {
char title[64];
qboolean log_active;
qboolean log_time;
char log_path[MAX_SYSPATH];
FILE *logfile;
int logfileno;
} s_ld;
typedef struct {
char title[64];
qboolean log_active;
char log_path[MAX_SYSPATH];
FILE *logfile;
int logfileno;
} LogData;
static LogData s_ld;
void Sys_DestroyConsole( void )
{
@@ -77,19 +78,14 @@ static void Sys_FlushLogfile( void )
void Sys_InitLog( void )
{
const char *mode;
const char *mode;
if( Sys_CheckParm( "-log" ))
{
if( !Sys_GetParmFromCmdLine( "-log", s_ld.log_path ) || !isalnum( s_ld.log_path[0] ))
Q_strncpy( s_ld.log_path, "engine.log", sizeof( s_ld.log_path ));
COM_DefaultExtension( s_ld.log_path, ".log", sizeof( s_ld.log_path ));
s_ld.log_active = true;
Q_strncpy( s_ld.log_path, "engine.log", sizeof( s_ld.log_path ));
}
s_ld.log_time = Sys_CheckParm( "-logtime" );
if( host.change_game && host.type != HOST_DEDICATED )
mode = "a";
else mode = "w";
@@ -105,7 +101,7 @@ void Sys_InitLog( void )
if ( !s_ld.logfile )
{
Con_Reportf( S_ERROR "%s: can't create log file %s: %s\n", __func__, s_ld.log_path, strerror( errno ));
Con_Reportf( S_ERROR "Sys_InitLog: can't create log file %s: %s\n", s_ld.log_path, strerror( errno ));
return;
}
@@ -299,23 +295,17 @@ void Sys_PrintLog( const char *pMsg )
// save last char to detect when line was not ended
lastchar = len > 0 ? pMsg[len - 1] : 0;
// spew to engine.log
if( s_ld.logfile )
{
if( s_ld.log_time && print_time )
{
logtime_len = strftime( logtime, sizeof( logtime ), "[%Y:%m:%d|%H:%M:%S] ", crt_tm ); //full time
logtime_len = Q_min( logtime_len, sizeof( logtime ) - 1 ); // just in case
}
else
{
logtime[0] = '\0';
logtime_len = 0;
}
if( !s_ld.logfile )
return;
Sys_PrintLogfile( s_ld.logfileno, logtime, logtime_len, pMsg, false );
Sys_FlushLogfile();
if( print_time )
{
logtime_len = strftime( logtime, sizeof( logtime ), "[%Y:%m:%d|%H:%M:%S] ", crt_tm ); //full time
logtime_len = Q_min( logtime_len, sizeof( logtime ) - 1 ); // just in case
}
Sys_PrintLogfile( s_ld.logfileno, logtime, logtime_len, pMsg, false );
Sys_FlushLogfile();
}
/*

View File

@@ -65,8 +65,6 @@ typedef struct memheader_s
// immediately followed by data, which is followed by a MEMHEADER_SENTINEL2 byte
} memheader_t;
STATIC_CHECK_SIZEOF( memheader_t, 24, 40 );
typedef struct mempool_s
{
struct memheader_s *chain; // chain of individual memory allocations

View File

@@ -184,7 +184,7 @@ qboolean SNDDMA_Init( void )
return false;
}
dma.buffer = Mem_Calloc( sndpool, samples * 2 ); //allocate pcm frame buffer
dma.buffer = Mem_Malloc( sndpool, samples * 2 ); //allocate pcm frame buffer
dma.samplepos = 0;
dma.samples = samples;
dma.format.width = 2;

View File

@@ -70,9 +70,6 @@ void Android_Shutdown( void );
#endif
#if XASH_WIN32
void Win32_Init( qboolean con_showalways );
void Win32_Shutdown( void );
qboolean Win32_NanoSleep( int nsec );
void Wcon_CreateConsole( qboolean con_showalways );
void Wcon_DestroyConsole( void );
void Wcon_InitConsoleCommands( void );
@@ -127,7 +124,7 @@ static inline void Platform_Init( qboolean con_showalways, const char *basedir )
#elif XASH_DOS
DOS_Init( );
#elif XASH_WIN32
Win32_Init( con_showalways );
Wcon_CreateConsole( con_showalways );
#elif XASH_LINUX
Linux_Init( );
#endif
@@ -142,7 +139,7 @@ static inline void Platform_Shutdown( void )
#elif XASH_DOS
DOS_Shutdown( );
#elif XASH_WIN32
Win32_Shutdown( );
Wcon_DestroyConsole( );
#elif XASH_LINUX
Linux_Shutdown( );
#endif
@@ -181,23 +178,6 @@ static inline void Platform_Sleep( int msec )
#endif
}
static inline qboolean Platform_NanoSleep( int nsec )
{
// SDL2 doesn't have nanosleep, so use low-level functions here
// When this code will be ported to SDL3, use SDL_DelayNS
#if XASH_POSIX
struct timespec ts = {
.tv_sec = 0,
.tv_nsec = nsec, // just don't put large numbers here
};
return nanosleep( &ts, NULL ) == 0;
#elif XASH_WIN32
return Win32_NanoSleep( nsec );
#else
return false;
#endif
}
#if XASH_WIN32 || XASH_FREEBSD || XASH_NETBSD || XASH_OPENBSD || XASH_ANDROID || XASH_LINUX || XASH_APPLE
void Sys_SetupCrashHandler( const char *argv0 );
void Sys_RestoreCrashHandler( void );

View File

@@ -158,7 +158,8 @@ void Sys_CrashLibbacktrace( int signal, siginfo_t *si, void *context )
pd.message_size = sizeof( message ) - len;
pd.len = 0;
backtrace_full( g_bt_state, 1, Sys_BacktracePrintFull, Sys_BacktracePrintError, &pd );
if( g_bt_state )
backtrace_full( g_bt_state, 0, Sys_BacktracePrintFull, Sys_BacktracePrintError, &pd );
// put MessageBox as Sys_Error
Msg( "%s\n", message );

View File

@@ -33,12 +33,6 @@ static struct
} cursors;
#endif
static struct
{
int x, y;
qboolean pushed;
} in_visible_cursor_pos;
/*
=============
Platform_GetMousePos
@@ -209,6 +203,11 @@ void Platform_SetCursorType( VGUI_DefaultCursor type )
{
qboolean visible;
#if SDL_VERSION_ATLEAST( 2, 0, 0 )
if( !cursors.initialized )
return;
#endif
switch( type )
{
case dc_user:
@@ -230,28 +229,11 @@ void Platform_SetCursorType( VGUI_DefaultCursor type )
#if SDL_VERSION_ATLEAST( 2, 0, 0 )
if( host.mouse_visible )
{
if( cursors.initialized )
SDL_SetCursor( cursors.cursors[type] );
SDL_SetCursor( cursors.cursors[type] );
SDL_ShowCursor( true );
// restore the last mouse position
if( in_visible_cursor_pos.pushed )
{
SDL_WarpMouseInWindow( host.hWnd, in_visible_cursor_pos.x, in_visible_cursor_pos.y );
in_visible_cursor_pos.pushed = false;
}
}
else
{
// save last mouse position and warp it to the center
if( !in_visible_cursor_pos.pushed )
{
SDL_GetMouseState( &in_visible_cursor_pos.x, &in_visible_cursor_pos.y );
SDL_WarpMouseInWindow( host.hWnd, host.window_center_x, host.window_center_y );
in_visible_cursor_pos.pushed = true;
}
SDL_ShowCursor( false );
}
#else

View File

@@ -175,7 +175,7 @@ qboolean SNDDMA_Init( void )
if( !samplecount )
samplecount = 0x8000;
dma.samples = samplecount * obtained.channels;
dma.buffer = Mem_Calloc( sndpool, dma.samples * 2 );
dma.buffer = Mem_Malloc( sndpool, dma.samples * 2 );
dma.samplepos = 0;
sdl_format = obtained.format;

View File

@@ -49,6 +49,10 @@ typedef struct
qboolean inputEnabled;
qboolean consoleVisible;
qboolean attached;
// log stuff
qboolean log_active;
char log_path[MAX_SYSPATH];
} WinConData;
static WinConData s_wcd;
@@ -498,13 +502,19 @@ create win32 console
*/
void Wcon_CreateConsole( qboolean con_showalways )
{
if( Sys_CheckParm( "-log" ))
s_wcd.log_active = true;
if( host.type == HOST_NORMAL )
{
Q_strncpy( s_wcd.title, XASH_ENGINE_NAME " " XASH_VERSION, sizeof( s_wcd.title ));
Q_strncpy( s_wcd.log_path, "engine.log", sizeof( s_wcd.log_path ));
}
else // dedicated console
{
Q_strncpy( s_wcd.title, XASH_DEDICATED_SERVER_NAME " " XASH_VERSION, sizeof( s_wcd.title ));
Q_strncpy( s_wcd.log_path, "dedicated.log", sizeof( s_wcd.log_path ));
s_wcd.log_active = true; // always make log
}
s_wcd.attached = ( AttachConsole( ATTACH_PARENT_PROCESS ) != 0 );
@@ -586,8 +596,10 @@ void Wcon_DestroyConsole( void )
// last text message into console or log
Con_Reportf( "%s: Unloading xash.dll\n", __func__ );
Sys_CloseLog( NULL );
if( !s_wcd.attached )
{
{
if( s_wcd.hWnd )
{
ShowWindow( s_wcd.hWnd, SW_HIDE );

View File

@@ -18,8 +18,6 @@ GNU General Public License for more details.
#include "server.h"
#include <shellapi.h>
HANDLE g_waitable_timer;
#if XASH_TIMER == TIMER_WIN32
double Platform_DoubleTime( void )
{
@@ -38,67 +36,6 @@ double Platform_DoubleTime( void )
}
#endif // XASH_TIMER == TIMER_WIN32
void Win32_Init( qboolean con_showalways )
{
HMODULE hModule = LoadLibrary( "kernel32.dll" );
if( hModule )
{
HANDLE ( __stdcall *pfnCreateWaitableTimerExW)( LPSECURITY_ATTRIBUTES lpTimerAttributes, LPCWSTR lpTimerName, DWORD dwFlags, DWORD dwDesiredAccess );
if(( pfnCreateWaitableTimerExW = (void *)GetProcAddress( hModule, "CreateWaitableTimerExW" )))
{
g_waitable_timer = pfnCreateWaitableTimerExW(
NULL,
NULL,
0x1 /* CREATE_WAITABLE_TIMER_MANUAL_RESET */ | 0x2 /* CREATE_WAITABLE_TIMER_HIGH_RESOLUTION */,
0x0002 /* TIMER_MODIFY_STATE */ | SYNCHRONIZE | DELETE
);
}
FreeLibrary( hModule );
}
#if 0 // FIXME: creates object but doesn't wait for specific time for me on Windows 10, with the code above commented
if( !g_waitable_timer )
g_waitable_timer = CreateWaitableTimer( NULL, TRUE, NULL );
#endif
Wcon_CreateConsole( con_showalways );
}
void Win32_Shutdown( void )
{
Wcon_DestroyConsole( );
if( g_waitable_timer )
{
CloseHandle( g_waitable_timer );
g_waitable_timer = 0;
}
}
qboolean Win32_NanoSleep( int nsec )
{
LARGE_INTEGER ts;
if( !g_waitable_timer )
return false;
ts.QuadPart = -nsec / 100;
if( !SetWaitableTimer( g_waitable_timer, &ts, 0, NULL, NULL, FALSE ))
{
CloseHandle( g_waitable_timer );
g_waitable_timer = 0;
return false;
}
if( WaitForSingleObject( g_waitable_timer, Q_max( 1, nsec / 1000000 )) != WAIT_OBJECT_0 )
return false;
return true;
}
qboolean Platform_DebuggerPresent( void )
{
return IsDebuggerPresent();

View File

@@ -279,6 +279,19 @@ typedef struct sv_client_s
a program error, like an overflowed reliable buffer
=============================================================================
*/
// MAX_CHALLENGES is made large to prevent a denial
// of service attack that could cycle all of them
// out before legitimate users connected
#define MAX_CHALLENGES 1024
typedef struct
{
netadr_t adr;
double time;
int challenge;
qboolean connected;
} challenge_t;
typedef struct
{
char name[32]; // in GoldSrc max name length is 12
@@ -372,7 +385,7 @@ typedef struct
entity_state_t *baselines; // [GI->max_edicts]
entity_state_t *static_entities; // [MAX_STATIC_ENTITIES];
uint32_t challenge_salt[16]; // pregenerated random numbers for generating challenged based on IP's MD5 address
challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting
sizebuf_t testpacket; // pregenerataed testpacket, only needs CRC32 patching
byte *testpacket_buf; // check for NULL if testpacket is available

View File

@@ -86,54 +86,38 @@ flood the server with invalid connection IPs. With a
challenge, they must give a valid IP address.
=================
*/
static int SV_GetChallenge( netadr_t from, qboolean *error )
static void SV_GetChallenge( netadr_t from )
{
const netadrtype_t type = NET_NetadrType( &from );
MD5Context_t ctx;
byte digest[16];
int i, oldest = 0;
double oldestTime;
*error = false;
oldestTime = 0x7fffffff;
MD5Init( &ctx );
switch( type )
// see if we already have a challenge for this ip
for( i = 0; i < MAX_CHALLENGES; i++ )
{
case NA_IP:
MD5Update( &ctx, from.ip, sizeof( from.ip ));
break;
case NA_IPX:
MD5Update( &ctx, from.ipx, sizeof( from.ipx ));
break;
case NA_IP6:
{
byte ip6[16];
NET_NetadrToIP6Bytes( ip6, &from );
MD5Update( &ctx, ip6, sizeof( ip6 ));
break;
}
case NA_LOOPBACK:
return 0;
default:
*error = true;
return 0;
if( !svs.challenges[i].connected && NET_CompareAdr( from, svs.challenges[i].adr ))
break;
if( svs.challenges[i].time < oldestTime )
{
oldestTime = svs.challenges[i].time;
oldest = i;
}
}
MD5Update( &ctx, (byte *)svs.challenge_salt, sizeof( svs.challenge_salt ));
MD5Final( digest, &ctx );
return digest[0] | digest[1] << 8 | digest[2] << 16 | digest[3] << 24;
}
static void SV_SendChallenge( netadr_t from )
{
qboolean error = false;
int challenge = SV_GetChallenge( from, &error );
if( error )
return;
if( i == MAX_CHALLENGES )
{
// this is the first time this client has asked for a challenge
svs.challenges[oldest].challenge = (COM_RandomLong( 0, 0x7FFF ) << 16) | COM_RandomLong( 0, 0xFFFF );
svs.challenges[oldest].adr = from;
svs.challenges[oldest].time = host.realtime;
svs.challenges[oldest].connected = false;
i = oldest;
}
// send it back
Netchan_OutOfBandPrint( NS_SERVER, from, S2C_CHALLENGE" %i", challenge );
Netchan_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, S2C_CHALLENGE" %i", svs.challenges[i].challenge );
}
static int SV_GetFragmentSize( void *pcl, fragsize_t mode )
@@ -227,16 +211,35 @@ Make sure connecting client is not spoofing
*/
static int SV_CheckChallenge( netadr_t from, int challenge )
{
qboolean error = false;
int challenge2 = SV_GetChallenge( from, &error );
int i;
if( error || challenge2 != challenge )
// see if the challenge is valid
// don't care if it is a local address.
if( NET_IsLocalAddress( from ))
return 1;
for( i = 0; i < MAX_CHALLENGES; i++ )
{
SV_RejectConnection( from, "no challenge for your address\n" );
return false;
if( NET_CompareAdr( from, svs.challenges[i].adr ))
{
if( challenge == svs.challenges[i].challenge )
break; // valid challenge
#if 0
// g-cont. this breaks multiple connections from single machine
SV_RejectConnection( from, "bad challenge %i\n", challenge );
return 0;
#endif
}
}
return true;
if( i == MAX_CHALLENGES )
{
SV_RejectConnection( from, "no challenge for your address\n" );
return 0;
}
svs.challenges[i].connected = true;
return 1;
}
/*
@@ -250,7 +253,7 @@ static int SV_CheckIPRestrictions( netadr_t from )
{
if( sv_lan.value )
{
if( !NET_IsReservedAdr( from ))
if( !NET_CompareClassBAdr( from, net_local ) && !NET_IsReservedAdr( from ))
return 0;
}
return 1;
@@ -264,17 +267,23 @@ Get slot # and set client_t pointer for player, if possible
We don't do this search on a "reconnect, we just reuse the slot
================
*/
static sv_client_t *SV_FindEmptySlot( void )
static int SV_FindEmptySlot( netadr_t from, int *pslot, sv_client_t **ppClient )
{
int i;
sv_client_t *cl;
int i;
for( i = 0; i < svs.maxclients; i++ )
for( i = 0, cl = svs.clients; i < svs.maxclients; i++, cl++ )
{
if( svs.clients[i].state == cs_free )
return &svs.clients[i];
if( cl->state == cs_free )
{
*ppClient = cl;
*pslot = i;
return 1;
}
}
return NULL;
SV_RejectConnection( from, "server is full\n" );
return 0;
}
/*
@@ -286,13 +295,15 @@ A connection request that did not come from the master
*/
static void SV_ConnectClient( netadr_t from )
{
char userinfo[MAX_INFO_STRING];
char protinfo[MAX_INFO_STRING];
sv_client_t *newcl = NULL;
int qport, version;
int i, count = 0;
int challenge;
const char *s;
char userinfo[MAX_INFO_STRING];
char protinfo[MAX_INFO_STRING];
sv_client_t *cl, *newcl = NULL;
qboolean reconnect = false;
int nClientSlot = 0;
int qport, version;
int i, count = 0;
int challenge;
const char *s;
int extensions;
uint netchan_flags = 0;
@@ -310,6 +321,39 @@ static void SV_ConnectClient( netadr_t from )
return;
}
challenge = Q_atoi( Cmd_Argv( 2 )); // get challenge
// see if the challenge is valid (local clients don't need to challenge)
if( !SV_CheckChallenge( from, challenge ))
return;
s = Cmd_Argv( 3 ); // protocol info
if( !Info_IsValid( s ))
{
SV_RejectConnection( from, "invalid protinfo in connect command\n" );
return;
}
Q_strncpy( protinfo, s, sizeof( protinfo ));
if( !SV_ProcessUserAgent( from, protinfo ) )
{
return;
}
// extract qport from protocol info
qport = Q_atoi( Info_ValueForKey( protinfo, "qport" ));
s = Info_ValueForKey( protinfo, "uuid" );
if( Q_strlen( s ) != 32 )
{
SV_RejectConnection( from, "invalid authentication certificate length\n" );
return;
}
extensions = Q_atoi( Info_ValueForKey( protinfo, "ext" ) );
// LAN servers restrict to class b IP addresses
if( !SV_CheckIPRestrictions( from ))
{
@@ -317,37 +361,9 @@ static void SV_ConnectClient( netadr_t from )
return;
}
challenge = Q_atoi( Cmd_Argv( 2 )); // get challenge
// see if the challenge is valid (local clients don't need to challenge)
if( !SV_CheckChallenge( from, challenge ))
return;
s = Cmd_Argv( 3 );
if( Q_strlen( s ) > sizeof( protinfo ) || !Info_IsValid( s ))
{
SV_RejectConnection( from, "invalid protinfo in connect command\n" );
return;
}
Q_strncpy( protinfo, s, sizeof( protinfo )); // protocol info
if( !SV_ProcessUserAgent( from, protinfo ))
return;
if( Q_strlen( Info_ValueForKey( protinfo, "uuid" )) != 32 )
{
SV_RejectConnection( from, "invalid authentication certificate length\n" );
return;
}
// extract qport from protocol info
qport = Q_atoi( Info_ValueForKey( protinfo, "qport" ));
extensions = Q_atoi( Info_ValueForKey( protinfo, "ext" ));
s = Cmd_Argv( 4 ); // user info
if( Q_strlen( s ) > sizeof( userinfo ) || !Info_IsValid( s ))
if( Q_strlen( s ) > MAX_INFO_STRING || !Info_IsValid( s ))
{
SV_RejectConnection( from, "invalid userinfo in connect command\n" );
return;
@@ -366,43 +382,43 @@ static void SV_ConnectClient( netadr_t from )
}
// if there is already a slot for this ip, reuse it
for( i = 0; i < svs.maxclients; i++ )
for( i = 0, cl = svs.clients; i < svs.maxclients; i++, cl++ )
{
sv_client_t *cl = &svs.clients[i];
if( cl->state == cs_free || cl->state == cs_zombie )
continue;
if( NET_CompareBaseAdr( from, cl->netchan.remote_address ) && ( cl->netchan.qport == qport || from.port == cl->netchan.remote_address.port ))
{
reconnect = true;
newcl = cl;
Con_Reportf( S_NOTE "%s:reconnect\n", NET_AdrToString( from ));
break;
}
}
// A reconnecting client will re-use the slot found above when checking for reconnection.
// the slot will be wiped clean.
if( !newcl )
if( !reconnect )
{
// connect the client if there are empty slots.
newcl = SV_FindEmptySlot();
if( !newcl )
{
SV_RejectConnection( from, "server is full\n" );
if( !SV_FindEmptySlot( from, &nClientSlot, &newcl ))
return;
}
}
else
{
Con_Reportf( S_NOTE "%s:reconnect\n", NET_AdrToString( from ));
}
// find a client slot
ASSERT( newcl != NULL );
// build a new connection
// accept the new client
sv.current_client = newcl;
newcl->edict = EDICT_NUM(( newcl - svs.clients ) + 1 );
newcl->edict = EDICT_NUM( (newcl - svs.clients) + 1 );
newcl->challenge = challenge; // save challenge for checksumming
newcl->frames = (client_frame_t *)Mem_Realloc( host.mempool, newcl->frames, sizeof( client_frame_t ) * SV_UPDATE_BACKUP );
memset( newcl->frames, 0, sizeof( client_frame_t ) * SV_UPDATE_BACKUP );
if( newcl->frames ) Mem_Free( newcl->frames );
newcl->frames = (client_frame_t *)Z_Calloc( sizeof( client_frame_t ) * SV_UPDATE_BACKUP );
newcl->userid = g_userid++; // create unique userid
newcl->state = cs_connected;
newcl->extensions = extensions & (NET_EXT_SPLITSIZE);
@@ -466,11 +482,8 @@ static void SV_ConnectClient( netadr_t from )
// if this was the first client on the server, or the last client
// the server can hold, send a heartbeat to the master.
for( i = 0; i < svs.maxclients; i++ )
{
if( svs.clients[i].state >= cs_connected )
count++;
}
for( i = 0, cl = svs.clients; i < svs.maxclients; i++, cl++ )
if( cl->state >= cs_connected ) count++;
Log_Printf( "\"%s<%i><%i><>\" connected, address \"%s\"\n", newcl->name, newcl->userid, i, NET_AdrToString( newcl->netchan.remote_address ));
@@ -841,7 +854,7 @@ static void SV_TestBandWidth( netadr_t from )
( packetsize > FRAGMENT_MAX_SIZE ))
{
// skip the test and just get challenge
SV_SendChallenge( from );
SV_GetChallenge( from );
return;
}
@@ -849,7 +862,7 @@ static void SV_TestBandWidth( netadr_t from )
ofs = packetsize - svs.testpacket_filepos - 1;
if(( ofs < 0 ) || ( ofs > svs.testpacket_filelen ))
{
SV_SendChallenge( from );
SV_GetChallenge( from );
return;
}
@@ -1772,7 +1785,7 @@ static qboolean SV_ShouldUpdateUserinfo( sv_client_t *cl )
if( host.realtime < cl->userinfo_next_changetime + cl->userinfo_penalty * sv_userinfo_penalty_multiplier.value )
{
// player changes userinfo too quick! ignore!
if( host.realtime < cl->userinfo_next_changetime && cl->userinfo_change_attempts > 0 )
if( host.realtime < cl->userinfo_next_changetime )
{
Con_Reportf( "%s: ignore userinfo update for %s: penalty %f, attempts %i\n",
__func__, cl->name, cl->userinfo_penalty, cl->userinfo_change_attempts );
@@ -1783,15 +1796,15 @@ static qboolean SV_ShouldUpdateUserinfo( sv_client_t *cl )
}
// they spammed too fast, increase penalty
if( cl->userinfo_change_attempts >= (int)sv_userinfo_penalty_attempts.value )
if( cl->userinfo_change_attempts > sv_userinfo_penalty_attempts.value )
{
Con_Reportf( "%s: penalty set %f for %s\n", __func__,
cl->userinfo_penalty, cl->name );
cl->userinfo_penalty *= sv_userinfo_penalty_multiplier.value;
cl->userinfo_change_attempts = 0;
Con_Reportf( "%s: penalty set %f for %s\n", __func__, cl->userinfo_penalty, cl->name );
}
cl->userinfo_next_changetime = host.realtime + cl->userinfo_penalty * sv_userinfo_penalty_multiplier.value;
cl->userinfo_next_changetime = host.realtime + cl->userinfo_penalty;
return allow;
}
@@ -1895,10 +1908,13 @@ static void SV_UserinfoChanged( sv_client_t *cl )
val = Info_ValueForKey( cl->userinfo, "cl_updaterate" );
if( COM_CheckString( val ))
if( COM_CheckString( val ) )
{
float rate = Q_atoi( val );
cl->cl_updaterate = 1.0 / bound( sv_minupdaterate.value, rate, sv_maxupdaterate.value );
if( Q_atoi( val ) != 0 )
{
cl->cl_updaterate = 1.0 / bound( sv_minupdaterate.value, Q_atoi( val ), sv_maxupdaterate.value );
}
else cl->cl_updaterate = 0.0;
}
// call prog code to allow overrides
@@ -3163,7 +3179,7 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
}
else if( !Q_strcmp( pcmd, C2S_GETCHALLENGE ))
{
SV_SendChallenge( from );
SV_GetChallenge( from );
}
else if( !Q_strcmp( pcmd, C2S_CONNECT ))
{

View File

@@ -573,7 +573,7 @@ static void SV_Kick_f( void )
sv_client_t *cl;
const char *param;
if( Cmd_Argc() < 2 )
if( Cmd_Argc() != 2 )
{
Con_Printf( S_USAGE "kick <#id|name> [reason]\n" );
return;

View File

@@ -2379,7 +2379,7 @@ void GAME_EXPORT pfnClientCommand( edict_t* pEdict, char* szFmt, ... )
if( sv.state != ss_active )
return; // early out
if(( cl = SV_ClientFromEdict( pEdict, false )) == NULL )
if(( cl = SV_ClientFromEdict( pEdict, true )) == NULL )
{
Con_Printf( S_ERROR "stuffcmd: client is not spawned!\n" );
return;
@@ -4600,7 +4600,7 @@ static void GAME_EXPORT pfnQueryClientCvarValue( const edict_t *player, const ch
if( !COM_CheckString( cvarName ))
return;
if(( cl = SV_ClientFromEdict( player, false )) != NULL )
if(( cl = SV_ClientFromEdict( player, true )) != NULL )
{
MSG_BeginServerCmd( &cl->netchan.message, svc_querycvarvalue );
MSG_WriteString( &cl->netchan.message, cvarName );
@@ -4627,7 +4627,7 @@ static void GAME_EXPORT pfnQueryClientCvarValue2( const edict_t *player, const c
if( !COM_CheckString( cvarName ))
return;
if(( cl = SV_ClientFromEdict( player, false )) != NULL )
if(( cl = SV_ClientFromEdict( player, true )) != NULL )
{
MSG_BeginServerCmd( &cl->netchan.message, svc_querycvarvalue2 );
MSG_WriteLong( &cl->netchan.message, requestID );

View File

@@ -1027,9 +1027,6 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean ba
svs.timestart = Sys_DoubleTime();
svs.spawncount++; // any partially connected client will be restarted
for( i = 0; i < ARRAYSIZE( svs.challenge_salt ); i++ )
svs.challenge_salt[i] = COM_RandomLong( 0, 0x7FFFFFFE );
cycle = Cvar_VariableString( "mapchangecfgfile" );
if( COM_CheckString( cycle ))

View File

@@ -601,7 +601,7 @@ static void SV_FindTouchedLeafs( edict_t *ent, model_t *mod, mnode_t *node, int
// add an efrag if the node is a leaf
if( node->contents < 0 )
{
if( ent->num_leafs >= MAX_ENT_LEAFS( FBitSet( mod->flags, MODEL_QBSP2 )))
if( ent->num_leafs > MAX_ENT_LEAFS( FBitSet( mod->flags, MODEL_QBSP2 )))
{
// continue counting leafs,
// so we know how many it's overrun

View File

@@ -453,83 +453,174 @@ int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p )
return sides;
}
void R_StudioCalcBones( int frame, float s, const mstudiobone_t *pbone, const mstudioanim_t *panim, const float *adj, vec3_t pos, vec4_t q )
/*
====================
StudioCalcBoneQuaternion
====================
*/
void R_StudioCalcBoneQuaternion( int frame, float s, const mstudiobone_t *pbone, const mstudioanim_t *panim, const float *adj, vec4_t q )
{
float v1[6], v2[6];
int i, max;
vec3_t angles1;
vec3_t angles2;
int j, k;
max = q != NULL ? 6 : 3;
for( i = 0; i < max; i++ )
for( j = 0; j < 3; j++ )
{
mstudioanimvalue_t *panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[i] );
int j = frame;
float fadj = 0.0f;
if( pbone->bonecontroller[i] >= 0 && adj != NULL )
fadj = adj[pbone->bonecontroller[i]];
if( panim->offset[i] == 0 )
if( !panim || panim->offset[j+3] == 0 )
{
v1[i] = v2[i] = pbone->value[i] + fadj;
continue;
}
if( panimvalue->num.total < panimvalue->num.valid )
j = 0;
while( panimvalue->num.total <= j )
{
j -= panimvalue->num.total;
panimvalue += panimvalue->num.valid + 1;
if( panimvalue->num.total < panimvalue->num.valid )
j = 0;
}
if( panimvalue->num.valid > j )
{
v1[i] = panimvalue[j + 1].value;
if( panimvalue->num.valid > j + 1 )
v2[i] = panimvalue[j + 2].value;
else if( panimvalue->num.total > j + 1 )
v2[i] = v1[i];
else
v2[i] = panimvalue[panimvalue->num.valid + 2].value;
angles2[j] = angles1[j] = pbone->value[j+3]; // default;
}
else
{
v1[i] = panimvalue[panimvalue->num.valid].value;
mstudioanimvalue_t *panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j+3]);
if( panimvalue->num.total > j + 1 )
v2[i] = v1[i];
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
v2[i] = panimvalue[panimvalue->num.valid + 2].value;
{
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];
}
v1[i] = pbone->value[i] + v1[i] * pbone->scale[i] + fadj;
v2[i] = pbone->value[i] + v2[i] * pbone->scale[i] + fadj;
if( pbone->bonecontroller[j+3] != -1 && adj != NULL )
{
angles1[j] += adj[pbone->bonecontroller[j+3]];
angles2[j] += adj[pbone->bonecontroller[j+3]];
}
}
if( !VectorCompare( v1, v2 ))
VectorLerp( v1, s, v2, pos );
else
VectorCopy( v1, pos );
if( q != NULL )
if( !VectorCompare( angles1, angles2 ))
{
if( !VectorCompare( &v1[3], &v2[3] ))
{
vec4_t q1, q2;
vec4_t q1, q2;
AngleQuaternion( &v1[3], q1, true );
AngleQuaternion( &v2[3], q2, true );
QuaternionSlerp( q1, q2, s, q );
}
else
{
AngleQuaternion( &v1[3], q, true );
}
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, const mstudiobone_t *pbone, const mstudioanim_t *panim, const 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 );
}
}

View File

@@ -168,8 +168,8 @@ void VectorsAngles( const vec3_t forward, const vec3_t right, const vec3_t up, v
void PlaneIntersect( const mplane_t *plane, const vec3_t p0, const vec3_t p1, vec3_t out );
qboolean SphereIntersect( const vec3_t vSphereCenter, float fSphereRadiusSquared, const vec3_t vLinePt, const vec3_t vLineDir );
void QuaternionSlerp( const vec4_t p, const vec4_t q, float t, vec4_t qt );
void R_StudioCalcBones( int frame, float s, const mstudiobone_t *pbone, const mstudioanim_t *panim, const float *adj, vec3_t pos, vec4_t q );
void R_StudioCalcBoneQuaternion( int frame, float s, const mstudiobone_t *pbone, const mstudioanim_t *panim, const float *adj, vec4_t q );
void R_StudioCalcBonePosition( int frame, float s, const mstudiobone_t *pbone, const mstudioanim_t *panim, const vec3_t adj, vec3_t pos );
int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p );
#define BOX_ON_PLANE_SIDE( emins, emaxs, p ) \
((( p )->type < 3 ) ? \

View File

@@ -2476,14 +2476,10 @@ static void R_SetupVBOArrayDlight( vboarray_t *vbo, texture_t *texture )
static void R_SetupVBOArrayDecalDlight( int decalcount )
{
if( vbos.decal_dlight_vbo )
{
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, vbos.decal_dlight_vbo );
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, vbos.decal_dlight_vbo );
#if !SPARSE_DECALS_UPLOAD
pglBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof( vbovertex_t ) * DECAL_VERTS_MAX * decalcount, vbos.decal_dlight, GL_STREAM_DRAW_ARB );
pglBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof( vbovertex_t ) * DECAL_VERTS_MAX * decalcount, vbos.decal_dlight , GL_STREAM_DRAW_ARB );
#endif
}
R_SetDecalMode( true );
// hack: fix decal dlights on gl_vbo_details == 2 (wrong state??)
/*if( mtst.details_enabled && mtst.tmu_dt != -1 )

View File

@@ -816,7 +816,10 @@ static void R_StudioCalcRotations( cl_entity_t *e, float pos[][3], vec4_t *q, ms
R_StudioCalcBoneAdj( dadt, adj, e->curstate.controller, e->latched.prevcontroller, e->mouth.mouthopen );
for( i = 0; i < m_pStudioHeader->numbones; i++, pbone++, panim++ )
R_StudioCalcBones( frame, s, pbone, panim, adj, pos[i], q[i] );
{
R_StudioCalcBoneQuaternion( frame, s, pbone, panim, adj, q[i] );
R_StudioCalcBonePosition( frame, s, pbone, panim, adj, pos[i] );
}
if( pseqdesc->motiontype & STUDIO_X ) pos[pseqdesc->motionbone][0] = 0.0f;
if( pseqdesc->motiontype & STUDIO_Y ) pos[pseqdesc->motionbone][1] = 0.0f;

View File

@@ -835,7 +835,10 @@ static void R_StudioCalcRotations( cl_entity_t *e, float pos[][3], vec4_t *q, ms
R_StudioCalcBoneAdj( dadt, adj, e->curstate.controller, e->latched.prevcontroller, e->mouth.mouthopen );
for( i = 0; i < m_pStudioHeader->numbones; i++, pbone++, panim++ )
R_StudioCalcBones( frame, s, pbone, panim, adj, pos[i], q[i] );
{
R_StudioCalcBoneQuaternion( frame, s, pbone, panim, adj, q[i] );
R_StudioCalcBonePosition( frame, s, pbone, panim, adj, pos[i] );
}
if( pseqdesc->motiontype & STUDIO_X )
pos[pseqdesc->motionbone][0] = 0.0f;

View File

@@ -21,6 +21,8 @@ build_engine()
die
fi
cat build/config.log
./waf build || die
}

11
wscript
View File

@@ -84,7 +84,7 @@ SUBDIRS = [
Subproject('filesystem'),
Subproject('stub/server'),
Subproject('dllemu'),
Subproject('3rdparty/libbacktrace'),
Subproject('3rdparty/libbacktrace', lambda x: not x.env.HAVE_SYSTEM_LIBBACKTRACE),
# disable only by engine feature, makes no sense to even parse subprojects in dedicated mode
Subproject('3rdparty/extras', lambda x: x.env.CLIENT and x.env.DEST_OS != 'android'),
@@ -485,8 +485,11 @@ def configure(conf):
conf.env.SHAREDIR = conf.env.LIBDIR = conf.env.BINDIR = conf.env.PREFIX
if not conf.options.BUILD_BUNDLED_DEPS:
# there was a check for system libbacktrace but we can't be sure if it supports fileline or not
# therefore, always build libbacktrace ourselves
frag='''#include <backtrace.h>
#include <backtrace-supported.h>
int main(int argc, char **argv) { return backtrace_create_state( argv[0], BACKTRACE_SUPPORTS_THREADS, 0, 0 ) != 0; }'''
conf.env.HAVE_SYSTEM_LIBBACKTRACE = conf.check_cc(lib='backtrace', fragment=frag, uselib_store='backtrace', mandatory=False)
if conf.env.CLIENT:
for i in ('ogg','opusfile','vorbis','vorbisfile'):
@@ -529,7 +532,7 @@ def build(bld):
# don't clean QtCreator files and reconfigure saved options
bld.clean_files = bld.bldnode.ant_glob('**',
excl='*.user configuration.py .lock* *conf_check_*/** config.log 3rdparty/libbacktrace/*.h %s/*' % Build.CACHE_DIR,
excl='*.user configuration.py .lock* *conf_check_*/** config.log %s/*' % Build.CACHE_DIR,
quiet=True, generator=True)
bld.load('xshlib')