mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-06 04:05:11 +08:00
Compare commits
62 Commits
continuous
...
continuous
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60c6767337 | ||
|
|
75451cc7fa | ||
|
|
db10035d9d | ||
|
|
de21d845ec | ||
|
|
320f8466e6 | ||
|
|
f3208e95b2 | ||
|
|
ea34bc8652 | ||
|
|
3daf014af8 | ||
|
|
ca9d3d262a | ||
|
|
a08f5e439d | ||
|
|
8f6771dff4 | ||
|
|
cd47c6b5b3 | ||
|
|
1f4f3d7fda | ||
|
|
e81b5144b3 | ||
|
|
9ec1caed53 | ||
|
|
ca3b4a9d7f | ||
|
|
87ac217887 | ||
|
|
213650db8f | ||
|
|
ac46164a6e | ||
|
|
6d12d84e94 | ||
|
|
2a18cde60c | ||
|
|
35783bcec2 | ||
|
|
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 |
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:
|
task:
|
||||||
name: freebsd-13-amd64
|
name: freebsd-13-amd64
|
||||||
freebsd_instance:
|
freebsd_instance:
|
||||||
@@ -26,7 +13,7 @@ task:
|
|||||||
task:
|
task:
|
||||||
name: freebsd-14-amd64
|
name: freebsd-14-amd64
|
||||||
freebsd_instance:
|
freebsd_instance:
|
||||||
image_family: freebsd-14-0-snap
|
image_family: freebsd-14-0
|
||||||
setup_script:
|
setup_script:
|
||||||
- pkg update
|
- pkg update
|
||||||
- pkg install -y pkgconf git sdl2 python fontconfig opus
|
- pkg install -y pkgconf git sdl2 python fontconfig opus
|
||||||
|
|||||||
2
3rdparty/mainui
vendored
2
3rdparty/mainui
vendored
Submodule 3rdparty/mainui updated: d75b7f4a57...f5497ceb04
@@ -1,17 +1,15 @@
|
|||||||
# Bug-compatibility in Xash3D FWGS
|
# Bug-compatibility in Xash3D FWGS
|
||||||
|
|
||||||
Xash3D FWGS has special mode for games that rely on original engine bugs.
|
Xash3D FWGS has special mode for games that rely on original engine bugs. In this mode, we emulate the behaviour of selected functions that may help running mods relying on engine bugs, but enabling them by default may break majority of other games.
|
||||||
|
|
||||||
In this mode, we emulate the behaviour of selected functions that may help running mods relying on engine bugs, but enabling them by default may break majority of other games.
|
|
||||||
|
|
||||||
At this time, we only have implemented GoldSrc bug-compatibility. It can be enabled with `-bugcomp` command line switch.
|
At this time, we only have implemented GoldSrc bug-compatibility. It can be enabled with `-bugcomp` command line switch.
|
||||||
|
|
||||||
|
When `-bugcomp` is specified without argument, it enables everything. This behavior might be changed or removed in future versions.
|
||||||
|
|
||||||
|
When `-bugcomp` is specified with argument, it interpreted as flags separated with `+`. This way it's possible to combine multiple levels of bug-compatibility.
|
||||||
|
|
||||||
## GoldSrc bug-compatibility
|
## GoldSrc bug-compatibility
|
||||||
|
|
||||||
### Emulated bugs
|
| Flag | Description | Games that require this flag |
|
||||||
|
| ------- | ----------- | ---------------------------- |
|
||||||
* `pfnPEntityOfEntIndex` in GoldSrc returns NULL for last player due to incorrect player index comparison
|
| `peoei` | Reverts `pfnPEntityOfEntIndex` behavior to GoldSrc, where it returns NULL for last player due to incorrect player index comparison | * Counter-Strike: Condition Zero - Deleted Scenes |
|
||||||
|
|
||||||
### Games and mods that require this
|
|
||||||
|
|
||||||
* Counter-Strike: Condition Zero - Deleted Scenes
|
|
||||||
|
|||||||
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 |
|
||||||
@@ -28,11 +28,7 @@ typedef byte rgb_t[3]; // unsigned byte colorpack
|
|||||||
typedef vec_t matrix3x4[3][4];
|
typedef vec_t matrix3x4[3][4];
|
||||||
typedef vec_t matrix4x4[4][4];
|
typedef vec_t matrix4x4[4][4];
|
||||||
|
|
||||||
#if XASH_64BIT
|
|
||||||
typedef uint32_t poolhandle_t;
|
typedef uint32_t poolhandle_t;
|
||||||
#else
|
|
||||||
typedef void* poolhandle_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#undef true
|
#undef true
|
||||||
#undef false
|
#undef false
|
||||||
|
|||||||
@@ -50,7 +50,15 @@ const char *CL_MsgInfo( int cmd )
|
|||||||
if( cmd >= 0 && cmd <= svc_lastmsg )
|
if( cmd >= 0 && cmd <= svc_lastmsg )
|
||||||
{
|
{
|
||||||
// get engine message name
|
// get engine message name
|
||||||
Q_strncpy( sz, svc_strings[cmd], sizeof( sz ));
|
const char *svc_string = NULL;
|
||||||
|
|
||||||
|
if( cls.legacymode )
|
||||||
|
svc_string = svc_legacy_strings[cmd];
|
||||||
|
|
||||||
|
if( !svc_string )
|
||||||
|
svc_string = svc_strings[cmd];
|
||||||
|
|
||||||
|
Q_strncpy( sz, svc_string, sizeof( sz ));
|
||||||
}
|
}
|
||||||
else if( cmd > svc_lastmsg && cmd <= ( svc_lastmsg + MAX_USER_MESSAGES ))
|
else if( cmd > svc_lastmsg && cmd <= ( svc_lastmsg + MAX_USER_MESSAGES ))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1448,7 +1448,7 @@ pfnSPR_Draw
|
|||||||
*/
|
*/
|
||||||
static void GAME_EXPORT pfnSPR_Draw( int frame, int x, int y, const wrect_t *prc )
|
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 );
|
SPR_DrawGeneric( frame, x, y, -1, -1, prc );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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_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_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_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_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_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" );
|
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
|
Voice_InitOpusDecoder
|
||||||
@@ -47,24 +67,17 @@ Voice_InitOpusDecoder
|
|||||||
*/
|
*/
|
||||||
static qboolean Voice_InitOpusDecoder( void )
|
static qboolean Voice_InitOpusDecoder( void )
|
||||||
{
|
{
|
||||||
int err;
|
int err = 0;
|
||||||
|
|
||||||
voice.width = sizeof( opus_int16 );
|
for( int i = 0; i < cl.maxclients; i++ )
|
||||||
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 ));
|
voice.decoders[i] = opus_custom_decoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
|
||||||
|
|
||||||
|
if( !voice.decoders[i] )
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "Can't create Opus decoder for %i: %s\n", i, opus_strerror( err ));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
voice.decoder = opus_custom_decoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
|
|
||||||
if( !voice.decoder )
|
|
||||||
{
|
|
||||||
Con_Printf( S_ERROR "Can't create Opus encoder: %s\n", opus_strerror( err ));
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -78,7 +91,7 @@ Voice_InitOpusEncoder
|
|||||||
*/
|
*/
|
||||||
static qboolean Voice_InitOpusEncoder( int quality )
|
static qboolean Voice_InitOpusEncoder( int quality )
|
||||||
{
|
{
|
||||||
int err;
|
int err = 0;
|
||||||
|
|
||||||
voice.encoder = opus_custom_encoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
|
voice.encoder = opus_custom_encoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
|
||||||
if( !voice.encoder )
|
if( !voice.encoder )
|
||||||
@@ -117,10 +130,13 @@ Voice_ShutdownOpusDecoder
|
|||||||
*/
|
*/
|
||||||
static void Voice_ShutdownOpusDecoder( void )
|
static void Voice_ShutdownOpusDecoder( void )
|
||||||
{
|
{
|
||||||
if( voice.decoder )
|
for( int i = 0; i < MAX_CLIENTS; i++ )
|
||||||
{
|
{
|
||||||
opus_custom_decoder_destroy( voice.decoder );
|
if( !voice.decoders[i] )
|
||||||
voice.decoder = NULL;
|
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 );
|
opus_custom_encoder_destroy( voice.encoder );
|
||||||
voice.encoder = NULL;
|
voice.encoder = NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Voice_ShutdownCustomMode( void )
|
||||||
|
{
|
||||||
if( voice.custom_mode )
|
if( voice.custom_mode )
|
||||||
{
|
{
|
||||||
opus_custom_mode_destroy( 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 )
|
if( !voice.input_file )
|
||||||
{
|
{
|
||||||
// adjust gain before encoding, but only for input from voice
|
// 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
|
#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;
|
float gain, modifiedMax;
|
||||||
int average, adjustedSample, blockOffset = 0;
|
int average, blockOffset = 0;
|
||||||
|
|
||||||
for( ;; )
|
for( ;; )
|
||||||
{
|
{
|
||||||
@@ -260,10 +279,8 @@ static void Voice_ApplyGainAdjust( int16_t *samples, int count )
|
|||||||
localMax = absSample;
|
localMax = absSample;
|
||||||
|
|
||||||
localSum += absSample;
|
localSum += absSample;
|
||||||
|
|
||||||
gain = voice.autogain.current_gain + i * voice.autogain.gain_multiplier;
|
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] = bound( SHRT_MIN, (int)( sample * gain ), SHRT_MAX );
|
||||||
samples[blockOffset + i] = adjustedSample;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( blockOffset % voice.autogain.block_size == 0 )
|
if( blockOffset % voice.autogain.block_size == 0 )
|
||||||
@@ -271,9 +288,9 @@ static void Voice_ApplyGainAdjust( int16_t *samples, int count )
|
|||||||
average = localSum / blockSize;
|
average = localSum / blockSize;
|
||||||
modifiedMax = average + ( localMax - average ) * voice_avggain.value;
|
modifiedMax = average + ( localMax - average ) * voice_avggain.value;
|
||||||
|
|
||||||
voice.autogain.current_gain = voice.autogain.next_gain * voice_scale.value;
|
voice.autogain.current_gain = voice.autogain.next_gain * scale;
|
||||||
voice.autogain.next_gain = Q_min( (float)SHRT_MAX / modifiedMax, voice_maxgain.value ) * voice_scale.value;
|
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 ) / ( voice.autogain.block_size - 1 );
|
voice.autogain.gain_multiplier = ( voice.autogain.next_gain - voice.autogain.current_gain ) / ( blockSize - 1 );
|
||||||
}
|
}
|
||||||
blockOffset += blockSize;
|
blockOffset += blockSize;
|
||||||
}
|
}
|
||||||
@@ -443,7 +460,7 @@ Feed the decoded data to engine sound subsystem
|
|||||||
static void Voice_StartChannel( uint samples, byte *data, int entnum )
|
static void Voice_StartChannel( uint samples, byte *data, int entnum )
|
||||||
{
|
{
|
||||||
SND_ForceInitMouth( 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 )
|
void Voice_AddIncomingData( int ent, const byte *data, uint size, uint frames )
|
||||||
{
|
{
|
||||||
|
const int playernum = ent - 1;
|
||||||
int samples = 0;
|
int samples = 0;
|
||||||
int ofs = 0;
|
int ofs = 0;
|
||||||
|
|
||||||
if( !voice.decoder )
|
if( playernum < 0 || playernum >= cl.maxclients || !voice.decoders[playernum] )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// decode frame by frame
|
// 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 )
|
if( ofs + compressed_size > size )
|
||||||
break;
|
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 );
|
(opus_int16*)voice.decompress_buffer + samples, voice.frame_size );
|
||||||
|
|
||||||
ofs += compressed_size;
|
ofs += compressed_size;
|
||||||
@@ -503,7 +521,7 @@ void CL_AddVoiceToDatagram( void )
|
|||||||
if( cls.state != ca_active || !Voice_IsRecording() || !voice.encoder )
|
if( cls.state != ca_active || !Voice_IsRecording() || !voice.encoder )
|
||||||
return;
|
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 )
|
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, voice_loopback.value != 0 );
|
||||||
MSG_WriteByte( &cls.datagram, frames );
|
MSG_WriteByte( &cls.datagram, frames );
|
||||||
MSG_WriteShort( &cls.datagram, size );
|
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_enable );
|
||||||
Cvar_RegisterVariable( &voice_loopback );
|
Cvar_RegisterVariable( &voice_loopback );
|
||||||
Cvar_RegisterVariable( &voice_scale );
|
Cvar_RegisterVariable( &voice_scale );
|
||||||
|
Cvar_RegisterVariable( &voice_transmit_scale );
|
||||||
Cvar_RegisterVariable( &voice_avggain );
|
Cvar_RegisterVariable( &voice_avggain );
|
||||||
Cvar_RegisterVariable( &voice_maxgain );
|
Cvar_RegisterVariable( &voice_maxgain );
|
||||||
Cvar_RegisterVariable( &voice_inputfromfile );
|
Cvar_RegisterVariable( &voice_inputfromfile );
|
||||||
@@ -544,8 +563,9 @@ static void Voice_Shutdown( void )
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
Voice_RecordStop();
|
Voice_RecordStop();
|
||||||
Voice_ShutdownOpusEncoder();
|
|
||||||
Voice_ShutdownOpusDecoder();
|
Voice_ShutdownOpusDecoder();
|
||||||
|
Voice_ShutdownOpusEncoder();
|
||||||
|
Voice_ShutdownCustomMode();
|
||||||
VoiceCapture_Shutdown();
|
VoiceCapture_Shutdown();
|
||||||
|
|
||||||
if( voice.local.talking_ack )
|
if( voice.local.talking_ack )
|
||||||
@@ -609,11 +629,10 @@ qboolean Voice_Init( const char *pszCodecName, int quality, qboolean preinit )
|
|||||||
|
|
||||||
voice.autogain.block_size = 128;
|
voice.autogain.block_size = 128;
|
||||||
|
|
||||||
if( !Voice_InitOpusDecoder( ))
|
if( !Voice_InitCustomMode( ))
|
||||||
{
|
{
|
||||||
// no reason to init encoder and open audio device
|
// no reason to init encoder and open audio device
|
||||||
// if we can't hear other players
|
// if we can't hear other players
|
||||||
Con_Printf( S_ERROR "Voice chat disabled.\n" );
|
|
||||||
Voice_Shutdown();
|
Voice_Shutdown();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -633,6 +652,16 @@ qboolean Voice_Init( const char *pszCodecName, int quality, qboolean preinit )
|
|||||||
|
|
||||||
if( !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();
|
voice.device_opened = VoiceCapture_Init();
|
||||||
|
|
||||||
if( !voice.device_opened )
|
if( !voice.device_opened )
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ typedef struct voice_state_s
|
|||||||
// opus stuff
|
// opus stuff
|
||||||
OpusCustomMode *custom_mode;
|
OpusCustomMode *custom_mode;
|
||||||
OpusCustomEncoder *encoder;
|
OpusCustomEncoder *encoder;
|
||||||
OpusCustomDecoder *decoder;
|
OpusCustomDecoder *decoders[MAX_CLIENTS];
|
||||||
|
|
||||||
// audio info
|
// audio info
|
||||||
uint width;
|
uint width;
|
||||||
@@ -71,7 +71,7 @@ typedef struct voice_state_s
|
|||||||
|
|
||||||
// buffers
|
// buffers
|
||||||
byte input_buffer[MAX_RAW_SAMPLES];
|
byte input_buffer[MAX_RAW_SAMPLES];
|
||||||
byte output_buffer[MAX_RAW_SAMPLES];
|
byte compress_buffer[MAX_RAW_SAMPLES];
|
||||||
byte decompress_buffer[MAX_RAW_SAMPLES];
|
byte decompress_buffer[MAX_RAW_SAMPLES];
|
||||||
fs_offset_t input_buffer_pos; // in bytes
|
fs_offset_t input_buffer_pos; // in bytes
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ GNU General Public License for more details.
|
|||||||
#define DEFAULT_UPDATE_PAGE "https://github.com/FWGS/xash3d-fwgs/releases/latest"
|
#define DEFAULT_UPDATE_PAGE "https://github.com/FWGS/xash3d-fwgs/releases/latest"
|
||||||
|
|
||||||
#define XASH_ENGINE_NAME "Xash3D FWGS"
|
#define XASH_ENGINE_NAME "Xash3D FWGS"
|
||||||
|
#define XASH_DEDICATED_SERVER_NAME "XashDS"
|
||||||
#define XASH_VERSION "0.20" // engine current version
|
#define XASH_VERSION "0.20" // engine current version
|
||||||
#define XASH_COMPAT_VERSION "0.99" // version we are based on
|
#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;
|
byte *pFinal = NULL;
|
||||||
lzss_state_t state;
|
lzss_state_t state;
|
||||||
|
|
||||||
|
if( !pStart )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
memset( &state, 0, sizeof( state ));
|
memset( &state, 0, sizeof( state ));
|
||||||
state.window_size = LZSS_WINDOW_SIZE;
|
state.window_size = LZSS_WINDOW_SIZE;
|
||||||
|
|
||||||
|
|||||||
@@ -273,12 +273,8 @@ typedef struct
|
|||||||
|
|
||||||
typedef enum bugcomp_e
|
typedef enum bugcomp_e
|
||||||
{
|
{
|
||||||
// default mode, we assume that user dlls are not relying on engine bugs
|
// reverts fix for pfnPEntityOfEntIndex for bug compatibility with GoldSrc
|
||||||
BUGCOMP_OFF,
|
BUGCOMP_PENTITYOFENTINDEX_FLAG = BIT( 0 ),
|
||||||
|
|
||||||
// GoldSrc mode, user dlls are relying on GoldSrc specific bugs
|
|
||||||
// but fixing them may break regular Xash games
|
|
||||||
BUGCOMP_GOLDSRC,
|
|
||||||
} bugcomp_t;
|
} bugcomp_t;
|
||||||
|
|
||||||
typedef struct host_parm_s
|
typedef struct host_parm_s
|
||||||
@@ -356,7 +352,7 @@ typedef struct host_parm_s
|
|||||||
int numdecals;
|
int numdecals;
|
||||||
|
|
||||||
// bug compatibility level, for very "special" games
|
// bug compatibility level, for very "special" games
|
||||||
bugcomp_t bugcomp;
|
uint32_t bugcomp;
|
||||||
|
|
||||||
// measure time to first frame
|
// measure time to first frame
|
||||||
double starttime;
|
double starttime;
|
||||||
|
|||||||
@@ -866,7 +866,7 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
|
|||||||
return true; // exist
|
return true; // exist
|
||||||
|
|
||||||
// setup mpfilter
|
// 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 );
|
t = FS_Search( "maps/*.bsp", false, onlyingamedir );
|
||||||
|
|
||||||
if( !t )
|
if( !t )
|
||||||
@@ -900,7 +900,7 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
|
|||||||
|
|
||||||
if( f )
|
if( f )
|
||||||
{
|
{
|
||||||
int num_spawnpoints = 0;
|
qboolean have_spawnpoints = false;
|
||||||
dheader_t *header;
|
dheader_t *header;
|
||||||
dlump_t entities;
|
dlump_t entities;
|
||||||
|
|
||||||
@@ -943,7 +943,18 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
|
|||||||
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )
|
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )
|
||||||
{
|
{
|
||||||
if( token[0] == '}' && worldspawn )
|
if( token[0] == '}' && worldspawn )
|
||||||
|
{
|
||||||
worldspawn = false;
|
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 )
|
else if( !Q_strcmp( token, "message" ) && worldspawn )
|
||||||
{
|
{
|
||||||
// get the message contents
|
// get the message contents
|
||||||
@@ -952,17 +963,23 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
|
|||||||
else if( !Q_strcmp( token, "classname" ))
|
else if( !Q_strcmp( token, "classname" ))
|
||||||
{
|
{
|
||||||
pfile = COM_ParseFile( pfile, token, sizeof( token ));
|
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 );
|
Mem_Free( ents );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( f ) FS_Close( f );
|
if( f ) FS_Close( f );
|
||||||
|
|
||||||
if( num_spawnpoints )
|
if( have_spawnpoints )
|
||||||
{
|
{
|
||||||
// format: mapname "maptitle"\n
|
// format: mapname "maptitle"\n
|
||||||
Q_snprintf( result, sizeof( result ), "%s \"%s\"\n", mapname, message );
|
Q_snprintf( result, sizeof( result ), "%s \"%s\"\n", mapname, message );
|
||||||
|
|||||||
@@ -152,8 +152,10 @@ static qboolean Cvar_UpdateInfo( convar_t *var, const char *value, qboolean noti
|
|||||||
if ( Host_IsDedicated() )
|
if ( Host_IsDedicated() )
|
||||||
{
|
{
|
||||||
// g-cont. this is a very strange behavior...
|
// g-cont. this is a very strange behavior...
|
||||||
Info_SetValueForKey( SV_Serverinfo(), var->name, value, MAX_SERVERINFO_STRING ),
|
char *info = SV_Serverinfo();
|
||||||
SV_BroadcastCommand( "fullserverinfo \"%s\"\n", SV_Serverinfo( ));
|
|
||||||
|
Info_SetValueForKey( info, var->name, value, MAX_SERVERINFO_STRING ),
|
||||||
|
SV_BroadcastCommand( "fullserverinfo \"%s\"\n", info );
|
||||||
}
|
}
|
||||||
#if !XASH_DEDICATED
|
#if !XASH_DEDICATED
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -89,32 +89,32 @@ qboolean FS_LoadProgs( void )
|
|||||||
|
|
||||||
if( !fs_hInstance )
|
if( !fs_hInstance )
|
||||||
{
|
{
|
||||||
Host_Error( "FS_LoadProgs: can't load filesystem library %s: %s\n", name, COM_GetLibraryError() );
|
Host_Error( "%s: can't load filesystem library %s: %s\n", __func__, name, COM_GetLibraryError() );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !( GetFSAPI = (FSAPI)COM_GetProcAddress( fs_hInstance, GET_FS_API )))
|
if( !( GetFSAPI = (FSAPI)COM_GetProcAddress( fs_hInstance, GET_FS_API )))
|
||||||
{
|
{
|
||||||
FS_UnloadProgs();
|
FS_UnloadProgs();
|
||||||
Host_Error( "FS_LoadProgs: can't find GetFSAPI entry point in %s\n", name );
|
Host_Error( "%s: can't find GetFSAPI entry point in %s\n", __func__, name );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !GetFSAPI( FS_API_VERSION, &g_fsapi, &FI, &fs_memfuncs ))
|
if( GetFSAPI( FS_API_VERSION, &g_fsapi, &FI, &fs_memfuncs ) != FS_API_VERSION )
|
||||||
{
|
{
|
||||||
FS_UnloadProgs();
|
FS_UnloadProgs();
|
||||||
Host_Error( "FS_LoadProgs: can't initialize filesystem API: wrong version\n" );
|
Host_Error( "%s: can't initialize filesystem API: wrong version\n", __func__ );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !( fs_pfnCreateInterface = (pfnCreateInterface_t)COM_GetProcAddress( fs_hInstance, "CreateInterface" )))
|
if( !( fs_pfnCreateInterface = (pfnCreateInterface_t)COM_GetProcAddress( fs_hInstance, "CreateInterface" )))
|
||||||
{
|
{
|
||||||
FS_UnloadProgs();
|
FS_UnloadProgs();
|
||||||
Host_Error( "FS_LoadProgs: can't find CreateInterface entry point in %s\n", name );
|
Host_Error( "%s: can't find CreateInterface entry point in %s\n", __func__, name );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Con_DPrintf( "FS_LoadProgs: filesystem_stdio successfully loaded\n" );
|
Con_DPrintf( "%s: filesystem_stdio successfully loaded\n", __func__ );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,32 @@ static CVAR_DEFINE( host_sleeptime, "sleeptime", "1", FCVAR_ARCHIVE|FCVAR_FILTER
|
|||||||
static CVAR_DEFINE_AUTO( host_sleeptime_debug, "0", 0, "print sleeps between frames" );
|
static CVAR_DEFINE_AUTO( host_sleeptime_debug, "0", 0, "print sleeps between frames" );
|
||||||
CVAR_DEFINE( con_gamemaps, "con_mapfilter", "1", FCVAR_ARCHIVE, "when true show only maps in game folder" );
|
CVAR_DEFINE( con_gamemaps, "con_mapfilter", "1", FCVAR_ARCHIVE, "when true show only maps in game folder" );
|
||||||
|
|
||||||
|
typedef struct feature_message_s
|
||||||
|
{
|
||||||
|
uint32_t mask;
|
||||||
|
const char *msg;
|
||||||
|
const char *arg;
|
||||||
|
} feature_message_t;
|
||||||
|
|
||||||
|
static feature_message_t bugcomp_features[] =
|
||||||
|
{
|
||||||
|
{ BUGCOMP_PENTITYOFENTINDEX_FLAG, "pfnPEntityOfEntIndex bugfix revert", "peoei" },
|
||||||
|
};
|
||||||
|
|
||||||
|
static feature_message_t engine_features[] =
|
||||||
|
{
|
||||||
|
{ ENGINE_WRITE_LARGE_COORD, "Big World Support" },
|
||||||
|
{ ENGINE_QUAKE_COMPATIBLE, "Quake Compatibility" },
|
||||||
|
{ ENGINE_LOAD_DELUXEDATA, "Deluxemap Support" },
|
||||||
|
{ ENGINE_PHYSICS_PUSHER_EXT, "Improved MOVETYPE_PUSH" },
|
||||||
|
{ ENGINE_LARGE_LIGHTMAPS, "Large Lightmaps" },
|
||||||
|
{ ENGINE_COMPENSATE_QUAKE_BUG, "Stupid Quake Bug Compensation" },
|
||||||
|
{ ENGINE_IMPROVED_LINETRACE, "Improved Trace Line" },
|
||||||
|
{ ENGINE_COMPUTE_STUDIO_LERP, "Studio MOVETYPE_STEP Lerping" },
|
||||||
|
{ ENGINE_LINEAR_GAMMA_SPACE, "Linear Gamma Space" },
|
||||||
|
{ ENGINE_STEP_POSHISTORY_LERP, "MOVETYPE_STEP Position History Based Lerping" },
|
||||||
|
};
|
||||||
|
|
||||||
static void Sys_PrintUsage( void )
|
static void Sys_PrintUsage( void )
|
||||||
{
|
{
|
||||||
string version_str;
|
string version_str;
|
||||||
@@ -92,8 +118,9 @@ static void Sys_PrintUsage( void )
|
|||||||
O("-minidumps ", "enable writing minidumps when game is crashed")
|
O("-minidumps ", "enable writing minidumps when game is crashed")
|
||||||
#endif
|
#endif
|
||||||
O("-rodir <path> ", "set read-only base directory")
|
O("-rodir <path> ", "set read-only base directory")
|
||||||
O("-bugcomp ", "enable precise bug compatibility. Will break games that don't require it")
|
O("-bugcomp [opts] ", "enable precise bug compatibility")
|
||||||
O(" ", "Refer to engine documentation for more info")
|
O(" ", "will break games that don't require it")
|
||||||
|
O(" ", "refer to engine documentation for more info")
|
||||||
O("-disablehelp ", "disable this message")
|
O("-disablehelp ", "disable this message")
|
||||||
#if !XASH_DEDICATED
|
#if !XASH_DEDICATED
|
||||||
O("-dedicated ", "run engine in dedicated mode")
|
O("-dedicated ", "run engine in dedicated mode")
|
||||||
@@ -106,7 +133,8 @@ static void Sys_PrintUsage( void )
|
|||||||
O("-noip6 ", "disable IPv6")
|
O("-noip6 ", "disable IPv6")
|
||||||
O("-ip6 <ip> ", "set IPv6 address")
|
O("-ip6 <ip> ", "set IPv6 address")
|
||||||
O("-port6 <port> ", "set IPv6 port")
|
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"
|
"\nGame options:\n"
|
||||||
O("-game <directory>", "set game directory to start engine with")
|
O("-game <directory>", "set game directory to start engine with")
|
||||||
@@ -191,31 +219,14 @@ void Host_ShutdownServer( void )
|
|||||||
Host_PrintEngineFeatures
|
Host_PrintEngineFeatures
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
static void Host_PrintEngineFeatures( int features )
|
static void Host_PrintFeatures( uint32_t flags, const char *s, feature_message_t *features, size_t size )
|
||||||
{
|
{
|
||||||
struct
|
size_t i;
|
||||||
{
|
|
||||||
uint32_t mask;
|
|
||||||
const char *msg;
|
|
||||||
} features_str[] =
|
|
||||||
{
|
|
||||||
{ ENGINE_WRITE_LARGE_COORD, "Big World Support" },
|
|
||||||
{ ENGINE_QUAKE_COMPATIBLE, "Quake Compatibility" },
|
|
||||||
{ ENGINE_LOAD_DELUXEDATA, "Deluxemap Support" },
|
|
||||||
{ ENGINE_PHYSICS_PUSHER_EXT, "Improved MOVETYPE_PUSH" },
|
|
||||||
{ ENGINE_LARGE_LIGHTMAPS, "Large Lightmaps" },
|
|
||||||
{ ENGINE_COMPENSATE_QUAKE_BUG, "Stupid Quake Bug Compensation" },
|
|
||||||
{ ENGINE_IMPROVED_LINETRACE, "Improved Trace Line" },
|
|
||||||
{ ENGINE_COMPUTE_STUDIO_LERP, "Studio MOVETYPE_STEP Lerping" },
|
|
||||||
{ ENGINE_LINEAR_GAMMA_SPACE, "Linear Gamma Space" },
|
|
||||||
{ ENGINE_STEP_POSHISTORY_LERP, "MOVETYPE_STEP Position History Based Lerping" },
|
|
||||||
};
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for( i = 0; i < ARRAYSIZE( features_str ); i++ )
|
for( i = 0; i < size; i++ )
|
||||||
{
|
{
|
||||||
if( FBitSet( features, features_str[i].mask ))
|
if( FBitSet( flags, features[i].mask ))
|
||||||
Con_Reportf( "^3EXT:^7 %s is enabled\n", features_str[i].msg );
|
Con_Printf( "^3%s:^7 %s is enabled\n", s, features[i].msg );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,7 +254,7 @@ void Host_ValidateEngineFeatures( uint32_t features )
|
|||||||
SetBits( features, ENGINE_STEP_POSHISTORY_LERP );
|
SetBits( features, ENGINE_STEP_POSHISTORY_LERP );
|
||||||
|
|
||||||
// print requested first
|
// print requested first
|
||||||
Host_PrintEngineFeatures( features );
|
Host_PrintFeatures( features, "EXT", engine_features, ARRAYSIZE( engine_features ));
|
||||||
|
|
||||||
// now warn about incompatible bits
|
// now warn about incompatible bits
|
||||||
if( FBitSet( features, ENGINE_STEP_POSHISTORY_LERP|ENGINE_COMPUTE_STUDIO_LERP ) == ( ENGINE_STEP_POSHISTORY_LERP|ENGINE_COMPUTE_STUDIO_LERP ))
|
if( FBitSet( features, ENGINE_STEP_POSHISTORY_LERP|ENGINE_COMPUTE_STUDIO_LERP ) == ( ENGINE_STEP_POSHISTORY_LERP|ENGINE_COMPUTE_STUDIO_LERP ))
|
||||||
@@ -939,11 +950,59 @@ static void Host_RunTests( int stage )
|
|||||||
TEST_LIST_1_CLIENT;
|
TEST_LIST_1_CLIENT;
|
||||||
#endif
|
#endif
|
||||||
Msg( "Done! %d passed, %d failed\n", tests_stats.passed, tests_stats.failed );
|
Msg( "Done! %d passed, %d failed\n", tests_stats.passed, tests_stats.failed );
|
||||||
|
error_on_exit = tests_stats.failed > 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||||
Sys_Quit();
|
Sys_Quit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static uint32_t Host_CheckBugcomp( void )
|
||||||
|
{
|
||||||
|
uint32_t flags = 0;
|
||||||
|
string args, arg;
|
||||||
|
char *prev, *next;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if( !Sys_CheckParm( "-bugcomp" ))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if( Sys_GetParmFromCmdLine( "-bugcomp", args ) && args[0] != '-' )
|
||||||
|
{
|
||||||
|
for( prev = args, next = Q_strchrnul( prev, '+' ); ; prev = next + 1, next = Q_strchrnul( prev, '+' ))
|
||||||
|
{
|
||||||
|
Q_strncpy( arg, prev, next - prev + 1 );
|
||||||
|
for( i = 0; i < ARRAYSIZE( bugcomp_features ); i++ )
|
||||||
|
{
|
||||||
|
if( !Q_stricmp( bugcomp_features[i].arg, arg ))
|
||||||
|
{
|
||||||
|
SetBits( flags, bugcomp_features[i].mask );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( i == ARRAYSIZE( bugcomp_features ))
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "Unknown bugcomp flag %s\n", arg );
|
||||||
|
Con_Printf( "Valid flags are:\n" );
|
||||||
|
for( i = 0; i < ARRAYSIZE( bugcomp_features ); i++ )
|
||||||
|
Con_Printf( "\t%s: %s\n", bugcomp_features[i].arg, bugcomp_features[i].msg );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !*next )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// no argument specified -bugcomp just enables everything
|
||||||
|
flags = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Host_PrintFeatures( flags, "BUGCOMP", bugcomp_features, ARRAYSIZE( bugcomp_features ));
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
Host_InitCommon
|
Host_InitCommon
|
||||||
@@ -1048,13 +1107,6 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
|
|||||||
// member console allowing
|
// member console allowing
|
||||||
host.allow_console_init = host.allow_console;
|
host.allow_console_init = host.allow_console;
|
||||||
|
|
||||||
if( Sys_CheckParm( "-bugcomp" ))
|
|
||||||
{
|
|
||||||
// add argument check here when we add other levels
|
|
||||||
// of bugcompatibility
|
|
||||||
host.bugcomp = BUGCOMP_GOLDSRC;
|
|
||||||
}
|
|
||||||
|
|
||||||
// timeBeginPeriod( 1 ); // a1ba: Do we need this?
|
// timeBeginPeriod( 1 ); // a1ba: Do we need this?
|
||||||
|
|
||||||
// NOTE: this message couldn't be passed into game console but it doesn't matter
|
// NOTE: this message couldn't be passed into game console but it doesn't matter
|
||||||
@@ -1181,11 +1233,11 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
|
|||||||
|
|
||||||
Sys_InitLog();
|
Sys_InitLog();
|
||||||
|
|
||||||
// print bugcompatibility level here, after log was initialized
|
// print current developer level to simplify processing users feedback
|
||||||
if( host.bugcomp == BUGCOMP_GOLDSRC )
|
if( developer > 0 )
|
||||||
{
|
Con_Printf( "Developer level: ^3%i\n", developer );
|
||||||
Con_Printf( "^3BUGCOMP^7: GoldSrc bug-compatibility enabled\n" );
|
|
||||||
}
|
host.bugcomp = Host_CheckBugcomp();
|
||||||
|
|
||||||
Cmd_AddCommand( "exec", Host_Exec_f, "execute a script file" );
|
Cmd_AddCommand( "exec", Host_Exec_f, "execute a script file" );
|
||||||
Cmd_AddCommand( "memlist", Host_MemStats_f, "prints memory pool information" );
|
Cmd_AddCommand( "memlist", Host_MemStats_f, "prints memory pool information" );
|
||||||
@@ -1369,7 +1421,11 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
|
|||||||
host.status = HOST_FRAME;
|
host.status = HOST_FRAME;
|
||||||
|
|
||||||
if( GameState->nextstate == STATE_RUNFRAME )
|
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" );
|
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
|
// execute server.cfg after commandline
|
||||||
// so we have a chance to set servercfgfile
|
// so we have a chance to set servercfgfile
|
||||||
|
|||||||
@@ -400,6 +400,7 @@ static qboolean HPAK_Validate( const char *filename, qboolean quiet, qboolean de
|
|||||||
f = FS_Open( pakname, "rb", true );
|
f = FS_Open( pakname, "rb", true );
|
||||||
if( !f )
|
if( !f )
|
||||||
{
|
{
|
||||||
|
if( !quiet )
|
||||||
Con_DPrintf( S_ERROR "Couldn't find %s.\n", pakname );
|
Con_DPrintf( S_ERROR "Couldn't find %s.\n", pakname );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -390,7 +390,7 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, fs_offset_t filesi
|
|||||||
if( Q_strrchr( name, '{' ))
|
if( Q_strrchr( name, '{' ))
|
||||||
{
|
{
|
||||||
// NOTE: decals with 'blue base' can be interpret as colored decals
|
// 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 );
|
SetBits( image.flags, IMAGE_ONEBIT_ALPHA );
|
||||||
rendermode = LUMP_MASKED;
|
rendermode = LUMP_MASKED;
|
||||||
@@ -488,6 +488,8 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, fs_offset_t filesi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check for half-life water texture
|
// check for half-life water texture
|
||||||
|
if( pal != NULL )
|
||||||
|
{
|
||||||
if( hl_texture && ( mip.name[0] == '!' || !Q_strnicmp( mip.name, "water", 5 )))
|
if( hl_texture && ( mip.name[0] == '!' || !Q_strnicmp( mip.name, "water", 5 )))
|
||||||
{
|
{
|
||||||
// grab the fog color
|
// grab the fog color
|
||||||
@@ -508,7 +510,7 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, fs_offset_t filesi
|
|||||||
// calc the decal reflectivity
|
// calc the decal reflectivity
|
||||||
image.fogParams[3] = VectorAvg( image.fogParams );
|
image.fogParams[3] = VectorAvg( image.fogParams );
|
||||||
}
|
}
|
||||||
else if( pal != NULL )
|
else
|
||||||
{
|
{
|
||||||
// calc texture reflectivity
|
// calc texture reflectivity
|
||||||
for( i = 0; i < 256; i++ )
|
for( i = 0; i < 256; i++ )
|
||||||
@@ -520,6 +522,7 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, fs_offset_t filesi
|
|||||||
|
|
||||||
VectorDivide( reflectivity, 256, image.fogParams );
|
VectorDivide( reflectivity, 256, image.fogParams );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
image.type = PF_INDEXED_32; // 32-bit palete
|
image.type = PF_INDEXED_32; // 32-bit palete
|
||||||
image.depth = 1;
|
image.depth = 1;
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ typedef struct dll_user_s
|
|||||||
qboolean custom_loader; // a bit who indicated loader type
|
qboolean custom_loader; // a bit who indicated loader type
|
||||||
qboolean encrypted; // dll is crypted (some client.dll in HL, CS etc)
|
qboolean encrypted; // dll is crypted (some client.dll in HL, CS etc)
|
||||||
char dllName[32]; // for debug messages
|
char dllName[32]; // for debug messages
|
||||||
string fullPath, shortPath; // actual dll paths
|
char fullPath[2048];
|
||||||
|
string shortPath; // actual dll paths
|
||||||
|
|
||||||
// ordinals stuff, valid only on Win32
|
// ordinals stuff, valid only on Win32
|
||||||
word *ordinals;
|
word *ordinals;
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ static void NET_AnnounceToMaster( master_t *m )
|
|||||||
MSG_WriteBytes( &msg, "q\xFF", 2 );
|
MSG_WriteBytes( &msg, "q\xFF", 2 );
|
||||||
MSG_WriteDword( &msg, m->heartbeat_challenge );
|
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 )
|
if( sv_verbose_heartbeats.value )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -89,6 +89,36 @@ const char *svc_strings[svc_lastmsg+1] =
|
|||||||
"svc_exec",
|
"svc_exec",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char *svc_legacy_strings[svc_lastmsg+1] =
|
||||||
|
{
|
||||||
|
[svc_legacy_changing] = "svc_legacy_changing",
|
||||||
|
[svc_legacy_ambientsound] = "svc_legacy_ambientsound",
|
||||||
|
[svc_legacy_soundindex] = "svc_legacy_soundindex",
|
||||||
|
[svc_legacy_ambientsound] = "svc_legacy_ambientsound",
|
||||||
|
[svc_legacy_modelindex] = "svc_legacy_modelindex",
|
||||||
|
[svc_legacy_eventindex] = "svc_legacy_eventindex",
|
||||||
|
[svc_legacy_chokecount] = "svc_legacy_chokecount",
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *svc_goldsrc_strings[svc_lastmsg+1] =
|
||||||
|
{
|
||||||
|
[svc_goldsrc_version] = "svc_goldsrc_version",
|
||||||
|
[svc_goldsrc_serverinfo] = "svc_goldsrc_serverinfo",
|
||||||
|
[svc_goldsrc_deltadescription] = "svc_goldsrc_deltadescription",
|
||||||
|
[svc_goldsrc_stopsound] = "svc_goldsrc_stopsound",
|
||||||
|
[svc_goldsrc_damage] = "svc_goldsrc_damage",
|
||||||
|
[svc_goldsrc_killedmonster] = "svc_goldsrc_killedmonster",
|
||||||
|
[svc_goldsrc_foundsecret] = "svc_goldsrc_foundsecret",
|
||||||
|
[svc_goldsrc_spawnstaticsound] = "svc_goldsrc_spawnstaticsound",
|
||||||
|
[svc_goldsrc_decalname] = "svc_goldsrc_decalname",
|
||||||
|
[svc_goldsrc_newusermsg] = "svc_goldsrc_newusermsg",
|
||||||
|
[svc_goldsrc_newmovevars] = "svc_goldsrc_newmovevars",
|
||||||
|
[svc_goldsrc_sendextrainfo] = "svc_goldsrc_sendextrainfo",
|
||||||
|
[svc_goldsrc_timescale] = "svc_goldsrc_timescale",
|
||||||
|
[svc_goldsrc_sendcvarvalue] = "svc_goldsrc_sendcvarvalue",
|
||||||
|
[svc_goldsrc_sendcvarvalue2] = "svc_goldsrc_sendcvarvalue2",
|
||||||
|
};
|
||||||
|
|
||||||
void MSG_InitMasks( void )
|
void MSG_InitMasks( void )
|
||||||
{
|
{
|
||||||
uint startbit, endbit;
|
uint startbit, endbit;
|
||||||
@@ -109,85 +139,6 @@ void MSG_InitMasks( void )
|
|||||||
ExtraMasks[maskBit] = (uint)BIT( maskBit ) - 1;
|
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 )
|
void MSG_WriteOneBit( sizebuf_t *sb, int nValue )
|
||||||
{
|
{
|
||||||
if( !MSG_Overflow( sb, 1 ))
|
if( !MSG_Overflow( sb, 1 ))
|
||||||
@@ -669,7 +620,7 @@ qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes )
|
|||||||
return MSG_ReadBits( sb, pOut, nBytes << 3 );
|
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];
|
static char string[4096];
|
||||||
int l = 0, c;
|
int l = 0, c;
|
||||||
@@ -695,6 +646,16 @@ char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
|
|||||||
return string;
|
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 )
|
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove )
|
||||||
{
|
{
|
||||||
int i, endbit = startbit + bitstoremove;
|
int i, endbit = startbit + bitstoremove;
|
||||||
|
|||||||
@@ -30,19 +30,18 @@ GNU General Public License for more details.
|
|||||||
// So PAD_NUMBER(0,4) is 0 and PAD_NUMBER(1,4) is 4
|
// So PAD_NUMBER(0,4) is 0 and PAD_NUMBER(1,4) is 4
|
||||||
#define PAD_NUMBER( num, boundary ) ((( num ) + (( boundary ) - 1 )) / ( boundary )) * ( boundary )
|
#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;
|
return PAD_NUMBER( bits, 8 ) >> 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sizebuf_s
|
struct sizebuf_s
|
||||||
{
|
{
|
||||||
qboolean bOverflow; // overflow reading or writing
|
|
||||||
const char *pDebugName; // buffer name (pointer to const name)
|
|
||||||
|
|
||||||
byte *pData;
|
byte *pData;
|
||||||
|
qboolean bOverflow; // overflow reading or writing
|
||||||
int iCurBit;
|
int iCurBit;
|
||||||
int nDataBits;
|
int nDataBits;
|
||||||
|
const char *pDebugName; // buffer name (pointer to const name)
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MSG_StartReading MSG_StartWriting
|
#define MSG_StartReading MSG_StartWriting
|
||||||
@@ -50,19 +49,109 @@ struct sizebuf_s
|
|||||||
#define MSG_GetRealBytesRead MSG_GetRealBytesWritten
|
#define MSG_GetRealBytesRead MSG_GetRealBytesWritten
|
||||||
#define MSG_GetNumBitsRead MSG_GetNumBitsWritten
|
#define MSG_GetNumBitsRead MSG_GetNumBitsWritten
|
||||||
#define MSG_ReadBitAngles MSG_ReadBitVec3Coord
|
#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_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_Init( sb, name, data, bytes ) MSG_InitExt( sb, name, data, bytes, -1 )
|
||||||
|
#define MSG_CheckOverflow( sb ) MSG_Overflow( sb, 0 )
|
||||||
|
|
||||||
// common functions
|
// common functions
|
||||||
void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nMaxBits );
|
static inline void MSG_Clear( sizebuf_t *sb )
|
||||||
void MSG_InitMasks( void ); // called once at startup engine
|
{
|
||||||
int MSG_SeekToBit( sizebuf_t *sb, int bitPos, int whence );
|
sb->bOverflow = false;
|
||||||
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove );
|
sb->iCurBit = 0;
|
||||||
_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_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
|
#if XASH_BIG_ENDIAN
|
||||||
#define MSG_BigShort( x ) ( x )
|
#define MSG_BigShort( x ) ( x )
|
||||||
@@ -73,9 +162,15 @@ static inline uint16_t MSG_BigShort( const uint16_t x )
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// init writing
|
static inline qboolean MSG_Overflow( sizebuf_t *sb, int nBits )
|
||||||
void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits );
|
{
|
||||||
void MSG_Clear( sizebuf_t *sb );
|
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
|
// Bit-write functions
|
||||||
void MSG_WriteOneBit( sizebuf_t *sb, int nValue );
|
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_WriteFloat( sizebuf_t *sb, float val );
|
||||||
void MSG_WriteVec3Coord( sizebuf_t *sb, const float *fa );
|
void MSG_WriteVec3Coord( sizebuf_t *sb, const float *fa );
|
||||||
void MSG_WriteVec3Angles( 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_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_WriteStringf( sizebuf_t *sb, const char *format, ... ) _format( 2 );
|
||||||
|
qboolean MSG_WriteBytes( sizebuf_t *sb, const void *pBuf, int nBytes );
|
||||||
|
|
||||||
// helper functions
|
// 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
|
// Bit-read functions
|
||||||
int MSG_ReadOneBit( sizebuf_t *sb );
|
int MSG_ReadOneBit( sizebuf_t *sb );
|
||||||
@@ -136,7 +222,8 @@ float MSG_ReadCoord( sizebuf_t *sb );
|
|||||||
float MSG_ReadFloat( sizebuf_t *sb );
|
float MSG_ReadFloat( sizebuf_t *sb );
|
||||||
void MSG_ReadVec3Coord( sizebuf_t *sb, vec3_t fa );
|
void MSG_ReadVec3Coord( sizebuf_t *sb, vec3_t fa );
|
||||||
void MSG_ReadVec3Angles( 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 );
|
qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes );
|
||||||
char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine );
|
|
||||||
|
|
||||||
#endif//NET_BUFFER_H
|
#endif//NET_BUFFER_H
|
||||||
|
|||||||
@@ -315,6 +315,43 @@ static const delta_field_t ent_fields[] =
|
|||||||
{ NULL },
|
{ NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if XASH_ENGINE_TESTS
|
||||||
|
typedef struct delta_test_struct_t
|
||||||
|
{
|
||||||
|
char dt_string[128]; // always signed
|
||||||
|
float dt_timewindow_big; // always signed
|
||||||
|
float dt_timewindow_8; // always signed
|
||||||
|
float dt_angle; // always_signed
|
||||||
|
float dt_float_signed;
|
||||||
|
float dt_float_unsigned;
|
||||||
|
int32_t dt_integer_signed;
|
||||||
|
uint32_t dt_integer_unsigned;
|
||||||
|
int16_t dt_short_signed;
|
||||||
|
uint16_t dt_short_unsigned;
|
||||||
|
int8_t dt_byte_signed;
|
||||||
|
uint8_t dt_byte_unsigned;
|
||||||
|
} delta_test_struct_t;
|
||||||
|
|
||||||
|
#define TEST_DEF( x ) #x, offsetof( delta_test_struct_t, x ), sizeof( ((delta_test_struct_t *)0)->x )
|
||||||
|
|
||||||
|
static const delta_field_t test_fields[] =
|
||||||
|
{
|
||||||
|
{ TEST_DEF( dt_string ) },
|
||||||
|
{ TEST_DEF( dt_timewindow_big )},
|
||||||
|
{ TEST_DEF( dt_timewindow_8 )},
|
||||||
|
{ TEST_DEF( dt_angle ) },
|
||||||
|
{ TEST_DEF( dt_float_signed ) },
|
||||||
|
{ TEST_DEF( dt_float_unsigned ) },
|
||||||
|
{ TEST_DEF( dt_integer_signed ) },
|
||||||
|
{ TEST_DEF( dt_integer_unsigned ) },
|
||||||
|
{ TEST_DEF( dt_short_signed ) },
|
||||||
|
{ TEST_DEF( dt_short_unsigned ) },
|
||||||
|
{ TEST_DEF( dt_byte_signed ) },
|
||||||
|
{ TEST_DEF( dt_byte_unsigned ) },
|
||||||
|
{ NULL },
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
DT_EVENT_T = 0,
|
DT_EVENT_T = 0,
|
||||||
@@ -325,6 +362,10 @@ enum
|
|||||||
DT_ENTITY_STATE_T,
|
DT_ENTITY_STATE_T,
|
||||||
DT_ENTITY_STATE_PLAYER_T,
|
DT_ENTITY_STATE_PLAYER_T,
|
||||||
DT_CUSTOM_ENTITY_STATE_T,
|
DT_CUSTOM_ENTITY_STATE_T,
|
||||||
|
#if XASH_ENGINE_TESTS
|
||||||
|
DT_DELTA_TEST_STRUCT_T,
|
||||||
|
#endif
|
||||||
|
DT_STRUCT_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
static delta_info_t dt_info[] =
|
static delta_info_t dt_info[] =
|
||||||
@@ -337,7 +378,10 @@ static delta_info_t dt_info[] =
|
|||||||
[DT_ENTITY_STATE_T] = { "entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
[DT_ENTITY_STATE_T] = { "entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
||||||
[DT_ENTITY_STATE_PLAYER_T] = { "entity_state_player_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
[DT_ENTITY_STATE_PLAYER_T] = { "entity_state_player_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
||||||
[DT_CUSTOM_ENTITY_STATE_T] = { "custom_entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
[DT_CUSTOM_ENTITY_STATE_T] = { "custom_entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
||||||
{ NULL },
|
#if XASH_ENGINE_TESTS
|
||||||
|
[DT_DELTA_TEST_STRUCT_T] = { "delta_test_struct_t", test_fields, NUM_FIELDS( test_fields ) },
|
||||||
|
#endif
|
||||||
|
[DT_STRUCT_COUNT] = { NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
static delta_info_t *Delta_FindStruct( const char *name )
|
static delta_info_t *Delta_FindStruct( const char *name )
|
||||||
@@ -411,10 +455,8 @@ static void Delta_CustomEncode( delta_info_t *dt, const void *from, const void *
|
|||||||
dt->pFields[i].bInactive = false;
|
dt->pFields[i].bInactive = false;
|
||||||
|
|
||||||
if( dt->userCallback )
|
if( dt->userCallback )
|
||||||
{
|
|
||||||
dt->userCallback( dt->pFields, from, to );
|
dt->userCallback( dt->pFields, from, to );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static delta_field_t *Delta_FindFieldInfo( const delta_field_t *pInfo, const char *fieldName )
|
static delta_field_t *Delta_FindFieldInfo( const delta_field_t *pInfo, const char *fieldName )
|
||||||
{
|
{
|
||||||
@@ -974,14 +1016,14 @@ static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, doubl
|
|||||||
toF = *(uint8_t *)((int8_t *)to + pField->offset );
|
toF = *(uint8_t *)((int8_t *)to + pField->offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !Q_equal(pField->multiplier, 1.0f ))
|
||||||
|
{
|
||||||
|
fromF *= pField->multiplier;
|
||||||
|
toF *= pField->multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
|
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
|
||||||
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
|
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
|
||||||
|
|
||||||
if( !Q_equal(pField->multiplier, 1.0f ))
|
|
||||||
fromF *= pField->multiplier;
|
|
||||||
|
|
||||||
if( !Q_equal( pField->multiplier, 1.0f ))
|
|
||||||
toF *= pField->multiplier;
|
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_SHORT )
|
else if( pField->flags & DT_SHORT )
|
||||||
{
|
{
|
||||||
@@ -996,14 +1038,14 @@ static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, doubl
|
|||||||
toF = *(uint16_t *)((int8_t *)to + pField->offset );
|
toF = *(uint16_t *)((int8_t *)to + pField->offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !Q_equal(pField->multiplier, 1.0f ))
|
||||||
|
{
|
||||||
|
fromF *= pField->multiplier;
|
||||||
|
toF *= pField->multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
|
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
|
||||||
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
|
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
|
||||||
|
|
||||||
if( !Q_equal(pField->multiplier, 1.0f ))
|
|
||||||
fromF *= pField->multiplier;
|
|
||||||
|
|
||||||
if( !Q_equal( pField->multiplier, 1.0f ))
|
|
||||||
toF *= pField->multiplier;
|
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_INTEGER )
|
else if( pField->flags & DT_INTEGER )
|
||||||
{
|
{
|
||||||
@@ -1017,14 +1059,15 @@ static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, doubl
|
|||||||
fromF = *(uint32_t *)((int8_t *)from + pField->offset );
|
fromF = *(uint32_t *)((int8_t *)from + pField->offset );
|
||||||
toF = *(uint32_t *)((int8_t *)to + pField->offset );
|
toF = *(uint32_t *)((int8_t *)to + pField->offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !Q_equal(pField->multiplier, 1.0f ))
|
||||||
|
{
|
||||||
|
fromF *= pField->multiplier;
|
||||||
|
toF *= pField->multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
|
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
|
||||||
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
|
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
|
||||||
|
|
||||||
if( !Q_equal(pField->multiplier, 1.0f ))
|
|
||||||
fromF *= pField->multiplier;
|
|
||||||
|
|
||||||
if( !Q_equal( pField->multiplier, 1.0f ))
|
|
||||||
toF *= pField->multiplier;
|
|
||||||
}
|
}
|
||||||
else if( pField->flags & ( DT_ANGLE|DT_FLOAT ))
|
else if( pField->flags & ( DT_ANGLE|DT_FLOAT ))
|
||||||
{
|
{
|
||||||
@@ -1034,33 +1077,17 @@ static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, doubl
|
|||||||
}
|
}
|
||||||
else if( pField->flags & DT_TIMEWINDOW_8 )
|
else if( pField->flags & DT_TIMEWINDOW_8 )
|
||||||
{
|
{
|
||||||
val_a = Q_rint((*(float *)((byte *)from + pField->offset )) * 100.0f );
|
val_a = *(float *)((byte *)from + pField->offset );
|
||||||
val_b = Q_rint((*(float *)((byte *)to + pField->offset )) * 100.0f );
|
val_b = *(float *)((byte *)to + pField->offset );
|
||||||
val_a -= Q_rint(timebase * 100.0);
|
fromF = Q_rint( val_a * 100.0 );
|
||||||
val_b -= Q_rint(timebase * 100.0);
|
toF = Q_rint( val_b * 100.0 );
|
||||||
fromF = FloatAsInt( val_a );
|
|
||||||
toF = FloatAsInt( val_b );
|
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_TIMEWINDOW_BIG )
|
else if( pField->flags & DT_TIMEWINDOW_BIG )
|
||||||
{
|
{
|
||||||
val_a = (*(float *)((byte *)from + pField->offset ));
|
val_a = *(float *)((byte *)from + pField->offset );
|
||||||
val_b = (*(float *)((byte *)to + pField->offset ));
|
val_b = *(float *)((byte *)to + pField->offset );
|
||||||
|
fromF = Q_rint( val_a * pField->multiplier );
|
||||||
if( !Q_equal( pField->multiplier, 1.0f ))
|
toF = Q_rint( val_b * pField->multiplier );
|
||||||
{
|
|
||||||
val_a *= pField->multiplier;
|
|
||||||
val_b *= pField->multiplier;
|
|
||||||
val_a = (timebase * pField->multiplier) - val_a;
|
|
||||||
val_b = (timebase * pField->multiplier) - val_b;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
val_a = timebase - val_a;
|
|
||||||
val_b = timebase - val_b;
|
|
||||||
}
|
|
||||||
|
|
||||||
fromF = FloatAsInt( val_a );
|
|
||||||
toF = FloatAsInt( val_b );
|
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_STRING )
|
else if( pField->flags & DT_STRING )
|
||||||
{
|
{
|
||||||
@@ -1144,6 +1171,7 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
|
|||||||
int signbit = FBitSet( pField->flags, DT_SIGNED ) ? 1 : 0;
|
int signbit = FBitSet( pField->flags, DT_SIGNED ) ? 1 : 0;
|
||||||
float flValue, flAngle;
|
float flValue, flAngle;
|
||||||
uint iValue;
|
uint iValue;
|
||||||
|
int dt;
|
||||||
const char *pStr;
|
const char *pStr;
|
||||||
|
|
||||||
if( Delta_CompareField( pField, from, to, timebase ))
|
if( Delta_CompareField( pField, from, to, timebase ))
|
||||||
@@ -1160,11 +1188,11 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
|
|||||||
iValue = *(int8_t *)((int8_t *)to + pField->offset );
|
iValue = *(int8_t *)((int8_t *)to + pField->offset );
|
||||||
else
|
else
|
||||||
iValue = *(uint8_t *)((int8_t *)to + pField->offset );
|
iValue = *(uint8_t *)((int8_t *)to + pField->offset );
|
||||||
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
|
||||||
|
|
||||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
if( !Q_equal( pField->multiplier, 1.0 ))
|
||||||
iValue *= pField->multiplier;
|
iValue *= pField->multiplier;
|
||||||
|
|
||||||
|
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
||||||
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_SHORT )
|
else if( pField->flags & DT_SHORT )
|
||||||
@@ -1173,11 +1201,11 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
|
|||||||
iValue = *(int16_t *)((int8_t *)to + pField->offset );
|
iValue = *(int16_t *)((int8_t *)to + pField->offset );
|
||||||
else
|
else
|
||||||
iValue = *(uint16_t *)((int8_t *)to + pField->offset );
|
iValue = *(uint16_t *)((int8_t *)to + pField->offset );
|
||||||
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
|
||||||
|
|
||||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
if( !Q_equal( pField->multiplier, 1.0 ))
|
||||||
iValue *= pField->multiplier;
|
iValue *= pField->multiplier;
|
||||||
|
|
||||||
|
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
||||||
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_INTEGER )
|
else if( pField->flags & DT_INTEGER )
|
||||||
@@ -1186,11 +1214,11 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
|
|||||||
iValue = *(int32_t *)((int8_t *)to + pField->offset );
|
iValue = *(int32_t *)((int8_t *)to + pField->offset );
|
||||||
else
|
else
|
||||||
iValue = *(uint32_t *)((int8_t *)to + pField->offset );
|
iValue = *(uint32_t *)((int8_t *)to + pField->offset );
|
||||||
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
|
||||||
|
|
||||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
if( !Q_equal( pField->multiplier, 1.0 ))
|
||||||
iValue *= pField->multiplier;
|
iValue *= pField->multiplier;
|
||||||
|
|
||||||
|
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
||||||
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_FLOAT )
|
else if( pField->flags & DT_FLOAT )
|
||||||
@@ -1210,19 +1238,17 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
|
|||||||
}
|
}
|
||||||
else if( pField->flags & DT_TIMEWINDOW_8 )
|
else if( pField->flags & DT_TIMEWINDOW_8 )
|
||||||
{
|
{
|
||||||
signbit = 1; // timewindow is always signed
|
|
||||||
flValue = *(float *)((byte *)to + pField->offset );
|
flValue = *(float *)((byte *)to + pField->offset );
|
||||||
iValue = (int)Q_rint( timebase * 100.0 ) - (int)Q_rint( flValue * 100.0 );
|
dt = Q_rint(( timebase - flValue ) * 100.0 );
|
||||||
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
dt = Delta_ClampIntegerField( pField, dt, 1, pField->bits );
|
||||||
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
MSG_WriteSBitLong( msg, dt, pField->bits );
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_TIMEWINDOW_BIG )
|
else if( pField->flags & DT_TIMEWINDOW_BIG )
|
||||||
{
|
{
|
||||||
signbit = 1; // timewindow is always signed
|
|
||||||
flValue = *(float *)((byte *)to + pField->offset );
|
flValue = *(float *)((byte *)to + pField->offset );
|
||||||
iValue = (int)Q_rint( timebase * pField->multiplier ) - (int)Q_rint( flValue * pField->multiplier );
|
dt = Q_rint(( timebase - flValue ) * pField->multiplier );
|
||||||
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
dt = Delta_ClampIntegerField( pField, dt, 1, pField->bits );
|
||||||
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
MSG_WriteSBitLong( msg, dt, pField->bits );
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_STRING )
|
else if( pField->flags & DT_STRING )
|
||||||
{
|
{
|
||||||
@@ -1309,6 +1335,9 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
|
|||||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
if( !Q_equal( pField->multiplier, 1.0 ))
|
||||||
iValue /= pField->multiplier;
|
iValue /= pField->multiplier;
|
||||||
|
|
||||||
|
if( !Q_equal( pField->post_multiplier, 1.0 ))
|
||||||
|
iValue *= pField->post_multiplier;
|
||||||
|
|
||||||
if( bSigned )
|
if( bSigned )
|
||||||
*(int8_t *)((uint8_t *)to + pField->offset ) = iValue;
|
*(int8_t *)((uint8_t *)to + pField->offset ) = iValue;
|
||||||
else
|
else
|
||||||
@@ -1320,6 +1349,9 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
|
|||||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
if( !Q_equal( pField->multiplier, 1.0 ))
|
||||||
iValue /= pField->multiplier;
|
iValue /= pField->multiplier;
|
||||||
|
|
||||||
|
if( !Q_equal( pField->post_multiplier, 1.0 ))
|
||||||
|
iValue *= pField->post_multiplier;
|
||||||
|
|
||||||
if( bSigned )
|
if( bSigned )
|
||||||
*(int16_t *)((uint8_t *)to + pField->offset ) = iValue;
|
*(int16_t *)((uint8_t *)to + pField->offset ) = iValue;
|
||||||
else
|
else
|
||||||
@@ -1331,6 +1363,9 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
|
|||||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
if( !Q_equal( pField->multiplier, 1.0 ))
|
||||||
iValue /= pField->multiplier;
|
iValue /= pField->multiplier;
|
||||||
|
|
||||||
|
if( !Q_equal( pField->post_multiplier, 1.0 ))
|
||||||
|
iValue *= pField->post_multiplier;
|
||||||
|
|
||||||
if( bSigned )
|
if( bSigned )
|
||||||
*(int32_t *)((uint8_t *)to + pField->offset ) = iValue;
|
*(int32_t *)((uint8_t *)to + pField->offset ) = iValue;
|
||||||
else
|
else
|
||||||
@@ -1345,10 +1380,10 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
|
|||||||
flValue = iValue;
|
flValue = iValue;
|
||||||
|
|
||||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
if( !Q_equal( pField->multiplier, 1.0 ))
|
||||||
flValue = flValue / pField->multiplier;
|
flValue /= pField->multiplier;
|
||||||
|
|
||||||
if( !Q_equal( pField->post_multiplier, 1.0 ))
|
if( !Q_equal( pField->post_multiplier, 1.0 ))
|
||||||
flValue = flValue * pField->post_multiplier;
|
flValue *= pField->post_multiplier;
|
||||||
|
|
||||||
*(float *)((byte *)to + pField->offset ) = flValue;
|
*(float *)((byte *)to + pField->offset ) = flValue;
|
||||||
}
|
}
|
||||||
@@ -1359,22 +1394,14 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
|
|||||||
}
|
}
|
||||||
else if( pField->flags & DT_TIMEWINDOW_8 )
|
else if( pField->flags & DT_TIMEWINDOW_8 )
|
||||||
{
|
{
|
||||||
bSigned = true; // timewindow is always signed
|
iValue = MSG_ReadSBitLong( msg, pField->bits );
|
||||||
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
|
||||||
flTime = ( timebase * 100.0 - (int)iValue ) / 100.0;
|
flTime = ( timebase * 100.0 - (int)iValue ) / 100.0;
|
||||||
|
|
||||||
*(float *)((byte *)to + pField->offset ) = flTime;
|
*(float *)((byte *)to + pField->offset ) = flTime;
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_TIMEWINDOW_BIG )
|
else if( pField->flags & DT_TIMEWINDOW_BIG )
|
||||||
{
|
{
|
||||||
bSigned = true; // timewindow is always signed
|
iValue = MSG_ReadSBitLong( msg, pField->bits );
|
||||||
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
|
||||||
|
|
||||||
if( !Q_equal( pField->multiplier, 1.0 ) )
|
|
||||||
flTime = ( timebase * pField->multiplier - (int)iValue ) / pField->multiplier;
|
flTime = ( timebase * pField->multiplier - (int)iValue ) / pField->multiplier;
|
||||||
else
|
|
||||||
flTime = timebase - (int)iValue;
|
|
||||||
|
|
||||||
*(float *)((byte *)to + pField->offset ) = flTime;
|
*(float *)((byte *)to + pField->offset ) = flTime;
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_STRING )
|
else if( pField->flags & DT_STRING )
|
||||||
@@ -2069,3 +2096,103 @@ void GAME_EXPORT Delta_UnsetFieldByIndex( delta_t *pFields, int fieldNumber )
|
|||||||
|
|
||||||
dt->pFields[fieldNumber].bInactive = true;
|
dt->pFields[fieldNumber].bInactive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if XASH_ENGINE_TESTS
|
||||||
|
#include "tests.h"
|
||||||
|
|
||||||
|
void Test_RunDelta( void )
|
||||||
|
{
|
||||||
|
delta_info_t *dt = &dt_info[DT_DELTA_TEST_STRUCT_T];
|
||||||
|
delta_test_struct_t from, to = { 0 };
|
||||||
|
delta_test_struct_t null = { 0 };
|
||||||
|
sizebuf_t msg;
|
||||||
|
int i;
|
||||||
|
char buffer[4096] = { 0 };
|
||||||
|
const double timebase = 123.123;
|
||||||
|
|
||||||
|
// a1ba: netbuffer bitmasks are initialized in netchan for some reason
|
||||||
|
// initialize it ourselves just in case
|
||||||
|
MSG_InitMasks(); // initialize bit-masks
|
||||||
|
|
||||||
|
Delta_AddField( dt, "dt_string", DT_STRING, 1, 1.0f, 1.0f );
|
||||||
|
Delta_AddField( dt, "dt_timewindow_big", DT_TIMEWINDOW_BIG, 24, 1000.f, 1.0f );
|
||||||
|
Delta_AddField( dt, "dt_timewindow_8", DT_TIMEWINDOW_8, 8, 1.0f, 1.0f );
|
||||||
|
Delta_AddField( dt, "dt_angle", DT_ANGLE, 16, 1.0f, 1.0f );
|
||||||
|
Delta_AddField( dt, "dt_float_signed", DT_FLOAT | DT_SIGNED, 22, 100.0f, 1.0f );
|
||||||
|
Delta_AddField( dt, "dt_float_unsigned", DT_FLOAT, 24, 10000.0f, 0.1f );
|
||||||
|
Delta_AddField( dt, "dt_integer_signed", DT_INTEGER | DT_SIGNED, 24, 1.0f, 1.0f );
|
||||||
|
Delta_AddField( dt, "dt_integer_unsigned", DT_INTEGER, 24, 1.0f, 1.0f );
|
||||||
|
Delta_AddField( dt, "dt_short_signed", DT_SHORT | DT_SIGNED, 16, 1.0f, 1.0f );
|
||||||
|
Delta_AddField( dt, "dt_short_unsigned", DT_SHORT, 15, 0.125f, 1.0f );
|
||||||
|
Delta_AddField( dt, "dt_byte_signed", DT_BYTE | DT_SIGNED, 6, 1.0f, 1.0f );
|
||||||
|
Delta_AddField( dt, "dt_byte_unsigned", DT_BYTE, 8, 1.0f, 1.0f );
|
||||||
|
|
||||||
|
Q_strncpy( from.dt_string, "test data check it's the same", sizeof( from.dt_string ));
|
||||||
|
from.dt_timewindow_big = timebase + 2.3456;
|
||||||
|
from.dt_timewindow_8 = timebase + 0.0234;
|
||||||
|
from.dt_angle = 160.245f;
|
||||||
|
from.dt_float_signed = -15.123f;
|
||||||
|
from.dt_float_unsigned = 1235.321f;
|
||||||
|
from.dt_integer_signed = -412784;
|
||||||
|
from.dt_integer_unsigned = 123453;
|
||||||
|
from.dt_short_signed = -12343;
|
||||||
|
from.dt_short_unsigned = 32131;
|
||||||
|
from.dt_byte_signed = 16;
|
||||||
|
from.dt_byte_unsigned = 218;
|
||||||
|
|
||||||
|
MSG_Init( &msg, "test message", buffer, sizeof( buffer ));
|
||||||
|
|
||||||
|
for( i = 0; i < dt->numFields; i++ )
|
||||||
|
Delta_WriteField( &msg, &dt->pFields[i], &null, &from, timebase );
|
||||||
|
|
||||||
|
MSG_SeekToBit( &msg, 0, SEEK_SET );
|
||||||
|
|
||||||
|
for( i = 0; i < dt->numFields; i++ )
|
||||||
|
Delta_ReadField( &msg, &dt->pFields[i], &null, &to, timebase );
|
||||||
|
|
||||||
|
Con_Printf( "struct as encoded to delta:\n" );
|
||||||
|
TASSERT_STR( from.dt_string, to.dt_string );
|
||||||
|
|
||||||
|
// the epsilon value is derived from multiplier value
|
||||||
|
TASSERT( Q_equal_e( from.dt_timewindow_big, to.dt_timewindow_big, 0.001f ));
|
||||||
|
|
||||||
|
// dt_timewindow_8 type has multiplier locked at 100.0f
|
||||||
|
TASSERT( Q_equal_e( from.dt_timewindow_8, to.dt_timewindow_8, 0.01f ));
|
||||||
|
TASSERT( Q_equal_e( from.dt_angle, to.dt_angle, 0.1f ));
|
||||||
|
TASSERT( Q_equal_e( from.dt_float_signed, to.dt_float_signed, 0.01f ));
|
||||||
|
|
||||||
|
// dt_float_unsigned has post-multiplier that doesn't affect network data
|
||||||
|
// and therefore should be reverted back when comparing
|
||||||
|
TASSERT( Q_equal_e( from.dt_float_unsigned, to.dt_float_unsigned * 10.f , 0.01f ));
|
||||||
|
|
||||||
|
TASSERT_EQi( from.dt_integer_signed, to.dt_integer_signed );
|
||||||
|
TASSERT_EQi( from.dt_integer_unsigned, to.dt_integer_unsigned );
|
||||||
|
TASSERT_EQi( from.dt_short_signed, to.dt_short_signed );
|
||||||
|
TASSERT(( from.dt_short_unsigned & ( 0xffff << 3 )) == to.dt_short_unsigned );
|
||||||
|
TASSERT_EQi( from.dt_byte_signed, to.dt_byte_signed );
|
||||||
|
TASSERT_EQi( from.dt_byte_unsigned, to.dt_byte_unsigned );
|
||||||
|
|
||||||
|
Con_Printf( "from.dt_timewindow_big = %f\n", from.dt_timewindow_big );
|
||||||
|
Con_Printf( "to.dt_timewindow_big = %f\n", to.dt_timewindow_big );
|
||||||
|
Con_Printf( "from.dt_timewindow_8 = %f\n", from.dt_timewindow_8 );
|
||||||
|
Con_Printf( "to.dt_timewindow_8 = %f\n", to.dt_timewindow_8 );
|
||||||
|
Con_Printf( "from.dt_angle = %f\n", from.dt_angle );
|
||||||
|
Con_Printf( "to.dt_angle = %f\n", to.dt_angle );
|
||||||
|
Con_Printf( "from.dt_float_signed = %f\n", from.dt_float_signed );
|
||||||
|
Con_Printf( "to.dt_float_signed = %f\n", to.dt_float_signed );
|
||||||
|
Con_Printf( "from.dt_float_unsigned = %f\n", from.dt_float_unsigned );
|
||||||
|
Con_Printf( "to.dt_float_unsigned = %f\n", to.dt_float_unsigned );
|
||||||
|
Con_Printf( "from.dt_integer_signed = %i\n", from.dt_integer_signed );
|
||||||
|
Con_Printf( "to.dt_integer_signed = %i\n", to.dt_integer_signed );
|
||||||
|
Con_Printf( "from.dt_integer_unsigned = %i\n", from.dt_integer_unsigned );
|
||||||
|
Con_Printf( "to.dt_integer_unsigned = %i\n", to.dt_integer_unsigned );
|
||||||
|
Con_Printf( "from.dt_short_signed = %i\n", from.dt_short_signed );
|
||||||
|
Con_Printf( "to.dt_short_signed = %i\n", to.dt_short_signed );
|
||||||
|
Con_Printf( "from.dt_short_unsigned = %i\n", from.dt_short_unsigned );
|
||||||
|
Con_Printf( "to.dt_short_unsigned = %i\n", to.dt_short_unsigned );
|
||||||
|
Con_Printf( "from.dt_byte_signed = %i\n", from.dt_byte_signed );
|
||||||
|
Con_Printf( "to.dt_byte_signed = %i\n", to.dt_byte_signed );
|
||||||
|
Con_Printf( "from.dt_byte_unsigned = %i\n", from.dt_byte_unsigned );
|
||||||
|
Con_Printf( "to.dt_byte_unsigned = %i\n", to.dt_byte_unsigned );
|
||||||
|
}
|
||||||
|
#endif // XASH_ENGINE_TESTS
|
||||||
|
|||||||
@@ -278,6 +278,8 @@ GNU General Public License for more details.
|
|||||||
#define SU_WEAPON (1<<14)
|
#define SU_WEAPON (1<<14)
|
||||||
|
|
||||||
extern const char *svc_strings[svc_lastmsg+1];
|
extern const char *svc_strings[svc_lastmsg+1];
|
||||||
|
extern const char *svc_legacy_strings[svc_lastmsg+1];
|
||||||
|
extern const char *svc_goldsrc_strings[svc_lastmsg+1];
|
||||||
extern const char *clc_strings[clc_lastmsg+1];
|
extern const char *clc_strings[clc_lastmsg+1];
|
||||||
|
|
||||||
// FWGS extensions
|
// FWGS extensions
|
||||||
@@ -316,4 +318,40 @@ extern const char *clc_strings[clc_lastmsg+1];
|
|||||||
// Master Server protocol
|
// Master Server protocol
|
||||||
#define MS_SCAN_REQUEST "1\xFF" "0.0.0.0:0\0" // TODO: implement IP filter
|
#define MS_SCAN_REQUEST "1\xFF" "0.0.0.0:0\0" // TODO: implement IP filter
|
||||||
|
|
||||||
|
// GoldSrc protocol definitions
|
||||||
|
#define PROTOCOL_GOLDSRC_VERSION_REAL 48
|
||||||
|
#define PROTOCOL_GOLDSRC_VERSION (PROTOCOL_GOLDSRC_VERSION_REAL | (BIT( 7 ))) // should be 48, only to differentiate it from PROTOCOL_LEGACY_VERSION
|
||||||
|
|
||||||
|
#define svc_goldsrc_version svc_changing
|
||||||
|
#define svc_goldsrc_serverinfo svc_serverdata
|
||||||
|
#define svc_goldsrc_deltadescription svc_deltatable
|
||||||
|
#define svc_goldsrc_stopsound svc_resource
|
||||||
|
#define svc_goldsrc_damage svc_restoresound
|
||||||
|
#define svc_goldsrc_killedmonster 27
|
||||||
|
#define svc_goldsrc_foundsecret 28
|
||||||
|
#define svc_goldsrc_spawnstaticsound 29
|
||||||
|
#define svc_goldsrc_decalname svc_bspdecal
|
||||||
|
#define svc_goldsrc_newusermsg svc_usermessage
|
||||||
|
#define svc_goldsrc_newmovevars svc_deltamovevars
|
||||||
|
#define svc_goldsrc_sendextrainfo 54
|
||||||
|
#define svc_goldsrc_timescale 55
|
||||||
|
#define svc_goldsrc_sendcvarvalue svc_querycvarvalue
|
||||||
|
#define svc_goldsrc_sendcvarvalue2 svc_querycvarvalue2
|
||||||
|
|
||||||
|
#define clc_goldsrc_hltv clc_requestcvarvalue // 9
|
||||||
|
#define clc_goldsrc_requestcvarvalue clc_requestcvarvalue2 // 10
|
||||||
|
#define clc_goldsrc_requestcvarvalue2 11
|
||||||
|
#define clc_goldsrc_lastmsg 12
|
||||||
|
|
||||||
|
#define S2C_REJECT_BADPASSWORD '8'
|
||||||
|
#define S2C_REJECT '9'
|
||||||
|
#define S2C_CHALLENGE "A00000000"
|
||||||
|
#define S2C_CONNECTION "B"
|
||||||
|
|
||||||
|
#define MAX_GOLDSRC_RESOURCE_BITS 12
|
||||||
|
#define MAX_GOLDSRC_ENTITY_BITS 11
|
||||||
|
// #define MAX_GOLDSRC_EDICTS BIT( MAX_ENTITY_BITS )
|
||||||
|
#define MAX_GOLDSRC_EDICTS ( BIT( MAX_ENTITY_BITS ) + ( MAX_CLIENTS * 15 ))
|
||||||
|
#define LAST_GOLDSRC_EDICT ( BIT( MAX_ENTITY_BITS ) - 1 )
|
||||||
|
|
||||||
#endif//NET_PROTOCOL_H
|
#endif//NET_PROTOCOL_H
|
||||||
|
|||||||
@@ -135,6 +135,10 @@ void Sys_InitLog( void )
|
|||||||
mode = "a";
|
mode = "a";
|
||||||
else mode = "w";
|
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
|
// create log if needed
|
||||||
if( s_ld.log_active )
|
if( s_ld.log_active )
|
||||||
{
|
{
|
||||||
@@ -148,9 +152,12 @@ void Sys_InitLog( void )
|
|||||||
|
|
||||||
s_ld.logfileno = fileno( s_ld.logfile );
|
s_ld.logfileno = fileno( s_ld.logfile );
|
||||||
|
|
||||||
fprintf( s_ld.logfile, "=================================================================================\n" );
|
// fit to 80 columns for easier read on standard terminal
|
||||||
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 ) );
|
fputs( "================================================================================\n", s_ld.logfile );
|
||||||
fprintf( s_ld.logfile, "=================================================================================\n" );
|
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 )
|
if( s_ld.logfile )
|
||||||
{
|
{
|
||||||
fprintf( s_ld.logfile, "\n");
|
fputc( '\n', s_ld.logfile );
|
||||||
fprintf( s_ld.logfile, "=================================================================================");
|
fputs( "================================================================================\n", 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 );
|
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
||||||
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, "Stopped with reason \"%s\" at %s\n", event_name, Q_timestamp( TIME_FULL ));
|
||||||
fprintf( s_ld.logfile, "=================================================================================\n");
|
fputs( "================================================================================\n", s_ld.logfile );
|
||||||
|
|
||||||
fclose( s_ld.logfile );
|
fclose( s_ld.logfile );
|
||||||
s_ld.logfile = NULL;
|
s_ld.logfile = NULL;
|
||||||
}
|
}
|
||||||
@@ -335,15 +341,18 @@ void GAME_EXPORT Con_Printf( const char *szFmt, ... )
|
|||||||
{
|
{
|
||||||
static char buffer[MAX_PRINT_MSG];
|
static char buffer[MAX_PRINT_MSG];
|
||||||
va_list args;
|
va_list args;
|
||||||
|
qboolean add_newline;
|
||||||
|
|
||||||
if( !host.allow_console )
|
if( !host.allow_console )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
va_start( args, szFmt );
|
va_start( args, szFmt );
|
||||||
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
|
add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
|
||||||
va_end( args );
|
va_end( args );
|
||||||
|
|
||||||
Sys_Print( buffer );
|
Sys_Print( buffer );
|
||||||
|
if( add_newline )
|
||||||
|
Sys_Print( "\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -356,18 +365,21 @@ void GAME_EXPORT Con_DPrintf( const char *szFmt, ... )
|
|||||||
{
|
{
|
||||||
static char buffer[MAX_PRINT_MSG];
|
static char buffer[MAX_PRINT_MSG];
|
||||||
va_list args;
|
va_list args;
|
||||||
|
qboolean add_newline;
|
||||||
|
|
||||||
if( host_developer.value < DEV_NORMAL )
|
if( host_developer.value < DEV_NORMAL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
va_start( args, szFmt );
|
va_start( args, szFmt );
|
||||||
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
|
add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
|
||||||
va_end( args );
|
va_end( args );
|
||||||
|
|
||||||
if( buffer[0] == '0' && buffer[1] == '\n' && buffer[2] == '\0' )
|
if( buffer[0] == '0' && buffer[1] == '\n' && buffer[2] == '\0' )
|
||||||
return; // hlrally spam
|
return; // hlrally spam
|
||||||
|
|
||||||
Sys_Print( buffer );
|
Sys_Print( buffer );
|
||||||
|
if( add_newline )
|
||||||
|
Sys_Print( "\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -380,15 +392,18 @@ void Con_Reportf( const char *szFmt, ... )
|
|||||||
{
|
{
|
||||||
static char buffer[MAX_PRINT_MSG];
|
static char buffer[MAX_PRINT_MSG];
|
||||||
va_list args;
|
va_list args;
|
||||||
|
qboolean add_newline;
|
||||||
|
|
||||||
if( host_developer.value < DEV_EXTENDED )
|
if( host_developer.value < DEV_EXTENDED )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
va_start( args, szFmt );
|
va_start( args, szFmt );
|
||||||
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
|
add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
|
||||||
va_end( args );
|
va_end( args );
|
||||||
|
|
||||||
Sys_Print( buffer );
|
Sys_Print( buffer );
|
||||||
|
if( add_newline )
|
||||||
|
Sys_Print( "\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ GNU General Public License for more details.
|
|||||||
#include "library.h"
|
#include "library.h"
|
||||||
#include "whereami.h"
|
#include "whereami.h"
|
||||||
|
|
||||||
qboolean error_on_exit = false; // arg for exit();
|
int error_on_exit = 0; // arg for exit();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
@@ -430,7 +430,7 @@ void Sys_Error( const char *error, ... )
|
|||||||
// make sure that console received last message
|
// make sure that console received last message
|
||||||
if( host.change_game ) Sys_Sleep( 200 );
|
if( host.change_game ) Sys_Sleep( 200 );
|
||||||
|
|
||||||
error_on_exit = true;
|
error_on_exit = 1;
|
||||||
host.status = HOST_ERR_FATAL;
|
host.status = HOST_ERR_FATAL;
|
||||||
va_start( argptr, error );
|
va_start( argptr, error );
|
||||||
Q_vsnprintf( text, MAX_PRINT_MSG, error, argptr );
|
Q_vsnprintf( text, MAX_PRINT_MSG, error, argptr );
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ NOTE: never change this structure because all dll descriptions in xash code
|
|||||||
writes into struct by offsets not names
|
writes into struct by offsets not names
|
||||||
========================================================================
|
========================================================================
|
||||||
*/
|
*/
|
||||||
|
extern int error_on_exit;
|
||||||
void Sys_Sleep( int msec );
|
void Sys_Sleep( int msec );
|
||||||
double Sys_DoubleTime( void );
|
double Sys_DoubleTime( void );
|
||||||
char *Sys_GetClipboardData( void );
|
char *Sys_GetClipboardData( void );
|
||||||
|
|||||||
@@ -39,13 +39,15 @@ void Test_RunCon( void );
|
|||||||
void Test_RunVOX( void );
|
void Test_RunVOX( void );
|
||||||
void Test_RunIPFilter( void );
|
void Test_RunIPFilter( void );
|
||||||
void Test_RunGamma( void );
|
void Test_RunGamma( void );
|
||||||
|
void Test_RunDelta( void );
|
||||||
|
|
||||||
#define TEST_LIST_0 \
|
#define TEST_LIST_0 \
|
||||||
Test_RunLibCommon(); \
|
Test_RunLibCommon(); \
|
||||||
Test_RunCommon(); \
|
Test_RunCommon(); \
|
||||||
Test_RunCmd(); \
|
Test_RunCmd(); \
|
||||||
Test_RunCvar(); \
|
Test_RunCvar(); \
|
||||||
Test_RunIPFilter();
|
Test_RunIPFilter(); \
|
||||||
|
Test_RunDelta();
|
||||||
|
|
||||||
#define TEST_LIST_0_CLIENT \
|
#define TEST_LIST_0_CLIENT \
|
||||||
Test_RunCon(); \
|
Test_RunCon(); \
|
||||||
|
|||||||
@@ -25,18 +25,39 @@ GNU General Public License for more details.
|
|||||||
#include "platform/swap/swap.h"
|
#include "platform/swap/swap.h"
|
||||||
#define Q_malloc SWAP_Malloc
|
#define Q_malloc SWAP_Malloc
|
||||||
#define Q_free SWAP_Free
|
#define Q_free SWAP_Free
|
||||||
|
|
||||||
|
static void *Q_realloc( void *mem, size_t size )
|
||||||
|
{
|
||||||
|
void *newmem;
|
||||||
|
|
||||||
|
if( mem && size == 0 )
|
||||||
|
{
|
||||||
|
Q_free( mem );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
newmem = Q_malloc( size );
|
||||||
|
if( mem && newmem )
|
||||||
|
{
|
||||||
|
memcpy( newmem, mem, size );
|
||||||
|
Q_free( mem );
|
||||||
|
}
|
||||||
|
|
||||||
|
return newmem;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
#define Q_malloc malloc
|
#define Q_malloc malloc
|
||||||
#define Q_free free
|
#define Q_free free
|
||||||
|
#define Q_realloc realloc
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct memheader_s
|
typedef struct memheader_s
|
||||||
{
|
{
|
||||||
struct memheader_s *next; // next and previous memheaders in chain belonging to pool
|
struct memheader_s *next; // next and previous memheaders in chain belonging to pool
|
||||||
struct memheader_s *prev;
|
struct memheader_s *prev;
|
||||||
struct mempool_s *pool; // pool this memheader belongs to
|
|
||||||
size_t size; // size of the memory after the header (excluding header and sentinel2)
|
|
||||||
const char *filename; // file name and line where Mem_Alloc was called
|
const char *filename; // file name and line where Mem_Alloc was called
|
||||||
|
size_t size; // size of the memory after the header (excluding header and sentinel2)
|
||||||
|
poolhandle_t poolptr; // pool this memheader belongs to
|
||||||
int fileline;
|
int fileline;
|
||||||
#if !XASH_64BIT
|
#if !XASH_64BIT
|
||||||
uint32_t pad0; // doesn't have value, only to make Mem_Alloc return aligned addresses on ILP32
|
uint32_t pad0; // doesn't have value, only to make Mem_Alloc return aligned addresses on ILP32
|
||||||
@@ -48,50 +69,34 @@ typedef struct memheader_s
|
|||||||
|
|
||||||
typedef struct mempool_s
|
typedef struct mempool_s
|
||||||
{
|
{
|
||||||
uint32_t sentinel1; // should always be MEMHEADER_SENTINEL1
|
|
||||||
struct memheader_s *chain; // chain of individual memory allocations
|
struct memheader_s *chain; // chain of individual memory allocations
|
||||||
size_t totalsize; // total memory allocated in this pool (inside memheaders)
|
size_t totalsize; // total memory allocated in this pool (inside memheaders)
|
||||||
size_t realsize; // total memory allocated in this pool (actual malloc total)
|
size_t realsize; // total memory allocated in this pool (actual malloc total)
|
||||||
size_t lastchecksize; // updated each time the pool is displayed by memlist
|
size_t lastchecksize; // updated each time the pool is displayed by memlist
|
||||||
struct mempool_s *next; // linked into global mempool list
|
|
||||||
const char *filename; // file name and line where Mem_AllocPool was called
|
const char *filename; // file name and line where Mem_AllocPool was called
|
||||||
int fileline;
|
int fileline;
|
||||||
#if XASH_64BIT
|
|
||||||
poolhandle_t idx;
|
|
||||||
#endif
|
|
||||||
char name[64]; // name of the pool
|
char name[64]; // name of the pool
|
||||||
uint32_t sentinel2; // should always be MEMHEADER_SENTINEL1
|
|
||||||
} mempool_t;
|
} mempool_t;
|
||||||
|
|
||||||
static mempool_t *poolchain = NULL; // critical stuff
|
static mempool_t *poolchain = NULL; // critical stuff
|
||||||
|
static size_t poolcount = 0;
|
||||||
|
|
||||||
#if XASH_64BIT
|
|
||||||
// a1ba: due to mempool being passed with the model through reused 32-bit field
|
// a1ba: due to mempool being passed with the model through reused 32-bit field
|
||||||
// which makes engine incompatible with 64-bit pointers I changed mempool type
|
// which makes engine incompatible with 64-bit pointers I changed mempool type
|
||||||
// from pointer to 32-bit handle, thankfully mempool structure is private
|
// from pointer to 32-bit handle, thankfully mempool structure is private
|
||||||
// But! Mempools are handled through linked list so we can't index them safely
|
|
||||||
static poolhandle_t lastidx = 0;
|
|
||||||
|
|
||||||
static mempool_t *Mem_FindPool( poolhandle_t poolptr )
|
static mempool_t *Mem_FindPool( poolhandle_t poolptr )
|
||||||
{
|
{
|
||||||
mempool_t *pool;
|
if( likely( poolptr > 0 && poolptr <= poolcount ))
|
||||||
|
return &poolchain[poolptr - 1];
|
||||||
for( pool = poolchain; pool; pool = pool->next )
|
|
||||||
{
|
|
||||||
if( pool->idx == poolptr )
|
|
||||||
return pool;
|
|
||||||
}
|
|
||||||
|
|
||||||
Sys_Error( "%s: not allocated or double freed pool %d", __FUNCTION__, poolptr );
|
Sys_Error( "%s: not allocated or double freed pool %d", __FUNCTION__, poolptr );
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
static mempool_t *Mem_FindPool( poolhandle_t poolptr )
|
static poolhandle_t Mem_PoolIndex( mempool_t *mempool )
|
||||||
{
|
{
|
||||||
return (mempool_t *)poolptr;
|
return (poolhandle_t)(mempool - poolchain) + 1;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline void Mem_PoolAdd( mempool_t *pool, size_t size )
|
static inline void Mem_PoolAdd( mempool_t *pool, size_t size )
|
||||||
{
|
{
|
||||||
@@ -111,7 +116,7 @@ static inline void Mem_PoolLinkAlloc( mempool_t *pool, memheader_t *mem )
|
|||||||
if( mem->next ) mem->next->prev = mem;
|
if( mem->next ) mem->next->prev = mem;
|
||||||
pool->chain = mem;
|
pool->chain = mem;
|
||||||
mem->prev = NULL;
|
mem->prev = NULL;
|
||||||
mem->pool = pool;
|
mem->poolptr = Mem_PoolIndex( pool );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void Mem_PoolUnlinkAlloc( mempool_t *pool, memheader_t *mem )
|
static inline void Mem_PoolUnlinkAlloc( mempool_t *pool, memheader_t *mem )
|
||||||
@@ -119,7 +124,7 @@ static inline void Mem_PoolUnlinkAlloc( mempool_t *pool, memheader_t *mem )
|
|||||||
if( mem->next ) mem->next->prev = mem->prev;
|
if( mem->next ) mem->next->prev = mem->prev;
|
||||||
if( mem->prev ) mem->prev->next = mem->next;
|
if( mem->prev ) mem->prev->next = mem->next;
|
||||||
else pool->chain = mem->next;
|
else pool->chain = mem->next;
|
||||||
mem->pool = NULL;
|
mem->poolptr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void Mem_InitAlloc( memheader_t *mem, size_t size, const char *filename, int fileline )
|
static inline void Mem_InitAlloc( memheader_t *mem, size_t size, const char *filename, int fileline )
|
||||||
@@ -165,23 +170,6 @@ static qboolean Mem_CheckAllocHeader( const char *func, const memheader_t *mem,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static qboolean Mem_CheckPool( const char *func, const mempool_t *pool, const char *filename, int fileline )
|
|
||||||
{
|
|
||||||
if( pool->sentinel1 != MEMHEADER_SENTINEL1 )
|
|
||||||
{
|
|
||||||
Sys_Error( "%s: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i)\n", func, pool->filename, pool->fileline, filename, fileline );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( pool->sentinel2 != MEMHEADER_SENTINEL1 )
|
|
||||||
{
|
|
||||||
Sys_Error( "%s: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i)\n", func, pool->filename, pool->fileline, filename, fileline );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
|
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
|
||||||
{
|
{
|
||||||
memheader_t *mem;
|
memheader_t *mem;
|
||||||
@@ -190,12 +178,16 @@ void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char
|
|||||||
if( size <= 0 )
|
if( size <= 0 )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if( !poolptr )
|
if( unlikely( !poolptr ))
|
||||||
{
|
{
|
||||||
Sys_Error( "%s: pool == NULL (alloc at %s:%i)\n", __func__, filename, fileline );
|
Sys_Error( "%s: pool == NULL (alloc at %s:%i)\n", __func__, filename, fileline );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pool = Mem_FindPool( poolptr );
|
||||||
|
if( !pool )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
mem = (memheader_t *)Q_malloc( sizeof( memheader_t ) + size + sizeof( byte ));
|
mem = (memheader_t *)Q_malloc( sizeof( memheader_t ) + size + sizeof( byte ));
|
||||||
if( mem == NULL )
|
if( mem == NULL )
|
||||||
{
|
{
|
||||||
@@ -205,7 +197,6 @@ void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char
|
|||||||
|
|
||||||
Mem_InitAlloc( mem, size, filename, fileline );
|
Mem_InitAlloc( mem, size, filename, fileline );
|
||||||
|
|
||||||
pool = Mem_FindPool( poolptr );
|
|
||||||
Mem_PoolAdd( pool, size );
|
Mem_PoolAdd( pool, size );
|
||||||
Mem_PoolLinkAlloc( pool, mem );
|
Mem_PoolLinkAlloc( pool, mem );
|
||||||
|
|
||||||
@@ -222,7 +213,9 @@ static void Mem_FreeBlock( memheader_t *mem, const char *filename, int fileline
|
|||||||
if( !Mem_CheckAllocHeader( __func__, mem, filename, fileline ))
|
if( !Mem_CheckAllocHeader( __func__, mem, filename, fileline ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pool = mem->pool;
|
pool = Mem_FindPool( mem->poolptr );
|
||||||
|
if( !pool )
|
||||||
|
return;
|
||||||
|
|
||||||
// unlink memheader from doubly linked list
|
// unlink memheader from doubly linked list
|
||||||
if(( mem->prev ? mem->prev->next != mem : pool->chain != mem ) || ( mem->next && mem->next->prev != mem ))
|
if(( mem->prev ? mem->prev->next != mem : pool->chain != mem ) || ( mem->next && mem->next->prev != mem ))
|
||||||
@@ -258,7 +251,7 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
|
|||||||
if( size <= 0 )
|
if( size <= 0 )
|
||||||
return data; // no need to reallocate
|
return data; // no need to reallocate
|
||||||
|
|
||||||
if( !poolptr )
|
if( unlikely( !poolptr ))
|
||||||
{
|
{
|
||||||
Sys_Error( "Mem_Realloc: pool == NULL (alloc at %s:%i)\n", filename, fileline );
|
Sys_Error( "Mem_Realloc: pool == NULL (alloc at %s:%i)\n", filename, fileline );
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -272,25 +265,21 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
|
|||||||
if( !Mem_CheckAllocHeader( "Mem_Realloc", mem, filename, fileline ))
|
if( !Mem_CheckAllocHeader( "Mem_Realloc", mem, filename, fileline ))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if( unlikely( mem->poolptr != poolptr ))
|
||||||
|
{
|
||||||
|
Sys_Error( "Mem_Realloc: pool migration is not allowed (alloc at %s:%i, realloc at %s:%i)\n",
|
||||||
|
Mem_CheckFilename( mem->filename ), mem->fileline, filename, fileline );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
oldsize = mem->size;
|
oldsize = mem->size;
|
||||||
if( size == oldsize )
|
if( size == oldsize )
|
||||||
return data;
|
return data;
|
||||||
|
|
||||||
#if XASH_CUSTOM_SWAP
|
|
||||||
{
|
|
||||||
char *nb = _Mem_Alloc( poolptr, size, clear, filename, fileline );
|
|
||||||
|
|
||||||
size_t newsize = mem->size < size ? mem->size : size; // upper data can be trucnated!
|
|
||||||
memcpy( nb, data, newsize );
|
|
||||||
_Mem_Free( data, filename, fileline ); // free unused old block
|
|
||||||
|
|
||||||
return nb;
|
|
||||||
}
|
|
||||||
#else // XASH_CUSTOM_SWAP
|
|
||||||
pool = Mem_FindPool( poolptr );
|
pool = Mem_FindPool( poolptr );
|
||||||
|
|
||||||
oldmem = (uintptr_t)mem;
|
oldmem = (uintptr_t)mem;
|
||||||
mem = realloc( mem, sizeof( memheader_t ) + size + sizeof( byte ));
|
mem = Q_realloc( mem, sizeof( memheader_t ) + size + sizeof( byte ));
|
||||||
|
|
||||||
if( mem == NULL )
|
if( mem == NULL )
|
||||||
{
|
{
|
||||||
@@ -312,14 +301,7 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
|
|||||||
}
|
}
|
||||||
else Mem_PoolSubtract( pool, oldsize - size );
|
else Mem_PoolSubtract( pool, oldsize - size );
|
||||||
|
|
||||||
// if allocation was migrated from one pool to another
|
if( oldmem != (uintptr_t)mem ) // just relink pointers
|
||||||
// (this is possible with original Mem_Realloc func)
|
|
||||||
if( unlikely( mem->pool != pool ))
|
|
||||||
{
|
|
||||||
Mem_PoolUnlinkAlloc( mem->pool, mem );
|
|
||||||
Mem_PoolLinkAlloc( pool, mem );
|
|
||||||
}
|
|
||||||
else if( oldmem != (uintptr_t)mem ) // just relink pointers
|
|
||||||
{
|
{
|
||||||
if( mem->next ) mem->next->prev = mem;
|
if( mem->next ) mem->next->prev = mem;
|
||||||
if( mem->prev ) mem->prev->next = mem;
|
if( mem->prev ) mem->prev->next = mem;
|
||||||
@@ -327,69 +309,81 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (void *)((byte *)mem + sizeof( memheader_t ));
|
return (void *)((byte *)mem + sizeof( memheader_t ));
|
||||||
#endif // XASH_CUSTOM_SWAP
|
}
|
||||||
|
|
||||||
|
static poolhandle_t Mem_InitPool( mempool_t *pool, const char *name, const char *filename, int fileline )
|
||||||
|
{
|
||||||
|
memset( pool, 0, sizeof( *pool ));
|
||||||
|
|
||||||
|
// fill header
|
||||||
|
pool->filename = filename;
|
||||||
|
pool->fileline = fileline;
|
||||||
|
pool->realsize = sizeof( mempool_t );
|
||||||
|
Q_strncpy( pool->name, name, sizeof( pool->name ));
|
||||||
|
|
||||||
|
return Mem_PoolIndex( pool );
|
||||||
}
|
}
|
||||||
|
|
||||||
poolhandle_t _Mem_AllocPool( const char *name, const char *filename, int fileline )
|
poolhandle_t _Mem_AllocPool( const char *name, const char *filename, int fileline )
|
||||||
{
|
{
|
||||||
mempool_t *pool;
|
mempool_t *pool;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
pool = (mempool_t *)Q_malloc( sizeof( mempool_t ));
|
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
||||||
|
{
|
||||||
|
if( pool->filename == NULL )
|
||||||
|
return Mem_InitPool( pool, name, filename, fileline );
|
||||||
|
}
|
||||||
|
|
||||||
|
pool = (mempool_t *)Q_realloc( poolchain, sizeof( *poolchain ) * ( poolcount + 1 ));
|
||||||
if( pool == NULL )
|
if( pool == NULL )
|
||||||
{
|
{
|
||||||
Sys_Error( "Mem_AllocPool: out of memory (allocpool at %s:%i)\n", filename, fileline );
|
Sys_Error( "Mem_AllocPool: out of memory (allocpool at %s:%i)\n", filename, fileline );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
memset( pool, 0, sizeof( mempool_t ));
|
|
||||||
|
|
||||||
// fill header
|
|
||||||
pool->sentinel1 = MEMHEADER_SENTINEL1;
|
|
||||||
pool->sentinel2 = MEMHEADER_SENTINEL1;
|
|
||||||
pool->filename = filename;
|
|
||||||
pool->fileline = fileline;
|
|
||||||
pool->chain = NULL;
|
|
||||||
pool->totalsize = 0;
|
|
||||||
pool->realsize = sizeof( mempool_t );
|
|
||||||
Q_strncpy( pool->name, name, sizeof( pool->name ));
|
|
||||||
pool->next = poolchain;
|
|
||||||
poolchain = pool;
|
poolchain = pool;
|
||||||
|
pool = &poolchain[poolcount++];
|
||||||
#if XASH_64BIT
|
return Mem_InitPool( pool, name, filename, fileline );
|
||||||
pool->idx = ++lastidx;
|
|
||||||
return pool->idx;
|
|
||||||
#else
|
|
||||||
return (poolhandle_t)pool;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _Mem_FreePool( poolhandle_t *poolptr, const char *filename, int fileline )
|
void _Mem_FreePool( poolhandle_t *poolptr, const char *filename, int fileline )
|
||||||
{
|
{
|
||||||
mempool_t *pool;
|
mempool_t *pool;
|
||||||
mempool_t **chainaddress;
|
|
||||||
|
|
||||||
if( *poolptr && ( pool = Mem_FindPool( *poolptr )))
|
if( *poolptr && ( pool = Mem_FindPool( *poolptr )))
|
||||||
{
|
{
|
||||||
// unlink pool from chain
|
if( !pool->filename )
|
||||||
for( chainaddress = &poolchain; *chainaddress && *chainaddress != pool; chainaddress = &((*chainaddress)->next));
|
{
|
||||||
if( *chainaddress != pool ) Sys_Error( "Mem_FreePool: pool already free (freepool at %s:%i)\n", filename, fileline );
|
Sys_Error( "Mem_FreePool: pool already free (freepool at %s:%i)\n", filename, fileline );
|
||||||
Mem_CheckPool( "Mem_FreePool", pool, filename, fileline );
|
*poolptr = 0;
|
||||||
*chainaddress = pool->next;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// free memory owned by the pool
|
// free memory owned by the pool
|
||||||
while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
|
while( pool->chain )
|
||||||
|
Mem_FreeBlock( pool->chain, filename, fileline );
|
||||||
|
|
||||||
// free the pool itself
|
// free the pool itself
|
||||||
memset( pool, 0xBF, sizeof( mempool_t ));
|
memset( pool, 0xBF, sizeof( mempool_t ));
|
||||||
Q_free( pool );
|
pool->chain = NULL;
|
||||||
|
pool->filename = NULL; // mark as reusable
|
||||||
*poolptr = 0;
|
*poolptr = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _Mem_EmptyPool( poolhandle_t poolptr, const char *filename, int fileline )
|
void _Mem_EmptyPool( poolhandle_t poolptr, const char *filename, int fileline )
|
||||||
{
|
{
|
||||||
mempool_t *pool = Mem_FindPool( poolptr );
|
mempool_t *pool;
|
||||||
if( !poolptr ) Sys_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)\n", filename, fileline );
|
if( unlikely( !poolptr ))
|
||||||
|
{
|
||||||
|
Sys_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)\n", filename, fileline );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Mem_CheckPool( "Mem_FreePool", pool, filename, fileline );
|
pool = Mem_FindPool( poolptr );
|
||||||
|
if( !pool )
|
||||||
|
return;
|
||||||
|
|
||||||
// free memory owned by the pool
|
// free memory owned by the pool
|
||||||
while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
|
while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
|
||||||
@@ -412,7 +406,8 @@ static qboolean Mem_CheckAlloc( mempool_t *pool, void *data )
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// search all pools
|
// search all pools
|
||||||
for( pool = poolchain; pool; pool = pool->next )
|
size_t i;
|
||||||
|
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
||||||
{
|
{
|
||||||
if( Mem_CheckAlloc( pool, data ))
|
if( Mem_CheckAlloc( pool, data ))
|
||||||
return true;
|
return true;
|
||||||
@@ -440,23 +435,24 @@ void _Mem_Check( const char *filename, int fileline )
|
|||||||
{
|
{
|
||||||
memheader_t *mem;
|
memheader_t *mem;
|
||||||
mempool_t *pool;
|
mempool_t *pool;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
for( pool = poolchain; pool; pool = pool->next )
|
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
||||||
Mem_CheckPool( "Mem_CheckSentinels", pool, filename, fileline );
|
|
||||||
|
|
||||||
for( pool = poolchain; pool; pool = pool->next )
|
|
||||||
for( mem = pool->chain; mem; mem = mem->next )
|
for( mem = pool->chain; mem; mem = mem->next )
|
||||||
Mem_CheckAllocHeader( "Mem_CheckSentinels", mem, filename, fileline );
|
Mem_CheckAllocHeader( "Mem_CheckSentinels", mem, filename, fileline );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mem_PrintStats( void )
|
void Mem_PrintStats( void )
|
||||||
{
|
{
|
||||||
size_t count = 0, size = 0, realsize = 0;
|
size_t count = 0, size = 0, realsize = 0, i;
|
||||||
mempool_t *pool;
|
mempool_t *pool;
|
||||||
|
|
||||||
Mem_Check();
|
Mem_Check();
|
||||||
for( pool = poolchain; pool; pool = pool->next )
|
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
||||||
{
|
{
|
||||||
|
if( !pool->filename )
|
||||||
|
continue;
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
size += pool->totalsize;
|
size += pool->totalsize;
|
||||||
realsize += pool->realsize;
|
realsize += pool->realsize;
|
||||||
@@ -470,15 +466,19 @@ void Mem_PrintList( size_t minallocationsize )
|
|||||||
{
|
{
|
||||||
mempool_t *pool;
|
mempool_t *pool;
|
||||||
memheader_t *mem;
|
memheader_t *mem;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
Mem_Check();
|
Mem_Check();
|
||||||
|
|
||||||
Con_Printf( "memory pool list:\n" );
|
Con_Printf( "memory pool list:\n" );
|
||||||
Con_Printf( "\t^3size\t\t\t\tname\n");
|
Con_Printf( "\t^3size\t\t\t\tname\n");
|
||||||
for( pool = poolchain; pool; pool = pool->next )
|
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
||||||
{
|
{
|
||||||
long changed_size = (long)pool->totalsize - (long)pool->lastchecksize;
|
long changed_size = (long)pool->totalsize - (long)pool->lastchecksize;
|
||||||
|
|
||||||
|
if( !pool->filename )
|
||||||
|
continue;
|
||||||
|
|
||||||
// poolnames can contain color symbols, make sure what color is reset
|
// poolnames can contain color symbols, make sure what color is reset
|
||||||
if( pool->lastchecksize != 0 && changed_size != 0 )
|
if( pool->lastchecksize != 0 && changed_size != 0 )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -111,6 +111,11 @@ void Linux_Init( void )
|
|||||||
if( !Host_IsDedicated( ))
|
if( !Host_IsDedicated( ))
|
||||||
return;
|
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 )
|
if(( g_hsystemd = dlopen( "libsystemd.so.0", RTLD_LAZY )) == NULL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -504,12 +504,12 @@ void Wcon_CreateConsole( void )
|
|||||||
|
|
||||||
if( host.type == HOST_NORMAL )
|
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 ));
|
Q_strncpy( s_wcd.log_path, "engine.log", sizeof( s_wcd.log_path ));
|
||||||
}
|
}
|
||||||
else // dedicated console
|
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 ));
|
Q_strncpy( s_wcd.log_path, "dedicated.log", sizeof( s_wcd.log_path ));
|
||||||
s_wcd.log_active = true; // always make log
|
s_wcd.log_active = true; // always make log
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ extern int SV_UPDATE_BACKUP;
|
|||||||
|
|
||||||
// mapvalid flags
|
// mapvalid flags
|
||||||
#define MAP_IS_EXIST BIT( 0 )
|
#define MAP_IS_EXIST BIT( 0 )
|
||||||
#define MAP_HAS_SPAWNPOINT BIT( 1 )
|
|
||||||
#define MAP_HAS_LANDMARK BIT( 2 )
|
#define MAP_HAS_LANDMARK BIT( 2 )
|
||||||
#define MAP_INVALID_VERSION BIT( 3 )
|
#define MAP_INVALID_VERSION BIT( 3 )
|
||||||
|
|
||||||
@@ -613,11 +612,9 @@ string_t SV_MakeString( const char *szValue );
|
|||||||
const char *SV_GetString( string_t iString );
|
const char *SV_GetString( string_t iString );
|
||||||
void SV_SetStringArrayMode( qboolean dynamic );
|
void SV_SetStringArrayMode( qboolean dynamic );
|
||||||
void SV_EmptyStringPool( void );
|
void SV_EmptyStringPool( void );
|
||||||
#ifdef XASH_64BIT
|
|
||||||
void SV_PrintStr64Stats_f( void );
|
void SV_PrintStr64Stats_f( void );
|
||||||
#endif
|
|
||||||
sv_client_t *SV_ClientFromEdict( const edict_t *pEdict, qboolean spawned_only );
|
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 );
|
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 );
|
edict_t *SV_FindGlobalEntity( string_t classname, string_t globalname );
|
||||||
qboolean SV_CreateStaticEntity( struct sizebuf_s *msg, int index );
|
qboolean SV_CreateStaticEntity( struct sizebuf_s *msg, int index );
|
||||||
@@ -628,12 +625,18 @@ void SV_RestartAmbientSounds( void );
|
|||||||
void SV_RestartDecals( void );
|
void SV_RestartDecals( void );
|
||||||
void SV_RestartStaticEnts( void );
|
void SV_RestartStaticEnts( void );
|
||||||
int pfnDropToFloor( edict_t* e );
|
int pfnDropToFloor( edict_t* e );
|
||||||
edict_t *SV_EdictNum( int n );
|
|
||||||
void SV_SetModel( edict_t *ent, const char *name );
|
void SV_SetModel( edict_t *ent, const char *name );
|
||||||
int pfnDecalIndex( const char *m );
|
int pfnDecalIndex( const char *m );
|
||||||
void SV_CreateDecal( sizebuf_t *msg, const float *origin, int decalIndex, int entityIndex, int modelIndex, int flags, float scale );
|
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 );
|
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
|
// sv_log.c
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1690,7 +1690,7 @@ static qboolean SV_New_f( sv_client_t *cl )
|
|||||||
|
|
||||||
// server info string
|
// server info string
|
||||||
MSG_BeginServerCmd( &msg, svc_stufftext );
|
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
|
// collect the info about all the players and send to me
|
||||||
for( i = 0, cur = svs.clients; i < svs.maxclients; i++, cur++ )
|
for( i = 0, cur = svs.clients; i < svs.maxclients; i++, cur++ )
|
||||||
|
|||||||
@@ -169,17 +169,11 @@ SV_ValidateMap
|
|||||||
check map for typically errors
|
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;
|
int flags;
|
||||||
|
|
||||||
// determine spawn entity classname
|
flags = SV_MapIsValid( pMapName, NULL );
|
||||||
if( !check_spawn || (int)sv_maxclients.value <= 1 )
|
|
||||||
spawn_entity = GI->sp_entity;
|
|
||||||
else spawn_entity = GI->mp_entity;
|
|
||||||
|
|
||||||
flags = SV_MapIsValid( pMapName, spawn_entity, NULL );
|
|
||||||
|
|
||||||
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
||||||
{
|
{
|
||||||
@@ -193,12 +187,6 @@ static qboolean SV_ValidateMap( const char *pMapName, qboolean check_spawn )
|
|||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,7 +212,7 @@ static void SV_Map_f( void )
|
|||||||
Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
|
Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
|
||||||
COM_StripExtension( mapname );
|
COM_StripExtension( mapname );
|
||||||
|
|
||||||
if( !SV_ValidateMap( mapname, true ))
|
if( !SV_ValidateMap( mapname ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Cvar_DirectSet( &sv_hostmap, mapname );
|
Cvar_DirectSet( &sv_hostmap, mapname );
|
||||||
@@ -296,7 +284,7 @@ static void SV_MapBackground_f( void )
|
|||||||
Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
|
Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
|
||||||
COM_StripExtension( mapname );
|
COM_StripExtension( mapname );
|
||||||
|
|
||||||
if( !SV_ValidateMap( mapname, false ))
|
if( !SV_ValidateMap( mapname ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// background map is always run as singleplayer
|
// background map is always run as singleplayer
|
||||||
@@ -346,7 +334,7 @@ static void SV_NextMap_f( void )
|
|||||||
Cvar_DirectSet( &sv_hostmap, nextmap );
|
Cvar_DirectSet( &sv_hostmap, nextmap );
|
||||||
|
|
||||||
// found current point, check for valid
|
// found current point, check for valid
|
||||||
if( SV_ValidateMap( nextmap, true ))
|
if( SV_ValidateMap( nextmap ))
|
||||||
{
|
{
|
||||||
// found and valid
|
// found and valid
|
||||||
COM_LoadLevel( nextmap, false );
|
COM_LoadLevel( nextmap, false );
|
||||||
@@ -546,7 +534,7 @@ classic change level
|
|||||||
*/
|
*/
|
||||||
static void SV_ChangeLevel_f( void )
|
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" );
|
Con_Printf( S_USAGE "changelevel <mapname>\n" );
|
||||||
return;
|
return;
|
||||||
@@ -564,13 +552,15 @@ smooth change level
|
|||||||
*/
|
*/
|
||||||
static void SV_ChangeLevel2_f( void )
|
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;
|
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 ));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -763,7 +753,7 @@ static void SV_ServerInfo_f( void )
|
|||||||
}
|
}
|
||||||
|
|
||||||
Info_SetValueForStarKey( svs.serverinfo, Cmd_Argv( 1 ), Cmd_Argv( 2 ), MAX_SERVERINFO_STRING );
|
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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1017,6 +1007,7 @@ void SV_InitOperatorCommands( void )
|
|||||||
Cmd_AddCommand( "redirect", Rcon_Redirect_f, "force enable rcon redirection" );
|
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( "logaddress", SV_SetLogAddress_f, "sets address and port for remote logging host" );
|
||||||
Cmd_AddCommand( "log", SV_ServerLog_f, "enables logging to file" );
|
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 )
|
if( host.type == HOST_NORMAL )
|
||||||
{
|
{
|
||||||
@@ -1055,6 +1046,7 @@ void SV_KillOperatorCommands( void )
|
|||||||
Cmd_RemoveCommand( "redirect" );
|
Cmd_RemoveCommand( "redirect" );
|
||||||
Cmd_RemoveCommand( "logaddress" );
|
Cmd_RemoveCommand( "logaddress" );
|
||||||
Cmd_RemoveCommand( "log" );
|
Cmd_RemoveCommand( "log" );
|
||||||
|
Cmd_RemoveCommand( "str64stats" );
|
||||||
|
|
||||||
if( host.type == HOST_NORMAL )
|
if( host.type == HOST_NORMAL )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -811,17 +811,17 @@ static void SV_UpdateToReliableMessages( void )
|
|||||||
continue; // reliables go to all connected or spawned
|
continue; // reliables go to all connected or spawned
|
||||||
|
|
||||||
if( MSG_GetNumBytesWritten( &sv.reliable_datagram ) < MSG_GetNumBytesLeft( &cl->netchan.message ))
|
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 );
|
else Netchan_CreateFragments( &cl->netchan, &sv.reliable_datagram );
|
||||||
|
|
||||||
if( MSG_GetNumBytesWritten( &sv.datagram ) < MSG_GetNumBytesLeft( &cl->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 );
|
else Con_DPrintf( S_WARN "Ignoring unreliable datagram for %s, would overflow\n", cl->name );
|
||||||
|
|
||||||
if( FBitSet( cl->flags, FCL_HLTV_PROXY ))
|
if( FBitSet( cl->flags, FCL_HLTV_PROXY ))
|
||||||
{
|
{
|
||||||
if( MSG_GetNumBytesWritten( &sv.spec_datagram ) < MSG_GetNumBytesLeft( &cl->datagram ))
|
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 );
|
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 (__cdecl *LINK_ENTITY_FUNC)( entvars_t *pev );
|
||||||
typedef void (__stdcall *GIVEFNPTRSTODLL)( enginefuncs_t* engfuncs, globalvars_t *pGlobals );
|
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
|
#ifndef NDEBUG
|
||||||
qboolean SV_CheckEdict( const edict_t *e, const char *file, const int line )
|
qboolean SV_CheckEdict( const edict_t *e, const char *file, const int line )
|
||||||
{
|
{
|
||||||
@@ -150,18 +143,6 @@ char *SV_Serverinfo( void )
|
|||||||
return svs.serverinfo;
|
return svs.serverinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
=============
|
|
||||||
SV_LocalInfo
|
|
||||||
|
|
||||||
get local infostring
|
|
||||||
=============
|
|
||||||
*/
|
|
||||||
static char *SV_Localinfo( void )
|
|
||||||
{
|
|
||||||
return svs.localinfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============
|
=============
|
||||||
SV_AngleMod
|
SV_AngleMod
|
||||||
@@ -268,7 +249,6 @@ SV_SetModel
|
|||||||
void GAME_EXPORT SV_SetModel( edict_t *ent, const char *modelname )
|
void GAME_EXPORT SV_SetModel( edict_t *ent, const char *modelname )
|
||||||
{
|
{
|
||||||
char name[MAX_QPATH];
|
char name[MAX_QPATH];
|
||||||
qboolean found = false;
|
|
||||||
model_t *mod;
|
model_t *mod;
|
||||||
int i = 1;
|
int i = 1;
|
||||||
|
|
||||||
@@ -778,7 +758,6 @@ void SV_QueueChangeLevel( const char *level, const char *landname )
|
|||||||
{
|
{
|
||||||
uint flags, smooth = false;
|
uint flags, smooth = false;
|
||||||
char mapname[MAX_QPATH];
|
char mapname[MAX_QPATH];
|
||||||
char *spawn_entity;
|
|
||||||
|
|
||||||
// hold mapname to other place
|
// hold mapname to other place
|
||||||
Q_strncpy( mapname, level, sizeof( mapname ));
|
Q_strncpy( mapname, level, sizeof( mapname ));
|
||||||
@@ -787,12 +766,7 @@ void SV_QueueChangeLevel( const char *level, const char *landname )
|
|||||||
if( COM_CheckString( landname ))
|
if( COM_CheckString( landname ))
|
||||||
smooth = true;
|
smooth = true;
|
||||||
|
|
||||||
// determine spawn entity classname
|
flags = SV_MapIsValid( mapname, landname );
|
||||||
if( svs.maxclients == 1 )
|
|
||||||
spawn_entity = GI->sp_entity;
|
|
||||||
else spawn_entity = GI->mp_entity;
|
|
||||||
|
|
||||||
flags = SV_MapIsValid( mapname, spawn_entity, landname );
|
|
||||||
|
|
||||||
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
||||||
{
|
{
|
||||||
@@ -826,15 +800,6 @@ void SV_QueueChangeLevel( const char *level, const char *landname )
|
|||||||
return;
|
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
|
// bad changelevel position invoke enables in one-way transition
|
||||||
if( sv.framecount < 15 )
|
if( sv.framecount < 15 )
|
||||||
{
|
{
|
||||||
@@ -864,7 +829,6 @@ void SV_WriteEntityPatch( const char *filename )
|
|||||||
int lumpofs = 0, lumplen = 0;
|
int lumpofs = 0, lumplen = 0;
|
||||||
byte buf[MAX_TOKEN]; // 1 kb
|
byte buf[MAX_TOKEN]; // 1 kb
|
||||||
string bspfilename;
|
string bspfilename;
|
||||||
dheader_t *header;
|
|
||||||
dlump_t entities;
|
dlump_t entities;
|
||||||
file_t *f;
|
file_t *f;
|
||||||
|
|
||||||
@@ -875,7 +839,6 @@ void SV_WriteEntityPatch( const char *filename )
|
|||||||
|
|
||||||
memset( buf, 0, MAX_TOKEN );
|
memset( buf, 0, MAX_TOKEN );
|
||||||
FS_Read( f, buf, MAX_TOKEN );
|
FS_Read( f, buf, MAX_TOKEN );
|
||||||
header = (dheader_t *)buf;
|
|
||||||
|
|
||||||
// check all the lumps and some other errors
|
// check all the lumps and some other errors
|
||||||
if( !Mod_TestBmodelLumps( f, bspfilename, buf, true, &entities ))
|
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;
|
int lumpofs = 0, lumplen = 0;
|
||||||
byte buf[MAX_TOKEN];
|
byte buf[MAX_TOKEN];
|
||||||
char *ents = NULL;
|
char *ents = NULL;
|
||||||
dheader_t *header;
|
|
||||||
dlump_t entities;
|
dlump_t entities;
|
||||||
size_t ft1, ft2;
|
size_t ft1, ft2;
|
||||||
file_t *f;
|
file_t *f;
|
||||||
@@ -930,7 +892,6 @@ static char *SV_ReadEntityScript( const char *filename, int *flags )
|
|||||||
SetBits( *flags, MAP_IS_EXIST );
|
SetBits( *flags, MAP_IS_EXIST );
|
||||||
memset( buf, 0, MAX_TOKEN );
|
memset( buf, 0, MAX_TOKEN );
|
||||||
FS_Read( f, buf, MAX_TOKEN );
|
FS_Read( f, buf, MAX_TOKEN );
|
||||||
header = (dheader_t *)buf;
|
|
||||||
|
|
||||||
// check all the lumps and some other errors
|
// check all the lumps and some other errors
|
||||||
if( !Mod_TestBmodelLumps( f, bspfilename, buf, (host_developer.value) ? false : true, &entities ))
|
if( !Mod_TestBmodelLumps( f, bspfilename, buf, (host_developer.value) ? false : true, &entities ))
|
||||||
@@ -977,7 +938,7 @@ SV_MapIsValid
|
|||||||
Validate map
|
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;
|
uint flags = 0;
|
||||||
char *pfile;
|
char *pfile;
|
||||||
@@ -993,44 +954,26 @@ uint SV_MapIsValid( const char *filename, const char *spawn_entity, const char *
|
|||||||
|
|
||||||
need_landmark = COM_CheckString( landmark_name );
|
need_landmark = COM_CheckString( landmark_name );
|
||||||
|
|
||||||
// g-cont. in-dev mode we can entering on map even without "info_player_start"
|
if( !need_landmark )
|
||||||
if( !need_landmark && host_developer.value )
|
|
||||||
{
|
{
|
||||||
// not transition
|
|
||||||
Mem_Free( ents );
|
Mem_Free( ents );
|
||||||
|
|
||||||
// skip spawnpoint checks in devmode
|
return flags;
|
||||||
return (flags|MAP_HAS_SPAWNPOINT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pfile = ents;
|
pfile = ents;
|
||||||
|
|
||||||
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )
|
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )
|
||||||
{
|
{
|
||||||
if( !Q_strcmp( token, "classname" ))
|
if( !Q_strcmp( token, "targetname" ))
|
||||||
{
|
|
||||||
// check classname for spawn entity
|
|
||||||
pfile = COM_ParseFile( pfile, check_name, sizeof( check_name ));
|
|
||||||
if( !Q_strcmp( spawn_entity, check_name ))
|
|
||||||
{
|
|
||||||
SetBits( flags, MAP_HAS_SPAWNPOINT );
|
|
||||||
|
|
||||||
// we already find landmark, stop the parsing
|
|
||||||
if( need_landmark && FBitSet( flags, MAP_HAS_LANDMARK ))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if( need_landmark && !Q_strcmp( token, "targetname" ))
|
|
||||||
{
|
{
|
||||||
// check targetname for landmark entity
|
// check targetname for landmark entity
|
||||||
pfile = COM_ParseFile( pfile, check_name, sizeof( check_name ));
|
pfile = COM_ParseFile( pfile, check_name, sizeof( check_name ));
|
||||||
|
|
||||||
if( !Q_strcmp( landmark_name, check_name ))
|
if( !Q_strcmp( landmark_name, check_name ))
|
||||||
{
|
{
|
||||||
|
// we found landmark, stop the parsing
|
||||||
SetBits( flags, MAP_HAS_LANDMARK );
|
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
|
SV_AllocPrivateData
|
||||||
|
|
||||||
allocate private data for a given edict
|
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;
|
const char *pszClassName;
|
||||||
LINK_ENTITY_FUNC SpawnEdict;
|
LINK_ENTITY_FUNC SpawnEdict;
|
||||||
|
|
||||||
pszClassName = STRING( className );
|
pszClassName = STRING( className );
|
||||||
|
|
||||||
|
if( customentity )
|
||||||
|
*customentity = false;
|
||||||
|
|
||||||
if( !ent )
|
if( !ent )
|
||||||
{
|
{
|
||||||
// allocate a new one
|
// 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 )
|
if( svgame.physFuncs.SV_CreateEntity && svgame.physFuncs.SV_CreateEntity( ent, pszClassName ) != -1 )
|
||||||
return ent;
|
return ent;
|
||||||
|
|
||||||
|
if( customentity )
|
||||||
|
{
|
||||||
SpawnEdict = SV_GetEntityClass( "custom" );
|
SpawnEdict = SV_GetEntityClass( "custom" );
|
||||||
|
*customentity = SpawnEdict != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if( !SpawnEdict )
|
if( !SpawnEdict )
|
||||||
{
|
{
|
||||||
@@ -1216,8 +1170,6 @@ static edict_t* SV_AllocPrivateData( edict_t *ent, string_t className )
|
|||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetBits( ent->v.flags, FL_CUSTOMENTITY ); // it's a custom entity but not a beam!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SpawnEdict( &ent->v );
|
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* SV_CreateNamedEntity( edict_t *ent, string_t className )
|
||||||
{
|
{
|
||||||
edict_t *ed = SV_AllocPrivateData( ent, className );
|
return SV_AllocPrivateData( ent, className, NULL );
|
||||||
|
|
||||||
// for some reasons this flag should be immediately cleared
|
|
||||||
if( ed ) ClearBits( ed->v.flags, FL_CUSTOMENTITY );
|
|
||||||
|
|
||||||
return ed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2851,9 +2798,11 @@ standard path to register game variable
|
|||||||
static void GAME_EXPORT pfnCvar_RegisterServerVariable( cvar_t *variable )
|
static void GAME_EXPORT pfnCvar_RegisterServerVariable( cvar_t *variable )
|
||||||
{
|
{
|
||||||
if( variable != NULL )
|
if( variable != NULL )
|
||||||
|
{
|
||||||
SetBits( variable->flags, FCVAR_EXTDLL );
|
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;
|
char *newString = NULL;
|
||||||
uint len;
|
uint len;
|
||||||
|
#ifdef XASH_64BIT
|
||||||
int cmp;
|
int cmp;
|
||||||
|
#endif
|
||||||
|
|
||||||
if( svgame.physFuncs.pfnAllocString != NULL )
|
if( svgame.physFuncs.pfnAllocString != NULL )
|
||||||
{
|
{
|
||||||
@@ -3281,19 +3232,21 @@ string_t GAME_EXPORT SV_AllocString( const char *szValue )
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef XASH_64BIT
|
|
||||||
void SV_PrintStr64Stats_f( void )
|
void SV_PrintStr64Stats_f( void )
|
||||||
{
|
{
|
||||||
Msg( "====================\n" );
|
#ifdef XASH_64BIT
|
||||||
Msg( "64 bit string pool statistics\n" );
|
Con_Printf( "====================\n" );
|
||||||
Msg( "====================\n" );
|
Con_Printf( "64 bit string pool statistics\n" );
|
||||||
Msg( "string array size: %lu\n", str64.maxstringarray );
|
Con_Printf( "====================\n" );
|
||||||
Msg( "total alloc %lu\n", str64.totalalloc );
|
Con_Printf( "string array size: %lu\n", str64.maxstringarray );
|
||||||
Msg( "maximum array usage: %lu\n", str64.maxalloc );
|
Con_Printf( "total alloc %lu\n", str64.totalalloc );
|
||||||
Msg( "overflow counter: %lu\n", str64.numoverflows );
|
Con_Printf( "maximum array usage: %lu\n", str64.maxalloc );
|
||||||
Msg( "dup string counter: %lu\n", str64.numdups );
|
Con_Printf( "overflow counter: %lu\n", str64.numoverflows );
|
||||||
}
|
Con_Printf( "dup string counter: %lu\n", str64.numdups );
|
||||||
|
#else
|
||||||
|
Con_Printf( "Not implemented\n" );
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============
|
=============
|
||||||
@@ -3391,12 +3344,10 @@ pfnPEntityOfEntIndex
|
|||||||
|
|
||||||
=============
|
=============
|
||||||
*/
|
*/
|
||||||
static edict_t *pfnPEntityOfEntIndex( int iEntIndex )
|
static edict_t *pfnPEntityOfEntIndexBroken( int iEntIndex )
|
||||||
{
|
{
|
||||||
// have to be bug-compatible with GoldSrc in this function
|
// have to be bug-compatible with GoldSrc in this function
|
||||||
if( host.bugcomp == BUGCOMP_GOLDSRC )
|
|
||||||
return SV_PEntityOfEntIndex( iEntIndex, false );
|
return SV_PEntityOfEntIndex( iEntIndex, false );
|
||||||
return SV_PEntityOfEntIndex( iEntIndex, true );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3737,9 +3688,9 @@ vaild map must contain one info_player_deatchmatch
|
|||||||
*/
|
*/
|
||||||
int GAME_EXPORT pfnIsMapValid( char *filename )
|
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 true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -3873,11 +3824,11 @@ static char *GAME_EXPORT pfnGetInfoKeyBuffer( edict_t *e )
|
|||||||
|
|
||||||
// NULL passes localinfo
|
// NULL passes localinfo
|
||||||
if( !SV_IsValidEdict( e ))
|
if( !SV_IsValidEdict( e ))
|
||||||
return SV_Localinfo();
|
return svs.localinfo;
|
||||||
|
|
||||||
// world passes serverinfo
|
// world passes serverinfo
|
||||||
if( e == svgame.edicts )
|
if( e == svgame.edicts )
|
||||||
return SV_Serverinfo();
|
return svs.serverinfo;
|
||||||
|
|
||||||
// userinfo for specified edict
|
// userinfo for specified edict
|
||||||
if(( cl = SV_ClientFromEdict( e, false )) != NULL )
|
if(( cl = SV_ClientFromEdict( e, false )) != NULL )
|
||||||
@@ -4731,7 +4682,7 @@ static enginefuncs_t gEngfuncs =
|
|||||||
pfnPEntityOfEntOffset,
|
pfnPEntityOfEntOffset,
|
||||||
pfnEntOffsetOfPEntity,
|
pfnEntOffsetOfPEntity,
|
||||||
pfnIndexOfEdict,
|
pfnIndexOfEdict,
|
||||||
pfnPEntityOfEntIndex,
|
pfnPEntityOfEntIndexAllEntities,
|
||||||
pfnFindEntityByVars,
|
pfnFindEntityByVars,
|
||||||
pfnGetModelPtr,
|
pfnGetModelPtr,
|
||||||
pfnRegUserMsg,
|
pfnRegUserMsg,
|
||||||
@@ -4820,6 +4771,15 @@ static enginefuncs_t gEngfuncs =
|
|||||||
pfnPEntityOfEntIndexAllEntities,
|
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
|
SV_ParseEdict
|
||||||
@@ -4831,36 +4791,34 @@ ed should be a properly initialized empty edict.
|
|||||||
static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
|
static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
|
||||||
{
|
{
|
||||||
KeyValueData pkvd[256]; // per one entity
|
KeyValueData pkvd[256]; // per one entity
|
||||||
qboolean adjust_origin = false;
|
qboolean adjust_origin = false, customentity;
|
||||||
int i, numpairs = 0;
|
int i, numpairs = 0;
|
||||||
char *classname = NULL;
|
const char *classname = NULL;
|
||||||
char token[2048];
|
|
||||||
vec3_t origin;
|
|
||||||
|
|
||||||
// go through all the dictionary pairs
|
// go through all the dictionary pairs
|
||||||
while( 1 )
|
while( 1 )
|
||||||
{
|
{
|
||||||
string keyname;
|
string keyname;
|
||||||
|
char value[2048];
|
||||||
|
int len;
|
||||||
|
|
||||||
// parse key
|
// 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" );
|
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
|
// 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" );
|
Host_Error( "ED_ParseEdict: EOF without closing brace\n" );
|
||||||
|
|
||||||
if( token[0] == '}' )
|
if( value[0] == '}' )
|
||||||
Host_Error( "ED_ParseEdict: closing brace without data\n" );
|
Host_Error( "ED_ParseEdict: closing brace without data\n" );
|
||||||
|
|
||||||
// ignore attempts to set key ""
|
// ignore attempts to set empty key or value
|
||||||
if( !keyname[0] ) continue;
|
|
||||||
|
|
||||||
// "wad" field is already handled
|
// "wad" field is already handled
|
||||||
if( !Q_strcmp( keyname, "wad" ))
|
if( !keyname[0] || !value[0] || !Q_strcmp( keyname, "wad" ))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// keynames with a leading underscore are used for
|
// keynames with a leading underscore are used for
|
||||||
@@ -4868,57 +4826,83 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
|
|||||||
if( FBitSet( world.flags, FWORLD_SKYSPHERE ) && keyname[0] == '_' )
|
if( FBitSet( world.flags, FWORLD_SKYSPHERE ) && keyname[0] == '_' )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// ignore attempts to set value ""
|
// classname must be first
|
||||||
if( !token[0] ) continue;
|
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
|
// create keyvalue strings
|
||||||
pkvd[numpairs].szClassName = (char*)""; // unknown at this moment
|
pkvd[numpairs].szClassName = (char*)""; // unknown at this moment
|
||||||
pkvd[numpairs].szKeyName = copystring( keyname );
|
pkvd[numpairs].szKeyName = copystring( keyname );
|
||||||
pkvd[numpairs].szValue = copystring( token );
|
pkvd[numpairs].szValue = copystring( value );
|
||||||
pkvd[numpairs].fHandled = false;
|
pkvd[numpairs].fHandled = false;
|
||||||
|
numpairs++;
|
||||||
|
|
||||||
if( !Q_strcmp( keyname, "classname" ) && classname == NULL )
|
if( numpairs > ARRAYSIZE( pkvd ))
|
||||||
classname = copystring( pkvd[numpairs].szValue );
|
{
|
||||||
if( ++numpairs >= 256 ) break;
|
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 )
|
if( classname == NULL )
|
||||||
{
|
{
|
||||||
// release allocated strings
|
// release allocated strings
|
||||||
for( i = 0; i < numpairs; i++ )
|
SV_FreeKeyValueStrings( pkvd, numpairs );
|
||||||
{
|
|
||||||
Mem_Free( pkvd[i].szKeyName );
|
|
||||||
Mem_Free( pkvd[i].szValue );
|
|
||||||
}
|
|
||||||
return false;
|
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 ))
|
if( !SV_IsValidEdict( ent ) || FBitSet( ent->v.flags, FL_KILLME ))
|
||||||
{
|
{
|
||||||
// release allocated strings
|
// release allocated strings
|
||||||
for( i = 0; i < numpairs; i++ )
|
SV_FreeKeyValueStrings( pkvd, numpairs );
|
||||||
{
|
|
||||||
Mem_Free( pkvd[i].szKeyName );
|
|
||||||
Mem_Free( pkvd[i].szValue );
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( FBitSet( ent->v.flags, FL_CUSTOMENTITY ))
|
if( customentity )
|
||||||
{
|
{
|
||||||
if( numpairs < 256 )
|
KeyValueData kvd = {
|
||||||
{
|
.szClassName = (char *)"custom",
|
||||||
pkvd[numpairs].szClassName = (char*)"custom";
|
.szKeyName = (char *)"customclass",
|
||||||
pkvd[numpairs].szKeyName = (char*)"customclass";
|
.szValue = (char *)classname,
|
||||||
pkvd[numpairs].szValue = classname;
|
.fHandled = false
|
||||||
pkvd[numpairs].fHandled = false;
|
};
|
||||||
numpairs++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear it now - no longer used
|
svgame.dllFuncs.pfnKeyValue( ent, &kvd );
|
||||||
ClearBits( ent->v.flags, FL_CUSTOMENTITY );
|
// no fHandled check, GoldSrc behavior
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HACKS_RELATED_HLMODS
|
#ifdef HACKS_RELATED_HLMODS
|
||||||
@@ -4932,6 +4916,14 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
|
|||||||
|
|
||||||
for( i = 0; i < numpairs; i++ )
|
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" ))
|
if( !Q_strcmp( pkvd[i].szKeyName, "angle" ))
|
||||||
{
|
{
|
||||||
float flYawAngle = Q_atof( pkvd[i].szValue );
|
float flYawAngle = Q_atof( pkvd[i].szValue );
|
||||||
@@ -4942,8 +4934,6 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
|
|||||||
|
|
||||||
if( flYawAngle >= 0.0f )
|
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] );
|
Q_snprintf( temp, sizeof( temp ), "%g %g %g", ent->v.angles[0], flYawAngle, ent->v.angles[2] );
|
||||||
pkvd[i].szValue = copystring( temp );
|
pkvd[i].szValue = copystring( temp );
|
||||||
}
|
}
|
||||||
@@ -4954,11 +4944,10 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
|
|||||||
else pkvd[i].szValue = copystring( "0 0 0" ); // technically an error
|
else pkvd[i].szValue = copystring( "0 0 0" ); // technically an error
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HACKS_RELATED_HLMODS
|
|
||||||
if( adjust_origin && !Q_strcmp( pkvd[i].szKeyName, "origin" ))
|
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 );
|
COM_ParseVector( &pstart, origin, 3 );
|
||||||
Mem_Free( pkvd[i].szValue ); // release old value, so we don't need these
|
Mem_Free( pkvd[i].szValue ); // release old value, so we don't need these
|
||||||
@@ -4966,24 +4955,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 );
|
Q_snprintf( temp, sizeof( temp ), "%g %g %g", origin[0], origin[1], origin[2] - 16.0f );
|
||||||
pkvd[i].szValue = copystring( temp );
|
pkvd[i].szValue = copystring( temp );
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
if( !pkvd[i].fHandled )
|
// do not leak memory if game overwritten these pointers
|
||||||
{
|
keyname = pkvd[i].szKeyName;
|
||||||
pkvd[i].szClassName = classname;
|
value = pkvd[i].szValue;
|
||||||
|
|
||||||
|
pkvd[i].szClassName = (char *)classname;
|
||||||
svgame.dllFuncs.pfnKeyValue( ent, &pkvd[i] );
|
svgame.dllFuncs.pfnKeyValue( ent, &pkvd[i] );
|
||||||
|
|
||||||
|
Mem_Free( keyname );
|
||||||
|
Mem_Free( value );
|
||||||
}
|
}
|
||||||
|
|
||||||
// no reason to keep this data
|
|
||||||
if( Mem_IsAllocatedExt( host.mempool, pkvd[i].szKeyName ))
|
|
||||||
Mem_Free( pkvd[i].szKeyName );
|
|
||||||
|
|
||||||
if( Mem_IsAllocatedExt( host.mempool, pkvd[i].szValue ))
|
|
||||||
Mem_Free( pkvd[i].szValue );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( Mem_IsAllocatedExt( host.mempool, classname ))
|
|
||||||
Mem_Free( classname );
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5102,8 +5085,6 @@ void SV_UnloadProgs( void )
|
|||||||
/// SV_UnloadProgs will be disabled
|
/// SV_UnloadProgs will be disabled
|
||||||
//Mod_ClearUserData ();
|
//Mod_ClearUserData ();
|
||||||
|
|
||||||
SV_FreeStringPool();
|
|
||||||
|
|
||||||
if( svgame.dllFuncs2.pfnGameShutdown != NULL )
|
if( svgame.dllFuncs2.pfnGameShutdown != NULL )
|
||||||
svgame.dllFuncs2.pfnGameShutdown ();
|
svgame.dllFuncs2.pfnGameShutdown ();
|
||||||
|
|
||||||
@@ -5124,6 +5105,8 @@ void SV_UnloadProgs( void )
|
|||||||
Cvar_Unlink( FCVAR_EXTDLL );
|
Cvar_Unlink( FCVAR_EXTDLL );
|
||||||
Cmd_Unlink( CMD_SERVERDLL );
|
Cmd_Unlink( CMD_SERVERDLL );
|
||||||
|
|
||||||
|
SV_FreeStringPool();
|
||||||
|
|
||||||
Mod_ResetStudioAPI ();
|
Mod_ResetStudioAPI ();
|
||||||
|
|
||||||
COM_FreeLibrary( svgame.hInstance );
|
COM_FreeLibrary( svgame.hInstance );
|
||||||
@@ -5170,6 +5153,11 @@ qboolean SV_LoadProgs( const char *name )
|
|||||||
// make sure what physic functions is cleared
|
// make sure what physic functions is cleared
|
||||||
memset( &svgame.physFuncs, 0, sizeof( svgame.physFuncs ));
|
memset( &svgame.physFuncs, 0, sizeof( svgame.physFuncs ));
|
||||||
|
|
||||||
|
// revert fix for pfnPEntityOfEntIndex to be compatible with GoldSrc
|
||||||
|
// games that rely on this bug
|
||||||
|
if( FBitSet( host.bugcomp, BUGCOMP_PENTITYOFENTINDEX_FLAG ))
|
||||||
|
gEngfuncs.pfnPEntityOfEntIndex = pfnPEntityOfEntIndexBroken;
|
||||||
|
|
||||||
// make local copy of engfuncs to prevent overwrite it with bots.dll
|
// make local copy of engfuncs to prevent overwrite it with bots.dll
|
||||||
memcpy( &gpEngfuncs, &gEngfuncs, sizeof( gpEngfuncs ));
|
memcpy( &gpEngfuncs, &gEngfuncs, sizeof( gpEngfuncs ));
|
||||||
|
|
||||||
@@ -5218,6 +5206,7 @@ qboolean SV_LoadProgs( const char *name )
|
|||||||
{
|
{
|
||||||
if( !GetEntityAPI2( &svgame.dllFuncs, &version ))
|
if( !GetEntityAPI2( &svgame.dllFuncs, &version ))
|
||||||
{
|
{
|
||||||
|
if( INTERFACE_VERSION != version )
|
||||||
Con_Printf( S_WARN "SV_LoadProgs: interface version %i should be %i\n", INTERFACE_VERSION, version );
|
Con_Printf( S_WARN "SV_LoadProgs: interface version %i should be %i\n", INTERFACE_VERSION, version );
|
||||||
|
|
||||||
// fallback to old API
|
// fallback to old API
|
||||||
@@ -5229,6 +5218,7 @@ qboolean SV_LoadProgs( const char *name )
|
|||||||
Mem_FreePool( &svgame.mempool );
|
Mem_FreePool( &svgame.mempool );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else Con_Reportf( "SV_LoadProgs: ^2initailized legacy EntityAPI ^7ver. %i\n", version );
|
||||||
}
|
}
|
||||||
else Con_Reportf( "SV_LoadProgs: ^2initailized extended EntityAPI ^7ver. %i\n", version );
|
else Con_Reportf( "SV_LoadProgs: ^2initailized extended EntityAPI ^7ver. %i\n", version );
|
||||||
}
|
}
|
||||||
@@ -5240,6 +5230,7 @@ qboolean SV_LoadProgs( const char *name )
|
|||||||
Mem_FreePool( &svgame.mempool );
|
Mem_FreePool( &svgame.mempool );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else Con_Reportf( "SV_LoadProgs: ^2initailized legacy EntityAPI ^7ver. %i\n", version );
|
||||||
|
|
||||||
SV_InitOperatorCommands();
|
SV_InitOperatorCommands();
|
||||||
Mod_InitStudioAPI();
|
Mod_InitStudioAPI();
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ void Log_Open( void )
|
|||||||
|
|
||||||
if( fp ) svs.log.file = fp;
|
if( fp ) svs.log.file = fp;
|
||||||
Log_Printf( "Log file started (file \"%s\") (game \"%s\") (version \"%i/" XASH_VERSION "/%d\")\n",
|
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 )
|
void Log_Close( void )
|
||||||
|
|||||||
@@ -2110,7 +2110,7 @@ qboolean SV_LoadGame( const char *pPath )
|
|||||||
if( validload )
|
if( validload )
|
||||||
{
|
{
|
||||||
// now check for map problems
|
// 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 ))
|
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
||||||
{
|
{
|
||||||
@@ -2386,7 +2386,7 @@ int GAME_EXPORT SV_GetSaveComment( const char *savename, char *comment )
|
|||||||
uint flags;
|
uint flags;
|
||||||
|
|
||||||
// now check for map problems
|
// now check for map problems
|
||||||
flags = SV_MapIsValid( mapName, GI->sp_entity, NULL );
|
flags = SV_MapIsValid( mapName, NULL );
|
||||||
|
|
||||||
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -320,6 +320,12 @@ public:
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
state = new CSearchState( &searchHead, search );
|
state = new CSearchState( &searchHead, search );
|
||||||
|
if( !state )
|
||||||
|
{
|
||||||
|
Mem_Free( search );
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
*handle = state->handle;
|
*handle = state->handle;
|
||||||
return state->search->filenames[0];
|
return state->search->filenames[0];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1363,8 +1363,13 @@ static qboolean FS_FindLibrary( const char *dllname, qboolean directpath, fs_dll
|
|||||||
|
|
||||||
if( index >= 0 && !dllInfo->encrypted && search )
|
if( index >= 0 && !dllInfo->encrypted && search )
|
||||||
{
|
{
|
||||||
Q_snprintf( dllInfo->fullPath, sizeof( dllInfo->fullPath ),
|
// gamedll might resolve it's own path using dladdr()
|
||||||
"%s%s", search->filename, dllInfo->shortPath );
|
// combine it with engine returned path to gamedir
|
||||||
|
// it might lead to double gamedir like this
|
||||||
|
// - valve/valve/dlls/hl.so
|
||||||
|
// instead of expected
|
||||||
|
// - valve/dlls/hl.so
|
||||||
|
Q_snprintf( dllInfo->fullPath, sizeof( dllInfo->fullPath ), "%s/%s%s", fs_rootdir, search->filename, dllInfo->shortPath );
|
||||||
dllInfo->custom_loader = false; // we can loading from disk and use normal debugging
|
dllInfo->custom_loader = false; // we can loading from disk and use normal debugging
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ extern "C"
|
|||||||
{
|
{
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
|
||||||
#define FS_API_VERSION 2 // not stable yet!
|
#define FS_API_VERSION 3 // not stable yet!
|
||||||
#define FS_API_CREATEINTERFACE_TAG "XashFileSystem002" // follow FS_API_VERSION!!!
|
#define FS_API_CREATEINTERFACE_TAG "XashFileSystem002" // follow FS_API_VERSION!!!
|
||||||
#define FILESYSTEM_INTERFACE_VERSION "VFileSystem009" // never change this!
|
#define FILESYSTEM_INTERFACE_VERSION "VFileSystem009" // never change this!
|
||||||
|
|
||||||
@@ -121,8 +121,8 @@ typedef enum
|
|||||||
|
|
||||||
typedef struct fs_dllinfo_t
|
typedef struct fs_dllinfo_t
|
||||||
{
|
{
|
||||||
string fullPath;
|
char fullPath[2048]; // absolute disk path
|
||||||
string shortPath;
|
string shortPath; // vfs path
|
||||||
qboolean encrypted;
|
qboolean encrypted;
|
||||||
qboolean custom_loader;
|
qboolean custom_loader;
|
||||||
} fs_dllinfo_t;
|
} fs_dllinfo_t;
|
||||||
|
|||||||
@@ -358,7 +358,7 @@ searchpath_t *FS_AddPak_Fullpath( const char *pakfile, int flags )
|
|||||||
search->pfnFindFile = FS_FindFile_PAK;
|
search->pfnFindFile = FS_FindFile_PAK;
|
||||||
search->pfnSearch = FS_Search_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;
|
return search;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -670,6 +670,6 @@ searchpath_t *FS_AddWad_Fullpath( const char *wadfile, int flags )
|
|||||||
search->pfnSearch = FS_Search_WAD;
|
search->pfnSearch = FS_Search_WAD;
|
||||||
search->pfnLoadFile = W_ReadLump;
|
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;
|
return search;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -701,7 +701,7 @@ searchpath_t *FS_AddZip_Fullpath( const char *zipfile, int flags )
|
|||||||
search->pfnSearch = FS_Search_ZIP;
|
search->pfnSearch = FS_Search_ZIP;
|
||||||
search->pfnLoadFile = FS_LoadZIPFile;
|
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;
|
return search;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -237,19 +237,25 @@ const char *Q_buildarch( void )
|
|||||||
=============
|
=============
|
||||||
Q_buildcommit
|
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
|
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 )
|
const char *Q_buildcommit( void )
|
||||||
{
|
{
|
||||||
#ifdef XASH_BUILD_COMMIT
|
|
||||||
return 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_ArchitectureStringByID( const int arch, const uint abi, const int endianness, const qboolean is64 );
|
||||||
const char *Q_buildarch( void );
|
const char *Q_buildarch( void );
|
||||||
const char *Q_buildcommit( void );
|
const char *Q_buildcommit( void );
|
||||||
|
const char *Q_buildbranch( void );
|
||||||
|
|
||||||
//
|
//
|
||||||
// crtlib.c
|
// 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
|
return
|
||||||
|
|
||||||
def configure(conf):
|
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):
|
def build(bld):
|
||||||
bld(name = 'sdk_includes', export_includes = '. ../common ../pm_shared ../engine')
|
bld(name = 'sdk_includes', export_includes = '. ../common ../pm_shared ../engine')
|
||||||
|
|||||||
@@ -73,7 +73,8 @@ GNU General Public License for more details.
|
|||||||
|
|
||||||
#define Q_min( a, b ) (((a) < (b)) ? (a) : (b))
|
#define Q_min( a, b ) (((a) < (b)) ? (a) : (b))
|
||||||
#define Q_max( a, b ) (((a) > (b)) ? (a) : (b))
|
#define Q_max( a, b ) (((a) > (b)) ? (a) : (b))
|
||||||
#define Q_equal( a, b ) (((a) > ((b) - EQUAL_EPSILON)) && ((a) < ((b) + EQUAL_EPSILON)))
|
#define Q_equal_e( a, b, e ) (((a) > ((b) - (e))) && ((a) < ((b) + (e))))
|
||||||
|
#define Q_equal( a, b ) Q_equal_e( a, b, EQUAL_EPSILON )
|
||||||
#define Q_recip( a ) ((float)(1.0f / (float)(a)))
|
#define Q_recip( a ) ((float)(1.0f / (float)(a)))
|
||||||
#define Q_floor( a ) ((float)(int)(a))
|
#define Q_floor( a ) ((float)(int)(a))
|
||||||
#define Q_ceil( a ) ((float)(int)((a) + 1))
|
#define Q_ceil( a ) ((float)(int)((a) + 1))
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ static int g_used[8192];
|
|||||||
|
|
||||||
// a pose is a single set of vertexes. a frame may be
|
// a pose is a single set of vertexes. a frame may be
|
||||||
// an animating sequence of poses
|
// 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
|
// the command list holds counts and s/t values that are valid for
|
||||||
// every frame
|
// every frame
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ static void R_SimpleStubBool( qboolean )
|
|||||||
|
|
||||||
static qboolean R_Init( void )
|
static qboolean R_Init( void )
|
||||||
{
|
{
|
||||||
|
gEngfuncs.R_Init_Video( REF_SOFTWARE );
|
||||||
return true;
|
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 )
|
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 )
|
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 )
|
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 )
|
static void Mod_StudioLoadTextures( model_t *mod, void *data )
|
||||||
|
|||||||
9
wscript
9
wscript
@@ -181,7 +181,7 @@ def configure(conf):
|
|||||||
if conf.env.COMPILER_CC == 'msvc':
|
if conf.env.COMPILER_CC == 'msvc':
|
||||||
conf.load('msvc_pdb')
|
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
|
# Force XP compatibility, all build targets should add subsystem=bld.env.MSVC_SUBSYSTEM
|
||||||
if conf.env.MSVC_TARGETS[0] == 'x86':
|
if conf.env.MSVC_TARGETS[0] == 'x86':
|
||||||
@@ -279,7 +279,7 @@ def configure(conf):
|
|||||||
conf.env.append_unique('CXXFLAGS', cxxflags)
|
conf.env.append_unique('CXXFLAGS', cxxflags)
|
||||||
conf.env.append_unique('LINKFLAGS', linkflags)
|
conf.env.append_unique('LINKFLAGS', linkflags)
|
||||||
|
|
||||||
if conf.env.COMPILER_CC != 'msvc' and not conf.options.DISABLE_WERROR:
|
if conf.env.COMPILER_CC != 'msvc':
|
||||||
opt_flags = [
|
opt_flags = [
|
||||||
# '-Wall', '-Wextra', '-Wpedantic',
|
# '-Wall', '-Wextra', '-Wpedantic',
|
||||||
'-fdiagnostics-color=always',
|
'-fdiagnostics-color=always',
|
||||||
@@ -342,6 +342,11 @@ def configure(conf):
|
|||||||
|
|
||||||
opt_cxxflags = [] # TODO:
|
opt_cxxflags = [] # TODO:
|
||||||
|
|
||||||
|
if conf.options.DISABLE_WERROR:
|
||||||
|
opt_flags = []
|
||||||
|
opt_cflags = ['-Werror=implicit-function-declaration']
|
||||||
|
opt_cxxflags = []
|
||||||
|
|
||||||
conf.env.CFLAGS_werror = conf.filter_cflags(opt_flags + opt_cflags, cflags)
|
conf.env.CFLAGS_werror = conf.filter_cflags(opt_flags + opt_cflags, cflags)
|
||||||
conf.env.CXXFLAGS_werror = conf.filter_cxxflags(opt_flags + opt_cxxflags, cxxflags)
|
conf.env.CXXFLAGS_werror = conf.filter_cxxflags(opt_flags + opt_cxxflags, cxxflags)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user