engine: implement small Message Rewrite Facitility that allows to run mods that directly write internal GoldSrc messages
This commit is contained in:
parent
7ccb0b5c02
commit
dd410a2de5
5 changed files with 100 additions and 5 deletions
|
@ -13,3 +13,4 @@ When `-bugcomp` is specified with argument, it interpreted as flags separated wi
|
||||||
| Flag | Description | Games that require this flag |
|
| Flag | Description | Games that require this flag |
|
||||||
| ------- | ----------- | ---------------------------- |
|
| ------- | ----------- | ---------------------------- |
|
||||||
| `peoei` | Reverts `pfnPEntityOfEntIndex` behavior to GoldSrc, where it returns NULL for last player due to incorrect player index comparison | * Counter-Strike: Condition Zero - Deleted Scenes |
|
| `peoei` | Reverts `pfnPEntityOfEntIndex` behavior to GoldSrc, where it returns NULL for last player due to incorrect player index comparison | * Counter-Strike: Condition Zero - Deleted Scenes |
|
||||||
|
| `gsmrf` | Rewrites message at the moment when Game DLL attempts to write an internal engine message, usually specific to GoldSrc protocol. Right now only supports `svc_spawnstaticsound`, more messages added by request. | * MetaMod/AMXModX based mods |
|
||||||
|
|
|
@ -275,6 +275,10 @@ typedef enum bugcomp_e
|
||||||
{
|
{
|
||||||
// reverts fix for pfnPEntityOfEntIndex for bug compatibility with GoldSrc
|
// reverts fix for pfnPEntityOfEntIndex for bug compatibility with GoldSrc
|
||||||
BUGCOMP_PENTITYOFENTINDEX_FLAG = BIT( 0 ),
|
BUGCOMP_PENTITYOFENTINDEX_FLAG = BIT( 0 ),
|
||||||
|
|
||||||
|
// rewrites mod's attempts to write GoldSrc-specific messages into Xash protocol
|
||||||
|
// (new wrappers are added by request)
|
||||||
|
BUGCOMP_MESSAGE_REWRITE_FACILITY_FLAG = BIT( 1 ),
|
||||||
} bugcomp_t;
|
} bugcomp_t;
|
||||||
|
|
||||||
typedef struct host_parm_s
|
typedef struct host_parm_s
|
||||||
|
|
|
@ -75,6 +75,7 @@ typedef struct feature_message_s
|
||||||
static feature_message_t bugcomp_features[] =
|
static feature_message_t bugcomp_features[] =
|
||||||
{
|
{
|
||||||
{ BUGCOMP_PENTITYOFENTINDEX_FLAG, "pfnPEntityOfEntIndex bugfix revert", "peoei" },
|
{ BUGCOMP_PENTITYOFENTINDEX_FLAG, "pfnPEntityOfEntIndex bugfix revert", "peoei" },
|
||||||
|
{ BUGCOMP_MESSAGE_REWRITE_FACILITY_FLAG, "GoldSrc Message Rewrite Facility", "gsmrf" },
|
||||||
};
|
};
|
||||||
|
|
||||||
static feature_message_t engine_features[] =
|
static feature_message_t engine_features[] =
|
||||||
|
|
|
@ -329,6 +329,8 @@ typedef struct
|
||||||
int msg_realsize; // left in bytes
|
int msg_realsize; // left in bytes
|
||||||
int msg_index; // for debug messages
|
int msg_index; // for debug messages
|
||||||
int msg_dest; // msg destination ( MSG_ONE, MSG_ALL etc )
|
int msg_dest; // msg destination ( MSG_ONE, MSG_ALL etc )
|
||||||
|
int msg_rewrite_index;
|
||||||
|
int msg_rewrite_pos;
|
||||||
qboolean msg_started; // to avoid recursive included messages
|
qboolean msg_started; // to avoid recursive included messages
|
||||||
edict_t *msg_ent; // user message member entity
|
edict_t *msg_ent; // user message member entity
|
||||||
vec3_t msg_org; // user message member origin
|
vec3_t msg_org; // user message member origin
|
||||||
|
|
|
@ -2501,6 +2501,62 @@ int GAME_EXPORT pfnDecalIndex( const char *m )
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int SV_CanRewriteMessage( int msg_num )
|
||||||
|
{
|
||||||
|
// feature is disabled
|
||||||
|
if( !FBitSet( host.bugcomp, BUGCOMP_MESSAGE_REWRITE_FACILITY_FLAG ))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch( msg_num )
|
||||||
|
{
|
||||||
|
case svc_goldsrc_spawnstaticsound:
|
||||||
|
return svc_sound;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean SV_RewriteMessage( void )
|
||||||
|
{
|
||||||
|
vec3_t origin;
|
||||||
|
const char *sample = NULL;
|
||||||
|
float vol, attn;
|
||||||
|
int ent, pitch, flags, idx;
|
||||||
|
int cmd;
|
||||||
|
|
||||||
|
MSG_SeekToBit( &sv.multicast, svgame.msg_rewrite_pos, SEEK_SET );
|
||||||
|
|
||||||
|
cmd = MSG_ReadCmd( &sv.multicast, NS_SERVER );
|
||||||
|
|
||||||
|
switch( cmd )
|
||||||
|
{
|
||||||
|
case svc_goldsrc_spawnstaticsound:
|
||||||
|
MSG_ReadVec3Coord( &sv.multicast, origin );
|
||||||
|
idx = MSG_ReadShort( &sv.multicast );
|
||||||
|
vol = MSG_ReadByte( &sv.multicast );
|
||||||
|
attn = MSG_ReadByte( &sv.multicast ) / 64.0f;
|
||||||
|
ent = MSG_ReadShort( &sv.multicast );
|
||||||
|
pitch = MSG_ReadByte( &sv.multicast );
|
||||||
|
flags = MSG_ReadByte( &sv.multicast );
|
||||||
|
|
||||||
|
if( FBitSet( flags, SND_SENTENCE ))
|
||||||
|
sample = va( "!%i", idx );
|
||||||
|
else if( idx >= 0 && idx < MAX_SOUNDS )
|
||||||
|
sample = sv.sound_precache[idx];
|
||||||
|
|
||||||
|
if( !COM_CheckString( sample ))
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "%s: unrecognized sample in svc_spawnstaticsound, index %d, flags 0x%x\n", __func__, idx, flags );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MSG_SeekToBit( &sv.multicast, svgame.msg_rewrite_pos, SEEK_SET );
|
||||||
|
return SV_BuildSoundMsg( &sv.multicast, EDICT_NUM( ent ), CHAN_STATIC, sample, vol, attn, flags, pitch, origin );
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============
|
=============
|
||||||
pfnMessageBegin
|
pfnMessageBegin
|
||||||
|
@ -2518,10 +2574,24 @@ static void GAME_EXPORT pfnMessageBegin( int msg_dest, int msg_num, const float
|
||||||
// check range
|
// check range
|
||||||
msg_num = bound( svc_bad, msg_num, 255 );
|
msg_num = bound( svc_bad, msg_num, 255 );
|
||||||
|
|
||||||
|
svgame.msg_rewrite_index = 0;
|
||||||
|
svgame.msg_rewrite_pos = 0;
|
||||||
|
|
||||||
if( msg_num <= svc_lastmsg )
|
if( msg_num <= svc_lastmsg )
|
||||||
|
{
|
||||||
|
// check if we should rewrite this message into something else...
|
||||||
|
if( SV_CanRewriteMessage( msg_num ))
|
||||||
|
{
|
||||||
|
svgame.msg_index = -SV_CanRewriteMessage( msg_num );
|
||||||
|
svgame.msg_name = svc_goldsrc_strings[msg_num] ? svc_goldsrc_strings[msg_num] : svc_strings[msg_num];
|
||||||
|
svgame.msg_rewrite_index = msg_num;
|
||||||
|
svgame.msg_rewrite_pos = MSG_TellBit( &sv.multicast );
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
svgame.msg_index = -msg_num; // this is a system message
|
svgame.msg_index = -msg_num; // this is a system message
|
||||||
svgame.msg_name = svc_strings[msg_num];
|
svgame.msg_name = svc_strings[msg_num];
|
||||||
|
}
|
||||||
|
|
||||||
if( msg_num == svc_temp_entity )
|
if( msg_num == svc_temp_entity )
|
||||||
iSize = -1; // temp entity have variable size
|
iSize = -1; // temp entity have variable size
|
||||||
|
@ -2596,6 +2666,25 @@ static void GAME_EXPORT pfnMessageEnd( void )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( svgame.msg_rewrite_index != 0 )
|
||||||
|
{
|
||||||
|
if( SV_RewriteMessage( ))
|
||||||
|
{
|
||||||
|
if( MSG_CheckOverflow( &sv.multicast ))
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "MessageEnd: %s has overflow multicast buffer (post-rewrite)\n", name );
|
||||||
|
MSG_Clear( &sv.multicast );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "MessageEnd: failed to rewrite message %s\n", name );
|
||||||
|
MSG_Clear( &sv.multicast );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// check for system message
|
// check for system message
|
||||||
if( svgame.msg_index < 0 )
|
if( svgame.msg_index < 0 )
|
||||||
{
|
{
|
||||||
|
@ -2662,9 +2751,7 @@ static void GAME_EXPORT pfnMessageEnd( void )
|
||||||
// update some messages in case their was format was changed and we want to keep backward compatibility
|
// update some messages in case their was format was changed and we want to keep backward compatibility
|
||||||
if( svgame.msg_index < 0 )
|
if( svgame.msg_index < 0 )
|
||||||
{
|
{
|
||||||
int svc_msg = abs( svgame.msg_index );
|
if(( svgame.msg_index == -svc_finale || svgame.msg_index == -svc_cutscene ) && svgame.msg_realsize == 0 )
|
||||||
|
|
||||||
if(( svc_msg == svc_finale || svc_msg == svc_cutscene ) && svgame.msg_realsize == 0 )
|
|
||||||
MSG_WriteChar( &sv.multicast, 0 ); // write null string
|
MSG_WriteChar( &sv.multicast, 0 ); // write null string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue