Compare commits

..

9 Commits

151 changed files with 2862 additions and 3456 deletions

View File

@@ -1,7 +1,32 @@
task:
# Seems packages for it were removed from the mirrors
# name: freebsd-12-amd64
# freebsd_instance:
# image_family: freebsd-12-4
# setup_script:
# - pkg update
# - pkg install -y pkgconf git sdl2 python fontconfig opus
# - git submodule update --init --recursive
# test_script:
# - ./scripts/cirrus/build_freebsd.sh dedicated
# - ./scripts/cirrus/build_freebsd.sh full
task:
name: freebsd-13-amd64
freebsd_instance:
image_family: freebsd-13-2
setup_script:
- pkg update
- pkg install -y pkgconf git sdl2 python fontconfig opus
- git submodule update --init --recursive
test_script:
- ./scripts/cirrus/build_freebsd.sh dedicated
- ./scripts/cirrus/build_freebsd.sh full
task:
name: freebsd-14-amd64
freebsd_instance:
image_family: freebsd-14-0
image_family: freebsd-14-0-snap
setup_script:
- pkg update
- pkg install -y pkgconf git sdl2 python fontconfig opus

1
.github/FUNDING.yml vendored
View File

@@ -1 +0,0 @@
custom: https://github.com/FWGS/xash3d-fwgs/blob/master/Documentation/donate.md

View File

@@ -44,7 +44,7 @@ jobs:
targetos: win32
targetarch: i386
env:
SDL_VERSION: 2.30.3
SDL_VERSION: 2.28.5
GH_CPU_ARCH: ${{ matrix.targetarch }}
steps:
- name: Checkout

View File

@@ -1,16 +1,17 @@
# Bug-compatibility in Xash3D FWGS
Xash3D FWGS has special mode for games that rely on original engine bugs. In this mode, we emulate the behaviour of selected functions that may help running mods relying on engine bugs, but enabling them by default may break majority of other games.
Xash3D FWGS has special mode for games that rely on original engine bugs.
In this mode, we emulate the behaviour of selected functions that may help running mods relying on engine bugs, but enabling them by default may break majority of other games.
At this time, we only have implemented GoldSrc bug-compatibility. It can be enabled with `-bugcomp` command line switch.
When `-bugcomp` is specified without argument, it enables everything. This behavior might be changed or removed in future versions.
When `-bugcomp` is specified with argument, it interpreted as flags separated with `+`. This way it's possible to combine multiple levels of bug-compatibility.
## GoldSrc bug-compatibility
| Flag | Description | Games that require this flag |
| ------- | ----------- | ---------------------------- |
| `peoei` | Reverts `pfnPEntityOfEntIndex` behavior to GoldSrc, where it returns NULL for last player due to incorrect player index comparison | * Counter-Strike: Condition Zero - Deleted Scenes |
| `gsmrf` | Rewrites message at the moment when Game DLL attempts to write an internal engine message, usually specific to GoldSrc protocol. Right now only supports `svc_spawnstaticsound`, more messages added by request. | * MetaMod/AMXModX based mods |
### Emulated bugs
* `pfnPEntityOfEntIndex` in GoldSrc returns NULL for last player due to incorrect player index comparison
### Games and mods that require this
* Counter-Strike: Condition Zero - Deleted Scenes

View File

@@ -1,21 +0,0 @@
## Environment variables
#### Xash3D FWGS
The engine respects these environment variables:
| Variable | Type | Description |
| --------------------- | ---------- | ----------- |
| `XASH3D_GAME` | _string_ | Overrides default game directory. Ignored if `-game` command line argument is set |
| `XASH3D_BASEDIR` | _string_ | Sets path to base (root) directory, instead of current working directory |
| `XASH3D_RODIR` | _string_ | Sets path to read-only base (root) directory. Ignored if `-rodir` command line argument is set |
| `XASH3D_EXTRAS_PAK1` | _string_ | Archive file from specified path will be added to virtual filesystem search path in the lowest possible priority |
| `XASH3D_EXTRAS_PAK2` | _string_ | Similar to `XASH3D_EXTRAS_PAK1` but next to it in priority list |
Environment variables NOT listed in the table above are used internally, and aren't considered as stable interface.
#### mdldec
| Variable | Type | Description |
| --------------------- | ---------- | ----------- |
| `MDLDEC_ACT_PATH` | _string_ | If set, will read activities list from this path |

25
common/boneinfo.h Normal file
View File

@@ -0,0 +1,25 @@
/*
boneinfo.h - structure that send delta-compressed bones across network
Copyright (C) 2018 Uncle Mike
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 BONEINFO_H
#define BONEINFO_H
typedef struct
{
vec3_t angles;
vec3_t origin;
} boneinfo_t;
#endif//BONEINFO_H

View File

@@ -54,6 +54,7 @@ BRUSH MODELS
#define SURF_CONVEYOR BIT( 6 ) // scrolled texture (was SURF_DRAWBACKGROUND)
#define SURF_UNDERWATER BIT( 7 ) // caustics
#define SURF_TRANSPARENT BIT( 8 ) // it's a transparent texture (was SURF_DONTWARP)
#define SURF_REFLECT BIT( 31 ) // mirrors
// lightstyle management
#define LM_STYLES 4 // MAXLIGHTMAPS

View File

@@ -228,7 +228,9 @@ typedef struct mextrasurf_s
unsigned short numverts; // world->vertexes[]
int firstvertex; // fisrt look up in tr.tbn_vectors[], then acess to world->vertexes[]
intptr_t reserved[32]; // just for future expansions or mod-makers
struct mextrasurf_s *mirrorchain; // engine-side mirrors, may be ignored in mods with custom renderers
intptr_t reserved[31]; // just for future expansions or mod-makers
} mextrasurf_t;
struct msurface_s

View File

@@ -92,6 +92,7 @@
#define SOLID_BSP 4 // bsp clip, touch on edge, block
#define SOLID_CUSTOM 5 // call external callbacks for tracing
#define SOLID_PORTAL 6 // borrowed from FTE
#define SOLID_GIB 7 // do not block, only collide with solid brushes
// edict->deadflag values
#define DEAD_NO 0 // alive
@@ -114,6 +115,8 @@
#define EF_LIGHT 64 // rocket flare glow sprite
#define EF_NODRAW 128 // don't draw entity
#define EF_NOREFLECT (1U<<24) // Entity won't reflecting in mirrors
#define EF_REFLECTONLY (1U<<25) // Entity will be drawing only in mirrors
#define EF_WATERSIDES (1U<<26) // Do not remove sides for func_water entity
#define EF_FULLBRIGHT (1U<<27) // Just get fullbright
#define EF_NOSHADOW (1U<<28) // ignore shadow for this entity

View File

@@ -164,6 +164,10 @@ Default build-depended cvar and constant values
#define XASH_INTERNAL_GAMELIBS
#endif // XASH_ANDROID || XASH_IOS || XASH_EMSCRIPTEN
#if XASH_ANDROID && XASH_SDL
#define XASH_ANDROID_ASSETS 1
#endif
// Defaults
#ifndef DEFAULT_TOUCH_ENABLE
#define DEFAULT_TOUCH_ENABLE "0"

View File

@@ -27,6 +27,7 @@ GNU General Public License for more details.
#define ENGINE_COMPUTE_STUDIO_LERP (1<<7) // enable MOVETYPE_STEP lerping back in engine
#define ENGINE_LINEAR_GAMMA_SPACE (1<<8) // disable influence of gamma/brightness cvars to textures/lightmaps, for mods with custom renderer
#define ENGINE_ALLOW_MIRRORS (1U<<30) // allow mirrors in engine renderer
#define ENGINE_STEP_POSHISTORY_LERP (1U<<31) // enable MOVETYPE_STEP interpolation based on position history. Incompatible with ENGINE_COMPUTE_STUDIO_LERP!
// adjust the mask when features will be added or removed
@@ -40,6 +41,7 @@ GNU General Public License for more details.
| ENGINE_IMPROVED_LINETRACE \
| ENGINE_COMPUTE_STUDIO_LERP \
| ENGINE_LINEAR_GAMMA_SPACE \
| ENGINE_ALLOW_MIRRORS \
| ENGINE_STEP_POSHISTORY_LERP )
#endif//FEATURES_H

View File

@@ -28,7 +28,11 @@ typedef byte rgb_t[3]; // unsigned byte colorpack
typedef vec_t matrix3x4[3][4];
typedef vec_t matrix4x4[4][4];
#if XASH_64BIT
typedef uint32_t poolhandle_t;
#else
typedef void* poolhandle_t;
#endif
#undef true
#undef false
@@ -70,50 +74,48 @@ typedef uint64_t longtime_t;
#define IsColorString( p ) ( p && *( p ) == '^' && *(( p ) + 1) && *(( p ) + 1) >= '0' && *(( p ) + 1 ) <= '9' )
#define ColorIndex( c ) ((( c ) - '0' ) & 7 )
#if defined( __GNUC__ )
#if defined( __i386__ )
#define EXPORT __attribute__(( visibility( "default" ), force_align_arg_pointer ))
#define GAME_EXPORT __attribute(( force_align_arg_pointer ))
#if defined(__GNUC__)
#ifdef __i386__
#define EXPORT __attribute__ ((visibility ("default"),force_align_arg_pointer))
#define GAME_EXPORT __attribute((force_align_arg_pointer))
#else
#define EXPORT __attribute__(( visibility ( "default" )))
#define EXPORT __attribute__ ((visibility ("default")))
#define GAME_EXPORT
#endif
#define NORETURN __attribute__(( noreturn ))
#define NONNULL __attribute__(( nonnull ))
#define _format( x ) __attribute__(( format( printf, x, x + 1 )))
#define ALLOC_CHECK( x ) __attribute__(( alloc_size( x )))
#define NO_ASAN __attribute__(( no_sanitize( "address" )))
#define RENAME_SYMBOL( x ) asm( x )
#else
#if defined( _MSC_VER )
#define EXPORT __declspec( dllexport )
#define NO_ASAN __declspec( no_sanitize_address )
#else
#define EXPORT
#define NO_ASAN
#endif
#define _format(x) __attribute__((format(printf, x, x+1)))
#define NORETURN __attribute__((noreturn))
#define NONNULL __attribute__((nonnull))
#define ALLOC_CHECK(x) __attribute__((alloc_size(x)))
#elif defined(_MSC_VER)
#define EXPORT __declspec( dllexport )
#define GAME_EXPORT
#define _format(x)
#define NORETURN
#define NONNULL
#define _format( x )
#define ALLOC_CHECK( x )
#define RENAME_SYMBOL( x )
#define ALLOC_CHECK(x)
#else
#define EXPORT
#define GAME_EXPORT
#define _format(x)
#define NORETURN
#define NONNULL
#define ALLOC_CHECK(x)
#endif
#if __GNUC__ >= 3
#define unlikely( x ) __builtin_expect( x, 0 )
#define likely( x ) __builtin_expect( x, 1 )
#if ( __GNUC__ >= 3 )
#define unlikely(x) __builtin_expect(x, 0)
#define likely(x) __builtin_expect(x, 1)
#elif defined( __has_builtin )
#if __has_builtin( __builtin_expect ) // this must be after defined() check
#define unlikely( x ) __builtin_expect( x, 0 )
#define likely( x ) __builtin_expect( x, 1 )
#if __has_builtin( __builtin_expect )
#define unlikely(x) __builtin_expect(x, 0)
#define likely(x) __builtin_expect(x, 1)
#else
#define unlikely(x) (x)
#define likely(x) (x)
#endif
#endif
#if !defined( unlikely ) || !defined( likely )
#define unlikely( x ) ( x )
#define likely( x ) ( x )
#else
#define unlikely(x) (x)
#define likely(x) (x)
#endif
#if __STDC_VERSION__ >= 202311L || __cplusplus >= 201103L // C23 or C++ static_assert is a keyword
@@ -130,14 +132,6 @@ typedef uint64_t longtime_t;
#define STATIC_ASSERT( x, y ) STATIC_ASSERT_2( __LINE__, x, y )
#endif
#if !defined( __cplusplus ) && __STDC_VERSION__ >= 199101L // not C++ and C99 or newer
#define XASH_RESTRICT restrict
#elif _MSC_VER || __GNUC__ || __clang__ // compiler-specific extensions
#define XASH_RESTRICT __restrict
#else
#define XASH_RESTRICT // nothing
#endif
#ifdef XASH_BIG_ENDIAN
#define LittleLong(x) (((int)(((x)&255)<<24)) + ((int)((((x)>>8)&255)<<16)) + ((int)(((x)>>16)&255)<<8) + (((x) >> 24)&255))
#define LittleLongSW(x) (x = LittleLong(x) )

View File

@@ -70,17 +70,16 @@ qboolean CL_CheckFile( sizebuf_t *msg, resource_t *pResource )
return true;
}
host.downloadcount++;
if( cl.http_download )
if( cl.downloadUrl[0] )
{
HTTP_AddDownload( filepath, pResource->nDownloadSize, true );
host.downloadcount++;
return false;
}
else
{
MSG_BeginClientCmd( msg, clc_stringcmd );
MSG_WriteStringf( msg, "dlfile %s", filepath );
}
MSG_BeginClientCmd( msg, clc_stringcmd );
MSG_WriteStringf( msg, "dlfile %s", filepath );
host.downloadcount++;
return false;
}

View File

@@ -50,15 +50,7 @@ const char *CL_MsgInfo( int cmd )
if( cmd >= 0 && cmd <= svc_lastmsg )
{
// get engine message name
const char *svc_string = NULL;
if( cls.legacymode )
svc_string = svc_legacy_strings[cmd];
if( !svc_string )
svc_string = svc_strings[cmd];
Q_strncpy( sz, svc_string, sizeof( sz ));
Q_strncpy( sz, svc_strings[cmd], sizeof( sz ));
}
else if( cmd > svc_lastmsg && cmd <= ( svc_lastmsg + MAX_USER_MESSAGES ))
{

View File

@@ -192,7 +192,7 @@ void CL_RegisterEvent( int lastnum, const char *szEvName, pfnEventHook func )
ev = clgame.events[lastnum];
// NOTE: ev->index will be set later
Q_strncpy( ev->name, szEvName, sizeof( ev->name ));
Q_strncpy( ev->name, szEvName, MAX_QPATH );
ev->func = func;
}

View File

@@ -1448,7 +1448,7 @@ pfnSPR_Draw
*/
static void GAME_EXPORT pfnSPR_Draw( int frame, int x, int y, const wrect_t *prc )
{
ref.dllFuncs.GL_SetRenderMode( kRenderTransAlpha );
ref.dllFuncs.GL_SetRenderMode( kRenderNormal );
SPR_DrawGeneric( frame, x, y, -1, -1, prc );
}
@@ -1713,8 +1713,7 @@ pfnCvar_RegisterVariable
static cvar_t *GAME_EXPORT pfnCvar_RegisterClientVariable( const char *szName, const char *szValue, int flags )
{
// a1ba: try to mitigate outdated client.dll vulnerabilities
if( !Q_stricmp( szName, "motdfile" )
|| !Q_stricmp( szName, "sensitivity" ))
if( !Q_stricmp( szName, "motdfile" ))
flags |= FCVAR_PRIVILEGED;
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_CLIENTDLL, Cvar_BuildAutoDescription( szName, flags|FCVAR_CLIENTDLL ));

View File

@@ -1097,20 +1097,6 @@ static void GAME_EXPORT pfnCon_DefaultColor( int r, int g, int b )
Con_DefaultColor( r, g, b, true );
}
static void GAME_EXPORT pfnSetCursor( void *hCursor )
{
uintptr_t cursor;
if( !gameui.use_extended_api )
return; // ignore original Xash menus
cursor = (uintptr_t)hCursor;
if( cursor < dc_user || cursor > dc_last )
return;
Platform_SetCursorType( cursor );
}
// engine callbacks
static ui_enginefuncs_t gEngfuncs =
{
@@ -1190,7 +1176,7 @@ static ui_enginefuncs_t gEngfuncs =
pfnHostEndGame,
COM_RandomFloat,
COM_RandomLong,
pfnSetCursor,
IN_SetCursor,
pfnIsMapValid,
GL_ProcessTexture,
COM_CompareFileTime,
@@ -1300,7 +1286,7 @@ qboolean UI_LoadProgs( void )
}
gameui.use_extended_api = false;
gameui.use_text_api = false;
// make local copy of engfuncs to prevent overwrite it with user dll
memcpy( &gpEngfuncs, &gEngfuncs, sizeof( gpEngfuncs ));
@@ -1327,7 +1313,7 @@ qboolean UI_LoadProgs( void )
if( GetExtAPI( MENU_EXTENDED_API_VERSION, &gameui.dllFuncs2, &gpExtendedfuncs ) )
{
Con_Reportf( "UI_LoadProgs: extended Menu API initialized\n" );
gameui.use_extended_api = true;
gameui.use_text_api = true;
}
}
else // otherwise, fallback to old and deprecated extensions
@@ -1339,7 +1325,7 @@ qboolean UI_LoadProgs( void )
if( GiveTextApi( &gpExtendedfuncs ) ) // they are binary compatible, so we can just pass extended funcs API to menu
{
Con_Reportf( "UI_LoadProgs: extended text API initialized\n" );
gameui.use_extended_api = true;
gameui.use_text_api = true;
}
}

View File

@@ -587,38 +587,21 @@ CL_CreateCmd
*/
static void CL_CreateCmd( void )
{
usercmd_t nullcmd, *cmd;
runcmd_t *pcmd;
qboolean active;
double accurate_ms;
vec3_t angles;
int input_override;
int i, ms;
usercmd_t nullcmd, *cmd;
runcmd_t *pcmd;
vec3_t angles;
qboolean active;
int input_override;
int i, ms;
if( cls.state < ca_connected || cls.state == ca_cinematic )
return;
// store viewangles in case it's will be freeze
VectorCopy( cl.viewangles, angles );
ms = bound( 1, host.frametime * 1000, 255 );
input_override = 0;
// fix rounding error and framerate depending player move
accurate_ms = host.frametime * 1000;
ms = (int)accurate_ms;
cl.frametime_remainder += accurate_ms - ms; // accumulate rounding error each frame
// add a ms if error accumulates enough
if( cl.frametime_remainder >= 1.0 )
{
int ms2 = (int)cl.frametime_remainder;
ms += ms2;
cl.frametime_remainder -= ms2;
}
// ms can't be negative, rely on error accumulation only if FPS > 1000
ms = Q_min( ms, 255 );
CL_SetSolidEntities();
CL_PushPMStates();
CL_SetSolidPlayers( cl.playernum );
@@ -1635,17 +1618,9 @@ static size_t NONNULL CL_BuildMasterServerScanRequest( char *buf, size_t size, u
#ifndef XASH_ALL_SERVERS
Info_SetValueForKey( info, "gamedir", GI->gamefolder, remaining );
#endif
// let master know about client version
Info_SetValueForKey( info, "clver", XASH_VERSION, remaining );
Info_SetValueForKey( info, "clver", XASH_VERSION, remaining ); // let master know about client version
Info_SetValueForKey( info, "nat", nat ? "1" : "0", remaining );
Info_SetValueForKey( info, "commit", Q_buildcommit(), remaining );
Info_SetValueForKey( info, "branch", Q_buildbranch(), remaining );
Info_SetValueForKey( info, "os", Q_buildos(), remaining );
Info_SetValueForKey( info, "arch", Q_buildarch(), remaining );
Q_snprintf( temp, sizeof( temp ), "%d", Q_buildnum() );
Info_SetValueForKey( info, "buildnum", temp, remaining );
Q_snprintf( temp, sizeof( temp ), "%x", *key );
Info_SetValueForKey( info, "key", temp, remaining );
@@ -2535,6 +2510,11 @@ void CL_ProcessFile( qboolean successfully_received, const char *filename )
return;
}
pfilename = filename;
if( !Q_strnicmp( filename, DEFAULT_SOUNDPATH, sound_len ))
pfilename += sound_len;
for( p = cl.resourcesneeded.pNext; p != &cl.resourcesneeded; p = p->pNext )
{
if( !Q_strnicmp( filename, "!MD5", 4 ))
@@ -2544,20 +2524,18 @@ void CL_ProcessFile( qboolean successfully_received, const char *filename )
if( !memcmp( p->rgucMD5_hash, rgucMD5_hash, 16 ))
break;
}
else if( p->type == t_sound )
{
const char *pfilename = filename;
if( !Q_strnicmp( filename, DEFAULT_SOUNDPATH, sound_len ))
pfilename += sound_len;
if( !Q_stricmp( p->szFileName, pfilename ))
break;
}
else
{
if( !Q_stricmp( p->szFileName, filename ))
if( p->type == t_generic )
{
if( !Q_stricmp( p->szFileName, filename ))
break;
}
else
{
if( !Q_stricmp( p->szFileName, pfilename ))
break;
}
}
}
@@ -2622,7 +2600,7 @@ void CL_ProcessFile( qboolean successfully_received, const char *filename )
if( cls.netchan.tempbuffer )
{
Con_Printf( "Received a decal %s, but didn't find it in resources needed list!\n", filename );
Con_Printf( "Received a decal %s, but didn't find it in resources needed list!\n", pfilename );
Mem_Free( cls.netchan.tempbuffer );
}
@@ -2715,32 +2693,10 @@ static void CL_Physinfo_f( void )
Con_Printf( "Total %i symbols\n", Q_strlen( cls.physinfo ));
}
static qboolean CL_ShouldRescanFilesystem( void )
{
resource_t *res;
for( res = cl.resourcesonhand.pNext; res && res != &cl.resourcesonhand; res = res->pNext )
{
if( res->type == t_generic )
{
const char *ext = COM_FileExtension( res->szFileName );
// TODO: query supported archives format from fs_stdio
// TODO: query if was already opened
if( !Q_stricmp( ext, "wad" ) || !Q_stricmp( ext, "pk3" ) || !Q_stricmp( ext, "pak" ))
return true;
}
}
return false;
}
qboolean CL_PrecacheResources( void )
{
resource_t *pRes;
// if we downloaded new WAD files or any other archives they must be added to searchpath
if( CL_ShouldRescanFilesystem( ))
g_fsapi.Rescan();
// NOTE: world need to be loaded as first model
for( pRes = cl.resourcesonhand.pNext; pRes && pRes != &cl.resourcesonhand; pRes = pRes->pNext )
{

View File

@@ -458,7 +458,6 @@ void CL_BatchResourceRequest( qboolean initialize )
byte data[MAX_INIT_MSG];
resource_t *p, *n;
sizebuf_t msg;
qboolean done_downloading = true;
MSG_Init( &msg, "Resource Batch", data, sizeof( data ));
@@ -488,10 +487,7 @@ void CL_BatchResourceRequest( qboolean initialize )
case t_model:
case t_eventscript:
if( !CL_CheckFile( &msg, p ))
{
done_downloading = false;
break;
}
CL_MoveToOnHandList( p );
break;
case t_skin:
@@ -505,7 +501,6 @@ void CL_BatchResourceRequest( qboolean initialize )
MSG_BeginClientCmd( &msg, clc_stringcmd );
MSG_WriteStringf( &msg, "dlfile !MD5%s", MD5_Print( p->rgucMD5_hash ));;
SetBits( p->ucFlags, RES_REQUESTED );
done_downloading = false;
}
break;
}
@@ -530,7 +525,11 @@ void CL_BatchResourceRequest( qboolean initialize )
if( cls.state != ca_disconnected )
{
if( done_downloading && CL_PrecacheResources( ))
if( !cl.downloadUrl[0] && !MSG_GetNumBytesWritten( &msg ) && CL_PrecacheResources( ))
{
CL_RegisterResources( &msg );
}
if( cl.downloadUrl[0] && host.downloadcount == 0 && CL_PrecacheResources( ) )
{
CL_RegisterResources( &msg );
}
@@ -1841,10 +1840,13 @@ void CL_ParseResLocation( sizebuf_t *msg )
return;
}
while(( data = COM_ParseFile( data, token, sizeof( token ))))
while( ( data = COM_ParseFile( data, token, sizeof( token ) ) ) )
{
Con_Reportf( "Adding %s as download location\n", token );
cl.http_download = true;
if( !cl.downloadUrl[0] )
Q_strncpy( cl.downloadUrl, token, sizeof( token ) );
HTTP_AddCustomServer( token );
}
}
@@ -1875,12 +1877,8 @@ void CL_ParseHLTV( sizebuf_t *msg )
break;
case HLTV_LISTEN:
cls.signon = SIGNONS;
#if 1
MSG_ReadString( msg );
#else
NET_StringToAdr( MSG_ReadString( msg ), &cls.hltv_listen_address );
NET_JoinGroup( cls.netchan.sock, cls.hltv_listen_address );
#endif
// NET_JoinGroup( cls.netchan.sock, cls.hltv_listen_address );
SCR_EndLoadingPlaque();
break;
default:

View File

@@ -194,7 +194,7 @@ static void CL_LegacyPrecacheModel( sizebuf_t *msg )
if( modelIndex < 0 || modelIndex >= MAX_MODELS )
Host_Error( "CL_PrecacheModel: bad modelindex %i\n", modelIndex );
Q_strncpy( model, MSG_ReadString( msg ), sizeof( model ));
Q_strncpy( model, MSG_ReadString( msg ), MAX_STRING );
//Q_strncpy( cl.model_precache[modelIndex], BF_ReadString( msg ), sizeof( cl.model_precache[0] ));
// when we loading map all resources is precached sequentially
@@ -261,7 +261,7 @@ static void CL_LegacyParseResourceList( sizebuf_t *msg )
for( i = 0; i < reslist.rescount; i++ )
{
reslist.restype[i] = MSG_ReadWord( msg );
Q_strncpy( reslist.resnames[i], MSG_ReadString( msg ), sizeof( reslist.resnames[i] ));
Q_strncpy( reslist.resnames[i], MSG_ReadString( msg ), MAX_QPATH );
}
if( CL_IsPlaybackDemo() )

View File

@@ -853,7 +853,7 @@ static void CL_SetupPMove( playermove_t *pmove, const local_state_t *from, const
VectorCopy( cd->vuser4, pmove->vuser4 );
pmove->cmd = *ucmd; // copy current cmds
Q_strncpy( pmove->physinfo, cls.physinfo, sizeof( pmove->physinfo ));
Q_strncpy( pmove->physinfo, cls.physinfo, MAX_INFO_STRING );
}
static const void CL_FinishPMove( const playermove_t *pmove, local_state_t *to )

View File

