Compare commits

...

40 Commits

Author SHA1 Message Date
Alibek Omarov
48bdd4238e engine: always include reason to server shutdown 2024-12-26 02:13:13 +03:00
Alibek Omarov
fd2b7e9197 engine: client: declare music command as overridable as the same command exists in HLU SDK 2024-12-26 01:16:48 +03:00
Alibek Omarov
0e42e5b9e3 engine: command: introduce new type of commands that can be overriden by a mod DLL for better compatibility 2024-12-26 01:15:32 +03:00
Alibek Omarov
65750f0cf3 engine: server: hack save fields that use types unsupported by Half-Life Unified SDK through array types 2024-12-26 00:36:28 +03:00
Alibek Omarov
6469b0a5f5 engine: common: shut up warn-unused-result on log write functions, only fetch system time for system logs when necessary 2024-12-24 11:27:34 +03:00
Alibek Omarov
4f98187e9a engine: move select-based stdin input function to platform/posix 2024-12-24 11:13:05 +03:00
Alibek Omarov
74c19a1557 engine: client: leave SDL2 client.dll detection for Windows only 2024-12-24 10:46:39 +03:00
Alibek Omarov
cfebee6ea8 engine: split crashhandler to win32 and posix versions 2024-12-24 10:37:49 +03:00
Alibek Omarov
bd0d6644e0 engine: move Sys_SendKeyEvents to platform/win32 2024-12-24 09:59:47 +03:00
Alibek Omarov
f41450127a Documentation: add note about pkg-config when compiling for Windows under Wine 2024-12-24 09:59:09 +03:00
Alibek Omarov
70897af362 public: add dll helpers to simplify basic interaction with exported functions lists 2024-12-23 04:43:15 +03:00
Alibek Omarov
f1d7101ad8 engine: client: get rid of NULL sentinels at the end of arrays 2024-12-22 07:43:26 +03:00
Alibek Omarov
ac9d960eef engine: common: get rid of NULL sentinels at the end of arrays 2024-12-22 07:22:10 +03:00
Alibek Omarov
0c471aecb1 engine: common: imagelib: get rid of NULL sentinels at the end of arrays 2024-12-22 07:21:06 +03:00
Alibek Omarov
72d0d70587 engine: server: get rid of NULL sentinels at the end of arrays 2024-12-22 07:12:32 +03:00
Alibek Omarov
bec526a77e utils: xar: fix xar build 2024-12-22 07:11:53 +03:00
Alibek Omarov
4d1119391a ref: gl: get rid of NULL sentinels at the end of arrays 2024-12-22 07:11:28 +03:00
Alibek Omarov
1dd622fcbb engine: client: keys: refactoring, remove NULL sentinels, make keys structs and few more functions private to keys.c file 2024-12-21 15:22:48 +03:00
Alibek Omarov
af4b64983a engine: fix a typo in Cmd_AddFilteredCommand flags passed to Cmd_AddCommandEx. Make them return Cmd_AddCommandEx value 2024-12-21 15:01:04 +03:00
Alibek Omarov
e751092555 engine: common: cmd: consider filtered buffer privileged when we're running local singleplayer game 2024-12-20 05:48:33 +03:00
Alibek Omarov
ce06b1d3d7 engine: client: allow CL_GetLocalPlayer to return NULL rather than halting whole server 2024-12-20 05:47:46 +03:00
Alibek Omarov
a834f4996f engine: move client adding functions to their appropriate subsystems and make them static. Make in-engine functions inlined. 2024-12-20 05:47:46 +03:00
Alibek Omarov
fdcf267fe3 engine: client: fix usermessage being removed because of case-sensitivity (message names are case-insensitive when transferred from server to client) 2024-12-20 03:05:14 +03:00
Alibek Omarov
7f2ebd1b5e engine: server: add command sv_list_messages to print all registered user messages 2024-12-20 02:37:38 +03:00
Alibek Omarov
68b2d9f269 engine: server: fix possible message number inconsistency if server requested it twice 2024-12-20 02:37:01 +03:00
Alibek Omarov
3f1eed9f59 engine: client: remove svc_goldsrc_* definitions for message that semantics matches Xash3D 49 protocol and instead use it's definitions 2024-12-20 01:51:24 +03:00
Alibek Omarov
0637dbaab1 engine: client: refactor and simplify CL_RegisterUserMessage 2024-12-20 01:51:24 +03:00
Alibek Omarov
85388e97c1 engine: client: add command cl_list_messages to print all registered user messages 2024-12-20 01:51:24 +03:00
Alibek Omarov
de961eb45e engine: client: use new extension for creating temporary files for demoheader 2024-12-19 07:10:02 +03:00
Alibek Omarov
3d60770b84 filesystem: add flag to open files in a RAM
On Linux, it uses memfd_create syscall that can be found on Linux 3.17 and
higher. By default memfds are executable, so we set MFD_NOEXEC_SEAL flag to
prevent execution at creation time.
2024-12-19 04:22:25 +03:00
Alibek Omarov
93c5853356 engine: server: merge SV_FindBestBaseline for normal entities and static entities into single function 2024-12-18 06:57:43 +03:00
Alibek Omarov
98e587285b engine: client: allocate static entities only when server sends static entity packet 2024-12-18 06:57:43 +03:00
Alibek Omarov
2aa13c8347 public: xash3d_mathlib: include string.h with memset definition 2024-12-17 21:58:42 +03:00
Alibek Omarov
53344771fd public: xash3d_mathlib: get rid of matrix identity global macros 2024-12-17 21:01:51 +03:00
Alibek Omarov
2373743920 public: mention FSF in copyright header, as some of the libc extensions callbacks were derived from glibc [skip ci] 2024-12-17 20:41:55 +03:00
Alibek Omarov
90a3497afe public: improve Q_strncat fallback implementation 2024-12-17 20:40:19 +03:00
Alibek Omarov
339aebb08c public: add Q_strnlen with fallback to memchr 2024-12-17 20:03:09 +03:00
Alibek Omarov
b4afe390d6 public: slight refactoring 2024-12-17 19:57:27 +03:00
Alibek Omarov
ca0c5f929a engine: slight refactoring of lightstyle handling functions 2024-12-17 17:04:26 +03:00
Alibek Omarov
48cc526c7e engine: client: fix possible svc_pings misparse by reading until null bit is encountered 2024-12-15 18:22:40 +03:00
57 changed files with 1632 additions and 1601 deletions

View File

@@ -5,5 +5,10 @@ This can be useful to test engine in Wine without using virtual machines or dual
0. Clone and install https://github.com/mstorsjo/msvc-wine (you can skip CMake part)
1. Set environment variable MSVC_WINE_PATH to the path to installed MSVC toolchain
2. Pre-load wine: `wineserver -k; wineserver -p; wine64 wineboot`
3. Run `./waf configure -T <build-type> --enable-wine-msvc --sdl2=../SDL2_VC`. Configuration step will take more time than usual.
3. Run `PKGCONFIG=/bin/false ./waf configure -T <build-type> --enable-wine-msvc --sdl2=../SDL2_VC`. Configuration step will take more time than usual.
4. .. other typical steps to build from console ...
> [!NOTE]
> Notice the usage of PKGCONFIG=/bin/false here. We're disabling pkg-config so we don't accidentally pull
> system-wide dependencies and force building them from source. In future builds we might set custom
> directory to pull dependencies from, like ffmpeg...

View File

@@ -232,6 +232,7 @@ typedef struct dll_info_s
{
const char *name; // name of library
const dllfunc_t *fcts; // list of dll exports
const size_t num_fcts;
qboolean crash; // crash if dll not found
void *link; // hinstance of loading library
} dll_info_t;

View File

