mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-05 19:45:05 +08:00
Compare commits
85 Commits
continuous
...
continuous
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1677835b45 | ||
|
|
2f2780cb1b | ||
|
|
95b134b5a6 | ||
|
|
f60e856f35 | ||
|
|
2ec0d25d85 | ||
|
|
fcd0982524 | ||
|
|
6881ee742d | ||
|
|
f070bbef3c | ||
|
|
dd8c66d90e | ||
|
|
f995d055b5 | ||
|
|
fed65dd497 | ||
|
|
c896425ad9 | ||
|
|
4107bd4e0f | ||
|
|
156b2b2b10 | ||
|
|
13a063bf7d | ||
|
|
ef786b7d79 | ||
|
|
5c0c1b1226 | ||
|
|
d041b2aa27 | ||
|
|
f6d489e038 | ||
|
|
d34fedea69 | ||
|
|
80b3f90091 | ||
|
|
2a4fafc3f9 | ||
|
|
9b3ccf5f04 | ||
|
|
f59ac2360a | ||
|
|
ff21fb42e6 | ||
|
|
288cac69de | ||
|
|
2640b6d869 | ||
|
|
d8910b0e38 | ||
|
|
049bed555e | ||
|
|
fe5944720b | ||
|
|
665c46b281 | ||
|
|
975ab6785e | ||
|
|
6fa4dbfba2 | ||
|
|
0506a1dfce | ||
|
|
908a9930e6 | ||
|
|
7d7e72196b | ||
|
|
7cc67157e5 | ||
|
|
b7ff9c7a24 | ||
|
|
aab1fa1ba2 | ||
|
|
effeba2f44 | ||
|
|
e039ef35c0 | ||
|
|
599a1f026e | ||
|
|
39cba17f01 | ||
|
|
17e106f96d | ||
|
|
081cf9132b | ||
|
|
6a7e027248 | ||
|
|
27100e7751 | ||
|
|
75d9ed341a | ||
|
|
1a0867523d | ||
|
|
7584bbe47e | ||
|
|
505b6cc264 | ||
|
|
24f23908be | ||
|
|
43bd73f37b | ||
|
|
bb2753cbfc | ||
|
|
5568eccc8a | ||
|
|
c3b2cc4423 | ||
|
|
d84130219f | ||
|
|
d97d4d6c42 | ||
|
|
15798aaf52 | ||
|
|
e53892e827 | ||
|
|
cb12af69ed | ||
|
|
e82050a4bc | ||
|
|
e4edd2da45 | ||
|
|
4f80922358 | ||
|
|
ae7ed03376 | ||
|
|
c082e46662 | ||
|
|
b0bbcab6b4 | ||
|
|
0fc83080ec | ||
|
|
73883b504f | ||
|
|
8efc9d74e8 | ||
|
|
373321ff00 | ||
|
|
a508467aac | ||
|
|
abbe993e80 | ||
|
|
c644e4d569 | ||
|
|
c200e008f1 | ||
|
|
e95a2da6d0 | ||
|
|
8afca1a79c | ||
|
|
827c9ca857 | ||
|
|
2416635ba3 | ||
|
|
39eec89580 | ||
|
|
98d88266a6 | ||
|
|
0f3359fc05 | ||
|
|
6c77608c34 | ||
|
|
abdff6eff6 | ||
|
|
95a75465c9 |
15
.cirrus.yml
15
.cirrus.yml
@@ -1,16 +1,3 @@
|
||||
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:
|
||||
@@ -26,7 +13,7 @@ task:
|
||||
task:
|
||||
name: freebsd-14-amd64
|
||||
freebsd_instance:
|
||||
image_family: freebsd-14-0-snap
|
||||
image_family: freebsd-14-0
|
||||
setup_script:
|
||||
- pkg update
|
||||
- pkg install -y pkgconf git sdl2 python fontconfig opus
|
||||
|
||||
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
custom: https://github.com/FWGS/xash3d-fwgs/blob/master/Documentation/donate.md
|
||||
2
3rdparty/gl4es/gl4es
vendored
2
3rdparty/gl4es/gl4es
vendored
Submodule 3rdparty/gl4es/gl4es updated: 5226f5f937...e39434a2b1
2
3rdparty/mainui
vendored
2
3rdparty/mainui
vendored
Submodule 3rdparty/mainui updated: da084b47f6...f5497ceb04
2
3rdparty/nanogl
vendored
2
3rdparty/nanogl
vendored
Submodule 3rdparty/nanogl updated: f48735b730...e75792de03
21
Documentation/environment-variables.md
Normal file
21
Documentation/environment-variables.md
Normal file
@@ -0,0 +1,21 @@
|
||||
## 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 |
|
||||
@@ -534,5 +534,14 @@ typedef struct
|
||||
#define MAX_EFRAGS 8192 // Arcane Dimensions required
|
||||
#define MAX_REQUESTS 64
|
||||
|
||||
#if ! XASH_64BIT
|
||||
STATIC_ASSERT( sizeof( mextrasurf_t ) == 324, "mextrasurf_t unexpected size" );
|
||||
STATIC_ASSERT( sizeof( decal_t ) == 60, "decal_t unexpected size");
|
||||
STATIC_ASSERT( sizeof( mfaceinfo_t ) == 176, "mfaceinfo_t unexpected size");
|
||||
#else
|
||||
STATIC_ASSERT( sizeof( mextrasurf_t) == 496, "mextrasurf_t unexpected size");
|
||||
STATIC_ASSERT( sizeof( decal_t ) == 88, "decal_t unexpected size");
|
||||
STATIC_ASSERT( sizeof( mfaceinfo_t ) == 304, "mfaceinfo_t unexpected size");
|
||||
#endif
|
||||
|
||||
#endif//COM_MODEL_H
|
||||
|
||||
@@ -86,8 +86,6 @@ typedef uint64_t longtime_t;
|
||||
#define NORETURN __attribute__((noreturn))
|
||||
#define NONNULL __attribute__((nonnull))
|
||||
#define ALLOC_CHECK(x) __attribute__((alloc_size(x)))
|
||||
#define FORCEINLINE inline __attribute__((always_inline))
|
||||
#define NOINLINE __attribute__((noinline))
|
||||
#elif defined(_MSC_VER)
|
||||
#define EXPORT __declspec( dllexport )
|
||||
#define GAME_EXPORT
|
||||
@@ -95,8 +93,6 @@ typedef uint64_t longtime_t;
|
||||
#define NORETURN
|
||||
#define NONNULL
|
||||
#define ALLOC_CHECK(x)
|
||||
#define FORCEINLINE __forceinline
|
||||
#define NOINLINE __declspec( noinline )
|
||||
#else
|
||||
#define EXPORT
|
||||
#define GAME_EXPORT
|
||||
@@ -104,8 +100,6 @@ typedef uint64_t longtime_t;
|
||||
#define NORETURN
|
||||
#define NONNULL
|
||||
#define ALLOC_CHECK(x)
|
||||
#define FORCEINLINE
|
||||
#define NOINLINE
|
||||
#endif
|
||||
|
||||
#if ( __GNUC__ >= 3 )
|
||||
|
||||
@@ -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( kRenderNormal );
|
||||
ref.dllFuncs.GL_SetRenderMode( kRenderTransAlpha );
|
||||
SPR_DrawGeneric( frame, x, y, -1, -1, prc );
|
||||
}
|
||||
|
||||
@@ -1713,7 +1713,8 @@ 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" ))
|
||||
if( !Q_stricmp( szName, "motdfile" )
|
||||
|| !Q_stricmp( szName, "sensitivity" ))
|
||||
flags |= FCVAR_PRIVILEGED;
|
||||
|
||||
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_CLIENTDLL, Cvar_BuildAutoDescription( szName, flags|FCVAR_CLIENTDLL ));
|
||||
|
||||
@@ -28,7 +28,6 @@ GNU General Public License for more details.
|
||||
#define MAX_CMD_BUFFER 8000
|
||||
#define CONNECTION_PROBLEM_TIME 15.0 // 15 seconds
|
||||
#define CL_CONNECTION_RETRIES 10
|
||||
#define CL_TEST_RETRIES_NORESPONCE 3
|
||||
#define CL_TEST_RETRIES 5
|
||||
|
||||
CVAR_DEFINE_AUTO( mp_decals, "300", FCVAR_ARCHIVE, "decals limit in multiplayer" );
|
||||
@@ -1072,6 +1071,22 @@ static void CL_SendConnectPacket( void )
|
||||
cls.timestart = Sys_DoubleTime();
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_GetTestFragmentSize
|
||||
|
||||
Returns bandwidth test fragment size
|
||||
=================
|
||||
*/
|
||||
static int CL_GetTestFragmentSize( void )
|
||||
{
|
||||
const int fragmentSizes[CL_TEST_RETRIES] = { 64000, 32000, 10666, 5200, 1400 };
|
||||
if( cls.connect_retry >= 0 && cls.connect_retry < CL_TEST_RETRIES )
|
||||
return bound( FRAGMENT_MIN_SIZE, fragmentSizes[cls.connect_retry], FRAGMENT_MAX_SIZE );
|
||||
else
|
||||
return FRAGMENT_MIN_SIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_CheckForResend
|
||||
@@ -1083,8 +1098,9 @@ static void CL_CheckForResend( void )
|
||||
{
|
||||
netadr_t adr;
|
||||
net_gai_state_t res;
|
||||
float resendTime;
|
||||
qboolean bandwidthTest;
|
||||
|
||||
|
||||
if( cls.internetservers_wait )
|
||||
CL_SendMasterServerScanRequest();
|
||||
|
||||
@@ -1110,7 +1126,10 @@ static void CL_CheckForResend( void )
|
||||
else if( cl_resend.value > CL_MAX_RESEND_TIME )
|
||||
Cvar_SetValue( "cl_resend", CL_MAX_RESEND_TIME );
|
||||
|
||||
if(( host.realtime - cls.connect_time ) < cl_resend.value )
|
||||
bandwidthTest = !cls.legacymode && cl_test_bandwidth.value && cls.connect_retry <= CL_TEST_RETRIES;
|
||||
resendTime = bandwidthTest ? 1.0f : cl_resend.value;
|
||||
|
||||
if(( host.realtime - cls.connect_time ) < resendTime )
|
||||
return;
|
||||
|
||||
res = NET_StringToAdrNB( cls.servername, &adr );
|
||||
@@ -1137,10 +1156,11 @@ static void CL_CheckForResend( void )
|
||||
|
||||
if( adr.port == 0 ) adr.port = MSG_BigShort( PORT_SERVER );
|
||||
|
||||
if( cls.connect_retry == CL_TEST_RETRIES_NORESPONCE )
|
||||
if( cls.connect_retry == CL_TEST_RETRIES )
|
||||
{
|
||||
// too many fails use default connection method
|
||||
Con_Printf( "hi-speed connection is failed, use default method\n" );
|
||||
Con_Printf( "Bandwidth test failed, fallback to default connecting method\n" );
|
||||
Con_Printf( "Connecting to %s... (retry #%i)\n", cls.servername, cls.connect_retry + 1 );
|
||||
Netchan_OutOfBandPrint( NS_CLIENT, adr, "getchallenge\n" );
|
||||
Cvar_SetValue( "cl_dlmax", FRAGMENT_MIN_SIZE );
|
||||
cls.connect_time = host.realtime;
|
||||
@@ -1148,16 +1168,15 @@ static void CL_CheckForResend( void )
|
||||
return;
|
||||
}
|
||||
|
||||
bandwidthTest = !cls.legacymode && cl_test_bandwidth.value;
|
||||
cls.serveradr = adr;
|
||||
cls.max_fragment_size = Q_min( FRAGMENT_MAX_SIZE, cls.max_fragment_size / (cls.connect_retry + 1));
|
||||
cls.max_fragment_size = CL_GetTestFragmentSize();
|
||||
cls.connect_time = host.realtime; // for retransmit requests
|
||||
cls.connect_retry++;
|
||||
|
||||
if( bandwidthTest )
|
||||
Con_Printf( "Connecting to %s... [retry #%i, max fragment size %i]\n", cls.servername, cls.connect_retry, cls.max_fragment_size );
|
||||
Con_Printf( "Connecting to %s... (retry #%i, fragment size %i)\n", cls.servername, cls.connect_retry, cls.max_fragment_size );
|
||||
else
|
||||
Con_Printf( "Connecting to %s... [retry #%i]\n", cls.servername, cls.connect_retry );
|
||||
Con_Printf( "Connecting to %s... (retry #%i)\n", cls.servername, cls.connect_retry );
|
||||
|
||||
if( bandwidthTest )
|
||||
Netchan_OutOfBandPrint( NS_CLIENT, adr, "bandwidth %i %i\n", PROTOCOL_VERSION, cls.max_fragment_size );
|
||||
|
||||
@@ -795,25 +795,14 @@ static void CL_SetupPMove( playermove_t *pmove, const local_state_t *from, const
|
||||
|
||||
pmove->player_index = ps->number - 1;
|
||||
|
||||
// a1ba: workaround bug on old protocol where the server refuse to send
|
||||
// our local player in delta. cl.playernum, in theory, must be equal
|
||||
// to our local player index anyway
|
||||
// a1ba: workaround bug where the server refuse to send our local player in delta
|
||||
// cl.playernum, in theory, must be equal to our local player index anyway
|
||||
//
|
||||
// this might not be a real solution, since everything else will be bogus
|
||||
// but we need to properly run prediction and avoid potential memory
|
||||
// corruption
|
||||
// either debug this, or remove when old protocol will be dropped!!!
|
||||
if( pmove->player_index < 0 )
|
||||
{
|
||||
if( cls.legacymode )
|
||||
{
|
||||
pmove->player_index = bound( 0, cl.playernum, cl.maxclients - 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
// if this happens, record a demo and send it to a1ba
|
||||
Host_Error( "%s: ps->number == %d\n", __func__, ps->number );
|
||||
}
|
||||
}
|
||||
pmove->player_index = bound( 0, cl.playernum, cl.maxclients - 1 );
|
||||
|
||||
pmove->multiplayer = (cl.maxclients > 1);
|
||||
pmove->runfuncs = runfuncs;
|
||||
|
||||
@@ -1125,7 +1125,7 @@ Con_ClearField
|
||||
*/
|
||||
static void Con_ClearField( field_t *edit )
|
||||
{
|
||||
memset( edit->buffer, 0, MAX_STRING );
|
||||
memset( edit->buffer, 0, sizeof( edit->buffer ));
|
||||
edit->cursor = 0;
|
||||
edit->scroll = 0;
|
||||
}
|
||||
@@ -1444,36 +1444,49 @@ 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;
|
||||
|
||||
if( !aFile )
|
||||
fd = FS_Open( "console_history.txt", "rb", true );
|
||||
|
||||
if( !fd )
|
||||
return;
|
||||
|
||||
for( pFile = pLine = (char *)aFile; *pFile; pFile++ )
|
||||
while( !FS_Eof( fd ))
|
||||
{
|
||||
if( *pFile != '\n' )
|
||||
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 )
|
||||
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);
|
||||
// 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;
|
||||
}
|
||||
|
||||
self->next++;
|
||||
|
||||
pLine = pFile + 1;
|
||||
}
|
||||
|
||||
FS_Close( fd );
|
||||
|
||||
for( i = self->next; i < CON_HISTORY; i++ )
|
||||
{
|
||||
Con_ClearField( &self->lines[i] );
|
||||
self->lines[i].widthInChars = con.linewidth;
|
||||
f = &self->lines[i];
|
||||
|
||||
Con_ClearField( f );
|
||||
f->widthInChars = con.linewidth;
|
||||
}
|
||||
|
||||
self->line = self->next;
|
||||
@@ -1491,7 +1504,7 @@ static void Con_SaveHistory( con_history_t *self )
|
||||
if( historyStart < 0 )
|
||||
historyStart = 0;
|
||||
|
||||
f = FS_Open( "console_history.txt", "w", true );
|
||||
f = FS_Open( "console_history.txt", "wb", true );
|
||||
|
||||
for( i = historyStart; i < self->next; i++ )
|
||||
FS_Printf( f, "%s\n", self->lines[i % CON_HISTORY].buffer );
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -43,7 +43,7 @@ CVAR_DEFINE_AUTO( s_lerping, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "apply interpo
|
||||
static CVAR_DEFINE( s_ambient_level, "ambient_level", "0.3", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "volume of environment noises (water and wind)" );
|
||||
static CVAR_DEFINE( s_ambient_fade, "ambient_fade", "1000", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "rate of volume fading when client is moving" );
|
||||
static CVAR_DEFINE_AUTO( s_combine_sounds, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "combine channels with same sounds" );
|
||||
CVAR_DEFINE_AUTO( snd_mute_losefocus, "1", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "silence the audio when game window loses focus" );
|
||||
static CVAR_DEFINE_AUTO( snd_mute_losefocus, "1", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "silence the audio when game window loses focus" );
|
||||
CVAR_DEFINE_AUTO( s_test, "0", 0, "engine developer cvar for quick testing new features" );
|
||||
CVAR_DEFINE_AUTO( s_samplecount, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "sample count (0 for default value)" );
|
||||
CVAR_DEFINE_AUTO( s_warn_late_precache, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "warn about late precached sounds on client-side" );
|
||||
@@ -64,6 +64,12 @@ float S_GetMasterVolume( void )
|
||||
{
|
||||
float scale = 1.0f;
|
||||
|
||||
if( host.status == HOST_NOFOCUS && snd_mute_losefocus.value != 0.0f )
|
||||
{
|
||||
// we return zero volume to keep sounds running
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if( !s_listener.inmenu && soundfade.percent != 0 )
|
||||
{
|
||||
scale = bound( 0.0f, soundfade.percent / 100.0f, 1.0f );
|
||||
|
||||
@@ -221,7 +221,6 @@ 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 snd_mute_losefocus;
|
||||
extern convar_t s_warn_late_precache;
|
||||
|
||||
void S_InitScaletable( void );
|
||||
|
||||
@@ -20,8 +20,6 @@ GNU General Public License for more details.
|
||||
#include "vid_common.h"
|
||||
#include "platform/platform.h"
|
||||
|
||||
static CVAR_DEFINE( window_width, "width", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen width" );
|
||||
static CVAR_DEFINE( window_height, "height", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen height" );
|
||||
static CVAR_DEFINE_AUTO( vid_mode, "0", FCVAR_RENDERINFO, "current video mode index (used only for storage)" );
|
||||
static CVAR_DEFINE_AUTO( vid_rotate, "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen rotation (0-3)" );
|
||||
static CVAR_DEFINE_AUTO( vid_scale, "1.0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "pixel scale" );
|
||||
@@ -29,6 +27,8 @@ static CVAR_DEFINE_AUTO( vid_scale, "1.0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "p
|
||||
CVAR_DEFINE_AUTO( vid_highdpi, "1", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "enable High-DPI mode" );
|
||||
CVAR_DEFINE_AUTO( vid_maximized, "0", FCVAR_RENDERINFO, "window maximized state, read-only" );
|
||||
CVAR_DEFINE( vid_fullscreen, "fullscreen", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "fullscreen state (0 windowed, 1 fullscreen, 2 borderless)" );
|
||||
CVAR_DEFINE( window_width, "width", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen width" );
|
||||
CVAR_DEFINE( window_height, "height", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen height" );
|
||||
CVAR_DEFINE( window_xpos, "_window_xpos", "-1", FCVAR_RENDERINFO, "window position by horizontal" );
|
||||
CVAR_DEFINE( window_ypos, "_window_ypos", "-1", FCVAR_RENDERINFO, "window position by vertical" );
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ extern glwstate_t glw_state;
|
||||
extern convar_t vid_fullscreen;
|
||||
extern convar_t vid_maximized;
|
||||
extern convar_t vid_highdpi;
|
||||
extern convar_t window_width;
|
||||
extern convar_t window_height;
|
||||
extern convar_t window_xpos;
|
||||
extern convar_t window_ypos;
|
||||
extern convar_t gl_msaa_samples;
|
||||
|
||||
@@ -25,11 +25,12 @@ 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 );
|
||||
static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale );
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
@@ -39,6 +40,25 @@ static void Voice_ApplyGainAdjust( int16_t *samples, int count );
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
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
|
||||
@@ -47,24 +67,17 @@ Voice_InitOpusDecoder
|
||||
*/
|
||||
static qboolean Voice_InitOpusDecoder( void )
|
||||
{
|
||||
int err;
|
||||
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 )
|
||||
for( int i = 0; i < cl.maxclients; i++ )
|
||||
{
|
||||
Con_Printf( S_ERROR "Can't create Opus Custom mode: %s\n", opus_strerror( err ));
|
||||
return false;
|
||||
}
|
||||
voice.decoders[i] = opus_custom_decoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
|
||||
|
||||
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;
|
||||
if( !voice.decoders[i] )
|
||||
{
|
||||
Con_Printf( S_ERROR "Can't create Opus decoder for %i: %s\n", i, opus_strerror( err ));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -78,7 +91,7 @@ Voice_InitOpusEncoder
|
||||
*/
|
||||
static qboolean Voice_InitOpusEncoder( int quality )
|
||||
{
|
||||
int err;
|
||||
int err = 0;
|
||||
|
||||
voice.encoder = opus_custom_encoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
|
||||
if( !voice.encoder )
|
||||
@@ -117,10 +130,13 @@ Voice_ShutdownOpusDecoder
|
||||
*/
|
||||
static void Voice_ShutdownOpusDecoder( void )
|
||||
{
|
||||
if( voice.decoder )
|
||||
for( int i = 0; i < MAX_CLIENTS; i++ )
|
||||
{
|
||||
opus_custom_decoder_destroy( voice.decoder );
|
||||
voice.decoder = NULL;
|
||||
if( !voice.decoders[i] )
|
||||
continue;
|
||||
|
||||
opus_custom_decoder_destroy( voice.decoders[i] );
|
||||
voice.decoders[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +153,10 @@ 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 );
|
||||
@@ -184,7 +203,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_ApplyGainAdjust((opus_int16*)(voice.input_buffer + ofs), voice.frame_size, voice_transmit_scale.value);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -238,10 +257,10 @@ Voice_ApplyGainAdjust
|
||||
|
||||
=========================
|
||||
*/
|
||||
static void Voice_ApplyGainAdjust( int16_t *samples, int count )
|
||||
static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale )
|
||||
{
|
||||
float gain, modifiedMax;
|
||||
int average, adjustedSample, blockOffset = 0;
|
||||
int average, blockOffset = 0;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
@@ -260,10 +279,8 @@ static void Voice_ApplyGainAdjust( int16_t *samples, int count )
|
||||
localMax = absSample;
|
||||
|
||||
localSum += absSample;
|
||||
|
||||
gain = voice.autogain.current_gain + i * voice.autogain.gain_multiplier;
|
||||
adjustedSample = Q_min( SHRT_MAX, Q_max(( int )( sample * gain ), SHRT_MIN ));
|
||||
samples[blockOffset + i] = adjustedSample;
|
||||
samples[blockOffset + i] = bound( SHRT_MIN, (int)( sample * gain ), SHRT_MAX );
|
||||
}
|
||||
|
||||
if( blockOffset % voice.autogain.block_size == 0 )
|
||||
@@ -271,9 +288,9 @@ static void Voice_ApplyGainAdjust( int16_t *samples, int count )
|
||||
average = localSum / blockSize;
|
||||
modifiedMax = average + ( localMax - average ) * voice_avggain.value;
|
||||
|
||||
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 );
|
||||
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 );
|
||||
}
|
||||
blockOffset += blockSize;
|
||||
}
|
||||
@@ -443,7 +460,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, 255 );
|
||||
S_RawEntSamples( entnum, samples, voice.samplerate, voice.width, VOICE_PCM_CHANNELS, data, bound( 0, 255 * voice_scale.value, 255 ));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -455,10 +472,11 @@ 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( !voice.decoder )
|
||||
if( playernum < 0 || playernum >= cl.maxclients || !voice.decoders[playernum] )
|
||||
return;
|
||||
|
||||
// decode frame by frame
|
||||
@@ -478,7 +496,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.decoder, data + ofs, compressed_size,
|
||||
frame_samples = opus_custom_decode( voice.decoders[playernum], data + ofs, compressed_size,
|
||||
(opus_int16*)voice.decompress_buffer + samples, voice.frame_size );
|
||||
|
||||
ofs += compressed_size;
|
||||
@@ -502,8 +520,8 @@ void CL_AddVoiceToDatagram( void )
|
||||
|
||||
if( cls.state != ca_active || !Voice_IsRecording() || !voice.encoder )
|
||||
return;
|
||||
|
||||
size = Voice_GetOpusCompressedData( voice.output_buffer, sizeof( voice.output_buffer ), &frames );
|
||||
|
||||
size = Voice_GetOpusCompressedData( voice.compress_buffer, sizeof( voice.compress_buffer ), &frames );
|
||||
|
||||
if( size > 0 && MSG_GetNumBytesLeft( &cls.datagram ) >= size + 32 )
|
||||
{
|
||||
@@ -511,7 +529,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.output_buffer, size );
|
||||
MSG_WriteBytes( &cls.datagram, voice.compress_buffer, size );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -527,6 +545,7 @@ 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 );
|
||||
@@ -544,8 +563,9 @@ static void Voice_Shutdown( void )
|
||||
int i;
|
||||
|
||||
Voice_RecordStop();
|
||||
Voice_ShutdownOpusEncoder();
|
||||
Voice_ShutdownOpusDecoder();
|
||||
Voice_ShutdownOpusEncoder();
|
||||
Voice_ShutdownCustomMode();
|
||||
VoiceCapture_Shutdown();
|
||||
|
||||
if( voice.local.talking_ack )
|
||||
@@ -609,11 +629,10 @@ qboolean Voice_Init( const char *pszCodecName, int quality, qboolean preinit )
|
||||
|
||||
voice.autogain.block_size = 128;
|
||||
|
||||
if( !Voice_InitOpusDecoder( ))
|
||||
if( !Voice_InitCustomMode( ))
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
@@ -633,6 +652,16 @@ 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 )
|
||||
|
||||
@@ -62,7 +62,7 @@ typedef struct voice_state_s
|
||||
// opus stuff
|
||||
OpusCustomMode *custom_mode;
|
||||
OpusCustomEncoder *encoder;
|
||||
OpusCustomDecoder *decoder;
|
||||
OpusCustomDecoder *decoders[MAX_CLIENTS];
|
||||
|
||||
// audio info
|
||||
uint width;
|
||||
@@ -71,7 +71,7 @@ typedef struct voice_state_s
|
||||
|
||||
// buffers
|
||||
byte input_buffer[MAX_RAW_SAMPLES];
|
||||
byte output_buffer[MAX_RAW_SAMPLES];
|
||||
byte compress_buffer[MAX_RAW_SAMPLES];
|
||||
byte decompress_buffer[MAX_RAW_SAMPLES];
|
||||
fs_offset_t input_buffer_pos; // in bytes
|
||||
|
||||
|
||||
@@ -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_" };
|
||||
const char *prefixes[] = { "cl_", "gl_", "r_", "m_", "hud_", "joy_" };
|
||||
int i;
|
||||
|
||||
// always allow local commands
|
||||
|
||||
@@ -74,6 +74,7 @@ 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
|
||||
|
||||
|
||||
@@ -390,6 +390,9 @@ 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;
|
||||
|
||||
|
||||
@@ -866,7 +866,7 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
|
||||
return true; // exist
|
||||
|
||||
// setup mpfilter
|
||||
size = Q_snprintf( mpfilter, sizeof( mpfilter ), "maps/%s", GI->mp_filter );
|
||||
Q_snprintf( mpfilter, sizeof( mpfilter ), "maps/%s", GI->mp_filter );
|
||||
t = FS_Search( "maps/*.bsp", false, onlyingamedir );
|
||||
|
||||
if( !t )
|
||||
@@ -900,9 +900,9 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
|
||||
|
||||
if( f )
|
||||
{
|
||||
int num_spawnpoints = 0;
|
||||
dheader_t *header;
|
||||
dlump_t entities;
|
||||
qboolean have_spawnpoints = false;
|
||||
dheader_t *header;
|
||||
dlump_t entities;
|
||||
|
||||
memset( buf, 0, MAX_SYSPATH );
|
||||
FS_Read( f, buf, MAX_SYSPATH );
|
||||
@@ -943,7 +943,18 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
|
||||
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
|
||||
@@ -952,17 +963,23 @@ 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 ) || use_filter )
|
||||
num_spawnpoints++;
|
||||
|
||||
if( !Q_strcmp( token, GI->mp_entity ))
|
||||
{
|
||||
have_spawnpoints = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( num_spawnpoints ) break; // valid map
|
||||
|
||||
if( have_spawnpoints )
|
||||
break; // valid map
|
||||
}
|
||||
Mem_Free( ents );
|
||||
}
|
||||
|
||||
if( f ) FS_Close( f );
|
||||
|
||||
if( num_spawnpoints )
|
||||
if( have_spawnpoints )
|
||||
{
|
||||
// format: mapname "maptitle"\n
|
||||
Q_snprintf( result, sizeof( result ), "%s \"%s\"\n", mapname, message );
|
||||
|
||||
@@ -490,13 +490,14 @@ static void Sys_Crash( int signal, siginfo_t *si, void *context)
|
||||
#ifdef XASH_SDL
|
||||
SDL_SetWindowGrab( host.hWnd, SDL_FALSE );
|
||||
#endif
|
||||
host.crashed = true;
|
||||
Platform_MessageBox( "Xash Error", message, false );
|
||||
|
||||
// log saved, now we can try to save configs and close log correctly, it may crash
|
||||
if( host.type == HOST_NORMAL )
|
||||
CL_Crashed();
|
||||
host.status = HOST_CRASHED;
|
||||
host.crashed = true;
|
||||
|
||||
|
||||
Sys_Quit();
|
||||
}
|
||||
|
||||
@@ -152,8 +152,10 @@ static qboolean Cvar_UpdateInfo( convar_t *var, const char *value, qboolean noti
|
||||
if ( Host_IsDedicated() )
|
||||
{
|
||||
// g-cont. this is a very strange behavior...
|
||||
Info_SetValueForKey( SV_Serverinfo(), var->name, value, MAX_SERVERINFO_STRING ),
|
||||
SV_BroadcastCommand( "fullserverinfo \"%s\"\n", SV_Serverinfo( ));
|
||||
char *info = SV_Serverinfo();
|
||||
|
||||
Info_SetValueForKey( info, var->name, value, MAX_SERVERINFO_STRING ),
|
||||
SV_BroadcastCommand( "fullserverinfo \"%s\"\n", info );
|
||||
}
|
||||
#if !XASH_DEDICATED
|
||||
else
|
||||
@@ -953,7 +955,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_" };
|
||||
const char *prefixes[] = { "cl_", "gl_", "m_", "r_", "hud_", "joy_" };
|
||||
int i;
|
||||
|
||||
if( isPrivileged )
|
||||
|
||||
@@ -92,8 +92,9 @@ 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 ", "enable precise bug compatibility. Will break games that don't require it")
|
||||
O(" ", "Refer to engine documentation for more info")
|
||||
O("-bugcomp ", "enable precise bug compatibility")
|
||||
O(" ", "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")
|
||||
@@ -106,7 +107,8 @@ 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 to prevent speed hacks")
|
||||
O("-clockwindow <cw>", "adjust clockwindow used to ignore client commands")
|
||||
O(" ", "to prevent speed hacks")
|
||||
|
||||
"\nGame options:\n"
|
||||
O("-game <directory>", "set game directory to start engine with")
|
||||
@@ -1187,6 +1189,11 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
|
||||
Con_Printf( "^3BUGCOMP^7: GoldSrc bug-compatibility enabled\n" );
|
||||
}
|
||||
|
||||
// print current developer level to simplify processing users feedback
|
||||
if( developer > 0 ) {
|
||||
Con_Printf( "Developer level: ^3%i\n", developer );
|
||||
}
|
||||
|
||||
Cmd_AddCommand( "exec", Host_Exec_f, "execute a script file" );
|
||||
Cmd_AddCommand( "memlist", Host_MemStats_f, "prints memory pool information" );
|
||||
Cmd_AddRestrictedCommand( "userconfigd", Host_Userconfigd_f, "execute all scripts from userconfig.d" );
|
||||
@@ -1369,7 +1376,11 @@ 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
|
||||
|
||||
@@ -70,6 +70,7 @@ static qboolean Image_KTX2Parse( const ktx2_header_t *header, const byte *buffer
|
||||
ktx2_index_t index;
|
||||
size_t total_size = 0;
|
||||
size_t max_offset = 0;
|
||||
int mip, cursor;
|
||||
const byte *const levels_begin = buffer + KTX2_LEVELS_OFFSET;
|
||||
|
||||
// Sets image.type and image.flags
|
||||
@@ -125,7 +126,7 @@ static qboolean Image_KTX2Parse( const ktx2_header_t *header, const byte *buffer
|
||||
|
||||
memcpy( &index, buffer + KTX2_IDENTIFIER_SIZE + sizeof( ktx2_header_t ), sizeof( index ));
|
||||
|
||||
for( int mip = 0; mip < header->levelCount; ++mip )
|
||||
for( mip = 0; mip < header->levelCount; ++mip )
|
||||
{
|
||||
const uint32_t width = Q_max( 1, ( header->pixelWidth >> mip ));
|
||||
const uint32_t height = Q_max( 1, ( header->pixelHeight >> mip ));
|
||||
@@ -154,7 +155,7 @@ static qboolean Image_KTX2Parse( const ktx2_header_t *header, const byte *buffer
|
||||
image.rgba = Mem_Malloc( host.imagepool, image.size );
|
||||
memcpy( image.rgba, buffer, image.size );
|
||||
|
||||
for( int mip = 0, cursor = 0; mip < header->levelCount; ++mip )
|
||||
for( mip = 0, cursor = 0; mip < header->levelCount; ++mip )
|
||||
{
|
||||
ktx2_level_t level;
|
||||
memcpy( &level, levels_begin + mip * sizeof( level ), sizeof( level ));
|
||||
|
||||
@@ -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[765] == 0 && pal[766] == 0 && pal[767] == 255 ))
|
||||
if( !Image_CheckFlag( IL_LOAD_DECAL ) || ( pal && pal[765] == 0 && pal[766] == 0 && pal[767] == 255 ))
|
||||
{
|
||||
SetBits( image.flags, IMAGE_ONEBIT_ALPHA );
|
||||
rendermode = LUMP_MASKED;
|
||||
@@ -488,37 +488,40 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
}
|
||||
|
||||
// check for half-life water texture
|
||||
if( hl_texture && ( mip.name[0] == '!' || !Q_strnicmp( mip.name, "water", 5 )))
|
||||
if( pal != NULL )
|
||||
{
|
||||
// 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];
|
||||
|
||||
// calc the decal reflectivity
|
||||
image.fogParams[3] = VectorAvg( image.fogParams );
|
||||
}
|
||||
else if( pal != NULL )
|
||||
{
|
||||
// calc texture reflectivity
|
||||
for( i = 0; i < 256; i++ )
|
||||
if( hl_texture && ( mip.name[0] == '!' || !Q_strnicmp( mip.name, "water", 5 )))
|
||||
{
|
||||
reflectivity[0] += pal[i*3+0];
|
||||
reflectivity[1] += pal[i*3+1];
|
||||
reflectivity[2] += pal[i*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];
|
||||
|
||||
VectorDivide( reflectivity, 256, image.fogParams );
|
||||
// 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 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 );
|
||||
}
|
||||
}
|
||||
|
||||
image.type = PF_INDEXED_32; // 32-bit palete
|
||||
|
||||
@@ -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_GetBuf( &msg ), m->adr );
|
||||
NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &msg ), MSG_GetData( &msg ), m->adr );
|
||||
|
||||
if( sv_verbose_heartbeats.value )
|
||||
{
|
||||
|
||||
@@ -109,85 +109,6 @@ 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 ))
|
||||
@@ -669,7 +590,7 @@ qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes )
|
||||
return MSG_ReadBits( sb, pOut, nBytes << 3 );
|
||||
}
|
||||
|
||||
char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
|
||||
static char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
|
||||
{
|
||||
static char string[4096];
|
||||
int l = 0, c;
|
||||
@@ -695,6 +616,16 @@ 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;
|
||||
|
||||
@@ -30,39 +30,128 @@ 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 )
|
||||
|
||||
_inline int BitByte( int bits )
|
||||
static inline int BitByte( int bits )
|
||||
{
|
||||
return PAD_NUMBER( bits, 8 ) >> 3;
|
||||
}
|
||||
|
||||
struct sizebuf_s
|
||||
{
|
||||
qboolean bOverflow; // overflow reading or writing
|
||||
const char *pDebugName; // buffer name (pointer to const name)
|
||||
|
||||
byte *pData;
|
||||
int iCurBit;
|
||||
int nDataBits;
|
||||
byte *pData;
|
||||
qboolean bOverflow; // overflow reading or writing
|
||||
int iCurBit;
|
||||
int nDataBits;
|
||||
const char *pDebugName; // buffer name (pointer to const name)
|
||||
};
|
||||
|
||||
#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 )
|
||||
#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 )
|
||||
|
||||
// common functions
|
||||
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 );
|
||||
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;
|
||||
}
|
||||
|
||||
#if XASH_BIG_ENDIAN
|
||||
#define MSG_BigShort( x ) ( x )
|
||||
@@ -73,9 +162,15 @@ static inline uint16_t MSG_BigShort( const uint16_t x )
|
||||
}
|
||||
#endif
|
||||
|
||||
// init writing
|
||||
void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits );
|
||||
void MSG_Clear( sizebuf_t *sb );
|
||||
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 );
|
||||
|
||||
// Bit-write functions
|
||||
void MSG_WriteOneBit( sizebuf_t *sb, int nValue );
|
||||
@@ -99,20 +194,11 @@ 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 );
|
||||
@@ -136,7 +222,8 @@ 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
|
||||
|
||||
@@ -127,7 +127,7 @@ GNU General Public License for more details.
|
||||
#define MAX_CUSTOM (1<<MAX_CUSTOM_BITS)// 10 bits == 1024 generic file
|
||||
#define MAX_USER_MESSAGES 197 // another 58 messages reserved for engine routines
|
||||
#define MAX_DLIGHTS 32 // dynamic lights (rendered per one frame)
|
||||
#define MAX_ELIGHTS 64 // entity only point lights
|
||||
#define MAX_ELIGHTS 128 // a1ba: increased from 64 to 128, entity only point lights
|
||||
#define MAX_LIGHTSTYLES 256 // a1ba: increased from 64 to 256, protocol limit
|
||||
#define MAX_RENDER_DECALS 4096 // max rendering decals per a level
|
||||
|
||||
|
||||
@@ -135,6 +135,10 @@ 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 )
|
||||
{
|
||||
@@ -142,15 +146,18 @@ 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 );
|
||||
|
||||
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" );
|
||||
// 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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,12 +184,11 @@ void Sys_CloseLog( void )
|
||||
|
||||
if( 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");
|
||||
|
||||
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 );
|
||||
fclose( s_ld.logfile );
|
||||
s_ld.logfile = NULL;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ GNU General Public License for more details.
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if _MSC_VER
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#ifdef XASH_SDL
|
||||
#include <SDL.h>
|
||||
#endif
|
||||
@@ -49,7 +53,7 @@ GNU General Public License for more details.
|
||||
#include "library.h"
|
||||
#include "whereami.h"
|
||||
|
||||
qboolean error_on_exit = false; // arg for exit();
|
||||
static int error_on_exit = 0; // arg for exit();
|
||||
|
||||
/*
|
||||
================
|
||||
@@ -68,17 +72,15 @@ Sys_DebugBreak
|
||||
*/
|
||||
void Sys_DebugBreak( void )
|
||||
{
|
||||
#if XASH_LINUX || ( XASH_WIN32 && !XASH_64BIT )
|
||||
#if _MSC_VER
|
||||
if( Sys_DebuggerPresent() )
|
||||
_asm { int 3 }
|
||||
#elif XASH_X86
|
||||
if( Sys_DebuggerPresent() )
|
||||
asm volatile( "int $3;" );
|
||||
#else
|
||||
if( Sys_DebuggerPresent() )
|
||||
raise( SIGINT );
|
||||
#endif
|
||||
if( Sys_DebuggerPresent( ))
|
||||
__debugbreak();
|
||||
#else // !_MSC_VER
|
||||
if( Sys_DebuggerPresent( ))
|
||||
{
|
||||
INLINE_RAISE( SIGINT );
|
||||
INLINE_NANOSLEEP1(); // sometimes signal comes with delay, let it interrupt nanosleep
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -402,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, false );
|
||||
Platform_MessageBox( "Xash Warning", text, true );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -428,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 = true;
|
||||
error_on_exit = 1;
|
||||
host.status = HOST_ERR_FATAL;
|
||||
va_start( argptr, error );
|
||||
Q_vsnprintf( text, MAX_PRINT_MSG, error, argptr );
|
||||
@@ -447,7 +449,7 @@ void Sys_Error( const char *error, ... )
|
||||
Wcon_ShowConsole( false );
|
||||
#endif
|
||||
Sys_Print( text );
|
||||
Platform_MessageBox( "Xash Error", text, false );
|
||||
Platform_MessageBox( "Xash Error", text, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -52,7 +52,7 @@ static pid_t gettid( void )
|
||||
static void *g_hsystemd;
|
||||
static int (*g_pfn_sd_notify)( int unset_environment, const char *state );
|
||||
|
||||
qboolean Sys_DebuggerPresent( void )
|
||||
qboolean Platform_DebuggerPresent( void )
|
||||
{
|
||||
char buf[4096];
|
||||
ssize_t num_read;
|
||||
@@ -111,6 +111,11 @@ 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;
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@ double Platform_DoubleTime( void );
|
||||
void Platform_Sleep( int msec );
|
||||
void Platform_ShellExecute( const char *path, const char *parms );
|
||||
void Platform_MessageBox( const char *title, const char *message, qboolean parentMainWindow );
|
||||
qboolean Sys_DebuggerPresent( void ); // optional, see Sys_DebugBreak
|
||||
void Platform_SetStatus( const char *status );
|
||||
qboolean Platform_DebuggerPresent( void );
|
||||
|
||||
// legacy iOS port functions
|
||||
#if TARGET_OS_IOS
|
||||
@@ -64,6 +64,8 @@ const char *Android_LoadID( void );
|
||||
void Android_SaveID( const char *id );
|
||||
void Android_Init( void );
|
||||
void *Android_GetNativeObject( const char *name );
|
||||
int Android_GetKeyboardHeight( void );
|
||||
void Android_Shutdown( void );
|
||||
#endif
|
||||
|
||||
#if XASH_WIN32
|
||||
@@ -140,6 +142,15 @@ static inline void Platform_Shutdown( void )
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline qboolean Sys_DebuggerPresent( void )
|
||||
{
|
||||
#if XASH_LINUX || XASH_WIN32
|
||||
return Platform_DebuggerPresent();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
@@ -256,4 +267,89 @@ void VoiceCapture_Shutdown( void );
|
||||
qboolean VoiceCapture_Activate( qboolean activate );
|
||||
qboolean VoiceCapture_Lock( qboolean lock );
|
||||
|
||||
// this allows to make break in current line, without entering libc code
|
||||
// libc built with -fomit-frame-pointer may just eat stack frame (hello, glibc), making entering libc even more useless
|
||||
// calling syscalls directly allows to make break like if it was asm("int $3") on x86
|
||||
#if XASH_LINUX && XASH_X86
|
||||
#define INLINE_RAISE(x) asm volatile( "int $3;" );
|
||||
#define INLINE_NANOSLEEP1() // nothing!
|
||||
#elif XASH_LINUX && XASH_ARM && !XASH_64BIT
|
||||
#define INLINE_RAISE(x) do \
|
||||
{ \
|
||||
int raise_pid = getpid(); \
|
||||
int raise_tid = gettid(); \
|
||||
int raise_sig = (x); \
|
||||
__asm__ volatile ( \
|
||||
"mov r7,#268\n\t" \
|
||||
"mov r0,%0\n\t" \
|
||||
"mov r1,%1\n\t" \
|
||||
"mov r2,%2\n\t" \
|
||||
"svc 0\n\t" \
|
||||
: \
|
||||
: "r"(raise_pid), "r"(raise_tid), "r"(raise_sig) \
|
||||
: "r0", "r1", "r2", "r7", "memory" \
|
||||
); \
|
||||
} while( 0 )
|
||||
#define INLINE_NANOSLEEP1() do \
|
||||
{ \
|
||||
struct timespec ns_t1 = {1, 0}; \
|
||||
struct timespec ns_t2 = {0, 0}; \
|
||||
__asm__ volatile ( \
|
||||
"mov r7,#162\n\t" \
|
||||
"mov r0,%0\n\t" \
|
||||
"mov r1,%1\n\t" \
|
||||
"svc 0\n\t" \
|
||||
: \
|
||||
: "r"(&ns_t1), "r"(&ns_t2) \
|
||||
: "r0", "r1", "r7", "memory" \
|
||||
); \
|
||||
} while( 0 )
|
||||
#elif XASH_LINUX && XASH_ARM && XASH_64BIT
|
||||
#define INLINE_RAISE(x) do \
|
||||
{ \
|
||||
int raise_pid = getpid(); \
|
||||
int raise_tid = gettid(); \
|
||||
int raise_sig = (x); \
|
||||
__asm__ volatile ( \
|
||||
"mov x8,#131\n\t" \
|
||||
"mov x0,%0\n\t" \
|
||||
"mov x1,%1\n\t" \
|
||||
"mov x2,%2\n\t" \
|
||||
"svc 0\n\t" \
|
||||
: \
|
||||
: "r"(raise_pid), "r"(raise_tid), "r"(raise_sig) \
|
||||
: "x0", "x1", "x2", "x8", "memory", "cc" \
|
||||
); \
|
||||
} while( 0 )
|
||||
#define INLINE_NANOSLEEP1() do \
|
||||
{ \
|
||||
struct timespec ns_t1 = {1, 0}; \
|
||||
struct timespec ns_t2 = {0, 0}; \
|
||||
__asm__ volatile ( \
|
||||
"mov x8,#101\n\t" \
|
||||
"mov x0,%0\n\t" \
|
||||
"mov x1,%1\n\t" \
|
||||
"svc 0\n\t" \
|
||||
: \
|
||||
: "r"(&ns_t1), "r"(&ns_t2) \
|
||||
: "x0", "x1", "x8", "memory", "cc" \
|
||||
); \
|
||||
} while( 0 )
|
||||
#elif XASH_LINUX
|
||||
#ifdef __NR_tgkill
|
||||
#define INLINE_RAISE(x) syscall( __NR_tgkill, getpid(), gettid(), x )
|
||||
#else // __NR_tgkill
|
||||
#define INLINE_RAISE(x) raise(x)
|
||||
#endif // __NR_tgkill
|
||||
#define INLINE_NANOSLEEP1() do \
|
||||
{ \
|
||||
struct timespec ns_t1 = {1, 0}; \
|
||||
struct timespec ns_t2 = {0, 0}; \
|
||||
nanosleep( &ns_t1, &ns_t2 ); \
|
||||
} while( 0 )
|
||||
#else // generic
|
||||
#define INLINE_RAISE(x) raise(x)
|
||||
#define INLINE_NANOSLEEP1() sleep(1)
|
||||
#endif // generic
|
||||
|
||||
#endif // PLATFORM_H
|
||||
|
||||
@@ -212,8 +212,8 @@ const char *COM_NameForFunction( void *hInstance, void *function )
|
||||
// NOTE: dladdr() is a glibc extension
|
||||
{
|
||||
Dl_info info = {0};
|
||||
dladdr( (void*)function, &info );
|
||||
if( info.dli_sname )
|
||||
int ret = dladdr( (void*)function, &info );
|
||||
if( ret && info.dli_sname )
|
||||
return COM_GetPlatformNeutralName( info.dli_sname );
|
||||
}
|
||||
#ifdef XASH_ALLOW_SAVERESTORE_OFFSETS
|
||||
|
||||
@@ -374,14 +374,8 @@ static void SDLash_ActiveEvent( int gain )
|
||||
{
|
||||
host.status = HOST_FRAME;
|
||||
if( cls.key_dest == key_game )
|
||||
{
|
||||
IN_ActivateMouse( );
|
||||
}
|
||||
|
||||
if( dma.initialized && snd_mute_losefocus.value )
|
||||
{
|
||||
SNDDMA_Activate( true );
|
||||
}
|
||||
host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME;
|
||||
if( vid_fullscreen.value == WINDOW_MODE_FULLSCREEN )
|
||||
VID_SetMode();
|
||||
@@ -397,14 +391,8 @@ static void SDLash_ActiveEvent( int gain )
|
||||
#endif
|
||||
host.status = HOST_NOFOCUS;
|
||||
if( cls.key_dest == key_game )
|
||||
{
|
||||
IN_DeactivateMouse();
|
||||
}
|
||||
|
||||
if( dma.initialized && snd_mute_losefocus.value )
|
||||
{
|
||||
SNDDMA_Activate( false );
|
||||
}
|
||||
host.force_draw_version_time = host.realtime + 2.0;
|
||||
VID_RestoreScreenResolution();
|
||||
}
|
||||
|
||||
@@ -44,6 +44,18 @@ Platform_GetMousePos
|
||||
void GAME_EXPORT Platform_GetMousePos( int *x, int *y )
|
||||
{
|
||||
SDL_GetMouseState( x, y );
|
||||
|
||||
if( x && window_width.value && window_width.value != refState.width )
|
||||
{
|
||||
float factor = refState.width / window_width.value;
|
||||
*x = *x * factor;
|
||||
}
|
||||
|
||||
if( y && window_height.value && window_height.value != refState.height )
|
||||
{
|
||||
float factor = refState.height / window_height.value;
|
||||
*y = *y * factor;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -576,10 +576,8 @@ static qboolean VID_SetScreenResolution( int width, int height, window_mode_t wi
|
||||
SDL_DisplayMode got;
|
||||
Uint32 wndFlags = 0;
|
||||
|
||||
#if !XASH_APPLE
|
||||
if( vid_highdpi.value )
|
||||
SetBits( wndFlags, SDL_WINDOW_ALLOW_HIGHDPI );
|
||||
#endif
|
||||
|
||||
SDL_SetWindowBordered( host.hWnd, SDL_FALSE );
|
||||
|
||||
|
||||
@@ -504,12 +504,12 @@ void Wcon_CreateConsole( void )
|
||||
|
||||
if( host.type == HOST_NORMAL )
|
||||
{
|
||||
Q_strncpy( s_wcd.title, "Xash3D " XASH_VERSION, sizeof( s_wcd.title ));
|
||||
Q_strncpy( s_wcd.title, XASH_ENGINE_NAME " " XASH_VERSION, sizeof( s_wcd.title ));
|
||||
Q_strncpy( s_wcd.log_path, "engine.log", sizeof( s_wcd.log_path ));
|
||||
}
|
||||
else // dedicated console
|
||||
{
|
||||
Q_strncpy( s_wcd.title, "XashDS " XASH_VERSION, sizeof( s_wcd.title ));
|
||||
Q_strncpy( s_wcd.title, XASH_DEDICATED_SERVER_NAME " " XASH_VERSION, sizeof( s_wcd.title ));
|
||||
Q_strncpy( s_wcd.log_path, "dedicated.log", sizeof( s_wcd.log_path ));
|
||||
s_wcd.log_active = true; // always make log
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ void Platform_Sleep( int msec )
|
||||
}
|
||||
#endif // XASH_TIMER == TIMER_WIN32
|
||||
|
||||
qboolean Sys_DebuggerPresent( void )
|
||||
qboolean Platform_DebuggerPresent( void )
|
||||
{
|
||||
return IsDebuggerPresent();
|
||||
}
|
||||
|
||||
@@ -43,10 +43,9 @@ 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_SPAWNPOINT BIT( 1 )
|
||||
#define MAP_HAS_LANDMARK BIT( 2 )
|
||||
#define MAP_INVALID_VERSION BIT( 3 )
|
||||
#define MAP_IS_EXIST BIT( 0 )
|
||||
#define MAP_HAS_LANDMARK BIT( 2 )
|
||||
#define MAP_INVALID_VERSION BIT( 3 )
|
||||
|
||||
#define SV_SPAWN_TIME 0.1
|
||||
|
||||
@@ -613,11 +612,9 @@ 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 *spawn_entity, const char *landmark_name );
|
||||
uint SV_MapIsValid( const char *filename, 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 );
|
||||
@@ -628,12 +625,18 @@ 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
|
||||
//
|
||||
|
||||
@@ -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", SV_Serverinfo( ));
|
||||
MSG_WriteStringf( &msg, "fullserverinfo \"%s\"\n", svs.serverinfo );
|
||||
|
||||
// collect the info about all the players and send to me
|
||||
for( i = 0, cur = svs.clients; i < svs.maxclients; i++, cur++ )
|
||||
|
||||
@@ -169,17 +169,11 @@ SV_ValidateMap
|
||||
check map for typically errors
|
||||
==================
|
||||
*/
|
||||
static qboolean SV_ValidateMap( const char *pMapName, qboolean check_spawn )
|
||||
static qboolean SV_ValidateMap( const char *pMapName )
|
||||
{
|
||||
char *spawn_entity;
|
||||
int flags;
|
||||
|
||||
// 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 );
|
||||
flags = SV_MapIsValid( pMapName, NULL );
|
||||
|
||||
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
||||
{
|
||||
@@ -193,12 +187,6 @@ static qboolean SV_ValidateMap( const char *pMapName, qboolean check_spawn )
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -224,7 +212,7 @@ static void SV_Map_f( void )
|
||||
Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
|
||||
COM_StripExtension( mapname );
|
||||
|
||||
if( !SV_ValidateMap( mapname, true ))
|
||||
if( !SV_ValidateMap( mapname ))
|
||||
return;
|
||||
|
||||
Cvar_DirectSet( &sv_hostmap, mapname );
|
||||
@@ -296,7 +284,7 @@ static void SV_MapBackground_f( void )
|
||||
Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
|
||||
COM_StripExtension( mapname );
|
||||
|
||||
if( !SV_ValidateMap( mapname, false ))
|
||||
if( !SV_ValidateMap( mapname ))
|
||||
return;
|
||||
|
||||
// background map is always run as singleplayer
|
||||
@@ -346,7 +334,7 @@ static void SV_NextMap_f( void )
|
||||
Cvar_DirectSet( &sv_hostmap, nextmap );
|
||||
|
||||
// found current point, check for valid
|
||||
if( SV_ValidateMap( nextmap, true ))
|
||||
if( SV_ValidateMap( nextmap ))
|
||||
{
|
||||
// found and valid
|
||||
COM_LoadLevel( nextmap, false );
|
||||
@@ -368,13 +356,12 @@ SV_NewGame_f
|
||||
*/
|
||||
static void SV_NewGame_f( void )
|
||||
{
|
||||
if( Cmd_Argc() != 1 )
|
||||
{
|
||||
if( Cmd_Argc() == 1 )
|
||||
COM_NewGame( GI->startmap );
|
||||
else if( Cmd_Argc() == 2 )
|
||||
COM_NewGame( Cmd_Argv( 1 ));
|
||||
else
|
||||
Con_Printf( S_USAGE "newgame\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
COM_NewGame( GI->startmap );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -547,7 +534,7 @@ classic change level
|
||||
*/
|
||||
static void SV_ChangeLevel_f( void )
|
||||
{
|
||||
if( Cmd_Argc() != 2 )
|
||||
if( Cmd_Argc() < 2 ) // allow extra arguments, for compatibility
|
||||
{
|
||||
Con_Printf( S_USAGE "changelevel <mapname>\n" );
|
||||
return;
|
||||
@@ -565,13 +552,15 @@ smooth change level
|
||||
*/
|
||||
static void SV_ChangeLevel2_f( void )
|
||||
{
|
||||
if( Cmd_Argc() != 3 )
|
||||
if( Cmd_Argc() < 2 ) // allow extra arguments, for compatibility
|
||||
{
|
||||
Con_Printf( S_USAGE "changelevel2 <mapname> <landmark>\n" );
|
||||
Con_Printf( S_USAGE "changelevel2 <mapname> [landmark]\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
SV_QueueChangeLevel( Cmd_Argv( 1 ), Cmd_Argv( 2 ));
|
||||
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 ));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -764,7 +753,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", SV_Serverinfo( ));
|
||||
SV_BroadcastCommand( "fullserverinfo \"%s\"\n", svs.serverinfo );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1018,6 +1007,7 @@ 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 )
|
||||
{
|
||||
@@ -1056,6 +1046,7 @@ void SV_KillOperatorCommands( void )
|
||||
Cmd_RemoveCommand( "redirect" );
|
||||
Cmd_RemoveCommand( "logaddress" );
|
||||
Cmd_RemoveCommand( "log" );
|
||||
Cmd_RemoveCommand( "str64stats" );
|
||||
|
||||
if( host.type == HOST_NORMAL )
|
||||
{
|
||||
|
||||
@@ -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_GetBuf( &sv.reliable_datagram ), MSG_GetNumBitsWritten( &sv.reliable_datagram ));
|
||||
MSG_WriteBits( &cl->netchan.message, MSG_GetData( &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_GetBuf( &sv.datagram ), MSG_GetNumBitsWritten( &sv.datagram ));
|
||||
MSG_WriteBits( &cl->datagram, MSG_GetData( &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_GetBuf( &sv.spec_datagram ), MSG_GetNumBitsWritten( &sv.spec_datagram ));
|
||||
MSG_WriteBits( &cl->datagram, MSG_GetData( &sv.spec_datagram ), MSG_GetNumBitsWritten( &sv.spec_datagram ));
|
||||
else Con_DPrintf( S_WARN "Ignoring spectator datagram for %s, would overflow\n", cl->name );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,13 +39,6 @@ static vec3_t viewPoint[MAX_CLIENTS];
|
||||
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 )
|
||||
{
|
||||
@@ -150,18 +143,6 @@ char *SV_Serverinfo( void )
|
||||
return svs.serverinfo;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_LocalInfo
|
||||
|
||||
get local infostring
|
||||
=============
|
||||
*/
|
||||
static char *SV_Localinfo( void )
|
||||
{
|
||||
return svs.localinfo;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_AngleMod
|
||||
@@ -268,7 +249,6 @@ 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;
|
||||
|
||||
@@ -778,7 +758,6 @@ 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 ));
|
||||
@@ -787,12 +766,7 @@ void SV_QueueChangeLevel( const char *level, const char *landname )
|
||||
if( COM_CheckString( landname ))
|
||||
smooth = true;
|
||||
|
||||
// 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 );
|
||||
flags = SV_MapIsValid( mapname, landname );
|
||||
|
||||
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
||||
{
|
||||
@@ -826,15 +800,6 @@ 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 )
|
||||
{
|
||||
@@ -864,7 +829,6 @@ 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;
|
||||
|
||||
@@ -875,7 +839,6 @@ 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 ))
|
||||
@@ -915,7 +878,6 @@ 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;
|
||||
@@ -930,7 +892,6 @@ 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 ))
|
||||
@@ -977,7 +938,7 @@ SV_MapIsValid
|
||||
Validate map
|
||||
==============
|
||||
*/
|
||||
uint SV_MapIsValid( const char *filename, const char *spawn_entity, const char *landmark_name )
|
||||
uint SV_MapIsValid( const char *filename, const char *landmark_name )
|
||||
{
|
||||
uint flags = 0;
|
||||
char *pfile;
|
||||
@@ -993,45 +954,27 @@ uint SV_MapIsValid( const char *filename, const char *spawn_entity, const char *
|
||||
|
||||
need_landmark = COM_CheckString( landmark_name );
|
||||
|
||||
// g-cont. in-dev mode we can entering on map even without "info_player_start"
|
||||
if( !need_landmark && host_developer.value )
|
||||
if( !need_landmark )
|
||||
{
|
||||
// not transition
|
||||
Mem_Free( ents );
|
||||
|
||||
// skip spawnpoint checks in devmode
|
||||
return (flags|MAP_HAS_SPAWNPOINT);
|
||||
return flags;
|
||||
}
|
||||
|
||||
pfile = ents;
|
||||
|
||||
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )
|
||||
{
|
||||
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" ))
|
||||
if( !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 );
|
||||
|
||||
// we already find spawnpoint, stop the parsing
|
||||
if( FBitSet( flags, MAP_HAS_SPAWNPOINT ))
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1174,15 +1117,22 @@ 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 )
|
||||
static edict_t* SV_AllocPrivateData( edict_t *ent, string_t className, qboolean *customentity )
|
||||
{
|
||||
const char *pszClassName;
|
||||
LINK_ENTITY_FUNC SpawnEdict;
|
||||
|
||||
pszClassName = STRING( className );
|
||||
|
||||
if( customentity )
|
||||
*customentity = false;
|
||||
|
||||
if( !ent )
|
||||
{
|
||||
// allocate a new one
|
||||
@@ -1205,7 +1155,11 @@ static edict_t* SV_AllocPrivateData( edict_t *ent, string_t className )
|
||||
if( svgame.physFuncs.SV_CreateEntity && svgame.physFuncs.SV_CreateEntity( ent, pszClassName ) != -1 )
|
||||
return ent;
|
||||
|
||||
SpawnEdict = SV_GetEntityClass( "custom" );
|
||||
if( customentity )
|
||||
{
|
||||
SpawnEdict = SV_GetEntityClass( "custom" );
|
||||
*customentity = SpawnEdict != NULL;
|
||||
}
|
||||
|
||||
if( !SpawnEdict )
|
||||
{
|
||||
@@ -1216,8 +1170,6 @@ static edict_t* SV_AllocPrivateData( edict_t *ent, string_t className )
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SetBits( ent->v.flags, FL_CUSTOMENTITY ); // it's a custom entity but not a beam!
|
||||
}
|
||||
|
||||
SpawnEdict( &ent->v );
|
||||
@@ -1234,12 +1186,7 @@ create specified entity, alloc private data
|
||||
*/
|
||||
edict_t* SV_CreateNamedEntity( edict_t *ent, string_t className )
|
||||
{
|
||||
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;
|
||||
return SV_AllocPrivateData( ent, className, NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2851,8 +2798,10 @@ 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 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3218,7 +3167,9 @@ 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 )
|
||||
{
|
||||
@@ -3281,19 +3232,21 @@ string_t GAME_EXPORT SV_AllocString( const char *szValue )
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef XASH_64BIT
|
||||
void SV_PrintStr64Stats_f( void )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
#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
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
@@ -3737,9 +3690,9 @@ vaild map must contain one info_player_deatchmatch
|
||||
*/
|
||||
int GAME_EXPORT pfnIsMapValid( char *filename )
|
||||
{
|
||||
uint flags = SV_MapIsValid( filename, GI->mp_entity, NULL );
|
||||
uint flags = SV_MapIsValid( filename, NULL );
|
||||
|
||||
if( FBitSet( flags, MAP_IS_EXIST ) && FBitSet( flags, MAP_HAS_SPAWNPOINT ))
|
||||
if( FBitSet( flags, MAP_IS_EXIST ))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -3873,11 +3826,11 @@ static char *GAME_EXPORT pfnGetInfoKeyBuffer( edict_t *e )
|
||||
|
||||
// NULL passes localinfo
|
||||
if( !SV_IsValidEdict( e ))
|
||||
return SV_Localinfo();
|
||||
return svs.localinfo;
|
||||
|
||||
// world passes serverinfo
|
||||
if( e == svgame.edicts )
|
||||
return SV_Serverinfo();
|
||||
return svs.serverinfo;
|
||||
|
||||
// userinfo for specified edict
|
||||
if(( cl = SV_ClientFromEdict( e, false )) != NULL )
|
||||
@@ -4820,6 +4773,15 @@ 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
|
||||
@@ -4831,36 +4793,34 @@ 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;
|
||||
qboolean adjust_origin = false, customentity;
|
||||
int i, numpairs = 0;
|
||||
char *classname = NULL;
|
||||
char token[2048];
|
||||
vec3_t origin;
|
||||
const char *classname = NULL;
|
||||
|
||||
// go through all the dictionary pairs
|
||||
while( 1 )
|
||||
{
|
||||
string keyname;
|
||||
char value[2048];
|
||||
int len;
|
||||
|
||||
// parse key
|
||||
if(( *pfile = COM_ParseFile( *pfile, token, sizeof( token ))) == NULL )
|
||||
if(( *pfile = COM_ParseFile( *pfile, keyname, sizeof( keyname ))) == NULL )
|
||||
Host_Error( "ED_ParseEdict: EOF without closing brace\n" );
|
||||
if( token[0] == '}' ) break; // end of desc
|
||||
|
||||
Q_strncpy( keyname, token, sizeof( keyname ));
|
||||
if( keyname[0] == '}' )
|
||||
break; // end of desc
|
||||
|
||||
// parse value
|
||||
if(( *pfile = COM_ParseFile( *pfile, token, sizeof( token ))) == NULL )
|
||||
if(( *pfile = COM_ParseFile( *pfile, value, sizeof( value ))) == NULL )
|
||||
Host_Error( "ED_ParseEdict: EOF without closing brace\n" );
|
||||
|
||||
if( token[0] == '}' )
|
||||
if( value[0] == '}' )
|
||||
Host_Error( "ED_ParseEdict: closing brace without data\n" );
|
||||
|
||||
// ignore attempts to set key ""
|
||||
if( !keyname[0] ) continue;
|
||||
|
||||
// ignore attempts to set empty key or value
|
||||
// "wad" field is already handled
|
||||
if( !Q_strcmp( keyname, "wad" ))
|
||||
if( !keyname[0] || !value[0] || !Q_strcmp( keyname, "wad" ))
|
||||
continue;
|
||||
|
||||
// keynames with a leading underscore are used for
|
||||
@@ -4868,57 +4828,83 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
|
||||
if( FBitSet( world.flags, FWORLD_SKYSPHERE ) && keyname[0] == '_' )
|
||||
continue;
|
||||
|
||||
// ignore attempts to set value ""
|
||||
if( !token[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';
|
||||
|
||||
// create keyvalue strings
|
||||
pkvd[numpairs].szClassName = (char*)""; // unknown at this moment
|
||||
pkvd[numpairs].szKeyName = copystring( keyname );
|
||||
pkvd[numpairs].szValue = copystring( token );
|
||||
pkvd[numpairs].szValue = copystring( value );
|
||||
pkvd[numpairs].fHandled = false;
|
||||
numpairs++;
|
||||
|
||||
if( !Q_strcmp( keyname, "classname" ) && classname == NULL )
|
||||
classname = copystring( pkvd[numpairs].szValue );
|
||||
if( ++numpairs >= 256 ) break;
|
||||
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( classname == NULL )
|
||||
{
|
||||
// release allocated strings
|
||||
for( i = 0; i < numpairs; i++ )
|
||||
{
|
||||
Mem_Free( pkvd[i].szKeyName );
|
||||
Mem_Free( pkvd[i].szValue );
|
||||
}
|
||||
SV_FreeKeyValueStrings( pkvd, numpairs );
|
||||
return false;
|
||||
}
|
||||
|
||||
ent = SV_AllocPrivateData( ent, ALLOC_STRING( classname ));
|
||||
ent = SV_AllocPrivateData( ent, ent->v.classname, &customentity );
|
||||
|
||||
if( !SV_IsValidEdict( ent ) || FBitSet( ent->v.flags, FL_KILLME ))
|
||||
{
|
||||
// release allocated strings
|
||||
for( i = 0; i < numpairs; i++ )
|
||||
{
|
||||
Mem_Free( pkvd[i].szKeyName );
|
||||
Mem_Free( pkvd[i].szValue );
|
||||
}
|
||||
SV_FreeKeyValueStrings( pkvd, numpairs );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( FBitSet( ent->v.flags, FL_CUSTOMENTITY ))
|
||||
if( customentity )
|
||||
{
|
||||
if( numpairs < 256 )
|
||||
{
|
||||
pkvd[numpairs].szClassName = (char*)"custom";
|
||||
pkvd[numpairs].szKeyName = (char*)"customclass";
|
||||
pkvd[numpairs].szValue = classname;
|
||||
pkvd[numpairs].fHandled = false;
|
||||
numpairs++;
|
||||
}
|
||||
KeyValueData kvd = {
|
||||
.szClassName = (char *)"custom",
|
||||
.szKeyName = (char *)"customclass",
|
||||
.szValue = (char *)classname,
|
||||
.fHandled = false
|
||||
};
|
||||
|
||||
// clear it now - no longer used
|
||||
ClearBits( ent->v.flags, FL_CUSTOMENTITY );
|
||||
svgame.dllFuncs.pfnKeyValue( ent, &kvd );
|
||||
// no fHandled check, GoldSrc behavior
|
||||
}
|
||||
|
||||
#ifdef HACKS_RELATED_HLMODS
|
||||
@@ -4932,6 +4918,14 @@ 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 );
|
||||
@@ -4942,8 +4936,6 @@ 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 );
|
||||
}
|
||||
@@ -4954,11 +4946,10 @@ 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 temp[MAX_VA_STRING];
|
||||
char *pstart = pkvd[i].szValue;
|
||||
char *pstart = pkvd[i].szValue;
|
||||
vec3_t origin;
|
||||
|
||||
COM_ParseVector( &pstart, origin, 3 );
|
||||
Mem_Free( pkvd[i].szValue ); // release old value, so we don't need these
|
||||
@@ -4966,24 +4957,18 @@ 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] );
|
||||
}
|
||||
|
||||
// no reason to keep this data
|
||||
if( Mem_IsAllocatedExt( host.mempool, pkvd[i].szKeyName ))
|
||||
Mem_Free( pkvd[i].szKeyName );
|
||||
// do not leak memory if game overwritten these pointers
|
||||
keyname = pkvd[i].szKeyName;
|
||||
value = pkvd[i].szValue;
|
||||
|
||||
if( Mem_IsAllocatedExt( host.mempool, pkvd[i].szValue ))
|
||||
Mem_Free( pkvd[i].szValue );
|
||||
pkvd[i].szClassName = (char *)classname;
|
||||
svgame.dllFuncs.pfnKeyValue( ent, &pkvd[i] );
|
||||
|
||||
Mem_Free( keyname );
|
||||
Mem_Free( value );
|
||||
}
|
||||
|
||||
if( Mem_IsAllocatedExt( host.mempool, classname ))
|
||||
Mem_Free( classname );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5102,8 +5087,6 @@ void SV_UnloadProgs( void )
|
||||
/// SV_UnloadProgs will be disabled
|
||||
//Mod_ClearUserData ();
|
||||
|
||||
SV_FreeStringPool();
|
||||
|
||||
if( svgame.dllFuncs2.pfnGameShutdown != NULL )
|
||||
svgame.dllFuncs2.pfnGameShutdown ();
|
||||
|
||||
@@ -5124,6 +5107,8 @@ void SV_UnloadProgs( void )
|
||||
Cvar_Unlink( FCVAR_EXTDLL );
|
||||
Cmd_Unlink( CMD_SERVERDLL );
|
||||
|
||||
SV_FreeStringPool();
|
||||
|
||||
Mod_ResetStudioAPI ();
|
||||
|
||||
COM_FreeLibrary( svgame.hInstance );
|
||||
|
||||
@@ -922,11 +922,11 @@ static void SV_GenerateTestPacket( void )
|
||||
// testpacket already generated once, exit
|
||||
// testpacket and lookup table takes ~300k of memory
|
||||
// disable for low memory mode
|
||||
if( svs.testpacket_buf || XASH_LOW_MEMORY >= 0 )
|
||||
if( svs.testpacket_buf || XASH_LOW_MEMORY > 0 )
|
||||
return;
|
||||
|
||||
// don't need in singleplayer with full client
|
||||
if( svs.maxclients <= 1 && !Host_IsDedicated( ))
|
||||
if( svs.maxclients <= 1 )
|
||||
return;
|
||||
|
||||
file = FS_Open( "gfx.wad", "rb", false );
|
||||
|
||||
@@ -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( SV_Serverinfo(), "*gamedir" ), PROTOCOL_VERSION, Q_buildnum() );
|
||||
szTestFile, Info_ValueForKey( svs.serverinfo, "*gamedir" ), PROTOCOL_VERSION, Q_buildnum() );
|
||||
}
|
||||
|
||||
void Log_Close( void )
|
||||
|
||||
@@ -2110,7 +2110,7 @@ qboolean SV_LoadGame( const char *pPath )
|
||||
if( validload )
|
||||
{
|
||||
// now check for map problems
|
||||
flags = SV_MapIsValid( gameHeader.mapName, GI->sp_entity, NULL );
|
||||
flags = SV_MapIsValid( gameHeader.mapName, NULL );
|
||||
|
||||
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
||||
{
|
||||
@@ -2386,7 +2386,7 @@ int GAME_EXPORT SV_GetSaveComment( const char *savename, char *comment )
|
||||
uint flags;
|
||||
|
||||
// now check for map problems
|
||||
flags = SV_MapIsValid( mapName, GI->sp_entity, NULL );
|
||||
flags = SV_MapIsValid( mapName, NULL );
|
||||
|
||||
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
||||
{
|
||||
|
||||
@@ -320,6 +320,12 @@ public:
|
||||
return nullptr;
|
||||
|
||||
state = new CSearchState( &searchHead, search );
|
||||
if( !state )
|
||||
{
|
||||
Mem_Free( search );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
*handle = state->handle;
|
||||
return state->search->filenames[0];
|
||||
}
|
||||
|
||||
@@ -276,6 +276,9 @@ searchpath_t *FS_AddAndroidAssets_Fullpath( const char *path, int flags )
|
||||
android_assets_t *assets = NULL;
|
||||
qboolean engine = true;
|
||||
|
||||
if( !jni.getPackageName || !jni.getCallingPackage || !jni.getAssetsList || !jni.getAssets )
|
||||
return NULL;
|
||||
|
||||
if( FBitSet( flags, FS_STATIC_PATH | FS_CUSTOM_PATH ))
|
||||
return NULL;
|
||||
|
||||
@@ -286,7 +289,7 @@ searchpath_t *FS_AddAndroidAssets_Fullpath( const char *path, int flags )
|
||||
|
||||
if( !assets )
|
||||
{
|
||||
Con_Reportf( S_ERROR "%s: unable to load Android assets \"%s\"\n", __FUNCTION__, Android_GetPackageName( engine ));
|
||||
Con_Reportf( S_ERROR "%s: unable to load Android assets \"%s\"\n", __func__, Android_GetPackageName( engine ));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -326,6 +329,9 @@ void FS_InitAndroid( void )
|
||||
jni.getCallingPackage = (*jni.env)->GetMethodID( jni.env, jni.activity_class, "getCallingPackage", "()Ljava/lang/String;" );
|
||||
jni.getAssetsList = (*jni.env)->GetMethodID( jni.env, jni.activity_class, "getAssetsList", "(ZLjava/lang/String;)[Ljava/lang/String;" );
|
||||
jni.getAssets = (*jni.env)->GetMethodID( jni.env, jni.activity_class, "getAssets", "(Z)Landroid/content/res/AssetManager;" );
|
||||
|
||||
if( !jni.getPackageName || !jni.getCallingPackage || !jni.getAssetsList || !jni.getAssets )
|
||||
Con_Reportf( S_WARN "%s: unable to find required JNI interface to load Android assets\n", __func__ );
|
||||
}
|
||||
|
||||
#endif // XASH_ANDROID
|
||||
|
||||
@@ -72,7 +72,7 @@ const fs_archive_t g_archives[] =
|
||||
static const fs_archive_t g_directory_archive =
|
||||
{ NULL, SEARCHPATH_PLAIN, FS_AddDir_Fullpath, false };
|
||||
|
||||
#ifdef XASH_ANDROID
|
||||
#if XASH_ANDROID
|
||||
static const fs_archive_t g_android_archive =
|
||||
{ NULL, SEARCHPATH_ANDROID_ASSETS, FS_AddAndroidAssets_Fullpath, false };
|
||||
#endif
|
||||
@@ -406,7 +406,7 @@ void FS_AddGameDirectory( const char *dir, uint flags )
|
||||
|
||||
stringlistfreecontents( &list );
|
||||
|
||||
#ifdef XASH_ANDROID
|
||||
#if XASH_ANDROID
|
||||
FS_AddArchive_Fullpath( &g_android_archive, dir, flags );
|
||||
#endif
|
||||
|
||||
@@ -632,30 +632,23 @@ static void FS_InitGameInfo( gameinfo_t *GameInfo, const char *gamedir )
|
||||
memset( GameInfo, 0, sizeof( *GameInfo ));
|
||||
|
||||
// filesystem info
|
||||
Q_strncpy( GameInfo->gamefolder, gamedir, sizeof( GameInfo->gamefolder ));
|
||||
Q_strncpy( GameInfo->basedir, "valve", sizeof( GameInfo->basedir ));
|
||||
GameInfo->falldir[0] = 0;
|
||||
Q_strncpy( GameInfo->startmap, "c0a0", sizeof( GameInfo->startmap ));
|
||||
Q_strncpy( GameInfo->trainmap, "t0a0", sizeof( GameInfo->trainmap ));
|
||||
Q_strncpy( GameInfo->title, "New Game", sizeof( GameInfo->title ));
|
||||
GameInfo->version = 1.0f;
|
||||
|
||||
// .dll pathes
|
||||
Q_strncpy( GameInfo->gamefolder, gamedir, sizeof( GameInfo->gamefolder ));
|
||||
Q_strncpy( GameInfo->basedir, fs_basedir, sizeof( GameInfo->basedir ));
|
||||
Q_strncpy( GameInfo->sp_entity, "info_player_start", sizeof( GameInfo->sp_entity ));
|
||||
Q_strncpy( GameInfo->mp_entity, "info_player_deathmatch", sizeof( GameInfo->mp_entity ));
|
||||
Q_strncpy( GameInfo->startmap, "newmap", sizeof( GameInfo->startmap ));
|
||||
Q_strncpy( GameInfo->dll_path, "cl_dlls", sizeof( GameInfo->dll_path ));
|
||||
Q_strncpy( GameInfo->game_dll, "dlls/hl.dll", sizeof( GameInfo->game_dll ));
|
||||
Q_strncpy( GameInfo->game_dll_linux, "dlls/hl.so", sizeof( GameInfo->game_dll_linux ));
|
||||
Q_strncpy( GameInfo->game_dll_osx, "dlls/hl.dylib", sizeof( GameInfo->game_dll_osx ));
|
||||
|
||||
// .ico path
|
||||
Q_strncpy( GameInfo->iconpath, "game.ico", sizeof( GameInfo->iconpath ));
|
||||
|
||||
Q_strncpy( GameInfo->sp_entity, "info_player_start", sizeof( GameInfo->sp_entity ));
|
||||
Q_strncpy( GameInfo->mp_entity, "info_player_deathmatch", sizeof( GameInfo->mp_entity ));
|
||||
|
||||
GameInfo->max_edicts = DEFAULT_MAX_EDICTS; // default value if not specified
|
||||
GameInfo->max_tents = 500;
|
||||
GameInfo->max_beams = 128;
|
||||
GameInfo->max_particles = 4096;
|
||||
GameInfo->version = 1.0f;
|
||||
}
|
||||
|
||||
static void FS_ParseGenericGameInfo( gameinfo_t *GameInfo, const char *buf, const qboolean isGameInfo )
|
||||
@@ -1468,7 +1461,7 @@ qboolean FS_InitStdio( qboolean unused_set_to_true, const char *rootdir, const c
|
||||
|
||||
FS_InitMemory();
|
||||
|
||||
#ifdef XASH_ANDROID
|
||||
#if XASH_ANDROID
|
||||
FS_InitAndroid();
|
||||
#endif
|
||||
|
||||
|
||||
@@ -358,7 +358,7 @@ searchpath_t *FS_AddPak_Fullpath( const char *pakfile, int flags )
|
||||
search->pfnFindFile = FS_FindFile_PAK;
|
||||
search->pfnSearch = FS_Search_PAK;
|
||||
|
||||
Con_Reportf( "Adding pakfile: %s (%i files)\n", pakfile, pak->numfiles );
|
||||
Con_Reportf( "Adding PAK: %s (%i files)\n", pakfile, pak->numfiles );
|
||||
|
||||
return search;
|
||||
}
|
||||
|
||||
@@ -670,6 +670,6 @@ searchpath_t *FS_AddWad_Fullpath( const char *wadfile, int flags )
|
||||
search->pfnSearch = FS_Search_WAD;
|
||||
search->pfnLoadFile = W_ReadLump;
|
||||
|
||||
Con_Reportf( "Adding wadfile: %s (%i files)\n", wadfile, wad->numlumps );
|
||||
Con_Reportf( "Adding WAD: %s (%i files)\n", wadfile, wad->numlumps );
|
||||
return search;
|
||||
}
|
||||
|
||||
@@ -701,7 +701,7 @@ searchpath_t *FS_AddZip_Fullpath( const char *zipfile, int flags )
|
||||
search->pfnSearch = FS_Search_ZIP;
|
||||
search->pfnLoadFile = FS_LoadZIPFile;
|
||||
|
||||
Con_Reportf( "Adding zipfile: %s (%i files)\n", zipfile, zip->numfiles );
|
||||
Con_Reportf( "Adding ZIP: %s (%i files)\n", zipfile, zip->numfiles );
|
||||
return search;
|
||||
}
|
||||
|
||||
|
||||
@@ -237,19 +237,25 @@ const char *Q_buildarch( void )
|
||||
=============
|
||||
Q_buildcommit
|
||||
|
||||
Returns a short hash of current commit in VCS as string.
|
||||
Returns a short hash of current commit in VCS as string
|
||||
XASH_BUILD_COMMIT must be passed in quotes
|
||||
|
||||
if XASH_BUILD_COMMIT is not defined,
|
||||
Q_buildcommit will identify this build as "notset"
|
||||
=============
|
||||
*/
|
||||
const char *Q_buildcommit( void )
|
||||
{
|
||||
#ifdef XASH_BUILD_COMMIT
|
||||
return XASH_BUILD_COMMIT;
|
||||
#else
|
||||
return "notset";
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Q_buildbranch
|
||||
|
||||
Returns current branch name in VCS as string
|
||||
XASH_BUILD_BRANCH must be passed in quotes
|
||||
=============
|
||||
*/
|
||||
const char *Q_buildbranch( void )
|
||||
{
|
||||
return XASH_BUILD_BRANCH;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ const char *Q_buildos( void );
|
||||
const char *Q_ArchitectureStringByID( const int arch, const uint abi, const int endianness, const qboolean is64 );
|
||||
const char *Q_buildarch( void );
|
||||
const char *Q_buildcommit( void );
|
||||
const char *Q_buildbranch( void );
|
||||
|
||||
//
|
||||
// crtlib.c
|
||||
|
||||
207
public/utflib.c
Normal file
207
public/utflib.c
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
utflib.c - small unicode conversion library
|
||||
Copyright (C) 2024 Alibek Omarov
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
#include "utflib.h"
|
||||
#include "xash3d_types.h"
|
||||
|
||||
uint32_t Q_DecodeUTF8( utfstate_t *s, uint32_t in )
|
||||
{
|
||||
// get character length
|
||||
if( s->len == 0 )
|
||||
{
|
||||
// init state
|
||||
s->uc = 0;
|
||||
|
||||
// expect ASCII symbols by default
|
||||
if( likely( in <= 0x7fu ))
|
||||
return in;
|
||||
|
||||
// invalid sequence
|
||||
if( unlikely( in >= 0xf8u ))
|
||||
return 0;
|
||||
|
||||
s->k = 0;
|
||||
|
||||
if( in >= 0xf0u )
|
||||
{
|
||||
s->uc = in & 0x07u;
|
||||
s->len = 3;
|
||||
}
|
||||
else if( in >= 0xe0u )
|
||||
{
|
||||
s->uc = in & 0x0fu;
|
||||
s->len = 2;
|
||||
}
|
||||
else if( in >= 0xc0u )
|
||||
{
|
||||
s->uc = in & 0x1fu;
|
||||
s->len = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// invalid sequence, reset
|
||||
if( unlikely( in > 0xbfu ))
|
||||
{
|
||||
s->len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s->uc <<= 6;
|
||||
s->uc += in & 0x3fu;
|
||||
s->k++;
|
||||
|
||||
// sequence complete, reset and return code point
|
||||
if( likely( s->k == s->len ))
|
||||
{
|
||||
s->len = 0;
|
||||
return s->uc;
|
||||
}
|
||||
|
||||
// feed more characters
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Q_DecodeUTF16( utfstate_t *s, uint32_t in )
|
||||
{
|
||||
// get character length
|
||||
if( s->len == 0 )
|
||||
{
|
||||
// init state
|
||||
s->uc = 0;
|
||||
|
||||
// expect simple case, after all decoding UTF-16 must be easy
|
||||
if( likely( in < 0xd800u || in > 0xdfffu ))
|
||||
return in;
|
||||
|
||||
s->uc = (( in - 0xd800u ) << 10 ) + 0x10000u;
|
||||
s->len = 1;
|
||||
s->k = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// invalid sequence, reset
|
||||
if( unlikely( in < 0xdc00u || in > 0xdfffu ))
|
||||
{
|
||||
s->len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s->uc |= in - 0xdc00u;
|
||||
s->k++;
|
||||
|
||||
// sequence complete, reset and return code point
|
||||
if( likely( s->k == s->len ))
|
||||
{
|
||||
s->len = 0;
|
||||
return s->uc;
|
||||
}
|
||||
|
||||
// feed more characters (should never happen with UTF-16)
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t Q_EncodeUTF8( char dst[4], uint32_t ch )
|
||||
{
|
||||
if( ch <= 0x7fu )
|
||||
{
|
||||
dst[0] = ch;
|
||||
return 1;
|
||||
}
|
||||
else if( ch <= 0x7ffu )
|
||||
{
|
||||
dst[0] = 0xc0u | (( ch >> 6 ) & 0x1fu );
|
||||
dst[1] = 0x80u | (( ch ) & 0x3fu );
|
||||
return 2;
|
||||
}
|
||||
else if( ch <= 0xffffu )
|
||||
{
|
||||
dst[0] = 0xe0u | (( ch >> 12 ) & 0x0fu );
|
||||
dst[1] = 0x80u | (( ch >> 6 ) & 0x3fu );
|
||||
dst[2] = 0x80u | (( ch ) & 0x3fu );
|
||||
return 3;
|
||||
}
|
||||
|
||||
dst[0] = 0xf0u | (( ch >> 18 ) & 0x07u );
|
||||
dst[1] = 0x80u | (( ch >> 12 ) & 0x3fu );
|
||||
dst[2] = 0x80u | (( ch >> 6 ) & 0x3fu );
|
||||
dst[3] = 0x80u | (( ch ) & 0x3fu );
|
||||
return 4;
|
||||
}
|
||||
|
||||
size_t Q_UTF8Length( const char *s )
|
||||
{
|
||||
size_t len = 0;
|
||||
utfstate_t state = { 0 };
|
||||
|
||||
if( !s )
|
||||
return 0;
|
||||
|
||||
for( ; *s; s++ )
|
||||
{
|
||||
uint32_t ch = Q_DecodeUTF8( &state, (uint32_t)*s );
|
||||
|
||||
if( ch == 0 )
|
||||
continue;
|
||||
|
||||
len++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static size_t Q_CodepointLength( uint32_t ch )
|
||||
{
|
||||
if( ch <= 0x7fu )
|
||||
return 1;
|
||||
else if( ch <= 0x7ffu )
|
||||
return 2;
|
||||
else if( ch <= 0xffffu )
|
||||
return 3;
|
||||
|
||||
return 4;
|
||||
}
|
||||
|
||||
size_t Q_UTF16ToUTF8( char *dst, size_t dstsize, const uint16_t *src, size_t srcsize )
|
||||
{
|
||||
utfstate_t state = { 0 };
|
||||
size_t dsti = 0, srci;
|
||||
|
||||
if( !dst || !src || !dstsize || !srcsize )
|
||||
return 0;
|
||||
|
||||
for( srci = 0; srci < srcsize && src[srci]; srci++ )
|
||||
{
|
||||
uint32_t ch;
|
||||
size_t len;
|
||||
|
||||
ch = Q_DecodeUTF16( &state, src[srci] );
|
||||
|
||||
if( ch == 0 )
|
||||
continue;
|
||||
|
||||
len = Q_CodepointLength( ch );
|
||||
|
||||
if( dsti + len + 1 > dstsize )
|
||||
break;
|
||||
|
||||
dsti += Q_EncodeUTF8( &dst[dsti], ch );
|
||||
}
|
||||
|
||||
dst[dsti] = 0;
|
||||
|
||||
return dsti;
|
||||
}
|
||||
40
public/utflib.h
Normal file
40
public/utflib.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
utflib.h - small unicode conversion library
|
||||
Copyright (C) 2024 Alibek Omarov
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
#ifndef UTFLIB_H
|
||||
#define UTFLIB_H
|
||||
|
||||
#include STDINT_H
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct utfstate_s
|
||||
{
|
||||
uint32_t uc;
|
||||
uint8_t len;
|
||||
uint8_t k;
|
||||
} utfstate_t;
|
||||
|
||||
// feed utf8 characters one by one
|
||||
// if it returns 0, feed more
|
||||
// utfstate_t must be zero initialized
|
||||
uint32_t Q_DecodeUTF8( utfstate_t *s, uint32_t ch );
|
||||
uint32_t Q_DecodeUTF16( utfstate_t *s, uint32_t ch );
|
||||
size_t Q_EncodeUTF8( char dst[4], uint32_t ch );
|
||||
|
||||
size_t Q_UTF8Length( const char *s );
|
||||
|
||||
// srcsize in byte pairs
|
||||
size_t Q_UTF16ToUTF8( char *dst, size_t dstsize, const uint16_t *src, size_t srcsize );
|
||||
|
||||
#endif // UTFLIB_H
|
||||
@@ -12,7 +12,9 @@ def options(opt):
|
||||
return
|
||||
|
||||
def configure(conf):
|
||||
conf.define('XASH_BUILD_COMMIT', conf.env.GIT_VERSION if conf.env.GIT_VERSION else 'notset')
|
||||
conf.load('gitversion')
|
||||
conf.define('XASH_BUILD_COMMIT', conf.env.GIT_VERSION if conf.env.GIT_VERSION else 'unknown-commit')
|
||||
conf.define('XASH_BUILD_BRANCH', conf.env.GIT_BRANCH if conf.env.GIT_BRANCH else 'unknown-branch')
|
||||
|
||||
def build(bld):
|
||||
bld(name = 'sdk_includes', export_includes = '. ../common ../pm_shared ../engine')
|
||||
|
||||
@@ -383,7 +383,9 @@ static gl2wrap_prog_t *GL2_GetProg( const GLuint flags )
|
||||
{
|
||||
if( gl2wrap_config.vao_mandatory || gl2wrap_config.incremental )
|
||||
{
|
||||
for( int j = 0; j < gl2wrap_config.cycle_buffers; j++ )
|
||||
int j;
|
||||
|
||||
for( j = 0; j < gl2wrap_config.cycle_buffers; j++ )
|
||||
{
|
||||
pglBindVertexArray( prog->vao_begin[j] );
|
||||
pglEnableVertexAttribArrayARB( prog->attridx[i] );
|
||||
@@ -472,12 +474,14 @@ static void GL2_InitTriQuads( void )
|
||||
|
||||
static void GL2_InitIncrementalBuffer( int i, GLuint size )
|
||||
{
|
||||
int j;
|
||||
|
||||
gl2wrap.attrbufobj[i] = Mem_Calloc( r_temppool, gl2wrap_config.cycle_buffers * sizeof( GLuint ));
|
||||
if( gl2wrap_config.buf_storage )
|
||||
gl2wrap.mappings[i] = Mem_Calloc( r_temppool, gl2wrap_config.cycle_buffers * sizeof( void * ));
|
||||
pglGenBuffersARB( gl2wrap_config.cycle_buffers, gl2wrap.attrbufobj[i] );
|
||||
|
||||
for( int j = 0; j < gl2wrap_config.cycle_buffers; j++ )
|
||||
for( j = 0; j < gl2wrap_config.cycle_buffers; j++ )
|
||||
{
|
||||
rpglBindBufferARB( GL_ARRAY_BUFFER_ARB, gl2wrap.attrbufobj[i][j] );
|
||||
if( gl2wrap_config.buf_storage )
|
||||
@@ -628,7 +632,9 @@ int GL2_ShimInit( void )
|
||||
pglGenBuffersARB( gl2wrap_config.cycle_buffers, gl2wrap.attrbufobj[i] );
|
||||
if( gl2wrap_config.supports_mapbuffer )
|
||||
{
|
||||
for( int j = 0; j < gl2wrap_config.cycle_buffers; j++ )
|
||||
int j;
|
||||
|
||||
for( j = 0; j < gl2wrap_config.cycle_buffers; j++ )
|
||||
{
|
||||
rpglBindBufferARB( GL_ARRAY_BUFFER_ARB, gl2wrap.attrbufobj[i][j] );
|
||||
pglBufferDataARB( GL_ARRAY_BUFFER_ARB, MAX_BEGINEND_VERTS, NULL, GL_STREAM_DRAW_ARB );
|
||||
@@ -1550,6 +1556,7 @@ static void GL2_SetupArrays( GLuint start, GLuint end )
|
||||
{
|
||||
gl2wrap_prog_t *prog;
|
||||
unsigned int flags = gl2wrap_arrays.flags;
|
||||
int i;
|
||||
|
||||
if( !flags )
|
||||
return; // Legacy pointers not used
|
||||
@@ -1573,7 +1580,7 @@ static void GL2_SetupArrays( GLuint start, GLuint end )
|
||||
pglBindVertexArray( gl2wrap_arrays.vao_dynamic );
|
||||
}
|
||||
|
||||
for( int i = 0; i < GL2_ATTR_MAX; i++ )
|
||||
for( i = 0; i < GL2_ATTR_MAX; i++ )
|
||||
{
|
||||
if( prog->attridx[i] < 0 )
|
||||
continue;
|
||||
|
||||
@@ -59,7 +59,7 @@ static int g_used[8192];
|
||||
|
||||
// a pose is a single set of vertexes. a frame may be
|
||||
// an animating sequence of poses
|
||||
int g_posenum;
|
||||
static int g_posenum;
|
||||
|
||||
// the command list holds counts and s/t values that are valid for
|
||||
// every frame
|
||||
|
||||
@@ -28,6 +28,10 @@ GNU General Public License for more details.
|
||||
#define XASH_GL_STATIC
|
||||
#define REF_GL_KEEP_MANGLED_FUNCTIONS
|
||||
#elif defined XASH_GLES3COMPAT
|
||||
#ifdef SOFTFP_LINK
|
||||
#undef APIENTRY
|
||||
#define APIENTRY __attribute__((pcs("aapcs")))
|
||||
#endif
|
||||
#define XASH_GLES
|
||||
#endif
|
||||
|
||||
|
||||
@@ -631,9 +631,12 @@ static void GL_SetTextureTarget( gl_texture_t *tex, rgbdata_t *pic )
|
||||
pic->numMips = Q_max( 1, pic->numMips );
|
||||
|
||||
// trying to determine texture type
|
||||
#ifndef XASH_GLES
|
||||
if( pic->width > 1 && pic->height <= 1 )
|
||||
tex->target = GL_TEXTURE_1D;
|
||||
else if( FBitSet( pic->flags, IMAGE_CUBEMAP ))
|
||||
else
|
||||
#endif // just skip first condition
|
||||
if( FBitSet( pic->flags, IMAGE_CUBEMAP ))
|
||||
tex->target = GL_TEXTURE_CUBE_MAP_ARB;
|
||||
else if( FBitSet( pic->flags, IMAGE_MULTILAYER ) && pic->depth >= 1 )
|
||||
tex->target = GL_TEXTURE_2D_ARRAY_EXT;
|
||||
@@ -1468,6 +1471,22 @@ static void GL_DeleteTexture( gl_texture_t *tex )
|
||||
prev = &cur->nextHash;
|
||||
}
|
||||
|
||||
// invalidate texture units state cache
|
||||
for( int i = 0; i < MAX_TEXTURE_UNITS; i++ )
|
||||
{
|
||||
if( glState.currentTextures[i] == tex->texnum )
|
||||
{
|
||||
if( glState.currentTextureTargets[i] != GL_NONE )
|
||||
{
|
||||
GL_SelectTexture( i );
|
||||
pglDisable( glState.currentTextureTargets[i] );
|
||||
}
|
||||
glState.currentTextureTargets[i] = GL_NONE;
|
||||
glState.currentTextures[i] = -1;
|
||||
glState.currentTexturesIndex[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// release source
|
||||
if( tex->original )
|
||||
gEngfuncs.FS_FreeImage( tex->original );
|
||||
|
||||
@@ -780,6 +780,7 @@ extern convar_t r_traceglow;
|
||||
extern convar_t r_vbo;
|
||||
extern convar_t r_vbo_dlightmode;
|
||||
extern convar_t r_vbo_detail;
|
||||
extern convar_t r_vbo_overbrightmode;
|
||||
extern convar_t r_studio_sort_textures;
|
||||
extern convar_t r_studio_drawelements;
|
||||
extern convar_t r_ripple;
|
||||
|
||||
@@ -32,6 +32,7 @@ CVAR_DEFINE_AUTO( gl_round_down, "2", FCVAR_GLCONFIG|FCVAR_READ_ONLY, "round tex
|
||||
CVAR_DEFINE( r_vbo, "gl_vbo", "0", FCVAR_ARCHIVE, "draw world using VBO (known to be glitchy)" );
|
||||
CVAR_DEFINE( r_vbo_detail, "gl_vbo_detail", "0", FCVAR_ARCHIVE, "detail vbo mode (0: disable, 1: multipass, 2: singlepass, broken decal dlights)" );
|
||||
CVAR_DEFINE( r_vbo_dlightmode, "gl_vbo_dlightmode", "1", FCVAR_ARCHIVE, "vbo dlight rendering mode (0-1)" );
|
||||
CVAR_DEFINE( r_vbo_overbrightmode, "gl_vbo_overbrightmode", "0", FCVAR_ARCHIVE, "vbo overbright rendering mode (0-1)" );
|
||||
CVAR_DEFINE_AUTO( r_ripple, "0", FCVAR_GLCONFIG, "enable software-like water texture ripple simulation" );
|
||||
CVAR_DEFINE_AUTO( r_ripple_updatetime, "0.05", FCVAR_GLCONFIG, "how fast ripple simulation is" );
|
||||
CVAR_DEFINE_AUTO( r_ripple_spawntime, "0.1", FCVAR_GLCONFIG, "how fast new ripples spawn" );
|
||||
@@ -1248,6 +1249,7 @@ static void R_CheckVBO( void )
|
||||
|
||||
gEngfuncs.Cvar_RegisterVariable( &r_vbo );
|
||||
gEngfuncs.Cvar_RegisterVariable( &r_vbo_dlightmode );
|
||||
gEngfuncs.Cvar_RegisterVariable( &r_vbo_overbrightmode );
|
||||
gEngfuncs.Cvar_RegisterVariable( &r_vbo_detail );
|
||||
}
|
||||
|
||||
|
||||
@@ -1011,10 +1011,11 @@ static void R_CheckGamma( void )
|
||||
ClearBits( gl_overbright.flags, FCVAR_CHANGED );
|
||||
}
|
||||
|
||||
if( gl_overbright.value && FBitSet( r_vbo.flags, FCVAR_CHANGED ))
|
||||
if( gl_overbright.value && ( FBitSet( r_vbo.flags, FCVAR_CHANGED ) || FBitSet( r_vbo_overbrightmode.flags, FCVAR_CHANGED ) ) )
|
||||
{
|
||||
rebuild = true;
|
||||
ClearBits( r_vbo.flags, FCVAR_CHANGED );
|
||||
ClearBits( r_vbo_overbrightmode.flags, FCVAR_CHANGED );
|
||||
}
|
||||
|
||||
if( rebuild )
|
||||
|
||||
@@ -718,7 +718,7 @@ static void R_BuildLightMap( msurface_t *surf, byte *dest, int stride, qboolean
|
||||
tmax = ( info->lightextents[1] / sample_size ) + 1;
|
||||
size = smax * tmax;
|
||||
if( gl_overbright.value )
|
||||
lightscale = r_vbo.value ? 171 : 256;
|
||||
lightscale = (r_vbo.value && !r_vbo_overbrightmode.value) ? 171 : 256;
|
||||
else lightscale = ( pow( 2.0f, 1.0f / v_lightgamma->value ) * 256 ) + 0.5;
|
||||
|
||||
lm = surf->samples;
|
||||
@@ -927,7 +927,8 @@ static void R_BlendLightmaps( void )
|
||||
if( gl_overbright.value )
|
||||
{
|
||||
pglBlendFunc( GL_DST_COLOR, GL_SRC_COLOR );
|
||||
pglColor4f( 128.0f / 192.0f, 128.0f / 192.0f, 128.0f / 192.0f, 1.0f );
|
||||
if(!( r_vbo.value && !r_vbo_overbrightmode.value ))
|
||||
pglColor4f( 128.0f / 192.0f, 128.0f / 192.0f, 128.0f / 192.0f, 1.0f );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2189,15 +2190,30 @@ static void R_SetLightmap( void )
|
||||
|
||||
if( gl_overbright.value )
|
||||
{
|
||||
// GLfloat color[4] = { 128.0f / 192.0f, 128.0f / 192.0f, 128.0f / 192.0f, 1.0f };
|
||||
if( r_vbo_overbrightmode.value == 1 )
|
||||
{
|
||||
GLfloat color[4] = { 128.0f / 192.0f, 128.0f / 192.0f, 128.0f / 192.0f, 1.0f };
|
||||
int tmu = glState.activeTMU;
|
||||
GL_SelectTexture( tmu - 1 );
|
||||
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
|
||||
pglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE );
|
||||
pglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_CONSTANT_ARB );
|
||||
pglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
|
||||
pglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
|
||||
pglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR );
|
||||
pglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE );
|
||||
// doesn't work here for some reason
|
||||
pglTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color );
|
||||
GL_SelectTexture( tmu );
|
||||
}
|
||||
|
||||
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
|
||||
pglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE );
|
||||
pglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB );
|
||||
pglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE );
|
||||
pglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE );
|
||||
pglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB );
|
||||
pglTexEnvi( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 2 );
|
||||
// doesn't work here for some reason
|
||||
// pglTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -46,7 +46,7 @@ R_SpriteLoadFrame
|
||||
upload a single frame
|
||||
====================
|
||||
*/
|
||||
static const dframetype_t *R_SpriteLoadFrame( model_t *mod, const void *pin, mspriteframe_t **ppframe, int num )
|
||||
static const byte *R_SpriteLoadFrame( model_t *mod, const void *pin, mspriteframe_t **ppframe, int num )
|
||||
{
|
||||
dspriteframe_t pinframe;
|
||||
mspriteframe_t *pspriteframe;
|
||||
@@ -82,7 +82,7 @@ static const dframetype_t *R_SpriteLoadFrame( model_t *mod, const void *pin, msp
|
||||
pspriteframe->gl_texturenum = gl_texturenum;
|
||||
*ppframe = pspriteframe;
|
||||
|
||||
return ( const dframetype_t* )(( const byte* )pin + sizeof( dspriteframe_t ) + pinframe.width * pinframe.height * bytes );
|
||||
return (( const byte* )pin + sizeof( dspriteframe_t ) + pinframe.width * pinframe.height * bytes );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -92,7 +92,7 @@ R_SpriteLoadGroup
|
||||
upload a group frames
|
||||
====================
|
||||
*/
|
||||
static const dframetype_t *R_SpriteLoadGroup( model_t *mod, const void *pin, mspriteframe_t **ppframe, int framenum )
|
||||
static const byte *R_SpriteLoadGroup( model_t *mod, const void *pin, mspriteframe_t **ppframe, int framenum )
|
||||
{
|
||||
const dspritegroup_t *pingroup;
|
||||
mspritegroup_t *pspritegroup;
|
||||
@@ -128,9 +128,10 @@ static const dframetype_t *R_SpriteLoadGroup( model_t *mod, const void *pin, msp
|
||||
ptemp = R_SpriteLoadFrame( mod, ptemp, &pspritegroup->frames[i], framenum * 10 + i );
|
||||
}
|
||||
|
||||
return (const dframetype_t *)ptemp;
|
||||
return ptemp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
Mod_LoadSpriteModel
|
||||
@@ -142,7 +143,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
|
||||
{
|
||||
const dsprite_t *pin;
|
||||
const short *numi = NULL;
|
||||
const dframetype_t *pframetype;
|
||||
const byte *pframetype;
|
||||
msprite_t *psprite;
|
||||
int i;
|
||||
|
||||
@@ -152,7 +153,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
|
||||
if( pin->version == SPRITE_VERSION_Q1 || pin->version == SPRITE_VERSION_32 )
|
||||
numi = NULL;
|
||||
else if( pin->version == SPRITE_VERSION_HL )
|
||||
numi = (const short *)(void *)((const byte*)buffer + sizeof( dsprite_hl_t ));
|
||||
numi = (const short *)((const byte*)buffer + sizeof( dsprite_hl_t ));
|
||||
|
||||
r_texFlags = texFlags;
|
||||
sprite_version = pin->version;
|
||||
@@ -164,7 +165,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
|
||||
rgbdata_t *pal;
|
||||
|
||||
pal = gEngfuncs.FS_LoadImage( "#id.pal", (byte *)&i, 768 );
|
||||
pframetype = (const dframetype_t *)(void *)((const byte*)buffer + sizeof( dsprite_q1_t )); // pinq1 + 1
|
||||
pframetype = ((const byte*)buffer + sizeof( dsprite_q1_t )); // pinq1 + 1
|
||||
gEngfuncs.FS_FreeImage( pal ); // palette installed, no reason to keep this data
|
||||
}
|
||||
else if( *numi == 256 )
|
||||
@@ -186,7 +187,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
|
||||
break;
|
||||
}
|
||||
|
||||
pframetype = (const dframetype_t *)(void *)(src + 768);
|
||||
pframetype = (const byte *)(src + 768);
|
||||
gEngfuncs.FS_FreeImage( pal ); // palette installed, no reason to keep this data
|
||||
}
|
||||
else
|
||||
@@ -200,22 +201,26 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
|
||||
|
||||
for( i = 0; i < mod->numframes; i++ )
|
||||
{
|
||||
frametype_t frametype = pframetype->type;
|
||||
frametype_t frametype;
|
||||
dframetype_t dframetype;
|
||||
|
||||
memcpy( &dframetype, pframetype, sizeof( dframetype ));
|
||||
frametype = dframetype.type;
|
||||
psprite->frames[i].type = (spriteframetype_t)frametype;
|
||||
|
||||
switch( frametype )
|
||||
{
|
||||
case FRAME_SINGLE:
|
||||
Q_strncpy( group_suffix, "frame", sizeof( group_suffix ));
|
||||
pframetype = R_SpriteLoadFrame( mod, pframetype + 1, &psprite->frames[i].frameptr, i );
|
||||
pframetype = R_SpriteLoadFrame( mod, pframetype + sizeof( dframetype_t ), &psprite->frames[i].frameptr, i );
|
||||
break;
|
||||
case FRAME_GROUP:
|
||||
Q_strncpy( group_suffix, "group", sizeof( group_suffix ));
|
||||
pframetype = R_SpriteLoadGroup( mod, pframetype + 1, &psprite->frames[i].frameptr, i );
|
||||
pframetype = R_SpriteLoadGroup( mod, pframetype + sizeof( dframetype_t ), &psprite->frames[i].frameptr, i );
|
||||
break;
|
||||
case FRAME_ANGLED:
|
||||
Q_strncpy( group_suffix, "angle", sizeof( group_suffix ));
|
||||
pframetype = R_SpriteLoadGroup( mod, pframetype + 1, &psprite->frames[i].frameptr, i );
|
||||
pframetype = R_SpriteLoadGroup( mod, pframetype + sizeof( dframetype_t ), &psprite->frames[i].frameptr, i );
|
||||
break;
|
||||
}
|
||||
if( pframetype == NULL ) break; // technically an error
|
||||
|
||||
@@ -968,6 +968,7 @@ void R_UploadRipples( texture_t *image )
|
||||
gl_texture_t *glt;
|
||||
uint32_t *pixels;
|
||||
int wbits, wmask, wshft;
|
||||
int y;
|
||||
|
||||
// discard unuseful textures
|
||||
if( !r_ripple.value || image->width > RIPPLES_CACHEWIDTH || image->width != image->height )
|
||||
@@ -1005,11 +1006,12 @@ void R_UploadRipples( texture_t *image )
|
||||
wshft = 7 - wbits;
|
||||
wmask = image->width - 1;
|
||||
|
||||
for( int y = 0; y < image->height; y++ )
|
||||
for( y = 0; y < image->height; y++ )
|
||||
{
|
||||
int ry = y << ( 7 + wshft );
|
||||
int x;
|
||||
|
||||
for( int x = 0; x < image->width; x++ )
|
||||
for( x = 0; x < image->width; x++ )
|
||||
{
|
||||
int rx = x << wshft;
|
||||
int val = g_ripple.curbuf[ry + rx] >> 4;
|
||||
|
||||
@@ -51,6 +51,7 @@ static void R_SimpleStubBool( qboolean )
|
||||
|
||||
static qboolean R_Init( void )
|
||||
{
|
||||
gEngfuncs.R_Init_Video( REF_SOFTWARE );
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -178,7 +179,14 @@ static void GL_SubdivideSurface( model_t *mod, msurface_t *fa )
|
||||
|
||||
static void R_GetSpriteParms( int *frameWidth, int *frameHeight, int *numFrames, int currentFrame, const model_t *pSprite )
|
||||
{
|
||||
*frameWidth = *frameHeight = *numFrames = 0;
|
||||
if( frameWidth )
|
||||
*frameWidth = 0;
|
||||
|
||||
if( frameHeight )
|
||||
*frameHeight = 0;
|
||||
|
||||
if( numFrames )
|
||||
*numFrames = 0;
|
||||
}
|
||||
|
||||
static int R_GetSpriteTexture( const model_t *m_pSpriteModel, int frame )
|
||||
@@ -194,7 +202,7 @@ static void Mod_LoadMapSprite( struct model_s *mod, const void *buffer, size_t s
|
||||
|
||||
static qboolean Mod_ProcessRenderData( model_t *mod, qboolean create, const byte *buffer )
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void Mod_StudioLoadTextures( model_t *mod, void *data )
|
||||
|
||||
@@ -95,7 +95,11 @@ static void R_DrawStretchPicImplementation( int x, int y, int w, int h, int s1,
|
||||
//gEngfuncs.Con_Printf ("pixels is %p\n", pic->pixels[0] );
|
||||
|
||||
height = h;
|
||||
if (y < 0)
|
||||
|
||||
if( y < -h ) // out of display, out of bounds
|
||||
return;
|
||||
|
||||
if( y < 0 )
|
||||
{
|
||||
skip = -y;
|
||||
height += y;
|
||||
|
||||
@@ -46,7 +46,7 @@ R_SpriteLoadFrame
|
||||
upload a single frame
|
||||
====================
|
||||
*/
|
||||
static const dframetype_t *R_SpriteLoadFrame( model_t *mod, const void *pin, mspriteframe_t **ppframe, int num )
|
||||
static const byte *R_SpriteLoadFrame( model_t *mod, const void *pin, mspriteframe_t **ppframe, int num )
|
||||
{
|
||||
dspriteframe_t pinframe;
|
||||
mspriteframe_t *pspriteframe;
|
||||
@@ -82,7 +82,7 @@ static const dframetype_t *R_SpriteLoadFrame( model_t *mod, const void *pin, msp
|
||||
pspriteframe->gl_texturenum = gl_texturenum;
|
||||
*ppframe = pspriteframe;
|
||||
|
||||
return ( const dframetype_t* )(( const byte* )pin + sizeof( dspriteframe_t ) + pinframe.width * pinframe.height * bytes );
|
||||
return ( const byte* )(( const byte* )pin + sizeof( dspriteframe_t ) + pinframe.width * pinframe.height * bytes );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -92,7 +92,7 @@ R_SpriteLoadGroup
|
||||
upload a group frames
|
||||
====================
|
||||
*/
|
||||
static const dframetype_t *R_SpriteLoadGroup( model_t *mod, const void *pin, mspriteframe_t **ppframe, int framenum )
|
||||
static const void *R_SpriteLoadGroup( model_t *mod, const void *pin, mspriteframe_t **ppframe, int framenum )
|
||||
{
|
||||
const dspritegroup_t *pingroup;
|
||||
mspritegroup_t *pspritegroup;
|
||||
@@ -128,7 +128,7 @@ static const dframetype_t *R_SpriteLoadGroup( model_t *mod, const void *pin, msp
|
||||
ptemp = R_SpriteLoadFrame( mod, ptemp, &pspritegroup->frames[i], framenum * 10 + i );
|
||||
}
|
||||
|
||||
return (const dframetype_t *)ptemp;
|
||||
return ptemp;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -142,7 +142,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
|
||||
{
|
||||
const dsprite_t *pin;
|
||||
const short *numi = NULL;
|
||||
const dframetype_t *pframetype;
|
||||
const byte *pframetype;
|
||||
msprite_t *psprite;
|
||||
int i;
|
||||
|
||||
@@ -164,7 +164,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
|
||||
rgbdata_t *pal;
|
||||
|
||||
pal = gEngfuncs.FS_LoadImage( "#id.pal", (byte *)&i, 768 );
|
||||
pframetype = (const dframetype_t *)((const byte*)buffer + sizeof( dsprite_q1_t )); // pinq1 + 1
|
||||
pframetype = ((const byte*)buffer + sizeof( dsprite_q1_t )); // pinq1 + 1
|
||||
gEngfuncs.FS_FreeImage( pal ); // palette installed, no reason to keep this data
|
||||
}
|
||||
else if( *numi == 256 )
|
||||
@@ -186,7 +186,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
|
||||
break;
|
||||
}
|
||||
|
||||
pframetype = (const dframetype_t *)(src + 768);
|
||||
pframetype = (const byte *)(src + 768);
|
||||
gEngfuncs.FS_FreeImage( pal ); // palette installed, no reason to keep this data
|
||||
}
|
||||
else
|
||||
@@ -200,22 +200,26 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
|
||||
|
||||
for( i = 0; i < mod->numframes; i++ )
|
||||
{
|
||||
frametype_t frametype = pframetype->type;
|
||||
frametype_t frametype;
|
||||
dframetype_t dframetype;
|
||||
|
||||
memcpy( &dframetype, pframetype, sizeof( dframetype ));
|
||||
frametype = dframetype.type;
|
||||
psprite->frames[i].type = (spriteframetype_t)frametype;
|
||||
|
||||
switch( frametype )
|
||||
{
|
||||
case FRAME_SINGLE:
|
||||
Q_strncpy( group_suffix, "frame", sizeof( group_suffix ));
|
||||
pframetype = R_SpriteLoadFrame( mod, pframetype + 1, &psprite->frames[i].frameptr, i );
|
||||
pframetype = R_SpriteLoadFrame( mod, pframetype + sizeof( dframetype_t ), &psprite->frames[i].frameptr, i );
|
||||
break;
|
||||
case FRAME_GROUP:
|
||||
Q_strncpy( group_suffix, "group", sizeof( group_suffix ));
|
||||
pframetype = R_SpriteLoadGroup( mod, pframetype + 1, &psprite->frames[i].frameptr, i );
|
||||
pframetype = R_SpriteLoadGroup( mod, pframetype + sizeof( dframetype_t ), &psprite->frames[i].frameptr, i );
|
||||
break;
|
||||
case FRAME_ANGLED:
|
||||
Q_strncpy( group_suffix, "angle", sizeof( group_suffix ));
|
||||
pframetype = R_SpriteLoadGroup( mod, pframetype + 1, &psprite->frames[i].frameptr, i );
|
||||
pframetype = R_SpriteLoadGroup( mod, pframetype + sizeof( dframetype_t ), &psprite->frames[i].frameptr, i );
|
||||
break;
|
||||
}
|
||||
if( pframetype == NULL ) break; // technically an error
|
||||
|
||||
@@ -64,6 +64,7 @@ CFLAGS = {
|
||||
'msvc': ['/O2', '/Oy', '/Zi'],
|
||||
'gcc': {
|
||||
'3': ['-O3', '-fomit-frame-pointer'],
|
||||
'4': ['-Ofast', '-funsafe-math-optimizations', '-funsafe-loop-optimizations', '-fomit-frame-pointer'],
|
||||
'default': ['-Ofast', '-funsafe-math-optimizations', '-funsafe-loop-optimizations', '-fomit-frame-pointer', '-fno-semantic-interposition']
|
||||
},
|
||||
'clang': ['-Ofast'],
|
||||
@@ -78,7 +79,11 @@ CFLAGS = {
|
||||
'humanrights': {
|
||||
'msvc': ['/O2', '/Zi'],
|
||||
'owcc': ['-O3', '-foptimize-sibling-calls', '-fomit-leaf-frame-pointer', '-fomit-frame-pointer', '-fschedule-insns', '-funsafe-math-optimizations', '-funroll-loops', '-frerun-optimizer', '-finline-functions', '-finline-limit=512', '-fguess-branch-probability', '-fno-strict-aliasing', '-floop-optimize'],
|
||||
'gcc': ['-O3', '-fno-semantic-interposition'],
|
||||
'gcc': {
|
||||
'4': ['-O3'],
|
||||
'3': ['-O3'],
|
||||
'default': ['-O3','-fno-semantic-interposition'],
|
||||
},
|
||||
'default': ['-O3']
|
||||
},
|
||||
'debug': {
|
||||
|
||||
@@ -601,6 +601,12 @@ void WriteQCScript( void )
|
||||
fputs( "$scale 1.0\n", fp );
|
||||
fputs( "\n", fp );
|
||||
|
||||
if( model_hdr->flags & STUDIO_HAS_BONEINFO )
|
||||
{
|
||||
if( model_hdr->flags & STUDIO_HAS_BONEWEIGHTS )
|
||||
fputs( "$boneweights\n\n", fp );
|
||||
}
|
||||
|
||||
WriteBodyGroupInfo( fp );
|
||||
|
||||
fprintf( fp, "$flags %u\n\n", model_hdr->flags &~( STUDIO_HAS_BONEINFO | STUDIO_HAS_BONEWEIGHTS ) );
|
||||
@@ -611,10 +617,6 @@ void WriteQCScript( void )
|
||||
|
||||
WriteSkinFamilyInfo( fp );
|
||||
WriteTextureRenderMode( fp );
|
||||
|
||||
if( model_hdr->flags & ( STUDIO_HAS_BONEINFO | STUDIO_HAS_BONEWEIGHTS ) )
|
||||
fputs( "$boneweights\n\n", fp );
|
||||
|
||||
WriteAttachmentInfo( fp );
|
||||
|
||||
fprintf( fp, "$bbox %f %f %f", model_hdr->min[0], model_hdr->min[1], model_hdr->min[2] );
|
||||
|
||||
4
wscript
4
wscript
@@ -181,7 +181,7 @@ def configure(conf):
|
||||
if conf.env.COMPILER_CC == 'msvc':
|
||||
conf.load('msvc_pdb')
|
||||
|
||||
conf.load('msvs msdev subproject gitversion clang_compilation_database strip_on_install waf_unit_test enforce_pic cmake')
|
||||
conf.load('msvs msdev subproject clang_compilation_database strip_on_install waf_unit_test enforce_pic cmake')
|
||||
|
||||
# Force XP compatibility, all build targets should add subsystem=bld.env.MSVC_SUBSYSTEM
|
||||
if conf.env.MSVC_TARGETS[0] == 'x86':
|
||||
@@ -197,7 +197,7 @@ def configure(conf):
|
||||
if conf.env.DEST_OS == 'android':
|
||||
conf.options.NO_VGUI = True # skip vgui
|
||||
conf.options.NANOGL = True
|
||||
conf.options.GLWES = True
|
||||
conf.options.GLWES = False # deprecated
|
||||
conf.options.GL4ES = True
|
||||
conf.options.GLES3COMPAT = True
|
||||
conf.options.GL = False
|
||||
|
||||
Reference in New Issue
Block a user