@@ -211,7 +211,7 @@ static void CL_ParseQuakeServerInfo( sizebuf_t *msg )
clgame.maxEntities = GI->max_edicts;
clgame.maxEntities = bound( 600, clgame.maxEntities, MAX_EDICTS );
clgame.maxModels = MAX_MODELS;
Q_strncpy( clgame.maptitle, MSG_ReadString( msg ), sizeof( clgame.maptitle ));
Q_strncpy( clgame.maptitle, MSG_ReadString( msg ), MAX_STRING );
// Re-init hud video, especially if we changed game directories
clgame.dllFuncs.pfnVidInit();
@@ -844,7 +844,7 @@ static void CL_QuakeExecStuff( void )
while( 1 )
{
// skip whitespace up to a /n
while( *text && ((byte)*text ) <= ' ' && *text != '\r' && *text != '\n' )
while( *text && ((byte)*text) <= ' ' && *text != '\r' && *text != '\n' )
text++;
if( *text == '\n' || *text == '\r' )

View File

@@ -20,7 +20,7 @@ GNU General Public License for more details.
int R_FatPVS( const vec3_t org, float radius, byte *visbuffer, qboolean merge, qboolean fullvis )
{
return Mod_FatPVS( org, radius, visbuffer, world.visbytes, merge, fullvis, false );
return Mod_FatPVS( org, radius, visbuffer, world.visbytes, merge, fullvis );
}
lightstyle_t *CL_GetLightStyle( int number )

View File

@@ -229,7 +229,7 @@ typedef struct
char serverinfo[MAX_SERVERINFO_STRING];
player_info_t players[MAX_CLIENTS]; // collected info about all other players include himself
double lastresourcecheck;
qboolean http_download;
string downloadUrl;
event_state_t events;
// predicting stuff but not only...
@@ -276,8 +276,6 @@ typedef struct
model_t *worldmodel; // pointer to world
int lostpackets; // count lost packets and show dialog in menu
double frametime_remainder;
} client_t;
/*
@@ -520,7 +518,7 @@ typedef struct
int logo_yres;
float logo_length;
qboolean use_extended_api;
qboolean use_text_api;
} gameui_static_t;
typedef struct
@@ -541,8 +539,12 @@ typedef struct
poolhandle_t mempool; // client premamnent pool: edicts etc
int signon; // 0 to SIGNONS, for the signon sequence.
netadr_t hltv_listen_address;
int signon; // 0 to SIGNONS, for the signon sequence.
int quakePort; // a 16 bit value that allows quake servers
// to work around address translating routers
// g-cont. this port allow many copies of engine in multiplayer game
// connection information
char servername[MAX_QPATH]; // name of server from original connect
double connect_time; // for connection retransmits
@@ -632,9 +634,6 @@ typedef struct
int extensions;
netadr_t serveradr;
// do we accept utf8 as input
qboolean accept_utf8;
} client_static_t;
#ifdef __cplusplus

View File

@@ -21,7 +21,6 @@ GNU General Public License for more details.
#include "qfont.h"
#include "wadfile.h"
#include "input.h"
#include "utflib.h"
static CVAR_DEFINE_AUTO( scr_conspeed, "600", FCVAR_ARCHIVE, "console moving speed" );
static CVAR_DEFINE_AUTO( con_notifytime, "3", FCVAR_ARCHIVE, "notify time to live" );
@@ -35,6 +34,7 @@ static CVAR_DEFINE_AUTO( scr_drawversion, "1", FCVAR_ARCHIVE, "draw version in m
static CVAR_DEFINE_AUTO( con_oldfont, "0", 0, "use legacy font from gfx.wad, might be missing or broken" );
static int g_codepage = 0;
static qboolean g_utf8 = false;
static qboolean g_messagemode_privileged = true;
@@ -610,6 +610,19 @@ static void Con_LoadConchars( void )
con.curFont = &con.chars[fontSize];
}
// CP1251 table
int table_cp1251[64] = {
0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021,
0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F,
0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
0x007F, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F,
0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7,
0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407,
0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7,
0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457
};
/*
============================
Con_UtfProcessChar
@@ -619,28 +632,84 @@ Convert utf char to current font's single-byte encoding
*/
int Con_UtfProcessCharForce( int in )
{
// TODO: get rid of global state where possible
static utfstate_t state = { 0 };
static int m = -1, k = 0; //multibyte state
static int uc = 0; //unicode char
int ch = Q_DecodeUTF8( &state, in );
if( !in )
{
m = -1;
k = 0;
uc = 0;
return 0;
}
if( g_codepage == 1251 )
return Q_UnicodeToCP1251( ch );
if( g_codepage == 1252 )
return Q_UnicodeToCP1252( ch );
// Get character length
if(m == -1)
{
uc = 0;
if( in >= 0xF8 )
return 0;
else if( in >= 0xF0 )
uc = in & 0x07, m = 3;
else if( in >= 0xE0 )
uc = in & 0x0F, m = 2;
else if( in >= 0xC0 )
uc = in & 0x1F, m = 1;
else if( in <= 0x7F)
return in; //ascii
// return 0 if we need more chars to decode one
k=0;
return 0;
}
// get more chars
else if( k <= m )
{
uc <<= 6;
uc += in & 0x3F;
k++;
}
if( in > 0xBF || m < 0 )
{
m = -1;
return 0;
}
if( k == m )
{
k = m = -1;
if( g_codepage == 1251 )
{
// cp1251 now
if( uc >= 0x0410 && uc <= 0x042F )
return uc - 0x410 + 0xC0;
if( uc >= 0x0430 && uc <= 0x044F )
return uc - 0x430 + 0xE0;
else
{
int i;
for( i = 0; i < 64; i++ )
if( table_cp1251[i] == uc )
return i + 0x80;
}
}
else if( g_codepage == 1252 )
{
if( uc < 255 )
return uc;
}
return '?'; // not implemented yet
// not implemented yet
return '?';
}
return 0;
}
int GAME_EXPORT Con_UtfProcessChar( int in )
{
if( !cls.accept_utf8 ) // incoming character is not a UTF-8 sequence
if( !g_utf8 )
return in;
// otherwise, decode it and convert to selected codepage
return Con_UtfProcessCharForce( in );
else
return Con_UtfProcessCharForce( in );
}
/*
=================
Con_UtfMoveLeft
@@ -650,22 +719,16 @@ get position of previous printful char
*/
int Con_UtfMoveLeft( char *str, int pos )
{
utfstate_t state = { 0 };
int k = 0;
int i;
if( !cls.accept_utf8 ) // incoming character is not a UTF-8 sequence
int i, k = 0;
// int j;
if( !g_utf8 )
return pos - 1;
if( pos == 1 )
return 0;
for( i = 0; i < pos - 1; i++ )
{
if( Q_DecodeUTF8( &state, (byte)str[i] ))
k = i + 1;
}
Con_UtfProcessChar( 0 );
if(pos == 1) return 0;
for( i = 0; i < pos-1; i++ )
if( Con_UtfProcessChar( (unsigned char)str[i] ) )
k = i+1;
Con_UtfProcessChar( 0 );
return k;
}
@@ -678,19 +741,17 @@ get next of previous printful char
*/
int Con_UtfMoveRight( char *str, int pos, int length )
{
utfstate_t state = { 0 };
int i;
if( !cls.accept_utf8 ) // incoming character is not a UTF-8 sequence
if( !g_utf8 )
return pos + 1;
Con_UtfProcessChar( 0 );
for( i = pos; i <= length; i++ )
{
if( Q_DecodeUTF8( &state, (byte)str[i] ))
return i + 1;
if( Con_UtfProcessChar( (unsigned char)str[i] ) )
return i+1;
}
return pos + 1;
Con_UtfProcessChar( 0 );
return pos+1;
}
static void Con_DrawCharToConback( int num, const byte *conchars, byte *dest )
@@ -1064,7 +1125,7 @@ Con_ClearField
*/
static void Con_ClearField( field_t *edit )
{
memset( edit->buffer, 0, sizeof( edit->buffer ));
memset( edit->buffer, 0, MAX_STRING );
edit->cursor = 0;
edit->scroll = 0;
}
@@ -1077,7 +1138,7 @@ Field_Set
static void Field_Set( field_t *f, const char *string )
{
f->scroll = 0;
f->cursor = Q_strncpy( f->buffer, string, sizeof( f->buffer ));
f->cursor = Q_strncpy( f->buffer, string, MAX_STRING );
}
/*
@@ -1383,49 +1444,36 @@ static void Con_HistoryAppend( con_history_t *self, field_t *from )
static void Con_LoadHistory( con_history_t *self )
{
const byte *aFile = FS_LoadFile( "console_history.txt", NULL, true );
const char *pLine, *pFile;
int i, len;
field_t *f;
file_t *fd;
int i;
fd = FS_Open( "console_history.txt", "rb", true );
if( !fd )
if( !aFile )
return;
while( !FS_Eof( fd ))
for( pFile = pLine = (char *)aFile; *pFile; pFile++ )
{
f = &self->lines[self->next % CON_HISTORY];
Con_ClearField( f );
f->widthInChars = con.linewidth;
FS_Gets( fd, f->buffer, sizeof( f->buffer ));
f->cursor = Q_strlen( f->buffer );
// skip empty lines
if( f->cursor == 0 )
if( *pFile != '\n' )
continue;
// skip repeating lines
if( self->next > 0 )
{
field_t *prev;
prev = &self->lines[(self->next - 1) % CON_HISTORY];
if( !Q_stricmp( prev->buffer, f->buffer ))
continue;
}
Con_ClearField( &self->lines[self->next] );
len = Q_min( pFile - pLine + 1, sizeof( f->buffer ));
f = &self->lines[self->next % CON_HISTORY];
f->widthInChars = con.linewidth;
f->cursor = len - 1;
Q_strncpy( f->buffer, pLine, len);
self->next++;
}
FS_Close( fd );
pLine = pFile + 1;
}
for( i = self->next; i < CON_HISTORY; i++ )
{
f = &self->lines[i];
Con_ClearField( f );
f->widthInChars = con.linewidth;
Con_ClearField( &self->lines[i] );
self->lines[i].widthInChars = con.linewidth;
}
self->line = self->next;
@@ -1443,7 +1491,7 @@ static void Con_SaveHistory( con_history_t *self )
if( historyStart < 0 )
historyStart = 0;
f = FS_Open( "console_history.txt", "wb", true );
f = FS_Open( "console_history.txt", "w", true );
for( i = historyStart; i < self->next; i++ )
FS_Printf( f, "%s\n", self->lines[i % CON_HISTORY].buffer );
@@ -1488,9 +1536,6 @@ void Key_Console( int key )
Con_Printf( ">%s\n", con.input.buffer );
// copy line to history buffer
// just in case, remove all CR and LF characters pushing it to the history
// not sure how they get even added in the first place
COM_RemoveLineFeed( con.input.buffer, sizeof( con.input.buffer ));
Con_HistoryAppend( &con.history, &con.input );
Con_ClearField( &con.input );
@@ -2099,7 +2144,7 @@ void Con_RunConsole( void )
g_codepage = 1252;
}
cls.accept_utf8 = !Q_stricmp( cl_charset.string, "utf-8" );
g_utf8 = !Q_stricmp( cl_charset.string, "utf-8" );
Con_InvalidateFonts();
Con_LoadConchars();
ClearBits( con_charset.flags, FCVAR_CHANGED );

View File

@@ -17,7 +17,6 @@ GNU General Public License for more details.
#include "input.h"
#include "client.h"
#include "vgui_draw.h"
#include "cursor_type.h"
#if XASH_SDL
#include <SDL.h>
@@ -124,6 +123,11 @@ static void IN_StartupMouse( void )
in_mouseinitialized = true;
}
void GAME_EXPORT IN_SetCursor( void *hCursor )
{
// stub
}
/*
===========
IN_MouseSavePos

View File

@@ -40,6 +40,7 @@ void IN_DeactivateMouse( void );
void IN_MouseSavePos( void );
void IN_MouseRestorePos( void );
void IN_ToggleClientMouse( int newstate, int oldstate );
void IN_SetCursor( void *hCursor );
uint IN_CollectInputDevices( void );
void IN_LockInputDevices( qboolean lock );

View File

@@ -553,7 +553,7 @@ static void Key_AddKeyCommands( int key, const char *kb, qboolean down )
}
buttonPtr = button;
while((((byte)kb[i]) <= ' ' || kb[i] == ';' ) && kb[i] != 0 )
while(( kb[i] <= ' ' || kb[i] == ';' ) && kb[i] != 0 )
i++;
}
@@ -749,10 +749,10 @@ void GAME_EXPORT Key_Event( int key, int down )
if( cls.key_dest == key_menu )
{
// only non printable keys passed
if( !gameui.use_extended_api )
if( !gameui.use_text_api )
Key_EnableTextInput( true, false );
//pass printable chars for old menus
if( !gameui.use_extended_api && !host.textmode && down && ( key >= 32 ) && ( key <= 'z' ) )
if( !gameui.use_text_api && !host.textmode && down && ( key >= 32 ) && ( key <= 'z' ) )
{
if( Key_IsDown( K_SHIFT ) )
{
@@ -1055,16 +1055,18 @@ static qboolean OSK_KeyEvent( int key, int down )
break;
}
ch = (byte)osk.curbutton.val;
// do not pass UTF-8 sequence into the engine, convert it here
if( !cls.accept_utf8 )
ch = Con_UtfProcessCharForce( ch );
if( !Q_stricmp( cl_charset.string, "utf-8" ) )
ch = (unsigned char)osk.curbutton.val;
else
ch = Con_UtfProcessCharForce( (unsigned char)osk.curbutton.val );
if( !ch )
break;
CL_CharEvent( ch );
Con_CharEvent( ch );
if( cls.key_dest == key_menu )
UI_CharEvent ( ch );
break;
}
}
@@ -1119,6 +1121,7 @@ static void OSK_EnableTextInput( qboolean enable, qboolean force )
{
osk.curlayout = 0;
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
}
}

View File

@@ -685,9 +685,6 @@ void Mod_CreatePolygonsForHull( int hullnum )
if( hullnum < 1 || hullnum > 3 )
return;
if( !world.num_hull_models )
Mod_InitDebugHulls( mod ); // FIXME: build hulls for separate bmodels (shells, medkits etc)
Con_Printf( "generating polygons for hull %u...\n", hullnum );
start = Sys_DoubleTime();

View File

@@ -565,7 +565,7 @@ static void R_CollectRendererNames( void )
"GL4ES",
#endif
#if XASH_REF_GLES3COMPAT_ENABLED
"GLES3 (gl2_shim)",
"GLES3 (gl2_shim)"
#endif
#if XASH_REF_SOFT_ENABLED
"Software",

View File

@@ -18,18 +18,19 @@ GNU General Public License for more details.
#include "ref_api.h"
#define RP_LOCALCLIENT( e ) ((e) != NULL && (e)->index == ( cl.playernum + 1 ) && e->player )
#define RP_LOCALCLIENT( e ) ((e) != NULL && (e)->index == ( cl.playernum + 1 ) && e->player )
struct ref_state_s
{
HINSTANCE hInstance;
qboolean initialized;
int numRenderers;
qboolean initialized;
HINSTANCE hInstance;
ref_interface_t dllFuncs;
// depends on build configuration
const char **shortNames;
const char **readableNames;
int numRenderers;
const char **shortNames;
const char **readableNames;
};
extern struct ref_state_s ref;
@@ -45,8 +46,8 @@ void R_GetTextureParms( int *w, int *h, int texnum );
void GL_RenderFrame( const struct ref_viewpass_s *rvp );
// common engine and renderer cvars
extern convar_t r_decals;
extern convar_t r_adjust_fov;
extern convar_t r_decals;
extern convar_t r_adjust_fov;
extern convar_t gl_clear;
qboolean R_Init( void );

View File

@@ -154,8 +154,7 @@ static const sx_preset_t rgsxpre_hlalpha052[] =
static const sx_preset_t *ptable = rgsxpre;
// cvars
static CVAR_DEFINE_AUTO( dsp_off, "0", FCVAR_ARCHIVE, "disable DSP processing (deprecated)" );
static CVAR_DEFINE_AUTO( room_off, "0", FCVAR_ARCHIVE, "disable DSP processing (GoldSrc compatible cvar)" );
static CVAR_DEFINE_AUTO( dsp_off, "0", FCVAR_ARCHIVE, "disable DSP processing" );
static CVAR_DEFINE_AUTO( dsp_coeff_table, "0", FCVAR_ARCHIVE, "select DSP coefficient table: 0 for release or 1 for alpha 0.52" );
static CVAR_DEFINE_AUTO( room_type, "0", 0, "current room type preset" );
@@ -233,7 +232,6 @@ void SX_Init( void )
sxmod2cur = sxmod2 = 450 * ( idsp_dma_speed / SOUND_11k );
Cvar_RegisterVariable( &dsp_off );
Cvar_RegisterVariable( &room_off );
Cvar_RegisterVariable( &dsp_coeff_table );
Cvar_RegisterVariable( &roomwater_type );
@@ -811,7 +809,7 @@ DSP_Process
*/
void DSP_Process( portable_samplepair_t *pbfront, int sampleCount )
{
if( dsp_off.value || room_off.value || !sampleCount )
if( dsp_off.value || !sampleCount )
return;
// preset is already installed by CheckNewDspPresets
@@ -845,7 +843,7 @@ CheckNewDspPresets
*/
void CheckNewDspPresets( void )
{
if( dsp_off.value || room_off.value )
if( dsp_off.value != 0.0f )
return;
if( FBitSet( dsp_coeff_table.flags, FCVAR_CHANGED ))

View File

@@ -52,11 +52,8 @@ void S_SoundList_f( void )
{
totalSize += sc->size;
if( FBitSet( sc->flags, SOUND_LOOPED ))
Con_Printf( "L" );
else
Con_Printf( " " );
if( sc->loopStart >= 0 ) Con_Printf( "L" );
else Con_Printf( " " );
if( sfx->name[0] == '*' || !Q_strncmp( sfx->name, DEFAULT_SOUNDPATH, sizeof( DEFAULT_SOUNDPATH ) - 1 ))
Con_Printf( " (%2db) %s : %s\n", sc->width * 8, Q_memprint( sc->size ), sfx->name );
else Con_Printf( " (%2db) %s : " DEFAULT_SOUNDPATH "%s\n", sc->width * 8, Q_memprint( sc->size ), sfx->name );
@@ -113,7 +110,7 @@ static wavdata_t *S_CreateDefaultSound( void )
sc->width = 2;
sc->channels = 1;
sc->loopStart = 0;
sc->loopStart = -1;
sc->rate = SOUND_DMA_SPEED;
sc->samples = SOUND_DMA_SPEED;
sc->size = sc->samples * sc->width * sc->channels;
@@ -158,7 +155,7 @@ wavdata_t *S_LoadSound( sfx_t *sfx )
Sound_Process( &sc, SOUND_11k, sc->width, SOUND_RESAMPLE );
else if( sc->rate > SOUND_11k && sc->rate < SOUND_22k ) // some bad sounds
Sound_Process( &sc, SOUND_22k, sc->width, SOUND_RESAMPLE );
else if( sc->rate > SOUND_22k && sc->rate < SOUND_44k ) // some bad sounds
else if( sc->rate > SOUND_22k && sc->rate <= SOUND_32k ) // some bad sounds
Sound_Process( &sc, SOUND_44k, sc->width, SOUND_RESAMPLE );
sfx->cache = sc;
@@ -221,7 +218,7 @@ sfx_t *S_FindName( const char *pname, int *pfInCache )
sfx = &s_knownSfx[i];
memset( sfx, 0, sizeof( *sfx ));
if( pfInCache ) *pfInCache = false;
Q_strncpy( sfx->name, name, sizeof( sfx->name ));
Q_strncpy( sfx->name, name, MAX_STRING );
sfx->servercount = cl.servercount;
sfx->hashValue = COM_HashKey( sfx->name, MAX_SFX_HASH );
@@ -380,7 +377,7 @@ S_InitSounds
void S_InitSounds( void )
{
// create unused 0-entry
Q_strncpy( s_knownSfx->name, "*default", sizeof( s_knownSfx->name ));
Q_strncpy( s_knownSfx->name, "*default", MAX_QPATH );
s_knownSfx->hashValue = COM_HashKey( s_knownSfx->name, MAX_SFX_HASH );
s_knownSfx->hashNext = s_sfxHashList[s_knownSfx->hashValue];
s_sfxHashList[s_knownSfx->hashValue] = s_knownSfx;

View File

@@ -70,12 +70,6 @@ float S_GetMasterVolume( void )
return 0.0f;
}
if( s_listener.inmenu && !ui_renderworld.value && !Host_IsLocalGame( ))
{
// mute sounds in menu when it's not transparent and we're in multiplayer
return 0.0f;
}
if( !s_listener.inmenu && soundfade.percent != 0 )
{
scale = bound( 0.0f, soundfade.percent / 100.0f, 1.0f );
@@ -334,7 +328,7 @@ channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx, qboolean
// don't restart looping sounds for the same entity
wavdata_t *sc = channels[first_to_die].sfx->cache;
if( sc && FBitSet( sc->flags, SOUND_LOOPED ))
if( sc && sc->loopStart != -1 )
{
channel_t *ch = &channels[first_to_die];
@@ -509,7 +503,7 @@ static void SND_Spatialize( channel_t *ch )
pSource = ch->sfx->cache;
if( ch->use_loop && pSource && FBitSet( pSource->flags, SOUND_LOOPED ))
if( ch->use_loop && pSource && pSource->loopStart != -1 )
looping = true;
if( !ch->staticsound )
@@ -647,7 +641,7 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv
if( !target_chan->leftvol && !target_chan->rightvol )
{
// looping sounds don't use this optimization because they should stick around until they're killed.
if( !sfx->cache || !FBitSet( sfx->cache->flags, SOUND_LOOPED ))
if( !sfx->cache || sfx->cache->loopStart == -1 )
{
// if this is a streaming sound, play the whole thing.
if( chan != CHAN_STREAM )
@@ -899,7 +893,7 @@ int S_GetCurrentStaticSounds( soundlist_t *pout, int size )
VectorCopy( channels[i].origin, pout->origin );
pout->volume = (float)channels[i].master_vol / 255.0f;
pout->attenuation = channels[i].dist_mult * SND_CLIP_DISTANCE;
pout->looping = ( channels[i].use_loop && FBitSet( channels[i].sfx->cache->flags, SOUND_LOOPED ));
pout->looping = ( channels[i].use_loop && channels[i].sfx->cache->loopStart != -1 );
pout->pitch = channels[i].basePitch;
pout->channel = channels[i].entchannel;
pout->wordIndex = channels[i].wordIndex;
@@ -934,7 +928,7 @@ int S_GetCurrentDynamicSounds( soundlist_t *pout, int size )
if( !channels[i].sfx || !channels[i].sfx->name[0] || !Q_stricmp( channels[i].sfx->name, "*default" ))
continue; // don't serialize default sounds
looped = ( channels[i].use_loop && FBitSet( channels[i].sfx->cache->flags, SOUND_LOOPED ));
looped = ( channels[i].use_loop && channels[i].sfx->cache->loopStart != -1 );
if( channels[i].entchannel == CHAN_STATIC && looped && !Host_IsQuakeCompatible())
continue; // never serialize static looped sounds. It will be restoring in game code
@@ -1605,6 +1599,7 @@ void SND_UpdateSound( void )
// release raw-channels that no longer used more than 10 secs
S_FreeIdleRawChannels();
VectorCopy( cl.simvel, s_listener.velocity );
s_listener.frametime = (cl.time - cl.oldtime);
s_listener.waterlevel = cl.local.waterlevel;
s_listener.active = CL_IsInGame();

View File

@@ -17,56 +17,30 @@ GNU General Public License for more details.
#include "sound.h"
#include "client.h"
enum
{
IPAINTBUFFER = 0,
IROOMBUFFER,
ISTREAMBUFFER,
CPAINTBUFFERS,
};
#define IPAINTBUFFER 0
#define IROOMBUFFER 1
#define ISTREAMBUFFER 2
enum
{
FILTERTYPE_NONE = 0,
FILTERTYPE_LINEAR,
FILTERTYPE_CUBIC,
};
#define FILTERTYPE_NONE 0
#define FILTERTYPE_LINEAR 1
#define FILTERTYPE_CUBIC 2
#define CCHANVOLUMES 2
#define SND_SCALE_BITS 7
#define SND_SCALE_SHIFT ( 8 - SND_SCALE_BITS )
#define SND_SCALE_LEVELS ( 1 << SND_SCALE_BITS )
#define SND_SCALE_BITS 7
#define SND_SCALE_SHIFT (8 - SND_SCALE_BITS)
#define SND_SCALE_LEVELS (1 << SND_SCALE_BITS)
// sound mixing buffer
#define CPAINTFILTERMEM 3
#define CPAINTFILTERS 4 // maximum number of consecutive upsample passes per paintbuffer
portable_samplepair_t *g_curpaintbuffer;
portable_samplepair_t streambuffer[(PAINTBUFFER_SIZE+1)];
portable_samplepair_t paintbuffer[(PAINTBUFFER_SIZE+1)];
portable_samplepair_t roombuffer[(PAINTBUFFER_SIZE+1)];
portable_samplepair_t facingbuffer[(PAINTBUFFER_SIZE+1)];
portable_samplepair_t temppaintbuffer[(PAINTBUFFER_SIZE+1)];
paintbuffer_t paintbuffers[CPAINTBUFFERS];
// fixed point stuff for real-time resampling
#define FIX_BITS 28
#define FIX_SCALE ( 1 << FIX_BITS )
#define FIX_MASK (( 1 << FIX_BITS ) - 1 )
#define FIX_FLOAT( a ) ((int)(( a ) * FIX_SCALE ))
#define FIX( a ) (((int)( a )) << FIX_BITS )
#define FIX_INTPART( a ) (((int)( a )) >> FIX_BITS )
#define FIX_FRACPART( a ) (( a ) & FIX_MASK )
int snd_scaletable[SND_SCALE_LEVELS][256];
typedef struct
{
qboolean factive; // if true, mix to this paintbuffer using flags
portable_samplepair_t *pbuf; // front stereo mix buffer, for 2 or 4 channel mixing
int ifilter; // current filter memory buffer to use for upsampling pass
portable_samplepair_t fltmem[CPAINTFILTERS][CPAINTFILTERMEM];
} paintbuffer_t;
static portable_samplepair_t *g_curpaintbuffer;
static portable_samplepair_t streambuffer[(PAINTBUFFER_SIZE+1)];
static portable_samplepair_t paintbuffer[(PAINTBUFFER_SIZE+1)];
static portable_samplepair_t roombuffer[(PAINTBUFFER_SIZE+1)];
static portable_samplepair_t temppaintbuffer[(PAINTBUFFER_SIZE+1)];
static paintbuffer_t paintbuffers[CPAINTBUFFERS];
static int snd_scaletable[SND_SCALE_LEVELS][256];
void S_InitScaletable( void )
{
int i, j;
@@ -93,7 +67,7 @@ static void S_TransferPaintBuffer( int endtime )
dword *pbuf;
pbuf = (dword *)dma.buffer;
snd_p = (int *)g_curpaintbuffer;
snd_p = (int *)PAINTBUFFER;
lpaintedtime = paintedtime;
sampleMask = ((dma.samples >> 1) - 1);
@@ -137,20 +111,20 @@ static void S_TransferPaintBuffer( int endtime )
//===============================================================================
// Activate a paintbuffer. All active paintbuffers are mixed in parallel within
// MIX_MixChannelsToPaintbuffer, according to flags
static void MIX_ActivatePaintbuffer( int ipaintbuffer )
_inline void MIX_ActivatePaintbuffer( int ipaintbuffer )
{
Assert( ipaintbuffer < CPAINTBUFFERS );
paintbuffers[ipaintbuffer].factive = true;
}
static void MIX_SetCurrentPaintbuffer( int ipaintbuffer )
_inline void MIX_SetCurrentPaintbuffer( int ipaintbuffer )
{
Assert( ipaintbuffer < CPAINTBUFFERS );
g_curpaintbuffer = paintbuffers[ipaintbuffer].pbuf;
Assert( g_curpaintbuffer != NULL );
}
static int MIX_GetCurrentPaintbufferIndex( void )
_inline int MIX_GetCurrentPaintbufferIndex( void )
{
int i;
@@ -162,7 +136,7 @@ static int MIX_GetCurrentPaintbufferIndex( void )
return 0;
}
static paintbuffer_t *MIX_GetCurrentPaintbufferPtr( void )
_inline paintbuffer_t *MIX_GetCurrentPaintbufferPtr( void )
{
int ipaint = MIX_GetCurrentPaintbufferIndex();
@@ -171,7 +145,7 @@ static paintbuffer_t *MIX_GetCurrentPaintbufferPtr( void )
}
// Don't mix into any paintbuffers
static void MIX_DeactivateAllPaintbuffers( void )
_inline void MIX_DeactivateAllPaintbuffers( void )
{
int i;
@@ -180,7 +154,7 @@ static void MIX_DeactivateAllPaintbuffers( void )
}
// set upsampling filter indexes back to 0
static void MIX_ResetPaintbufferFilterCounters( void )
_inline void MIX_ResetPaintbufferFilterCounters( void )
{
int i;
@@ -189,13 +163,13 @@ static void MIX_ResetPaintbufferFilterCounters( void )
}
// return pointer to front paintbuffer pbuf, given index
static portable_samplepair_t *MIX_GetPFrontFromIPaint( int ipaintbuffer )
_inline portable_samplepair_t *MIX_GetPFrontFromIPaint( int ipaintbuffer )
{
Assert( ipaintbuffer < CPAINTBUFFERS );
return paintbuffers[ipaintbuffer].pbuf;
}
static paintbuffer_t *MIX_GetPPaintFromIPaint( int ipaint )
_inline paintbuffer_t *MIX_GetPPaintFromIPaint( int ipaint )
{
Assert( ipaint < CPAINTBUFFERS );
return &paintbuffers[ipaint];
@@ -549,7 +523,6 @@ static void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate
wavdata_t *pSource;
int i, sampleCount;
qboolean bZeroVolume;
qboolean local = Host_IsLocalGame();
// mix each channel into paintbuffer
ch = channels;
@@ -576,7 +549,7 @@ static void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate
{
// play, playvol
}
else if(( s_listener.inmenu || s_listener.paused ) && !ch->localsound && local )
else if(( s_listener.inmenu || s_listener.paused ) && !ch->localsound )
{
// play only local sounds, keep pause for other
continue;
@@ -594,7 +567,6 @@ static void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate
// Don't mix sound data for sounds with zero volume. If it's a non-looping sound,
// just remove the sound when its volume goes to zero.
bZeroVolume = !ch->leftvol && !ch->rightvol;
if( !bZeroVolume )
@@ -604,7 +576,7 @@ static void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate
bZeroVolume = true;
}
if( !pSource || ( bZeroVolume && !FBitSet( pSource->flags, SOUND_LOOPED )))
if( !pSource || ( bZeroVolume && pSource->loopStart == -1 ))
{
if( !pSource )
{
@@ -657,7 +629,7 @@ static void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate
}
// pass in index -1...count+2, return pointer to source sample in either paintbuffer or delay buffer
static portable_samplepair_t *S_GetNextpFilter( int i, portable_samplepair_t *pbuffer, portable_samplepair_t *pfiltermem )
_inline portable_samplepair_t *S_GetNextpFilter( int i, portable_samplepair_t *pbuffer, portable_samplepair_t *pfiltermem )
{
// The delay buffer is assumed to precede the paintbuffer by 6 duplicated samples
if( i == -1 ) return (&(pfiltermem[0]));
@@ -866,14 +838,6 @@ static void MIX_MixPaintbuffers( int ibuf1, int ibuf2, int ibuf3, int count, flo
pbuf2 = paintbuffers[ibuf2].pbuf;
pbuf3 = paintbuffers[ibuf3].pbuf;
if( !gain )
{
// do not mix buf2 into buf3, just copy
if( pbuf1 != pbuf3 )
memcpy( pbuf3, pbuf1, sizeof( *pbuf1 ) * count );
return;
}
// destination buffer stereo - average n chans down to stereo
// destination 2ch:

View File

@@ -142,7 +142,7 @@ S_StreamGetCurrentState
save\restore code
=================
*/
qboolean S_StreamGetCurrentState( char *currentTrack, size_t currentTrackSize, char *loopTrack, size_t loopTrackSize, int *position )
qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position )
{
if( !s_bgTrack.stream )
return false; // not active
@@ -150,15 +150,15 @@ qboolean S_StreamGetCurrentState( char *currentTrack, size_t currentTrackSize, c
if( currentTrack )
{
if( s_bgTrack.current[0] )
Q_strncpy( currentTrack, s_bgTrack.current, currentTrackSize );
else Q_strncpy( currentTrack, "*", currentTrackSize ); // no track
Q_strncpy( currentTrack, s_bgTrack.current, MAX_STRING );
else Q_strncpy( currentTrack, "*", MAX_STRING ); // no track
}
if( loopTrack )
{
if( s_bgTrack.loopName[0] )
Q_strncpy( loopTrack, s_bgTrack.loopName, loopTrackSize );
else Q_strncpy( loopTrack, "*", loopTrackSize ); // no track
Q_strncpy( loopTrack, s_bgTrack.loopName, MAX_STRING );
else Q_strncpy( loopTrack, "*", MAX_STRING ); // no track
}
if( position )

View File

@@ -27,7 +27,7 @@ int S_ConvertLoopedPosition( wavdata_t *pSource, int samplePosition, qboolean us
// convert to a position within the loop
// At the end of the loop, we return a short buffer, and subsequent call
// will loop back and get the rest of the buffer
if( FBitSet( pSource->flags, SOUND_LOOPED ) && samplePosition >= pSource->samples && use_loop )
if( pSource->loopStart >= 0 && samplePosition >= pSource->samples && use_loop )
{
// size of loop
int loopSize = pSource->samples - pSource->loopStart;

View File

@@ -20,178 +20,206 @@ extern poolhandle_t sndpool;
#include "xash3d_mathlib.h"
#define XASH_AUDIO_CD_QUALITY 1 // some platforms might need this
// sound engine rate defines
#if XASH_AUDIO_CD_QUALITY
#define SOUND_11k 11025 // 11khz sample rate
#define SOUND_22k 22050 // 22khz sample rate
#define SOUND_44k 44100 // 44khz sample rate
#else // XASH_AUDIO_CD_QUALITY
#define SOUND_11k 12000 // 11khz sample rate
#define SOUND_22k 24000 // 22khz sample rate
#define SOUND_44k 48000 // 44khz sample rate
#endif // XASH_AUDIO_CD_QUALITY
#define SOUND_DMA_SPEED 44100 // hardware playback rate
#define SOUND_11k 11025 // 11khz sample rate
#define SOUND_16k 16000 // 16khz sample rate
#define SOUND_22k 22050 // 22khz sample rate
#define SOUND_32k 32000 // 32khz sample rate
#define SOUND_44k 44100 // 44khz sample rate
#define DMA_MSEC_PER_SAMPLE ((float)(1000.0 / SOUND_DMA_SPEED))
#define SOUND_DMA_SPEED SOUND_44k // hardware playback rate
// fixed point stuff for real-time resampling
#define FIX_BITS 28
#define FIX_SCALE (1 << FIX_BITS)
#define FIX_MASK ((1 << FIX_BITS)-1)
#define FIX_FLOAT(a) ((int)((a) * FIX_SCALE))
#define FIX(a) (((int)(a)) << FIX_BITS)
#define FIX_INTPART(a) (((int)(a)) >> FIX_BITS)
#define FIX_FRACTION(a,b) (FIX(a)/(b))
#define FIX_FRACPART(a) ((a) & FIX_MASK)
// NOTE: clipped sound at 32760 to avoid overload
#define CLIP( x ) (( x ) > 32760 ? 32760 : (( x ) < -32760 ? -32760 : ( x )))
#define CLIP( x ) (( x ) > 32760 ? 32760 : (( x ) < -32760 ? -32760 : ( x )))
#define PAINTBUFFER_SIZE 1024 // 44k: was 512
#define PAINTBUFFER_SIZE 1024 // 44k: was 512
#define PAINTBUFFER (g_curpaintbuffer)
#define CPAINTBUFFERS 3
#define S_RAW_SOUND_IDLE_SEC 10 // time interval for idling raw sound before it's freed
#define S_RAW_SOUND_BACKGROUNDTRACK -2
#define S_RAW_SOUND_SOUNDTRACK -1
#define S_RAW_SAMPLES_PRECISION_BITS 14
// sound mixing buffer
#define CPAINTFILTERMEM 3
#define CPAINTFILTERS 4 // maximum number of consecutive upsample passes per paintbuffer
#define S_RAW_SOUND_IDLE_SEC 10 // time interval for idling raw sound before it's freed
#define S_RAW_SOUND_BACKGROUNDTRACK -2
#define S_RAW_SOUND_SOUNDTRACK -1
#define S_RAW_SAMPLES_PRECISION_BITS 14
#define CIN_FRAMETIME (1.0f / 30.0f)
typedef struct
{
int left;
int right;
int left;
int right;
} portable_samplepair_t;
typedef struct
{
qboolean factive; // if true, mix to this paintbuffer using flags
portable_samplepair_t *pbuf; // front stereo mix buffer, for 2 or 4 channel mixing
int ifilter; // current filter memory buffer to use for upsampling pass
portable_samplepair_t fltmem[CPAINTFILTERS][CPAINTFILTERMEM];
} paintbuffer_t;
typedef struct sfx_s
{
char name[MAX_QPATH];
wavdata_t *cache;
char name[MAX_QPATH];
wavdata_t *cache;
int servercount;
uint hashValue;
struct sfx_s *hashNext;
int servercount;
uint hashValue;
struct sfx_s *hashNext;
} sfx_t;
extern portable_samplepair_t paintbuffer[];
extern portable_samplepair_t roombuffer[];
extern portable_samplepair_t temppaintbuffer[];
extern portable_samplepair_t *g_curpaintbuffer;
extern paintbuffer_t paintbuffers[];
// structure used for fading in and out client sound volume.
typedef struct
{
float initial_percent;
float percent; // how far to adjust client's volume down by.
float starttime; // GetHostTime() when we started adjusting volume
float fadeouttime; // # of seconds to get to faded out state
float holdtime; // # of seconds to hold
float fadeintime; // # of seconds to restore
float initial_percent;
float percent; // how far to adjust client's volume down by.
float starttime; // GetHostTime() when we started adjusting volume
float fadeouttime; // # of seconds to get to faded out state
float holdtime; // # of seconds to hold
float fadeintime; // # of seconds to restore
} soundfade_t;
typedef struct
{
float percent;
float percent;
} musicfade_t;
typedef struct snd_format_s
{
uint speed;
byte width;
byte channels;
unsigned int speed;
unsigned int width;
unsigned int channels;
} snd_format_t;
typedef struct
{
snd_format_t format;
int samples; // mono samples in buffer
int samplepos; // in mono samples
qboolean initialized; // sound engine is active
byte *buffer;
const char *backendName;
snd_format_t format;
int samples; // mono samples in buffer
int samplepos; // in mono samples
byte *buffer;
qboolean initialized; // sound engine is active
const char *backendName;
} dma_t;
#include "vox.h"
typedef struct
{
double sample;
wavdata_t *pData;
double forcedEndSample;
qboolean finished;
double sample;
wavdata_t *pData;
double forcedEndSample;
qboolean finished;
} mixer_t;
typedef struct rawchan_s
{
int entnum;
int master_vol;
int leftvol; // 0-255 left volume
int rightvol; // 0-255 right volume
float dist_mult; // distance multiplier (attenuation/clipK)
vec3_t origin; // only use if fixed_origin is set
volatile uint s_rawend;
float oldtime; // catch time jumps
wavdata_t sound_info; // advance play position
size_t max_samples; // buffer length
portable_samplepair_t rawsamples[1]; // variable sized
int entnum;
int master_vol;
int leftvol; // 0-255 left volume
int rightvol; // 0-255 right volume
float dist_mult; // distance multiplier (attenuation/clipK)
vec3_t origin; // only use if fixed_origin is set
volatile uint s_rawend;
wavdata_t sound_info; // advance play position
float oldtime; // catch time jumps
size_t max_samples; // buffer length
portable_samplepair_t rawsamples[1]; // variable sized
} rawchan_t;
typedef struct channel_s
{
char name[16]; // keep sentence name
sfx_t *sfx; // sfx number
char name[16]; // keept sentence name
sfx_t *sfx; // sfx number
int leftvol; // 0-255 left volume
int rightvol; // 0-255 right volume
int leftvol; // 0-255 left volume
int rightvol; // 0-255 right volume
int entnum; // entity soundsource
int entchannel; // sound channel (CHAN_STREAM, CHAN_VOICE, etc.)
vec3_t origin; // only use if fixed_origin is set
float dist_mult; // distance multiplier (attenuation/clipK)
int master_vol; // 0-255 master volume
int basePitch; // base pitch percent (100% is normal pitch playback)
float pitch; // real-time pitch after any modulation or shift by dynamic data
qboolean use_loop; // don't loop default and local sounds
qboolean staticsound; // use origin instead of fetching entnum's origin
qboolean localsound; // it's a local menu sound (not looped, not paused)
mixer_t pMixer;
int entnum; // entity soundsource
int entchannel; // sound channel (CHAN_STREAM, CHAN_VOICE, etc.)
vec3_t origin; // only use if fixed_origin is set
float dist_mult; // distance multiplier (attenuation/clipK)
int master_vol; // 0-255 master volume
qboolean isSentence; // bit who indicated sentence
int basePitch; // base pitch percent (100% is normal pitch playback)
float pitch; // real-time pitch after any modulation or shift by dynamic data
qboolean use_loop; // don't loop default and local sounds
qboolean staticsound; // use origin instead of fetching entnum's origin
qboolean localsound; // it's a local menu sound (not looped, not paused)
mixer_t pMixer;
// sentence mixer
qboolean isSentence; // bit indicating sentence
int wordIndex;
mixer_t *currentWord; // NULL if sentence is finished
voxword_t words[CVOXWORDMAX];
int wordIndex;
mixer_t *currentWord; // NULL if sentence is finished
voxword_t words[CVOXWORDMAX];
} channel_t;
typedef struct
{
vec3_t origin; // simorg + view_ofs
vec3_t forward;
vec3_t right;
vec3_t up;
vec3_t origin; // simorg + view_ofs
vec3_t velocity;
vec3_t forward;
vec3_t right;
vec3_t up;
int entnum;
int waterlevel;
float frametime; // used for sound fade
qboolean active;
qboolean inmenu; // listener in-menu ?
qboolean paused;
qboolean streaming; // playing AVI-file
qboolean stream_paused; // pause only background track
int entnum;
int waterlevel;
float frametime; // used for sound fade
qboolean active;
qboolean inmenu; // listener in-menu ?
qboolean paused;
qboolean streaming; // playing AVI-file
qboolean stream_paused; // pause only background track
} listener_t;
typedef struct
{
string current; // a currently playing track
string loopName; // may be empty
stream_t *stream;
int source; // may be game, menu, etc
string current; // a currently playing track
string loopName; // may be empty
stream_t *stream;
int source; // may be game, menu, etc
} bg_track_t;
//====================================================================
#define MAX_DYNAMIC_CHANNELS (60 + NUM_AMBIENTS)
#define MAX_CHANNELS (256 + MAX_DYNAMIC_CHANNELS) // Scourge Of Armagon has too many static sounds on hip2m4.bsp
#define MAX_RAW_CHANNELS 48
#define MAX_RAW_SAMPLES 8192
#define MAX_DYNAMIC_CHANNELS (60 + NUM_AMBIENTS)
#define MAX_CHANNELS (256 + MAX_DYNAMIC_CHANNELS) // Scourge Of Armagon has too many static sounds on hip2m4.bsp
#define MAX_RAW_CHANNELS 48
#define MAX_RAW_SAMPLES 8192
extern sound_t ambient_sfx[NUM_AMBIENTS];
extern qboolean snd_ambient;
extern channel_t channels[MAX_CHANNELS];
extern rawchan_t *raw_channels[MAX_RAW_CHANNELS];
extern int total_channels;
extern int paintedtime;
extern int soundtime;
extern listener_t s_listener;
extern int idsp_room;
extern dma_t dma;
extern sound_t ambient_sfx[NUM_AMBIENTS];
extern qboolean snd_ambient;
extern channel_t channels[MAX_CHANNELS];
extern rawchan_t *raw_channels[MAX_RAW_CHANNELS];
extern int total_channels;
extern int paintedtime;
extern int soundtime;
extern listener_t s_listener;
extern int idsp_room;
extern dma_t dma;
extern convar_t s_musicvolume;
extern convar_t s_lerping;
extern convar_t s_test; // cvar to test new effects
extern convar_t s_musicvolume;
extern convar_t s_lerping;
extern convar_t s_test; // cvar to testify new effects
extern convar_t s_samplecount;
extern convar_t s_warn_late_precache;
@@ -264,6 +292,7 @@ void SND_ForceCloseMouth( int entnum );
//
void S_StreamSoundTrack( void );
void S_StreamBackgroundTrack( void );
qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position );
void S_PrintBackgroundTrackState( void );
void S_FadeMusicVolume( float fadePercent );

View File

@@ -25,12 +25,11 @@ voice_state_t voice = { 0 };
CVAR_DEFINE_AUTO( voice_enable, "1", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "enable voice chat" );
CVAR_DEFINE_AUTO( voice_loopback, "0", FCVAR_PRIVILEGED, "loopback voice back to the speaker" );
CVAR_DEFINE_AUTO( voice_scale, "1.0", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "incoming voice volume scale" );
CVAR_DEFINE_AUTO( voice_transmit_scale, "1.0", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "outcoming voice volume scale" );
CVAR_DEFINE_AUTO( voice_avggain, "0.5", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "automatic voice gain control (average)" );
CVAR_DEFINE_AUTO( voice_maxgain, "5.0", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "automatic voice gain control (maximum)" );
CVAR_DEFINE_AUTO( voice_inputfromfile, "0", FCVAR_PRIVILEGED, "input voice from voice_input.wav" );
static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale );
static void Voice_ApplyGainAdjust( int16_t *samples, int count );
/*
===============================================================================
@@ -40,25 +39,6 @@ static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale );
===============================================================================
*/
static qboolean Voice_InitCustomMode( void )
{
int err = 0;
voice.width = sizeof( opus_int16 );
voice.samplerate = VOICE_OPUS_CUSTOM_SAMPLERATE;
voice.frame_size = VOICE_OPUS_CUSTOM_FRAME_SIZE;
voice.custom_mode = opus_custom_mode_create( SOUND_44k, voice.frame_size, &err );
if( !voice.custom_mode )
{
Con_Printf( S_ERROR "Can't create Opus Custom mode: %s\n", opus_strerror( err ));
return false;
}
return true;
}
/*
=========================
Voice_InitOpusDecoder
@@ -67,17 +47,24 @@ Voice_InitOpusDecoder
*/
static qboolean Voice_InitOpusDecoder( void )
{
int err = 0;
int err;
for( int i = 0; i < cl.maxclients; i++ )
voice.width = sizeof( opus_int16 );
voice.samplerate = VOICE_OPUS_CUSTOM_SAMPLERATE;
voice.frame_size = VOICE_OPUS_CUSTOM_FRAME_SIZE;
voice.custom_mode = opus_custom_mode_create( SOUND_44k, voice.frame_size, &err );
if( !voice.custom_mode )
{
voice.decoders[i] = opus_custom_decoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
Con_Printf( S_ERROR "Can't create Opus Custom mode: %s\n", opus_strerror( err ));
return false;
}
if( !voice.decoders[i] )
{
Con_Printf( S_ERROR "Can't create Opus decoder for %i: %s\n", i, opus_strerror( err ));
return false;
}
voice.decoder = opus_custom_decoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
if( !voice.decoder )
{
Con_Printf( S_ERROR "Can't create Opus encoder: %s\n", opus_strerror( err ));
return false;
}
return true;
@@ -91,7 +78,7 @@ Voice_InitOpusEncoder
*/
static qboolean Voice_InitOpusEncoder( int quality )
{
int err = 0;
int err;
voice.encoder = opus_custom_encoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
if( !voice.encoder )
@@ -130,13 +117,10 @@ Voice_ShutdownOpusDecoder
*/
static void Voice_ShutdownOpusDecoder( void )
{
for( int i = 0; i < MAX_CLIENTS; i++ )
if( voice.decoder )
{
if( !voice.decoders[i] )
continue;
opus_custom_decoder_destroy( voice.decoders[i] );
voice.decoders[i] = NULL;
opus_custom_decoder_destroy( voice.decoder );
voice.decoder = NULL;
}
}
@@ -153,10 +137,7 @@ static void Voice_ShutdownOpusEncoder( void )
opus_custom_encoder_destroy( voice.encoder );
voice.encoder = NULL;
}
}
static void Voice_ShutdownCustomMode( void )
{
if( voice.custom_mode )
{
opus_custom_mode_destroy( voice.custom_mode );
@@ -203,7 +184,7 @@ static uint Voice_GetOpusCompressedData( byte *out, uint maxsize, uint *frames )
if( !voice.input_file )
{
// adjust gain before encoding, but only for input from voice
Voice_ApplyGainAdjust((opus_int16*)(voice.input_buffer + ofs), voice.frame_size, voice_transmit_scale.value);
Voice_ApplyGainAdjust((opus_int16*)(voice.input_buffer + ofs), voice.frame_size);
}
#endif
@@ -257,10 +238,10 @@ Voice_ApplyGainAdjust
=========================
*/
static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale )
static void Voice_ApplyGainAdjust( int16_t *samples, int count )
{
float gain, modifiedMax;
int average, blockOffset = 0;
int average, adjustedSample, blockOffset = 0;
for( ;; )
{
@@ -279,8 +260,10 @@ static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale )
localMax = absSample;
localSum += absSample;
gain = voice.autogain.current_gain + i * voice.autogain.gain_multiplier;
samples[blockOffset + i] = bound( SHRT_MIN, (int)( sample * gain ), SHRT_MAX );
adjustedSample = Q_min( SHRT_MAX, Q_max(( int )( sample * gain ), SHRT_MIN ));
samples[blockOffset + i] = adjustedSample;
}
if( blockOffset % voice.autogain.block_size == 0 )
@@ -288,9 +271,9 @@ static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale )
average = localSum / blockSize;
modifiedMax = average + ( localMax - average ) * voice_avggain.value;
voice.autogain.current_gain = voice.autogain.next_gain * scale;
voice.autogain.next_gain = Q_min( (float)SHRT_MAX / modifiedMax, voice_maxgain.value ) * scale;
voice.autogain.gain_multiplier = ( voice.autogain.next_gain - voice.autogain.current_gain ) / ( blockSize - 1 );
voice.autogain.current_gain = voice.autogain.next_gain * voice_scale.value;
voice.autogain.next_gain = Q_min( (float)SHRT_MAX / modifiedMax, voice_maxgain.value ) * voice_scale.value;
voice.autogain.gain_multiplier = ( voice.autogain.next_gain - voice.autogain.current_gain ) / ( voice.autogain.block_size - 1 );
}
blockOffset += blockSize;
}
@@ -460,7 +443,7 @@ Feed the decoded data to engine sound subsystem
static void Voice_StartChannel( uint samples, byte *data, int entnum )
{
SND_ForceInitMouth( entnum );
S_RawEntSamples( entnum, samples, voice.samplerate, voice.width, VOICE_PCM_CHANNELS, data, bound( 0, 255 * voice_scale.value, 255 ));
S_RawEntSamples( entnum, samples, voice.samplerate, voice.width, VOICE_PCM_CHANNELS, data, 255 );
}
/*
@@ -472,11 +455,10 @@ Received encoded voice data, decode it
*/
void Voice_AddIncomingData( int ent, const byte *data, uint size, uint frames )
{
const int playernum = ent - 1;
int samples = 0;
int ofs = 0;
if( playernum < 0 || playernum >= cl.maxclients || !voice.decoders[playernum] )
if( !voice.decoder )
return;
// decode frame by frame
@@ -496,7 +478,7 @@ void Voice_AddIncomingData( int ent, const byte *data, uint size, uint frames )
if( ofs + compressed_size > size )
break;
frame_samples = opus_custom_decode( voice.decoders[playernum], data + ofs, compressed_size,
frame_samples = opus_custom_decode( voice.decoder, data + ofs, compressed_size,
(opus_int16*)voice.decompress_buffer + samples, voice.frame_size );
ofs += compressed_size;
@@ -520,8 +502,8 @@ void CL_AddVoiceToDatagram( void )
if( cls.state != ca_active || !Voice_IsRecording() || !voice.encoder )
return;
size = Voice_GetOpusCompressedData( voice.compress_buffer, sizeof( voice.compress_buffer ), &frames );
size = Voice_GetOpusCompressedData( voice.output_buffer, sizeof( voice.output_buffer ), &frames );
if( size > 0 && MSG_GetNumBytesLeft( &cls.datagram ) >= size + 32 )
{
@@ -529,7 +511,7 @@ void CL_AddVoiceToDatagram( void )
MSG_WriteByte( &cls.datagram, voice_loopback.value != 0 );
MSG_WriteByte( &cls.datagram, frames );
MSG_WriteShort( &cls.datagram, size );
MSG_WriteBytes( &cls.datagram, voice.compress_buffer, size );
MSG_WriteBytes( &cls.datagram, voice.output_buffer, size );
}
}
@@ -545,7 +527,6 @@ void Voice_RegisterCvars( void )
Cvar_RegisterVariable( &voice_enable );
Cvar_RegisterVariable( &voice_loopback );
Cvar_RegisterVariable( &voice_scale );
Cvar_RegisterVariable( &voice_transmit_scale );
Cvar_RegisterVariable( &voice_avggain );
Cvar_RegisterVariable( &voice_maxgain );
Cvar_RegisterVariable( &voice_inputfromfile );
@@ -563,9 +544,8 @@ static void Voice_Shutdown( void )
int i;
Voice_RecordStop();
Voice_ShutdownOpusDecoder();
Voice_ShutdownOpusEncoder();
Voice_ShutdownCustomMode();
Voice_ShutdownOpusDecoder();
VoiceCapture_Shutdown();
if( voice.local.talking_ack )
@@ -629,10 +609,11 @@ qboolean Voice_Init( const char *pszCodecName, int quality, qboolean preinit )
voice.autogain.block_size = 128;
if( !Voice_InitCustomMode( ))
if( !Voice_InitOpusDecoder( ))
{
// no reason to init encoder and open audio device
// if we can't hear other players
Con_Printf( S_ERROR "Voice chat disabled.\n" );
Voice_Shutdown();
return false;
}
@@ -652,16 +633,6 @@ qboolean Voice_Init( const char *pszCodecName, int quality, qboolean preinit )
if( !preinit )
{
Voice_ShutdownOpusDecoder();
if( !Voice_InitOpusDecoder())
{
// no reason to init encoder and open audio device
// if we can't hear other players
Con_Printf( S_ERROR "Can't create decoders, voice chat is disabled.\n" );
Voice_Shutdown();
return false;
}
voice.device_opened = VoiceCapture_Init();
if( !voice.device_opened )

View File

@@ -31,7 +31,7 @@ typedef struct OpusCustomMode OpusCustomMode;
#define VOICE_PCM_CHANNELS 1 // always mono
// never change these parameters when using opuscustom
#define VOICE_OPUS_CUSTOM_SAMPLERATE 44100
#define VOICE_OPUS_CUSTOM_SAMPLERATE SOUND_44k
// must follow opus custom requirements
// also be divisible with MAX_RAW_SAMPLES
#define VOICE_OPUS_CUSTOM_FRAME_SIZE 1024
@@ -62,7 +62,7 @@ typedef struct voice_state_s
// opus stuff
OpusCustomMode *custom_mode;
OpusCustomEncoder *encoder;
OpusCustomDecoder *decoders[MAX_CLIENTS];
OpusCustomDecoder *decoder;
// audio info
uint width;
@@ -71,7 +71,7 @@ typedef struct voice_state_s
// buffers
byte input_buffer[MAX_RAW_SAMPLES];
byte compress_buffer[MAX_RAW_SAMPLES];
byte output_buffer[MAX_RAW_SAMPLES];
byte decompress_buffer[MAX_RAW_SAMPLES];
fs_offset_t input_buffer_pos; // in bytes

View File

@@ -16,20 +16,21 @@ GNU General Public License for more details.
#ifndef VOX_H
#define VOX_H
#define CVOXWORDMAX 64
#define SENTENCE_INDEX -99999 // unique sentence index
#define CVOXWORDMAX 64
#define SENTENCE_INDEX -99999 // unique sentence index
typedef struct voxword_s
{
int volume; // increase percent, ie: 125 = 125% increase
int pitch; // pitch shift up percent
int start; // offset start of wave percent
int end; // offset end of wave percent
int cbtrim; // end of wave after being trimmed to 'end'
int fKeepCached; // 1 if this word was already in cache before sentence referenced it
int samplefrac; // if pitch shifting, this is position into wav * 256
int timecompress; // % of wave to skip during playback (causes no pitch shift)
sfx_t *sfx; // name and cache pointer
int volume; // increase percent, ie: 125 = 125% increase
int pitch; // pitch shift up percent
int start; // offset start of wave percent
int end; // offset end of wave percent
int cbtrim; // end of wave after being trimmed to 'end'
int fKeepCached; // 1 if this word was already in cache before sentence referenced it
int samplefrac; // if pitch shifting, this is position into wav * 256
int timecompress; // % of wave to skip during playback (causes no pitch shift)
sfx_t *sfx; // name and cache pointer
} voxword_t;
struct channel_s;

View File

@@ -19,15 +19,13 @@ GNU General Public License for more details.
#define HASH_SIZE 128 // 128 * 4 * 4 == 2048 bytes
typedef struct base_command_hashmap_s base_command_hashmap_t;
struct base_command_hashmap_s
typedef struct base_command_hashmap_s
{
base_command_t *basecmd; // base command: cvar, alias or command
base_command_hashmap_t *next;
base_command_type_e type; // type for faster searching
char name[1]; // key for searching
};
base_command_t *basecmd; // base command: cvar, alias or command
const char *name; // key for searching
base_command_type_e type; // type for faster searching
struct base_command_hashmap_s *next;
} base_command_hashmap_t;
static base_command_hashmap_t *hashed_cmds[HASH_SIZE];
@@ -126,12 +124,11 @@ void BaseCmd_Insert( base_command_type_e type, base_command_t *basecmd, const ch
{
base_command_hashmap_t *elem, *cur, *find;
uint hash = BaseCmd_HashKey( name );
size_t len = Q_strlen( name );
elem = Z_Malloc( sizeof( base_command_hashmap_t ) + len );
elem = Z_Malloc( sizeof( base_command_hashmap_t ) );
elem->basecmd = basecmd;
elem->type = type;
Q_strncpy( elem->name, name, len + 1 );
elem->name = name;
// link the variable in alphanumerical order
for( cur = NULL, find = hashed_cmds[hash];

View File

@@ -31,6 +31,8 @@ typedef enum base_command_type
typedef void base_command_t;
void BaseCmd_Init( void );
base_command_t *BaseCmd_Find( base_command_type_e type, const char *name );
void BaseCmd_FindAll( const char *name,

View File

@@ -640,7 +640,7 @@ void Cmd_TokenizeString( const char *text )
while( 1 )
{
// skip whitespace up to a /n
while( *text && ((byte)*text ) <= ' ' && *text != '\r' && *text != '\n' )
while( *text && *text <= ' ' && *text != '\r' && *text != '\n' )
text++;
if( *text == '\n' || *text == '\r' )
@@ -949,7 +949,7 @@ static void Cmd_Else_f( void )
static qboolean Cmd_ShouldAllowCommand( cmd_t *cmd, qboolean isPrivileged )
{
const char *prefixes[] = { "cl_", "gl_", "r_", "m_", "hud_", "joy_", "con_", "scr_" };
const char *prefixes[] = { "cl_", "gl_", "r_", "m_", "hud_" };
int i;
// always allow local commands
@@ -1015,7 +1015,7 @@ static void Cmd_ExecuteStringWithPrivilegeCheck( const char *text, qboolean isPr
*ptoken++ = *text++;
*ptoken = 0;
len += Q_strncpy( pcmd, Cvar_VariableString( token ), sizeof( token ) - len );
len += Q_strncpy( pcmd, Cvar_VariableString( token ), MAX_CMD_LINE - len );
pcmd = command + len;
if( !*text ) break;

View File

@@ -74,7 +74,6 @@ GNU General Public License for more details.
#define DEFAULT_UPDATE_PAGE "https://github.com/FWGS/xash3d-fwgs/releases/latest"
#define XASH_ENGINE_NAME "Xash3D FWGS"
#define XASH_DEDICATED_SERVER_NAME "XashDS"
#define XASH_VERSION "0.20" // engine current version
#define XASH_COMPAT_VERSION "0.99" // version we are based on

View File

@@ -25,19 +25,16 @@ GNU General Public License for more details.
static const char *file_exts[] =
{
// ban text files that don't make sense as resource
"cfg", "lst", "ini", "log",
// ban Windows code
"exe", "vbs", "com", "bat",
"dll", "sys", "ps1",
// ban common unix code
// NOTE: in unix anything can be executed as long it has access flag
"so", "sh", "dylib",
// ban mobile archives
"apk", "ipa",
"cfg",
"lst",
"exe",
"vbs",
"com",
"bat",
"dll",
"ini",
"log",
"sys",
};
#ifdef _DEBUG
@@ -393,9 +390,6 @@ byte *LZSS_Compress( byte *pInput, int inputLength, uint *pOutputSize )
byte *pFinal = NULL;
lzss_state_t state;
if( !pStart )
return NULL;
memset( &state, 0, sizeof( state ));
state.window_size = LZSS_WINDOW_SIZE;
@@ -903,10 +897,7 @@ qboolean COM_IsSafeFileToDownload( const char *filename )
if( !COM_CheckString( filename ))
return false;
ext = COM_FileExtension( lwrfilename );
// only allow extensionless files that start with !MD5
if( !Q_strncmp( filename, "!MD5", 4 ) && ext[0] == 0 )
if( !Q_strncmp( filename, "!MD5", 4 ))
return true;
Q_strnlwr( filename, lwrfilename, sizeof( lwrfilename ));
@@ -929,6 +920,8 @@ qboolean COM_IsSafeFileToDownload( const char *filename )
if( Q_strlen( first ) != 4 )
return false;
ext = COM_FileExtension( lwrfilename );
for( i = 0; i < ARRAYSIZE( file_exts ); i++ )
{
if( !Q_stricmp( ext, file_exts[i] ))

View File

@@ -273,12 +273,12 @@ typedef struct
typedef enum bugcomp_e
{
// reverts fix for pfnPEntityOfEntIndex for bug compatibility with GoldSrc
BUGCOMP_PENTITYOFENTINDEX_FLAG = BIT( 0 ),
// default mode, we assume that user dlls are not relying on engine bugs
BUGCOMP_OFF,
// rewrites mod's attempts to write GoldSrc-specific messages into Xash protocol
// (new wrappers are added by request)
BUGCOMP_MESSAGE_REWRITE_FACILITY_FLAG = BIT( 1 ),
// GoldSrc mode, user dlls are relying on GoldSrc specific bugs
// but fixing them may break regular Xash games
BUGCOMP_GOLDSRC,
} bugcomp_t;
typedef struct host_parm_s
@@ -356,7 +356,7 @@ typedef struct host_parm_s
int numdecals;
// bug compatibility level, for very "special" games
uint32_t bugcomp;
bugcomp_t bugcomp;
// measure time to first frame
double starttime;
@@ -479,6 +479,14 @@ typedef enum
WF_TOTALCOUNT, // must be last
} sndformat_t;
// soundlib global settings
typedef enum
{
SL_USE_LERPING = BIT(0), // lerping sounds during resample
SL_KEEP_8BIT = BIT(1), // don't expand 8bit sounds automatically up to 16 bit
SL_ALLOW_OVERWRITE = BIT(2), // allow to overwrite stored sounds
} slFlags_t;
// wavdata output flags
typedef enum
{
@@ -487,20 +495,21 @@ typedef enum
SOUND_STREAM = BIT( 1 ), // this is a streaminfo, not a real sound
// Sound_Process manipulation flags
SOUND_RESAMPLE = BIT( 12 ), // resample sound to specified rate
SOUND_RESAMPLE = BIT(12), // resample sound to specified rate
SOUND_CONVERT16BIT = BIT(13), // change sound resolution from 8 bit to 16
} sndFlags_t;
typedef struct
{
word rate; // num samples per second (e.g. 11025 - 11 khz)
byte width; // resolution - bum bits divided by 8 (8 bit is 1, 16 bit is 2)
byte channels; // num channels (1 - mono, 2 - stereo)
uint loopStart; // offset at this point sound will be looping while playing more than only once
uint samples; // total samplecount in wav
uint type; // compression type
uint flags; // misc sound flags
byte *buffer; // sound buffer
size_t size; // for bounds checking
word rate; // num samples per second (e.g. 11025 - 11 khz)
byte width; // resolution - bum bits divided by 8 (8 bit is 1, 16 bit is 2)
byte channels; // num channels (1 - mono, 2 - stereo)
int loopStart; // offset at this point sound will be looping while playing more than only once
int samples; // total samplecount in wav
uint type; // compression type
uint flags; // misc sound flags
byte *buffer; // sound buffer
size_t size; // for bounds checking
} wavdata_t;
//
@@ -695,7 +704,7 @@ void Log_Printf( const char *fmt, ... ) _format( 1 );
void SV_BroadcastCommand( const char *fmt, ... ) _format( 1 );
void SV_BroadcastPrintf( struct sv_client_s *ignore, const char *fmt, ... ) _format( 2 );
void CL_ClearStaticEntities( void );
qboolean S_StreamGetCurrentState( char *currentTrack, size_t currentTrackSize, char *loopTrack, size_t loopTrackSize, int *position );
qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position );
void CL_ServerCommand( qboolean reliable, const char *fmt, ... ) _format( 2 );
void CL_HudMessage( const char *pMessage );
const char *CL_MsgInfo( int cmd );

View File

@@ -465,7 +465,7 @@ static qboolean Cmd_GetSoundList( const char *s, char *completedname, int length
t = FS_Search( va( "%s%s*.*", DEFAULT_SOUNDPATH, s ), true, false );
if( !t ) return false;
Q_strncpy( matchbuf, t->filenames[0] + sizeof( DEFAULT_SOUNDPATH ) - 1, sizeof( matchbuf ));
Q_strncpy( matchbuf, t->filenames[0] + sizeof( DEFAULT_SOUNDPATH ) - 1, MAX_STRING );
COM_StripExtension( matchbuf );
if( completedname && length )
Q_strncpy( completedname, matchbuf, length );
@@ -478,7 +478,7 @@ static qboolean Cmd_GetSoundList( const char *s, char *completedname, int length
if( Q_stricmp( ext, "wav" ) && Q_stricmp( ext, "mp3" ))
continue;
Q_strncpy( matchbuf, t->filenames[i] + sizeof( DEFAULT_SOUNDPATH ) - 1, sizeof( matchbuf ));
Q_strncpy( matchbuf, t->filenames[i] + sizeof( DEFAULT_SOUNDPATH ) - 1, MAX_STRING );
COM_StripExtension( matchbuf );
Con_Printf( "%16s\n", matchbuf );
numsounds++;
@@ -764,14 +764,14 @@ static qboolean Cmd_GetGamesList( const char *s, char *completedname, int length
}
if( !numgamedirs ) return false;
Q_strncpy( matchbuf, gamedirs[0], sizeof( matchbuf ));
Q_strncpy( matchbuf, gamedirs[0], MAX_STRING );
if( completedname && length )
Q_strncpy( completedname, matchbuf, length );
if( numgamedirs == 1 ) return true;
for( i = 0; i < numgamedirs; i++ )
{
Q_strncpy( matchbuf, gamedirs[i], sizeof( matchbuf ));
Q_strncpy( matchbuf, gamedirs[i], MAX_STRING );
Con_Printf( "%16s\n", matchbuf );
}
@@ -825,14 +825,14 @@ static qboolean Cmd_GetCDList( const char *s, char *completedname, int length )
}
if( !numcdcommands ) return false;
Q_strncpy( matchbuf, cdcommands[0], sizeof( matchbuf ));
Q_strncpy( matchbuf, cdcommands[0], MAX_STRING );
if( completedname && length )
Q_strncpy( completedname, matchbuf, length );
if( numcdcommands == 1 ) return true;
for( i = 0; i < numcdcommands; i++ )
{
Q_strncpy( matchbuf, cdcommands[i], sizeof( matchbuf ));
Q_strncpy( matchbuf, cdcommands[i], MAX_STRING );
Con_Printf( "%16s\n", matchbuf );
}
@@ -866,7 +866,7 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
return true; // exist
// setup mpfilter
Q_snprintf( mpfilter, sizeof( mpfilter ), "maps/%s", GI->mp_filter );
size = Q_snprintf( mpfilter, sizeof( mpfilter ), "maps/%s", GI->mp_filter );
t = FS_Search( "maps/*.bsp", false, onlyingamedir );
if( !t )
@@ -900,11 +900,13 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
if( f )
{
qboolean have_spawnpoints = false;
dlump_t entities;
int num_spawnpoints = 0;
dheader_t *header;
dlump_t entities;
memset( buf, 0, MAX_SYSPATH );
FS_Read( f, buf, MAX_SYSPATH );
header = (dheader_t *)buf;
// check all the lumps and some other errors
if( !Mod_TestBmodelLumps( f, t->filenames[i], buf, true, &entities ))
@@ -935,24 +937,13 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
char token[MAX_TOKEN];
qboolean worldspawn = true;
Q_strncpy( message, "No Title", sizeof( message ));
Q_strncpy( message, "No Title", MAX_STRING );
pfile = ents;
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )
{
if( token[0] == '}' && worldspawn )
{
worldspawn = false;
// if mod has mp_filter set up, then it's a mod that
// might not have valid mp_entity set in GI
// if mod is multiplayer only, assume all maps are valid
if( use_filter || GI->gamemode == GAME_MULTIPLAYER_ONLY )
{
have_spawnpoints = true;
break;
}
}
else if( !Q_strcmp( token, "message" ) && worldspawn )
{
// get the message contents
@@ -961,23 +952,17 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
else if( !Q_strcmp( token, "classname" ))
{
pfile = COM_ParseFile( pfile, token, sizeof( token ));
if( !Q_strcmp( token, GI->mp_entity ))
{
have_spawnpoints = true;
break;
}
if( !Q_strcmp( token, GI->mp_entity ) || use_filter )
num_spawnpoints++;
}
if( have_spawnpoints )
break; // valid map
if( num_spawnpoints ) break; // valid map
}
Mem_Free( ents );
}
if( f ) FS_Close( f );
if( have_spawnpoints )
if( num_spawnpoints )
{
// format: mapname "maptitle"\n
Q_snprintf( result, sizeof( result ), "%s \"%s\"\n", mapname, message );

View File

@@ -129,22 +129,6 @@ static void Sys_StackTrace( PEXCEPTION_POINTERS pInfo )
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

View File

@@ -152,10 +152,8 @@ static qboolean Cvar_UpdateInfo( convar_t *var, const char *value, qboolean noti
if ( Host_IsDedicated() )
{
// g-cont. this is a very strange behavior...
char *info = SV_Serverinfo();
Info_SetValueForKey( info, var->name, value, MAX_SERVERINFO_STRING ),
SV_BroadcastCommand( "fullserverinfo \"%s\"\n", info );
Info_SetValueForKey( SV_Serverinfo(), var->name, value, MAX_SERVERINFO_STRING ),
SV_BroadcastCommand( "fullserverinfo \"%s\"\n", SV_Serverinfo( ));
}
#if !XASH_DEDICATED
else
@@ -955,7 +953,7 @@ static void Cvar_SetGL( const char *name, const char *value )
static qboolean Cvar_ShouldSetCvar( convar_t *v, qboolean isPrivileged )
{
const char *prefixes[] = { "cl_", "gl_", "m_", "r_", "hud_", "joy_", "con_", "scr_" };
const char *prefixes[] = { "cl_", "gl_", "m_", "r_", "hud_" };
int i;
if( isPrivileged )

View File

@@ -89,32 +89,32 @@ qboolean FS_LoadProgs( void )
if( !fs_hInstance )
{
Host_Error( "%s: can't load filesystem library %s: %s\n", __func__, name, COM_GetLibraryError() );
Host_Error( "FS_LoadProgs: can't load filesystem library %s: %s\n", name, COM_GetLibraryError() );
return false;
}
if( !( GetFSAPI = (FSAPI)COM_GetProcAddress( fs_hInstance, GET_FS_API )))
{
FS_UnloadProgs();
Host_Error( "%s: can't find GetFSAPI entry point in %s\n", __func__, name );
Host_Error( "FS_LoadProgs: can't find GetFSAPI entry point in %s\n", name );
return false;
}
if( GetFSAPI( FS_API_VERSION, &g_fsapi, &FI, &fs_memfuncs ) != FS_API_VERSION )
if( !GetFSAPI( FS_API_VERSION, &g_fsapi, &FI, &fs_memfuncs ))
{
FS_UnloadProgs();
Host_Error( "%s: can't initialize filesystem API: wrong version\n", __func__ );
Host_Error( "FS_LoadProgs: can't initialize filesystem API: wrong version\n" );
return false;
}
if( !( fs_pfnCreateInterface = (pfnCreateInterface_t)COM_GetProcAddress( fs_hInstance, "CreateInterface" )))
{
FS_UnloadProgs();
Host_Error( "%s: can't find CreateInterface entry point in %s\n", __func__, name );
Host_Error( "FS_LoadProgs: can't find CreateInterface entry point in %s\n", name );
return false;
}
Con_DPrintf( "%s: filesystem_stdio successfully loaded\n", __func__ );
Con_DPrintf( "FS_LoadProgs: filesystem_stdio successfully loaded\n" );
return true;
}

View File

@@ -65,33 +65,6 @@ static CVAR_DEFINE( host_sleeptime, "sleeptime", "1", FCVAR_ARCHIVE|FCVAR_FILTER
static CVAR_DEFINE_AUTO( host_sleeptime_debug, "0", 0, "print sleeps between frames" );
CVAR_DEFINE( con_gamemaps, "con_mapfilter", "1", FCVAR_ARCHIVE, "when true show only maps in game folder" );
typedef struct feature_message_s
{
uint32_t mask;
const char *msg;
const char *arg;
} feature_message_t;
static feature_message_t bugcomp_features[] =
{
{ BUGCOMP_PENTITYOFENTINDEX_FLAG, "pfnPEntityOfEntIndex bugfix revert", "peoei" },
{ BUGCOMP_MESSAGE_REWRITE_FACILITY_FLAG, "GoldSrc Message Rewrite Facility", "gsmrf" },
};
static feature_message_t engine_features[] =
{
{ ENGINE_WRITE_LARGE_COORD, "Big World Support" },
{ ENGINE_QUAKE_COMPATIBLE, "Quake Compatibility" },
{ ENGINE_LOAD_DELUXEDATA, "Deluxemap Support" },
{ ENGINE_PHYSICS_PUSHER_EXT, "Improved MOVETYPE_PUSH" },
{ ENGINE_LARGE_LIGHTMAPS, "Large Lightmaps" },
{ ENGINE_COMPENSATE_QUAKE_BUG, "Stupid Quake Bug Compensation" },
{ ENGINE_IMPROVED_LINETRACE, "Improved Trace Line" },
{ ENGINE_COMPUTE_STUDIO_LERP, "Studio MOVETYPE_STEP Lerping" },
{ ENGINE_LINEAR_GAMMA_SPACE, "Linear Gamma Space" },
{ ENGINE_STEP_POSHISTORY_LERP, "MOVETYPE_STEP Position History Based Lerping" },
};
static void Sys_PrintUsage( void )
{
string version_str;
@@ -119,9 +92,8 @@ static void Sys_PrintUsage( void )
O("-minidumps ", "enable writing minidumps when game is crashed")
#endif
O("-rodir <path> ", "set read-only base directory")
O("-bugcomp [opts] ", "enable precise bug compatibility")
O(" ", "will break games that don't require it")
O(" ", "refer to engine documentation for more info")
O("-bugcomp ", "enable precise bug compatibility. Will break games that don't require it")
O(" ", "Refer to engine documentation for more info")
O("-disablehelp ", "disable this message")
#if !XASH_DEDICATED
O("-dedicated ", "run engine in dedicated mode")
@@ -134,8 +106,7 @@ static void Sys_PrintUsage( void )
O("-noip6 ", "disable IPv6")
O("-ip6 <ip> ", "set IPv6 address")
O("-port6 <port> ", "set IPv6 port")
O("-clockwindow <cw>", "adjust clockwindow used to ignore client commands")
O(" ", "to prevent speed hacks")
O("-clockwindow <cw>", "adjust clockwindow used to ignore client commands to prevent speed hacks")
"\nGame options:\n"
O("-game <directory>", "set game directory to start engine with")
@@ -220,14 +191,31 @@ void Host_ShutdownServer( void )
Host_PrintEngineFeatures
================
*/
static void Host_PrintFeatures( uint32_t flags, const char *s, feature_message_t *features, size_t size )
static void Host_PrintEngineFeatures( int features )
{
size_t i;
for( i = 0; i < size; i++ )
struct
{
if( FBitSet( flags, features[i].mask ))
Con_Printf( "^3%s:^7 %s is enabled\n", s, features[i].msg );
uint32_t mask;
const char *msg;
} features_str[] =
{
{ ENGINE_WRITE_LARGE_COORD, "Big World Support" },
{ ENGINE_QUAKE_COMPATIBLE, "Quake Compatibility" },
{ ENGINE_LOAD_DELUXEDATA, "Deluxemap Support" },
{ ENGINE_PHYSICS_PUSHER_EXT, "Improved MOVETYPE_PUSH" },
{ ENGINE_LARGE_LIGHTMAPS, "Large Lightmaps" },
{ ENGINE_COMPENSATE_QUAKE_BUG, "Stupid Quake Bug Compensation" },
{ ENGINE_IMPROVED_LINETRACE, "Improved Trace Line" },
{ ENGINE_COMPUTE_STUDIO_LERP, "Studio MOVETYPE_STEP Lerping" },
{ ENGINE_LINEAR_GAMMA_SPACE, "Linear Gamma Space" },
{ ENGINE_STEP_POSHISTORY_LERP, "MOVETYPE_STEP Position History Based Lerping" },
};
int i;
for( i = 0; i < ARRAYSIZE( features_str ); i++ )
{
if( FBitSet( features, features_str[i].mask ))
Con_Reportf( "^3EXT:^7 %s is enabled\n", features_str[i].msg );
}
}
@@ -255,7 +243,7 @@ void Host_ValidateEngineFeatures( uint32_t features )
SetBits( features, ENGINE_STEP_POSHISTORY_LERP );
// print requested first
Host_PrintFeatures( features, "EXT", engine_features, ARRAYSIZE( engine_features ));
Host_PrintEngineFeatures( features );
// now warn about incompatible bits
if( FBitSet( features, ENGINE_STEP_POSHISTORY_LERP|ENGINE_COMPUTE_STUDIO_LERP ) == ( ENGINE_STEP_POSHISTORY_LERP|ENGINE_COMPUTE_STUDIO_LERP ))
@@ -865,7 +853,7 @@ void GAME_EXPORT Host_Error( const char *error, ... )
}
recursive = true;
Q_strncpy( hosterror2, hosterror1, sizeof( hosterror2 ));
Q_strncpy( hosterror2, hosterror1, MAX_SYSPATH );
host.errorframe = host.framecount; // to avoid multply calls per frame
Q_snprintf( host.finalmsg, sizeof( host.finalmsg ), "Server crashed: %s", hosterror1 );
@@ -951,59 +939,11 @@ static void Host_RunTests( int stage )
TEST_LIST_1_CLIENT;
#endif
Msg( "Done! %d passed, %d failed\n", tests_stats.passed, tests_stats.failed );
error_on_exit = tests_stats.failed > 0 ? EXIT_FAILURE : EXIT_SUCCESS;
Sys_Quit();
}
}
#endif
static uint32_t Host_CheckBugcomp( void )
{
const char *prev, *next;
uint32_t flags = 0;
string args, arg;
size_t i;
if( !Sys_CheckParm( "-bugcomp" ))
return 0;
if( Sys_GetParmFromCmdLine( "-bugcomp", args ) && isalpha( args[0] ))
{
for( prev = args, next = Q_strchrnul( prev, '+' ); ; prev = next + 1, next = Q_strchrnul( prev, '+' ))
{
Q_strncpy( arg, prev, next - prev + 1 );
for( i = 0; i < ARRAYSIZE( bugcomp_features ); i++ )
{
if( !Q_stricmp( bugcomp_features[i].arg, arg ))
{
SetBits( flags, bugcomp_features[i].mask );
break;
}
}
if( i == ARRAYSIZE( bugcomp_features ))
{
Con_Printf( S_ERROR "Unknown bugcomp flag %s\n", arg );
Con_Printf( "Valid flags are:\n" );
for( i = 0; i < ARRAYSIZE( bugcomp_features ); i++ )
Con_Printf( "\t%s: %s\n", bugcomp_features[i].arg, bugcomp_features[i].msg );
}
if( !*next )
break;
}
}
else
{
// no argument specified -bugcomp just enables everything
flags = -1;
}
Host_PrintFeatures( flags, "BUGCOMP", bugcomp_features, ARRAYSIZE( bugcomp_features ));
return flags;
}
/*
=================
Host_InitCommon
@@ -1108,6 +1048,13 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
// member console allowing
host.allow_console_init = host.allow_console;
if( Sys_CheckParm( "-bugcomp" ))
{
// add argument check here when we add other levels
// of bugcompatibility
host.bugcomp = BUGCOMP_GOLDSRC;
}
// timeBeginPeriod( 1 ); // a1ba: Do we need this?
// NOTE: this message couldn't be passed into game console but it doesn't matter
@@ -1234,11 +1181,11 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
Sys_InitLog();
// print current developer level to simplify processing users feedback
if( developer > 0 )
Con_Printf( "Developer level: ^3%i\n", developer );
host.bugcomp = Host_CheckBugcomp();
// print bugcompatibility level here, after log was initialized
if( host.bugcomp == BUGCOMP_GOLDSRC )
{
Con_Printf( "^3BUGCOMP^7: GoldSrc bug-compatibility enabled\n" );
}
Cmd_AddCommand( "exec", Host_Exec_f, "execute a script file" );
Cmd_AddCommand( "memlist", Host_MemStats_f, "prints memory pool information" );
@@ -1422,11 +1369,7 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
host.status = HOST_FRAME;
if( GameState->nextstate == STATE_RUNFRAME )
#if XASH_WIN32 // FIXME: implement autocomplete on *nix
Con_Printf( "Type 'map <mapname>' to start game... (TAB-autocomplete is working too)\n" );
#else // !XASH_WIN32
Con_Printf( "Type 'map <mapname>' to start game...\n" );
#endif // !XASH_WIN32
// execute server.cfg after commandline
// so we have a chance to set servercfgfile

View File

@@ -400,8 +400,7 @@ static qboolean HPAK_Validate( const char *filename, qboolean quiet, qboolean de
f = FS_Open( pakname, "rb", true );
if( !f )
{
if( !quiet )
Con_DPrintf( S_ERROR "Couldn't find %s.\n", pakname );
Con_DPrintf( S_ERROR "Couldn't find %s.\n", pakname );
return true;
}

View File

@@ -390,7 +390,7 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, fs_offset_t filesi
if( Q_strrchr( name, '{' ))
{
// NOTE: decals with 'blue base' can be interpret as colored decals
if( !Image_CheckFlag( IL_LOAD_DECAL ) || ( pal && pal[765] == 0 && pal[766] == 0 && pal[767] == 255 ))
if( !Image_CheckFlag( IL_LOAD_DECAL ) || ( pal[765] == 0 && pal[766] == 0 && pal[767] == 255 ))
{
SetBits( image.flags, IMAGE_ONEBIT_ALPHA );
rendermode = LUMP_MASKED;
@@ -488,40 +488,37 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, fs_offset_t filesi
}
// check for half-life water texture
if( pal != NULL )
if( hl_texture && ( mip.name[0] == '!' || !Q_strnicmp( mip.name, "water", 5 )))
{
if( hl_texture && ( mip.name[0] == '!' || !Q_strnicmp( mip.name, "water", 5 )))
{
// grab the fog color
image.fogParams[0] = pal[3*3+0];
image.fogParams[1] = pal[3*3+1];
image.fogParams[2] = pal[3*3+2];
// grab the fog color
image.fogParams[0] = pal[3*3+0];
image.fogParams[1] = pal[3*3+1];
image.fogParams[2] = pal[3*3+2];
// grab the fog density
image.fogParams[3] = pal[4*3+0];
}
else if( hl_texture && ( rendermode == LUMP_GRADIENT ))
{
// grab the decal color
image.fogParams[0] = pal[255*3+0];
image.fogParams[1] = pal[255*3+1];
image.fogParams[2] = pal[255*3+2];
// grab the fog density
image.fogParams[3] = pal[4*3+0];
}
else if( hl_texture && ( rendermode == LUMP_GRADIENT ))
{
// grab the decal color
image.fogParams[0] = pal[255*3+0];
image.fogParams[1] = pal[255*3+1];
image.fogParams[2] = pal[255*3+2];
// calc the decal reflectivity
image.fogParams[3] = VectorAvg( image.fogParams );
}
else
// calc the decal reflectivity
image.fogParams[3] = VectorAvg( image.fogParams );
}
else if( pal != NULL )
{
// calc texture reflectivity
for( i = 0; i < 256; i++ )
{
// calc texture reflectivity
for( i = 0; i < 256; i++ )
{
reflectivity[0] += pal[i*3+0];
reflectivity[1] += pal[i*3+1];
reflectivity[2] += pal[i*3+2];
}
VectorDivide( reflectivity, 256, image.fogParams );
reflectivity[0] += pal[i*3+0];
reflectivity[1] += pal[i*3+1];
reflectivity[2] += pal[i*3+2];
}
VectorDivide( reflectivity, 256, image.fogParams );
}
image.type = PF_INDEXED_32; // 32-bit palete

View File

@@ -24,8 +24,7 @@ typedef struct dll_user_s
qboolean custom_loader; // a bit who indicated loader type
qboolean encrypted; // dll is crypted (some client.dll in HL, CS etc)
char dllName[32]; // for debug messages
char fullPath[2048];
string shortPath; // actual dll paths
string fullPath, shortPath; // actual dll paths
// ordinals stuff, valid only on Win32
word *ordinals;

View File

@@ -118,7 +118,7 @@ static void NET_AnnounceToMaster( master_t *m )
MSG_WriteBytes( &msg, "q\xFF", 2 );
MSG_WriteDword( &msg, m->heartbeat_challenge );
NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &msg ), MSG_GetData( &msg ), m->adr );
NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &msg ), MSG_GetBuf( &msg ), m->adr );
if( sv_verbose_heartbeats.value )
{
@@ -262,7 +262,7 @@ static void NET_AddMaster( const char *addr, qboolean save )
}
master = Mem_Malloc( host.mempool, sizeof( master_t ) );
Q_strncpy( master->address, addr, sizeof( master->address ));
Q_strncpy( master->address, addr, MAX_STRING );
master->sent = false;
master->save = save;
master->next = NULL;

View File

@@ -24,9 +24,6 @@ GNU General Public License for more details.
#include "client.h"
#include "server.h" // LUMP_ error codes
#include "ref_common.h"
#if defined( HAVE_OPENMP )
#include <omp.h>
#endif // HAVE_OPENMP
#define MIPTEX_CUSTOM_PALETTE_SIZE_BYTES ( sizeof( int16_t ) + 768 )
@@ -581,42 +578,6 @@ void Mod_PrintWorldStats_f( void )
===============================================================================
*/
/*
===================
Mod_DecompressPVS
TODO: replace all Mod_DecompressPVS calls by this
===================
*/
static void Mod_DecompressPVSTo( byte *const out, const byte *in, size_t visbytes )
{
byte *dst = out;
if( !in ) // no visinfo, make all visible
{
memset( out, 0xFF, visbytes );
return;
}
while( dst < out + visbytes )
{
if( *in ) // uncompressed
{
*dst++ = *in++;
}
else // zero repeated `c` times
{
size_t c = in[1];
if( c > out + visbytes - dst )
c = out + visbytes - dst;
memset( dst, 0, c );
in += 2;
dst += c;
}
}
}
/*
===================
Mod_DecompressPVS
@@ -624,36 +585,41 @@ Mod_DecompressPVS
*/
static byte *Mod_DecompressPVS( const byte *in, int visbytes )
{
Mod_DecompressPVSTo( g_visdata, in, visbytes );
return g_visdata;
}
byte *out;
int c;
static size_t Mod_CompressPVS( byte *const out, const byte *in, size_t inbytes )
{
size_t i;
byte *dst = out;
out = g_visdata;
for( i = 0; i < inbytes; i++ )
if( !in )
{
size_t j = i + 1, rep = 1;
*dst++ = in[i];
// only compress zeros
if( in[i] )
continue;
for( ; j < inbytes && rep != 255; j++, rep++ )
// no vis info, so make all visible
while( visbytes )
{
if( in[j] )
break;
*out++ = 0xff;
visbytes--;
}
*dst++ = rep;
i = j - 1;
return g_visdata;
}
return dst - out;
do
{
if( *in )
{
*out++ = *in++;
continue;
}
c = in[1];
in += 2;
while( c )
{
*out++ = 0;
c--;
}
} while( out - g_visdata < visbytes );
return g_visdata;
}
/*
@@ -687,11 +653,22 @@ NOTE: can return NULL
*/
byte *Mod_GetPVSForPoint( const vec3_t p )
{
mleaf_t *leaf;
mnode_t *node;
mleaf_t *leaf = NULL;
ASSERT( worldmodel != NULL );
leaf = Mod_PointInLeaf( p, worldmodel->nodes );
node = worldmodel->nodes;
while( 1 )
{
if( node->contents < 0 )
{
leaf = (mleaf_t *)node;
break; // we found a leaf
}
node = node->children[PlaneDiff( p, node->plane ) <= 0];
}
if( leaf && leaf->cluster >= 0 )
return Mod_DecompressPVS( leaf->compressed_vis, world.visbytes );
@@ -704,7 +681,7 @@ Mod_FatPVS_RecursiveBSPNode
==================
*/
static void Mod_FatPVS_RecursiveBSPNode( const vec3_t org, float radius, byte *visbuffer, int visbytes, mnode_t *node, qboolean phs )
static void Mod_FatPVS_RecursiveBSPNode( const vec3_t org, float radius, byte *visbuffer, int visbytes, mnode_t *node )
{
int i;
@@ -719,7 +696,7 @@ static void Mod_FatPVS_RecursiveBSPNode( const vec3_t org, float radius, byte *v
else
{
// go down both sides
Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, visbytes, node->children[0], phs );
Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, visbytes, node->children[0] );
node = node->children[1];
}
}
@@ -727,19 +704,10 @@ static void Mod_FatPVS_RecursiveBSPNode( const vec3_t org, float radius, byte *v
// if this leaf is in a cluster, accumulate the vis bits
if(((mleaf_t *)node)->cluster >= 0 )
{
byte *vis;
byte *vis = Mod_DecompressPVS( ((mleaf_t *)node)->compressed_vis, world.visbytes );
if( phs )
{
int i = ((mleaf_t *)node)->cluster + 1;
vis = Mod_DecompressPVS( &world.compressed_phs[world.phsofs[i]], world.visbytes );
}
else
{
vis = Mod_DecompressPVS( ((mleaf_t *)node)->compressed_vis, world.visbytes );
}
Q_memor( visbuffer, vis, visbytes );
for( i = 0; i < visbytes; i++ )
visbuffer[i] |= vis[i];
}
}
@@ -751,7 +719,7 @@ Calculates a PVS that is the inclusive or of all leafs
within radius pixels of the given point.
==================
*/
int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis, qboolean phs )
int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis )
{
int bytes = world.visbytes;
mleaf_t *leaf = NULL;
@@ -768,17 +736,9 @@ int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, q
return bytes;
}
// requested PHS but we don't have PHS for some reason
// enable full visibility
if( phs && !( world.compressed_phs && world.phsofs ))
{
memset( visbuffer, 0xFF, bytes );
return bytes;
}
if( !merge ) memset( visbuffer, 0x00, bytes );
Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, bytes, worldmodel->nodes, phs );
Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, bytes, worldmodel->nodes );
return bytes;
}
@@ -1863,8 +1823,8 @@ static void Mod_LoadEntities( model_t *mod, dbspmodel_t *bmod )
{
char *pszWadFile;
Q_strncpy( wadstring, token, sizeof( wadstring ) - 2 );
wadstring[sizeof( wadstring ) - 2] = 0;
Q_strncpy( wadstring, token, MAX_TOKEN - 2 );
wadstring[MAX_TOKEN - 2] = 0;
if( !Q_strchr( wadstring, ';' ))
Q_strncat( wadstring, ";", sizeof( wadstring ));
@@ -1875,7 +1835,7 @@ static void Mod_LoadEntities( model_t *mod, dbspmodel_t *bmod )
COM_FixSlashes( pszWadFile );
COM_FileBase( pszWadFile, token, sizeof( token ));
// make sure that wad is really exist
// make sure what wad is really exist
if( FS_FileExists( va( "%s.wad", token ), false ))
{
int num = bmod->wadlist.count++;
@@ -2066,18 +2026,28 @@ static qboolean Mod_LooksLikeWaterTexture( const char *name )
return false;
}
static qboolean Mod_LooksLikeReflectiveTexture( const char *name )
{
if( !Q_strcmp( name, "reflect1" ) || !Q_strncmp( name, "!reflect", 8 ))
return true;
return false;
}
static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureIndex )
{
#if !XASH_DEDICATED
texture_t *texture = NULL;
mip_t *mipTex = NULL;
qboolean usesCustomPalette = false;
uint32_t txFlags = 0;
// don't load texture data on dedicated server, as there is no renderer.
// but count the wadusage for automatic precache
//
// Don't load texture data on dedicated server, as there is no renderer.
// FIXME: for ENGINE_IMPROVED_LINETRACE we need to load textures on server too
// but there is no facility for this yet
if( Host_IsDedicated( ))
return;
texture = mod->textures[textureIndex];
mipTex = Mod_GetMipTexForTexture( bmod, textureIndex );
@@ -2093,15 +2063,10 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
// check for multi-layered sky texture (quake1 specific)
if( bmod->isworld && Q_strncmp( mipTex->name, "sky", 3 ) == 0 && ( mipTex->width / mipTex->height ) == 2 )
{
#if !XASH_DEDICATED
if( !Host_IsDedicated( ))
{
ref.dllFuncs.R_InitSkyClouds( mipTex, texture, usesCustomPalette ); // load quake sky
ref.dllFuncs.R_InitSkyClouds( mipTex, texture, usesCustomPalette ); // load quake sky
if( R_GetBuiltinTexture( REF_SOLIDSKY_TEXTURE ) && R_GetBuiltinTexture( REF_ALPHASKY_TEXTURE ))
SetBits( world.flags, FWORLD_SKYSPHERE );
}
#endif // !XASH_DEDICATED
if( R_GetBuiltinTexture( REF_SOLIDSKY_TEXTURE ) && R_GetBuiltinTexture( REF_ALPHASKY_TEXTURE ))
SetBits( world.flags, FWORLD_SKYSPHERE );
// No texture to load in this case, so just exit.
return;
@@ -2119,18 +2084,11 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
if( wadIndex >= 0 )
{
#if !XASH_DEDICATED
if( !Host_IsDedicated( ))
texture->gl_texturenum = ref.dllFuncs.GL_LoadTexture( texpath, NULL, 0, txFlags );
#endif // !XASH_DEDICATED
texture->gl_texturenum = ref.dllFuncs.GL_LoadTexture( texpath, NULL, 0, txFlags );
bmod->wadlist.wadusage[wadIndex]++;
}
}
#if !XASH_DEDICATED
if( Host_IsDedicated( ))
return;
// WAD failed, so use internal texture (if present)
if( mipTex->offsets[0] > 0 && texture->gl_texturenum == 0 )
{
@@ -2530,6 +2488,13 @@ static void Mod_LoadSurfaces( model_t *mod, dbspmodel_t *bmod )
if( !Q_strncmp( tex->name, "{scroll", 7 ))
SetBits( out->flags, SURF_CONVEYOR|SURF_TRANSPARENT );
// some mods don't work with mirrors or make random surfaces reflective
if( FBitSet( host.features, ENGINE_ALLOW_MIRRORS ) && Mod_LooksLikeReflectiveTexture( tex->name ))
{
SetBits( world.flags, FWORLD_HAS_MIRRORS );
SetBits( out->flags, SURF_REFLECT );
}
if( tex->name[0] == '{' )
SetBits( out->flags, SURF_TRANSPARENT );
@@ -2747,6 +2712,9 @@ static void Mod_LoadLeafs( model_t *mod, dbspmodel_t *bmod )
{
// mark underwater surfaces
SetBits( out->firstmarksurface[j]->flags, SURF_UNDERWATER );
// underwater surfaces can't have reflection (performance)
ClearBits( out->firstmarksurface[j]->flags, SURF_REFLECT );
}
}
}
@@ -2759,153 +2727,6 @@ static void Mod_LoadLeafs( model_t *mod, dbspmodel_t *bmod )
SetBits( world.flags, FWORLD_WATERALPHA );
}
/*
===========
Mod_CalcPHS
To be called while loading world for multiplayer game server
===========
*/
static void Mod_CalcPHS( model_t *mod )
{
const qboolean vis_stats = host_developer.value >= DEV_EXTENDED;
const size_t rowbytes = ALIGN( world.visbytes, 4 ); // force align rows by 32-bit boundary
const size_t count = mod->numleafs + 1; // same as mod->submodels[0].visleafs + 1
double t1;
double t2;
size_t total_compressed_size = 0;
size_t hcount = 0;
size_t vcount = 0;
int i;
byte *uncompressed_pvs;
byte *uncompressed_phs;
if( !mod->visdata )
return;
#if defined( HAVE_OPENMP )
Con_Reportf( "Building PHS in %d threads...\n", omp_get_max_threads( ));
#else
Con_Reportf( "Building PHS...\n" );
#endif
uncompressed_pvs = Mem_Calloc( mod->mempool, rowbytes * count * 2 );
uncompressed_phs = &uncompressed_pvs[rowbytes * count];
world.phsofs = Mem_Calloc( mod->mempool, sizeof( size_t ) * count );
world.compressed_phs = NULL;
t1 = Platform_DoubleTime();
#pragma omp parallel
{
// uncompress pvs first
#pragma omp for schedule( static, 256 ) // there might be thousands of leafs, split by 256
for( i = 0; i < count; i++ )
Mod_DecompressPVSTo( &uncompressed_pvs[rowbytes * i], mod->leafs[i].compressed_vis, world.visbytes );
// now create phs
#pragma omp for schedule( static, 256 ) reduction( + : vcount, hcount )
for( i = 0; i < count; i++ )
{
const byte *scan = &uncompressed_pvs[rowbytes * i];
byte *dst = &uncompressed_phs[rowbytes * i]; // rowbytes, not rowwords!
size_t j;
memcpy( dst, scan, rowbytes );
for( j = 0; j < rowbytes; j++ )
{
size_t k;
uint bitbyte = scan[j];
if( bitbyte == 0 )
continue;
for( k = 0; k < 8; k++ )
{
size_t index;
if( !FBitSet( bitbyte, BIT( k )))
continue;
// OR this pvs row into the phs
// +1 because pvs is 1 based
index = (( j * 8 ) + k + 1 );
if( index >= count )
continue;
Q_memor( dst, &uncompressed_pvs[rowbytes * index], rowbytes );
}
}
if( vis_stats && i != 0 )
{
size_t j;
for( j = 0; j < count; j++ )
{
if( CHECKVISBIT( scan, j ))
vcount++;
if( CHECKVISBIT( dst, j ))
hcount++;
}
}
}
}
// since I can't predict at which spot compressed array
// should be put, this loop is single threaded
for( i = 0; i < count; i++ )
{
const byte *src = &uncompressed_phs[rowbytes * i];
byte temp_compressed_row[(MAX_MAP_LEAFS+1)/4]; // compression for this row might be ineffective
size_t compressed_size;
compressed_size = Mod_CompressPVS( temp_compressed_row, src, rowbytes );
world.compressed_phs = Mem_Realloc( mod->mempool, world.compressed_phs, total_compressed_size + compressed_size );
memcpy( &world.compressed_phs[total_compressed_size], temp_compressed_row, compressed_size );
world.phsofs[i] = total_compressed_size;
total_compressed_size += compressed_size;
}
t2 = Platform_DoubleTime();
if( vis_stats )
Con_Reportf( "Average leaves visible / audible / total: %i / %i / %i\n", vcount / count, hcount / count, count );
Con_Reportf( "Uncompressed PHS size: %s\n", Q_memprint( rowbytes * count ));
Con_Reportf( "Compressed PHS size: %s\n", Q_memprint( total_compressed_size + sizeof( *world.phsofs ) * count ));
Con_Reportf( "PHS building time: %.2f ms\n", ( t2 - t1 ) * 1000.0f );
// TODO: rewrite this into a unit test
// NOTE: how to get GoldSrc fat PHS and PVS data
// start a multiplayer server with some op4_bootcamp (for example)
// attach to process with GDB:
// (gdb) p gPAS[0]
// $0 = (byte *) ...
// (gdb) p gPAS[gPVSRowBytes * (cl.worldmodel->numleafs + 1)]
// $1 = (byte *) ...
// (gdb) dump binary memory op4_bootcamp_gs.phs $0 $1
// (gdb) p gPVS[0]
// $2 = (byte *) ...
// (gdb) p gPVS[gPVSRowBytes * (cl.worldmodel->numleafs + 1)]
// $3 = (byte *) ...
// (gdb) dump binary memory op4_bootcamp_gs.pvs $0 $1
//
// NOTE: as of writing, uncompressed PVS and PHS data do match! hooray!
//
// FS_WriteFile( "op4_bootcamp.pvs", uncompressed_pvs, rowbytes * count );
// FS_WriteFile( "op4_bootcamp.phs", uncompressed_phs, rowbytes * count );
// release uncompressed data
Mem_Free( uncompressed_pvs );
// TODO: cache the PHS somewhere, it might take a long time on giant maps
}
/*
=================
Mod_LoadClipnodes
@@ -3103,7 +2924,6 @@ static qboolean Mod_LoadBmodelLumps( model_t *mod, const byte *mod_base, qboolea
char wadvalue[2048];
size_t len = 0;
int i, ret, flags = 0;
qboolean wadlist_warn = false;
// always reset the intermediate struct
memset( bmod, 0, sizeof( dbspmodel_t ));
@@ -3198,37 +3018,23 @@ static qboolean Mod_LoadBmodelLumps( model_t *mod, const byte *mod_base, qboolea
{
world.version = bmod->version;
#if !XASH_DEDICATED
Mod_InitDebugHulls( mod ); // FIXME: build hulls for separate bmodels (shells, medkits etc)
world.deluxedata = bmod->deluxedata_out; // deluxemap data pointer
world.shadowdata = bmod->shadowdata_out; // occlusion data pointer
#endif // XASH_DEDICATED
if( SV_Active() && svs.maxclients > 1 )
Mod_CalcPHS( mod );
}
for( i = 0; i < bmod->wadlist.count; i++ )
{
string wadname;
if( !bmod->wadlist.wadusage[i] )
continue;
Q_snprintf( wadname, sizeof( wadname ), "%s.wad", bmod->wadlist.wadnames[i] );
// a1ba: automatically precache used wad files so client will download it
if( SV_Active( ))
SV_GenericIndex( wadname );
if( !wadlist_warn )
ret = Q_snprintf( &wadvalue[len], sizeof( wadvalue ), "%s.wad; ", bmod->wadlist.wadnames[i] );
if( ret == -1 )
{
ret = Q_snprintf( &wadvalue[len], sizeof( wadvalue ), "%s; ", wadname );
if( ret == -1 )
{
Con_DPrintf( S_WARN "Too many wad files for output!\n" );
wadlist_warn = true;
}
len += ret;
Con_DPrintf( S_WARN "Too many wad files for output!\n" );
break;
}
len += ret;
}
if( COM_CheckString( wadvalue ))

View File

@@ -33,7 +33,7 @@ GNU General Public License for more details.
#define REFPVS_RADIUS 2.0f // radius for rendering
#define FATPVS_RADIUS 8.0f // FatPVS use radius smaller than the FatPHS
#define FATPHS_RADIUS 8.0f // see SV_AddToFatPAS in GoldSrc
#define FATPHS_RADIUS 16.0f
#define WORLD_INDEX (1) // world index is always 1
@@ -115,10 +115,6 @@ typedef struct world_static_s
int max_recursion;
uint32_t version; // BSP version
// Potentially Hearable Set
byte *compressed_phs;
size_t *phsofs;
} world_static_t;
#ifndef REF_DLL
@@ -155,7 +151,7 @@ void Mod_FreeUnused( void );
void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *loaded );
qboolean Mod_TestBmodelLumps( file_t *f, const char *name, const byte *mod_base, qboolean silent, dlump_t *entities );
qboolean Mod_HeadnodeVisible( mnode_t *node, const byte *visbits, int *lastleaf );
int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis, qboolean false );
int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis );
qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbits );
int Mod_CheckLump( const char *filename, const int lump, int *lumpsize );
int Mod_ReadLump( const char *filename, const int lump, void **lumpdata, int *lumpsize );

View File

@@ -780,7 +780,7 @@ extract texture filename from modelname
*/
const char *Mod_StudioTexName( const char *modname )
{
static char texname[MAX_QPATH+1];
static char texname[MAX_QPATH];
Q_strncpy( texname, modname, sizeof( texname ));
COM_StripExtension( texname );
@@ -841,22 +841,6 @@ static studiohdr_t *R_StudioLoadHeader( model_t *mod, const void *buffer )
return (studiohdr_t *)buffer;
}
static studiohdr_t *Mod_MaybeTruncateStudioTextureData( model_t *mod )
{
#if XASH_LOW_MEMORY
studiohdr_t *phdr = (studiohdr_t *)mod->cache.data;
mod->cache.data = Mem_Realloc( mod->mempool, mod->cache.data, phdr->texturedataindex );
phdr = (studiohdr_t *)mod->cache.data; // get the new pointer on studiohdr
phdr->length = phdr->texturedataindex; // update model size
return phdr;
#else
// NOTE: some mods potentially might require full studio model data
return (studiohdr_t *)mod->cache.data;
#endif
}
/*
=================
Mod_LoadStudioModel
@@ -876,62 +860,73 @@ void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded )
phdr = R_StudioLoadHeader( mod, buffer );
if( !phdr ) return; // bad model
if( !Host_IsDedicated( ) && phdr->numtextures == 0 )
if( !Host_IsDedicated() )
{
studiohdr_t *thdr;
void *buffer2;
buffer2 = FS_LoadFile( Mod_StudioTexName( mod->name ), NULL, false );
thdr = R_StudioLoadHeader( mod, buffer2 );
if( thdr != NULL )
if( phdr->numtextures == 0 )
{
byte *in, *out;
size_t size1, size2;
studiohdr_t *thdr;
byte *in, *out;
void *buffer2 = NULL;
size_t size1, size2;
buffer2 = FS_LoadFile( Mod_StudioTexName( mod->name ), NULL, false );
thdr = R_StudioLoadHeader( mod, buffer2 );
if( !thdr )
{
Con_Printf( S_WARN "Mod_LoadStudioModel: %s missing textures file\n", mod->name );
if( buffer2 ) Mem_Free( buffer2 );
}
else
{
#if !XASH_DEDICATED
// TODO: Mod_StudioLoadTextures will crash if passed a merged studio model!
ref.dllFuncs.Mod_StudioLoadTextures( mod, thdr );
ref.dllFuncs.Mod_StudioLoadTextures( mod, thdr );
#endif
// give space for textures and skinrefs
size1 = thdr->numtextures * sizeof( mstudiotexture_t );
size2 = thdr->numskinfamilies * thdr->numskinref * sizeof( short );
mod->cache.data = Mem_Calloc( mod->mempool, phdr->length + size1 + size2 );
memcpy( mod->cache.data, buffer, phdr->length ); // copy main mdl buffer
phdr = (studiohdr_t *)mod->cache.data; // get the new pointer on studiohdr
phdr->numskinfamilies = thdr->numskinfamilies;
phdr->numtextures = thdr->numtextures;
phdr->numskinref = thdr->numskinref;
phdr->textureindex = phdr->length;
phdr->skinindex = phdr->textureindex + size1;
// give space for textures and skinrefs
size1 = thdr->numtextures * sizeof( mstudiotexture_t );
size2 = thdr->numskinfamilies * thdr->numskinref * sizeof( short );
mod->cache.data = Mem_Calloc( mod->mempool, phdr->length + size1 + size2 );
memcpy( mod->cache.data, buffer, phdr->length ); // copy main mdl buffer
phdr = (studiohdr_t *)mod->cache.data; // get the new pointer on studiohdr
phdr->numskinfamilies = thdr->numskinfamilies;
phdr->numtextures = thdr->numtextures;
phdr->numskinref = thdr->numskinref;
phdr->textureindex = phdr->length;
phdr->skinindex = phdr->textureindex + size1;
in = (byte *)thdr + thdr->textureindex;
out = (byte *)phdr + phdr->textureindex;
memcpy( out, in, size1 + size2 ); // copy textures + skinrefs
phdr->length += size1 + size2;
in = (byte *)thdr + thdr->textureindex;
out = (byte *)phdr + phdr->textureindex;
memcpy( out, in, size1 + size2 ); // copy textures + skinrefs
phdr->length += size1 + size2;
Mem_Free( buffer2 ); // release T.mdl
}
}
else Con_Printf( S_WARN "%s: %s missing textures file\n", __func__, mod->name );
else
{
// NOTE: don't modify source buffer because it's used for CRC computing
mod->cache.data = Mem_Calloc( mod->mempool, phdr->length );
memcpy( mod->cache.data, buffer, phdr->length );
phdr = (studiohdr_t *)mod->cache.data; // get the new pointer on studiohdr
#if !XASH_DEDICATED
ref.dllFuncs.Mod_StudioLoadTextures( mod, phdr );
#endif
if( buffer2 )
Mem_Free( buffer2 ); // release T.mdl
// NOTE: we wan't keep raw textures in memory. just cutoff model pointer above texture base
mod->cache.data = Mem_Realloc( mod->mempool, mod->cache.data, phdr->texturedataindex );
phdr = (studiohdr_t *)mod->cache.data; // get the new pointer on studiohdr
phdr->length = phdr->texturedataindex; // update model size
}
}
else
{
// NOTE: don't modify source buffer because it's used for CRC computing
// just copy model into memory
mod->cache.data = Mem_Calloc( mod->mempool, phdr->length );
memcpy( mod->cache.data, buffer, phdr->length );
phdr = mod->cache.data;
#if !XASH_DEDICATED
if( !Host_IsDedicated( ))
ref.dllFuncs.Mod_StudioLoadTextures( mod, phdr );
#endif
}
// NOTE: we may not want to keep raw textures in memory. just cutoff model pointer above texture base
phdr = Mod_MaybeTruncateStudioTextureData( mod );
// setup bounding box
if( !VectorCompare( vec3_origin, phdr->bbmin ))
{

View File

@@ -114,11 +114,6 @@ void Mod_FreeModel( model_t *mod )
world.version = 0;
world.shadowdata = NULL;
world.deluxedata = NULL;
// data already freed by Mem_FreePool above
world.hull_models = NULL;
world.compressed_phs = NULL;
world.phsofs = NULL;
}
memset( mod, 0, sizeof( *mod ));

View File

@@ -89,36 +89,6 @@ const char *svc_strings[svc_lastmsg+1] =
"svc_exec",
};
const char *svc_legacy_strings[svc_lastmsg+1] =
{
[svc_legacy_changing] = "svc_legacy_changing",
[svc_legacy_ambientsound] = "svc_legacy_ambientsound",
[svc_legacy_soundindex] = "svc_legacy_soundindex",
[svc_legacy_ambientsound] = "svc_legacy_ambientsound",
[svc_legacy_modelindex] = "svc_legacy_modelindex",
[svc_legacy_eventindex] = "svc_legacy_eventindex",
[svc_legacy_chokecount] = "svc_legacy_chokecount",
};
const char *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",
};
void MSG_InitMasks( void )
{
uint startbit, endbit;
@@ -139,6 +109,85 @@ void MSG_InitMasks( void )
ExtraMasks[maskBit] = (uint)BIT( maskBit ) - 1;
}
void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nMaxBits )
{
MSG_StartWriting( sb, pData, nBytes, 0, nMaxBits );
sb->pDebugName = pDebugName;
}
void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits )
{
// make sure it's dword aligned and padded.
Assert(((uint32_t)pData & 3 ) == 0 );
sb->pDebugName = "Unnamed";
sb->pData = (byte *)pData;
if( nBits == -1 )
{
sb->nDataBits = nBytes << 3;
}
else
{
Assert( nBits <= nBytes * 8 );
sb->nDataBits = nBits;
}
sb->iCurBit = iStartBit;
sb->bOverflow = false;
}
/*
=======================
MSG_Clear
for clearing overflowed buffer
=======================
*/
void MSG_Clear( sizebuf_t *sb )
{
sb->iCurBit = 0;
sb->bOverflow = false;
}
static qboolean MSG_Overflow( sizebuf_t *sb, int nBits )
{
if( sb->iCurBit + nBits > sb->nDataBits )
sb->bOverflow = true;
return sb->bOverflow;
}
qboolean MSG_CheckOverflow( sizebuf_t *sb )
{
return MSG_Overflow( sb, 0 );
}
int MSG_SeekToBit( sizebuf_t *sb, int bitPos, int whence )
{
// compute the file offset
switch( whence )
{
case SEEK_CUR:
bitPos += sb->iCurBit;
break;
case SEEK_SET:
break;
case SEEK_END:
bitPos += sb->nDataBits;
break;
default:
return -1;
}
if( bitPos < 0 || bitPos > sb->nDataBits )
return -1;
sb->iCurBit = bitPos;
return 0;
}
void MSG_WriteOneBit( sizebuf_t *sb, int nValue )
{
if( !MSG_Overflow( sb, 1 ))
@@ -620,7 +669,7 @@ qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes )
return MSG_ReadBits( sb, pOut, nBytes << 3 );
}
static char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
{
static char string[4096];
int l = 0, c;
@@ -646,16 +695,6 @@ static char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
return string;
}
char *MSG_ReadString( sizebuf_t *sb )
{
return MSG_ReadStringExt( sb, false );
}
char *MSG_ReadStringLine( sizebuf_t *sb )
{
return MSG_ReadStringExt( sb, true );
}
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove )
{
int i, endbit = startbit + bitstoremove;

View File

@@ -30,128 +30,39 @@ GNU General Public License for more details.
// So PAD_NUMBER(0,4) is 0 and PAD_NUMBER(1,4) is 4
#define PAD_NUMBER( num, boundary ) ((( num ) + (( boundary ) - 1 )) / ( boundary )) * ( boundary )
static inline int BitByte( int bits )
_inline int BitByte( int bits )
{
return PAD_NUMBER( bits, 8 ) >> 3;
}
struct sizebuf_s
{
byte *pData;
qboolean bOverflow; // overflow reading or writing
int iCurBit;
int nDataBits;
const char *pDebugName; // buffer name (pointer to const name)
qboolean bOverflow; // overflow reading or writing
const char *pDebugName; // buffer name (pointer to const name)
byte *pData;
int iCurBit;
int nDataBits;
};
#define MSG_StartReading MSG_StartWriting
#define MSG_GetNumBytesRead MSG_GetNumBytesWritten
#define MSG_GetRealBytesRead MSG_GetRealBytesWritten
#define MSG_GetNumBitsRead MSG_GetNumBitsWritten
#define MSG_ReadBitAngles MSG_ReadBitVec3Coord
#define MSG_ReadAngle( sb ) (float)( MSG_ReadChar( sb ) * ( 360.0f / 256.0f ))
#define MSG_Init( sb, name, data, bytes ) MSG_InitExt( sb, name, data, bytes, -1 )
#define MSG_CheckOverflow( sb ) MSG_Overflow( sb, 0 )
#define MSG_StartReading MSG_StartWriting
#define MSG_GetNumBytesRead MSG_GetNumBytesWritten
#define MSG_GetRealBytesRead MSG_GetRealBytesWritten
#define MSG_GetNumBitsRead MSG_GetNumBitsWritten
#define MSG_ReadBitAngles MSG_ReadBitVec3Coord
#define MSG_ReadString( sb ) MSG_ReadStringExt( sb, false )
#define MSG_ReadStringLine( sb ) MSG_ReadStringExt( sb, true )
#define MSG_ReadAngle( sb ) (float)(MSG_ReadChar( sb ) * ( 360.0f / 256.0f ))
#define MSG_Init( sb, name, data, bytes ) MSG_InitExt( sb, name, data, bytes, -1 )
// common functions
static inline void MSG_Clear( sizebuf_t *sb )
{
sb->bOverflow = false;
sb->iCurBit = 0;
}
static inline void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nBits )
{
sb->pData = pData;
MSG_Clear( sb );
if( nBits < 0 )
sb->nDataBits = nBytes << 3;
else
sb->nDataBits = nBits;
sb->pDebugName = pDebugName;
}
static inline void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits )
{
MSG_InitExt( sb, "Unnamed", pData, nBytes, nBits );
sb->iCurBit = iStartBit;
}
static inline int MSG_SeekToBit( sizebuf_t *sb, int bitPos, int whence )
{
// compute the file offset
switch( whence )
{
case SEEK_CUR:
bitPos += sb->iCurBit;
break;
case SEEK_SET:
break;
case SEEK_END:
bitPos += sb->nDataBits;
break;
default:
return -1;
}
if( unlikely( bitPos < 0 || bitPos > sb->nDataBits ))
return -1;
sb->iCurBit = bitPos;
return 0;
}
static inline int MSG_TellBit( sizebuf_t *sb )
{
return sb->iCurBit;
}
static inline const char *MSG_GetName( sizebuf_t *sb )
{
return sb->pDebugName;
}
static inline int MSG_GetNumBytesWritten( sizebuf_t *sb )
{
return BitByte( sb->iCurBit );
}
static inline int MSG_GetRealBytesWritten( sizebuf_t *sb )
{
return sb->iCurBit >> 3; // unpadded
}
static inline int MSG_GetNumBitsWritten( sizebuf_t *sb )
{
return sb->iCurBit;
}
static inline int MSG_GetMaxBits( sizebuf_t *sb )
{
return sb->nDataBits;
}
static inline int MSG_GetMaxBytes( sizebuf_t *sb )
{
return sb->nDataBits >> 3;
}
static inline int MSG_GetNumBitsLeft( sizebuf_t *sb )
{
return sb->nDataBits - sb->iCurBit;
}
static inline int MSG_GetNumBytesLeft( sizebuf_t *sb )
{
return MSG_GetNumBitsLeft( sb ) >> 3;
}
static inline byte *MSG_GetData( sizebuf_t *sb )
{
return sb->pData;
}
void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nMaxBits );
void MSG_InitMasks( void ); // called once at startup engine
int MSG_SeekToBit( sizebuf_t *sb, int bitPos, int whence );
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove );
_inline int MSG_TellBit( sizebuf_t *sb ) { return sb->iCurBit; }
_inline const char *MSG_GetName( sizebuf_t *sb ) { return sb->pDebugName; }
qboolean MSG_CheckOverflow( sizebuf_t *sb );
#if XASH_BIG_ENDIAN
#define MSG_BigShort( x ) ( x )
@@ -162,19 +73,13 @@ static inline uint16_t MSG_BigShort( const uint16_t x )
}
#endif
static inline qboolean MSG_Overflow( sizebuf_t *sb, int nBits )
{
if( sb->iCurBit + nBits > sb->nDataBits )
sb->bOverflow = true;
return sb->bOverflow;
}
void MSG_InitMasks( void ); // called once at startup engine
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove );
// init writing
void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits );
void MSG_Clear( sizebuf_t *sb );
// Bit-write functions
void MSG_WriteOneBit( sizebuf_t *sb, int nValue );
NO_ASAN void MSG_WriteUBitLong( sizebuf_t *sb, uint curData, int numbits );
void MSG_WriteUBitLong( sizebuf_t *sb, uint curData, int numbits );
void MSG_WriteSBitLong( sizebuf_t *sb, int data, int numbits );
void MSG_WriteBitLong( sizebuf_t *sb, uint data, int numbits, qboolean bSigned );
qboolean MSG_WriteBits( sizebuf_t *sb, const void *pData, int nBits );
@@ -194,11 +99,20 @@ void MSG_WriteCoord( sizebuf_t *sb, float val );
void MSG_WriteFloat( sizebuf_t *sb, float val );
void MSG_WriteVec3Coord( sizebuf_t *sb, const float *fa );
void MSG_WriteVec3Angles( sizebuf_t *sb, const float *fa );
qboolean MSG_WriteBytes( sizebuf_t *sb, const void *pBuf, int nBytes ); // same as MSG_WriteData
qboolean MSG_WriteString( sizebuf_t *sb, const char *pStr ); // returns false if it overflows the buffer.
qboolean MSG_WriteStringf( sizebuf_t *sb, const char *format, ... ) _format( 2 );
qboolean MSG_WriteBytes( sizebuf_t *sb, const void *pBuf, int nBytes );
// helper functions
_inline int MSG_GetNumBytesWritten( sizebuf_t *sb ) { return BitByte( sb->iCurBit ); }
_inline int MSG_GetRealBytesWritten( sizebuf_t *sb ) { return sb->iCurBit >> 3; } // unpadded
_inline int MSG_GetNumBitsWritten( sizebuf_t *sb ) { return sb->iCurBit; }
_inline int MSG_GetMaxBits( sizebuf_t *sb ) { return sb->nDataBits; }
_inline int MSG_GetMaxBytes( sizebuf_t *sb ) { return sb->nDataBits >> 3; }
_inline int MSG_GetNumBitsLeft( sizebuf_t *sb ) { return sb->nDataBits - sb->iCurBit; }
_inline int MSG_GetNumBytesLeft( sizebuf_t *sb ) { return MSG_GetNumBitsLeft( sb ) >> 3; }
_inline byte *MSG_GetData( sizebuf_t *sb ) { return sb->pData; }
_inline byte *MSG_GetBuf( sizebuf_t *sb ) { return sb->pData; } // just an alias
// Bit-read functions
int MSG_ReadOneBit( sizebuf_t *sb );
@@ -222,8 +136,7 @@ float MSG_ReadCoord( sizebuf_t *sb );
float MSG_ReadFloat( sizebuf_t *sb );
void MSG_ReadVec3Coord( sizebuf_t *sb, vec3_t fa );
void MSG_ReadVec3Angles( sizebuf_t *sb, vec3_t fa );
char *MSG_ReadString( sizebuf_t *sb );
char *MSG_ReadStringLine( sizebuf_t *sb );
qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes );
char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine );
#endif//NET_BUFFER_H

View File

@@ -919,20 +919,13 @@ int Netchan_CreateFileFragments( netchan_t *chan, const char *filename )
int remaining;
int bufferid = 1;
fs_offset_t filesize = 0;
char compressedfilename[MAX_OSPATH];
int compressedFileTime;
int fileTime;
qboolean firstfragment = true;
qboolean bCompressed = false;
fragbufwaiting_t *wait, *p;
fragbuf_t *buf;
char compressedfilename[sizeof( buf->filename ) + 5];
// shouldn't be critical, but just in case
if( Q_strlen( filename ) > sizeof( buf->filename ) - 1 )
{
Con_Printf( S_WARN "Unable to transfer %s due to path length overflow\n", filename );
return 0;
}
if(( filesize = FS_FileSize( filename, false )) <= 0 )
{
@@ -944,7 +937,8 @@ int Netchan_CreateFileFragments( netchan_t *chan, const char *filename )
chunksize = chan->pfnBlockSize( chan->client, FRAGSIZE_FRAG );
else chunksize = FRAGMENT_MAX_SIZE; // fallback
Q_snprintf( compressedfilename, sizeof( compressedfilename ), "%s.ztmp", filename );
Q_strncpy( compressedfilename, filename, sizeof( compressedfilename ));
COM_ReplaceExtension( compressedfilename, ".ztmp", sizeof( compressedfilename ));
compressedFileTime = FS_FileTime( compressedfilename, false );
fileTime = FS_FileTime( filename, false );
@@ -1527,9 +1521,10 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
if( pbuf->iscompressed )
{
char compressedfilename[sizeof( pbuf->filename ) + 5];
char compressedfilename[MAX_OSPATH];
Q_snprintf( compressedfilename, sizeof( compressedfilename ), "%s.ztmp", pbuf->filename );
Q_strncpy( compressedfilename, pbuf->filename, sizeof( compressedfilename ));
COM_ReplaceExtension( compressedfilename, ".ztmp", sizeof( compressedfilename ));
file = FS_Open( compressedfilename, "rb", false );
}
else file = FS_Open( pbuf->filename, "rb", false );

View File

@@ -315,43 +315,6 @@ static const delta_field_t ent_fields[] =
{ NULL },
};
#if XASH_ENGINE_TESTS
typedef struct delta_test_struct_t
{
char dt_string[128]; // always signed
float dt_timewindow_big; // always signed
float dt_timewindow_8; // always signed
float dt_angle; // always_signed
float dt_float_signed;
float dt_float_unsigned;
int32_t dt_integer_signed;
uint32_t dt_integer_unsigned;
int16_t dt_short_signed;
uint16_t dt_short_unsigned;
int8_t dt_byte_signed;
uint8_t dt_byte_unsigned;
} delta_test_struct_t;
#define TEST_DEF( x ) #x, offsetof( delta_test_struct_t, x ), sizeof( ((delta_test_struct_t *)0)->x )
static const delta_field_t test_fields[] =
{
{ TEST_DEF( dt_string ) },
{ TEST_DEF( dt_timewindow_big )},
{ TEST_DEF( dt_timewindow_8 )},
{ TEST_DEF( dt_angle ) },
{ TEST_DEF( dt_float_signed ) },
{ TEST_DEF( dt_float_unsigned ) },
{ TEST_DEF( dt_integer_signed ) },
{ TEST_DEF( dt_integer_unsigned ) },
{ TEST_DEF( dt_short_signed ) },
{ TEST_DEF( dt_short_unsigned ) },
{ TEST_DEF( dt_byte_signed ) },
{ TEST_DEF( dt_byte_unsigned ) },
{ NULL },
};
#endif
enum
{
DT_EVENT_T = 0,
@@ -362,10 +325,6 @@ enum
DT_ENTITY_STATE_T,
DT_ENTITY_STATE_PLAYER_T,
DT_CUSTOM_ENTITY_STATE_T,
#if XASH_ENGINE_TESTS
DT_DELTA_TEST_STRUCT_T,
#endif
DT_STRUCT_COUNT
};
static delta_info_t dt_info[] =
@@ -378,10 +337,7 @@ static delta_info_t dt_info[] =
[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 ) },
#if XASH_ENGINE_TESTS
[DT_DELTA_TEST_STRUCT_T] = { "delta_test_struct_t", test_fields, NUM_FIELDS( test_fields ) },
#endif
[DT_STRUCT_COUNT] = { NULL },
{ NULL },
};
static delta_info_t *Delta_FindStruct( const char *name )
@@ -455,7 +411,9 @@ static void Delta_CustomEncode( delta_info_t *dt, const void *from, const void *
dt->pFields[i].bInactive = false;
if( dt->userCallback )
{
dt->userCallback( dt->pFields, from, to );
}
}
static delta_field_t *Delta_FindFieldInfo( const delta_field_t *pInfo, const char *fieldName )
@@ -1016,14 +974,14 @@ static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, doubl
toF = *(uint8_t *)((int8_t *)to + pField->offset );
}
if( !Q_equal(pField->multiplier, 1.0f ))
{
fromF *= pField->multiplier;
toF *= pField->multiplier;
}
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
if( !Q_equal(pField->multiplier, 1.0f ))
fromF *= pField->multiplier;
if( !Q_equal( pField->multiplier, 1.0f ))
toF *= pField->multiplier;
}
else if( pField->flags & DT_SHORT )
{
@@ -1038,14 +996,14 @@ static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, doubl
toF = *(uint16_t *)((int8_t *)to + pField->offset );
}
if( !Q_equal(pField->multiplier, 1.0f ))
{
fromF *= pField->multiplier;
toF *= pField->multiplier;
}
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
if( !Q_equal(pField->multiplier, 1.0f ))
fromF *= pField->multiplier;
if( !Q_equal( pField->multiplier, 1.0f ))
toF *= pField->multiplier;
}
else if( pField->flags & DT_INTEGER )
{
@@ -1059,15 +1017,14 @@ static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, doubl
fromF = *(uint32_t *)((int8_t *)from + pField->offset );
toF = *(uint32_t *)((int8_t *)to + pField->offset );
}
if( !Q_equal(pField->multiplier, 1.0f ))
{
fromF *= pField->multiplier;
toF *= pField->multiplier;
}
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
if( !Q_equal(pField->multiplier, 1.0f ))
fromF *= pField->multiplier;
if( !Q_equal( pField->multiplier, 1.0f ))
toF *= pField->multiplier;
}
else if( pField->flags & ( DT_ANGLE|DT_FLOAT ))
{
@@ -1077,17 +1034,33 @@ static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, doubl
}
else if( pField->flags & DT_TIMEWINDOW_8 )
{
val_a = *(float *)((byte *)from + pField->offset );
val_b = *(float *)((byte *)to + pField->offset );
fromF = Q_rint( val_a * 100.0 );
toF = Q_rint( val_b * 100.0 );
val_a = Q_rint((*(float *)((byte *)from + pField->offset )) * 100.0f );
val_b = Q_rint((*(float *)((byte *)to + pField->offset )) * 100.0f );
val_a -= Q_rint(timebase * 100.0);
val_b -= Q_rint(timebase * 100.0);
fromF = FloatAsInt( val_a );
toF = FloatAsInt( val_b );
}
else if( pField->flags & DT_TIMEWINDOW_BIG )
{
val_a = *(float *)((byte *)from + pField->offset );
val_b = *(float *)((byte *)to + pField->offset );
fromF = Q_rint( val_a * pField->multiplier );
toF = Q_rint( val_b * pField->multiplier );
val_a = (*(float *)((byte *)from + pField->offset ));
val_b = (*(float *)((byte *)to + pField->offset ));
if( !Q_equal( pField->multiplier, 1.0f ))
{
val_a *= pField->multiplier;
val_b *= pField->multiplier;
val_a = (timebase * pField->multiplier) - val_a;
val_b = (timebase * pField->multiplier) - val_b;
}
else
{
val_a = timebase - val_a;
val_b = timebase - val_b;
}
fromF = FloatAsInt( val_a );
toF = FloatAsInt( val_b );
}
else if( pField->flags & DT_STRING )
{
@@ -1171,7 +1144,6 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
int signbit = FBitSet( pField->flags, DT_SIGNED ) ? 1 : 0;
float flValue, flAngle;
uint iValue;
int dt;
const char *pStr;
if( Delta_CompareField( pField, from, to, timebase ))
@@ -1188,11 +1160,11 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
iValue = *(int8_t *)((int8_t *)to + pField->offset );
else
iValue = *(uint8_t *)((int8_t *)to + pField->offset );
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
if( !Q_equal( pField->multiplier, 1.0 ))
if( !Q_equal( pField->multiplier, 1.0 ) )
iValue *= pField->multiplier;
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
}
else if( pField->flags & DT_SHORT )
@@ -1201,11 +1173,11 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
iValue = *(int16_t *)((int8_t *)to + pField->offset );
else
iValue = *(uint16_t *)((int8_t *)to + pField->offset );
if( !Q_equal( pField->multiplier, 1.0 ))
iValue *= pField->multiplier;
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
if( !Q_equal( pField->multiplier, 1.0 ) )
iValue *= pField->multiplier;
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
}
else if( pField->flags & DT_INTEGER )
@@ -1214,11 +1186,11 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
iValue = *(int32_t *)((int8_t *)to + pField->offset );
else
iValue = *(uint32_t *)((int8_t *)to + pField->offset );
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
if( !Q_equal( pField->multiplier, 1.0 ))
if( !Q_equal( pField->multiplier, 1.0 ) )
iValue *= pField->multiplier;
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
}
else if( pField->flags & DT_FLOAT )
@@ -1238,17 +1210,19 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
}
else if( pField->flags & DT_TIMEWINDOW_8 )
{
signbit = 1; // timewindow is always signed
flValue = *(float *)((byte *)to + pField->offset );
dt = Q_rint(( timebase - flValue ) * 100.0 );
dt = Delta_ClampIntegerField( pField, dt, 1, pField->bits );
MSG_WriteSBitLong( msg, dt, pField->bits );
iValue = (int)Q_rint( timebase * 100.0 ) - (int)Q_rint( flValue * 100.0 );
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
}
else if( pField->flags & DT_TIMEWINDOW_BIG )
{
signbit = 1; // timewindow is always signed
flValue = *(float *)((byte *)to + pField->offset );
dt = Q_rint(( timebase - flValue ) * pField->multiplier );
dt = Delta_ClampIntegerField( pField, dt, 1, pField->bits );
MSG_WriteSBitLong( msg, dt, pField->bits );
iValue = (int)Q_rint( timebase * pField->multiplier ) - (int)Q_rint( flValue * pField->multiplier );
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
}
else if( pField->flags & DT_STRING )
{
@@ -1332,12 +1306,9 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
if( pField->flags & DT_BYTE )
{
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
if( !Q_equal( pField->multiplier, 1.0 ))
if( !Q_equal( pField->multiplier, 1.0 ) )
iValue /= pField->multiplier;
if( !Q_equal( pField->post_multiplier, 1.0 ))
iValue *= pField->post_multiplier;
if( bSigned )
*(int8_t *)((uint8_t *)to + pField->offset ) = iValue;
else
@@ -1346,12 +1317,9 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
else if( pField->flags & DT_SHORT )
{
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
if( !Q_equal( pField->multiplier, 1.0 ))
if( !Q_equal( pField->multiplier, 1.0 ) )
iValue /= pField->multiplier;
if( !Q_equal( pField->post_multiplier, 1.0 ))
iValue *= pField->post_multiplier;
if( bSigned )
*(int16_t *)((uint8_t *)to + pField->offset ) = iValue;
else
@@ -1360,12 +1328,9 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
else if( pField->flags & DT_INTEGER )
{
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
if( !Q_equal( pField->multiplier, 1.0 ))
if( !Q_equal( pField->multiplier, 1.0 ) )
iValue /= pField->multiplier;
if( !Q_equal( pField->post_multiplier, 1.0 ))
iValue *= pField->post_multiplier;
if( bSigned )
*(int32_t *)((uint8_t *)to + pField->offset ) = iValue;
else
@@ -1379,11 +1344,11 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
else
flValue = iValue;
if( !Q_equal( pField->multiplier, 1.0 ))
flValue /= pField->multiplier;
if( !Q_equal( pField->multiplier, 1.0 ) )
flValue = flValue / pField->multiplier;
if( !Q_equal( pField->post_multiplier, 1.0 ))
flValue *= pField->post_multiplier;
if( !Q_equal( pField->post_multiplier, 1.0 ) )
flValue = flValue * pField->post_multiplier;
*(float *)((byte *)to + pField->offset ) = flValue;
}
@@ -1394,14 +1359,22 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
}
else if( pField->flags & DT_TIMEWINDOW_8 )
{
iValue = MSG_ReadSBitLong( msg, pField->bits );
flTime = ( timebase * 100.0 - (int)iValue ) / 100.0;
bSigned = true; // timewindow is always signed
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
flTime = (timebase * 100.0 - (int)iValue) / 100.0;
*(float *)((byte *)to + pField->offset ) = flTime;
}
else if( pField->flags & DT_TIMEWINDOW_BIG )
{
iValue = MSG_ReadSBitLong( msg, pField->bits );
flTime = ( timebase * pField->multiplier - (int)iValue ) / pField->multiplier;
bSigned = true; // timewindow is always signed
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
if( !Q_equal( pField->multiplier, 1.0 ) )
flTime = ( timebase * pField->multiplier - (int)iValue ) / pField->multiplier;
else
flTime = timebase - (int)iValue;
*(float *)((byte *)to + pField->offset ) = flTime;
}
else if( pField->flags & DT_STRING )
@@ -2096,103 +2069,3 @@ void GAME_EXPORT Delta_UnsetFieldByIndex( delta_t *pFields, int fieldNumber )
dt->pFields[fieldNumber].bInactive = true;
}
#if XASH_ENGINE_TESTS
#include "tests.h"
void Test_RunDelta( void )
{
delta_info_t *dt = &dt_info[DT_DELTA_TEST_STRUCT_T];
delta_test_struct_t from, to = { 0 };
delta_test_struct_t null = { 0 };
sizebuf_t msg;
int i;
char buffer[4096] = { 0 };
const double timebase = 123.123;
// a1ba: netbuffer bitmasks are initialized in netchan for some reason
// initialize it ourselves just in case
MSG_InitMasks(); // initialize bit-masks
Delta_AddField( dt, "dt_string", DT_STRING, 1, 1.0f, 1.0f );
Delta_AddField( dt, "dt_timewindow_big", DT_TIMEWINDOW_BIG, 24, 1000.f, 1.0f );
Delta_AddField( dt, "dt_timewindow_8", DT_TIMEWINDOW_8, 8, 1.0f, 1.0f );
Delta_AddField( dt, "dt_angle", DT_ANGLE, 16, 1.0f, 1.0f );
Delta_AddField( dt, "dt_float_signed", DT_FLOAT | DT_SIGNED, 22, 100.0f, 1.0f );
Delta_AddField( dt, "dt_float_unsigned", DT_FLOAT, 24, 10000.0f, 0.1f );
Delta_AddField( dt, "dt_integer_signed", DT_INTEGER | DT_SIGNED, 24, 1.0f, 1.0f );
Delta_AddField( dt, "dt_integer_unsigned", DT_INTEGER, 24, 1.0f, 1.0f );
Delta_AddField( dt, "dt_short_signed", DT_SHORT | DT_SIGNED, 16, 1.0f, 1.0f );
Delta_AddField( dt, "dt_short_unsigned", DT_SHORT, 15, 0.125f, 1.0f );
Delta_AddField( dt, "dt_byte_signed", DT_BYTE | DT_SIGNED, 6, 1.0f, 1.0f );
Delta_AddField( dt, "dt_byte_unsigned", DT_BYTE, 8, 1.0f, 1.0f );
Q_strncpy( from.dt_string, "test data check it's the same", sizeof( from.dt_string ));
from.dt_timewindow_big = timebase + 2.3456;
from.dt_timewindow_8 = timebase + 0.0234;
from.dt_angle = 160.245f;
from.dt_float_signed = -15.123f;
from.dt_float_unsigned = 1235.321f;
from.dt_integer_signed = -412784;
from.dt_integer_unsigned = 123453;
from.dt_short_signed = -12343;
from.dt_short_unsigned = 32131;
from.dt_byte_signed = 16;
from.dt_byte_unsigned = 218;
MSG_Init( &msg, "test message", buffer, sizeof( buffer ));
for( i = 0; i < dt->numFields; i++ )
Delta_WriteField( &msg, &dt->pFields[i], &null, &from, timebase );
MSG_SeekToBit( &msg, 0, SEEK_SET );
for( i = 0; i < dt->numFields; i++ )
Delta_ReadField( &msg, &dt->pFields[i], &null, &to, timebase );
Con_Printf( "struct as encoded to delta:\n" );
TASSERT_STR( from.dt_string, to.dt_string );
// the epsilon value is derived from multiplier value
TASSERT( Q_equal_e( from.dt_timewindow_big, to.dt_timewindow_big, 0.001f ));
// dt_timewindow_8 type has multiplier locked at 100.0f
TASSERT( Q_equal_e( from.dt_timewindow_8, to.dt_timewindow_8, 0.01f ));
TASSERT( Q_equal_e( from.dt_angle, to.dt_angle, 0.1f ));
TASSERT( Q_equal_e( from.dt_float_signed, to.dt_float_signed, 0.01f ));
// dt_float_unsigned has post-multiplier that doesn't affect network data
// and therefore should be reverted back when comparing
TASSERT( Q_equal_e( from.dt_float_unsigned, to.dt_float_unsigned * 10.f , 0.01f ));
TASSERT_EQi( from.dt_integer_signed, to.dt_integer_signed );
TASSERT_EQi( from.dt_integer_unsigned, to.dt_integer_unsigned );
TASSERT_EQi( from.dt_short_signed, to.dt_short_signed );
TASSERT(( from.dt_short_unsigned & ( 0xffff << 3 )) == to.dt_short_unsigned );
TASSERT_EQi( from.dt_byte_signed, to.dt_byte_signed );
TASSERT_EQi( from.dt_byte_unsigned, to.dt_byte_unsigned );
Con_Printf( "from.dt_timewindow_big = %f\n", from.dt_timewindow_big );
Con_Printf( "to.dt_timewindow_big = %f\n", to.dt_timewindow_big );
Con_Printf( "from.dt_timewindow_8 = %f\n", from.dt_timewindow_8 );
Con_Printf( "to.dt_timewindow_8 = %f\n", to.dt_timewindow_8 );
Con_Printf( "from.dt_angle = %f\n", from.dt_angle );
Con_Printf( "to.dt_angle = %f\n", to.dt_angle );
Con_Printf( "from.dt_float_signed = %f\n", from.dt_float_signed );
Con_Printf( "to.dt_float_signed = %f\n", to.dt_float_signed );
Con_Printf( "from.dt_float_unsigned = %f\n", from.dt_float_unsigned );
Con_Printf( "to.dt_float_unsigned = %f\n", to.dt_float_unsigned );
Con_Printf( "from.dt_integer_signed = %i\n", from.dt_integer_signed );
Con_Printf( "to.dt_integer_signed = %i\n", to.dt_integer_signed );
Con_Printf( "from.dt_integer_unsigned = %i\n", from.dt_integer_unsigned );
Con_Printf( "to.dt_integer_unsigned = %i\n", to.dt_integer_unsigned );
Con_Printf( "from.dt_short_signed = %i\n", from.dt_short_signed );
Con_Printf( "to.dt_short_signed = %i\n", to.dt_short_signed );
Con_Printf( "from.dt_short_unsigned = %i\n", from.dt_short_unsigned );
Con_Printf( "to.dt_short_unsigned = %i\n", to.dt_short_unsigned );
Con_Printf( "from.dt_byte_signed = %i\n", from.dt_byte_signed );
Con_Printf( "to.dt_byte_signed = %i\n", to.dt_byte_signed );
Con_Printf( "from.dt_byte_unsigned = %i\n", from.dt_byte_unsigned );
Con_Printf( "to.dt_byte_unsigned = %i\n", to.dt_byte_unsigned );
}
#endif // XASH_ENGINE_TESTS

View File

@@ -2375,7 +2375,7 @@ static qboolean HTTP_ProcessStream( httpfile_t *curfile )
if( curfile->header_size >= sizeof( buf ))
{
Con_Reportf( S_ERROR "Header too big, the size is %d\n", curfile->header_size );
Con_Reportf( S_ERROR "Header too big, the size is %s\n", curfile->header_size );
HTTP_FreeFile( curfile, true );
return false;
}
@@ -2395,6 +2395,8 @@ static qboolean HTTP_ProcessStream( httpfile_t *curfile )
int cutheadersize = begin - curfile->buf + 4; // after that begin of data
char *content_length_line;
Con_Reportf( "HTTP: Got response!\n" );
if( !Q_strstr( curfile->buf, "200 OK" ))
{
*begin = 0; // cut string to print out response
@@ -2418,10 +2420,10 @@ static qboolean HTTP_ProcessStream( httpfile_t *curfile )
content_length_line += sizeof( "Content-Length: " ) - 1;
size = Q_atoi( content_length_line );
Con_Reportf( "HTTP: Got 200 OK! File size is %d\n", size );
Con_Reportf( "HTTP: File size is %d\n", size );
if( ( curfile->size != -1 ) && ( curfile->size != size )) // check size if specified, not used
Con_Reportf( S_WARN "Server reports wrong file size for %s!\n", curfile->path );
Con_Reportf( S_WARN "Server reports wrong file size!\n" );
curfile->size = size;
curfile->header_size = 0;
@@ -2533,7 +2535,7 @@ void HTTP_Run( void )
if( !curfile->file )
{
Con_Printf( S_ERROR "HTTP: cannot open %s!\n", name );
Con_Printf( S_ERROR "cannot open %s!\n", name );
HTTP_FreeFile( curfile, true );
break;
}

View File

@@ -278,8 +278,6 @@ GNU General Public License for more details.
#define SU_WEAPON (1<<14)
extern const char *svc_strings[svc_lastmsg+1];
extern const char *svc_legacy_strings[svc_lastmsg+1];
extern const char *svc_goldsrc_strings[svc_lastmsg+1];
extern const char *clc_strings[clc_lastmsg+1];
// FWGS extensions
@@ -318,40 +316,4 @@ extern const char *clc_strings[clc_lastmsg+1];
// Master Server protocol
#define MS_SCAN_REQUEST "1\xFF" "0.0.0.0:0\0" // TODO: implement IP filter
// GoldSrc protocol definitions
#define PROTOCOL_GOLDSRC_VERSION_REAL 48
#define PROTOCOL_GOLDSRC_VERSION (PROTOCOL_GOLDSRC_VERSION_REAL | (BIT( 7 ))) // should be 48, only to differentiate it from PROTOCOL_LEGACY_VERSION
#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
#define clc_goldsrc_requestcvarvalue2 11
#define clc_goldsrc_lastmsg 12
#define S2C_REJECT_BADPASSWORD '8'
#define S2C_REJECT '9'
#define S2C_CHALLENGE "A00000000"
#define S2C_CONNECTION "B"
#define MAX_GOLDSRC_RESOURCE_BITS 12
#define MAX_GOLDSRC_ENTITY_BITS 11
// #define MAX_GOLDSRC_EDICTS BIT( MAX_ENTITY_BITS )
#define MAX_GOLDSRC_EDICTS ( BIT( MAX_ENTITY_BITS ) + ( MAX_CLIENTS * 15 ))
#define LAST_GOLDSRC_EDICT ( BIT( MAX_ENTITY_BITS ) - 1 )
#endif//NET_PROTOCOL_H

View File

@@ -87,7 +87,7 @@ int open_mpeg_stream( void *mpg, void *file, pfread f_read, pfseek f_seek, wavin
if( !mh || !sc ) return 0;
ret = mpg123_replace_reader_handle( mh, f_read, f_seek, NULL );
ret = mpg123_replace_reader_handle( mh, (void *)f_read, (void *)f_seek, NULL );
if( ret != MPG123_OK )
return 0;

View File

@@ -34,15 +34,9 @@ typedef struct
int playtime; // stream size in milliseconds
} wavinfo_t;
#ifdef _MSC_VER // a1ba: MSVC6 don't have ssize_t
typedef long mpg_ssize_t;
#else
typedef ssize_t mpg_ssize_t;
#endif
// custom stdio
typedef mpg_ssize_t (*pfread)( void *handle, void *buf, size_t count );
typedef fs_offset_t (*pfseek)( void *handle, fs_offset_t offset, int whence );
typedef long (*pfread)( void *handle, void *buf, size_t count );
typedef long (*pfseek)( void *handle, long offset, int whence );
extern void *create_decoder( int *error );
extern int feed_mpeg_header( void *mpg, const byte *data, long bufsize, long streamsize, wavinfo_t *sc );

View File

@@ -32,7 +32,6 @@ typedef struct mpg123_handle_s mpg123_handle_t;
#include <stdlib.h>
#include "fmt123.h"
#include STDINT_H
#include "xash3d_types.h"
#ifndef FALSE
#define FALSE 0
@@ -51,7 +50,7 @@ typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long ulong;
typedef unsigned int uint;
typedef fs_offset_t mpg_off_t;
typedef long mpg_off_t;
#ifdef _MSC_VER // a1ba: MSVC6 don't have ssize_t
typedef long mpg_ssize_t;

View File

@@ -853,21 +853,11 @@ int open_feed( mpg123_handle_t *fr )
return 0;
}
static mpg_ssize_t read_mpgtypes( int fd, void *buf, size_t count )
{
return read( fd, buf, count );
}
static mpg_off_t lseek_mpgtypes( int fd, mpg_off_t offset, int whence )
{
return lseek( fd, offset, whence );
}
static int default_init( mpg123_handle_t *fr )
{
fr->rdat.fdread = plain_read;
fr->rdat.read = fr->rdat.r_read != NULL ? fr->rdat.r_read : read_mpgtypes;
fr->rdat.lseek = fr->rdat.r_lseek != NULL ? fr->rdat.r_lseek : lseek_mpgtypes;
fr->rdat.read = fr->rdat.r_read != NULL ? fr->rdat.r_read : read;
fr->rdat.lseek = fr->rdat.r_lseek != NULL ? fr->rdat.r_lseek : lseek;
fr->rdat.filelen = get_fileinfo( fr );
fr->rdat.filepos = 0;

View File

@@ -216,7 +216,7 @@ wavdata_t *FS_StreamInfo( stream_t *stream )
if( !stream ) return NULL;
// fill structure
info.loopStart = 0;
info.loopStart = -1;
info.rate = stream->rate;
info.width = stream->width;
info.channels = stream->channels;

View File

@@ -74,10 +74,7 @@ static uint32_t Sound_ParseSynchInteger( uint32_t v )
static void Sound_HandleCustomID3Comment( const char *key, const char *value )
{
if( !Q_strcmp( key, "LOOP_START" ) || !Q_strcmp( key, "LOOPSTART" ))
{
sound.loopstart = Q_atoi( value );
SetBits( sound.flags, SOUND_LOOPED );
}
// unknown comment is not an error
}
@@ -236,6 +233,7 @@ qboolean Sound_LoadMPG( const char *name, const byte *buffer, fs_offset_t filesi
sound.channels = sc.channels;
sound.rate = sc.rate;
sound.width = 2; // always 16-bit PCM
sound.loopstart = -1;
sound.size = ( sound.channels * sound.rate * sound.width ) * ( sc.playtime / 1000 ); // in bytes
padsize = sound.size % FRAME_SIZE;
pos += FRAME_SIZE; // evaluate pos
@@ -243,6 +241,7 @@ qboolean Sound_LoadMPG( const char *name, const byte *buffer, fs_offset_t filesi
if( !Sound_ParseID3Tag( buffer, filesize ))
{
Con_DPrintf( S_WARN "Sound_LoadMPG: (%s) failed to extract LOOP_START tag\n", name );
sound.loopstart = -1;
}
if( !sound.size )
@@ -291,14 +290,14 @@ qboolean Sound_LoadMPG( const char *name, const byte *buffer, fs_offset_t filesi
return true;
}
static fs_offset_t FS_SeekMpg( void *file, fs_offset_t offset, int whence )
/*
=================
FS_SeekEx
=================
*/
static fs_offset_t FS_SeekEx( file_t *file, fs_offset_t offset, int whence )
{
return g_fsapi.Seek((file_t *)file, offset, whence ) == -1 ? -1 : g_fsapi.Tell((file_t *)file );
}
static mpg_ssize_t FS_ReadMpg( void *file, void *buf, size_t count )
{
return g_fsapi.Read((file_t *)file, buf, count );
return FS_Seek( file, offset, whence ) == -1 ? -1 : FS_Tell( file );
}
/*
@@ -334,7 +333,7 @@ stream_t *Stream_OpenMPG( const char *filename )
if( ret ) Con_DPrintf( S_ERROR "%s\n", get_error( mpeg ));
// trying to open stream and read header
if( !open_mpeg_stream( mpeg, file, FS_ReadMpg, FS_SeekMpg, &sc ))
if( !open_mpeg_stream( mpeg, file, (void*)FS_Read, (void*)FS_SeekEx, &sc ))
{
Con_DPrintf( S_ERROR "Stream_OpenMPG: failed to load (%s): %s\n", filename, get_error( mpeg ));
close_decoder( mpeg );

View File

@@ -14,9 +14,6 @@ GNU General Public License for more details.
*/
#include "soundlib.h"
#if XASH_SDL
#include <SDL_audio.h>
#endif // XASH_SDL
/*
=============================================================================
@@ -133,309 +130,7 @@ uint GAME_EXPORT Sound_GetApproxWavePlayLen( const char *filepath )
return msecs;
}
static qboolean Sound_ConvertNoResample( wavdata_t *sc, int inwidth, int outwidth, int outcount )
{
size_t i;
if( inwidth == 1 && outwidth == 2 ) // S8 to S16
{
for( i = 0; i < outcount * sc->channels; i++ )
((int16_t*)sound.tempbuffer)[i] = ((int8_t *)sc->buffer)[i] * 256;
return true;
}
if( inwidth == 2 && outwidth == 1 ) // S16 to S8
{
for( i = 0; i < outcount * sc->channels; i++ )
((int8_t*)sound.tempbuffer)[i] = ((int16_t *)sc->buffer)[i] / 256;
return true;
}
return false;
}
static qboolean Sound_ConvertDownsample( wavdata_t *sc, int inwidth, int outwidth, int outcount, double stepscale )
{
size_t i;
double j;
if( inwidth == 1 && outwidth == 1 )
{
int8_t *data = (int8_t *)sc->buffer;
if( outwidth == 1 )
{
int8_t *outdata = (int8_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0];
outdata[i*2+1] = data[((int)j)*2+1];
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j];
}
}
return true;
}
if( outwidth == 2 )
{
int16_t *outdata = (int16_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0] * 256;
outdata[i*2+1] = data[((int)j)*2+1] * 256;
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j] * 256;
}
}
return true;
}
}
if( inwidth == 2 )
{
int16_t *data = (int16_t *)sc->buffer;
if( outwidth == 1 )
{
int8_t *outdata = (int8_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0] / 256;
outdata[i*2+1] = data[((int)j)*2+1] / 256;
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j] / 256;
}
}
return true;
}
if( outwidth == 2 )
{
int16_t *outdata = (int16_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0];
outdata[i*2+1] = data[((int)j)*2+1];
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j];
}
}
return true;
}
}
return false;
}
static qboolean Sound_ConvertUpsample( wavdata_t *sc, int inwidth, int outwidth, int outcount, int incount, double stepscale )
{
size_t i;
double j;
double frac;
incount--; // to not go past last sample while interpolating
if( inwidth == 1 )
{
int8_t *data = (int8_t *)sc->buffer;
if( outwidth == 1 )
{
int8_t *outdata = (int8_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0];
outdata[i*2+1] = data[((int)j)*2+1];
if( j != (int)j && j < incount )
{
frac = j - (int)j;
outdata[i*2+0] += (data[((int)j+1)*2+0] - data[((int)j)*2+0]) * frac;
outdata[i*2+1] += (data[((int)j+1)*2+1] - data[((int)j)*2+1]) * frac;
}
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j];
if( j != (int)j && j < incount )
{
frac = j - (int)j;
outdata[i] += (data[(int)j+1] - data[(int)j]) * frac;
}
}
}
return true;
}
if( outwidth == 2 )
{
int16_t *outdata = (int16_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0] * 256;
outdata[i*2+1] = data[((int)j)*2+1] * 256;
if( j != (int)j && j < incount )
{
frac = ( j - (int)j ) * 256;
outdata[i*2+0] += (data[((int)j+1)*2+0] - data[((int)j)*2+0]) * frac;
outdata[i*2+1] += (data[((int)j+1)*2+1] - data[((int)j)*2+1]) * frac;
}
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j] * 256;
if( j != (int)j && j < incount )
{
frac = ( j - (int)j ) * 256;
outdata[i] += (data[(int)j+1] - data[(int)j]) * frac;
}
}
}
return true;
}
}
if( inwidth == 2 )
{
int16_t *data = (int16_t *)sc->buffer;
if( outwidth == 1 )
{
int8_t *outdata = (int8_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0] / 256;
outdata[i*2+1] = data[((int)j)*2+1] / 256;
if( j != (int)j && j < incount )
{
frac = ( j - (int)j ) / 256;
outdata[i*2+0] += (data[((int)j+1)*2+0] - data[((int)j)*2+0]) * frac;
outdata[i*2+1] += (data[((int)j+1)*2+1] - data[((int)j)*2+1]) * frac;
}
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j] / 256;
if( j != (int)j && j < incount )
{
frac = ( j - (int)j ) / 256;
outdata[i] += (data[(int)j+1] - data[(int)j]) * frac;
}
}
}
return true;
}
if( outwidth == 2 )
{
int16_t *outdata = (int16_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0];
outdata[i*2+1] = data[((int)j)*2+1];
if( j != (int)j && j < incount )
{
frac = j - (int)j;
outdata[i*2+0] += (data[((int)j+1)*2+0] - data[((int)j)*2+0]) * frac;
outdata[i*2+1] += (data[((int)j+1)*2+1] - data[((int)j)*2+1]) * frac;
}
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j];
if( j != (int)j && j < incount )
{
frac = j - (int)j;
outdata[i] += (data[(int)j+1] - data[(int)j]) * frac;
}
}
}
return true;
}
}
return false;
}
#define drint( v ) (int)( v + 0.5 )
/*
================
@@ -446,70 +141,125 @@ We need convert sound to signed even if nothing to resample
*/
static qboolean Sound_ResampleInternal( wavdata_t *sc, int inrate, int inwidth, int outrate, int outwidth )
{
const size_t oldsize = sc->size;
double stepscale, j;
int outcount;
int i;
qboolean handled = false;
double stepscale;
double t1, t2;
int outcount, incount = sc->samples;
if( inrate == outrate && inwidth == outwidth )
return false;
t1 = Sys_DoubleTime();
stepscale = (double)inrate / outrate; // this is usually 0.5, 1, or 2
outcount = sc->samples / stepscale;
sc->size = outcount * outwidth * sc->channels;
sound.tempbuffer = (byte *)Mem_Realloc( host.soundpool, sound.tempbuffer, sc->size );
sc->samples = outcount;
if( FBitSet( sc->flags, SOUND_LOOPED ))
if( sc->loopStart != -1 )
sc->loopStart = sc->loopStart / stepscale;
#if 0 && XASH_SDL // slow but somewhat accurate
if( inrate == outrate )
{
const SDL_AudioFormat infmt = inwidth == 1 ? AUDIO_S8 : AUDIO_S16;
const SDL_AudioFormat outfmt = outwidth == 1 ? AUDIO_S8 : AUDIO_S16;
SDL_AudioCVT cvt;
// SDL_AudioCVT does conversion in place, original buffer is used for it
if( SDL_BuildAudioCVT( &cvt, infmt, sc->channels, inrate, outfmt, sc->channels, outrate ) > 0 && cvt.needed )
if( inwidth == 1 && outwidth == 2 ) // S8 to S16
{
sc->buffer = (byte *)Mem_Realloc( host.soundpool, sc->buffer, oldsize * cvt.len_mult );
cvt.len = oldsize;
cvt.buf = sc->buffer;
for( i = 0; i < outcount * sc->channels; i++ )
((int16_t*)sound.tempbuffer)[i] = ((int8_t *)sc->buffer)[i] * 256;
handled = true;
}
else if( inwidth == 2 && outwidth == 1 ) // S16 to S8
{
for( i = 0; i < outcount * sc->channels; i++ )
((int8_t*)sound.tempbuffer)[i] = ((int16_t *)sc->buffer)[i] / 256;
handled = true;
}
}
else // resample case
{
if( inwidth == 1 )
{
int8_t *data = (int8_t *)sc->buffer;
if( !SDL_ConvertAudio( &cvt ))
if( outwidth == 1 )
{
t2 = Sys_DoubleTime();
Con_Reportf( "Sound_Resample: from [%d bit %d Hz] to [%d bit %d Hz] (took %.3fs through SDL)\n", inwidth * 8, inrate, outwidth * 8, outrate, t2 - t1 );
sc->rate = outrate;
sc->width = outwidth;
return false; // HACKHACK: return false so Sound_Process won't reallocate buffer
if( sc->channels == 2 )
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
{
((int8_t*)sound.tempbuffer)[i*2+0] = data[((int)j)*2+0];
((int8_t*)sound.tempbuffer)[i*2+1] = data[((int)j)*2+1];
}
}
else
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
((int8_t*)sound.tempbuffer)[i] = data[(int)j];
}
handled = true;
}
else if( outwidth == 2 )
{
if( sc->channels == 2 )
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
{
((int16_t*)sound.tempbuffer)[i*2+0] = data[((int)j)*2+0] * 256;
((int16_t*)sound.tempbuffer)[i*2+1] = data[((int)j)*2+1] * 256;
}
}
else
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
((int16_t*)sound.tempbuffer)[i] = data[(int)j] * 256;
}
handled = true;
}
}
else if( inwidth == 2 )
{
int16_t *data = (int16_t *)sc->buffer;
if( outwidth == 1 )
{
if( sc->channels == 2 )
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
{
((int8_t*)sound.tempbuffer)[i*2+0] = data[((int)j)*2+0] / 256;
((int8_t*)sound.tempbuffer)[i*2+1] = data[((int)j)*2+1] / 256;
}
}
else
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
((int8_t*)sound.tempbuffer)[i] = data[(int)j] / 256;
}
handled = true;
}
else if( outwidth == 2 )
{
if( sc->channels == 2 )
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
{
((int16_t*)sound.tempbuffer)[i*2+0] = data[((int)j)*2+0];
((int16_t*)sound.tempbuffer)[i*2+1] = data[((int)j)*2+1];
}
}
else
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
((int16_t*)sound.tempbuffer)[i] = data[(int)j];
}
handled = true;
}
}
}
#endif
sound.tempbuffer = (byte *)Mem_Realloc( host.soundpool, sound.tempbuffer, sc->size );
if( inrate == outrate ) // no resampling, just copy data
handled = Sound_ConvertNoResample( sc, inwidth, outwidth, outcount );
else if( inrate > outrate ) // fast case, usually downsample but is also ok for upsampling
handled = Sound_ConvertDownsample( sc, inwidth, outwidth, outcount, stepscale );
else // upsample case, w/ interpolation
handled = Sound_ConvertUpsample( sc, inwidth, outwidth, outcount, incount, stepscale );
t2 = Sys_DoubleTime();
if( handled )
{
if( t2 - t1 > 0.01f ) // critical, report to mod developer
Con_Printf( S_WARN "Sound_Resample: from [%d bit %d Hz] to [%d bit %d Hz] (took %.3fs)\n", inwidth * 8, inrate, outwidth * 8, outrate, t2 - t1 );
else
Con_Reportf( "Sound_Resample: from [%d bit %d Hz] to [%d bit %d Hz] (took %.3fs)\n", inwidth * 8, inrate, outwidth * 8, outrate, t2 - t1 );
}
Con_Reportf( "Sound_Resample: from [%d bit %d Hz] to [%d bit %d Hz]\n", inwidth * 8, inrate, outwidth * 8, outrate );
else
Con_Printf( S_ERROR "Sound_Resample: unsupported from [%d bit %d Hz] to [%d bit %d Hz]\n", inwidth * 8, inrate, outwidth * 8, outrate );
Con_Reportf( S_ERROR "Sound_Resample: unsupported from [%d bit %d Hz] to [%d bit %d Hz]\n", inwidth * 8, inrate, outwidth * 8, outrate );
sc->rate = outrate;
sc->width = outwidth;
@@ -526,20 +276,23 @@ qboolean Sound_Process( wavdata_t **wav, int rate, int width, uint flags )
if( !snd || !snd->buffer )
return false;
if( FBitSet( flags, SOUND_RESAMPLE ) && ( width > 0 || rate > 0 ))
if(( flags & SOUND_RESAMPLE ) && ( width > 0 || rate > 0 ))
{
result = Sound_ResampleInternal( snd, snd->rate, snd->width, rate, width );
if( result )
if( Sound_ResampleInternal( snd, snd->rate, snd->width, rate, width ))
{
Mem_Free( snd->buffer ); // free original image buffer
snd->buffer = Sound_Copy( snd->size ); // unzone buffer (don't touch sound.tempbuffer)
snd->buffer = Sound_Copy( snd->size ); // unzone buffer (don't touch image.tempbuffer)
}
else
{
// not resampled
result = false;
}
}
*wav = snd;
return result;
return false;
}
qboolean Sound_SupportedFileFormat( const char *fileext )