@@ -30,10 +30,9 @@ static dllfunc_t msvfw_funcs[] =
{ "DrawDibOpen", (void **) &pDrawDibOpen },
{ "DrawDibDraw", (void **) &pDrawDibDraw },
{ "DrawDibClose", (void **) &pDrawDibClose },
{ NULL, NULL }
};
dll_info_t msvfw_dll = { "msvfw32.dll", msvfw_funcs, false };
dll_info_t msvfw_dll = { "msvfw32.dll", msvfw_funcs, ARRAYSIZE( msvfw_funcs ), false };
// msacm32.dll exports
static MMRESULT (_stdcall *pacmStreamOpen)( LPHACMSTREAM, HACMDRIVER, LPWAVEFORMATEX, LPWAVEFORMATEX, LPWAVEFILTER, DWORD, DWORD, DWORD );
@@ -51,10 +50,9 @@ static dllfunc_t msacm_funcs[] =
{ "acmStreamConvert", (void **) &pacmStreamConvert },
{ "acmStreamSize", (void **) &pacmStreamSize },
{ "acmStreamClose", (void **) &pacmStreamClose },
{ NULL, NULL }
};
dll_info_t msacm_dll = { "msacm32.dll", msacm_funcs, false };
dll_info_t msacm_dll = { "msacm32.dll", msacm_funcs, ARRAYSIZE( msacm_funcs ), false };
// avifil32.dll exports
static int (_stdcall *pAVIStreamInfo)( PAVISTREAM pavi, AVISTREAMINFO *psi, LONG lSize );
@@ -88,10 +86,9 @@ static dllfunc_t avifile_funcs[] =
{ "AVIStreamRelease", (void **) &pAVIStreamRelease },
{ "AVIStreamStart", (void **) &pAVIStreamStart },
{ "AVIStreamTimeToSample", (void **) &pAVIStreamTimeToSample },
{ NULL, NULL }
};
dll_info_t avifile_dll = { "avifil32.dll", avifile_funcs, false };
dll_info_t avifile_dll = { "avifil32.dll", avifile_funcs, ARRAYSIZE( avifile_funcs ), false };
typedef struct movie_state_s
{

View File

@@ -157,7 +157,7 @@ void CL_StartupDemoHeader( void )
{
CL_CloseDemoHeader();
cls.demoheader = FS_Open( "demoheader.tmp", "w+b", true );
cls.demoheader = FS_Open( "demoheader.tmp", "w+bm", true );
if( !cls.demoheader )
{
@@ -724,7 +724,7 @@ static void CL_DemoStartPlayback( int mode )
{
// NOTE: at this point demo is still valid
CL_Disconnect();
Host_ShutdownServer();
SV_Shutdown( "Server was killed due to demo playback start\n" );
Con_FastClose();
UI_SetActiveMenu( false );

View File

@@ -76,7 +76,6 @@ static const dllfunc_t cdll_exports[] =
{ "IN_ClearStates", (void **)&clgame.dllFuncs.IN_ClearStates },
{ "V_CalcRefdef", (void **)&clgame.dllFuncs.pfnCalcRefdef },
{ "KB_Find", (void **)&clgame.dllFuncs.KB_Find },
{ NULL, NULL }
};
// optional exports
@@ -91,7 +90,6 @@ static const dllfunc_t cdll_new_exports[] = // allowed only in SDK 2.3 and high
{ "IN_ClientTouchEvent", (void **)&clgame.dllFuncs.pfnTouchEvent}, // Xash3D FWGS ext
{ "IN_ClientMoveEvent", (void **)&clgame.dllFuncs.pfnMoveEvent}, // Xash3D FWGS ext
{ "IN_ClientLookEvent", (void **)&clgame.dllFuncs.pfnLookEvent}, // Xash3D FWGS ext
{ NULL, NULL }
};
static void pfnSPR_DrawHoles( int frame, int x, int y, const wrect_t *prc );
@@ -976,7 +974,7 @@ static void CL_ClearUserMessage( char *pszName, int svc_num )
int i;
for( i = 0; i < MAX_USER_MESSAGES && clgame.msg[i].name[0]; i++ )
if( ( clgame.msg[i].number == svc_num ) && Q_strcmp( clgame.msg[i].name, pszName ) )
if( ( clgame.msg[i].number == svc_num ) && Q_stricmp( clgame.msg[i].name, pszName ) )
clgame.msg[i].number = 0;
}
@@ -1046,7 +1044,7 @@ void CL_InitEdicts( int maxclients )
cls.num_client_entities = CL_UPDATE_BACKUP * NUM_PACKET_ENTITIES;
cls.packet_entities = Mem_Realloc( clgame.mempool, cls.packet_entities, sizeof( entity_state_t ) * cls.num_client_entities );
clgame.entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * clgame.maxEntities );
clgame.static_entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES );
clgame.static_entities = NULL; // will be initialized later
clgame.numStatics = 0;
if(( clgame.maxRemapInfos - 1 ) != clgame.maxEntities )
@@ -1765,6 +1763,17 @@ static cvar_t *GAME_EXPORT pfnCvar_RegisterClientVariable( const char *szName, c
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_CLIENTDLL, Cvar_BuildAutoDescription( szName, flags|FCVAR_CLIENTDLL ));
}
static int GAME_EXPORT Cmd_AddClientCommand( const char *cmd_name, xcommand_t function )
{
int flags = CMD_CLIENTDLL;
// a1ba: try to mitigate outdated client.dll vulnerabilities
if( !Q_stricmp( cmd_name, "motd_write" ))
flags |= CMD_PRIVILEGED;
return Cmd_AddCommandEx( cmd_name, function, "client command", flags, __func__ );
}
/*
=============
pfnHookUserMsg
@@ -2698,17 +2707,6 @@ static const char *pfnGetGameDirectory( void )
return szGetGameDir;
}
/*
=============
Key_LookupBinding
=============
*/
static const char *Key_LookupBinding( const char *pBinding )
{
return Key_KeynumToString( Key_GetKey( pBinding ));
}
/*
=============
pfnGetLevelName
@@ -4007,9 +4005,10 @@ void CL_UnloadProgs( void )
qboolean CL_LoadProgs( const char *name )
{
static playermove_t gpMove;
const dllfunc_t *func;
CL_EXPORT_FUNCS GetClientAPI; // single export
qboolean critical_exports = true;
CL_EXPORT_FUNCS GetClientAPI; // single export
qboolean valid_single_export = false;
qboolean missed_exports = false;
int i;
if( clgame.hInstance ) CL_UnloadProgs();
@@ -4020,36 +4019,19 @@ qboolean CL_LoadProgs( const char *name )
clgame.mempool = Mem_AllocPool( "Client Edicts Zone" );
clgame.entities = NULL;
// a1ba: we need to check if client.dll has direct dependency on SDL2
// and if so, disable relative mouse mode
#if XASH_WIN32 && !XASH_64BIT
if( ( clgame.client_dll_uses_sdl = COM_CheckLibraryDirectDependency( name, OS_LIB_PREFIX "SDL2." OS_LIB_EXT, false ) ) )
{
Con_Printf( S_NOTE "%s uses SDL2 for mouse input\n", name );
}
else
{
Con_Printf( S_NOTE "%s uses Windows API for mouse input\n", name );
}
#else
// this doesn't mean other platforms uses SDL2 in any case
// it just helps input code to stay platform-independent
clgame.client_dll_uses_sdl = true;
clgame.client_dll_uses_sdl = COM_CheckLibraryDirectDependency( name, OS_LIB_PREFIX "SDL2." OS_LIB_EXT, false );
Con_Printf( S_NOTE "%s uses %s for mouse input\n", name, clgame.client_dll_uses_sdl ? "SDL2" : "Windows API" );
#endif
// NOTE: important stuff!
// vgui must startup BEFORE loading client.dll to avoid get error ERROR_NOACESS
// during LoadLibrary
// vgui must startup BEFORE loading client.dll to avoid get error ERROR_NOACESS during LoadLibrary
if( !GI->internal_vgui_support && VGui_LoadProgs( NULL ))
{
VGui_Startup( refState.width, refState.height );
}
else
{
// we failed to load vgui_support, but let's probe client.dll for support anyway
GI->internal_vgui_support = true;
}
GI->internal_vgui_support = true; // we failed to load vgui_support, but let's probe client.dll for support anyway
clgame.hInstance = COM_LoadLibrary( name, false, false );
@@ -4058,13 +4040,10 @@ qboolean CL_LoadProgs( const char *name )
// delayed vgui initialization for internal support
if( GI->internal_vgui_support && VGui_LoadProgs( clgame.hInstance ))
{
VGui_Startup( refState.width, refState.height );
}
// clear exports
for( func = cdll_exports; func && func->name; func++ )
*func->func = NULL;
ClearExports( cdll_exports, ARRAYSIZE( cdll_exports ));
// trying to get single export
if(( GetClientAPI = (void *)COM_GetProcAddress( clgame.hInstance, "GetClientAPI" )) != NULL )
@@ -4082,56 +4061,44 @@ qboolean CL_LoadProgs( const char *name )
CL_GetSecuredClientAPI( GetClientAPI );
}
if ( GetClientAPI != NULL )
{
// check critical functions again
for( func = cdll_exports; func && func->name; func++ )
{
if( func->func == NULL )
break; // BAH critical function was missed
}
if( GetClientAPI != NULL ) // check critical functions again
valid_single_export = ValidateExports( cdll_exports, ARRAYSIZE( cdll_exports ));
// because all the exports are loaded through function 'F"
if( !func || !func->name )
critical_exports = false;
}
for( func = cdll_exports; func && func->name != NULL; func++ )
for( i = 0; i < ARRAYSIZE( cdll_exports ); i++ )
{
if( *func->func != NULL )
continue; // already get through 'F'
if( *(cdll_exports[i].func) != NULL )
continue; // already gott through 'F' or 'GetClientAPI'
// functions are cleared before all the extensions are evaluated
if(( *func->func = (void *)COM_GetProcAddress( clgame.hInstance, func->name )) == NULL )
if(( *(cdll_exports[i].func) = (void *)COM_GetProcAddress( clgame.hInstance, cdll_exports[i].name )) == NULL )
{
Con_Reportf( "%s: failed to get address of %s proc\n", __func__, func->name );
Con_Reportf( S_ERROR "%s: failed to get address of %s proc\n", __func__, cdll_exports[i].name );
if( critical_exports )
{
COM_FreeLibrary( clgame.hInstance );
clgame.hInstance = NULL;
return false;
}
// print all not found exports at once, for debug
missed_exports = true;
}
}
if( missed_exports )
{
COM_FreeLibrary( clgame.hInstance );
clgame.hInstance = NULL;
return false;
}
// it may be loaded through 'GetClientAPI' so we don't need to clear them
if( critical_exports )
{
// clear new exports
for( func = cdll_new_exports; func && func->name; func++ )
*func->func = NULL;
}
if( !valid_single_export )
ClearExports( cdll_new_exports, ARRAYSIZE( cdll_new_exports ));
for( func = cdll_new_exports; func && func->name != NULL; func++ )
for( i = 0; i < ARRAYSIZE( cdll_new_exports ); i++ )
{
if( *func->func != NULL )
continue; // already get through 'F'
if( *(cdll_new_exports[i].func) != NULL )
continue; // already gott through 'F' or 'GetClientAPI'
// functions are cleared before all the extensions are evaluated
// NOTE: new exports can be missed without stop the engine
if(( *func->func = (void *)COM_GetProcAddress( clgame.hInstance, func->name )) == NULL )
Con_Reportf( "%s: failed to get address of %s proc\n", __func__, func->name );
if(( *(cdll_new_exports[i].func) = (void *)COM_GetProcAddress( clgame.hInstance, cdll_new_exports[i].name )) == NULL )
Con_Reportf( S_WARN "%s: failed to get address of %s proc\n", __func__, cdll_new_exports[i].name );
}
if( !clgame.dllFuncs.pfnInitialize( &gEngfuncs, CLDLL_INTERFACE_VERSION ))

View File

@@ -694,6 +694,11 @@ static cvar_t *GAME_EXPORT pfnCvar_RegisterGameUIVariable( const char *szName, c
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_GAMEUIDLL, Cvar_BuildAutoDescription( szName, flags|FCVAR_GAMEUIDLL ));
}
static int GAME_EXPORT Cmd_AddGameUICommand( const char *cmd_name, xcommand_t function )
{
return Cmd_AddCommandEx( cmd_name, function, "gameui command", CMD_GAMEUIDLL, __func__ );
}
/*
=============
pfnClientCmd

View File

@@ -1401,7 +1401,8 @@ static void CL_Connect_f( void )
Q_strncpy( server, Cmd_Argv( 1 ), sizeof( server ));
// if running a local server, kill it and reissue
if( SV_Active( )) Host_ShutdownServer();
if( SV_Active( ))
SV_Shutdown( "Server was killed due to connection to remote server\n" );
NET_Config( true, !cl_nat.value ); // allow remote
Con_Printf( "server %s\n", server );
@@ -3326,6 +3327,22 @@ static void CL_Escape_f( void )
else UI_SetActiveMenu( true );
}
static void CL_ListMessages_f( void )
{
int i;
Con_Printf( "num size name\n" );
for( i = 0; i < MAX_USER_MESSAGES; i++ )
{
if( !COM_CheckStringEmpty( clgame.msg[i].name ))
break;
Con_Printf( "%3d\t%3d\t%s\n", clgame.msg[i].number, clgame.msg[i].size, clgame.msg[i].name );
}
Con_Printf( "Total %i messages\n", i );
}
/*
=================
CL_InitLocal
@@ -3483,6 +3500,7 @@ static void CL_InitLocal( void )
Cmd_AddCommand( "richpresence_gamemode", Cmd_Null_f, "compatibility command, does nothing" );
Cmd_AddCommand( "richpresence_update", Cmd_Null_f, "compatibility command, does nothing" );
Cmd_AddCommand( "cl_list_messages", CL_ListMessages_f, "list registered user messages" );
}
//============================================================================

View File

@@ -311,10 +311,13 @@ static client entity
static void CL_ParseStaticEntity( sizebuf_t *msg )
{
int i, newnum;
entity_state_t from, to;
const entity_state_t from = { 0 };
entity_state_t to;
cl_entity_t *ent;
memset( &from, 0, sizeof( from ));
if( !clgame.static_entities )
clgame.static_entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES );
newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
MSG_ReadDeltaEntity( msg, &from, &to, 0, DELTA_STATIC, cl.mtime[0] );
@@ -1424,37 +1427,31 @@ register new user message or update existing
void CL_RegisterUserMessage( sizebuf_t *msg, connprotocol_t proto )
{
char *pszName;
int svc_num, size, bits;
svc_num = MSG_ReadByte( msg );
char szName[17];
int size;
int svc_num = MSG_ReadByte( msg );
if( proto == PROTO_LEGACY || proto == PROTO_GOLDSRC )
{
size = MSG_ReadByte( msg );
bits = 8;
if( size == UINT8_MAX )
size = -1;
}
else
{
size = MSG_ReadWord( msg );
bits = 16;
if( size == UINT16_MAX )
size = -1;
}
if( proto == PROTO_GOLDSRC )
{
static char szName[17];
MSG_ReadBytes( msg, szName, sizeof( szName ) - 1 );
szName[16] = 0;
pszName = szName;
}
else pszName = MSG_ReadString( msg );
// important stuff
if( size == ( BIT( bits ) - 1 ) )
size = -1;
svc_num = bound( 0, svc_num, 255 );
CL_LinkUserMessage( pszName, svc_num, size );
}
@@ -1593,17 +1590,23 @@ collect pings and packet lossage from clients
*/
void CL_UpdateUserPings( sizebuf_t *msg )
{
int i, slot;
player_info_t *player;
for( i = 0; i < MAX_CLIENTS; i++ )
// a1ba: there was a MAX_PLAYERS check but it doesn't make sense
// because pings message always ends by null bit
while( 1 )
{
if( !MSG_ReadOneBit( msg )) break; // end of message
int slot;
player_info_t *player;
if( !MSG_ReadOneBit( msg ))
break; // end of message
slot = MSG_ReadUBitLong( msg, MAX_CLIENT_BITS );
if( slot >= MAX_CLIENTS )
if( unlikely( slot >= MAX_CLIENTS ))
{
Host_Error( "%s: svc_pings > MAX_CLIENTS\n", __func__ );
return;
}
player = &cl.players[slot];
player->ping = MSG_ReadUBitLong( msg, 12 );

View File

@@ -33,10 +33,12 @@ static client entity
static void CL_LegacyParseStaticEntity( sizebuf_t *msg )
{
int i;
entity_state_t state;
entity_state_t state = { 0 };
cl_entity_t *ent;
memset( &state, 0, sizeof( state ));
if( !clgame.static_entities )
clgame.static_entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES );
state.modelindex = MSG_ReadShort( msg );
state.sequence = MSG_ReadByte( msg );
state.frame = MSG_ReadByte( msg );

View File

@@ -615,7 +615,7 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
case svc_setangle:
CL_ParseSetAngle( msg );
break;
case svc_goldsrc_serverinfo:
case svc_serverdata:
Cbuf_Execute(); // make sure any stuffed commands are done
CL_ParseServerData( msg, PROTO_GOLDSRC );
break;
@@ -625,7 +625,7 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
case svc_updateuserinfo:
CL_UpdateUserinfo( msg, PROTO_GOLDSRC );
break;
case svc_goldsrc_deltadescription:
case svc_deltatable:
Delta_ParseTableField_GS( msg );
break;
case svc_clientdata:
@@ -687,7 +687,7 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
case svc_addangle:
CL_ParseAddAngle( msg );
break;
case svc_goldsrc_newusermsg:
case svc_usermessage:
CL_RegisterUserMessage( msg, PROTO_GOLDSRC );
break;
case svc_packetentities:
@@ -709,7 +709,7 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
CL_ParseResourceList( msg, PROTO_GOLDSRC );
MSG_EndBitWriting( msg );
break;
case svc_goldsrc_newmovevars:
case svc_deltamovevars:
CL_ParseNewMovevars( msg );
break;
case svc_resourcerequest:
@@ -749,10 +749,10 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
Con_Reportf( S_ERROR "%s: svc_goldsrc_timescale: implement me!\n", __func__ );
MSG_ReadFloat( msg );
break;
case svc_goldsrc_sendcvarvalue:
case svc_querycvarvalue:
CL_ParseCvarValue( msg, false, PROTO_GOLDSRC );
break;
case svc_goldsrc_sendcvarvalue2:
case svc_querycvarvalue2:
CL_ParseCvarValue( msg, true, PROTO_GOLDSRC );
break;
case svc_exec:

View File

@@ -628,11 +628,12 @@ CL_ParseStaticEntity
*/
static void CL_ParseQuakeStaticEntity( sizebuf_t *msg )
{
entity_state_t state;
entity_state_t state = { 0 };
cl_entity_t *ent;
int i;
memset( &state, 0, sizeof( state ));
if( !clgame.static_entities )
clgame.static_entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES );
state.modelindex = MSG_ReadByte( msg );
state.frame = MSG_ReadByte( msg );

View File

@@ -124,7 +124,7 @@ void SCR_DrawPos( void )
if( cls.state != ca_active || !cl_showpos.value || cl.background )
return;
ent = CL_EDICT_NUM( cl.playernum + 1 );
ent = CL_GetLocalPlayer();
speed = VectorLength( cl.simvel );
Q_snprintf( msg, MAX_SYSPATH,

View File

@@ -2427,18 +2427,18 @@ static void CL_ClearLightStyles( void )
void CL_SetLightstyle( int style, const char *s, float f )
{
int i, k;
lightstyle_t *ls;
float val1, val2;
int i;
lightstyle_t *ls;
Assert( s != NULL );
Assert( style >= 0 && style < MAX_LIGHTSTYLES );
if( unlikely( style < 0 || style >= MAX_LIGHTSTYLES ))
{
Con_Printf( S_WARN "%s: ignored invalid lightstyle id %d\n", style );
return;
}
ls = &cl.lightstyles[style];
Q_strncpy( ls->pattern, s, sizeof( ls->pattern ));
ls->length = Q_strlen( s );
ls->length = Q_strncpy( ls->pattern, s, sizeof( ls->pattern ));
ls->time = f; // set local time
for( i = 0; i < ls->length; i++ )
@@ -2448,10 +2448,10 @@ void CL_SetLightstyle( int style, const char *s, float f )
// check for allow interpolate
// NOTE: fast flickering styles looks ugly when interpolation is running
for( k = 0; k < (ls->length - 1); k++ )
for( i = 0; i < ( ls->length - 1 ); i++ )
{
val1 = ls->map[(k+0) % ls->length];
val2 = ls->map[(k+1) % ls->length];
float val1 = ls->map[( i + 0 ) % ls->length];
float val2 = ls->map[( i + 1 ) % ls->length];
if( fabs( val1 - val2 ) > STYLE_LERPING_THRESHOLD )
{
@@ -2471,8 +2471,8 @@ DLIGHT MANAGEMENT
==============================================================
*/
dlight_t cl_dlights[MAX_DLIGHTS];
dlight_t cl_elights[MAX_ELIGHTS];
static dlight_t cl_dlights[MAX_DLIGHTS];
static dlight_t cl_elights[MAX_ELIGHTS];
/*
================

View File

@@ -495,7 +495,9 @@ typedef struct
cl_entity_t viewent; // viewmodel
#if XASH_WIN32
qboolean client_dll_uses_sdl;
#endif
} clgame_static_t;
typedef struct
@@ -881,10 +883,12 @@ static inline qboolean CL_IsThirdPerson( void )
static inline cl_entity_t *CL_GetLocalPlayer( void )
{
cl_entity_t *player;
cl_entity_t *player = CL_GetEntityByIndex( cl.playernum + 1 );
player = CL_EDICT_NUM( cl.playernum + 1 );
Assert( player != NULL );
// HACKHACK: GoldSrc doesn't do this, but some mods actually check it for null pointer
// this is a lesser evil than changing semantics of HUD_VidInit and call it after entities are allocated
if( !player )
Con_Printf( S_WARN "%s: client entities are not initialized yet! Returning NULL...\n", __func__ );
return player;
}
@@ -1195,10 +1199,9 @@ void Key_Init( void );
void Key_WriteBindings( file_t *f );
const char *Key_GetBinding( int keynum );
void Key_SetBinding( int keynum, const char *binding );
const char *Key_LookupBinding( const char *pBinding );
void Key_ClearStates( void );
const char *Key_KeynumToString( int keynum );
int Key_StringToKeynum( const char *str );
int Key_GetKey( const char *binding );
void Key_EnumCmds_f( void );
void Key_SetKeyDest( int key_dest );
void Key_EnableTextInput( qboolean enable, qboolean force );

View File

@@ -633,7 +633,7 @@ Called every frame, even if not generating commands
*/
void Host_InputFrame( void )
{
Sys_SendKeyEvents ();
Platform_SendKeyEvents();
IN_Commands();

View File

@@ -34,9 +34,9 @@ typedef struct keyname_s
const char *binding; // default bind
} keyname_t;
enginekey_t keys[256];
static enginekey_t keys[256];
keyname_t keynames[] =
static const keyname_t keynames[] =
{
{"TAB", K_TAB, "" },
{"ENTER", K_ENTER, "" },
@@ -139,7 +139,6 @@ keyname_t keynames[] =
// raw semicolon seperates commands
{"SEMICOLON", ';', "" },
{NULL, 0, NULL },
};
static void OSK_EnableTextInput( qboolean enable, qboolean force );
@@ -172,48 +171,25 @@ the K_* names are matched up.
to be configured even if they don't have defined names.
===================
*/
int Key_StringToKeynum( const char *str )
static int Key_StringToKeynum( const char *str )
{
keyname_t *kn;
int i;
if( !str || !str[0] ) return -1;
if( !str[1] ) return str[0];
if( !str || !str[0] )
return -1;
if( !str[1] )
return str[0];
// check for hex code
if( str[0] == '0' && str[1] == 'x' && Q_strlen( str ) == 4 )
{
int n1, n2;
n1 = str[2];
if( n1 >= '0' && n1 <= '9' )
{
n1 -= '0';
}
else if( n1 >= 'a' && n1 <= 'f' )
{
n1 = n1 - 'a' + 10;
}
else n1 = 0;
n2 = str[3];
if( n2 >= '0' && n2 <= '9' )
{
n2 -= '0';
}
else if( n2 >= 'a' && n2 <= 'f' )
{
n2 = n2 - 'a' + 10;
}
else n2 = 0;
return n1 * 16 + n2;
}
return COM_Nibble( str[2] ) << 4 | COM_Nibble( str[3] );
// scan for a text match
for( kn = keynames; kn->name; kn++ )
for( i = 0; i < ARRAYSIZE( keynames ); i++ )
{
if( !Q_stricmp( str, kn->name ))
return kn->keynum;
if( !Q_stricmp( str, keynames[i].name ))
return keynames[i].keynum;
}
return -1;
@@ -229,12 +205,14 @@ given keynum.
*/
const char *Key_KeynumToString( int keynum )
{
keyname_t *kn;
static char tinystr[5];
int i, j;
if ( keynum == -1 ) return "<KEY NOT FOUND>";
if ( keynum < 0 || keynum > 255 ) return "<OUT OF RANGE>";
if( keynum == -1 )
return "<KEY NOT FOUND>";
if( keynum < 0 || keynum > 255 )
return "<OUT OF RANGE>";
// check for printable ascii (don't use quote)
if( keynum > 32 && keynum < 127 && keynum != '"' && keynum != ';' && keynum != K_SCROLLOCK )
@@ -245,10 +223,10 @@ const char *Key_KeynumToString( int keynum )
}
// check for a key string
for( kn = keynames; kn->name; kn++ )
for( i = 0; i < ARRAYSIZE( keynames ); i++ )
{
if( keynum == kn->keynum )
return kn->name;
if( keynum == keynames[i].keynum )
return keynames[i].name;
}
// make a hex string
@@ -301,7 +279,7 @@ const char *Key_GetBinding( int keynum )
Key_GetKey
===================
*/
int Key_GetKey( const char *pBinding )
static int Key_GetKey( const char *pBinding )
{
int i, len;
const char *p;
@@ -327,6 +305,17 @@ int Key_GetKey( const char *pBinding )
return -1;
}
/*
=============
Key_LookupBinding
=============
*/
const char *Key_LookupBinding( const char *pBinding )
{
return Key_KeynumToString( Key_GetKey( pBinding ));
}
/*
===================
Key_Unbind_f
@@ -380,7 +369,6 @@ Key_Reset_f
*/
static void Key_Reset_f( void )
{
keyname_t *kn;
int i;
// clear all keys first
@@ -391,8 +379,8 @@ static void Key_Reset_f( void )
}
// apply default values
for( kn = keynames; kn->name; kn++ )
Key_SetBinding( kn->keynum, kn->binding );
for( i = 0; i < ARRAYSIZE( keynames ); i++ )
Key_SetBinding( keynames[i].keynum, keynames[i].binding );
}
/*
@@ -500,7 +488,7 @@ Key_Init
*/
void Key_Init( void )
{
keyname_t *kn;
int i;
// register our functions
Cmd_AddRestrictedCommand( "bind", Key_Bind_f, "binds a command to the specified key in bindmap" );
@@ -511,7 +499,8 @@ void Key_Init( void )
Cmd_AddCommand( "makehelp", Key_EnumCmds_f, "write help.txt that contains all console cvars and cmds" );
// setup default binding. "unbindall" from config.cfg will be reset it
for( kn = keynames; kn->name; kn++ ) Key_SetBinding( kn->keynum, kn->binding );
for( i = 0; i < ARRAYSIZE( keynames ); i++ )
Key_SetBinding( keynames[i].keynum, keynames[i].binding );
Cvar_RegisterVariable( &osk_enable );
Cvar_RegisterVariable( &key_rotate );
@@ -909,17 +898,16 @@ A helper function if platform input doesn't support text mode properly
*/
int Key_ToUpper( int keynum )
{
keynum = Q_toupper( keynum );
if( keynum == '-' )
keynum = '_';
return '_';
if( keynum == '=' )
keynum = '+';
return '+';
if( keynum == ';' )
keynum = ':';
return ':';
if( keynum == '\'' )
keynum = '"';
return '"';
return keynum;
return Q_toupper( keynum );
}
/* On-screen keyboard:

View File

@@ -181,6 +181,11 @@ static void pfnCvar_FullSet( const char *var_name, const char *value, int flags
Cvar_FullSet( var_name, value, flags | FCVAR_REFDLL );
}
static int Cmd_AddRefCommand( const char *cmd_name, xcommand_t function, const char *description )
{
return Cmd_AddCommandEx( cmd_name, function, description, CMD_REFDLL, __func__ );
}
static void pfnStudioEvent( const mstudioevent_t *event, const cl_entity_t *e )
{
clgame.dllFuncs.pfnStudioEvent( event, e );

View File

@@ -1944,7 +1944,8 @@ qboolean S_Init( void )
Cmd_AddCommand( "play2", S_Play2_f, "playing a group of specified sound files" ); // nehahra stuff
Cmd_AddCommand( "playvol", S_PlayVol_f, "playing a specified sound file with specified volume" );
Cmd_AddCommand( "stopsound", S_StopSound_f, "stop all sounds" );
Cmd_AddCommand( "music", S_Music_f, "starting a background track" );
// HLU SDK have command with the same name
Cmd_AddCommandWithFlags( "music", S_Music_f, "starting a background track", CMD_OVERRIDABLE );
Cmd_AddCommand( "soundlist", S_SoundList_f, "display loaded sounds" );
Cmd_AddCommand( "s_info", S_SoundInfo_f, "print sound system information" );
Cmd_AddCommand( "s_fade", S_SoundFade_f, "fade all sounds then stop all" );
@@ -1987,7 +1988,8 @@ void S_Shutdown( void )
Cmd_RemoveCommand( "play" );
Cmd_RemoveCommand( "playvol" );
Cmd_RemoveCommand( "stopsound" );
Cmd_RemoveCommand( "music" );
if( Cmd_Exists( "music" ))
Cmd_RemoveCommand( "music" );
Cmd_RemoveCommand( "soundlist" );
Cmd_RemoveCommand( "s_info" );
Cmd_RemoveCommand( "s_fade" );

View File

@@ -263,10 +263,16 @@ Cbuf_Execute
void Cbuf_Execute( void )
{
Cbuf_ExecuteCommandsFromBuffer( &cmd_text, true, -1 );
// a1ba: unlimited commands for filtered buffer per frame
// a1ba: goldsrc limits unprivileged commands per frame to 1 here
// I don't see any sense in restricting that at this moment
// but in future we may limit this
Cbuf_ExecuteCommandsFromBuffer( &filteredcmd_text, false, -1 );
// a1ba: there is little to no sense limit privileged commands in
// local game, as client runs server code anyway
// do this for singleplayer only though, to make it easier to catch
// possible bugs during local multiplayer testing
Cbuf_ExecuteCommandsFromBuffer( &filteredcmd_text, SV_Active() && SV_GetMaxClients() == 1, -1 );
}
/*
@@ -512,14 +518,14 @@ static void Cmd_UnAlias_f ( void )
=============================================================================
*/
typedef struct cmd_s
struct cmd_s
{
struct cmd_s *next;
char *name;
xcommand_t function;
int flags;
char *desc;
} cmd_t;
};
static int cmd_argc;
static const char *cmd_args = NULL;
@@ -670,8 +676,7 @@ void Cmd_TokenizeString( const char *text )
Cmd_AddCommandEx
============
*/
static int Cmd_AddCommandEx( const char *funcname, const char *cmd_name, xcommand_t function,
const char *cmd_desc, int iFlags )
int Cmd_AddCommandEx( const char *cmd_name, xcommand_t function, const char *cmd_desc, int iFlags, const char *funcname )
{
cmd_t *cmd, *cur, *prev;
@@ -688,11 +693,28 @@ static int Cmd_AddCommandEx( const char *funcname, const char *cmd_name, xcomman
return 0;
}
// fail if the command already exists
if( Cmd_Exists( cmd_name ))
// fail if the command already exists and cannot be overriden
cmd = Cmd_Exists( cmd_name );
if( cmd )
{
Con_DPrintf( S_ERROR "%s: %s already defined\n", funcname, cmd_name );
return 0;
// some mods register commands that share the name with some engine's commands
// when they aren't critical to keep engine running, we can let mods to override them
// unfortunately, we lose original command this way
if( FBitSet( cmd->flags, CMD_OVERRIDABLE ))
{
Mem_Free( cmd->desc );
cmd->desc = copystring( cmd_desc );
cmd->function = function;
cmd->flags = iFlags;
Con_DPrintf( S_WARN "%s: %s already defined but is allowed to be overriden\n", funcname, cmd_name );
return 1;
}
else
{
Con_DPrintf( S_ERROR "%s: %s already defined\n", funcname, cmd_name );
return 0;
}
}
// use a small malloc to avoid zone fragmentation
@@ -716,75 +738,6 @@ static int Cmd_AddCommandEx( const char *funcname, const char *cmd_name, xcomman
return 1;
}
/*
============
Cmd_AddCommand
============
*/
void Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc )
{
Cmd_AddCommandEx( __func__, cmd_name, function, cmd_desc, 0 );
}
/*
============
Cmd_AddRestrictedCommand
============
*/
void Cmd_AddRestrictedCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc )
{
Cmd_AddCommandEx( __func__, cmd_name, function, cmd_desc, CMD_PRIVILEGED );
}
/*
============
Cmd_AddServerCommand
============
*/
void GAME_EXPORT Cmd_AddServerCommand( const char *cmd_name, xcommand_t function )
{
Cmd_AddCommandEx( __func__, cmd_name, function, "server command", CMD_SERVERDLL );
}
/*
============
Cmd_AddClientCommand
============
*/
int GAME_EXPORT Cmd_AddClientCommand( const char *cmd_name, xcommand_t function )
{
int flags = CMD_CLIENTDLL;
// a1ba: try to mitigate outdated client.dll vulnerabilities
if( !Q_stricmp( cmd_name, "motd_write" ))
{
flags |= CMD_PRIVILEGED;
}
return Cmd_AddCommandEx( __func__, cmd_name, function, "client command", flags );
}
/*
============
Cmd_AddGameUICommand
============
*/
int GAME_EXPORT Cmd_AddGameUICommand( const char *cmd_name, xcommand_t function )
{
return Cmd_AddCommandEx( __func__, cmd_name, function, "gameui command", CMD_GAMEUIDLL );
}
/*
============
Cmd_AddRefCommand
============
*/
int Cmd_AddRefCommand( const char *cmd_name, xcommand_t function, const char *description )
{
return Cmd_AddCommandEx( __func__, cmd_name, function, description, CMD_REFDLL );
}
/*
============
Cmd_RemoveCommand
@@ -853,19 +806,18 @@ void Cmd_LookupCmds( void *buffer, void *ptr, setpair_t callback )
Cmd_Exists
============
*/
qboolean Cmd_Exists( const char *cmd_name )
cmd_t *Cmd_Exists( const char *cmd_name )
{
#if defined(XASH_HASHED_VARS)
return BaseCmd_Find( HM_CMD, cmd_name ) != NULL;
return BaseCmd_Find( HM_CMD, cmd_name );
#else
cmd_t *cmd;
for( cmd = cmd_functions; cmd; cmd = cmd->next )
{
if( !Q_strcmp( cmd_name, cmd->name ))
return true;
return cmd;
}
return false;
return NULL;
#endif
}

View File

@@ -612,7 +612,7 @@ COM_Nibble
Returns the 4 bit nibble for a hex character
==================
*/
static byte COM_Nibble( char c )
byte COM_Nibble( char c )
{
if(( c >= '0' ) && ( c <= '9' ))
{

View File

@@ -362,12 +362,13 @@ typedef struct host_parm_s
extern host_parm_t host;
#define CMD_SERVERDLL BIT( 0 ) // added by server.dll
#define CMD_CLIENTDLL BIT( 1 ) // added by client.dll
#define CMD_GAMEUIDLL BIT( 2 ) // added by GameUI.dll
#define CMD_PRIVILEGED BIT( 3 ) // only available in privileged mode
#define CMD_FILTERABLE BIT( 4 ) // filtered in unprivileged mode if cl_filterstuffcmd is 1
#define CMD_REFDLL BIT( 5 ) // added by ref.dll
#define CMD_SERVERDLL BIT( 0 ) // added by server.dll
#define CMD_CLIENTDLL BIT( 1 ) // added by client.dll
#define CMD_GAMEUIDLL BIT( 2 ) // added by GameUI.dll
#define CMD_PRIVILEGED BIT( 3 ) // only available in privileged mode
#define CMD_FILTERABLE BIT( 4 ) // filtered in unprivileged mode if cl_filterstuffcmd is 1
#define CMD_REFDLL BIT( 5 ) // added by ref.dll
#define CMD_OVERRIDABLE BIT( 6 ) // can be removed by DLLs if name matches
typedef void (*xcommand_t)( void );
@@ -418,6 +419,7 @@ byte *FS_LoadDirectFile( const char *path, fs_offset_t *filesizeptr )
//
// cmd.c
//
typedef struct cmd_s cmd_t;
void Cbuf_Clear( void );
void Cbuf_AddText( const char *text );
void Cbuf_AddTextf( const char *text, ... ) FORMAT_CHECK( 1 );
@@ -431,14 +433,25 @@ const char *Cmd_Args( void ) RETURNS_NONNULL;
const char *Cmd_Argv( int arg ) RETURNS_NONNULL;
void Cmd_Init( void );
void Cmd_Unlink( int group );
void Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc );
void Cmd_AddRestrictedCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc );
void Cmd_AddServerCommand( const char *cmd_name, xcommand_t function );
int Cmd_AddClientCommand( const char *cmd_name, xcommand_t function );
int Cmd_AddGameUICommand( const char *cmd_name, xcommand_t function );
int Cmd_AddRefCommand( const char *cmd_name, xcommand_t function, const char *description );
int Cmd_AddCommandEx( const char *cmd_name, xcommand_t function, const char *cmd_desc, int flags, const char *funcname );
static inline int Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc )
{
return Cmd_AddCommandEx( cmd_name, function, cmd_desc, 0, __func__ );
}
static inline int Cmd_AddRestrictedCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc )
{
return Cmd_AddCommandEx( cmd_name, function, cmd_desc, CMD_PRIVILEGED, __func__ );
}
static inline int Cmd_AddCommandWithFlags( const char *cmd_name, xcommand_t function, const char *cmd_desc, int flags )
{
return Cmd_AddCommandEx( cmd_name, function, cmd_desc, flags, __func__ );
}
void Cmd_RemoveCommand( const char *cmd_name );
qboolean Cmd_Exists( const char *cmd_name );
cmd_t *Cmd_Exists( const char *cmd_name );
void Cmd_LookupCmds( void *buffer, void *ptr, setpair_t callback );
int Cmd_ListMaps( search_t *t , char *lastmapname, size_t len );
void Cmd_TokenizeString( const char *text );
@@ -542,7 +555,6 @@ void Host_WriteServerConfig( const char *name );
void Host_WriteOpenGLConfig( void );
void Host_WriteVideoConfig( void );
void Host_WriteConfig( void );
void Host_ShutdownServer( void );
void Host_Error( const char *error, ... ) FORMAT_CHECK( 1 );
void Host_ValidateEngineFeatures( uint32_t mask, uint32_t features );
void Host_Frame( double time );
@@ -586,6 +598,7 @@ qboolean SV_Active( void );
*/
char *COM_MemFgets( byte *pMemFile, int fileSize, int *filePos, char *pBuffer, int bufferSize );
void COM_HexConvert( const char *pszInput, int nInputLength, byte *pOutput );
byte COM_Nibble( char c );
int COM_SaveFile( const char *filename, const void *data, int len );
byte *COM_LoadFileForMe( const char *filename, int *pLength ) MALLOC_LIKE( free, 1 );
qboolean COM_IsSafeFileToDownload( const char *filename );

View File

@@ -1040,7 +1040,6 @@ static const autocomplete_list_t cmd_list[] =
{ "map", 1, Cmd_GetMapList },
{ "cd", 1, Cmd_GetCDList },
{ "mp3", 1, Cmd_GetCDList },
{ NULL }, // termiantor
};
/*
@@ -1073,12 +1072,12 @@ for various cmds
*/
static qboolean Cmd_AutocompleteName( const char *source, int arg, char *buffer, size_t bufsize )
{
const autocomplete_list_t *list;
int i;
for( list = cmd_list; list->name; list++ )
for( i = 0; i < ARRAYSIZE( cmd_list ); i++ )
{
if( list->arg == arg && Cmd_CheckName( list->name ))
return list->func( source, buffer, bufsize );
if( cmd_list[i].arg == arg && Cmd_CheckName( cmd_list[i].name ))
return cmd_list[i].func( source, buffer, bufsize );
}
return false;

View File

@@ -1,558 +0,0 @@
/*
crashhandler.c - advanced crashhandler
Copyright (C) 2016 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.
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "common.h"
/*
================
Sys_Crash
Crash handler, called from system
================
*/
#if XASH_WIN32
#if DBGHELP
#pragma comment( lib, "dbghelp" )
#include <winnt.h>
#include <dbghelp.h>
#include <psapi.h>
#include <time.h>
#ifndef XASH_SDL
typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
#endif
static int Sys_ModuleName( HANDLE process, char *name, void *address, int len )
{
DWORD_PTR baseAddress = 0;
static HMODULE *moduleArray;
static unsigned int moduleCount;
LPBYTE moduleArrayBytes;
DWORD bytesRequired;
int i;
if( len < 3 )
return 0;
if( !moduleArray && EnumProcessModules( process, NULL, 0, &bytesRequired ) )
{
if ( bytesRequired )
{
moduleArrayBytes = (LPBYTE)LocalAlloc( LPTR, bytesRequired );
if( moduleArrayBytes && EnumProcessModules( process, (HMODULE *)moduleArrayBytes, bytesRequired, &bytesRequired ) )
{
moduleCount = bytesRequired / sizeof( HMODULE );
moduleArray = (HMODULE *)moduleArrayBytes;
}
}
}
for( i = 0; i < moduleCount; i++ )
{
MODULEINFO info;
GetModuleInformation( process, moduleArray[i], &info, sizeof(MODULEINFO) );
if( ( address > info.lpBaseOfDll ) &&
( (DWORD64)address < (DWORD64)info.lpBaseOfDll + (DWORD64)info.SizeOfImage ) )
return GetModuleBaseName( process, moduleArray[i], name, len );
}
return Q_snprintf( name, len, "???" );
}
static void Sys_StackTrace( PEXCEPTION_POINTERS pInfo )
{
char message[8192]; // match *nix Sys_Crash
int len = 0;
size_t i;
HANDLE process = GetCurrentProcess();
HANDLE thread = GetCurrentThread();
IMAGEHLP_LINE64 line;
DWORD dline = 0;
DWORD options;
CONTEXT context;
STACKFRAME64 stackframe;
DWORD image;
context = *pInfo->ContextRecord;
options = SymGetOptions();
options |= SYMOPT_DEBUG;
options |= SYMOPT_LOAD_LINES;
SymSetOptions( options );
SymInitialize( process, NULL, TRUE );
ZeroMemory( &stackframe, sizeof( STACKFRAME64 ));
#ifdef _M_IX86
image = IMAGE_FILE_MACHINE_I386;
stackframe.AddrPC.Offset = context.Eip;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.Ebp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Esp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
image = IMAGE_FILE_MACHINE_AMD64;
stackframe.AddrPC.Offset = context.Rip;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.Rsp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Rsp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif _M_IA64
image = IMAGE_FILE_MACHINE_IA64;
stackframe.AddrPC.Offset = context.StIIP;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.IntSp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrBStore.Offset = context.RsBSP;
stackframe.AddrBStore.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.IntSp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif _M_ARM
image = IMAGE_FILE_MACHINE_ARMNT;
stackframe.AddrPC.Offset = context.Pc;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.R11;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Sp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif _M_ARM64
image = IMAGE_FILE_MACHINE_ARM64;
stackframe.AddrPC.Offset = context.Pc;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.Fp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Sp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif
#error
#endif
len = Q_snprintf( message, sizeof( message ), "Ver: " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s, %s-%s)\n",
Q_buildnum(), Q_buildcommit(), Q_buildos(), Q_buildarch() );
len += Q_snprintf( message + len, 1024 - len, "Sys_Crash: address %p, code %p\n",
pInfo->ExceptionRecord->ExceptionAddress, (void*)pInfo->ExceptionRecord->ExceptionCode );
if( SymGetLineFromAddr64( process, (DWORD64)pInfo->ExceptionRecord->ExceptionAddress, &dline, &line ) )
{
len += Q_snprintf(message + len, 1024 - len, "Exception: %s:%d:%d\n",
(char*)line.FileName, (int)line.LineNumber, (int)dline);
}
if( SymGetLineFromAddr64( process, stackframe.AddrPC.Offset, &dline, &line ) )
{
len += Q_snprintf(message + len, 1024 - len,"PC: %s:%d:%d\n",
(char*)line.FileName, (int)line.LineNumber, (int)dline);
}
if( SymGetLineFromAddr64( process, stackframe.AddrFrame.Offset, &dline, &line ) )
{
len += Q_snprintf(message + len, 1024 - len,"Frame: %s:%d:%d\n",
(char*)line.FileName, (int)line.LineNumber, (int)dline);
}
for( i = 0; i < 25; i++ )
{
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
BOOL result = StackWalk64(
image, process, thread,
&stackframe, &context, NULL,
SymFunctionTableAccess64, SymGetModuleBase64, NULL);
DWORD64 displacement = 0;
if( !result )
break;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_SYM_NAME;
len += Q_snprintf( message + len, 1024 - len, "% 2d %p",
i, (void*)stackframe.AddrPC.Offset );
if( SymFromAddr( process, stackframe.AddrPC.Offset, &displacement, symbol ) )
{
len += Q_snprintf( message + len, 1024 - len, " %s ", symbol->Name );
}
if( SymGetLineFromAddr64( process, stackframe.AddrPC.Offset, &dline, &line ) )
{
len += Q_snprintf(message + len, 1024 - len,"(%s:%d:%d) ",
(char*)line.FileName, (int)line.LineNumber, (int)dline);
}
len += Q_snprintf( message + len, 1024 - len, "(");
len += Sys_ModuleName( process, message + len, (void*)stackframe.AddrPC.Offset, 1024 - len );
len += Q_snprintf( message + len, 1024 - len, ")\n");
}
#if XASH_SDL == 2
if( host.type != HOST_DEDICATED ) // let system to restart server automaticly
SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR, "Sys_Crash", message, host.hWnd );
#endif
Sys_PrintLog( message );
SymCleanup( process );
}
static void Sys_GetProcessName( char *processName, size_t bufferSize )
{
char fullpath[MAX_PATH];
GetModuleBaseName( GetCurrentProcess(), NULL, fullpath, sizeof( fullpath ) - 1 );
COM_FileBase( fullpath, processName, bufferSize );
}
static void Sys_GetMinidumpFileName( const char *processName, char *mdmpFileName, size_t bufferSize )
{
time_t currentUtcTime = time( NULL );
struct tm *currentLocalTime = localtime( &currentUtcTime );
Q_snprintf( mdmpFileName, bufferSize, "%s_%s_crash_%d%.2d%.2d_%.2d%.2d%.2d.mdmp",
processName,
Q_buildcommit(),
currentLocalTime->tm_year + 1900,
currentLocalTime->tm_mon + 1,
currentLocalTime->tm_mday,
currentLocalTime->tm_hour,
currentLocalTime->tm_min,
currentLocalTime->tm_sec);
}
static qboolean Sys_WriteMinidump(PEXCEPTION_POINTERS exceptionInfo, MINIDUMP_TYPE minidumpType)
{
HRESULT errorCode;
string processName;
string mdmpFileName;
MINIDUMP_EXCEPTION_INFORMATION minidumpInfo;
Sys_GetProcessName( processName, sizeof( processName ));
Sys_GetMinidumpFileName( processName, mdmpFileName, sizeof( mdmpFileName ));
SetLastError( NOERROR );
HANDLE fileHandle = CreateFile(
mdmpFileName, GENERIC_WRITE, FILE_SHARE_WRITE,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
errorCode = HRESULT_FROM_WIN32( GetLastError( ));
if( !SUCCEEDED( errorCode )) {
CloseHandle( fileHandle );
return false;
}
minidumpInfo.ThreadId = GetCurrentThreadId();
minidumpInfo.ExceptionPointers = exceptionInfo;
minidumpInfo.ClientPointers = FALSE;
qboolean status = MiniDumpWriteDump(
GetCurrentProcess(), GetCurrentProcessId(), fileHandle,
minidumpType, &minidumpInfo, NULL, NULL);
CloseHandle( fileHandle );
return status;
}
#endif /* DBGHELP */
LPTOP_LEVEL_EXCEPTION_FILTER oldFilter;
static long _stdcall Sys_Crash( PEXCEPTION_POINTERS pInfo )
{
// save config
if( host.status != HOST_CRASHED )
{
// check to avoid recursive call
host.crashed = true;
#ifdef XASH_SDL
SDL_SetWindowGrab( host.hWnd, SDL_FALSE );
#endif // XASH_SDL
#if DBGHELP
Sys_StackTrace( pInfo );
#else
Sys_Warn( "Sys_Crash: call %p at address %p", pInfo->ExceptionRecord->ExceptionAddress, pInfo->ExceptionRecord->ExceptionCode );
#endif
if( host.type == HOST_NORMAL )
CL_Crashed(); // tell client about crash
else host.status = HOST_CRASHED;
#if DBGHELP
if( Sys_CheckParm( "-minidumps" ))
{
int minidumpFlags = (
MiniDumpWithDataSegs |
MiniDumpWithCodeSegs |
MiniDumpWithHandleData |
MiniDumpWithFullMemory |
MiniDumpWithFullMemoryInfo |
MiniDumpWithIndirectlyReferencedMemory |
MiniDumpWithThreadInfo |
MiniDumpWithModuleHeaders);
if( !Sys_WriteMinidump( pInfo, (MINIDUMP_TYPE)minidumpFlags )) {
// fallback method, create minidump with minimal info in it
Sys_WriteMinidump( pInfo, MiniDumpWithDataSegs );
}
}
#endif
if( host_developer.value <= 0 )
{
// no reason to call debugger in release build - just exit
Sys_Quit();
return EXCEPTION_CONTINUE_EXECUTION;
}
// all other states keep unchanged to let debugger find bug
Sys_DestroyConsole();
}
if( oldFilter )
return oldFilter( pInfo );
return EXCEPTION_CONTINUE_EXECUTION;
}
void Sys_SetupCrashHandler( void )
{
SetErrorMode( SEM_FAILCRITICALERRORS ); // no abort/retry/fail errors
oldFilter = SetUnhandledExceptionFilter( Sys_Crash );
}
void Sys_RestoreCrashHandler( void )
{
// restore filter
if( oldFilter ) SetUnhandledExceptionFilter( oldFilter );
}
#elif XASH_FREEBSD || XASH_NETBSD || XASH_OPENBSD || XASH_ANDROID || XASH_LINUX
// Posix signal handler
#ifndef XASH_OPENBSD
#include <ucontext.h>
#endif
#include <signal.h>
#include <sys/mman.h>
#include "library.h"
#define STACK_BACKTRACE_STR "Stack backtrace:\n"
#define STACK_DUMP_STR "Stack dump:\n"
#define STACK_BACKTRACE_STR_LEN ( sizeof( STACK_BACKTRACE_STR ) - 1 )
#define STACK_DUMP_STR_LEN ( sizeof( STACK_DUMP_STR ) - 1 )
#define ALIGN( x, y ) (((uintptr_t) ( x ) + (( y ) - 1 )) & ~(( y ) - 1 ))
static struct sigaction oldFilter;
static int Sys_PrintFrame( char *buf, int len, int i, void *addr )
{
Dl_info dlinfo;
if( len <= 0 )
return 0; // overflow
if( dladdr( addr, &dlinfo ))
{
if( dlinfo.dli_sname )
return Q_snprintf( buf, len, "%2d: %p <%s+%lu> (%s)\n", i, addr, dlinfo.dli_sname,
(unsigned long)addr - (unsigned long)dlinfo.dli_saddr, dlinfo.dli_fname ); // print symbol, module and address
return Q_snprintf( buf, len, "%2d: %p (%s)\n", i, addr, dlinfo.dli_fname ); // print module and address
}
return Q_snprintf( buf, len, "%2d: %p\n", i, addr ); // print only address
}
static void Sys_Crash( int signal, siginfo_t *si, void *context)
{
void *pc = NULL, **bp = NULL, **sp = NULL; // this must be set for every OS!
char message[8192];
int len, logfd, i = 0;
#if XASH_OPENBSD
struct sigcontext *ucontext = (struct sigcontext*)context;
#else
ucontext_t *ucontext = (ucontext_t*)context;
#endif
#if XASH_AMD64
#if XASH_FREEBSD
pc = (void*)ucontext->uc_mcontext.mc_rip;
bp = (void**)ucontext->uc_mcontext.mc_rbp;
sp = (void**)ucontext->uc_mcontext.mc_rsp;
#elif XASH_NETBSD
pc = (void*)ucontext->uc_mcontext.__gregs[_REG_RIP];
bp = (void**)ucontext->uc_mcontext.__gregs[_REG_RBP];
sp = (void**)ucontext->uc_mcontext.__gregs[_REG_RSP];
#elif XASH_OPENBSD
pc = (void*)ucontext->sc_rip;
bp = (void**)ucontext->sc_rbp;
sp = (void**)ucontext->sc_rsp;
#else
pc = (void*)ucontext->uc_mcontext.gregs[REG_RIP];
bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP];
sp = (void**)ucontext->uc_mcontext.gregs[REG_RSP];
#endif
#elif XASH_X86
#if XASH_FREEBSD
pc = (void*)ucontext->uc_mcontext.mc_eip;
bp = (void**)ucontext->uc_mcontext.mc_ebp;
sp = (void**)ucontext->uc_mcontext.mc_esp;
#elif XASH_NETBSD
pc = (void*)ucontext->uc_mcontext.__gregs[_REG_EIP];
bp = (void**)ucontext->uc_mcontext.__gregs[_REG_EBP];
sp = (void**)ucontext->uc_mcontext.__gregs[_REG_ESP];
#elif XASH_OPENBSD
pc = (void*)ucontext->sc_eip;
bp = (void**)ucontext->sc_ebp;
sp = (void**)ucontext->sc_esp;
#else
pc = (void*)ucontext->uc_mcontext.gregs[REG_EIP];
bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP];
sp = (void**)ucontext->uc_mcontext.gregs[REG_ESP];
#endif
#elif XASH_ARM && XASH_64BIT
pc = (void*)ucontext->uc_mcontext.pc;
bp = (void*)ucontext->uc_mcontext.regs[29];
sp = (void*)ucontext->uc_mcontext.sp;
#elif XASH_ARM
pc = (void*)ucontext->uc_mcontext.arm_pc;
bp = (void*)ucontext->uc_mcontext.arm_fp;
sp = (void*)ucontext->uc_mcontext.arm_sp;
#endif
// safe actions first, stack and memory may be corrupted
len = Q_snprintf( message, sizeof( message ), "Ver: " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s, %s-%s)\n",
Q_buildnum(), Q_buildcommit(), Q_buildos(), Q_buildarch() );
#if !XASH_FREEBSD && !XASH_NETBSD && !XASH_OPENBSD
len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: signal %d errno %d with code %d at %p %p\n", signal, si->si_errno, si->si_code, si->si_addr, si->si_ptr );
#else
len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: signal %d errno %d with code %d at %p\n", signal, si->si_errno, si->si_code, si->si_addr );
#endif
write( STDERR_FILENO, message, len );
// flush buffers before writing directly to descriptors
fflush( stdout );
fflush( stderr );
// now get log fd and write trace directly to log
logfd = Sys_LogFileNo();
write( logfd, message, len );
if( pc && bp && sp )
{
size_t pagesize = sysconf( _SC_PAGESIZE );
// try to print backtrace
write( STDERR_FILENO, STACK_BACKTRACE_STR, STACK_BACKTRACE_STR_LEN );
write( logfd, STACK_BACKTRACE_STR, STACK_BACKTRACE_STR_LEN );
Q_strncpy( message + len, STACK_BACKTRACE_STR, sizeof( message ) - len );
len += STACK_BACKTRACE_STR_LEN;
// false on success, true on failure
#define try_allow_read(pointer, pagesize) \
((mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ | PROT_WRITE | PROT_EXEC ) == -1) && \
( mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ | PROT_EXEC ) == -1) && \
( mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ | PROT_WRITE ) == -1) && \
( mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ ) == -1))
do
{
int line = Sys_PrintFrame( message + len, sizeof( message ) - len, ++i, pc);
write( STDERR_FILENO, message + len, line );
write( logfd, message + len, line );
len += line;
//if( !dladdr(bp,0) ) break; // only when bp is in module
if( try_allow_read( bp, pagesize ) )
break;
if( try_allow_read( bp[0], pagesize ) )
break;
pc = bp[1];
bp = (void**)bp[0];
}
while( bp && i < 128 );
// try to print stack
write( STDERR_FILENO, STACK_DUMP_STR, STACK_DUMP_STR_LEN );
write( logfd, STACK_DUMP_STR, STACK_DUMP_STR_LEN );
Q_strncpy( message + len, STACK_DUMP_STR, sizeof( message ) - len );
len += STACK_DUMP_STR_LEN;
if( !try_allow_read( sp, pagesize ) )
{
for( i = 0; i < 32; i++ )
{
int line = Sys_PrintFrame( message + len, sizeof( message ) - len, i, sp[i] );
write( STDERR_FILENO, message + len, line );
write( logfd, message + len, line );
len += line;
}
}
#undef try_allow_read
}
// put MessageBox as Sys_Error
Msg( "%s\n", message );
#ifdef XASH_SDL
SDL_SetWindowGrab( host.hWnd, SDL_FALSE );
#endif
host.crashed = true;
Platform_MessageBox( "Xash Error", message, false );
// log saved, now we can try to save configs and close log correctly, it may crash
if( host.type == HOST_NORMAL )
CL_Crashed();
host.status = HOST_CRASHED;
Sys_Quit();
}
void Sys_SetupCrashHandler( void )
{
struct sigaction act = { 0 };
act.sa_sigaction = Sys_Crash;
act.sa_flags = SA_SIGINFO | SA_ONSTACK;
sigaction( SIGSEGV, &act, &oldFilter );
sigaction( SIGABRT, &act, &oldFilter );
sigaction( SIGBUS, &act, &oldFilter );
sigaction( SIGILL, &act, &oldFilter );
}
void Sys_RestoreCrashHandler( void )
{
sigaction( SIGSEGV, &oldFilter, NULL );
sigaction( SIGABRT, &oldFilter, NULL );
sigaction( SIGBUS, &oldFilter, NULL );
sigaction( SIGILL, &oldFilter, NULL );
}
#else
void Sys_SetupCrashHandler( void )
{
// stub
}
void Sys_RestoreCrashHandler( void )
{
// stub
}
#endif

View File

@@ -237,11 +237,6 @@ static void Sys_PrintBugcompUsage( const char *exename )
Sys_Quit();
}
void Host_ShutdownServer( void )
{
SV_Shutdown( "Server was killed\n" );
}
/*
================
Host_PrintEngineFeatures
@@ -595,7 +590,7 @@ static void Host_GetCommands( void )
{
char *cmd;
while( ( cmd = Sys_Input() ) )
while( ( cmd = Platform_Input() ) )
{
Cbuf_AddText( cmd );
Cbuf_Execute();
@@ -841,7 +836,7 @@ void GAME_EXPORT Host_Error( const char *error, ... )
COM_InitHostState();
Cbuf_Clear();
Host_ShutdownServer();
SV_Shutdown( "Server was killed due to an error\n" );
CL_Drop(); // drop clients
// recreate world if needs

View File

@@ -15,6 +15,7 @@ GNU General Public License for more details.
#include <math.h>
#include "imagelib.h"
#include "eiface.h" // ARRAYSIZE
// global image variables
imglib_t image;
@@ -67,7 +68,6 @@ static const cubepack_t load_cubemap[] =
{ "3Ds Sky1", skybox_qv1 },
{ "3Ds Sky2", skybox_qv2 },
{ "3Ds Cube", cubemap_v1 },
{ NULL, NULL },
};
// soul of ImageLib - table of image format constants
@@ -297,9 +297,8 @@ rgbdata_t *FS_LoadImage( const char *filename, const byte *buffer, size_t size )
{
const char *ext = COM_FileExtension( filename );
string loadname;
int i;
int i, j;
const loadpixformat_t *extfmt;
const cubepack_t *cmap;
Q_strncpy( loadname, filename, sizeof( loadname ));
Image_Reset(); // clear old image
@@ -317,8 +316,10 @@ rgbdata_t *FS_LoadImage( const char *filename, const byte *buffer, size_t size )
return ImagePack();
// check all cubemap sides with package suffix
for( cmap = load_cubemap; cmap && cmap->type; cmap++ )
for( j = 0; j < ARRAYSIZE( load_cubemap ); j++ )
{
const cubepack_t *cmap = &load_cubemap[j];
for( i = 0; i < 6; i++ )
{
if( Image_ProbeLoad( extfmt, loadname, cmap->type[i].suf, cmap->type[i].hint ))

View File

@@ -101,20 +101,14 @@ const char *const svc_legacy_strings[svc_lastmsg+1] =
const char *const svc_goldsrc_strings[svc_lastmsg+1] =
{
[svc_goldsrc_version] = "svc_goldsrc_version",
[svc_goldsrc_serverinfo] = "svc_goldsrc_serverinfo",
[svc_goldsrc_deltadescription] = "svc_goldsrc_deltadescription",
[svc_goldsrc_stopsound] = "svc_goldsrc_stopsound",
[svc_goldsrc_damage] = "svc_goldsrc_damage",
[svc_goldsrc_killedmonster] = "svc_goldsrc_killedmonster",
[svc_goldsrc_foundsecret] = "svc_goldsrc_foundsecret",
[svc_goldsrc_spawnstaticsound] = "svc_goldsrc_spawnstaticsound",
[svc_goldsrc_decalname] = "svc_goldsrc_decalname",
[svc_goldsrc_newusermsg] = "svc_goldsrc_newusermsg",
[svc_goldsrc_newmovevars] = "svc_goldsrc_newmovevars",
[svc_goldsrc_sendextrainfo] = "svc_goldsrc_sendextrainfo",
[svc_goldsrc_timescale] = "svc_goldsrc_timescale",
[svc_goldsrc_sendcvarvalue] = "svc_goldsrc_sendcvarvalue",
[svc_goldsrc_sendcvarvalue2] = "svc_goldsrc_sendcvarvalue2",
};
const char *const svc_quake_strings[svc_lastmsg+1] =

View File

@@ -39,8 +39,6 @@ GNU General Public License for more details.
#define DT_SIGNED BIT( 8 ) // sign modificator
#define DT_SIGNED_GS BIT( 31 ) // GoldSrc-specific sign modificator
#define NUM_FIELDS( x ) ((sizeof( x ) / sizeof( x[0] )) - 1)
// helper macroses
#define ENTS_DEF( x ) #x, offsetof( entity_state_t, x ), sizeof( ((entity_state_t *)0)->x )
#define UCMD_DEF( x ) #x, offsetof( usercmd_t, x ), sizeof( ((usercmd_t *)0)->x )
@@ -71,7 +69,6 @@ static const delta_field_t cmd_fields[] =
{ UCMD_DEF( impact_position[0] ) },
{ UCMD_DEF( impact_position[1] ) },
{ UCMD_DEF( impact_position[2] ) },
{ NULL },
};
static const delta_field_t pm_fields[] =
@@ -107,7 +104,6 @@ static const delta_field_t pm_fields[] =
{ PHYS_DEF( skydir_y ) },
{ PHYS_DEF( skydir_z ) },
{ PHYS_DEF( skyangle ) },
{ NULL },
};
static const delta_field_t ev_fields[] =
@@ -130,7 +126,6 @@ static const delta_field_t ev_fields[] =
{ EVNT_DEF( iparam2 ) },
{ EVNT_DEF( bparam1 ) },
{ EVNT_DEF( bparam2 ) },
{ NULL },
};
static const delta_field_t wd_fields[] =
@@ -157,7 +152,6 @@ static const delta_field_t wd_fields[] =
{ WPDT_DEF( fuser2 ) },
{ WPDT_DEF( fuser3 ) },
{ WPDT_DEF( fuser4 ) },
{ NULL },
};
static const delta_field_t cd_fields[] =
@@ -218,7 +212,6 @@ static const delta_field_t cd_fields[] =
{ CLDT_DEF( vuser4[0] ) },
{ CLDT_DEF( vuser4[1] ) },
{ CLDT_DEF( vuser4[2] ) },
{ NULL },
};
static const delta_field_t ent_fields[] =
@@ -314,7 +307,6 @@ static const delta_field_t ent_fields[] =
{ ENTS_DEF( vuser4[0] ) },
{ ENTS_DEF( vuser4[1] ) },
{ ENTS_DEF( vuser4[2] ) },
{ NULL },
};
static const delta_field_t meta_fields[] =
@@ -326,7 +318,6 @@ static const delta_field_t meta_fields[] =
{ DESC_DEF( significant_bits ), },
{ DESC_DEF( premultiply ), },
{ DESC_DEF( postmultiply ), },
{ NULL },
};
#if XASH_ENGINE_TESTS
@@ -362,24 +353,22 @@ static const delta_field_t test_fields[] =
{ TEST_DEF( dt_short_unsigned ) },
{ TEST_DEF( dt_byte_signed ) },
{ TEST_DEF( dt_byte_unsigned ) },
{ NULL },
};
#endif
static delta_info_t dt_info[] =
{
[DT_EVENT_T] = { "event_t", ev_fields, NUM_FIELDS( ev_fields ) },
[DT_MOVEVARS_T] = { "movevars_t", pm_fields, NUM_FIELDS( pm_fields ) },
[DT_USERCMD_T] = { "usercmd_t", cmd_fields, NUM_FIELDS( cmd_fields ) },
[DT_CLIENTDATA_T] = { "clientdata_t", cd_fields, NUM_FIELDS( cd_fields ) },
[DT_WEAPONDATA_T] = { "weapon_data_t", wd_fields, NUM_FIELDS( wd_fields ) },
[DT_ENTITY_STATE_T] = { "entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
[DT_ENTITY_STATE_PLAYER_T] = { "entity_state_player_t", ent_fields, NUM_FIELDS( ent_fields ) },
[DT_CUSTOM_ENTITY_STATE_T] = { "custom_entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
[DT_EVENT_T] = { "event_t", ev_fields, ARRAYSIZE( ev_fields ) },
[DT_MOVEVARS_T] = { "movevars_t", pm_fields, ARRAYSIZE( pm_fields ) },
[DT_USERCMD_T] = { "usercmd_t", cmd_fields, ARRAYSIZE( cmd_fields ) },
[DT_CLIENTDATA_T] = { "clientdata_t", cd_fields, ARRAYSIZE( cd_fields ) },
[DT_WEAPONDATA_T] = { "weapon_data_t", wd_fields, ARRAYSIZE( wd_fields ) },
[DT_ENTITY_STATE_T] = { "entity_state_t", ent_fields, ARRAYSIZE( ent_fields ) },
[DT_ENTITY_STATE_PLAYER_T] = { "entity_state_player_t", ent_fields, ARRAYSIZE( ent_fields ) },
[DT_CUSTOM_ENTITY_STATE_T] = { "custom_entity_state_t", ent_fields, ARRAYSIZE( ent_fields ) },
#if XASH_ENGINE_TESTS
[DT_DELTA_TEST_STRUCT_T] = { "delta_test_struct_t", test_fields, NUM_FIELDS( test_fields ) },
[DT_DELTA_TEST_STRUCT_T] = { "delta_test_struct_t", test_fields, ARRAYSIZE( test_fields ) },
#endif
[DT_STRUCT_COUNT] = { NULL },
};
// meta description is special, it cannot be overriden
@@ -387,9 +376,9 @@ static const delta_info_t dt_goldsrc_meta =
{
.pName = "goldsrc_delta_t",
.pInfo = meta_fields,
.maxFields = NUM_FIELDS( meta_fields ),
.numFields = NUM_FIELDS( meta_fields ),
.pFields = (delta_t[NUM_FIELDS( meta_fields )])
.maxFields = ARRAYSIZE( meta_fields ),
.numFields = ARRAYSIZE( meta_fields ),
.pFields = (delta_t[ARRAYSIZE( meta_fields )])
{
{
DESC_DEF( fieldType ),
@@ -451,7 +440,7 @@ static delta_info_t *Delta_FindStruct( const char *name )
if( !COM_CheckString( name ))
return NULL;
for( i = 0; i < NUM_FIELDS( dt_info ); i++ )
for( i = 0; i < ARRAYSIZE( dt_info ); i++ )
{
if( !Q_stricmp( dt_info[i].pName, name ))
return &dt_info[i];
@@ -465,7 +454,7 @@ static delta_info_t *Delta_FindStruct( const char *name )
static int Delta_NumTables( void )
{
return NUM_FIELDS( dt_info );
return ARRAYSIZE( dt_info );
}
static delta_info_t *Delta_FindStructByIndex( int index )
@@ -480,7 +469,7 @@ static delta_info_t *Delta_FindStructByEncoder( const char *encoderName )
if( !COM_CheckString( encoderName ) )
return NULL;
for( i = 0; i < NUM_FIELDS( dt_info ); i++ )
for( i = 0; i < ARRAYSIZE( dt_info ); i++ )
{
if( !Q_stricmp( dt_info[i].funcName, encoderName ))
return &dt_info[i];
@@ -495,7 +484,7 @@ static delta_info_t *Delta_FindStructByDelta( const delta_t *pFields )
if( !pFields ) return NULL;
for( i = 0; i < NUM_FIELDS( dt_info ); i++ )
for( i = 0; i < ARRAYSIZE( dt_info ); i++ )
{
if( dt_info[i].pFields == pFields )
return &dt_info[i];
@@ -518,29 +507,32 @@ static void Delta_CustomEncode( delta_info_t *dt, const void *from, const void *
dt->userCallback( dt->pFields, from, to );
}
static delta_field_t *Delta_FindFieldInfo( const delta_field_t *pInfo, const char *fieldName )
static const delta_field_t *Delta_FindFieldInfo( const delta_field_t *pInfo, const char *fieldName, int maxFields )
{
int i;
if( !fieldName || !*fieldName )
return NULL;
for( ; pInfo->name; pInfo++ )
for( i = 0; i < maxFields; i++ )
{
if( !Q_strcmp( pInfo->name, fieldName ))
return (delta_field_t *)pInfo;
if( !Q_strcmp( pInfo[i].name, fieldName ))
return &pInfo[i];
}
return NULL;
}
static int Delta_IndexForFieldInfo( const delta_field_t *pInfo, const char *fieldName )
static int Delta_IndexForFieldInfo( const delta_field_t *pInfo, const char *fieldName, int maxFields )
{
int i;
if( !fieldName || !*fieldName )
return -1;
for( i = 0; pInfo->name; i++, pInfo++ )
for( i = 0; i < maxFields; i++ )
{
if( !Q_strcmp( pInfo->name, fieldName ))
if( !Q_strcmp( pInfo[i].name, fieldName ))
return i;
}
return -1;
@@ -548,7 +540,7 @@ static int Delta_IndexForFieldInfo( const delta_field_t *pInfo, const char *fiel
static qboolean Delta_AddField( delta_info_t *dt, const char *pName, int flags, int bits, float mul, float post_mul )
{
delta_field_t *pFieldInfo;
const delta_field_t *pFieldInfo;
delta_t *pField;
int i;
@@ -567,7 +559,7 @@ static qboolean Delta_AddField( delta_info_t *dt, const char *pName, int flags,
}
// find field description
pFieldInfo = Delta_FindFieldInfo( dt->pInfo, pName );
pFieldInfo = Delta_FindFieldInfo( dt->pInfo, pName, dt->maxFields );
if( !pFieldInfo )
{
Con_DPrintf( S_ERROR "%s: couldn't find description for %s->%s\n", __func__, dt->pName, pName );
@@ -610,7 +602,7 @@ static void Delta_WriteTableField( sizebuf_t *msg, int tableIndex, const delta_t
dt = Delta_FindStructByIndex( tableIndex );
Assert( dt && dt->bInitialized );
nameIndex = Delta_IndexForFieldInfo( dt->pInfo, pField->name );
nameIndex = Delta_IndexForFieldInfo( dt->pInfo, pField->name, dt->maxFields );
Assert( nameIndex >= 0 && nameIndex < dt->maxFields );
MSG_BeginServerCmd( msg, svc_deltatable );
@@ -681,10 +673,10 @@ void Delta_ParseTableField( sizebuf_t *msg )
Delta_AddField( dt, pName, flags, bits, mul, post_mul );
}
static qboolean Delta_ParseField( char **delta_script, const delta_field_t *pInfo, delta_t *pField, qboolean bPost )
static qboolean Delta_ParseField( char **delta_script, const delta_info_t *dt, delta_t *pField, qboolean bPost )
{
const delta_field_t *pFieldInfo;
string token;
delta_field_t *pFieldInfo;
char *oldpos;
*delta_script = COM_ParseFile( *delta_script, token, sizeof( token ));
@@ -701,7 +693,7 @@ static qboolean Delta_ParseField( char **delta_script, const delta_field_t *pInf
return false;
}
pFieldInfo = Delta_FindFieldInfo( pInfo, token );
pFieldInfo = Delta_FindFieldInfo( dt->pInfo, token, dt->maxFields );
if( !pFieldInfo )
{
Con_DPrintf( S_ERROR "%s: unable to find field %s\n", __func__, token );
@@ -825,13 +817,11 @@ static void Delta_ParseTable( char **delta_script, delta_info_t *dt, const char
{
string token;
delta_t *pField;
const delta_field_t *pInfo;
// allocate the delta-structures
if( !dt->pFields ) dt->pFields = (delta_t *)Z_Calloc( dt->maxFields * sizeof( delta_t ));
pField = dt->pFields;
pInfo = dt->pInfo;
dt->numFields = 0;
// assume we have handled '{'
@@ -841,12 +831,12 @@ static void Delta_ParseTable( char **delta_script, delta_info_t *dt, const char
if( !Q_strcmp( token, "DEFINE_DELTA" ))
{
if( Delta_ParseField( delta_script, pInfo, &pField[dt->numFields], false ))
if( Delta_ParseField( delta_script, dt, &pField[dt->numFields], false ))
dt->numFields++;
}
else if( !Q_strcmp( token, "DEFINE_DELTA_POST" ))
{
if( Delta_ParseField( delta_script, pInfo, &pField[dt->numFields], true ))
if( Delta_ParseField( delta_script, dt, &pField[dt->numFields], true ))
dt->numFields++;
}
else if( token[0] == '}' )
@@ -963,7 +953,7 @@ void Delta_Init( void )
Delta_AddField( dt, "skyvec_z", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f );
Delta_AddField( dt, "wateralpha", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f );
Delta_AddField( dt, "fog_settings", DT_INTEGER, 32, 1.0f, 1.0f );
dt->numFields = NUM_FIELDS( pm_fields ) - 4;
dt->numFields = ARRAYSIZE( pm_fields ) - 4;
// now done
dt->bInitialized = true;
@@ -976,7 +966,7 @@ void Delta_InitClient( void )
// already initalized
if( delta_init ) return;
for( i = 0; i < NUM_FIELDS( dt_info ); i++ )
for( i = 0; i < ARRAYSIZE( dt_info ); i++ )
{
if( dt_info[i].numFields > 0 )
{
@@ -994,7 +984,7 @@ void Delta_Shutdown( void )
if( !delta_init ) return;
for( i = 0; i < NUM_FIELDS( dt_info ); i++ )
for( i = 0; i < ARRAYSIZE( dt_info ); i++ )
{
dt_info[i].numFields = 0;
dt_info[i].customEncode = CUSTOM_NONE;

View File

@@ -46,7 +46,6 @@ enum
#if XASH_ENGINE_TESTS
DT_DELTA_TEST_STRUCT_T,
#endif
DT_STRUCT_COUNT
};
// struct info (filled by engine)

View File

@@ -324,20 +324,14 @@ extern const char *const clc_strings[clc_lastmsg+1];
#define PROTOCOL_GOLDSRC_VERSION 48
#define svc_goldsrc_version svc_changing
#define svc_goldsrc_serverinfo svc_serverdata
#define svc_goldsrc_deltadescription svc_deltatable
#define svc_goldsrc_stopsound svc_resource
#define svc_goldsrc_damage svc_restoresound
#define svc_goldsrc_killedmonster 27
#define svc_goldsrc_foundsecret 28
#define svc_goldsrc_spawnstaticsound 29
#define svc_goldsrc_decalname svc_bspdecal
#define svc_goldsrc_newusermsg svc_usermessage
#define svc_goldsrc_newmovevars svc_deltamovevars
#define svc_goldsrc_sendextrainfo 54
#define svc_goldsrc_timescale 55
#define svc_goldsrc_sendcvarvalue svc_querycvarvalue
#define svc_goldsrc_sendcvarvalue2 svc_querycvarvalue2
#define clc_goldsrc_hltv clc_requestcvarvalue // 9
#define clc_goldsrc_requestcvarvalue clc_requestcvarvalue2 // 10

View File

@@ -14,10 +14,7 @@ GNU General Public License for more details.
*/
#include "common.h"
#if XASH_WIN32
#define STDOUT_FILENO 1
#include <io.h>
#elif XASH_ANDROID
#if XASH_ANDROID
#include <android/log.h>
#endif
#include <string.h>
@@ -25,20 +22,13 @@ GNU General Public License for more details.
#if XASH_IRIX
#include <sys/time.h>
#endif
#include "xash3d_mathlib.h"
// do not waste precious CPU cycles on mobiles or low memory devices
#if !XASH_WIN32 && !XASH_MOBILE_PLATFORM && !XASH_LOW_MEMORY
#define XASH_COLORIZE_CONSOLE true
// use with caution, running engine in Qt Creator may cause a freeze in read() call
// I have never encountered this bug anywhere else, so still enable by default
#define XASH_USE_SELECT 1
#define XASH_COLORIZE_CONSOLE 1
#else
#define XASH_COLORIZE_CONSOLE false
#endif
#if XASH_USE_SELECT
// non-blocking console input
#include <sys/select.h>
#define XASH_COLORIZE_CONSOLE 0
#endif
typedef struct {
@@ -51,41 +41,6 @@ typedef struct {
static LogData s_ld;
char *Sys_Input( void )
{
#if XASH_USE_SELECT
if( Host_IsDedicated( ))
{
fd_set rfds;
static char line[1024];
static int len;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO( &rfds );
FD_SET( 0, &rfds); // stdin
while( select( 1, &rfds, NULL, NULL, &tv ) > 0 )
{
if( read( 0, &line[len], 1 ) != 1 )
break;
if( line[len] == '\n' || len > 1022 )
{
line[ ++len ] = 0;
len = 0;
return line;
}
len++;
tv.tv_sec = 0;
tv.tv_usec = 0;
}
}
#endif
#if XASH_WIN32
return Wcon_Input();
#endif
return NULL;
}
void Sys_DestroyConsole( void )
{
// last text message into console or log
@@ -194,8 +149,8 @@ void Sys_CloseLog( void )
}
}
#if XASH_COLORIZE_CONSOLE == true
static void Sys_WriteEscapeSequenceForColorcode( int fd, int c )
#if XASH_COLORIZE_CONSOLE
static qboolean Sys_WriteEscapeSequenceForColorcode( int fd, int c )
{
static const char *q3ToAnsi[ 8 ] =
{
@@ -210,19 +165,26 @@ static void Sys_WriteEscapeSequenceForColorcode( int fd, int c )
};
const char *esc = q3ToAnsi[c];
if( c == 7 )
write( fd, esc, 4 );
else write( fd, esc, 7 );
return write( fd, esc, c == 7 ? 4 : 7 ) < 0 ? false : true;
}
#else
static void Sys_WriteEscapeSequenceForColorcode( int fd, int c ) {}
static qboolean Sys_WriteEscapeSequenceForColorcode( int fd, int c )
{
return true;
}
#endif
static void Sys_PrintLogfile( const int fd, const char *logtime, const char *msg, const qboolean colorize )
static void Sys_PrintLogfile( const int fd, const char *logtime, size_t logtime_len, const char *msg, const int colorize )
{
const char *p = msg;
write( fd, logtime, Q_strlen( logtime ) );
if( logtime_len != 0 )
{
if( write( fd, logtime, logtime_len ) < 0 )
{
// not critical for us
}
}
while( p && *p )
{
@@ -262,7 +224,7 @@ static void Sys_PrintLogfile( const int fd, const char *logtime, const char *msg
Sys_WriteEscapeSequenceForColorcode( fd, 7 );
}
static void Sys_PrintStdout( const char *logtime, const char *msg )
static void Sys_PrintStdout( const char *logtime, size_t logtime_len, const char *msg )
{
#if XASH_MOBILE_PLATFORM
static char buf[MAX_PRINT_MSG];
@@ -294,7 +256,7 @@ static void Sys_PrintStdout( const char *logtime, const char *msg )
#endif
#elif !XASH_WIN32 // Wcon does the job
Sys_PrintLogfile( STDOUT_FILENO, logtime, msg, XASH_COLORIZE_CONSOLE );
Sys_PrintLogfile( STDOUT_FILENO, logtime, logtime_len, msg, XASH_COLORIZE_CONSOLE );
Sys_FlushStdout();
#endif
}
@@ -305,33 +267,44 @@ void Sys_PrintLog( const char *pMsg )
const struct tm *crt_tm;
char logtime[32] = "";
static char lastchar;
size_t len;
qboolean print_time = true;
size_t len, logtime_len = 0;
time( &crt_time );
crt_tm = localtime( &crt_time );
if( !lastchar || lastchar == '\n' )
{
if( time( &crt_time ) >= 0 )
{
crt_tm = localtime( &crt_time );
if( crt_tm == NULL )
print_time = false;
}
}
else print_time = false;
if( !lastchar || lastchar == '\n')
strftime( logtime, sizeof( logtime ), "[%H:%M:%S] ", crt_tm ); //short time
if( print_time )
{
logtime_len = strftime( logtime, sizeof( logtime ), "[%H:%M:%S] ", crt_tm ); // short time
logtime_len = Q_min( logtime_len, sizeof( logtime ) - 1 ); // just in case
}
// spew to stdout
Sys_PrintStdout( logtime, pMsg );
Sys_PrintStdout( logtime, logtime_len, pMsg );
len = Q_strlen( pMsg );
if( !s_ld.logfile )
{
// save last char to detect when line was not ended
lastchar = len > 0 ? pMsg[len - 1] : 0;
return;
}
if( !lastchar || lastchar == '\n')
strftime( logtime, sizeof( logtime ), "[%Y:%m:%d|%H:%M:%S] ", crt_tm ); //full time
// save last char to detect when line was not ended
lastchar = len > 0 ? pMsg[len - 1] : 0;
Sys_PrintLogfile( s_ld.logfileno, logtime, pMsg, false );
if( !s_ld.logfile )
return;
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

@@ -234,28 +234,12 @@ qboolean Sys_GetIntFromCmdLine( const char* argName, int *out )
return true;
}
void Sys_SendKeyEvents( void )
{
#if XASH_WIN32
MSG msg;
while( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ))
{
if( !GetMessage( &msg, NULL, 0, 0 ))
Sys_Quit ();
TranslateMessage( &msg );
DispatchMessage( &msg );
}
#endif
}
//=======================================================================
// DLL'S MANAGER SYSTEM
//=======================================================================
qboolean Sys_LoadLibrary( dll_info_t *dll )
{
const dllfunc_t *func;
size_t i;
string errorstring;
// check errors
@@ -267,12 +251,8 @@ qboolean Sys_LoadLibrary( dll_info_t *dll )
Con_Reportf( "%s: Loading %s", __func__, dll->name );
if( dll->fcts )
{
// lookup export table
for( func = dll->fcts; func && func->name != NULL; func++ )
*func->func = NULL;
}
if( dll->fcts ) // lookup export table
ClearExports( dll->fcts, dll->num_fcts );
if( !dll->link )
dll->link = COM_LoadLibrary( dll->name, false, true ); // environment pathes
@@ -285,9 +265,10 @@ qboolean Sys_LoadLibrary( dll_info_t *dll )
}
// Get the function adresses
for( func = dll->fcts; func && func->name != NULL; func++ )
for( i = 0; i < dll->num_fcts; i++ )
{
if( !( *func->func = Sys_GetProcAddress( dll, func->name )))
const dllfunc_t *func = &dll->fcts[i];
if( !( *func->func = COM_GetProcAddress( dll->link, func->name )))
{
Q_snprintf( errorstring, sizeof( errorstring ), "Sys_LoadLibrary: %s missing or invalid function (%s)\n", dll->name, func->name );
goto error;
@@ -300,19 +281,11 @@ error:
Con_Reportf( " - failed\n" );
Sys_FreeLibrary( dll ); // trying to free
if( dll->crash ) Sys_Error( "%s", errorstring );
else Con_Reportf( S_ERROR "%s", errorstring );
else Con_Reportf( S_ERROR "%s", errorstring );
return false;
}
void* Sys_GetProcAddress( dll_info_t *dll, const char* name )
{
if( !dll || !dll->link ) // invalid desc
return NULL;
return (void *)COM_GetProcAddress( dll->link, name );
}
qboolean Sys_FreeLibrary( dll_info_t *dll )
{
// invalid desc or alredy freed
@@ -330,6 +303,8 @@ qboolean Sys_FreeLibrary( dll_info_t *dll )
COM_FreeLibrary( dll->link );
dll->link = NULL;
ClearExports( dll->fcts, dll->num_fcts );
return true;
}

View File

@@ -49,11 +49,8 @@ int Sys_CheckParm( const char *parm );
void Sys_Warn( const char *format, ... ) FORMAT_CHECK( 1 );
void Sys_Error( const char *error, ... ) FORMAT_CHECK( 1 );
qboolean Sys_LoadLibrary( dll_info_t *dll );
void* Sys_GetProcAddress( dll_info_t *dll, const char* name );
qboolean Sys_FreeLibrary( dll_info_t *dll );
void Sys_ParseCommandLine( int argc, char **argv );
void Sys_SetupCrashHandler( void );
void Sys_RestoreCrashHandler( void );
void Sys_DebugBreak( void );
#define Sys_GetParmFromCmdLine( parm, out ) _Sys_GetParmFromCmdLine( parm, out, sizeof( out ))
qboolean _Sys_GetParmFromCmdLine( const char *parm, char *out, size_t size );

View File

@@ -51,6 +51,7 @@ void IOS_LaunchDialog( void );
#if XASH_POSIX
void Posix_Daemonize( void );
void Posix_SetupSigtermHandling( void );
char *Posix_Input( void );
#endif
#if XASH_SDL
@@ -177,6 +178,20 @@ static inline void Platform_Sleep( int msec )
#endif
}
#if XASH_WIN32 || XASH_FREEBSD || XASH_NETBSD || XASH_OPENBSD || XASH_ANDROID || XASH_LINUX
void Sys_SetupCrashHandler( void );
void Sys_RestoreCrashHandler( void );
#else
static inline void Sys_SetupCrashHandler( void )
{
}
static inline void Sys_RestoreCrashHandler( void )
{
}
#endif
/*
==============================================================================
@@ -227,6 +242,25 @@ static inline void Platform_SetTimer( float time )
#endif
}
static inline char *Platform_Input( void )
{
#if XASH_WIN32
return Wcon_Input();
#elif XASH_POSIX && !XASH_MOBILE_PLATFORM && !XASH_LOW_MEMORY
return Posix_Input();
#else
return NULL;
#endif
}
#if XASH_WIN32
void Platform_SendKeyEvents( void );
#else
static inline void Platform_SendKeyEvents( void )
{
}
#endif
/*
==============================================================================

View File

@@ -0,0 +1,52 @@
/*
con_posix.c - reading from stdin
Copyright (C) 2024 Flying With Gauss
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.
*/
#include "platform/platform.h"
#if !XASH_MOBILE_PLATFORM && !XASH_LOW_MEMORY
// use with caution, running engine in Qt Creator may cause a freeze in read() call
// I have never encountered this bug anywhere else, so still enable by default
#include <sys/select.h>
char *Posix_Input( void )
{
fd_set rfds;
static char line[1024];
static int len;
struct timeval tv = { 0 };
if( !Host_IsDedicated( ))
return NULL;
FD_ZERO( &rfds );
FD_SET( 0, &rfds); // stdin
while( select( 1, &rfds, NULL, NULL, &tv ) > 0 )
{
if( read( 0, &line[len], 1 ) != 1 )
break;
if( line[len] == '\n' || len > ( sizeof( line ) - 2 ))
{
line[ ++len ] = 0;
len = 0;
return line;
}
len++;
tv.tv_sec = 0;
tv.tv_usec = 0;
}
return NULL;
}
#endif // !XASH_MOBILE_PLATFORM && !XASH_LOW_MEMORY

View File

@@ -0,0 +1,223 @@
/*
crashhandler.c - advanced crashhandler
Copyright (C) 2016 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.
*/
#include "common.h"
// while this is mostly POSIX-compatible functions
// the contents of ucontext_t is platform-dependent
// before adding new OS here, check platform.h
#if XASH_FREEBSD || XASH_NETBSD || XASH_OPENBSD || XASH_ANDROID || XASH_LINUX
#ifndef XASH_OPENBSD
#include <ucontext.h>
#endif
#include <signal.h>
#include <sys/mman.h>
#include "library.h"
#define STACK_BACKTRACE_STR "Stack backtrace:\n"
#define STACK_DUMP_STR "Stack dump:\n"
#define STACK_BACKTRACE_STR_LEN ( sizeof( STACK_BACKTRACE_STR ) - 1 )
#define STACK_DUMP_STR_LEN ( sizeof( STACK_DUMP_STR ) - 1 )
#define ALIGN( x, y ) (((uintptr_t) ( x ) + (( y ) - 1 )) & ~(( y ) - 1 ))
static struct sigaction oldFilter;
static int Sys_PrintFrame( char *buf, int len, int i, void *addr )
{
Dl_info dlinfo;
if( len <= 0 )
return 0; // overflow
if( dladdr( addr, &dlinfo ))
{
if( dlinfo.dli_sname )
return Q_snprintf( buf, len, "%2d: %p <%s+%lu> (%s)\n", i, addr, dlinfo.dli_sname,
(unsigned long)addr - (unsigned long)dlinfo.dli_saddr, dlinfo.dli_fname ); // print symbol, module and address
return Q_snprintf( buf, len, "%2d: %p (%s)\n", i, addr, dlinfo.dli_fname ); // print module and address
}
return Q_snprintf( buf, len, "%2d: %p\n", i, addr ); // print only address
}
static void Sys_Crash( int signal, siginfo_t *si, void *context)
{
void *pc = NULL, **bp = NULL, **sp = NULL; // this must be set for every OS!
char message[8192];
int len, logfd, i = 0;
#if XASH_OPENBSD
struct sigcontext *ucontext = (struct sigcontext*)context;
#else
ucontext_t *ucontext = (ucontext_t*)context;
#endif
#if XASH_AMD64
#if XASH_FREEBSD
pc = (void*)ucontext->uc_mcontext.mc_rip;
bp = (void**)ucontext->uc_mcontext.mc_rbp;
sp = (void**)ucontext->uc_mcontext.mc_rsp;
#elif XASH_NETBSD
pc = (void*)ucontext->uc_mcontext.__gregs[_REG_RIP];
bp = (void**)ucontext->uc_mcontext.__gregs[_REG_RBP];
sp = (void**)ucontext->uc_mcontext.__gregs[_REG_RSP];
#elif XASH_OPENBSD
pc = (void*)ucontext->sc_rip;
bp = (void**)ucontext->sc_rbp;
sp = (void**)ucontext->sc_rsp;
#else
pc = (void*)ucontext->uc_mcontext.gregs[REG_RIP];
bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP];
sp = (void**)ucontext->uc_mcontext.gregs[REG_RSP];
#endif
#elif XASH_X86
#if XASH_FREEBSD
pc = (void*)ucontext->uc_mcontext.mc_eip;
bp = (void**)ucontext->uc_mcontext.mc_ebp;
sp = (void**)ucontext->uc_mcontext.mc_esp;
#elif XASH_NETBSD
pc = (void*)ucontext->uc_mcontext.__gregs[_REG_EIP];
bp = (void**)ucontext->uc_mcontext.__gregs[_REG_EBP];
sp = (void**)ucontext->uc_mcontext.__gregs[_REG_ESP];
#elif XASH_OPENBSD
pc = (void*)ucontext->sc_eip;
bp = (void**)ucontext->sc_ebp;
sp = (void**)ucontext->sc_esp;
#else
pc = (void*)ucontext->uc_mcontext.gregs[REG_EIP];
bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP];
sp = (void**)ucontext->uc_mcontext.gregs[REG_ESP];
#endif
#elif XASH_ARM && XASH_64BIT
pc = (void*)ucontext->uc_mcontext.pc;
bp = (void*)ucontext->uc_mcontext.regs[29];
sp = (void*)ucontext->uc_mcontext.sp;
#elif XASH_ARM
pc = (void*)ucontext->uc_mcontext.arm_pc;
bp = (void*)ucontext->uc_mcontext.arm_fp;
sp = (void*)ucontext->uc_mcontext.arm_sp;
#endif
// safe actions first, stack and memory may be corrupted
len = Q_snprintf( message, sizeof( message ), "Ver: " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s, %s-%s)\n",
Q_buildnum(), Q_buildcommit(), Q_buildos(), Q_buildarch() );
#if !XASH_FREEBSD && !XASH_NETBSD && !XASH_OPENBSD
len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: signal %d errno %d with code %d at %p %p\n", signal, si->si_errno, si->si_code, si->si_addr, si->si_ptr );
#else
len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: signal %d errno %d with code %d at %p\n", signal, si->si_errno, si->si_code, si->si_addr );
#endif
write( STDERR_FILENO, message, len );
// flush buffers before writing directly to descriptors
fflush( stdout );
fflush( stderr );
// now get log fd and write trace directly to log
logfd = Sys_LogFileNo();
write( logfd, message, len );
if( pc && bp && sp )
{
size_t pagesize = sysconf( _SC_PAGESIZE );
// try to print backtrace
write( STDERR_FILENO, STACK_BACKTRACE_STR, STACK_BACKTRACE_STR_LEN );
write( logfd, STACK_BACKTRACE_STR, STACK_BACKTRACE_STR_LEN );
Q_strncpy( message + len, STACK_BACKTRACE_STR, sizeof( message ) - len );
len += STACK_BACKTRACE_STR_LEN;
// false on success, true on failure
#define try_allow_read(pointer, pagesize) \
(( mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ | PROT_WRITE | PROT_EXEC ) == -1 ) && \
( mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ | PROT_EXEC ) == -1 ) && \
( mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ | PROT_WRITE ) == -1 ) && \
( mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ ) == -1 ))
do
{
int line = Sys_PrintFrame( message + len, sizeof( message ) - len, ++i, pc);
write( STDERR_FILENO, message + len, line );
write( logfd, message + len, line );
len += line;
//if( !dladdr(bp,0) ) break; // only when bp is in module
if( try_allow_read( bp, pagesize ) )
break;
if( try_allow_read( bp[0], pagesize ) )
break;
pc = bp[1];
bp = (void**)bp[0];
}
while( bp && i < 128 );
// try to print stack
write( STDERR_FILENO, STACK_DUMP_STR, STACK_DUMP_STR_LEN );
write( logfd, STACK_DUMP_STR, STACK_DUMP_STR_LEN );
Q_strncpy( message + len, STACK_DUMP_STR, sizeof( message ) - len );
len += STACK_DUMP_STR_LEN;
if( !try_allow_read( sp, pagesize ) )
{
for( i = 0; i < 32; i++ )
{
int line = Sys_PrintFrame( message + len, sizeof( message ) - len, i, sp[i] );
write( STDERR_FILENO, message + len, line );
write( logfd, message + len, line );
len += line;
}
}
#undef try_allow_read
}
// put MessageBox as Sys_Error
Msg( "%s\n", message );
#ifdef XASH_SDL
SDL_SetWindowGrab( host.hWnd, SDL_FALSE );
#endif
host.crashed = true;
Platform_MessageBox( "Xash Error", message, false );
// log saved, now we can try to save configs and close log correctly, it may crash
if( host.type == HOST_NORMAL )
CL_Crashed();
host.status = HOST_CRASHED;
Sys_Quit();
}
void Sys_SetupCrashHandler( void )
{
struct sigaction act = { 0 };
act.sa_sigaction = Sys_Crash;
act.sa_flags = SA_SIGINFO | SA_ONSTACK;
sigaction( SIGSEGV, &act, &oldFilter );
sigaction( SIGABRT, &act, &oldFilter );
sigaction( SIGBUS, &act, &oldFilter );
sigaction( SIGILL, &act, &oldFilter );
}
void Sys_RestoreCrashHandler( void )
{
sigaction( SIGSEGV, &oldFilter, NULL );
sigaction( SIGABRT, &oldFilter, NULL );
sigaction( SIGBUS, &oldFilter, NULL );
sigaction( SIGILL, &oldFilter, NULL );
}
#endif // XASH_FREEBSD || XASH_NETBSD || XASH_OPENBSD || XASH_ANDROID || XASH_LINUX