View File

@@ -23,11 +23,6 @@ static const byte *iff_end;
static const byte *iff_lastChunk;
static int iff_chunkLen;
static int IsFourCC( const byte *ptr, const byte *fourcc )
{
return 0 == memcmp( ptr, fourcc, 4 );
}
/*
=================
GetLittleShort
@@ -91,21 +86,7 @@ static void FindNextChunk( const char *filename, const char *name )
if( iff_chunkLen > remaining )
{
// only print this warning if selected chunk is truncated
//
// otherwise this warning becomes misleading because some
// idiot programs like CoolEdit (i.e. Adobe Audition) don't always
// respect pad byte. The file isn't actually truncated, it just
// can't be reliably parsed as a whole
if( IsFourCC( iff_lastChunk, "RIFF" )
|| IsFourCC( iff_lastChunk, "fmt " )
|| IsFourCC( iff_lastChunk, "cue " )
|| IsFourCC( iff_lastChunk, "LIST" )
|| IsFourCC( iff_lastChunk, "data" ))
{
Con_DPrintf( "%s: '%s' truncated by %i bytes\n", __func__, filename, iff_chunkLen - remaining );
}
Con_DPrintf( "%s: '%s' truncated by %i bytes\n", __func__, filename, iff_chunkLen - remaining );
iff_chunkLen = remaining;
}
@@ -113,9 +94,9 @@ static void FindNextChunk( const char *filename, const char *name )
iff_dataPtr -= 8;
iff_lastChunk = iff_dataPtr + 8 + iff_chunkLen;
if(( iff_chunkLen & 1 ) && remaining )
if ((iff_chunkLen&1) && remaining)
iff_lastChunk++;
if( IsFourCC( iff_dataPtr, name ))
if (!Q_strncmp(iff_dataPtr, name, 4))
return;
}
}
@@ -149,18 +130,15 @@ static qboolean StreamFindNextChunk( file_t *file, const char *name, int *last_c
return false; // didn't find the chunk
FS_Seek( file, 4, SEEK_CUR );
if( FS_Read( file, &iff_chunk_len, sizeof( iff_chunk_len )) != sizeof( iff_chunk_len ))
return false;
FS_Read( file, &iff_chunk_len, sizeof( iff_chunk_len ));
if( iff_chunk_len < 0 )
return false; // didn't find the chunk
FS_Seek( file, -8, SEEK_CUR );
*last_chunk = FS_Tell( file ) + 8 + (( iff_chunk_len + 1 ) & ~1 );
if( FS_Read( file, chunkName, sizeof( chunkName )) != sizeof( chunkName ))
return false;
FS_Read( file, chunkName, 4 );
if( IsFourCC( chunkName, name ))
if( !Q_strncmp( chunkName, name, 4 ))
return true;
}
@@ -186,7 +164,7 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, fs_offset_t filesi
// find "RIFF" chunk
FindChunk( name, "RIFF" );
if( !iff_dataPtr || !IsFourCC( iff_dataPtr + 8, "WAVE" ))
if( !( iff_dataPtr && !Q_strncmp( (const char *)iff_dataPtr + 8, "WAVE", 4 )))
{
Con_DPrintf( S_ERROR "Sound_LoadWAV: %s missing 'RIFF/WAVE' chunks\n", name );
return false;
@@ -245,12 +223,11 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, fs_offset_t filesi
{
iff_dataPtr += 32;
sound.loopstart = GetLittleLong();
SetBits( sound.flags, SOUND_LOOPED );
FindNextChunk( name, "LIST" ); // if the next chunk is a LIST chunk, look for a cue length marker
if( iff_dataPtr )
{
if( IsFourCC( iff_dataPtr + 28, "mark" ))
if( !Q_strncmp( (const char *)iff_dataPtr + 28, "mark", 4 ))
{
// this is not a proper parse, but it works with CoolEdit...
iff_dataPtr += 24;
@@ -260,7 +237,7 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, fs_offset_t filesi
}
else
{
sound.loopstart = 0;
sound.loopstart = -1;
sound.samples = 0;
}
@@ -365,16 +342,8 @@ stream_t *Stream_OpenWAV( const char *filename )
return NULL;
}
FS_Seek( file, 4, SEEK_CUR );
if( FS_Read( file, chunkName, 4 ) != 4 )
{
Con_DPrintf( S_ERROR "%s: %s missing WAVE chunk, truncated\n", filename );
FS_Close( file );
return false;
}
if( !IsFourCC( chunkName, "WAVE" ))
FS_Read( file, chunkName, 4 );
if( !Q_strncmp( chunkName, "WAVE", 4 ))
{
Con_DPrintf( S_ERROR "Stream_OpenWAV: %s missing WAVE chunk\n", filename );
FS_Close( file );
@@ -382,7 +351,7 @@ stream_t *Stream_OpenWAV( const char *filename )
}
// get "fmt " chunk
iff_data = FS_Tell( file );
iff_data = FS_Tell( file ) + 4;
last_chunk = iff_data;
if( !StreamFindNextChunk( file, "fmt ", &last_chunk ))
{

View File

@@ -50,7 +50,7 @@ typedef struct sndlib_s
int rate; // num samples per second (e.g. 11025 - 11 khz)
int width; // resolution - bum bits divided by 8 (8 bit is 1, 16 bit is 2)
int channels; // num channels (1 - mono, 2 - stereo)
uint loopstart; // start looping from
int loopstart; // start looping from
uint samples; // total samplecount in sound
uint flags; // additional sound flags
size_t size; // sound unpacked size (for bounds checking)

View File

@@ -135,10 +135,6 @@ void Sys_InitLog( void )
mode = "a";
else mode = "w";
if( Host_IsDedicated( ))
Q_strncpy( s_ld.title, XASH_DEDICATED_SERVER_NAME " " XASH_VERSION, sizeof( s_ld.title ));
else Q_strncpy( s_ld.title, XASH_ENGINE_NAME " " XASH_VERSION, sizeof( s_ld.title ));
// create log if needed
if( s_ld.log_active )
{
@@ -146,18 +142,15 @@ void Sys_InitLog( void )
if ( !s_ld.logfile )
{
Con_Reportf( S_ERROR "Sys_InitLog: can't create log file %s: %s\n", s_ld.log_path, strerror( errno ));
Con_Reportf( S_ERROR "Sys_InitLog: can't create log file %s: %s\n", s_ld.log_path, strerror( errno ) );
return;
}
s_ld.logfileno = fileno( s_ld.logfile );
// fit to 80 columns for easier read on standard terminal
fputs( "================================================================================\n", s_ld.logfile );
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
fprintf( s_ld.logfile, "Game started at %s\n", Q_timestamp( TIME_FULL ));
fputs( "================================================================================\n", s_ld.logfile );
fflush( s_ld.logfile );
fprintf( s_ld.logfile, "=================================================================================\n" );
fprintf( s_ld.logfile, "\t%s (build %i commit %s (%s-%s)) started at %s\n", s_ld.title, Q_buildnum(), Q_buildcommit(), Q_buildos(), Q_buildarch(), Q_timestamp( TIME_FULL ) );
fprintf( s_ld.logfile, "=================================================================================\n" );
}
}
@@ -184,11 +177,12 @@ void Sys_CloseLog( void )
if( s_ld.logfile )
{
fputc( '\n', s_ld.logfile );
fputs( "================================================================================\n", s_ld.logfile );
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
fprintf( s_ld.logfile, "Stopped with reason \"%s\" at %s\n", event_name, Q_timestamp( TIME_FULL ));
fputs( "================================================================================\n", s_ld.logfile );
fprintf( s_ld.logfile, "\n");
fprintf( s_ld.logfile, "=================================================================================");
if( host.change_game ) fprintf( s_ld.logfile, "\n\t%s (build %i) %s\n", s_ld.title, Q_buildnum(), event_name );
else fprintf( s_ld.logfile, "\n\t%s (build %i) %s at %s\n", s_ld.title, Q_buildnum(), event_name, Q_timestamp( TIME_FULL ));
fprintf( s_ld.logfile, "=================================================================================\n");
fclose( s_ld.logfile );
s_ld.logfile = NULL;
}
@@ -341,18 +335,15 @@ void GAME_EXPORT Con_Printf( const char *szFmt, ... )
{
static char buffer[MAX_PRINT_MSG];
va_list args;
qboolean add_newline;
if( !host.allow_console )
return;
va_start( args, szFmt );
add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
va_end( args );
Sys_Print( buffer );
if( add_newline )
Sys_Print( "\n" );
}
/*
@@ -365,21 +356,18 @@ void GAME_EXPORT Con_DPrintf( const char *szFmt, ... )
{
static char buffer[MAX_PRINT_MSG];
va_list args;
qboolean add_newline;
if( host_developer.value < DEV_NORMAL )
return;
va_start( args, szFmt );
add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
va_end( args );
if( buffer[0] == '0' && buffer[1] == '\n' && buffer[2] == '\0' )
return; // hlrally spam
Sys_Print( buffer );
if( add_newline )
Sys_Print( "\n" );
}
/*
@@ -392,18 +380,15 @@ void Con_Reportf( const char *szFmt, ... )
{
static char buffer[MAX_PRINT_MSG];
va_list args;
qboolean add_newline;
if( host_developer.value < DEV_EXTENDED )
return;
va_start( args, szFmt );
add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
va_end( args );
Sys_Print( buffer );
if( add_newline )
Sys_Print( "\n" );
}

View File

@@ -53,7 +53,7 @@ GNU General Public License for more details.
#include "library.h"
#include "whereami.h"
int error_on_exit = 0; // arg for exit();
qboolean error_on_exit = false; // arg for exit();
/*
================
@@ -404,7 +404,7 @@ void Sys_Warn( const char *format, ... )
Msg( "Sys_Warn: %s\n", text );
if( !Host_IsDedicated() ) // dedicated server should not hang on messagebox
Platform_MessageBox( "Xash Warning", text, true );
Platform_MessageBox( "Xash Warning", text, false );
}
/*
@@ -430,7 +430,7 @@ void Sys_Error( const char *error, ... )
// make sure that console received last message
if( host.change_game ) Sys_Sleep( 200 );
error_on_exit = 1;
error_on_exit = true;
host.status = HOST_ERR_FATAL;
va_start( argptr, error );
Q_vsnprintf( text, MAX_PRINT_MSG, error, argptr );
@@ -449,7 +449,7 @@ void Sys_Error( const char *error, ... )
Wcon_ShowConsole( false );
#endif
Sys_Print( text );
Platform_MessageBox( "Xash Error", text, true );
Platform_MessageBox( "Xash Error", text, false );
}
else
{

View File

@@ -41,7 +41,7 @@ NOTE: never change this structure because all dll descriptions in xash code
writes into struct by offsets not names
========================================================================
*/
extern int error_on_exit;
void Sys_Sleep( int msec );
double Sys_DoubleTime( void );
char *Sys_GetClipboardData( void );