View File

@@ -0,0 +1,331 @@
/*
crashhandler.c - advanced crashhandler
Copyright (C) 2016 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.
*/
#include "platform/platform.h"
#define DBGHELP 1 // we always enable dbghelp.dll on Windows targets
#if DBGHELP
#include <winnt.h>
#include <dbghelp.h>
#include <psapi.h>
#include <time.h>
#ifndef XASH_SDL
typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
#endif
static int Sys_ModuleName( HANDLE process, char *name, void *address, int len )
{
DWORD_PTR baseAddress = 0;
static HMODULE *moduleArray;
static unsigned int moduleCount;
LPBYTE moduleArrayBytes;
DWORD bytesRequired;
int i;
if( len < 3 )
return 0;
if( !moduleArray && EnumProcessModules( process, NULL, 0, &bytesRequired ) )
{
if ( bytesRequired )
{
moduleArrayBytes = (LPBYTE)LocalAlloc( LPTR, bytesRequired );
if( moduleArrayBytes && EnumProcessModules( process, (HMODULE *)moduleArrayBytes, bytesRequired, &bytesRequired ) )
{
moduleCount = bytesRequired / sizeof( HMODULE );
moduleArray = (HMODULE *)moduleArrayBytes;
}
}
}
for( i = 0; i < moduleCount; i++ )
{
MODULEINFO info;
GetModuleInformation( process, moduleArray[i], &info, sizeof(MODULEINFO) );
if( ( address > info.lpBaseOfDll ) &&
( (DWORD64)address < (DWORD64)info.lpBaseOfDll + (DWORD64)info.SizeOfImage ) )
return GetModuleBaseName( process, moduleArray[i], name, len );
}
return Q_snprintf( name, len, "???" );
}
static void Sys_StackTrace( PEXCEPTION_POINTERS pInfo )
{
char message[8192]; // match *nix Sys_Crash
int len = 0;
size_t i;
HANDLE process = GetCurrentProcess();
HANDLE thread = GetCurrentThread();
IMAGEHLP_LINE64 line;
DWORD dline = 0;
DWORD options;
CONTEXT context;
STACKFRAME64 stackframe;
DWORD image;
context = *pInfo->ContextRecord;
options = SymGetOptions();
options |= SYMOPT_DEBUG;
options |= SYMOPT_LOAD_LINES;
SymSetOptions( options );
SymInitialize( process, NULL, TRUE );
ZeroMemory( &stackframe, sizeof( STACKFRAME64 ));
#ifdef _M_IX86
image = IMAGE_FILE_MACHINE_I386;
stackframe.AddrPC.Offset = context.Eip;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.Ebp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Esp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
image = IMAGE_FILE_MACHINE_AMD64;
stackframe.AddrPC.Offset = context.Rip;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.Rsp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Rsp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif _M_IA64
image = IMAGE_FILE_MACHINE_IA64;
stackframe.AddrPC.Offset = context.StIIP;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.IntSp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrBStore.Offset = context.RsBSP;
stackframe.AddrBStore.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.IntSp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif _M_ARM
image = IMAGE_FILE_MACHINE_ARMNT;
stackframe.AddrPC.Offset = context.Pc;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.R11;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Sp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif _M_ARM64
image = IMAGE_FILE_MACHINE_ARM64;
stackframe.AddrPC.Offset = context.Pc;
stackframe.AddrPC.Mode = AddrModeFlat;
stackframe.AddrFrame.Offset = context.Fp;
stackframe.AddrFrame.Mode = AddrModeFlat;
stackframe.AddrStack.Offset = context.Sp;
stackframe.AddrStack.Mode = AddrModeFlat;
#elif
#error
#endif
len = Q_snprintf( message, sizeof( message ), "Ver: " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s, %s-%s)\n",
Q_buildnum(), Q_buildcommit(), Q_buildos(), Q_buildarch() );
len += Q_snprintf( message + len, 1024 - len, "Sys_Crash: address %p, code %p\n",
pInfo->ExceptionRecord->ExceptionAddress, (void*)pInfo->ExceptionRecord->ExceptionCode );
if( SymGetLineFromAddr64( process, (DWORD64)pInfo->ExceptionRecord->ExceptionAddress, &dline, &line ) )
{
len += Q_snprintf(message + len, 1024 - len, "Exception: %s:%d:%d\n",
(char*)line.FileName, (int)line.LineNumber, (int)dline);
}
if( SymGetLineFromAddr64( process, stackframe.AddrPC.Offset, &dline, &line ) )
{
len += Q_snprintf(message + len, 1024 - len,"PC: %s:%d:%d\n",
(char*)line.FileName, (int)line.LineNumber, (int)dline);
}
if( SymGetLineFromAddr64( process, stackframe.AddrFrame.Offset, &dline, &line ) )
{
len += Q_snprintf(message + len, 1024 - len,"Frame: %s:%d:%d\n",
(char*)line.FileName, (int)line.LineNumber, (int)dline);
}
for( i = 0; i < 25; i++ )
{
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
BOOL result = StackWalk64(
image, process, thread,
&stackframe, &context, NULL,
SymFunctionTableAccess64, SymGetModuleBase64, NULL);
DWORD64 displacement = 0;
if( !result )
break;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_SYM_NAME;
len += Q_snprintf( message + len, 1024 - len, "% 2d %p",
i, (void*)stackframe.AddrPC.Offset );
if( SymFromAddr( process, stackframe.AddrPC.Offset, &displacement, symbol ) )
{
len += Q_snprintf( message + len, 1024 - len, " %s ", symbol->Name );
}
if( SymGetLineFromAddr64( process, stackframe.AddrPC.Offset, &dline, &line ) )
{
len += Q_snprintf(message + len, 1024 - len,"(%s:%d:%d) ",
(char*)line.FileName, (int)line.LineNumber, (int)dline);
}
len += Q_snprintf( message + len, 1024 - len, "(");
len += Sys_ModuleName( process, message + len, (void*)stackframe.AddrPC.Offset, 1024 - len );
len += Q_snprintf( message + len, 1024 - len, ")\n");
}
#if XASH_SDL == 2
if( host.type != HOST_DEDICATED ) // let system to restart server automaticly
SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR, "Sys_Crash", message, host.hWnd );
#endif
Sys_PrintLog( message );
SymCleanup( process );
}
static void Sys_GetProcessName( char *processName, size_t bufferSize )
{
char fullpath[MAX_PATH];
GetModuleBaseName( GetCurrentProcess(), NULL, fullpath, sizeof( fullpath ) - 1 );
COM_FileBase( fullpath, processName, bufferSize );
}
static void Sys_GetMinidumpFileName( const char *processName, char *mdmpFileName, size_t bufferSize )
{
time_t currentUtcTime = time( NULL );
struct tm *currentLocalTime = localtime( &currentUtcTime );
Q_snprintf( mdmpFileName, bufferSize, "%s_%s_crash_%d%.2d%.2d_%.2d%.2d%.2d.mdmp",
processName,
Q_buildcommit(),
currentLocalTime->tm_year + 1900,
currentLocalTime->tm_mon + 1,
currentLocalTime->tm_mday,
currentLocalTime->tm_hour,
currentLocalTime->tm_min,
currentLocalTime->tm_sec);
}
static qboolean Sys_WriteMinidump(PEXCEPTION_POINTERS exceptionInfo, MINIDUMP_TYPE minidumpType)
{
HRESULT errorCode;
string processName;
string mdmpFileName;
MINIDUMP_EXCEPTION_INFORMATION minidumpInfo;
Sys_GetProcessName( processName, sizeof( processName ));
Sys_GetMinidumpFileName( processName, mdmpFileName, sizeof( mdmpFileName ));
SetLastError( NOERROR );
HANDLE fileHandle = CreateFile(
mdmpFileName, GENERIC_WRITE, FILE_SHARE_WRITE,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
errorCode = HRESULT_FROM_WIN32( GetLastError( ));
if( !SUCCEEDED( errorCode )) {
CloseHandle( fileHandle );
return false;
}
minidumpInfo.ThreadId = GetCurrentThreadId();
minidumpInfo.ExceptionPointers = exceptionInfo;
minidumpInfo.ClientPointers = FALSE;
qboolean status = MiniDumpWriteDump(
GetCurrentProcess(), GetCurrentProcessId(), fileHandle,
minidumpType, &minidumpInfo, NULL, NULL);
CloseHandle( fileHandle );
return status;
}
#endif /* DBGHELP */
static LPTOP_LEVEL_EXCEPTION_FILTER oldFilter;
static long _stdcall Sys_Crash( PEXCEPTION_POINTERS pInfo )
{
// save config
if( host.status != HOST_CRASHED )
{
// check to avoid recursive call
host.crashed = true;
#ifdef XASH_SDL
SDL_SetWindowGrab( host.hWnd, SDL_FALSE );
#endif // XASH_SDL
#if DBGHELP
Sys_StackTrace( pInfo );
#else
Sys_Warn( "Sys_Crash: call %p at address %p", pInfo->ExceptionRecord->ExceptionAddress, pInfo->ExceptionRecord->ExceptionCode );
#endif
if( host.type == HOST_NORMAL )
CL_Crashed(); // tell client about crash
else host.status = HOST_CRASHED;
#if DBGHELP
if( Sys_CheckParm( "-minidumps" ))
{
int minidumpFlags = (
MiniDumpWithDataSegs |
MiniDumpWithCodeSegs |
MiniDumpWithHandleData |
MiniDumpWithFullMemory |
MiniDumpWithFullMemoryInfo |
MiniDumpWithIndirectlyReferencedMemory |
MiniDumpWithThreadInfo |
MiniDumpWithModuleHeaders);
if( !Sys_WriteMinidump( pInfo, (MINIDUMP_TYPE)minidumpFlags )) {
// fallback method, create minidump with minimal info in it
Sys_WriteMinidump( pInfo, MiniDumpWithDataSegs );
}
}
#endif
if( host_developer.value <= 0 )
{
// no reason to call debugger in release build - just exit
Sys_Quit();
return EXCEPTION_CONTINUE_EXECUTION;
}
// all other states keep unchanged to let debugger find bug
Sys_DestroyConsole();
}
if( oldFilter )
return oldFilter( pInfo );
return EXCEPTION_CONTINUE_EXECUTION;
}
void Sys_SetupCrashHandler( void )
{
SetErrorMode( SEM_FAILCRITICALERRORS ); // no abort/retry/fail errors
oldFilter = SetUnhandledExceptionFilter( Sys_Crash );
}
void Sys_RestoreCrashHandler( void )
{
// restore filter
if( oldFilter ) SetUnhandledExceptionFilter( oldFilter );
}

View File

@@ -55,3 +55,18 @@ void Platform_MessageBox( const char *title, const char *message, qboolean paren
MessageBox( parentMainWindow ? host.hWnd : NULL, message, title, MB_OK|MB_SETFOREGROUND|MB_ICONSTOP );
}
#endif // XASH_MESSAGEBOX == MSGBOX_WIN32
// I don't know why we need this or what this does
void Platform_SendKeyEvents( void )
{
MSG msg;
while( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ))
{
if( !GetMessage( &msg, NULL, 0, 0 ))
Sys_Quit ();
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}

View File

@@ -593,7 +593,7 @@ qboolean SV_CheckID( const char *id );
// sv_frame.c
//
void SV_InactivateClients( void );
int SV_FindBestBaselineForStatic( int index, entity_state_t **baseline, entity_state_t *to );
int SV_FindBestBaseline( int index, entity_state_t **baseline, entity_state_t *to, client_frame_t *frame, qboolean player );
void SV_SkipUpdates( void );
//

View File

@@ -3022,7 +3022,6 @@ static const ucmd_t ucmds[] =
{ "disconnect", SV_Disconnect_f },
{ "userinfo", SV_UpdateUserinfo_f },
{ "_sv_build_info", SV_SendBuildInfo_f },
{ NULL, NULL }
};
static const ucmd_t enttoolscmds[] =
@@ -3032,7 +3031,6 @@ static const ucmd_t enttoolscmds[] =
{ "ent_fire", SV_EntFire_f },
{ "ent_create", SV_EntCreate_f },
{ "ent_getvars", SV_EntGetVars_f },
{ NULL, NULL }
};
/*
@@ -3042,25 +3040,30 @@ SV_ExecuteUserCommand
*/
static void SV_ExecuteClientCommand( sv_client_t *cl, const char *s )
{
const ucmd_t *u;
int i;
Cmd_TokenizeString( s );
for( u = ucmds; u->name; u++ )
for( i = 0; i < ARRAYSIZE( ucmds ); i++ )
{
const ucmd_t *u = &ucmds[i];
if( !Q_strcmp( Cmd_Argv( 0 ), u->name ))
{
if( !u->func( cl ))
Con_Printf( "'%s' is not valid from the console\n", u->name );
else Con_Reportf( "ucmd->%s()\n", u->name );
break;
else
Con_Reportf( "ucmd->%s()\n", u->name );
return;
}
}
if( !u->name && sv_enttools_enable.value > 0.0f && !sv.background )
if( sv_enttools_enable.value > 0.0f && !sv.background )
{
for( u = enttoolscmds; u->name; u++ )
for( i = 0; i < ARRAYSIZE( enttoolscmds ); i++ )
{
const ucmd_t *u = &enttoolscmds[i];
if( !Q_strcmp( Cmd_Argv( 0 ), u->name ))
{
Con_Reportf( "enttools->%s(): %s\n", u->name, s );
@@ -3070,12 +3073,12 @@ static void SV_ExecuteClientCommand( sv_client_t *cl, const char *s )
if( u->func )
u->func( cl );
break;
return;
}
}
}
if( !u->name && sv.state == ss_active )
if( sv.state == ss_active )
{
qboolean fullupdate = !Q_strcmp( Cmd_Argv( 0 ), "fullupdate" );

View File

@@ -846,7 +846,7 @@ Kick everyone off, possibly in preparation for a new game
*/
static void SV_KillServer_f( void )
{
Host_ShutdownServer();
SV_Shutdown( "Server was killed due to shutdownserver command\n" );
}
/*
@@ -954,6 +954,22 @@ static void Rcon_Redirect_f( void )
Msg( "Redirection enabled for next %d lines\n", lines );
}
static void SV_ListMessages_f( void )
{
int i;
Con_Printf( "num size name\n" );
for( i = 1; i < MAX_USER_MESSAGES; i++ )
{
if( !COM_CheckStringEmpty( svgame.msg[i].name ))
break;
Con_Printf( "%3d\t%3d\t%s\n", svgame.msg[i].number, svgame.msg[i].size, svgame.msg[i].name );
}
Con_Printf( "Total %i messages\n", i - 1 );
}
/*
==================
SV_InitHostCommands
@@ -1006,6 +1022,7 @@ void SV_InitOperatorCommands( void )
Cmd_AddCommand( "logaddress", SV_SetLogAddress_f, "sets address and port for remote logging host" );
Cmd_AddCommand( "log", SV_ServerLog_f, "enables logging to file" );
Cmd_AddCommand( "str64stats", SV_PrintStr64Stats_f, "print engine pool string statistics" );
Cmd_AddCommand( "sv_list_messages", SV_ListMessages_f, "list registered user messages" );
if( host.type == HOST_NORMAL )
{

View File

@@ -178,9 +178,10 @@ Encode a client frame onto the network channel
SV_FindBestBaseline
trying to deltas with previous entities
set frame to NULL to check for static entities
=============
*/
static int SV_FindBestBaseline( sv_client_t *cl, int index, entity_state_t **baseline, entity_state_t *to, client_frame_t *frame, qboolean player )
int SV_FindBestBaseline( int index, entity_state_t **baseline, entity_state_t *to, client_frame_t *frame, qboolean player )
{
int bestBitCount;
int i, bitCount;
@@ -193,7 +194,13 @@ static int SV_FindBestBaseline( sv_client_t *cl, int index, entity_state_t **bas
for( i = index - 1; bestBitCount > 0 && i >= 0 && ( index - i ) < ( MAX_CUSTOM_BASELINES - 1 ); i-- )
{
// don't worry about underflow in circular buffer
entity_state_t *test = &svs.packet_entities[(frame->first_entity+i) % svs.num_client_entities];
entity_state_t *test;
// if set, then it's normal entity
if( frame != NULL )
test = &svs.packet_entities[(frame->first_entity+i) % svs.num_client_entities];
else
test = &svs.static_entities[i];
if( to->entityType == test->entityType )
{
@@ -209,44 +216,12 @@ static int SV_FindBestBaseline( sv_client_t *cl, int index, entity_state_t **bas
// using delta from previous entity as baseline for current
if( index != bestfound )
*baseline = &svs.packet_entities[(frame->first_entity+bestfound) % svs.num_client_entities];
return index - bestfound;
}
/*
=============
SV_FindBestBaselineForStatic
trying to deltas with previous static entities
=============
*/
int SV_FindBestBaselineForStatic( int index, entity_state_t **baseline, entity_state_t *to )
{
int bestBitCount;
int i, bitCount;
int bestfound, j;
bestBitCount = j = Delta_TestBaseline( *baseline, to, false, sv.time );
bestfound = index;
// lookup backward for previous 64 states and try to interpret current delta as baseline
for( i = index - 1; bestBitCount > 0 && i >= 0 && ( index - i ) < ( MAX_CUSTOM_BASELINES - 1 ); i-- )
{
// don't worry about underflow in circular buffer
entity_state_t *test = &svs.static_entities[i];
bitCount = Delta_TestBaseline( test, to, false, sv.time );
if( bitCount < bestBitCount )
{
bestBitCount = bitCount;
bestfound = i;
}
if( frame != NULL )
*baseline = &svs.packet_entities[(frame->first_entity+bestfound) % svs.num_client_entities];
else
*baseline = &svs.static_entities[bestfound];
}
// using delta from previous entity as baseline for current
if( index != bestfound )
*baseline = &svs.static_entities[bestfound];
return index - bestfound;
}
@@ -347,7 +322,7 @@ static void SV_EmitPacketEntities( sv_client_t *cl, client_frame_t *to, sizebuf_
// trying to reduce message by select optimal baseline
if( !sv_instancedbaseline.value || !sv.num_instanced || sv.last_valid_baseline > newnum )
{
offset = SV_FindBestBaseline( cl, newindex, &baseline, newent, to, player );
offset = SV_FindBestBaseline( newindex, &baseline, newent, to, player );
}
else
{

View File

@@ -578,7 +578,7 @@ qboolean SV_CreateStaticEntity( sizebuf_t *msg, int index )
state->number = 0;
// trying to compress with previous delta's
offset = SV_FindBestBaselineForStatic( index, &baseline, state );
offset = SV_FindBestBaseline( index, &baseline, state, NULL, false );
MSG_BeginServerCmd( msg, svc_spawnstatic );
MSG_WriteDeltaEntity( baseline, state, msg, true, DELTA_STATIC, sv.time, offset );
@@ -1565,21 +1565,6 @@ edict_t *SV_FindGlobalEntity( string_t classname, string_t globalname )
return pent;
}
/*
==============
pfnGetEntityIllum
returns averaged lightvalue for entity
==============
*/
static int GAME_EXPORT pfnGetEntityIllum( edict_t* pEnt )
{
if( !SV_IsValidEdict( pEnt ))
return -1;
return SV_LightForEntity( pEnt );
}
/*
=================
pfnFindEntityInSphere
@@ -2450,10 +2435,17 @@ pfnLightStyle
*/
static void GAME_EXPORT pfnLightStyle( int style, const char* val )
{
if( style < 0 ) style = 0;
if( style < 0 )
style = 0;
if( style >= MAX_LIGHTSTYLES )
{
Host_Error( "%s: style: %i >= %d", __func__, style, MAX_LIGHTSTYLES );
if( sv.loadgame ) return; // don't let the world overwrite our restored styles
return;
}
if( sv.loadgame )
return; // don't let the world overwrite our restored styles
SV_SetLightStyle( style, val, 0.0f ); // set correct style
}
@@ -3520,7 +3512,7 @@ static int GAME_EXPORT pfnRegUserMsg( const char *pszName, int iSize )
{
// see if already registered
if( !Q_strcmp( svgame.msg[i].name, pszName ))
return svc_lastmsg + i; // offset
return svgame.msg[i].number;
}
if( i == MAX_USER_MESSAGES )
@@ -4446,6 +4438,11 @@ static void GAME_EXPORT pfnGetPlayerStats( const edict_t *pClient, int *ping, in
if( ping ) *ping = cl->latency * 1000;
}
static void GAME_EXPORT Cmd_AddServerCommand( const char *cmd_name, xcommand_t function )
{
Cmd_AddCommandEx( cmd_name, function, "server command", CMD_SERVERDLL, __func__ );
}
/*
=============
pfnForceUnmodified
@@ -4677,7 +4674,7 @@ static enginefuncs_t gEngfuncs =
pfnChangeYaw,
pfnChangePitch,
SV_FindEntityByString,
pfnGetEntityIllum,
SV_LightForEntity,
pfnFindEntityInSphere,
pfnFindClientInPVS,
pfnEntitiesInPVS,

View File

@@ -805,7 +805,8 @@ static void SV_SetupClients( void )
if( !changed_maxclients ) return; // nothing to change
// if clients count was changed we need to run full shutdown procedure
if( svs.maxclients ) Host_ShutdownServer();
if( svs.maxclients )
SV_Shutdown( "Server was killed due to maxclients change\n" );
// copy the actual value from cvar
svs.maxclients = (int)sv_maxclients.value;

View File

@@ -1784,21 +1784,23 @@ static void SV_Physics_Entity( edict_t *ent )
static void SV_RunLightStyles( void )
{
int i, ofs;
lightstyle_t *ls;
float scale;
scale = 1.0f;
int i;
// run lightstyles animation
for( i = 0, ls = sv.lightstyles; i < MAX_LIGHTSTYLES; i++, ls++ )
for( i = 0; i < MAX_LIGHTSTYLES; i++ )
{
lightstyle_t *ls = &sv.lightstyles[i];
int ofs;
ls->time += sv.frametime;
ofs = (ls->time * 10);
if( ls->length == 0 ) ls->value = scale; // disable this light
else if( ls->length == 1 ) ls->value = ( ls->map[0] / 12.0f ) * scale;
else ls->value = ( ls->map[ofs % ls->length] / 12.0f ) * scale;
if( ls->length == 0 )
ls->value = 1.0f; // disable this light
else if( ls->length == 1 )
ls->value = ls->map[0] / 12.0f;
else
ls->value = ls->map[ofs % ls->length] / 12.0f;
}
}

View File

@@ -141,7 +141,8 @@ static TYPEDESCRIPTION gSaveClient[] =
DEFINE_ARRAY( SAVE_CLIENT, introTrack, FIELD_CHARACTER, 64 ),
DEFINE_ARRAY( SAVE_CLIENT, mainTrack, FIELD_CHARACTER, 64 ),
DEFINE_FIELD( SAVE_CLIENT, trackPosition, FIELD_INTEGER ),
DEFINE_FIELD( SAVE_CLIENT, viewentity, FIELD_SHORT ),
// mods based on HLU SDK disallow usage of FIELD_SHORT
DEFINE_ARRAY( SAVE_CLIENT, viewentity, FIELD_CHARACTER, sizeof( short )),
DEFINE_FIELD( SAVE_CLIENT, wateralpha, FIELD_FLOAT ),
DEFINE_FIELD( SAVE_CLIENT, wateramp, FIELD_FLOAT ),
};
@@ -150,7 +151,8 @@ static TYPEDESCRIPTION gDecalEntry[] =
{
DEFINE_FIELD( decallist_t, position, FIELD_VECTOR ),
DEFINE_ARRAY( decallist_t, name, FIELD_CHARACTER, 64 ),
DEFINE_FIELD( decallist_t, entityIndex, FIELD_SHORT ),
// mods based on HLU SDK disallow usage of FIELD_SHORT
DEFINE_ARRAY( decallist_t, entityIndex, FIELD_CHARACTER, sizeof( short )),
DEFINE_FIELD( decallist_t, depth, FIELD_CHARACTER ),
DEFINE_FIELD( decallist_t, flags, FIELD_CHARACTER ),
DEFINE_FIELD( decallist_t, scale, FIELD_FLOAT ),
@@ -158,6 +160,7 @@ static TYPEDESCRIPTION gDecalEntry[] =
DEFINE_ARRAY( decallist_t, studio_state, FIELD_CHARACTER, sizeof( modelstate_t )),
};
// Can use any FIELD type here because only Xash3D games will spawn static entities
static TYPEDESCRIPTION gStaticEntry[] =
{
DEFINE_FIELD( entity_state_t, messagenum, FIELD_MODELNAME ), // HACKHACK: store model into messagenum
@@ -200,7 +203,8 @@ static TYPEDESCRIPTION gStaticEntry[] =
static TYPEDESCRIPTION gSoundEntry[] =
{
DEFINE_ARRAY( soundlist_t, name, FIELD_CHARACTER, 64 ),
DEFINE_FIELD( soundlist_t, entnum, FIELD_SHORT ),
// mods based on HLU SDK disallow usage of FIELD_SHORT
DEFINE_ARRAY( soundlist_t, entnum, FIELD_CHARACTER, sizeof( short )),
DEFINE_FIELD( soundlist_t, origin, FIELD_VECTOR ),
DEFINE_FIELD( soundlist_t, volume, FIELD_FLOAT ),
DEFINE_FIELD( soundlist_t, attenuation, FIELD_FLOAT ),

View File

@@ -1508,23 +1508,16 @@ trace_t SV_MoveToss( edict_t *tossent, edict_t *ignore )
===============================================================================
*/
static vec3_t sv_pointColor;
/*
=================
SV_RecursiveLightPoint
=================
*/
static qboolean SV_RecursiveLightPoint( model_t *model, mnode_t *node, const vec3_t start, const vec3_t end )
static qboolean SV_RecursiveLightPoint( model_t *model, mnode_t *node, const vec3_t start, const vec3_t end, vec3_t point_color )
{
float front, back, scale, frac;
int i, map, side, size;
float ds, dt, s, t;
int sample_size;
msurface_t *surf;
mextrasurf_t *info;
color24 *lm;
vec3_t mid;
float front, back, frac;
int i, side;
vec3_t mid;
// didn't hit anything
if( !node || node->contents < 0 )
@@ -1536,27 +1529,28 @@ static qboolean SV_RecursiveLightPoint( model_t *model, mnode_t *node, const vec
side = front < 0.0f;
if(( back < 0.0f ) == side )
return SV_RecursiveLightPoint( model, node->children[side], start, end );
return SV_RecursiveLightPoint( model, node->children[side], start, end, point_color );
frac = front / ( front - back );
VectorLerp( start, frac, end, mid );
// co down front side
if( SV_RecursiveLightPoint( model, node->children[side], start, mid ))
if( SV_RecursiveLightPoint( model, node->children[side], start, mid, point_color ))
return true; // hit something
if(( back < 0.0f ) == side )
return false;// didn't hit anything
return false; // didn't hit anything
// check for impact on this node
surf = model->surfaces + node->firstsurface;
for( i = 0; i < node->numsurfaces; i++, surf++ )
for( i = 0; i < node->numsurfaces; i++ )
{
int smax, tmax;
info = surf->info;
const msurface_t *surf = &model->surfaces[node->firstsurface + i];
const mextrasurf_t *info = surf->info;
int smax, tmax, map, size;
int sample_size;
float ds, dt, s, t;
const color24 *lm;
if( FBitSet( surf->flags, SURF_DRAWTILED ))
continue; // no lightmaps
@@ -1582,26 +1576,27 @@ static qboolean SV_RecursiveLightPoint( model_t *model, mnode_t *node, const vec
ds /= sample_size;
dt /= sample_size;
VectorClear( sv_pointColor );
VectorClear( point_color );
lm = surf->samples + Q_rint( dt ) * smax + Q_rint( ds );
size = smax * tmax;
for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255; map++ )
{
scale = sv.lightstyles[surf->styles[map]].value;
float scale = sv.lightstyles[surf->styles[map]].value;
sv_pointColor[0] += lm->r * scale;
sv_pointColor[1] += lm->g * scale;
sv_pointColor[2] += lm->b * scale;
point_color[0] += lm->r * scale;
point_color[1] += lm->g * scale;
point_color[2] += lm->b * scale;
lm += size; // skip to next lightmap
}
return true;
}
// go down back side
return SV_RecursiveLightPoint( model, node->children[!side], mid, end );
return SV_RecursiveLightPoint( model, node->children[!side], mid, end, point_color );
}
/*
@@ -1615,10 +1610,8 @@ void SV_SetLightStyle( int style, const char* s, float f )
{
int j, k;
Q_strncpy( sv.lightstyles[style].pattern, s, sizeof( sv.lightstyles[0].pattern ));
j = Q_strncpy( sv.lightstyles[style].pattern, s, sizeof( sv.lightstyles[0].pattern ));
sv.lightstyles[style].time = f;
j = Q_strlen( s );
sv.lightstyles[style].length = j;
for( k = 0; k < j; k++ )
@@ -1642,12 +1635,16 @@ grab the ambient lighting color for current point
*/
int SV_LightForEntity( edict_t *pEdict )
{
vec3_t start, end;
vec3_t point_color = { 1.0f, 1.0f, 1.0f };
vec3_t start, end;
if( !SV_IsValidEdict( pEdict ))
return -1;
if( FBitSet( pEdict->v.effects, EF_FULLBRIGHT ) || !sv.worldmodel->lightdata )
return 255;
// player has more precision light level that come from client-side
// player has more precise light level that come from client-side
if( FBitSet( pEdict->v.flags, FL_CLIENT ))
return pEdict->v.light_level;
@@ -1657,9 +1654,8 @@ int SV_LightForEntity( edict_t *pEdict )
if( FBitSet( pEdict->v.effects, EF_INVLIGHT ))
end[2] = start[2] + world.size[2];
else end[2] = start[2] - world.size[2];
VectorSet( sv_pointColor, 1.0f, 1.0f, 1.0f );
SV_RecursiveLightPoint( sv.worldmodel, sv.worldmodel->nodes, start, end );
SV_RecursiveLightPoint( sv.worldmodel, sv.worldmodel->nodes, start, end, point_color );
return VectorAvg( sv_pointColor );
return VectorAvg( point_color );
}

View File

@@ -130,7 +130,6 @@ def configure(conf):
conf.define_cond('XASH_CUSTOM_SWAP', conf.options.CUSTOM_SWAP)
conf.define_cond('XASH_ENABLE_MAIN', conf.env.DISABLE_LAUNCHER)
conf.define_cond('XASH_NO_ASYNC_NS_RESOLVE', conf.options.NO_ASYNC_RESOLVE)
conf.define_cond('DBGHELP', conf.env.DEST_OS == 'win32')
conf.define_cond('PSAPI_VERSION', conf.env.DEST_OS == 'win32') # will be defined as 1
for refdll in conf.refdlls:

View File

@@ -16,6 +16,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#define _GNU_SOURCE 1
#include "build.h"
#include <fcntl.h>
#include <sys/types.h>
@@ -32,6 +34,9 @@ GNU General Public License for more details.
#endif
#include <stdio.h>
#include <stdarg.h>
#if HAVE_MEMFD_CREATE
#include <sys/mman.h>
#endif
#include "port.h"
#include "defaults.h"
#include "const.h"
@@ -1666,9 +1671,10 @@ Internal function used to create a file_t and open the relevant non-packed file
*/
file_t *FS_SysOpen( const char *filepath, const char *mode )
{
file_t *file;
int mod, opt;
uint ind;
file_t *file;
int mod, opt, fd = -1;
qboolean memfile = false;
uint ind;
// Parse the mode string
switch( mode[0] )
@@ -1708,30 +1714,52 @@ file_t *FS_SysOpen( const char *filepath, const char *mode )
}
}
file = (file_t *)Mem_Calloc( fs_mempool, sizeof( *file ));
file->filetime = FS_SysFileTime( filepath );
file->ungetc = EOF;
// the 'm' flag let's user to create temporary file in memory
// through so-called "anonymous files"
if( Q_strchr( mode, 'm' ))
{
#if HAVE_MEMFD_CREATE
#ifndef MFD_NOEXEC_SEAL
#define MFD_NOEXEC_SEAL 8U
#endif
fd = memfd_create( filepath, MFD_CLOEXEC | MFD_NOEXEC_SEAL );
// through fcntl() and MFD_ALLOW_SEALING we could enforce
// read-write flags but we don't really care about them yet
if( fd < 0 )
Con_Printf( S_ERROR "%s: can't create anonymous file %s: %s", __func__, filepath, strerror( errno ));
else memfile = true;
#endif
// if it's unsupported, we can open it on disk
}
if( fd < 0 )
{
#if XASH_WIN32
file->handle = _wopen( FS_PathToWideChar( filepath ), mod | opt, 0666 );
fd = _wopen( FS_PathToWideChar( filepath ), mod | opt, 0666 );
#else
file->handle = open( filepath, mod|opt, 0666 );
fd = open( filepath, mod|opt, 0666 );
#endif
}
#if !XASH_WIN32
if( file->handle < 0 )
FS_BackupFileName( file, filepath, mod|opt );
#endif
if( file->handle < 0 )
if( fd < 0 )
{
if( errno != ENOENT )
Con_Printf( S_ERROR "%s: can't open file %s: %s\n", __func__, filepath, strerror( errno ));
Mem_Free( file );
return NULL;
}
file = (file_t *)Mem_Calloc( fs_mempool, sizeof( *file ));
file->filetime = memfile ? 0 : FS_SysFileTime( filepath );
file->ungetc = EOF;
file->handle = fd;
#if !XASH_WIN32
if( !memfile )
FS_BackupFileName( file, filepath, mod|opt );
#endif
file->searchpath = NULL;
file->real_length = lseek( file->handle, 0, SEEK_END );

View File

@@ -1,5 +1,9 @@
#!/usr/bin/env python
MEMFD_CREATE_TEST = '''#define _GNU_SOURCE
#include <sys/mman.h>
int main(int argc, char **argv) { return memfd_create(argv[0], 0); }'''
def options(opt):
pass
@@ -11,6 +15,9 @@ def configure(conf):
elif conf.env.cxxshlib_PATTERN.startswith('lib'): # remove lib prefix for other systems than Android
conf.env.cxxshlib_PATTERN = conf.env.cxxshlib_PATTERN[3:]
if conf.check_cc(fragment=MEMFD_CREATE_TEST, msg='Checking for memfd_create', mandatory=False):
conf.define('HAVE_MEMFD_CREATE', 1)
def build(bld):
bld(name = 'filesystem_includes', export_includes = '.')

View File

@@ -1,6 +1,7 @@
/*
crtlib.h - internal stdlib
Copyright (C) 2011 Uncle Mike
Copyright (C) Free Software Foundation, Inc
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
@@ -105,6 +106,12 @@ char *COM_ParseFileSafe( char *data, char *token, const int size, unsigned int f
int matchpattern( const char *in, const char *pattern, qboolean caseinsensitive );
int matchpattern_with_separator( const char *in, const char *pattern, qboolean caseinsensitive, const char *separators, qboolean wildcard_least_one );
//
// dllhelpers.c
//
void ClearExports( const dllfunc_t *funcs, size_t num_funcs );
qboolean ValidateExports( const dllfunc_t *funcs, size_t num_funcs );
static inline char Q_toupper( const char in )
{
char out;
@@ -169,63 +176,62 @@ static inline char *Q_strstr( const char *s1, const char *s2 )
}
// libc extensions, be careful what to enable or what not
static inline size_t Q_strnlen( const char *str, size_t size )
{
#if HAVE_STRNLEN
return strnlen( str, size );
#else
const char *p = (const char *)memchr( str, 0, size );
return p ? p - str : size;
#endif
}
static inline size_t Q_strncpy( char *dst, const char *src, size_t size )
{
#if HAVE_STRLCPY
if( unlikely( !dst || !src || !size ))
return 0;
#if HAVE_STRLCPY
return strlcpy( dst, src, size );
#else
size_t len;
if( unlikely( !dst || !src || !size ))
return 0;
len = strlen( src );
if( len + 1 > size ) // check if truncate
{
memcpy( dst, src, size - 1 );
dst[size - 1] = 0;
}
else memcpy( dst, src, len + 1 );
size_t len = strlen( src );
return len; // count does not include NULL
if( len >= size ) // check if truncate
{
memcpy( dst, src, size );
dst[size - 1] = 0;
}
else memcpy( dst, src, len + 1 );
return len; // count does not include NULL
}
#endif
}
static inline size_t Q_strncat( char *dst, const char *src, size_t size )
{
#if HAVE_STRLCAT
if( unlikely( !dst || !src || !size ))
return 0;
#if HAVE_STRLCAT
return strlcat( dst, src, size );
#else
char *d = dst;
const char *s = src;
size_t n = size;
size_t dlen;
if( unlikely( !dst || !src || !size ))
return 0;
// find the end of dst and adjust bytes left but don't go past end
while( n-- != 0 && *d != '\0' ) d++;
dlen = d - dst;
n = size - dlen;
if( n == 0 ) return( dlen + Q_strlen( s ));
while( *s != '\0' )
{
if( n != 1 )
{
*d++ = *s;
n--;
}
s++;
}
size_t slen = strlen( src );
size_t dlen = Q_strnlen( dst, size );
*d = '\0';
return( dlen + ( s - src )); // count does not include NULL
if( dlen != size )
{
size_t copy = size - dlen - 1;
if( copy > slen )
copy = slen;
memcpy( &dst[dlen], src, copy );
dst[dlen + copy] = 0;
}
return dlen + slen;
}
#endif
}

36
public/dllhelpers.c Normal file
View File

@@ -0,0 +1,36 @@
/*
dllhelpers.c - dll exports helpers
Copyright (C) 2024 Alibek Omarov
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.
*/
#include "crtlib.h"
void ClearExports( const dllfunc_t *funcs, size_t num_funcs )
{
size_t i;
for( i = 0; i < num_funcs; i++ )
*(funcs[i].func) = NULL;
}
qboolean ValidateExports( const dllfunc_t *funcs, size_t num_funcs )
{
size_t i;
for( i = 0; i < num_funcs; i++ )
{
if( *(funcs[i].func) == NULL )
return false;
}
return true;
}

View File

@@ -29,6 +29,10 @@ int main(int argc, char **argv) { return strlcpy(argv[1], argv[2], 10); }'''
STRLCAT_TEST = '''#include <string.h>
int main(int argc, char **argv) { return strlcat(argv[1], argv[2], 10); }'''
STRNLEN_TEST = '''#include <string.h>
int main(int argc, char **argv) { return (int)strnlen(argv[0], 10); }
'''
ALLOCA_TEST = '''#include <%s>
int main(void) { alloca(1); return 0; }'''
@@ -106,6 +110,7 @@ def configure(conf):
check_libc_extension(STRCHRNUL_TEST, 'strchrnul', 'HAVE_STRCHRNUL')
check_libc_extension(STRLCPY_TEST, 'strlcpy', 'HAVE_STRLCPY')
check_libc_extension(STRLCAT_TEST, 'strlcat', 'HAVE_STRLCAT')
check_libc_extension(STRNLEN_TEST, 'strnlen', 'HAVE_STRNLEN')
# kill temporary uselib
del conf.env.DEFINES_export

View File

@@ -20,6 +20,7 @@ GNU General Public License for more details.
#if HAVE_TGMATH_H
#include <tgmath.h>
#endif
#include <string.h>
#include "build.h"
#include "xash3d_types.h"
@@ -141,15 +142,6 @@ CONSTANTS GLOBALS
// a1ba: we never return pointers to these globals
// so help compiler optimize constants away
#define vec3_origin ((vec3_t){ 0.0f, 0.0f, 0.0f })
#define m_matrix3x4_identity ((matrix3x4) { \
{ 1.0f, 0.0f, 0.0f, 0.0f }, \
{ 0.0f, 1.0f, 0.0f, 0.0f }, \
{ 0.0f, 0.0f, 1.0f, 0.0f }} )
#define m_matrix4x4_identity ((matrix4x4) { \
{ 1.0f, 0.0f, 0.0f, 0.0f }, \
{ 0.0f, 1.0f, 0.0f, 0.0f }, \
{ 0.0f, 0.0f, 1.0f, 0.0f }, \
{ 0.0f, 0.0f, 0.0f, 1.0f }} )
extern const int boxpnt[6][4];
extern const float m_bytenormals[NUMVERTEXNORMALS][3];
@@ -191,7 +183,11 @@ int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p );
//
// matrixlib.c
//
#define Matrix3x4_LoadIdentity( mat ) Matrix3x4_Copy( mat, m_matrix3x4_identity )
static inline void Matrix3x4_LoadIdentity( matrix3x4 m )
{
memset( m, 0, sizeof( *m ));
m[0][0] = m[1][1] = m[2][2] = 1.0f;
}
#define Matrix3x4_Copy( out, in ) memcpy( out, in, sizeof( matrix3x4 ))
void Matrix3x4_VectorTransform( const matrix3x4 in, const float v[3], float out[3] );
void Matrix3x4_VectorITransform( const matrix3x4 in, const float v[3], float out[3] );
@@ -203,7 +199,11 @@ void Matrix3x4_CreateFromEntity( matrix3x4 out, const vec3_t angles, const vec3_
void Matrix3x4_TransformAABB( const matrix3x4 world, const vec3_t mins, const vec3_t maxs, vec3_t absmin, vec3_t absmax );
void Matrix3x4_AnglesFromMatrix( const matrix3x4 in, vec3_t out );
#define Matrix4x4_LoadIdentity( mat ) Matrix4x4_Copy( mat, m_matrix4x4_identity )
static inline void Matrix4x4_LoadIdentity( matrix4x4 m )
{
memset( m, 0, sizeof( *m ));
m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0f;
}
#define Matrix4x4_Copy( out, in ) memcpy( out, in, sizeof( matrix4x4 ))
void Matrix4x4_VectorTransform( const matrix4x4 in, const float v[3], float out[3] );
void Matrix4x4_VectorITransform( const matrix4x4 in, const float v[3], float out[3] );

View File

@@ -561,8 +561,6 @@ void GL_CheckForErrors_( const char *filename, const int fileline );
const char *GL_ErrorString( int err );
qboolean GL_Support( int r_ext );
int GL_MaxTextureUnits( void );
qboolean GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char *cvarname, int r_ext, float minver );
void GL_SetExtension( int r_ext, int enable );
//
// gl_triapi.c

View File

@@ -38,7 +38,6 @@ CVAR_DEFINE_AUTO( r_ripple, "0", FCVAR_GLCONFIG, "enable software-like water tex
CVAR_DEFINE_AUTO( r_ripple_updatetime, "0.05", FCVAR_GLCONFIG, "how fast ripple simulation is" );
CVAR_DEFINE_AUTO( r_ripple_spawntime, "0.1", FCVAR_GLCONFIG, "how fast new ripples spawn" );
DEFINE_ENGINE_SHARED_CVAR_LIST()
poolhandle_t r_temppool;
@@ -54,208 +53,199 @@ glwstate_t glw_state;
#define GL_CALL( x ) #x, (void**)&p##x
#endif
static dllfunc_t opengl_110funcs[] =
static const dllfunc_t opengl_110funcs[] =
{
{ GL_CALL( glClearColor ) },
{ GL_CALL( glClear ) },
{ GL_CALL( glAlphaFunc ) },
{ GL_CALL( glBlendFunc ) },
{ GL_CALL( glCullFace ) },
{ GL_CALL( glDrawBuffer ) },
{ GL_CALL( glReadBuffer ) },
{ GL_CALL( glAccum ) },
{ GL_CALL( glEnable ) },
{ GL_CALL( glDisable ) },
{ GL_CALL( glEnableClientState ) },
{ GL_CALL( glDisableClientState ) },
{ GL_CALL( glGetBooleanv ) },
{ GL_CALL( glGetDoublev ) },
{ GL_CALL( glGetFloatv ) },
{ GL_CALL( glGetIntegerv ) },
{ GL_CALL( glGetError ) },
{ GL_CALL( glGetString ) },
{ GL_CALL( glFinish ) },
{ GL_CALL( glFlush ) },
{ GL_CALL( glClearDepth ) },
{ GL_CALL( glDepthFunc ) },
{ GL_CALL( glDepthMask ) },
{ GL_CALL( glDepthRange ) },
{ GL_CALL( glFrontFace ) },
{ GL_CALL( glDrawElements ) },
{ GL_CALL( glDrawArrays ) },
{ GL_CALL( glColorMask ) },
{ GL_CALL( glIndexPointer ) },
{ GL_CALL( glVertexPointer ) },
{ GL_CALL( glNormalPointer ) },
{ GL_CALL( glColorPointer ) },
{ GL_CALL( glTexCoordPointer ) },
{ GL_CALL( glArrayElement ) },
{ GL_CALL( glColor3f ) },
{ GL_CALL( glColor3fv ) },
{ GL_CALL( glColor4f ) },
{ GL_CALL( glColor4fv ) },
{ GL_CALL( glColor3ub ) },
{ GL_CALL( glColor4ub ) },
{ GL_CALL( glColor4ubv ) },
{ GL_CALL( glTexCoord1f ) },
{ GL_CALL( glTexCoord2f ) },
{ GL_CALL( glTexCoord3f ) },
{ GL_CALL( glTexCoord4f ) },
{ GL_CALL( glTexCoord1fv ) },
{ GL_CALL( glTexCoord2fv ) },
{ GL_CALL( glTexCoord3fv ) },
{ GL_CALL( glTexCoord4fv ) },
{ GL_CALL( glTexGenf ) },
{ GL_CALL( glTexGenfv ) },
{ GL_CALL( glTexGeni ) },
{ GL_CALL( glVertex2f ) },
{ GL_CALL( glVertex3f ) },
{ GL_CALL( glVertex3fv ) },
{ GL_CALL( glNormal3f ) },
{ GL_CALL( glNormal3fv ) },
{ GL_CALL( glBegin ) },
{ GL_CALL( glEnd ) },
{ GL_CALL( glLineWidth ) },
{ GL_CALL( glPointSize ) },
{ GL_CALL( glMatrixMode ) },
{ GL_CALL( glOrtho ) },
{ GL_CALL( glRasterPos2f ) },
{ GL_CALL( glFrustum ) },
{ GL_CALL( glViewport ) },
{ GL_CALL( glPushMatrix ) },
{ GL_CALL( glPopMatrix ) },
{ GL_CALL( glPushAttrib ) },
{ GL_CALL( glPopAttrib ) },
{ GL_CALL( glLoadIdentity ) },
{ GL_CALL( glLoadMatrixd ) },
{ GL_CALL( glLoadMatrixf ) },
{ GL_CALL( glMultMatrixd ) },
{ GL_CALL( glMultMatrixf ) },
{ GL_CALL( glRotated ) },
{ GL_CALL( glRotatef ) },
{ GL_CALL( glScaled ) },
{ GL_CALL( glScalef ) },
{ GL_CALL( glTranslated ) },
{ GL_CALL( glTranslatef ) },
{ GL_CALL( glReadPixels ) },
{ GL_CALL( glDrawPixels ) },
{ GL_CALL( glStencilFunc ) },
{ GL_CALL( glStencilMask ) },
{ GL_CALL( glStencilOp ) },
{ GL_CALL( glClearStencil ) },
{ GL_CALL( glIsEnabled ) },
{ GL_CALL( glIsList ) },
{ GL_CALL( glIsTexture ) },
{ GL_CALL( glTexEnvf ) },
{ GL_CALL( glTexEnvfv ) },
{ GL_CALL( glTexEnvi ) },
{ GL_CALL( glTexParameterf ) },
{ GL_CALL( glTexParameterfv ) },
{ GL_CALL( glTexParameteri ) },
{ GL_CALL( glHint ) },
{ GL_CALL( glPixelStoref ) },
{ GL_CALL( glPixelStorei ) },
{ GL_CALL( glGenTextures ) },
{ GL_CALL( glDeleteTextures ) },
{ GL_CALL( glBindTexture ) },
{ GL_CALL( glTexImage1D ) },
{ GL_CALL( glTexImage2D ) },
{ GL_CALL( glTexSubImage1D ) },
{ GL_CALL( glTexSubImage2D ) },
{ GL_CALL( glCopyTexImage1D ) },
{ GL_CALL( glCopyTexImage2D ) },
{ GL_CALL( glCopyTexSubImage1D ) },
{ GL_CALL( glCopyTexSubImage2D ) },
{ GL_CALL( glScissor ) },
{ GL_CALL( glGetTexImage ) },
{ GL_CALL( glGetTexEnviv ) },
{ GL_CALL( glPolygonOffset ) },
{ GL_CALL( glPolygonMode ) },
{ GL_CALL( glPolygonStipple ) },
{ GL_CALL( glClipPlane ) },
{ GL_CALL( glGetClipPlane ) },
{ GL_CALL( glShadeModel ) },
{ GL_CALL( glGetTexLevelParameteriv ) },
{ GL_CALL( glGetTexLevelParameterfv ) },
{ GL_CALL( glFogfv ) },
{ GL_CALL( glFogf ) },
{ GL_CALL( glFogi ) },
{ NULL , NULL }
{ GL_CALL( glClearColor ) },
{ GL_CALL( glClear ) },
{ GL_CALL( glAlphaFunc ) },
{ GL_CALL( glBlendFunc ) },
{ GL_CALL( glCullFace ) },
{ GL_CALL( glDrawBuffer ) },
{ GL_CALL( glReadBuffer ) },
{ GL_CALL( glAccum ) },
{ GL_CALL( glEnable ) },
{ GL_CALL( glDisable ) },
{ GL_CALL( glEnableClientState ) },
{ GL_CALL( glDisableClientState ) },
{ GL_CALL( glGetBooleanv ) },
{ GL_CALL( glGetDoublev ) },
{ GL_CALL( glGetFloatv ) },
{ GL_CALL( glGetIntegerv ) },
{ GL_CALL( glGetError ) },
{ GL_CALL( glGetString ) },
{ GL_CALL( glFinish ) },
{ GL_CALL( glFlush ) },
{ GL_CALL( glClearDepth ) },
{ GL_CALL( glDepthFunc ) },
{ GL_CALL( glDepthMask ) },
{ GL_CALL( glDepthRange ) },
{ GL_CALL( glFrontFace ) },
{ GL_CALL( glDrawElements ) },
{ GL_CALL( glDrawArrays ) },
{ GL_CALL( glColorMask ) },
{ GL_CALL( glIndexPointer ) },
{ GL_CALL( glVertexPointer ) },
{ GL_CALL( glNormalPointer ) },
{ GL_CALL( glColorPointer ) },
{ GL_CALL( glTexCoordPointer ) },
{ GL_CALL( glArrayElement ) },
{ GL_CALL( glColor3f ) },
{ GL_CALL( glColor3fv ) },
{ GL_CALL( glColor4f ) },
{ GL_CALL( glColor4fv ) },
{ GL_CALL( glColor3ub ) },
{ GL_CALL( glColor4ub ) },
{ GL_CALL( glColor4ubv ) },
{ GL_CALL( glTexCoord1f ) },
{ GL_CALL( glTexCoord2f ) },
{ GL_CALL( glTexCoord3f ) },
{ GL_CALL( glTexCoord4f ) },
{ GL_CALL( glTexCoord1fv ) },
{ GL_CALL( glTexCoord2fv ) },
{ GL_CALL( glTexCoord3fv ) },
{ GL_CALL( glTexCoord4fv ) },
{ GL_CALL( glTexGenf ) },
{ GL_CALL( glTexGenfv ) },
{ GL_CALL( glTexGeni ) },
{ GL_CALL( glVertex2f ) },
{ GL_CALL( glVertex3f ) },
{ GL_CALL( glVertex3fv ) },
{ GL_CALL( glNormal3f ) },
{ GL_CALL( glNormal3fv ) },
{ GL_CALL( glBegin ) },
{ GL_CALL( glEnd ) },
{ GL_CALL( glLineWidth ) },
{ GL_CALL( glPointSize ) },
{ GL_CALL( glMatrixMode ) },
{ GL_CALL( glOrtho ) },
{ GL_CALL( glRasterPos2f ) },
{ GL_CALL( glFrustum ) },
{ GL_CALL( glViewport ) },
{ GL_CALL( glPushMatrix ) },
{ GL_CALL( glPopMatrix ) },
{ GL_CALL( glPushAttrib ) },
{ GL_CALL( glPopAttrib ) },
{ GL_CALL( glLoadIdentity ) },
{ GL_CALL( glLoadMatrixd ) },
{ GL_CALL( glLoadMatrixf ) },
{ GL_CALL( glMultMatrixd ) },
{ GL_CALL( glMultMatrixf ) },
{ GL_CALL( glRotated ) },
{ GL_CALL( glRotatef ) },
{ GL_CALL( glScaled ) },
{ GL_CALL( glScalef ) },
{ GL_CALL( glTranslated ) },
{ GL_CALL( glTranslatef ) },
{ GL_CALL( glReadPixels ) },
{ GL_CALL( glDrawPixels ) },
{ GL_CALL( glStencilFunc ) },
{ GL_CALL( glStencilMask ) },
{ GL_CALL( glStencilOp ) },
{ GL_CALL( glClearStencil ) },
{ GL_CALL( glIsEnabled ) },
{ GL_CALL( glIsList ) },
{ GL_CALL( glIsTexture ) },
{ GL_CALL( glTexEnvf ) },
{ GL_CALL( glTexEnvfv ) },
{ GL_CALL( glTexEnvi ) },
{ GL_CALL( glTexParameterf ) },
{ GL_CALL( glTexParameterfv ) },
{ GL_CALL( glTexParameteri ) },
{ GL_CALL( glHint ) },
{ GL_CALL( glPixelStoref ) },
{ GL_CALL( glPixelStorei ) },
{ GL_CALL( glGenTextures ) },
{ GL_CALL( glDeleteTextures ) },
{ GL_CALL( glBindTexture ) },
{ GL_CALL( glTexImage1D ) },
{ GL_CALL( glTexImage2D ) },
{ GL_CALL( glTexSubImage1D ) },
{ GL_CALL( glTexSubImage2D ) },
{ GL_CALL( glCopyTexImage1D ) },
{ GL_CALL( glCopyTexImage2D ) },
{ GL_CALL( glCopyTexSubImage1D ) },
{ GL_CALL( glCopyTexSubImage2D ) },
{ GL_CALL( glScissor ) },
{ GL_CALL( glGetTexImage ) },
{ GL_CALL( glGetTexEnviv ) },
{ GL_CALL( glPolygonOffset ) },
{ GL_CALL( glPolygonMode ) },
{ GL_CALL( glPolygonStipple ) },
{ GL_CALL( glClipPlane ) },
{ GL_CALL( glGetClipPlane ) },
{ GL_CALL( glShadeModel ) },
{ GL_CALL( glGetTexLevelParameteriv ) },
{ GL_CALL( glGetTexLevelParameterfv ) },
{ GL_CALL( glFogfv ) },
{ GL_CALL( glFogf ) },
{ GL_CALL( glFogi ) },
};
static dllfunc_t debugoutputfuncs[] =
static const dllfunc_t debugoutputfuncs[] =
{
{ GL_CALL( glDebugMessageControlARB ) },
{ GL_CALL( glDebugMessageInsertARB ) },
{ GL_CALL( glDebugMessageCallbackARB ) },
{ GL_CALL( glGetDebugMessageLogARB ) },
{ NULL , NULL }
{ GL_CALL( glDebugMessageControlARB ) },
{ GL_CALL( glDebugMessageInsertARB ) },
{ GL_CALL( glDebugMessageCallbackARB ) },
{ GL_CALL( glGetDebugMessageLogARB ) },
};
static dllfunc_t multitexturefuncs[] =
static const dllfunc_t multitexturefuncs[] =
{
{ GL_CALL( glMultiTexCoord1f ) },
{ GL_CALL( glMultiTexCoord2f ) },
{ GL_CALL( glMultiTexCoord3f ) },
{ GL_CALL( glMultiTexCoord4f ) },
{ GL_CALL( glActiveTexture ) },
{ GL_CALL( glActiveTextureARB ) },
{ GL_CALL( glClientActiveTexture ) },
{ GL_CALL( glClientActiveTextureARB ) },
{ NULL , NULL }
{ GL_CALL( glMultiTexCoord1f ) },
{ GL_CALL( glMultiTexCoord2f ) },
{ GL_CALL( glMultiTexCoord3f ) },
{ GL_CALL( glMultiTexCoord4f ) },
{ GL_CALL( glActiveTexture ) },
{ GL_CALL( glActiveTextureARB ) },
{ GL_CALL( glClientActiveTexture ) },
{ GL_CALL( glClientActiveTextureARB ) },
};
static dllfunc_t texture3dextfuncs[] =
static const dllfunc_t texture3dextfuncs[] =
{
{ GL_CALL( glTexImage3D ) },
{ GL_CALL( glTexSubImage3D ) },
{ GL_CALL( glCopyTexSubImage3D ) },
{ NULL , NULL }
{ GL_CALL( glTexImage3D ) },
{ GL_CALL( glTexSubImage3D ) },
{ GL_CALL( glCopyTexSubImage3D ) },
};
static dllfunc_t texturecompressionfuncs[] =
static const dllfunc_t texturecompressionfuncs[] =
{
{ GL_CALL( glCompressedTexImage3DARB ) },
{ GL_CALL( glCompressedTexImage2DARB ) },
{ GL_CALL( glCompressedTexImage1DARB ) },
{ GL_CALL( glCompressedTexSubImage3DARB ) },
{ GL_CALL( glCompressedTexSubImage2DARB ) },
{ GL_CALL( glCompressedTexSubImage1DARB ) },
{ GL_CALL( glGetCompressedTexImage ) },
{ NULL , NULL }
{ GL_CALL( glCompressedTexImage3DARB ) },
{ GL_CALL( glCompressedTexImage2DARB ) },
{ GL_CALL( glCompressedTexImage1DARB ) },
{ GL_CALL( glCompressedTexSubImage3DARB ) },
{ GL_CALL( glCompressedTexSubImage2DARB ) },
{ GL_CALL( glCompressedTexSubImage1DARB ) },
{ GL_CALL( glGetCompressedTexImage ) },
};
static dllfunc_t vbofuncs[] =
static const dllfunc_t vbofuncs[] =
{
{ GL_CALL( glBindBufferARB ) },
{ GL_CALL( glDeleteBuffersARB ) },
{ GL_CALL( glGenBuffersARB ) },
{ GL_CALL( glIsBufferARB ) },
{ GL_CALL( glBindBufferARB ) },
{ GL_CALL( glDeleteBuffersARB ) },
{ GL_CALL( glGenBuffersARB ) },
{ GL_CALL( glIsBufferARB ) },
#if !XASH_GLES
{ GL_CALL( glMapBufferARB ) },
{ GL_CALL( glUnmapBufferARB ) },
{ GL_CALL( glMapBufferARB ) },
{ GL_CALL( glUnmapBufferARB ) },
#endif
{ GL_CALL( glBufferDataARB ) },
{ GL_CALL( glBufferSubDataARB ) },
{ NULL, NULL }
{ GL_CALL( glBufferDataARB ) },
{ GL_CALL( glBufferSubDataARB ) },
};
static dllfunc_t multisampletexfuncs[] =
static const dllfunc_t multisampletexfuncs[] =
{
{ GL_CALL(glTexImage2DMultisample) },
{ NULL, NULL }
{ GL_CALL(glTexImage2DMultisample) },
};
static dllfunc_t drawrangeelementsfuncs[] =
static const dllfunc_t drawrangeelementsfuncs[] =
{
{ GL_CALL( glDrawRangeElements ) },
{ NULL, NULL }
};
static dllfunc_t drawrangeelementsextfuncs[] =
static const dllfunc_t drawrangeelementsextfuncs[] =
{
{ GL_CALL( glDrawRangeElementsEXT ) },
{ NULL, NULL }
};
@@ -263,85 +253,80 @@ static dllfunc_t drawrangeelementsextfuncs[] =
// still need resolve some ext dynamicly, and mangling beginend wrappers will help only with LTO
// anyway this will not work with gl-wes/nanogl, we do not link to libGLESv2, so skip this now
#if !XASH_GL_STATIC
static dllfunc_t mapbufferrangefuncs[] =
static const dllfunc_t mapbufferrangefuncs[] =
{
{ GL_CALL( glMapBufferRange ) },
{ GL_CALL( glFlushMappedBufferRange ) },
#if XASH_GLES
{ GL_CALL( glUnmapBufferARB ) },
#endif
{ NULL, NULL }
};
static dllfunc_t drawrangeelementsbasevertexfuncs[] =
static const dllfunc_t drawrangeelementsbasevertexfuncs[] =
{
{ GL_CALL( glDrawRangeElementsBaseVertex ) },
{ NULL, NULL }
};
static dllfunc_t bufferstoragefuncs[] =
static const dllfunc_t bufferstoragefuncs[] =
{
{ GL_CALL( glBufferStorage ) },
{ NULL, NULL }
};
static dllfunc_t shaderobjectsfuncs[] =
static const dllfunc_t shaderobjectsfuncs[] =
{
{ GL_CALL( glDeleteObjectARB ) },
{ GL_CALL( glGetHandleARB ) },
{ GL_CALL( glDetachObjectARB ) },
{ GL_CALL( glCreateShaderObjectARB ) },
{ GL_CALL( glShaderSourceARB ) },
{ GL_CALL( glCompileShaderARB ) },
{ GL_CALL( glCreateProgramObjectARB ) },
{ GL_CALL( glAttachObjectARB ) },
{ GL_CALL( glLinkProgramARB ) },
{ GL_CALL( glUseProgramObjectARB ) },
{ GL_CALL( glValidateProgramARB ) },
{ GL_CALL( glUniform1fARB ) },
{ GL_CALL( glUniform2fARB ) },
{ GL_CALL( glUniform3fARB ) },
{ GL_CALL( glUniform4fARB ) },
{ GL_CALL( glUniform1iARB ) },
{ GL_CALL( glUniform2iARB ) },
{ GL_CALL( glUniform3iARB ) },
{ GL_CALL( glUniform4iARB ) },
{ GL_CALL( glUniform1fvARB ) },
{ GL_CALL( glUniform2fvARB ) },
{ GL_CALL( glUniform3fvARB ) },
{ GL_CALL( glUniform4fvARB ) },
{ GL_CALL( glUniform1ivARB ) },
{ GL_CALL( glUniform2ivARB ) },
{ GL_CALL( glUniform3ivARB ) },
{ GL_CALL( glUniform4ivARB ) },
{ GL_CALL( glUniformMatrix2fvARB ) },
{ GL_CALL( glUniformMatrix3fvARB ) },
{ GL_CALL( glUniformMatrix4fvARB ) },
{ GL_CALL( glGetObjectParameterfvARB ) },
{ GL_CALL( glGetObjectParameterivARB ) },
{ GL_CALL( glGetInfoLogARB ) },
{ GL_CALL( glGetAttachedObjectsARB ) },
{ GL_CALL( glGetUniformLocationARB ) },
{ GL_CALL( glGetActiveUniformARB ) },
{ GL_CALL( glGetUniformfvARB ) },
{ GL_CALL( glGetUniformivARB ) },
{ GL_CALL( glGetShaderSourceARB ) },
{ GL_CALL( glVertexAttribPointerARB ) },
{ GL_CALL( glEnableVertexAttribArrayARB ) },
{ GL_CALL( glDisableVertexAttribArrayARB ) },
{ GL_CALL( glBindAttribLocationARB ) },
{ GL_CALL( glGetActiveAttribARB ) },
{ GL_CALL( glGetAttribLocationARB ) },
{ GL_CALL( glVertexAttrib2fARB ) },
{ GL_CALL( glVertexAttrib2fvARB ) },
// { GL_CALL( glVertexAttrib3fv ) },
// { GL_CALL( glVertexAttrib4f ) },
// { GL_CALL( glVertexAttrib4fv ) },
// { GL_CALL( glVertexAttrib4ubv ) },
{ NULL, NULL }
{ GL_CALL( glDeleteObjectARB ) },
{ GL_CALL( glGetHandleARB ) },
{ GL_CALL( glDetachObjectARB ) },
{ GL_CALL( glCreateShaderObjectARB ) },
{ GL_CALL( glShaderSourceARB ) },
{ GL_CALL( glCompileShaderARB ) },
{ GL_CALL( glCreateProgramObjectARB ) },
{ GL_CALL( glAttachObjectARB ) },
{ GL_CALL( glLinkProgramARB ) },
{ GL_CALL( glUseProgramObjectARB ) },
{ GL_CALL( glValidateProgramARB ) },
{ GL_CALL( glUniform1fARB ) },
{ GL_CALL( glUniform2fARB ) },
{ GL_CALL( glUniform3fARB ) },
{ GL_CALL( glUniform4fARB ) },
{ GL_CALL( glUniform1iARB ) },
{ GL_CALL( glUniform2iARB ) },
{ GL_CALL( glUniform3iARB ) },
{ GL_CALL( glUniform4iARB ) },
{ GL_CALL( glUniform1fvARB ) },
{ GL_CALL( glUniform2fvARB ) },
{ GL_CALL( glUniform3fvARB ) },
{ GL_CALL( glUniform4fvARB ) },
{ GL_CALL( glUniform1ivARB ) },
{ GL_CALL( glUniform2ivARB ) },
{ GL_CALL( glUniform3ivARB ) },
{ GL_CALL( glUniform4ivARB ) },
{ GL_CALL( glUniformMatrix2fvARB ) },
{ GL_CALL( glUniformMatrix3fvARB ) },
{ GL_CALL( glUniformMatrix4fvARB ) },
{ GL_CALL( glGetObjectParameterfvARB ) },
{ GL_CALL( glGetObjectParameterivARB ) },
{ GL_CALL( glGetInfoLogARB ) },
{ GL_CALL( glGetAttachedObjectsARB ) },
{ GL_CALL( glGetUniformLocationARB ) },
{ GL_CALL( glGetActiveUniformARB ) },
{ GL_CALL( glGetUniformfvARB ) },
{ GL_CALL( glGetUniformivARB ) },
{ GL_CALL( glGetShaderSourceARB ) },
{ GL_CALL( glVertexAttribPointerARB ) },
{ GL_CALL( glEnableVertexAttribArrayARB ) },
{ GL_CALL( glDisableVertexAttribArrayARB ) },
{ GL_CALL( glBindAttribLocationARB ) },
{ GL_CALL( glGetActiveAttribARB ) },
{ GL_CALL( glGetAttribLocationARB ) },
{ GL_CALL( glVertexAttrib2fARB ) },
{ GL_CALL( glVertexAttrib2fvARB ) },
//{ GL_CALL( glVertexAttrib3fv ) },
//{ GL_CALL( glVertexAttrib4f ) },
//{ GL_CALL( glVertexAttrib4fv ) },
//{ GL_CALL( glVertexAttrib4ubv ) },
};
/*
==================
Even if *ARB functions may work in GL driver in Core context,
@@ -354,90 +339,86 @@ Commented out lines left there intentionally to prevent usage on core/gles
==================
*/
static dllfunc_t shaderobjectsfuncs_gles[] =
static const dllfunc_t shaderobjectsfuncs_gles[] =
{
{ "glDeleteShader" , (void **)&pglDeleteObjectARB },
//{ "glGetHandleARB" , (void **)&pglGetHandleARB },
{ "glDetachShader" , (void **)&pglDetachObjectARB },
{ "glCreateShader" , (void **)&pglCreateShaderObjectARB },
{ "glShaderSource" , (void **)&pglShaderSourceARB },
{ "glCompileShader" , (void **)&pglCompileShaderARB },
{ "glCreateProgram" , (void **)&pglCreateProgramObjectARB },
{ "glAttachShader" , (void **)&pglAttachObjectARB },
{ "glLinkProgram" , (void **)&pglLinkProgramARB },
{ "glUseProgram" , (void **)&pglUseProgramObjectARB },
{ "glValidateProgram" , (void **)&pglValidateProgramARB },
{ "glUniform1f" , (void **)&pglUniform1fARB },
{ "glUniform2f" , (void **)&pglUniform2fARB },
{ "glUniform3f" , (void **)&pglUniform3fARB },
{ "glUniform4f" , (void **)&pglUniform4fARB },
{ "glUniform1i" , (void **)&pglUniform1iARB },
{ "glUniform2i" , (void **)&pglUniform2iARB },
{ "glUniform3i" , (void **)&pglUniform3iARB },
{ "glUniform4i" , (void **)&pglUniform4iARB },
{ "glUniform1f" , (void **)&pglUniform1fvARB },
{ "glUniform2fv" , (void **)&pglUniform2fvARB },
{ "glUniform3fv" , (void **)&pglUniform3fvARB },
{ "glUniform4fv" , (void **)&pglUniform4fvARB },
{ "glUniform1iv" , (void **)&pglUniform1ivARB },
{ "glUniform2iv" , (void **)&pglUniform2ivARB },
{ "glUniform3iv" , (void **)&pglUniform3ivARB },
{ "glUniform4iv" , (void **)&pglUniform4ivARB },
{ "glUniformMatrix2fv" , (void **)&pglUniformMatrix2fvARB },
{ "glUniformMatrix3fv" , (void **)&pglUniformMatrix3fvARB },
{ "glUniformMatrix4fv" , (void **)&pglUniformMatrix4fvARB },
// { "glGetShaderfv" , (void **)&pglGetObjectParameterfvARB }, // missing in ES2?
{ "glGetShaderiv" , (void **)&pglGetObjectParameterivARB },
{ "glGetShaderInfoLog" , (void **)&pglGetInfoLogARB },
// { "glGetAttachedObjects" , (void **)&pglGetAttachedObjectsARB }, // missing in ES2?
{ "glGetUniformLocation" , (void **)&pglGetUniformLocationARB },
{ "glGetActiveUniform" , (void **)&pglGetActiveUniformARB },
{ "glGetUniformfv" , (void **)&pglGetUniformfvARB },
{ "glGetUniformiv" , (void **)&pglGetUniformivARB },
{ "glGetShaderSource" , (void **)&pglGetShaderSourceARB },
{ "glVertexAttribPointer" , (void **)&pglVertexAttribPointerARB },
{ "glEnableVertexAttribArray" , (void **)&pglEnableVertexAttribArrayARB },
{ "glDisableVertexAttribArray" , (void **)&pglDisableVertexAttribArrayARB },
{ "glBindAttribLocation" , (void **)&pglBindAttribLocationARB },
{ "glGetActiveAttrib" , (void **)&pglGetActiveAttribARB },
{ "glGetAttribLocation" , (void **)&pglGetAttribLocationARB },
{ "glVertexAttrib2f" , (void **)&pglVertexAttrib2fARB },
{ "glVertexAttrib2fv" , (void **)&pglVertexAttrib2fvARB },
{ "glVertexAttrib3fv" , (void **)&pglVertexAttrib3fvARB },
{ "glDeleteShader" , (void **)&pglDeleteObjectARB },
//{ "glGetHandleARB" , (void **)&pglGetHandleARB },
{ "glDetachShader" , (void **)&pglDetachObjectARB },
{ "glCreateShader" , (void **)&pglCreateShaderObjectARB },
{ "glShaderSource" , (void **)&pglShaderSourceARB },
{ "glCompileShader" , (void **)&pglCompileShaderARB },
{ "glCreateProgram" , (void **)&pglCreateProgramObjectARB },
{ "glAttachShader" , (void **)&pglAttachObjectARB },
{ "glLinkProgram" , (void **)&pglLinkProgramARB },
{ "glUseProgram" , (void **)&pglUseProgramObjectARB },
{ "glValidateProgram" , (void **)&pglValidateProgramARB },
{ "glUniform1f" , (void **)&pglUniform1fARB },
{ "glUniform2f" , (void **)&pglUniform2fARB },
{ "glUniform3f" , (void **)&pglUniform3fARB },
{ "glUniform4f" , (void **)&pglUniform4fARB },
{ "glUniform1i" , (void **)&pglUniform1iARB },
{ "glUniform2i" , (void **)&pglUniform2iARB },
{ "glUniform3i" , (void **)&pglUniform3iARB },
{ "glUniform4i" , (void **)&pglUniform4iARB },
{ "glUniform1f" , (void **)&pglUniform1fvARB },
{ "glUniform2fv" , (void **)&pglUniform2fvARB },
{ "glUniform3fv" , (void **)&pglUniform3fvARB },
{ "glUniform4fv" , (void **)&pglUniform4fvARB },
{ "glUniform1iv" , (void **)&pglUniform1ivARB },
{ "glUniform2iv" , (void **)&pglUniform2ivARB },
{ "glUniform3iv" , (void **)&pglUniform3ivARB },
{ "glUniform4iv" , (void **)&pglUniform4ivARB },
{ "glUniformMatrix2fv" , (void **)&pglUniformMatrix2fvARB },
{ "glUniformMatrix3fv" , (void **)&pglUniformMatrix3fvARB },
{ "glUniformMatrix4fv" , (void **)&pglUniformMatrix4fvARB },
//{ "glGetShaderfv" , (void **)&pglGetObjectParameterfvARB }, // missing in ES2?
{ "glGetShaderiv" , (void **)&pglGetObjectParameterivARB },
{ "glGetShaderInfoLog" , (void **)&pglGetInfoLogARB },
//{ "glGetAttachedObjects" , (void **)&pglGetAttachedObjectsARB }, // missing in ES2?
{ "glGetUniformLocation" , (void **)&pglGetUniformLocationARB },
{ "glGetActiveUniform" , (void **)&pglGetActiveUniformARB },
{ "glGetUniformfv" , (void **)&pglGetUniformfvARB },
{ "glGetUniformiv" , (void **)&pglGetUniformivARB },
{ "glGetShaderSource" , (void **)&pglGetShaderSourceARB },
{ "glVertexAttribPointer" , (void **)&pglVertexAttribPointerARB },
{ "glEnableVertexAttribArray" , (void **)&pglEnableVertexAttribArrayARB },
{ "glDisableVertexAttribArray" , (void **)&pglDisableVertexAttribArrayARB },
{ "glBindAttribLocation" , (void **)&pglBindAttribLocationARB },
{ "glGetActiveAttrib" , (void **)&pglGetActiveAttribARB },
{ "glGetAttribLocation" , (void **)&pglGetAttribLocationARB },
{ "glVertexAttrib2f" , (void **)&pglVertexAttrib2fARB },
{ "glVertexAttrib2fv" , (void **)&pglVertexAttrib2fvARB },
{ "glVertexAttrib3fv" , (void **)&pglVertexAttrib3fvARB },
// Core/GLES only
{ GL_CALL( glGetProgramiv ) },
{ GL_CALL( glDeleteProgram ) },
{ GL_CALL( glGetProgramInfoLog ) },
//{ "glVertexAttrib4f" , (void **)&pglVertexAttrib4fARB },
//{ "glVertexAttrib4fv" , (void **)&pglVertexAttrib4fvARB },
//{ "glVertexAttrib4ubv" , (void **)&pglVertexAttrib4ubvARB },
{ NULL, NULL }
// Core/GLES only
{ GL_CALL( glGetProgramiv ) },
{ GL_CALL( glDeleteProgram ) },
{ GL_CALL( glGetProgramInfoLog ) },
//{ "glVertexAttrib4f" , (void **)&pglVertexAttrib4fARB },
//{ "glVertexAttrib4fv" , (void **)&pglVertexAttrib4fvARB },
//{ "glVertexAttrib4ubv" , (void **)&pglVertexAttrib4ubvARB },
};
static dllfunc_t vaofuncs[] =
static const dllfunc_t vaofuncs[] =
{
{ GL_CALL( glBindVertexArray ) },
{ GL_CALL( glDeleteVertexArrays ) },
{ GL_CALL( glGenVertexArrays ) },
{ GL_CALL( glIsVertexArray ) },
{ NULL, NULL }
{ GL_CALL( glBindVertexArray ) },
{ GL_CALL( glDeleteVertexArrays ) },
{ GL_CALL( glGenVertexArrays ) },
{ GL_CALL( glIsVertexArray ) },
};
static dllfunc_t multitexturefuncs_es[] =
static const dllfunc_t multitexturefuncs_es[] =
{
{ GL_CALL( glActiveTexture ) },
{ GL_CALL( glActiveTextureARB ) },
{ GL_CALL( glClientActiveTexture ) },
{ GL_CALL( glClientActiveTextureARB ) },
{ NULL , NULL }
{ GL_CALL( glActiveTexture ) },
{ GL_CALL( glActiveTextureARB ) },
{ GL_CALL( glClientActiveTexture ) },
{ GL_CALL( glClientActiveTextureARB ) },
};
static dllfunc_t multitexturefuncs_es2[] =
static const dllfunc_t multitexturefuncs_es2[] =
{
{ GL_CALL( glActiveTexture ) },
{ GL_CALL( glActiveTextureARB ) },
{ NULL , NULL }
{ GL_CALL( glActiveTexture ) },
{ GL_CALL( glActiveTextureARB ) },
};
#endif // !XASH_GL_STATIC
@@ -476,7 +457,7 @@ static void APIENTRY GL_DebugOutput( GLuint source, GLuint type, GLuint id, GLui
GL_SetExtension
=================
*/
void GL_SetExtension( int r_ext, int enable )
static void GL_SetExtension( int r_ext, int enable )
{
if( r_ext >= 0 && r_ext < GL_EXTCOUNT )
glConfig.extension[r_ext] = enable ? GL_TRUE : GL_FALSE;
@@ -514,12 +495,12 @@ int GL_MaxTextureUnits( void )
GL_CheckExtension
=================
*/
qboolean GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char *cvarname, int r_ext, float minver )
static qboolean GL_CheckExtension( const char *name, const dllfunc_t *funcs, size_t num_funcs, const char *cvarname, int r_ext, float minver )
{
const dllfunc_t *func;
cvar_t *parm = NULL;
const char *extensions_string;
char desc[MAX_VA_STRING];
size_t i;
cvar_t *parm = NULL;
const char *extensions_string;
char desc[MAX_VA_STRING];
float glver = (float)glConfig.version_major + glConfig.version_minor / 10.0f;
gEngfuncs.Con_Reportf( "%s: %s ", __func__, name );
@@ -550,17 +531,16 @@ qboolean GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char
#if !XASH_GL_STATIC
// clear exports
for( func = funcs; func && func->name; func++ )
*func->func = NULL;
ClearExports( funcs, num_funcs );
for( func = funcs; func && func->name; func++ )
for( i = 0; i < num_funcs; i++ )
{
// functions are cleared before all the extensions are evaluated
if(( *func->func = (void *)gEngfuncs.GL_GetProcAddress( func->name )) == NULL )
if(( *(funcs[i].func) = (void *)gEngfuncs.GL_GetProcAddress( funcs[i].name )) == NULL )
{
string name;
char *end;
size_t i = 0;
size_t j = 0;
#if XASH_GLES
const char *suffixes[] = { "", "EXT", "OES" };
#else
@@ -568,7 +548,7 @@ qboolean GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char
#endif
// HACK: fix ARB names
Q_strncpy( name, func->name, sizeof( name ));
Q_strncpy( name, funcs[i].name, sizeof( name ));
if(( end = Q_strstr( name, "ARB" )))
{
*end = '\0';
@@ -576,21 +556,21 @@ qboolean GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char
else // I need Q_strstrnul
{
end = name + Q_strlen( name );
i++; // skip empty suffix
j++; // skip empty suffix
}
for( ; i < sizeof( suffixes ) / sizeof( suffixes[0] ); i++ )
for( ; j < sizeof( suffixes ) / sizeof( suffixes[0] ); j++ )
{
void *f;
Q_strncat( name, suffixes[i], sizeof( name ));
Q_strncat( name, suffixes[j], sizeof( name ));
if(( f = gEngfuncs.GL_GetProcAddress( name )))
{
// GL_GetProcAddress prints errors about missing functions, so tell user that we found it with different name
gEngfuncs.Con_Printf( S_NOTE "found %s\n", name );
*func->func = f;
*(funcs[i].func) = f;
break;
}
else
@@ -600,7 +580,7 @@ qboolean GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char
}
// not found...
if( i == sizeof( suffixes ) / sizeof( suffixes[0] ))
if( j == sizeof( suffixes ) / sizeof( suffixes[0] ))
{
GL_SetExtension( r_ext, false );
}
@@ -798,14 +778,14 @@ static void GL_InitExtensionsGLES( void )
switch( extid )
{
case GL_ARB_VERTEX_BUFFER_OBJECT_EXT:
GL_CheckExtension( "vertex_buffer_object", vbofuncs, "gl_vertex_buffer_object", extid, 1.0 );
GL_CheckExtension( "vertex_buffer_object", vbofuncs, ARRAYSIZE( vbofuncs ), "gl_vertex_buffer_object", extid, 1.0 );
break;
case GL_ARB_MULTITEXTURE:
if( !GL_CheckExtension( "multitexture", multitexturefuncs, "gl_arb_multitexture", GL_ARB_MULTITEXTURE, 1.0 ) && glConfig.wrapper == GLES_WRAPPER_NONE )
if( !GL_CheckExtension( "multitexture", multitexturefuncs, ARRAYSIZE( multitexturefuncs ), "gl_arb_multitexture", GL_ARB_MULTITEXTURE, 1.0 ) && glConfig.wrapper == GLES_WRAPPER_NONE )
{
#if !XASH_GL_STATIC
if( !GL_CheckExtension( "multitexture_es1", multitexturefuncs_es, "gl_arb_multitexture", GL_ARB_MULTITEXTURE, 1.0 )
&& !GL_CheckExtension( "multitexture_es2", multitexturefuncs_es2, "gl_arb_multitexture", GL_ARB_MULTITEXTURE, 2.0 ))
if( !GL_CheckExtension( "multitexture_es1", multitexturefuncs_es, ARRAYSIZE( multitexturefuncs_es ), "gl_arb_multitexture", GL_ARB_MULTITEXTURE, 1.0 )
&& !GL_CheckExtension( "multitexture_es2", multitexturefuncs_es2, ARRAYSIZE( multitexturefuncs_es2 ), "gl_arb_multitexture", GL_ARB_MULTITEXTURE, 2.0 ))
break;
#endif
}
@@ -823,48 +803,48 @@ static void GL_InitExtensionsGLES( void )
glConfig.max_texture_coords = glConfig.max_teximage_units = glConfig.max_texture_units;
break;
case GL_TEXTURE_CUBEMAP_EXT:
if( GL_CheckExtension( "GL_OES_texture_cube_map", NULL, "gl_texture_cubemap", extid, 0 ))
if( GL_CheckExtension( "GL_OES_texture_cube_map", NULL, 0, "gl_texture_cubemap", extid, 0 ))
pglGetIntegerv( GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, &glConfig.max_cubemap_size );
break;
case GL_ANISOTROPY_EXT:
glConfig.max_texture_anisotropy = 0.0f;
if( GL_CheckExtension( "GL_EXT_texture_filter_anisotropic", NULL, "gl_ext_anisotropic_filter", extid, 0 ))
if( GL_CheckExtension( "GL_EXT_texture_filter_anisotropic", NULL, 0, "gl_ext_anisotropic_filter", extid, 0 ))
pglGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glConfig.max_texture_anisotropy );
break;
case GL_TEXTURE_LOD_BIAS:
if( GL_CheckExtension( "GL_EXT_texture_lod_bias", NULL, "gl_texture_mipmap_biasing", extid, 0 ))
if( GL_CheckExtension( "GL_EXT_texture_lod_bias", NULL, 0, "gl_texture_mipmap_biasing", extid, 0 ))
pglGetFloatv( GL_MAX_TEXTURE_LOD_BIAS_EXT, &glConfig.max_texture_lod_bias );
break;
case GL_ARB_TEXTURE_NPOT_EXT:
GL_CheckExtension( "GL_OES_texture_npot", NULL, "gl_texture_npot", extid, 0 );
GL_CheckExtension( "GL_OES_texture_npot", NULL, 0, "gl_texture_npot", extid, 0 );
break;
#if !XASH_GL_STATIC
case GL_SHADER_OBJECTS_EXT:
GL_CheckExtension( "ES2 Shaders", shaderobjectsfuncs_gles, "gl_shaderobjects", extid, 2.0 );
GL_CheckExtension( "ES2 Shaders", shaderobjectsfuncs_gles, ARRAYSIZE( shaderobjectsfuncs_gles ), "gl_shaderobjects", extid, 2.0 );
break;
case GL_ARB_VERTEX_ARRAY_OBJECT_EXT:
if( !GL_CheckExtension( "GL_OES_vertex_array_object", vaofuncs, "gl_vertex_array_object", extid, 3.0 ))
GL_CheckExtension( "GL_EXT_vertex_array_object", vaofuncs, "gl_vertex_array_object", extid, 3.0 );
if( !GL_CheckExtension( "GL_OES_vertex_array_object", vaofuncs, ARRAYSIZE( vaofuncs ), "gl_vertex_array_object", extid, 3.0 ))
GL_CheckExtension( "GL_EXT_vertex_array_object", vaofuncs, ARRAYSIZE( vaofuncs ), "gl_vertex_array_object", extid, 3.0 );
break;
case GL_DRAW_RANGEELEMENTS_EXT:
if( !GL_CheckExtension( "GL_EXT_draw_range_elements", drawrangeelementsfuncs, "gl_drawrangeelements", extid, 3.0 ))
GL_CheckExtension( "GL_OES_draw_range_elements", drawrangeelementsfuncs, "gl_drawrangeelements", extid, 3.0 );
if( !GL_CheckExtension( "GL_EXT_draw_range_elements", drawrangeelementsfuncs, ARRAYSIZE( drawrangeelementsfuncs ), "gl_drawrangeelements", extid, 3.0 ))
GL_CheckExtension( "GL_OES_draw_range_elements", drawrangeelementsfuncs, ARRAYSIZE( drawrangeelementsfuncs ), "gl_drawrangeelements", extid, 3.0 );
break;
case GL_DRAW_RANGE_ELEMENTS_BASE_VERTEX_EXT:
if( !GL_CheckExtension( "GL_OES_draw_elements_base_vertex", drawrangeelementsbasevertexfuncs, "gl_drawrangeelementsbasevertex", GL_DRAW_RANGE_ELEMENTS_BASE_VERTEX_EXT, 0 ))
GL_CheckExtension( "GL_EXT_draw_elements_base_vertex", drawrangeelementsbasevertexfuncs, "gl_drawrangeelementsbasevertex", GL_DRAW_RANGE_ELEMENTS_BASE_VERTEX_EXT, 3.2 );
if( !GL_CheckExtension( "GL_OES_draw_elements_base_vertex", drawrangeelementsbasevertexfuncs, ARRAYSIZE( drawrangeelementsbasevertexfuncs ), "gl_drawrangeelementsbasevertex", GL_DRAW_RANGE_ELEMENTS_BASE_VERTEX_EXT, 0 ))
GL_CheckExtension( "GL_EXT_draw_elements_base_vertex", drawrangeelementsbasevertexfuncs, ARRAYSIZE( drawrangeelementsbasevertexfuncs ), "gl_drawrangeelementsbasevertex", GL_DRAW_RANGE_ELEMENTS_BASE_VERTEX_EXT, 3.2 );
break;
case GL_MAP_BUFFER_RANGE_EXT:
GL_CheckExtension( "GL_EXT_map_buffer_range", mapbufferrangefuncs, "gl_map_buffer_range", GL_MAP_BUFFER_RANGE_EXT , 3.0);
GL_CheckExtension( "GL_EXT_map_buffer_range", mapbufferrangefuncs, ARRAYSIZE( mapbufferrangefuncs ), "gl_map_buffer_range", GL_MAP_BUFFER_RANGE_EXT , 3.0);
break;
case GL_BUFFER_STORAGE_EXT:
GL_CheckExtension( "GL_EXT_buffer_storage", bufferstoragefuncs, "gl_buffer_storage", GL_BUFFER_STORAGE_EXT, 0);
GL_CheckExtension( "GL_EXT_buffer_storage", bufferstoragefuncs, ARRAYSIZE( bufferstoragefuncs ), "gl_buffer_storage", GL_BUFFER_STORAGE_EXT, 0);
break;
#endif
case GL_DEBUG_OUTPUT:
if( glw_state.extended )
GL_CheckExtension( "GL_KHR_debug", debugoutputfuncs, "gl_debug_output", extid, 0 );
GL_CheckExtension( "GL_KHR_debug", debugoutputfuncs, ARRAYSIZE( debugoutputfuncs ), "gl_debug_output", extid, 0 );
else
GL_SetExtension( extid, false );
break;
@@ -918,7 +898,7 @@ static void GL_InitExtensionsBigGL( void )
// multitexture
glConfig.max_texture_units = glConfig.max_texture_coords = glConfig.max_teximage_units = 1;
if( GL_CheckExtension( "GL_ARB_multitexture", multitexturefuncs, "gl_arb_multitexture", GL_ARB_MULTITEXTURE, 1.3f ))
if( GL_CheckExtension( "GL_ARB_multitexture", multitexturefuncs, ARRAYSIZE( multitexturefuncs ), "gl_arb_multitexture", GL_ARB_MULTITEXTURE, 1.3f ))
{
pglGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB, &glConfig.max_texture_units );
}
@@ -927,7 +907,7 @@ static void GL_InitExtensionsBigGL( void )
GL_SetExtension( GL_ARB_MULTITEXTURE, false );
// 3d texture support
if( GL_CheckExtension( "GL_EXT_texture3D", texture3dextfuncs, "gl_texture_3d", GL_TEXTURE_3D_EXT, 2.0f ))
if( GL_CheckExtension( "GL_EXT_texture3D", texture3dextfuncs, ARRAYSIZE( texture3dextfuncs ), "gl_texture_3d", GL_TEXTURE_3D_EXT, 2.0f ))
{
pglGetIntegerv( GL_MAX_3D_TEXTURE_SIZE, &glConfig.max_3d_texture_size );
@@ -939,25 +919,25 @@ static void GL_InitExtensionsBigGL( void )
}
// 2d texture array support
if( GL_CheckExtension( "GL_EXT_texture_array", texture3dextfuncs, "gl_texture_2d_array", GL_TEXTURE_ARRAY_EXT, 0 ))
if( GL_CheckExtension( "GL_EXT_texture_array", texture3dextfuncs, ARRAYSIZE( texture3dextfuncs ), "gl_texture_2d_array", GL_TEXTURE_ARRAY_EXT, 0 ))
pglGetIntegerv( GL_MAX_ARRAY_TEXTURE_LAYERS_EXT, &glConfig.max_2d_texture_layers );
// cubemaps support
if( GL_CheckExtension( "GL_ARB_texture_cube_map", NULL, "gl_texture_cubemap", GL_TEXTURE_CUBEMAP_EXT, 0 ))
if( GL_CheckExtension( "GL_ARB_texture_cube_map", NULL, 0, "gl_texture_cubemap", GL_TEXTURE_CUBEMAP_EXT, 0 ))
{
pglGetIntegerv( GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, &glConfig.max_cubemap_size );
// check for seamless cubemaps too
GL_CheckExtension( "GL_ARB_seamless_cube_map", NULL, "gl_texture_cubemap_seamless", GL_ARB_SEAMLESS_CUBEMAP, 0 );
GL_CheckExtension( "GL_ARB_seamless_cube_map", NULL, 0, "gl_texture_cubemap_seamless", GL_ARB_SEAMLESS_CUBEMAP, 0 );
}
GL_CheckExtension( "GL_ARB_texture_non_power_of_two", NULL, "gl_texture_npot", GL_ARB_TEXTURE_NPOT_EXT, 0 );
GL_CheckExtension( "GL_ARB_texture_compression", texturecompressionfuncs, "gl_texture_dxt_compression", GL_TEXTURE_COMPRESSION_EXT, 0 );
if( !GL_CheckExtension( "GL_EXT_texture_edge_clamp", NULL, "gl_clamp_to_edge", GL_CLAMPTOEDGE_EXT, 2.0 )) // present in ES2
GL_CheckExtension( "GL_SGIS_texture_edge_clamp", NULL, "gl_clamp_to_edge", GL_CLAMPTOEDGE_EXT, 0 );
GL_CheckExtension( "GL_ARB_texture_non_power_of_two", NULL, 0, "gl_texture_npot", GL_ARB_TEXTURE_NPOT_EXT, 0 );
GL_CheckExtension( "GL_ARB_texture_compression", texturecompressionfuncs, ARRAYSIZE( texturecompressionfuncs ), "gl_texture_dxt_compression", GL_TEXTURE_COMPRESSION_EXT, 0 );
if( !GL_CheckExtension( "GL_EXT_texture_edge_clamp", NULL, 0, "gl_clamp_to_edge", GL_CLAMPTOEDGE_EXT, 2.0 )) // present in ES2
GL_CheckExtension( "GL_SGIS_texture_edge_clamp", NULL, 0, "gl_clamp_to_edge", GL_CLAMPTOEDGE_EXT, 0 );
glConfig.max_texture_anisotropy = 0.0f;
if( GL_CheckExtension( "GL_EXT_texture_filter_anisotropic", NULL, "gl_texture_anisotropic_filter", GL_ANISOTROPY_EXT, 0 ))
if( GL_CheckExtension( "GL_EXT_texture_filter_anisotropic", NULL, 0, "gl_texture_anisotropic_filter", GL_ANISOTROPY_EXT, 0 ))
pglGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glConfig.max_texture_anisotropy );
#if XASH_WIN32 // Win32 only drivers?
@@ -965,30 +945,30 @@ static void GL_InitExtensionsBigGL( void )
if( glConfig.hardware_type != GLHW_INTEL )
#endif
{
if( GL_CheckExtension( "GL_EXT_texture_lod_bias", NULL, "gl_texture_mipmap_biasing", GL_TEXTURE_LOD_BIAS, 1.4 ))
if( GL_CheckExtension( "GL_EXT_texture_lod_bias", NULL, 0, "gl_texture_mipmap_biasing", GL_TEXTURE_LOD_BIAS, 1.4 ))
pglGetFloatv( GL_MAX_TEXTURE_LOD_BIAS_EXT, &glConfig.max_texture_lod_bias );
}
GL_CheckExtension( "GL_ARB_texture_border_clamp", NULL, NULL, GL_CLAMP_TEXBORDER_EXT, 2.0 ); // present in ES2
GL_CheckExtension( "GL_ARB_texture_border_clamp", NULL, 0, NULL, GL_CLAMP_TEXBORDER_EXT, 2.0 ); // present in ES2
GL_CheckExtension( "GL_ARB_depth_texture", NULL, NULL, GL_DEPTH_TEXTURE, 1.4 ); // missing in gles, check GL_OES_depth_texture
GL_CheckExtension( "GL_ARB_texture_float", NULL, "gl_texture_float", GL_ARB_TEXTURE_FLOAT_EXT, 0 );
GL_CheckExtension( "GL_ARB_depth_buffer_float", NULL, "gl_texture_depth_float", GL_ARB_DEPTH_FLOAT_EXT, 0 );
GL_CheckExtension( "GL_EXT_gpu_shader4", NULL, NULL, GL_EXT_GPU_SHADER4, 0 ); // don't confuse users
GL_CheckExtension( "GL_ARB_vertex_buffer_object", vbofuncs, "gl_vertex_buffer_object", GL_ARB_VERTEX_BUFFER_OBJECT_EXT, 2.0 );
GL_CheckExtension( "GL_ARB_texture_multisample", multisampletexfuncs, "gl_texture_multisample", GL_TEXTURE_MULTISAMPLE, 0 );
GL_CheckExtension( "GL_ARB_texture_compression_bptc", NULL, "gl_texture_bptc_compression", GL_ARB_TEXTURE_COMPRESSION_BPTC, 0 );
GL_CheckExtension( "GL_ARB_depth_texture", NULL, 0, NULL, GL_DEPTH_TEXTURE, 1.4 ); // missing in gles, check GL_OES_depth_texture
GL_CheckExtension( "GL_ARB_texture_float", NULL, 0, "gl_texture_float", GL_ARB_TEXTURE_FLOAT_EXT, 0 );
GL_CheckExtension( "GL_ARB_depth_buffer_float", NULL, 0, "gl_texture_depth_float", GL_ARB_DEPTH_FLOAT_EXT, 0 );
GL_CheckExtension( "GL_EXT_gpu_shader4", NULL, 0, NULL, GL_EXT_GPU_SHADER4, 0 ); // don't confuse users
GL_CheckExtension( "GL_ARB_vertex_buffer_object", vbofuncs, ARRAYSIZE( vbofuncs ), "gl_vertex_buffer_object", GL_ARB_VERTEX_BUFFER_OBJECT_EXT, 2.0 );
GL_CheckExtension( "GL_ARB_texture_multisample", multisampletexfuncs, ARRAYSIZE( multisampletexfuncs ), "gl_texture_multisample", GL_TEXTURE_MULTISAMPLE, 0 );
GL_CheckExtension( "GL_ARB_texture_compression_bptc", NULL, 0, "gl_texture_bptc_compression", GL_ARB_TEXTURE_COMPRESSION_BPTC, 0 );
#if !XASH_GL_STATIC
if( glConfig.context == CONTEXT_TYPE_GL_CORE )
GL_CheckExtension( "shader_objects", shaderobjectsfuncs_gles, "gl_shaderobjects", GL_SHADER_OBJECTS_EXT, 2.0 );
GL_CheckExtension( "shader_objects", shaderobjectsfuncs_gles, ARRAYSIZE( shaderobjectsfuncs_gles ), "gl_shaderobjects", GL_SHADER_OBJECTS_EXT, 2.0 );
else
GL_CheckExtension( "GL_ARB_shader_objects", shaderobjectsfuncs, "gl_shaderobjects", GL_SHADER_OBJECTS_EXT, 2.0 );
GL_CheckExtension( "GL_ARB_vertex_array_object", vaofuncs, "gl_vertex_array_object", GL_ARB_VERTEX_ARRAY_OBJECT_EXT, 3.0 );
GL_CheckExtension( "GL_ARB_buffer_storage", bufferstoragefuncs, "gl_buffer_storage", GL_BUFFER_STORAGE_EXT, 4.4);
GL_CheckExtension( "GL_ARB_map_buffer_range", mapbufferrangefuncs, "gl_map_buffer_range", GL_MAP_BUFFER_RANGE_EXT , 3.0);
GL_CheckExtension( "GL_ARB_draw_elements_base_vertex", drawrangeelementsbasevertexfuncs, "gl_drawrangeelementsbasevertex", GL_DRAW_RANGE_ELEMENTS_BASE_VERTEX_EXT, 3.2 );
GL_CheckExtension( "GL_ARB_shader_objects", shaderobjectsfuncs, ARRAYSIZE( shaderobjectsfuncs ), "gl_shaderobjects", GL_SHADER_OBJECTS_EXT, 2.0 );
GL_CheckExtension( "GL_ARB_vertex_array_object", vaofuncs, ARRAYSIZE( vaofuncs ), "gl_vertex_array_object", GL_ARB_VERTEX_ARRAY_OBJECT_EXT, 3.0 );
GL_CheckExtension( "GL_ARB_buffer_storage", bufferstoragefuncs, ARRAYSIZE( bufferstoragefuncs ), "gl_buffer_storage", GL_BUFFER_STORAGE_EXT, 4.4);
GL_CheckExtension( "GL_ARB_map_buffer_range", mapbufferrangefuncs, ARRAYSIZE( mapbufferrangefuncs ), "gl_map_buffer_range", GL_MAP_BUFFER_RANGE_EXT , 3.0);
GL_CheckExtension( "GL_ARB_draw_elements_base_vertex", drawrangeelementsbasevertexfuncs, ARRAYSIZE( drawrangeelementsbasevertexfuncs ), "gl_drawrangeelementsbasevertex", GL_DRAW_RANGE_ELEMENTS_BASE_VERTEX_EXT, 3.2 );
#endif
if( GL_CheckExtension( "GL_ARB_shading_language_100", NULL, NULL, GL_SHADER_GLSL100_EXT, 2.0 ))
if( GL_CheckExtension( "GL_ARB_shading_language_100", NULL, 0, NULL, GL_SHADER_GLSL100_EXT, 2.0 ))
{
pglGetIntegerv( GL_MAX_TEXTURE_COORDS_ARB, &glConfig.max_texture_coords );
pglGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &glConfig.max_teximage_units );
@@ -1009,11 +989,11 @@ static void GL_InitExtensionsBigGL( void )
}
// rectangle textures support
GL_CheckExtension( "GL_ARB_texture_rectangle", NULL, "gl_texture_rectangle", GL_TEXTURE_2D_RECT_EXT, 0 );
GL_CheckExtension( "GL_ARB_texture_rectangle", NULL, 0, "gl_texture_rectangle", GL_TEXTURE_2D_RECT_EXT, 0 );
if( !GL_CheckExtension( "glDrawRangeElements", drawrangeelementsfuncs, "gl_drawrangeelements", GL_DRAW_RANGEELEMENTS_EXT, 0 ) )
if( !GL_CheckExtension( "glDrawRangeElements", drawrangeelementsfuncs, ARRAYSIZE( drawrangeelementsfuncs ), "gl_drawrangeelements", GL_DRAW_RANGEELEMENTS_EXT, 0 ) )
{
if( GL_CheckExtension( "glDrawRangeElementsEXT", drawrangeelementsextfuncs,
if( GL_CheckExtension( "glDrawRangeElementsEXT", drawrangeelementsextfuncs, ARRAYSIZE( drawrangeelementsextfuncs ),
"gl_drawrangelements", GL_DRAW_RANGEELEMENTS_EXT, 0 ))
{
#if !XASH_GL_STATIC
@@ -1024,7 +1004,7 @@ static void GL_InitExtensionsBigGL( void )
// this won't work without extended context
if( glw_state.extended )
GL_CheckExtension( "GL_ARB_debug_output", debugoutputfuncs, "gl_debug_output", GL_DEBUG_OUTPUT, 0 );
GL_CheckExtension( "GL_ARB_debug_output", debugoutputfuncs, ARRAYSIZE( debugoutputfuncs ), "gl_debug_output", GL_DEBUG_OUTPUT, 0 );
#if XASH_PSVITA
// not all GL1.1 functions are implemented in vitaGL, but there's enough
@@ -1047,7 +1027,7 @@ void GL_InitExtensions( void )
GL_OnContextCreated();
// initialize gl extensions
GL_CheckExtension( "OpenGL 1.1.0", opengl_110funcs, NULL, GL_OPENGL_110, 1.0 );
GL_CheckExtension( "OpenGL 1.1.0", opengl_110funcs, ARRAYSIZE( opengl_110funcs ), NULL, GL_OPENGL_110, 1.0 );
// get our various GL strings
glConfig.vendor_string = (const char *)pglGetString( GL_VENDOR );

View File

@@ -79,7 +79,7 @@ static void FS_CreatePath( char *path )
}
}
void usage( const char *arg0 )
static void usage( const char *arg0 )
{
printf( "%s: <action> [option...] <file>\n", arg0 );
puts( "XAR is a simple frontend to Xash3D FWGS's filesystem_stdio library" );

View File

@@ -392,6 +392,7 @@ def configure(conf):
conf.env.TESTS = conf.options.TESTS
conf.env.ENABLE_UTILS = conf.options.ENABLE_UTILS
conf.env.ENABLE_XAR = conf.options.ENABLE_XAR
conf.env.ENABLE_FUZZER = conf.options.ENABLE_FUZZER
conf.env.DEDICATED = conf.options.DEDICATED