View File

@@ -39,15 +39,13 @@ void Test_RunCon( void );
void Test_RunVOX( void );
void Test_RunIPFilter( void );
void Test_RunGamma( void );
void Test_RunDelta( void );
#define TEST_LIST_0 \
Test_RunLibCommon(); \
Test_RunCommon(); \
Test_RunCmd(); \
Test_RunCvar(); \
Test_RunIPFilter(); \
Test_RunDelta();
Test_RunIPFilter();
#define TEST_LIST_0_CLIENT \
Test_RunCon(); \

View File

@@ -20,6 +20,63 @@ GNU General Public License for more details.
#include "xash3d_mathlib.h"
#include "studio.h"
// just for debug
const char *et_name[] =
{
"normal",
"player",
"tempentity",
"beam",
"fragmented",
};
/*
===============================================================================
ENTITY LINKING
===============================================================================
*/
/*
===============
ClearLink
ClearLink is used for new headnodes
===============
*/
void ClearLink( link_t *l )
{
l->prev = l->next = l;
}
/*
===============
RemoveLink
remove link from chain
===============
*/
void RemoveLink( link_t *l )
{
l->next->prev = l->prev;
l->prev->next = l->next;
}
/*
===============
InsertLinkBefore
kept trigger and solid entities seperate
===============
*/
void InsertLinkBefore( link_t *l, link_t *before )
{
l->next = before;
l->prev = before->prev;
l->prev->next = l;
l->next->prev = l;
}
/*
==================
World_MoveBounds

View File

@@ -35,6 +35,13 @@ ENTITY AREA CHECKING
#include "lightstyle.h"
extern const char *et_name[];
// linked list
void InsertLinkBefore( link_t *l, link_t *before );
void RemoveLink( link_t *l );
void ClearLink( link_t *l );
// trace common
void World_MoveBounds( const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, vec3_t boxmins, vec3_t boxmaxs );
void World_TransformAABB( matrix4x4 transform, const vec3_t mins, const vec3_t maxs, vec3_t outmins, vec3_t outmaxs );

View File

@@ -25,39 +25,18 @@ GNU General Public License for more details.
#include "platform/swap/swap.h"
#define Q_malloc SWAP_Malloc
#define Q_free SWAP_Free
static void *Q_realloc( void *mem, size_t size )
{
void *newmem;
if( mem && size == 0 )
{
Q_free( mem );
return NULL;
}
newmem = Q_malloc( size );
if( mem && newmem )
{
memcpy( newmem, mem, size );
Q_free( mem );
}
return newmem;
}
#else
#define Q_malloc malloc
#define Q_free free
#define Q_realloc realloc
#endif
typedef struct memheader_s
{
struct memheader_s *next; // next and previous memheaders in chain belonging to pool
struct memheader_s *prev;
const char *filename; // file name and line where Mem_Alloc was called
struct mempool_s *pool; // pool this memheader belongs to
size_t size; // size of the memory after the header (excluding header and sentinel2)
poolhandle_t poolptr; // pool this memheader belongs to
const char *filename; // file name and line where Mem_Alloc was called
int fileline;
#if !XASH_64BIT
uint32_t pad0; // doesn't have value, only to make Mem_Alloc return aligned addresses on ILP32
@@ -69,34 +48,50 @@ typedef struct memheader_s
typedef struct mempool_s
{
uint32_t sentinel1; // should always be MEMHEADER_SENTINEL1
struct memheader_s *chain; // chain of individual memory allocations
size_t totalsize; // total memory allocated in this pool (inside memheaders)
size_t realsize; // total memory allocated in this pool (actual malloc total)
size_t lastchecksize; // updated each time the pool is displayed by memlist
struct mempool_s *next; // linked into global mempool list
const char *filename; // file name and line where Mem_AllocPool was called
int fileline;
#if XASH_64BIT
poolhandle_t idx;
#endif
char name[64]; // name of the pool
uint32_t sentinel2; // should always be MEMHEADER_SENTINEL1
} mempool_t;
static mempool_t *poolchain = NULL; // critical stuff
static size_t poolcount = 0;
#if XASH_64BIT
// a1ba: due to mempool being passed with the model through reused 32-bit field
// which makes engine incompatible with 64-bit pointers I changed mempool type
// from pointer to 32-bit handle, thankfully mempool structure is private
// But! Mempools are handled through linked list so we can't index them safely
static poolhandle_t lastidx = 0;
static mempool_t *Mem_FindPool( poolhandle_t poolptr )
{
if( likely( poolptr > 0 && poolptr <= poolcount ))
return &poolchain[poolptr - 1];
mempool_t *pool;
for( pool = poolchain; pool; pool = pool->next )
{
if( pool->idx == poolptr )
return pool;
}
Sys_Error( "%s: not allocated or double freed pool %d", __FUNCTION__, poolptr );
return NULL;
}
static poolhandle_t Mem_PoolIndex( mempool_t *mempool )
#else
static mempool_t *Mem_FindPool( poolhandle_t poolptr )
{
return (poolhandle_t)(mempool - poolchain) + 1;
return (mempool_t *)poolptr;
}
#endif
static inline void Mem_PoolAdd( mempool_t *pool, size_t size )
{
@@ -116,7 +111,7 @@ static inline void Mem_PoolLinkAlloc( mempool_t *pool, memheader_t *mem )
if( mem->next ) mem->next->prev = mem;
pool->chain = mem;
mem->prev = NULL;
mem->poolptr = Mem_PoolIndex( pool );
mem->pool = pool;
}
static inline void Mem_PoolUnlinkAlloc( mempool_t *pool, memheader_t *mem )
@@ -124,7 +119,7 @@ static inline void Mem_PoolUnlinkAlloc( mempool_t *pool, memheader_t *mem )
if( mem->next ) mem->next->prev = mem->prev;
if( mem->prev ) mem->prev->next = mem->next;
else pool->chain = mem->next;
mem->poolptr = 0;
mem->pool = NULL;
}
static inline void Mem_InitAlloc( memheader_t *mem, size_t size, const char *filename, int fileline )
@@ -170,6 +165,23 @@ static qboolean Mem_CheckAllocHeader( const char *func, const memheader_t *mem,
return true;
}
static qboolean Mem_CheckPool( const char *func, const mempool_t *pool, const char *filename, int fileline )
{
if( pool->sentinel1 != MEMHEADER_SENTINEL1 )
{
Sys_Error( "%s: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i)\n", func, pool->filename, pool->fileline, filename, fileline );
return false;
}
if( pool->sentinel2 != MEMHEADER_SENTINEL1 )
{
Sys_Error( "%s: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i)\n", func, pool->filename, pool->fileline, filename, fileline );
return false;
}
return true;
}
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
{
memheader_t *mem;
@@ -178,16 +190,12 @@ void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char
if( size <= 0 )
return NULL;
if( unlikely( !poolptr ))
if( !poolptr )
{
Sys_Error( "%s: pool == NULL (alloc at %s:%i)\n", __func__, filename, fileline );
return NULL;
}
pool = Mem_FindPool( poolptr );
if( !pool )
return NULL;
mem = (memheader_t *)Q_malloc( sizeof( memheader_t ) + size + sizeof( byte ));
if( mem == NULL )
{
@@ -197,6 +205,7 @@ void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char
Mem_InitAlloc( mem, size, filename, fileline );
pool = Mem_FindPool( poolptr );
Mem_PoolAdd( pool, size );
Mem_PoolLinkAlloc( pool, mem );
@@ -213,9 +222,7 @@ static void Mem_FreeBlock( memheader_t *mem, const char *filename, int fileline
if( !Mem_CheckAllocHeader( __func__, mem, filename, fileline ))
return;
pool = Mem_FindPool( mem->poolptr );
if( !pool )
return;
pool = mem->pool;
// unlink memheader from doubly linked list
if(( mem->prev ? mem->prev->next != mem : pool->chain != mem ) || ( mem->next && mem->next->prev != mem ))
@@ -251,7 +258,7 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
if( size <= 0 )
return data; // no need to reallocate
if( unlikely( !poolptr ))
if( !poolptr )
{
Sys_Error( "Mem_Realloc: pool == NULL (alloc at %s:%i)\n", filename, fileline );
return NULL;
@@ -265,21 +272,25 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
if( !Mem_CheckAllocHeader( "Mem_Realloc", mem, filename, fileline ))
return NULL;
if( unlikely( mem->poolptr != poolptr ))
{
Sys_Error( "Mem_Realloc: pool migration is not allowed (alloc at %s:%i, realloc at %s:%i)\n",
Mem_CheckFilename( mem->filename ), mem->fileline, filename, fileline );
return NULL;
}
oldsize = mem->size;
if( size == oldsize )
return data;
#if XASH_CUSTOM_SWAP
{
char *nb = _Mem_Alloc( poolptr, size, clear, filename, fileline );
size_t newsize = mem->size < size ? mem->size : size; // upper data can be trucnated!
memcpy( nb, data, newsize );
_Mem_Free( data, filename, fileline ); // free unused old block
return nb;
}
#else // XASH_CUSTOM_SWAP
pool = Mem_FindPool( poolptr );
oldmem = (uintptr_t)mem;
mem = Q_realloc( mem, sizeof( memheader_t ) + size + sizeof( byte ));
mem = realloc( mem, sizeof( memheader_t ) + size + sizeof( byte ));
if( mem == NULL )
{
@@ -301,7 +312,14 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
}
else Mem_PoolSubtract( pool, oldsize - size );
if( oldmem != (uintptr_t)mem ) // just relink pointers
// if allocation was migrated from one pool to another
// (this is possible with original Mem_Realloc func)
if( unlikely( mem->pool != pool ))
{
Mem_PoolUnlinkAlloc( mem->pool, mem );
Mem_PoolLinkAlloc( pool, mem );
}
else if( oldmem != (uintptr_t)mem ) // just relink pointers
{
if( mem->next ) mem->next->prev = mem;
if( mem->prev ) mem->prev->next = mem;
@@ -309,81 +327,69 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
}
return (void *)((byte *)mem + sizeof( memheader_t ));
}
static poolhandle_t Mem_InitPool( mempool_t *pool, const char *name, const char *filename, int fileline )
{
memset( pool, 0, sizeof( *pool ));
// fill header
pool->filename = filename;
pool->fileline = fileline;
pool->realsize = sizeof( mempool_t );
Q_strncpy( pool->name, name, sizeof( pool->name ));
return Mem_PoolIndex( pool );
#endif // XASH_CUSTOM_SWAP
}
poolhandle_t _Mem_AllocPool( const char *name, const char *filename, int fileline )
{
mempool_t *pool;
size_t i;
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
{
if( pool->filename == NULL )
return Mem_InitPool( pool, name, filename, fileline );
}
pool = (mempool_t *)Q_realloc( poolchain, sizeof( *poolchain ) * ( poolcount + 1 ));
pool = (mempool_t *)Q_malloc( sizeof( mempool_t ));
if( pool == NULL )
{
Sys_Error( "Mem_AllocPool: out of memory (allocpool at %s:%i)\n", filename, fileline );
return 0;
}
memset( pool, 0, sizeof( mempool_t ));
// fill header
pool->sentinel1 = MEMHEADER_SENTINEL1;
pool->sentinel2 = MEMHEADER_SENTINEL1;
pool->filename = filename;
pool->fileline = fileline;
pool->chain = NULL;
pool->totalsize = 0;
pool->realsize = sizeof( mempool_t );
Q_strncpy( pool->name, name, sizeof( pool->name ));
pool->next = poolchain;
poolchain = pool;
pool = &poolchain[poolcount++];
return Mem_InitPool( pool, name, filename, fileline );
#if XASH_64BIT
pool->idx = ++lastidx;
return pool->idx;
#else
return (poolhandle_t)pool;
#endif
}
void _Mem_FreePool( poolhandle_t *poolptr, const char *filename, int fileline )
{
mempool_t *pool;
mempool_t **chainaddress;
if( *poolptr && ( pool = Mem_FindPool( *poolptr )))
{
if( !pool->filename )
{
Sys_Error( "Mem_FreePool: pool already free (freepool at %s:%i)\n", filename, fileline );
*poolptr = 0;
return;
}
// unlink pool from chain
for( chainaddress = &poolchain; *chainaddress && *chainaddress != pool; chainaddress = &((*chainaddress)->next));
if( *chainaddress != pool ) Sys_Error( "Mem_FreePool: pool already free (freepool at %s:%i)\n", filename, fileline );
Mem_CheckPool( "Mem_FreePool", pool, filename, fileline );
*chainaddress = pool->next;
// free memory owned by the pool
while( pool->chain )
Mem_FreeBlock( pool->chain, filename, fileline );
while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
// free the pool itself
memset( pool, 0xBF, sizeof( mempool_t ));
pool->chain = NULL;
pool->filename = NULL; // mark as reusable
Q_free( pool );
*poolptr = 0;
}
}
void _Mem_EmptyPool( poolhandle_t poolptr, const char *filename, int fileline )
{
mempool_t *pool;
if( unlikely( !poolptr ))
{
Sys_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)\n", filename, fileline );
return;
}
mempool_t *pool = Mem_FindPool( poolptr );
if( !poolptr ) Sys_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)\n", filename, fileline );
pool = Mem_FindPool( poolptr );
if( !pool )
return;
Mem_CheckPool( "Mem_FreePool", pool, filename, fileline );
// free memory owned by the pool
while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
@@ -406,8 +412,7 @@ static qboolean Mem_CheckAlloc( mempool_t *pool, void *data )
else
{
// search all pools
size_t i;
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
for( pool = poolchain; pool; pool = pool->next )
{
if( Mem_CheckAlloc( pool, data ))
return true;
@@ -435,24 +440,23 @@ void _Mem_Check( const char *filename, int fileline )
{
memheader_t *mem;
mempool_t *pool;
size_t i;
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
for( pool = poolchain; pool; pool = pool->next )
Mem_CheckPool( "Mem_CheckSentinels", pool, filename, fileline );
for( pool = poolchain; pool; pool = pool->next )
for( mem = pool->chain; mem; mem = mem->next )
Mem_CheckAllocHeader( "Mem_CheckSentinels", mem, filename, fileline );
}
void Mem_PrintStats( void )
{
size_t count = 0, size = 0, realsize = 0, i;
size_t count = 0, size = 0, realsize = 0;
mempool_t *pool;
Mem_Check();
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
for( pool = poolchain; pool; pool = pool->next )
{
if( !pool->filename )
continue;
count++;
size += pool->totalsize;
realsize += pool->realsize;
@@ -466,19 +470,15 @@ void Mem_PrintList( size_t minallocationsize )
{
mempool_t *pool;
memheader_t *mem;
size_t i;
Mem_Check();
Con_Printf( "memory pool list:\n" );
Con_Printf( "\t^3size\t\t\t\tname\n");
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
for( pool = poolchain; pool; pool = pool->next )
{
long changed_size = (long)pool->totalsize - (long)pool->lastchecksize;
if( !pool->filename )
continue;
// poolnames can contain color symbols, make sure what color is reset
if( pool->lastchecksize != 0 && changed_size != 0 )
{

View File

@@ -50,10 +50,6 @@ GNU General Public License for more details.
#define LUMP_SAVE_NO_DATA 7
#define LUMP_SAVE_CORRUPTED 8
#ifndef ALLOC_CHECK
#define ALLOC_CHECK( x )
#endif
typedef struct areanode_s
{
int axis; // -1 = leaf node

View File

@@ -175,13 +175,11 @@ void Evdev_Autodetect_f( void )
if( evdev.devices >= MAX_EVDEV_DEVICES )
continue;
Q_snprintf( path, sizeof( path ), "/dev/input/%s", entry->d_name );
Q_snprintf( path, MAX_STRING, "/dev/input/%s", entry->d_name );
for( i = 0; i < evdev.devices; i++ )
{
if( !Q_strncmp( evdev.paths[i], path, sizeof( evdev.paths[i] ))
if( !Q_strncmp( evdev.paths[i], path, MAX_STRING ) )
goto next;
}
if( Q_strncmp( entry->d_name, "event", 5 ) )
continue;
@@ -222,7 +220,7 @@ void Evdev_Autodetect_f( void )
}
goto close;
open:
Q_strncpy( evdev.paths[evdev.devices], path, sizeof( evdev.paths[0] ));
Q_strncpy( evdev.paths[evdev.devices], path, MAX_STRING );
evdev.fds[evdev.devices++] = fd;
Con_Printf( "Opened device %s\n", path );
#if XASH_INPUT == INPUT_EVDEV
@@ -262,7 +260,7 @@ void Evdev_OpenDevice ( const char *path )
for( i = 0; i < evdev.devices; i++ )
{
if( !Q_strncmp( evdev.paths[i], path, sizeof( evdev.paths[i] )))
if( !Q_strncmp( evdev.paths[i], path, MAX_STRING ) )
{
Con_Printf( "device %s already open!\n", path );
return;
@@ -277,7 +275,7 @@ void Evdev_OpenDevice ( const char *path )
}
Con_Printf( "Input device #%d: %s opened sucessfully\n", evdev.devices, path );
evdev.fds[evdev.devices] = ret;
Q_strncpy( evdev.paths[evdev.devices++], path, sizeof( evdev.paths[0] ));
Q_strncpy( evdev.paths[evdev.devices++], path, MAX_STRING );
#if XASH_INPUT == INPUT_EVDEV
if( Sys_CheckParm( "-grab" ) )
@@ -311,7 +309,7 @@ void Evdev_CloseDevice_f ( void )
if( Q_isdigit( arg ) )
i = Q_atoi( arg );
else for( i = 0; i < evdev.devices; i++ )
if( !Q_strncmp( evdev.paths[i], arg, sizeof( evdev.paths[i] )))
if( !Q_strncmp( evdev.paths[i], arg, MAX_STRING ) )
break;
if( i >= evdev.devices )
@@ -326,7 +324,7 @@ void Evdev_CloseDevice_f ( void )
for( ; i < evdev.devices; i++ )
{
Q_strncpy( evdev.paths[i], evdev.paths[i+1], sizeof( evdev.paths[i] ));
Q_strncpy( evdev.paths[i], evdev.paths[i+1], MAX_STRING );
evdev.fds[i] = evdev.fds[i+1];
}
}

View File

@@ -111,11 +111,6 @@ void Linux_Init( void )
if( !Host_IsDedicated( ))
return;
// manpage says sd_notify will send messages to socket in NOTIFY_SOCKET
// environment variable. Check if it's available.
if( getenv( "NOTIFY_SOCKET" ) == NULL )
return;
if(( g_hsystemd = dlopen( "libsystemd.so.0", RTLD_LAZY )) == NULL )
return;

View File

@@ -148,6 +148,7 @@ static void SDLash_KeyEvent( SDL_KeyboardEvent key )
#else
int keynum = key.keysym.sym;
#endif
qboolean numLock = FBitSet( SDL_GetModState(), KMOD_NUM );
#if XASH_ANDROID
if( keynum == SDL_SCANCODE_VOLUMEUP || keynum == SDL_SCANCODE_VOLUMEDOWN )
@@ -156,39 +157,32 @@ static void SDLash_KeyEvent( SDL_KeyboardEvent key )
}
#endif
if( SDL_IsTextInputActive( ))
if( SDL_IsTextInputActive() && down && cls.key_dest != key_game )
{
// this is how engine understands ctrl+c, ctrl+v and other hotkeys
if( down && cls.key_dest != key_game )
if( FBitSet( SDL_GetModState(), KMOD_CTRL ))
{
if( FBitSet( SDL_GetModState(), KMOD_CTRL ))
if( keynum >= SDL_SCANCODE_A && keynum <= SDL_SCANCODE_Z )
{
if( keynum >= SDL_SCANCODE_A && keynum <= SDL_SCANCODE_Z )
{
keynum = keynum - SDL_SCANCODE_A + 1;
CL_CharEvent( keynum );
}
return;
keynum = keynum - SDL_SCANCODE_A + 1;
CL_CharEvent( keynum );
}
return;
}
#if SDL_VERSION_ATLEAST( 2, 0, 0 )
// ignore printable keys, they are coming through SDL_TEXTINPUT
if(( keynum >= SDL_SCANCODE_A && keynum <= SDL_SCANCODE_Z )
|| ( keynum >= SDL_SCANCODE_1 && keynum <= SDL_SCANCODE_0 )
|| ( keynum >= SDL_SCANCODE_KP_1 && keynum <= SDL_SCANCODE_KP_0 ))
return;
#else
#if !SDL_VERSION_ATLEAST( 2, 0, 0 )
if( keynum >= SDLK_KP0 && keynum <= SDLK_KP9 )
keynum -= SDLK_KP0 + '0';
if( isprint( keynum ))
if( isprint( keynum ) )
{
if( FBitSet( SDL_GetModState(), KMOD_SHIFT ))
{
keynum = Key_ToUpper( keynum );
}
CL_CharEvent( keynum );
return;
}
#endif
}
@@ -204,8 +198,6 @@ static void SDLash_KeyEvent( SDL_KeyboardEvent key )
else DECLARE_KEY_RANGE( SDL_SCANCODE_F1, SDL_SCANCODE_F12, K_F1 )
else
{
qboolean numLock = FBitSet( SDL_GetModState(), KMOD_NUM );
switch( keynum )
{
case SDL_SCANCODE_GRAVE: keynum = '`'; break;
@@ -357,17 +349,16 @@ SDLash_InputEvent
#if SDL_VERSION_ATLEAST( 2, 0, 0 )
static void SDLash_InputEvent( SDL_TextInputEvent input )
{
const char *text;
char *text;
VGui_ReportTextInput( input.text );
for( text = input.text; *text; text++ )
{
int ch = (byte)*text;
int ch;
// do not pass UTF-8 sequence into the engine, convert it here
if( !cls.accept_utf8 )
ch = Con_UtfProcessCharForce( ch );
if( !Q_stricmp( cl_charset.string, "utf-8" ) )
ch = (unsigned char)*text;
else
ch = Con_UtfProcessCharForce( (unsigned char)*text );
if( !ch )
continue;
@@ -457,7 +448,7 @@ SDLash_EventFilter
=============
*/
static void SDLash_EventHandler( SDL_Event *event )
static void SDLash_EventFilter( SDL_Event *event )
{
switch ( event->type )
{
@@ -688,7 +679,7 @@ void Platform_RunEvents( void )
SDL_Event event;
while( !host.crashed && !host.shutdown_issued && SDL_PollEvent( &event ) )
SDLash_EventHandler( &event );
SDLash_EventFilter( &event );
#if XASH_PSVITA
PSVita_InputUpdate();

View File

@@ -843,8 +843,6 @@ qboolean VID_CreateWindow( int width, int height, window_mode_t window_mode )
#else // SDL_VERSION_ATLEAST( 2, 0, 0 )
Uint32 flags = 0;
Q_strncpy( wndname, GI->title, sizeof( wndname ));
if( window_mode != WINDOW_MODE_WINDOWED )
SetBits( flags, SDL_FULLSCREEN|SDL_HWSURFACE );

View File

@@ -504,12 +504,12 @@ void Wcon_CreateConsole( void )
if( host.type == HOST_NORMAL )
{
Q_strncpy( s_wcd.title, XASH_ENGINE_NAME " " XASH_VERSION, sizeof( s_wcd.title ));
Q_strncpy( s_wcd.title, "Xash3D " XASH_VERSION, sizeof( s_wcd.title ));
Q_strncpy( s_wcd.log_path, "engine.log", sizeof( s_wcd.log_path ));
}
else // dedicated console
{
Q_strncpy( s_wcd.title, XASH_DEDICATED_SERVER_NAME " " XASH_VERSION, sizeof( s_wcd.title ));
Q_strncpy( s_wcd.title, "XashDS " XASH_VERSION, sizeof( s_wcd.title ));
Q_strncpy( s_wcd.log_path, "dedicated.log", sizeof( s_wcd.log_path ));
s_wcd.log_active = true; // always make log
}

View File

@@ -77,6 +77,7 @@ GNU General Public License for more details.
#define FWORLD_CUSTOM_SKYBOX BIT( 1 )
#define FWORLD_WATERALPHA BIT( 2 )
#define FWORLD_HAS_DELUXEMAP BIT( 3 )
#define FWORLD_HAS_MIRRORS BIT( 4 )
// special rendermode for screenfade modulate
// (probably will be expanded at some point)

View File

@@ -43,9 +43,10 @@ extern int SV_UPDATE_BACKUP;
#define SVF_MERGE_VISIBILITY BIT( 1 ) // we are do portal pass
// mapvalid flags
#define MAP_IS_EXIST BIT( 0 )
#define MAP_HAS_LANDMARK BIT( 2 )
#define MAP_INVALID_VERSION BIT( 3 )
#define MAP_IS_EXIST BIT( 0 )
#define MAP_HAS_SPAWNPOINT BIT( 1 )
#define MAP_HAS_LANDMARK BIT( 2 )
#define MAP_INVALID_VERSION BIT( 3 )
#define SV_SPAWN_TIME 0.1
@@ -329,8 +330,6 @@ typedef struct
int msg_realsize; // left in bytes
int msg_index; // for debug messages
int msg_dest; // msg destination ( MSG_ONE, MSG_ALL etc )
int msg_rewrite_index;
int msg_rewrite_pos;
qboolean msg_started; // to avoid recursive included messages
edict_t *msg_ent; // user message member entity
vec3_t msg_org; // user message member origin
@@ -394,10 +393,10 @@ typedef struct
//=============================================================================
extern server_static_t svs RENAME_SYMBOL( "svs_" ); // persistant server info
extern server_t sv RENAME_SYMBOL( "sv_" ); // local server
extern svgame_static_t svgame; // persistant game info
extern areanode_t sv_areanodes[]; // AABB dynamic tree
extern server_static_t svs; // persistant server info
extern server_t sv; // local server
extern svgame_static_t svgame; // persistant game info
extern areanode_t sv_areanodes[]; // AABB dynamic tree
extern convar_t mp_logecho;
extern convar_t mp_logfile;
@@ -475,7 +474,6 @@ extern convar_t sv_fullupdate_penalty_time;
extern convar_t sv_log_outofband;
extern convar_t sv_allow_autoaim;
extern convar_t sv_aim;
extern convar_t sv_allow_testpacket;
//===========================================================
//
@@ -483,7 +481,7 @@ extern convar_t sv_allow_testpacket;
//
void SV_FinalMessage( const char *message, qboolean reconnect );
void SV_KickPlayer( sv_client_t *cl, const char *fmt, ... ) _format( 2 );
void SV_DropClient( sv_client_t *cl, qboolean crash ) RENAME_SYMBOL( "SV_DropClient_" );
void SV_DropClient( sv_client_t *cl, qboolean crash );
void SV_UpdateMovevars( qboolean initialize );
int SV_ModelIndex( const char *name );
int SV_SoundIndex( const char *name );
@@ -504,7 +502,6 @@ void SV_ActivateServer( int runPhysics );
qboolean SV_SpawnServer( const char *server, const char *startspot, qboolean background );
model_t *SV_ModelHandle( int modelindex );
void SV_DeactivateServer( void );
void SV_FreeTestPacket( void );
//
// sv_phys.c
@@ -616,9 +613,11 @@ string_t SV_MakeString( const char *szValue );
const char *SV_GetString( string_t iString );
void SV_SetStringArrayMode( qboolean dynamic );
void SV_EmptyStringPool( void );
#ifdef XASH_64BIT
void SV_PrintStr64Stats_f( void );
#endif
sv_client_t *SV_ClientFromEdict( const edict_t *pEdict, qboolean spawned_only );
uint SV_MapIsValid( const char *filename, const char *landmark_name );
uint SV_MapIsValid( const char *filename, const char *spawn_entity, const char *landmark_name );
void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float attn, int flags, int pitch );
edict_t *SV_FindGlobalEntity( string_t classname, string_t globalname );
qboolean SV_CreateStaticEntity( struct sizebuf_s *msg, int index );
@@ -629,18 +628,12 @@ void SV_RestartAmbientSounds( void );
void SV_RestartDecals( void );
void SV_RestartStaticEnts( void );
int pfnDropToFloor( edict_t* e );
edict_t *SV_EdictNum( int n );
void SV_SetModel( edict_t *ent, const char *name );
int pfnDecalIndex( const char *m );
void SV_CreateDecal( sizebuf_t *msg, const float *origin, int decalIndex, int entityIndex, int modelIndex, int flags, float scale );
qboolean SV_RestoreCustomDecal( struct decallist_s *entry, edict_t *pEdict, qboolean adjacent );
static inline edict_t *SV_EdictNum( int n )
{
if( likely( n >= 0 && n < GI->max_edicts ))
return &svgame.edicts[n];
return NULL;
}
//
// sv_log.c
//

View File

@@ -108,7 +108,7 @@ static void SV_GetChallenge( netadr_t from )
if( i == MAX_CHALLENGES )
{
// this is the first time this client has asked for a challenge
svs.challenges[oldest].challenge = (COM_RandomLong( 0, 0x7FFF ) << 16) | COM_RandomLong( 0, 0xFFFF );
svs.challenges[oldest].challenge = (COM_RandomLong( 0, 0xFFFF ) << 16) | COM_RandomLong( 0, 0xFFFF );
svs.challenges[oldest].adr = from;
svs.challenges[oldest].time = host.realtime;
svs.challenges[oldest].connected = false;
@@ -417,7 +417,7 @@ static void SV_ConnectClient( netadr_t from )
newcl->userid = g_userid++; // create unique userid
newcl->state = cs_connected;
newcl->extensions = extensions & (NET_EXT_SPLITSIZE);
Q_strncpy( newcl->useragent, protinfo, sizeof( newcl->useragent ));
Q_strncpy( newcl->useragent, protinfo, MAX_INFO_STRING );
// reset viewentities (from previous level)
memset( newcl->viewentity, 0, sizeof( newcl->viewentity ));
@@ -852,7 +852,7 @@ static void SV_TestBandWidth( netadr_t from )
}
// quickly reject invalid packets
if( !sv_allow_testpacket.value || !svs.testpacket_buf ||
if( !svs.testpacket_buf ||
( packetsize <= FRAGMENT_MIN_SIZE ) ||
( packetsize > FRAGMENT_MAX_SIZE ))
{
@@ -1690,7 +1690,7 @@ static qboolean SV_New_f( sv_client_t *cl )
// server info string
MSG_BeginServerCmd( &msg, svc_stufftext );
MSG_WriteStringf( &msg, "fullserverinfo \"%s\"\n", svs.serverinfo );
MSG_WriteStringf( &msg, "fullserverinfo \"%s\"\n", SV_Serverinfo( ));
// collect the info about all the players and send to me
for( i = 0, cur = svs.clients; i < svs.maxclients; i++, cur++ )
@@ -2035,7 +2035,7 @@ static qboolean SV_Kill_f( sv_client_t *cl )
{
if( !SV_IsValidEdict( cl->edict ))
return true;
if( cl->state != cs_spawned )
{
SV_ClientPrintf( cl, "Can't suicide - not connected!\n" );
@@ -2424,7 +2424,7 @@ static qboolean SV_EntList_f( sv_client_t *cl )
// filter by string
if( Cmd_Argc() > 1 )
{
{
if( !Q_stricmpext( Cmd_Argv( 1 ), STRING( ent->v.classname ) ) && !Q_stricmpext( Cmd_Argv( 1 ), STRING( ent->v.targetname ) ) )
continue;
}

View File

@@ -169,11 +169,17 @@ SV_ValidateMap
check map for typically errors
==================
*/
static qboolean SV_ValidateMap( const char *pMapName )
static qboolean SV_ValidateMap( const char *pMapName, qboolean check_spawn )
{
char *spawn_entity;
int flags;
flags = SV_MapIsValid( pMapName, NULL );
// determine spawn entity classname
if( !check_spawn || (int)sv_maxclients.value <= 1 )
spawn_entity = GI->sp_entity;
else spawn_entity = GI->mp_entity;
flags = SV_MapIsValid( pMapName, spawn_entity, NULL );
if( FBitSet( flags, MAP_INVALID_VERSION ))
{
@@ -187,6 +193,12 @@ static qboolean SV_ValidateMap( const char *pMapName )
return false;
}
if( check_spawn && !FBitSet( flags, MAP_HAS_SPAWNPOINT ))
{
Con_Printf( S_ERROR "map %s doesn't have a valid spawnpoint\n", pMapName );
return false;
}
return true;
}
@@ -212,7 +224,7 @@ static void SV_Map_f( void )
Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
COM_StripExtension( mapname );
if( !SV_ValidateMap( mapname ))
if( !SV_ValidateMap( mapname, true ))
return;
Cvar_DirectSet( &sv_hostmap, mapname );
@@ -284,7 +296,7 @@ static void SV_MapBackground_f( void )
Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
COM_StripExtension( mapname );
if( !SV_ValidateMap( mapname ))
if( !SV_ValidateMap( mapname, false ))
return;
// background map is always run as singleplayer
@@ -334,7 +346,7 @@ static void SV_NextMap_f( void )
Cvar_DirectSet( &sv_hostmap, nextmap );
// found current point, check for valid
if( SV_ValidateMap( nextmap ))
if( SV_ValidateMap( nextmap, true ))
{
// found and valid
COM_LoadLevel( nextmap, false );
@@ -534,7 +546,7 @@ classic change level
*/
static void SV_ChangeLevel_f( void )
{
if( Cmd_Argc() < 2 ) // allow extra arguments, for compatibility
if( Cmd_Argc() != 2 )
{
Con_Printf( S_USAGE "changelevel <mapname>\n" );
return;
@@ -552,15 +564,13 @@ smooth change level
*/
static void SV_ChangeLevel2_f( void )
{
if( Cmd_Argc() < 2 ) // allow extra arguments, for compatibility
if( Cmd_Argc() != 3 )
{
Con_Printf( S_USAGE "changelevel2 <mapname> [landmark]\n" );
Con_Printf( S_USAGE "changelevel2 <mapname> <landmark>\n" );
return;
}
if( Cmd_Argc() == 2 ) // with single argument, behaves like usual changelevel
SV_QueueChangeLevel( Cmd_Argv( 1 ), NULL );
else SV_QueueChangeLevel( Cmd_Argv( 1 ), Cmd_Argv( 2 ));
SV_QueueChangeLevel( Cmd_Argv( 1 ), Cmd_Argv( 2 ));
}
/*
@@ -690,7 +700,7 @@ static void SV_ConSay_f( void )
}
p = Cmd_Args();
Q_strncpy( text, *p == '"' ? p + 1 : p, sizeof( text ));
Q_strncpy( text, *p == '"' ? p + 1 : p, MAX_SYSPATH );
if( *p == '"' )
{
@@ -753,7 +763,7 @@ static void SV_ServerInfo_f( void )
}
Info_SetValueForStarKey( svs.serverinfo, Cmd_Argv( 1 ), Cmd_Argv( 2 ), MAX_SERVERINFO_STRING );
SV_BroadcastCommand( "fullserverinfo \"%s\"\n", svs.serverinfo );
SV_BroadcastCommand( "fullserverinfo \"%s\"\n", SV_Serverinfo( ));
}
/*
@@ -1007,7 +1017,6 @@ void SV_InitOperatorCommands( void )
Cmd_AddCommand( "redirect", Rcon_Redirect_f, "force enable rcon redirection" );
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" );
if( host.type == HOST_NORMAL )
{
@@ -1046,7 +1055,6 @@ void SV_KillOperatorCommands( void )
Cmd_RemoveCommand( "redirect" );
Cmd_RemoveCommand( "logaddress" );
Cmd_RemoveCommand( "log" );
Cmd_RemoveCommand( "str64stats" );
if( host.type == HOST_NORMAL )
{

View File

@@ -811,17 +811,17 @@ static void SV_UpdateToReliableMessages( void )
continue; // reliables go to all connected or spawned
if( MSG_GetNumBytesWritten( &sv.reliable_datagram ) < MSG_GetNumBytesLeft( &cl->netchan.message ))
MSG_WriteBits( &cl->netchan.message, MSG_GetData( &sv.reliable_datagram ), MSG_GetNumBitsWritten( &sv.reliable_datagram ));
MSG_WriteBits( &cl->netchan.message, MSG_GetBuf( &sv.reliable_datagram ), MSG_GetNumBitsWritten( &sv.reliable_datagram ));
else Netchan_CreateFragments( &cl->netchan, &sv.reliable_datagram );
if( MSG_GetNumBytesWritten( &sv.datagram ) < MSG_GetNumBytesLeft( &cl->datagram ))
MSG_WriteBits( &cl->datagram, MSG_GetData( &sv.datagram ), MSG_GetNumBitsWritten( &sv.datagram ));
MSG_WriteBits( &cl->datagram, MSG_GetBuf( &sv.datagram ), MSG_GetNumBitsWritten( &sv.datagram ));
else Con_DPrintf( S_WARN "Ignoring unreliable datagram for %s, would overflow\n", cl->name );
if( FBitSet( cl->flags, FCL_HLTV_PROXY ))
{
if( MSG_GetNumBytesWritten( &sv.spec_datagram ) < MSG_GetNumBytesLeft( &cl->datagram ))
MSG_WriteBits( &cl->datagram, MSG_GetData( &sv.spec_datagram ), MSG_GetNumBitsWritten( &sv.spec_datagram ));
MSG_WriteBits( &cl->datagram, MSG_GetBuf( &sv.spec_datagram ), MSG_GetNumBitsWritten( &sv.spec_datagram ));
else Con_DPrintf( S_WARN "Ignoring spectator datagram for %s, would overflow\n", cl->name );
}
}

View File

@@ -30,13 +30,22 @@ GNU General Public License for more details.
static int GAME_EXPORT pfnModelIndex( const char *m );
// fatpvs stuff
static byte fatphs[(MAX_MAP_LEAFS+7)/8];
static byte clientpvs[(MAX_MAP_LEAFS+7)/8]; // for find client in PVS
static byte fatpvs[MAX_MAP_LEAFS/8];
static byte fatphs[MAX_MAP_LEAFS/8];
static byte clientpvs[MAX_MAP_LEAFS/8]; // for find client in PVS
static vec3_t viewPoint[MAX_CLIENTS];
// exports
typedef void (__cdecl *LINK_ENTITY_FUNC)( entvars_t *pev );
typedef void (__stdcall *GIVEFNPTRSTODLL)( enginefuncs_t* engfuncs, globalvars_t *pGlobals );
edict_t *SV_EdictNum( int n )
{
if(( n >= 0 ) && ( n < GI->max_edicts ))
return svgame.edicts + n;
return NULL;
}
#ifndef NDEBUG
qboolean SV_CheckEdict( const edict_t *e, const char *file, const int line )
{
@@ -141,6 +150,18 @@ char *SV_Serverinfo( void )
return svs.serverinfo;
}
/*
=============
SV_LocalInfo
get local infostring
=============
*/
static char *SV_Localinfo( void )
{
return svs.localinfo;
}
/*
=============
SV_AngleMod
@@ -247,6 +268,7 @@ SV_SetModel
void GAME_EXPORT SV_SetModel( edict_t *ent, const char *modelname )
{
char name[MAX_QPATH];
qboolean found = false;
model_t *mod;
int i = 1;
@@ -256,7 +278,7 @@ void GAME_EXPORT SV_SetModel( edict_t *ent, const char *modelname )
return;
}
if( !modelname || ((byte)modelname[0] ) <= ' ' )
if( !modelname || modelname[0] <= ' ' )
{
Con_Printf( S_WARN "SV_SetModel: null name\n" );
return;
@@ -337,12 +359,11 @@ static qboolean SV_CheckClientVisiblity( sv_client_t *cl, const byte *mask )
if( !mask ) return true; // GoldSrc rules
clientnum = cl - svs.clients;
VectorCopy( viewPoint[clientnum], vieworg );
// Invasion issues: wrong camera position received in ENGINE_SET_PVS
if( cl->pViewEntity )
if( cl->pViewEntity && !VectorCompare( vieworg, cl->pViewEntity->v.origin ))
VectorCopy( cl->pViewEntity->v.origin, vieworg );
else
VectorCopy( cl->edict->v.origin, vieworg );
leaf = Mod_PointInLeaf( vieworg, sv.worldmodel->nodes );
@@ -421,7 +442,7 @@ static int SV_Multicast( int dest, const vec3_t origin, const edict_t *ent, qboo
case MSG_PAS:
if( origin == NULL ) return false;
// NOTE: GoldSource not using PHS for singleplayer
Mod_FatPVS( origin, FATPHS_RADIUS, fatphs, world.fatbytes, false, ( svs.maxclients == 1 ), true );
Mod_FatPVS( origin, FATPHS_RADIUS, fatphs, world.fatbytes, false, ( svs.maxclients == 1 ));
mask = fatphs; // using the FatPVS like a PHS
break;
case MSG_PVS_R:
@@ -665,7 +686,7 @@ void SV_RestartAmbientSounds( void )
#if !XASH_DEDICATED // TODO: ???
// restart soundtrack
if( S_StreamGetCurrentState( curtrack, sizeof( curtrack ), looptrack, sizeof( looptrack ), &position ))
if( S_StreamGetCurrentState( curtrack, looptrack, &position ))
{
SV_StartMusic( curtrack, looptrack, position );
}
@@ -757,6 +778,7 @@ void SV_QueueChangeLevel( const char *level, const char *landname )
{
uint flags, smooth = false;
char mapname[MAX_QPATH];
char *spawn_entity;
// hold mapname to other place
Q_strncpy( mapname, level, sizeof( mapname ));
@@ -765,7 +787,12 @@ void SV_QueueChangeLevel( const char *level, const char *landname )
if( COM_CheckString( landname ))
smooth = true;
flags = SV_MapIsValid( mapname, landname );
// determine spawn entity classname
if( svs.maxclients == 1 )
spawn_entity = GI->sp_entity;
else spawn_entity = GI->mp_entity;
flags = SV_MapIsValid( mapname, spawn_entity, landname );
if( FBitSet( flags, MAP_INVALID_VERSION ))
{
@@ -799,6 +826,15 @@ void SV_QueueChangeLevel( const char *level, const char *landname )
return;
}
if( !smooth && !FBitSet( flags, MAP_HAS_SPAWNPOINT ))
{
if( sv_validate_changelevel.value )
{
Con_Printf( S_ERROR "changelevel: %s doesn't have a valid spawnpoint. Ignored.\n", mapname );
return;
}
}
// bad changelevel position invoke enables in one-way transition
if( sv.framecount < 15 )
{
@@ -828,6 +864,7 @@ void SV_WriteEntityPatch( const char *filename )
int lumpofs = 0, lumplen = 0;
byte buf[MAX_TOKEN]; // 1 kb
string bspfilename;
dheader_t *header;
dlump_t entities;
file_t *f;
@@ -838,6 +875,7 @@ void SV_WriteEntityPatch( const char *filename )
memset( buf, 0, MAX_TOKEN );
FS_Read( f, buf, MAX_TOKEN );
header = (dheader_t *)buf;
// check all the lumps and some other errors
if( !Mod_TestBmodelLumps( f, bspfilename, buf, true, &entities ))
@@ -877,6 +915,7 @@ static char *SV_ReadEntityScript( const char *filename, int *flags )
int lumpofs = 0, lumplen = 0;
byte buf[MAX_TOKEN];
char *ents = NULL;
dheader_t *header;
dlump_t entities;
size_t ft1, ft2;
file_t *f;
@@ -891,6 +930,7 @@ static char *SV_ReadEntityScript( const char *filename, int *flags )
SetBits( *flags, MAP_IS_EXIST );
memset( buf, 0, MAX_TOKEN );
FS_Read( f, buf, MAX_TOKEN );
header = (dheader_t *)buf;
// check all the lumps and some other errors
if( !Mod_TestBmodelLumps( f, bspfilename, buf, (host_developer.value) ? false : true, &entities ))
@@ -937,7 +977,7 @@ SV_MapIsValid
Validate map
==============
*/
uint SV_MapIsValid( const char *filename, const char *landmark_name )
uint SV_MapIsValid( const char *filename, const char *spawn_entity, const char *landmark_name )
{
uint flags = 0;
char *pfile;
@@ -953,27 +993,45 @@ uint SV_MapIsValid( const char *filename, const char *landmark_name )
need_landmark = COM_CheckString( landmark_name );
if( !need_landmark )
// g-cont. in-dev mode we can entering on map even without "info_player_start"
if( !need_landmark && host_developer.value )
{
// not transition
Mem_Free( ents );
return flags;
// skip spawnpoint checks in devmode
return (flags|MAP_HAS_SPAWNPOINT);
}
pfile = ents;
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )
{
if( !Q_strcmp( token, "targetname" ))
if( !Q_strcmp( token, "classname" ))
{
// check classname for spawn entity
pfile = COM_ParseFile( pfile, check_name, sizeof( check_name ));
if( !Q_strcmp( spawn_entity, check_name ))
{
SetBits( flags, MAP_HAS_SPAWNPOINT );
// we already find landmark, stop the parsing
if( need_landmark && FBitSet( flags, MAP_HAS_LANDMARK ))
break;
}
}
else if( need_landmark && !Q_strcmp( token, "targetname" ))
{
// check targetname for landmark entity
pfile = COM_ParseFile( pfile, check_name, sizeof( check_name ));
if( !Q_strcmp( landmark_name, check_name ))
{
// we found landmark, stop the parsing
SetBits( flags, MAP_HAS_LANDMARK );
break;
// we already find spawnpoint, stop the parsing
if( FBitSet( flags, MAP_HAS_SPAWNPOINT ))
break;
}
}
}
@@ -1116,22 +1174,15 @@ static LINK_ENTITY_FUNC SV_GetEntityClass( const char *pszClassName )
SV_AllocPrivateData
allocate private data for a given edict
if customentity is NULL, no "custom" entity EXPORT is being done
if customentity is not NULL, will be set to true if "custom" export
was used to create this entity
==============
*/
static edict_t* SV_AllocPrivateData( edict_t *ent, string_t className, qboolean *customentity )
static edict_t* SV_AllocPrivateData( edict_t *ent, string_t className )
{
const char *pszClassName;
LINK_ENTITY_FUNC SpawnEdict;
pszClassName = STRING( className );
if( customentity )
*customentity = false;
if( !ent )
{
// allocate a new one
@@ -1154,11 +1205,7 @@ static edict_t* SV_AllocPrivateData( edict_t *ent, string_t className, qboolean
if( svgame.physFuncs.SV_CreateEntity && svgame.physFuncs.SV_CreateEntity( ent, pszClassName ) != -1 )
return ent;
if( customentity )
{
SpawnEdict = SV_GetEntityClass( "custom" );
*customentity = SpawnEdict != NULL;
}
SpawnEdict = SV_GetEntityClass( "custom" );
if( !SpawnEdict )
{
@@ -1169,6 +1216,8 @@ static edict_t* SV_AllocPrivateData( edict_t *ent, string_t className, qboolean
return NULL;
}
SetBits( ent->v.flags, FL_CUSTOMENTITY ); // it's a custom entity but not a beam!
}
SpawnEdict( &ent->v );
@@ -1185,7 +1234,12 @@ create specified entity, alloc private data
*/
edict_t* SV_CreateNamedEntity( edict_t *ent, string_t className )
{
return SV_AllocPrivateData( ent, className, NULL );
edict_t *ed = SV_AllocPrivateData( ent, className );
// for some reasons this flag should be immediately cleared
if( ed ) ClearBits( ed->v.flags, FL_CUSTOMENTITY );
return ed;
}
/*
@@ -2500,62 +2554,6 @@ int GAME_EXPORT pfnDecalIndex( const char *m )
return -1;
}
static int SV_CanRewriteMessage( int msg_num )
{
// feature is disabled
if( !FBitSet( host.bugcomp, BUGCOMP_MESSAGE_REWRITE_FACILITY_FLAG ))
return 0;
switch( msg_num )
{
case svc_goldsrc_spawnstaticsound:
return svc_sound;
}
return 0;
}
static qboolean SV_RewriteMessage( void )
{
vec3_t origin;
const char *sample = NULL;
float vol, attn;
int ent, pitch, flags, idx;
int cmd;
MSG_SeekToBit( &sv.multicast, svgame.msg_rewrite_pos, SEEK_SET );
cmd = MSG_ReadCmd( &sv.multicast, NS_SERVER );
switch( cmd )
{
case svc_goldsrc_spawnstaticsound:
MSG_ReadVec3Coord( &sv.multicast, origin );
idx = MSG_ReadShort( &sv.multicast );
vol = MSG_ReadByte( &sv.multicast );
attn = MSG_ReadByte( &sv.multicast ) / 64.0f;
ent = MSG_ReadShort( &sv.multicast );
pitch = MSG_ReadByte( &sv.multicast );
flags = MSG_ReadByte( &sv.multicast );
if( FBitSet( flags, SND_SENTENCE ))
sample = va( "!%i", idx );
else if( idx >= 0 && idx < MAX_SOUNDS )
sample = sv.sound_precache[idx];
if( !COM_CheckString( sample ))
{
Con_Printf( S_ERROR "%s: unrecognized sample in svc_spawnstaticsound, index %d, flags 0x%x\n", __func__, idx, flags );
return false;
}
MSG_SeekToBit( &sv.multicast, svgame.msg_rewrite_pos, SEEK_SET );
return SV_BuildSoundMsg( &sv.multicast, EDICT_NUM( ent ), CHAN_STATIC, sample, vol, attn, flags, pitch, origin );
}
return false;
}
/*
=============
pfnMessageBegin
@@ -2573,24 +2571,10 @@ static void GAME_EXPORT pfnMessageBegin( int msg_dest, int msg_num, const float
// check range
msg_num = bound( svc_bad, msg_num, 255 );
svgame.msg_rewrite_index = 0;
svgame.msg_rewrite_pos = 0;
if( msg_num <= svc_lastmsg )
{
// check if we should rewrite this message into something else...
if( SV_CanRewriteMessage( msg_num ))
{
svgame.msg_index = -SV_CanRewriteMessage( msg_num );
svgame.msg_name = svc_goldsrc_strings[msg_num] ? svc_goldsrc_strings[msg_num] : svc_strings[msg_num];
svgame.msg_rewrite_index = msg_num;
svgame.msg_rewrite_pos = MSG_TellBit( &sv.multicast );
}
else
{
svgame.msg_index = -msg_num; // this is a system message
svgame.msg_name = svc_strings[msg_num];
}
svgame.msg_index = -msg_num; // this is a system message
svgame.msg_name = svc_strings[msg_num];
if( msg_num == svc_temp_entity )
iSize = -1; // temp entity have variable size
@@ -2665,25 +2649,6 @@ static void GAME_EXPORT pfnMessageEnd( void )
return;
}
if( svgame.msg_rewrite_index != 0 )
{
if( SV_RewriteMessage( ))
{
if( MSG_CheckOverflow( &sv.multicast ))
{
Con_Printf( S_ERROR "MessageEnd: %s has overflow multicast buffer (post-rewrite)\n", name );
MSG_Clear( &sv.multicast );
return;
}
}
else
{
Con_Printf( S_ERROR "MessageEnd: failed to rewrite message %s\n", name );
MSG_Clear( &sv.multicast );
return;
}
}
// check for system message
if( svgame.msg_index < 0 )
{
@@ -2750,7 +2715,9 @@ static void GAME_EXPORT pfnMessageEnd( void )
// update some messages in case their was format was changed and we want to keep backward compatibility
if( svgame.msg_index < 0 )
{
if(( svgame.msg_index == -svc_finale || svgame.msg_index == -svc_cutscene ) && svgame.msg_realsize == 0 )
int svc_msg = abs( svgame.msg_index );
if(( svc_msg == svc_finale || svc_msg == svc_cutscene ) && svgame.msg_realsize == 0 )
MSG_WriteChar( &sv.multicast, 0 ); // write null string
}
@@ -2884,10 +2851,8 @@ standard path to register game variable
static void GAME_EXPORT pfnCvar_RegisterServerVariable( cvar_t *variable )
{
if( variable != NULL )
{
SetBits( variable->flags, FCVAR_EXTDLL );
Cvar_RegisterVariable( (convar_t *)variable );
}
Cvar_RegisterVariable( (convar_t *)variable );
}
/*
@@ -3253,9 +3218,7 @@ string_t GAME_EXPORT SV_AllocString( const char *szValue )
{
char *newString = NULL;
uint len;
#ifdef XASH_64BIT
int cmp;
#endif
if( svgame.physFuncs.pfnAllocString != NULL )
{
@@ -3318,21 +3281,19 @@ string_t GAME_EXPORT SV_AllocString( const char *szValue )
#endif
}
#ifdef XASH_64BIT
void SV_PrintStr64Stats_f( void )
{
#ifdef XASH_64BIT
Con_Printf( "====================\n" );
Con_Printf( "64 bit string pool statistics\n" );
Con_Printf( "====================\n" );
Con_Printf( "string array size: %lu\n", str64.maxstringarray );
Con_Printf( "total alloc %lu\n", str64.totalalloc );
Con_Printf( "maximum array usage: %lu\n", str64.maxalloc );
Con_Printf( "overflow counter: %lu\n", str64.numoverflows );
Con_Printf( "dup string counter: %lu\n", str64.numdups );
#else
Con_Printf( "Not implemented\n" );
#endif
Msg( "====================\n" );
Msg( "64 bit string pool statistics\n" );
Msg( "====================\n" );
Msg( "string array size: %lu\n", str64.maxstringarray );
Msg( "total alloc %lu\n", str64.totalalloc );
Msg( "maximum array usage: %lu\n", str64.maxalloc );
Msg( "overflow counter: %lu\n", str64.numoverflows );
Msg( "dup string counter: %lu\n", str64.numdups );
}
#endif
/*
=============
@@ -3430,10 +3391,12 @@ pfnPEntityOfEntIndex
=============
*/
static edict_t *pfnPEntityOfEntIndexBroken( int iEntIndex )
static edict_t *pfnPEntityOfEntIndex( int iEntIndex )
{
// have to be bug-compatible with GoldSrc in this function
return SV_PEntityOfEntIndex( iEntIndex, false );
if( host.bugcomp == BUGCOMP_GOLDSRC )
return SV_PEntityOfEntIndex( iEntIndex, false );
return SV_PEntityOfEntIndex( iEntIndex, true );
}
/*
@@ -3774,9 +3737,9 @@ vaild map must contain one info_player_deatchmatch
*/
int GAME_EXPORT pfnIsMapValid( char *filename )
{
uint flags = SV_MapIsValid( filename, NULL );
uint flags = SV_MapIsValid( filename, GI->mp_entity, NULL );
if( FBitSet( flags, MAP_IS_EXIST ))
if( FBitSet( flags, MAP_IS_EXIST ) && FBitSet( flags, MAP_HAS_SPAWNPOINT ))
return true;
return false;
}
@@ -3910,11 +3873,11 @@ static char *GAME_EXPORT pfnGetInfoKeyBuffer( edict_t *e )
// NULL passes localinfo
if( !SV_IsValidEdict( e ))
return svs.localinfo;
return SV_Localinfo();
// world passes serverinfo
if( e == svgame.edicts )
return svs.serverinfo;
return SV_Serverinfo();
// userinfo for specified edict
if(( cl = SV_ClientFromEdict( e, false )) != NULL )
@@ -4156,7 +4119,7 @@ void GAME_EXPORT SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word
// setup pvs cluster for invoker
if( !FBitSet( flags, FEV_GLOBAL ))
{
Mod_FatPVS( pvspoint, FATPHS_RADIUS, fatphs, world.fatbytes, false, ( svs.maxclients == 1 ), true );
Mod_FatPVS( pvspoint, FATPHS_RADIUS, fatphs, world.fatbytes, false, ( svs.maxclients == 1 ));
mask = fatphs; // using the FatPVS like a PHS
}
@@ -4181,16 +4144,7 @@ void GAME_EXPORT SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word
continue;
}
// a1ba: GoldSrc never cleans up host_client pointer (similar to sv.current_client)
// so it's always points at some client and in singleplayer this check always succeedes
// in Xash, however, sv.current_client might be reset and set to NULL
// this is especially dangerous when weapons play events in Think functions
//
// IMHO, it doesn't make sense to me to compare it against current client when we have
// invoker edict pointer but to preserve behaviour check for them both
//
// if it breaks some mods, probably sv.current_client semantics must be reworked to match GoldSrc
if( FBitSet( flags, FEV_NOTHOST ) && ( cl == sv.current_client || cl->edict == pInvoker ) && FBitSet( cl->flags, FCL_LOCAL_WEAPONS ))
if( FBitSet( flags, FEV_NOTHOST ) && cl == sv.current_client && FBitSet( cl->flags, FCL_LOCAL_WEAPONS ))
continue; // will be played on client side
if( FBitSet( flags, FEV_HOSTONLY ) && cl->edict != pInvoker )
@@ -4277,16 +4231,43 @@ so we can't use a single PVS point
*/
static byte *GAME_EXPORT pfnSetFatPVS( const float *org )
{
static byte fatpvs[(MAX_MAP_LEAFS+7)/8];
qboolean fullvis = false, merge = false;
qboolean fullvis = false;
if( !sv.worldmodel->visdata || sv_novis.value || !org || CL_DisableVisibility( ))
fullvis = true;
if( FBitSet( sv.hostflags, SVF_MERGE_VISIBILITY ))
merge = true;
// portals can't change viewpoint!
if( !FBitSet( sv.hostflags, SVF_MERGE_VISIBILITY ))
{
vec3_t viewPos, offset;
qboolean client_active = pfnGetCurrentPlayer() != -1;
Mod_FatPVS( org, FATPVS_RADIUS, fatpvs, world.fatbytes, merge, fullvis, false );
// see code from client.cpp for understanding:
// org = pView->v.origin + pView->v.view_ofs;
// if ( pView->v.flags & FL_DUCKING )
// {
// org = org + ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN );
// }
// so we have unneeded duck calculations who have affect when player
// is ducked into water. Remove offset to restore right PVS position
if( client_active && FBitSet( sv.current_client->edict->v.flags, FL_DUCKING ))
{
VectorSubtract( svgame.pmove->player_mins[0], svgame.pmove->player_mins[1], offset );
VectorSubtract( org, offset, viewPos );
}
else VectorCopy( org, viewPos );
// build a new PVS frame
Mod_FatPVS( viewPos, FATPVS_RADIUS, fatpvs, world.fatbytes, false, fullvis );
if( client_active )
VectorCopy( viewPos, viewPoint[pfnGetCurrentPlayer()] );
}
else
{
// merge PVS
Mod_FatPVS( org, FATPVS_RADIUS, fatpvs, world.fatbytes, true, fullvis );
}
return fatpvs;
}
@@ -4301,15 +4282,40 @@ so we can't use a single PHS point
*/
static byte *GAME_EXPORT pfnSetFatPAS( const float *org )
{
qboolean fullvis = false, merge = false;
qboolean fullvis = false;
if( !sv.worldmodel->visdata || sv_novis.value || !org || CL_DisableVisibility( ))
fullvis = true;
if( FBitSet( sv.hostflags, SVF_MERGE_VISIBILITY ))
merge = true;
// portals can't change viewpoint!
if( !FBitSet( sv.hostflags, SVF_MERGE_VISIBILITY ))
{
vec3_t viewPos, offset;
qboolean client_active = pfnGetCurrentPlayer() != -1;
Mod_FatPVS( org, FATPHS_RADIUS, fatphs, world.fatbytes, merge, fullvis, true );
// see code from client.cpp for understanding:
// org = pView->v.origin + pView->v.view_ofs;
// if ( pView->v.flags & FL_DUCKING )
// {
// org = org + ( VEC_HULL_MIN - VEC_DUCK_HULL_MIN );
// }
// so we have unneeded duck calculations who have affect when player
// is ducked into water. Remove offset to restore right PVS position
if( client_active && FBitSet( sv.current_client->edict->v.flags, FL_DUCKING ))
{
VectorSubtract( svgame.pmove->player_mins[0], svgame.pmove->player_mins[1], offset );
VectorSubtract( org, offset, viewPos );
}
else VectorCopy( org, viewPos );
// build a new PHS frame
Mod_FatPVS( viewPos, FATPHS_RADIUS, fatphs, world.fatbytes, false, fullvis );
}
else
{
// merge PHS
Mod_FatPVS( org, FATPHS_RADIUS, fatphs, world.fatbytes, true, fullvis );
}
return fatphs;
}
@@ -4725,7 +4731,7 @@ static enginefuncs_t gEngfuncs =
pfnPEntityOfEntOffset,
pfnEntOffsetOfPEntity,
pfnIndexOfEdict,
pfnPEntityOfEntIndexAllEntities,
pfnPEntityOfEntIndex,
pfnFindEntityByVars,
pfnGetModelPtr,
pfnRegUserMsg,
@@ -4814,15 +4820,6 @@ static enginefuncs_t gEngfuncs =
pfnPEntityOfEntIndexAllEntities,
};
static void SV_FreeKeyValueStrings( KeyValueData *kvd, int numpairs )
{
for( int i = 0; i < numpairs; i++ )
{
Mem_Free( kvd[i].szKeyName );
Mem_Free( kvd[i].szValue );
}
}
/*
====================
SV_ParseEdict
@@ -4834,34 +4831,36 @@ ed should be a properly initialized empty edict.
static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
{
KeyValueData pkvd[256]; // per one entity
qboolean adjust_origin = false, customentity;
qboolean adjust_origin = false;
int i, numpairs = 0;
const char *classname = NULL;
char *classname = NULL;
char token[2048];
vec3_t origin;
// go through all the dictionary pairs
while( 1 )
{
string keyname;
char value[2048];
int len;
// parse key
if(( *pfile = COM_ParseFile( *pfile, keyname, sizeof( keyname ))) == NULL )
if(( *pfile = COM_ParseFile( *pfile, token, sizeof( token ))) == NULL )
Host_Error( "ED_ParseEdict: EOF without closing brace\n" );
if( token[0] == '}' ) break; // end of desc
if( keyname[0] == '}' )
break; // end of desc
Q_strncpy( keyname, token, sizeof( keyname ));
// parse value
if(( *pfile = COM_ParseFile( *pfile, value, sizeof( value ))) == NULL )
if(( *pfile = COM_ParseFile( *pfile, token, sizeof( token ))) == NULL )
Host_Error( "ED_ParseEdict: EOF without closing brace\n" );
if( value[0] == '}' )
if( token[0] == '}' )
Host_Error( "ED_ParseEdict: closing brace without data\n" );
// ignore attempts to set empty key or value
// ignore attempts to set key ""
if( !keyname[0] ) continue;
// "wad" field is already handled
if( !keyname[0] || !value[0] || !Q_strcmp( keyname, "wad" ))
if( !Q_strcmp( keyname, "wad" ))
continue;
// keynames with a leading underscore are used for
@@ -4869,83 +4868,57 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
if( FBitSet( world.flags, FWORLD_SKYSPHERE ) && keyname[0] == '_' )
continue;
// classname must be first
if( !Q_strcmp( keyname, "classname" ))
{
KeyValueData kvd = {
.szClassName = NULL,
.szKeyName = keyname,
.szValue = value,
.fHandled = false
};
// don't allow double classnames
if( classname != NULL )
continue;
svgame.dllFuncs.pfnKeyValue( ent, &kvd );
// ideally, all game dlls should handle classname.
// throw an error for now, improve the logic if it causes
// compatibility issues with Xash-based games
if( !kvd.fHandled )
Host_Error( "%s: game didn't handled \"%s\" classname\n", __func__, value );
// this lets game dll override custom entity classname
// to something bogus that's exported in game dll
classname = STRING( ent->v.classname );
continue;
}
// GoldSrc removes trailing spaces
// but does this after sucking out classname
// which doesn't have similar check
for( len = Q_strlen( keyname ); len > 0 && keyname[len - 1] == ' '; len-- )
keyname[len - 1] = '\0';
// ignore attempts to set value ""
if( !token[0] ) continue;
// create keyvalue strings
pkvd[numpairs].szClassName = (char*)""; // unknown at this moment
pkvd[numpairs].szKeyName = copystring( keyname );
pkvd[numpairs].szValue = copystring( value );
pkvd[numpairs].szValue = copystring( token );
pkvd[numpairs].fHandled = false;
numpairs++;
if( numpairs > ARRAYSIZE( pkvd ))
{
if( classname )
Con_Printf( S_ERROR "%s: too many keyvalue pairs for %s!\n", __func__, classname );
else Con_Printf( S_ERROR "%s: too many keyvalue pairs!\n", __func__ );
break;
}
if( !Q_strcmp( keyname, "classname" ) && classname == NULL )
classname = copystring( pkvd[numpairs].szValue );
if( ++numpairs >= 256 ) break;
}
if( classname == NULL )
{
// release allocated strings
SV_FreeKeyValueStrings( pkvd, numpairs );
for( i = 0; i < numpairs; i++ )
{
Mem_Free( pkvd[i].szKeyName );
Mem_Free( pkvd[i].szValue );
}
return false;
}
ent = SV_AllocPrivateData( ent, ent->v.classname, &customentity );
ent = SV_AllocPrivateData( ent, ALLOC_STRING( classname ));
if( !SV_IsValidEdict( ent ) || FBitSet( ent->v.flags, FL_KILLME ))
{
// release allocated strings
SV_FreeKeyValueStrings( pkvd, numpairs );
for( i = 0; i < numpairs; i++ )
{
Mem_Free( pkvd[i].szKeyName );
Mem_Free( pkvd[i].szValue );
}
return false;
}
if( customentity )
if( FBitSet( ent->v.flags, FL_CUSTOMENTITY ))
{
KeyValueData kvd = {
.szClassName = (char *)"custom",
.szKeyName = (char *)"customclass",
.szValue = (char *)classname,
.fHandled = false
};
if( numpairs < 256 )
{
pkvd[numpairs].szClassName = (char*)"custom";
pkvd[numpairs].szKeyName = (char*)"customclass";
pkvd[numpairs].szValue = classname;
pkvd[numpairs].fHandled = false;
numpairs++;
}
svgame.dllFuncs.pfnKeyValue( ent, &kvd );
// no fHandled check, GoldSrc behavior
// clear it now - no longer used
ClearBits( ent->v.flags, FL_CUSTOMENTITY );
}
#ifdef HACKS_RELATED_HLMODS
@@ -4959,14 +4932,6 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
for( i = 0; i < numpairs; i++ )
{
char *keyname, *value;
char temp[MAX_VA_STRING];
#if 0 // this is stupid bug in GoldSrc, disable
if( !Q_strcmp( pkvd[i].szValue, classname ))
continue;
#endif
if( !Q_strcmp( pkvd[i].szKeyName, "angle" ))
{
float flYawAngle = Q_atof( pkvd[i].szValue );
@@ -4977,6 +4942,8 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
if( flYawAngle >= 0.0f )
{
char temp[MAX_VA_STRING];
Q_snprintf( temp, sizeof( temp ), "%g %g %g", ent->v.angles[0], flYawAngle, ent->v.angles[2] );
pkvd[i].szValue = copystring( temp );
}
@@ -4987,10 +4954,11 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
else pkvd[i].szValue = copystring( "0 0 0" ); // technically an error
}
#ifdef HACKS_RELATED_HLMODS
if( adjust_origin && !Q_strcmp( pkvd[i].szKeyName, "origin" ))
{
char *pstart = pkvd[i].szValue;
vec3_t origin;
char temp[MAX_VA_STRING];
char *pstart = pkvd[i].szValue;
COM_ParseVector( &pstart, origin, 3 );
Mem_Free( pkvd[i].szValue ); // release old value, so we don't need these
@@ -4998,18 +4966,24 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
Q_snprintf( temp, sizeof( temp ), "%g %g %g", origin[0], origin[1], origin[2] - 16.0f );
pkvd[i].szValue = copystring( temp );
}
#endif
if( !pkvd[i].fHandled )
{
pkvd[i].szClassName = classname;
svgame.dllFuncs.pfnKeyValue( ent, &pkvd[i] );
}
// do not leak memory if game overwritten these pointers
keyname = pkvd[i].szKeyName;
value = pkvd[i].szValue;
// no reason to keep this data
if( Mem_IsAllocatedExt( host.mempool, pkvd[i].szKeyName ))
Mem_Free( pkvd[i].szKeyName );
pkvd[i].szClassName = (char *)classname;
svgame.dllFuncs.pfnKeyValue( ent, &pkvd[i] );
Mem_Free( keyname );
Mem_Free( value );
if( Mem_IsAllocatedExt( host.mempool, pkvd[i].szValue ))
Mem_Free( pkvd[i].szValue );
}
if( Mem_IsAllocatedExt( host.mempool, classname ))
Mem_Free( classname );
return true;
}
@@ -5128,6 +5102,8 @@ void SV_UnloadProgs( void )
/// SV_UnloadProgs will be disabled
//Mod_ClearUserData ();
SV_FreeStringPool();
if( svgame.dllFuncs2.pfnGameShutdown != NULL )
svgame.dllFuncs2.pfnGameShutdown ();
@@ -5148,8 +5124,6 @@ void SV_UnloadProgs( void )
Cvar_Unlink( FCVAR_EXTDLL );
Cmd_Unlink( CMD_SERVERDLL );
SV_FreeStringPool();
Mod_ResetStudioAPI ();
COM_FreeLibrary( svgame.hInstance );
@@ -5196,11 +5170,6 @@ qboolean SV_LoadProgs( const char *name )
// make sure what physic functions is cleared
memset( &svgame.physFuncs, 0, sizeof( svgame.physFuncs ));
// revert fix for pfnPEntityOfEntIndex to be compatible with GoldSrc
// games that rely on this bug
if( FBitSet( host.bugcomp, BUGCOMP_PENTITYOFENTINDEX_FLAG ))
gEngfuncs.pfnPEntityOfEntIndex = pfnPEntityOfEntIndexBroken;
// make local copy of engfuncs to prevent overwrite it with bots.dll
memcpy( &gpEngfuncs, &gEngfuncs, sizeof( gpEngfuncs ));
@@ -5213,7 +5182,7 @@ qboolean SV_LoadProgs( const char *name )
COM_FreeLibrary( svgame.hInstance );
Con_Printf( S_ERROR "SV_LoadProgs: failed to get address of GetEntityAPI proc\n" );
svgame.hInstance = NULL;
Mem_FreePool( &svgame.mempool );
Mem_FreePool(&svgame.mempool);
return false;
}
@@ -5224,7 +5193,7 @@ qboolean SV_LoadProgs( const char *name )
COM_FreeLibrary( svgame.hInstance );
Con_Printf( S_ERROR "SV_LoadProgs: failed to get address of GiveFnptrsToDll proc\n" );
svgame.hInstance = NULL;
Mem_FreePool( &svgame.mempool );
Mem_FreePool(&svgame.mempool);
return false;
}
@@ -5249,8 +5218,7 @@ qboolean SV_LoadProgs( const char *name )
{
if( !GetEntityAPI2( &svgame.dllFuncs, &version ))
{
if( INTERFACE_VERSION != version )
Con_Printf( S_WARN "SV_LoadProgs: interface version %i should be %i\n", INTERFACE_VERSION, version );
Con_Printf( S_WARN "SV_LoadProgs: interface version %i should be %i\n", INTERFACE_VERSION, version );
// fallback to old API
if( !GetEntityAPI( &svgame.dllFuncs, version ))
@@ -5258,10 +5226,9 @@ qboolean SV_LoadProgs( const char *name )
COM_FreeLibrary( svgame.hInstance );
Con_Printf( S_ERROR "SV_LoadProgs: couldn't get entity API\n" );
svgame.hInstance = NULL;
Mem_FreePool( &svgame.mempool );
Mem_FreePool(&svgame.mempool);
return false;
}
else Con_Reportf( "SV_LoadProgs: ^2initailized legacy EntityAPI ^7ver. %i\n", version );
}
else Con_Reportf( "SV_LoadProgs: ^2initailized extended EntityAPI ^7ver. %i\n", version );
}
@@ -5270,10 +5237,9 @@ qboolean SV_LoadProgs( const char *name )
COM_FreeLibrary( svgame.hInstance );
Con_Printf( S_ERROR "SV_LoadProgs: couldn't get entity API\n" );
svgame.hInstance = NULL;
Mem_FreePool( &svgame.mempool );
Mem_FreePool(&svgame.mempool);
return false;
}
else Con_Reportf( "SV_LoadProgs: ^2initailized legacy EntityAPI ^7ver. %i\n", version );
SV_InitOperatorCommands();
Mod_InitStudioAPI();

View File

@@ -906,21 +906,6 @@ qboolean CRC32_MapFile( dword *crcvalue, const char *filename, qboolean multipla
return 1;
}
void SV_FreeTestPacket( void )
{
if( svs.testpacket_buf )
{
Mem_Free( svs.testpacket_buf );
svs.testpacket_buf = NULL;
}
if( svs.testpacket_crcs )
{
Mem_Free( svs.testpacket_crcs );
svs.testpacket_crcs = NULL;
}
}
/*
================
SV_GenerateTestPacket
@@ -932,13 +917,7 @@ static void SV_GenerateTestPacket( void )
uint32_t crc;
file_t *file;
byte *filepos;
int i;
if( !sv_allow_testpacket.value )
{
SV_FreeTestPacket();
return;
}
int i, filesize;
// testpacket already generated once, exit
// testpacket and lookup table takes ~300k of memory
@@ -1066,7 +1045,9 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean ba
// make cvars consistant
if( coop.value ) Cvar_SetValue( "deathmatch", 0 );
current_skill = Q_rint( skill.value );
#if 0 // a1ba: don't limit the skill, it's limited in game rules anyway
current_skill = bound( 0, current_skill, 3 );
#endif
Cvar_SetValue( "skill", (float)current_skill );
// enforce hpk_maxsize

View File

@@ -77,7 +77,7 @@ void Log_Open( void )
if( fp ) svs.log.file = fp;
Log_Printf( "Log file started (file \"%s\") (game \"%s\") (version \"%i/" XASH_VERSION "/%d\")\n",
szTestFile, Info_ValueForKey( svs.serverinfo, "*gamedir" ), PROTOCOL_VERSION, Q_buildnum() );
szTestFile, Info_ValueForKey( SV_Serverinfo(), "*gamedir" ), PROTOCOL_VERSION, Q_buildnum() );
}
void Log_Close( void )

View File

@@ -48,7 +48,7 @@ CVAR_DEFINE_AUTO( sv_proxies, "1", FCVAR_SERVER, "maximum count of allowed proxi
CVAR_DEFINE_AUTO( sv_send_logos, "1", 0, "send custom decal logo to other players so they can view his too" );
CVAR_DEFINE_AUTO( sv_send_resources, "1", 0, "allow to download missed resources for players" );
CVAR_DEFINE_AUTO( sv_logbans, "0", 0, "print into the server log info about player bans" );
CVAR_DEFINE( sv_allow_upload, "sv_allowupload", "1", FCVAR_SERVER, "allow uploading custom resources on a server" );
CVAR_DEFINE_AUTO( sv_allow_upload, "1", FCVAR_SERVER, "allow uploading custom resources on a server" );
CVAR_DEFINE( sv_allow_download, "sv_allowdownload", "1", FCVAR_SERVER, "allow downloading custom resources to the client" );
static CVAR_DEFINE_AUTO( sv_allow_dlfile, "1", 0, "compatibility cvar, does nothing" );
CVAR_DEFINE_AUTO( sv_uploadmax, "0.5", FCVAR_SERVER, "max size to upload custom resources (500 kB as default)" );
@@ -150,8 +150,6 @@ CVAR_DEFINE_AUTO( sv_userinfo_penalty_attempts, "4", FCVAR_ARCHIVE, "if max atte
CVAR_DEFINE_AUTO( sv_fullupdate_penalty_time, "1", FCVAR_ARCHIVE, "allow fullupdate command only once in this timewindow (set 0 to disable)" );
CVAR_DEFINE_AUTO( sv_log_outofband, "0", FCVAR_ARCHIVE, "log out of band messages, can be useful for server admins and for engine debugging" );
CVAR_DEFINE_AUTO( sv_allow_testpacket, "1", FCVAR_ARCHIVE, "allow generating and sending a big blob of data to test maximum packet size" );
//============================================================================
/*
================
@@ -975,7 +973,6 @@ void SV_Init( void )
Cvar_RegisterVariable( &sv_userinfo_penalty_attempts );
Cvar_RegisterVariable( &sv_fullupdate_penalty_time );
Cvar_RegisterVariable( &sv_log_outofband );
Cvar_RegisterVariable( &sv_allow_testpacket );
// when we in developer-mode automatically turn cheats on
if( host_developer.value ) Cvar_SetValue( "sv_cheats", 1.0f );
@@ -1118,9 +1115,6 @@ void SV_Shutdown( const char *finalmsg )
SV_FreeClients();
svs.maxclients = 0;
// release test packet blob
SV_FreeTestPacket();
// release all models
Mod_FreeAll();

View File

@@ -802,7 +802,7 @@ static trace_t SV_PushEntity( edict_t *ent, const vec3_t lpush, const vec3_t apu
if( ent->v.movetype == MOVETYPE_FLYMISSILE )
type = MOVE_MISSILE;
else if( ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT )
else if( ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT || ent->v.solid == SOLID_GIB )
type = MOVE_NOMONSTERS; // only clip against bmodels
else type = MOVE_NORMAL;
@@ -878,7 +878,7 @@ static qboolean SV_CanBlock( edict_t *ent )
if( ent->v.mins[0] == ent->v.maxs[0] )
return false;
if( ent->v.solid == SOLID_NOT || ent->v.solid == SOLID_TRIGGER )
if( ent->v.solid == SOLID_NOT || ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_GIB )
{
// clear bounds for deadbody
ent->v.mins[0] = ent->v.mins[1] = 0;

Some files were not shown because too many files have changed in this diff Show More