Skip to content

Commit

Permalink
Restore compatibility with Q2PRO extended games after fog changes
Browse files Browse the repository at this point in the history
* Support reading player state(s) possibly containing fog changes,
  when connecting to a Q2PRO extended server as a client.
* Translate player state fog to svc_fog messages, when running
  a Q2PRO extended game.

(based on commit fbf0cd9)
  • Loading branch information
res2k committed Oct 26, 2024
1 parent 8658120 commit 78367cc
Show file tree
Hide file tree
Showing 14 changed files with 352 additions and 95 deletions.
51 changes: 45 additions & 6 deletions inc/common/msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ typedef struct {
// KEX
} entity_packed_t;

typedef struct {
uint8_t color[3][3];
uint32_t density;
uint16_t height_density;
uint16_t height_falloff;
int32_t height_dist[2];
} player_packed_fog_t;

typedef struct {
pmove_state_t pmove;
int16_t viewangles[3];
Expand All @@ -61,6 +69,7 @@ typedef struct {
uint8_t gunframe;
uint8_t screen_blend[4];
uint8_t damage_blend[4];
player_packed_fog_t fog;
uint8_t fov;
uint8_t rdflags;
int16_t stats[MAX_STATS_NEW];
Expand All @@ -69,6 +78,35 @@ typedef struct {
// KEX
} player_packed_t;

typedef enum
{
// global fog
FOG_BIT_DENSITY = BIT(0),
FOG_BIT_R = BIT(1),
FOG_BIT_G = BIT(2),
FOG_BIT_B = BIT(3),
FOG_BIT_TIME = BIT(4), // if set, the transition takes place over N milliseconds

// height fog
FOG_BIT_HEIGHTFOG_FALLOFF = BIT(5),
FOG_BIT_HEIGHTFOG_DENSITY = BIT(6),
FOG_BIT_MORE_BITS = BIT(7), // read additional bit
FOG_BIT_HEIGHTFOG_START_R = BIT(8),
FOG_BIT_HEIGHTFOG_START_G = BIT(9),
FOG_BIT_HEIGHTFOG_START_B = BIT(10),
FOG_BIT_HEIGHTFOG_START_DIST= BIT(11),
FOG_BIT_HEIGHTFOG_END_R = BIT(12),
FOG_BIT_HEIGHTFOG_END_G = BIT(13),
FOG_BIT_HEIGHTFOG_END_B = BIT(14),
FOG_BIT_HEIGHTFOG_END_DIST = BIT(15)
} fog_bits_t;

typedef struct {
fog_bits_t bits;
player_fog_t linear;
player_heightfog_t height;
} player_fogchange_t;

typedef enum {
MSG_PS_IGNORE_GUNINDEX = BIT(0), // ignore gunindex
MSG_PS_IGNORE_GUNFRAMES = BIT(1), // ignore gunframe/gunoffset/gunangles
Expand All @@ -78,12 +116,13 @@ typedef enum {
MSG_PS_IGNORE_PREDICTION = BIT(5), // mutually exclusive with IGNORE_VIEWANGLES
MSG_PS_EXTENSIONS = BIT(6), // enable protocol extensions
MSG_PS_EXTENSIONS_2 = BIT(7), // enable more protocol extensions
MSG_PS_RERELEASE = BIT(8), // rerelease extensions: floating point coordinates,
MSG_PS_MOREBITS = BIT(8), // read more playerstate bits
MSG_PS_FORCE = BIT(9), // send even if unchanged (MVD stream only)
MSG_PS_REMOVE = BIT(10), // player is removed (MVD stream only)
MSG_PS_RERELEASE = BIT(11), // rerelease extensions: floating point coordinates,
// increased stats numbers,
// wider pm_time and pm_flags,
// different viewoffset, kick_angles, gunoffset, gunangles encodings
MSG_PS_FORCE = BIT(9), // send even if unchanged (MVD stream only)
MSG_PS_REMOVE = BIT(10), // player is removed (MVD stream only)
} msgPsFlags_t;

typedef enum {
Expand Down Expand Up @@ -171,10 +210,10 @@ void MSG_ReadDeltaUsercmd_Enhanced(const usercmd_t *from, usercmd_t *to);
int MSG_ParseEntityBits(uint64_t *bits, msgEsFlags_t flags);
void MSG_ParseDeltaEntity(entity_state_t *to, int number, uint64_t bits, msgEsFlags_t flags);
#if USE_CLIENT
void MSG_ParseDeltaPlayerstate_Default(const player_state_t *from, player_state_t *to, int flags, msgPsFlags_t psflags);
void MSG_ParseDeltaPlayerstate_Enhanced(const player_state_t *from, player_state_t *to, int flags, int extraflags, msgPsFlags_t psflags);
void MSG_ParseDeltaPlayerstate_Default(const player_state_t *from, player_state_t *to, player_fogchange_t *fog_change, int flags, msgPsFlags_t psflags);
void MSG_ParseDeltaPlayerstate_Enhanced(const player_state_t *from, player_state_t *to, player_fogchange_t *fog_change, int flags, int extraflags, msgPsFlags_t psflags);
#endif
void MSG_ParseDeltaPlayerstate_Packet(player_state_t *to, int flags, msgPsFlags_t psflags);
void MSG_ParseDeltaPlayerstate_Packet(player_state_t *to, player_fogchange_t *fog_change, int flags, msgPsFlags_t psflags);

#if USE_DEBUG
#if USE_CLIENT
Expand Down
39 changes: 33 additions & 6 deletions inc/common/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define PROTOCOL_VERSION_Q2PRO 36
#define PROTOCOL_VERSION_MVD 37 // not used for UDP connections
#define PROTOCOL_VERSION_RERELEASE 1038
#define PROTOCOL_VERSION_EXTENDED_OLD 3434 // used in demos
#define PROTOCOL_VERSION_EXTENDED 3435 // used in demos

#define PROTOCOL_VERSION_EXTENDED_MINIMUM 3434 // r2894
#define PROTOCOL_VERSION_EXTENDED_LIMITS_2 3435 // r3300
#define PROTOCOL_VERSION_EXTENDED_PLAYERFOG 3436 // r3579
#define PROTOCOL_VERSION_EXTENDED_CURRENT 3436 // r3579

#define PROTOCOL_VERSION_R1Q2_MINIMUM 1903 // b6377
#define PROTOCOL_VERSION_R1Q2_UCMD 1904 // b7387
Expand All @@ -49,13 +52,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define PROTOCOL_VERSION_Q2PRO_CINEMATICS 1023 // r2263
#define PROTOCOL_VERSION_Q2PRO_EXTENDED_LIMITS 1024 // r2894
#define PROTOCOL_VERSION_Q2PRO_EXTENDED_LIMITS_2 1025 // r3300
#define PROTOCOL_VERSION_Q2PRO_CURRENT 1025 // r3300
#define PROTOCOL_VERSION_Q2PRO_PLAYERFOG 1026 // r3579
#define PROTOCOL_VERSION_Q2PRO_CURRENT 1026 // r3579

#define PROTOCOL_VERSION_MVD_MINIMUM 2009 // r168
#define PROTOCOL_VERSION_MVD_DEFAULT 2010 // r177
#define PROTOCOL_VERSION_MVD_EXTENDED_LIMITS 2011 // r2894
#define PROTOCOL_VERSION_MVD_EXTENDED_LIMITS_2 2012 // r3300
#define PROTOCOL_VERSION_MVD_CURRENT 2012 // r3300
#define PROTOCOL_VERSION_MVD_PLAYERFOG 2013 // r3579
#define PROTOCOL_VERSION_MVD_CURRENT 2013 // r3579
#define PROTOCOL_VERSION_MVD_RERELEASE 3038

#define R1Q2_SUPPORTED(x) \
Expand All @@ -71,6 +76,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
(x) <= PROTOCOL_VERSION_MVD_CURRENT) \
|| ((x) == PROTOCOL_VERSION_MVD_RERELEASE))

#define EXTENDED_SUPPORTED(x) \
((x) >= PROTOCOL_VERSION_EXTENDED_MINIMUM && \
(x) <= PROTOCOL_VERSION_EXTENDED_CURRENT)

#define VALIDATE_CLIENTNUM(csr, x) \
((x) >= -1 && (x) < (csr)->max_edicts - 1)

Expand Down Expand Up @@ -244,6 +253,17 @@ typedef enum {

//==============================================

typedef enum {
Q2PRO_FOG_BIT_COLOR = BIT(0),
Q2PRO_FOG_BIT_DENSITY = BIT(1),
Q2PRO_FOG_BIT_HEIGHT_DENSITY = BIT(2),
Q2PRO_FOG_BIT_HEIGHT_FALLOFF = BIT(3),
Q2PRO_FOG_BIT_HEIGHT_START_COLOR = BIT(4),
Q2PRO_FOG_BIT_HEIGHT_END_COLOR = BIT(5),
Q2PRO_FOG_BIT_HEIGHT_START_DIST = BIT(6),
Q2PRO_FOG_BIT_HEIGHT_END_DIST = BIT(7),
} q2pro_fog_bits_t;

// player_state_t communication

#define PS_M_TYPE BIT(0)
Expand All @@ -262,7 +282,10 @@ typedef enum {
#define PS_WEAPONINDEX BIT(12)
#define PS_WEAPONFRAME BIT(13)
#define PS_RDFLAGS BIT(14)
#define PS_VIEWHEIGHT BIT(15) // re-release
#define PS_RR_VIEWHEIGHT BIT(15) // re-release
#define PS_MOREBITS BIT(15) // read one additional byte (q2pro)

#define PS_FOG BIT(16)

// R1Q2 protocol specific extra flags
#define EPS_GUNOFFSET BIT(0)
Expand Down Expand Up @@ -307,7 +330,11 @@ typedef enum {
#define PPS_GUNANGLES BIT(12)
#define PPS_RDFLAGS BIT(13)
#define PPS_STATS BIT(14)
#define PPS_REMOVE BIT(15)
#define PPS_MOREBITS BIT(15) // read one additional byte
// same as PPS_REMOVE for old demos!!!

#define PPS_REMOVE BIT(16)
#define PPS_FOG BIT(17)

// this is just a small hack to store inuse flag
// in a field left otherwise unused by MVD code
Expand Down
8 changes: 7 additions & 1 deletion inc/shared/game3.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,21 @@ typedef struct {
vec3_t gunoffset;
int gunindex;
int gunframe;
int reserved_1;
int reserved_2;

vec4_t blend; // rgba full screen effect
vec4_t damage_blend;

player_fog_t fog;
player_heightfog_t heightfog;

float fov; // horizontal field of view

int rdflags; // refdef flags

int reserved[4];
int reserved_3;
int reserved_4;

int16_t stats[MAX_STATS_NEW]; // fast status bar updates
} game3_player_state_new_t;
Expand Down
26 changes: 2 additions & 24 deletions src/client/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,7 @@ typedef struct {
entity_packed_t entities[MAX_EDICTS];
msgPsFlags_t psFlags;
msgEsFlags_t esFlags; // for writing
msgPsFlags_t psFlags;

sizebuf_t message;
} gtv;
Expand Down Expand Up @@ -808,7 +809,7 @@ void CL_SendCmd(void);
(MSG_ES_LONGSOLID | MSG_ES_UMASK | MSG_ES_BEAMORIGIN | MSG_ES_SHORTANGLES | MSG_ES_EXTENSIONS)

#define CL_ES_EXTENDED_MASK_2 (CL_ES_EXTENDED_MASK | MSG_ES_EXTENSIONS_2)
#define CL_PS_EXTENDED_MASK_2 (MSG_PS_EXTENSIONS | MSG_PS_EXTENSIONS_2)
#define CL_PS_EXTENDED_MASK_2 (MSG_PS_EXTENSIONS | MSG_PS_EXTENSIONS_2 | MSG_PS_MOREBITS)

typedef struct {
int type;
Expand Down Expand Up @@ -879,29 +880,6 @@ void CL_GetEntitySoundOrigin(unsigned entnum, vec3_t org);
extern int gun_frame;
extern qhandle_t gun_model;

typedef enum
{
// global fog
FOG_BIT_DENSITY = BIT(0),
FOG_BIT_R = BIT(1),
FOG_BIT_G = BIT(2),
FOG_BIT_B = BIT(3),
FOG_BIT_TIME = BIT(4), // if set, the transition takes place over N milliseconds

// height fog
FOG_BIT_HEIGHTFOG_FALLOFF = BIT(5),
FOG_BIT_HEIGHTFOG_DENSITY = BIT(6),
FOG_BIT_MORE_BITS = BIT(7), // read additional bit
FOG_BIT_HEIGHTFOG_START_R = BIT(8),
FOG_BIT_HEIGHTFOG_START_G = BIT(9),
FOG_BIT_HEIGHTFOG_START_B = BIT(10),
FOG_BIT_HEIGHTFOG_START_DIST= BIT(11),
FOG_BIT_HEIGHTFOG_END_R = BIT(12),
FOG_BIT_HEIGHTFOG_END_G = BIT(13),
FOG_BIT_HEIGHTFOG_END_B = BIT(14),
FOG_BIT_HEIGHTFOG_END_DIST = BIT(15)
} fog_bits_t;

void V_Init(void);
void V_Shutdown(void);
void V_RenderView(void);
Expand Down
4 changes: 2 additions & 2 deletions src/client/demo.c
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,7 @@ static void CL_Record_f(void)
if (cls.serverProtocol == PROTOCOL_VERSION_RERELEASE)
MSG_WriteLong(PROTOCOL_VERSION_RERELEASE);
else if (cl.csr.extended)
MSG_WriteLong(PROTOCOL_VERSION_EXTENDED);
MSG_WriteLong(PROTOCOL_VERSION_EXTENDED_CURRENT);
else
MSG_WriteLong(min(cls.serverProtocol, PROTOCOL_VERSION_DEFAULT));
MSG_WriteLong(cl.servercount);
Expand Down Expand Up @@ -1224,7 +1224,7 @@ bool CL_GetDemoInfo(const char *path, demoInfo_t *info)
int protocol = MSG_ReadLong();
if (protocol == PROTOCOL_VERSION_RERELEASE) {
// Don't futz anything
} else if (protocol == PROTOCOL_VERSION_EXTENDED || protocol == PROTOCOL_VERSION_EXTENDED_OLD) {
} else if (EXTENDED_SUPPORTED(protocol)) {
csr = &cs_remap_q2pro_new;
} else if (protocol < PROTOCOL_VERSION_OLD || protocol > PROTOCOL_VERSION_DEFAULT) {
goto fail;
Expand Down
13 changes: 6 additions & 7 deletions src/client/gtv.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,11 @@ static void build_gamestate(void)
}

// set protocol flags
cls.gtv.psFlags = MSG_PS_RERELEASE | MSG_PS_EXTENSIONS;
cls.gtv.esFlags = MSG_ES_UMASK | MSG_ES_BEAMORIGIN | (cl.esFlags & CL_ES_EXTENDED_MASK_2);
if (cl.csr.extended)
cls.gtv.esFlags |= MSG_ES_LONGSOLID | MSG_ES_SHORTANGLES | MSG_ES_EXTENSIONS;
cls.gtv.psFlags = MSG_PS_FORCE | MSG_PS_RERELEASE | (cl.psFlags & CL_PS_EXTENDED_MASK_2);

if (cls.gtv.psFlags & MSG_PS_EXTENSIONS_2)
cls.gtv.psFlags |= MSG_PS_MOREBITS;
}

static void emit_gamestate(void)
Expand Down Expand Up @@ -109,8 +110,7 @@ static void emit_gamestate(void)
MSG_WriteByte(0);

// send player state
MSG_WriteDeltaPlayerstate_Packet(NULL, &cls.gtv.ps,
cl.clientNum, cl.psFlags | MSG_PS_FORCE);
MSG_WriteDeltaPlayerstate_Packet(NULL, &cls.gtv.ps, cl.clientNum, cls.gtv.psFlags);
MSG_WriteByte(CLIENTNUM_NONE);

// send entity states
Expand Down Expand Up @@ -148,8 +148,7 @@ void CL_GTV_EmitFrame(void)
// send player state
MSG_PackPlayer(&newps, &cl.frame.ps, cl.psFlags);

MSG_WriteDeltaPlayerstate_Packet(&cls.gtv.ps, &newps,
cl.clientNum, cl.psFlags | MSG_PS_FORCE);
MSG_WriteDeltaPlayerstate_Packet(&cls.gtv.ps, &newps, cl.clientNum, cls.gtv.psFlags);

// shuffle current state to previous
cls.gtv.ps = newps;
Expand Down
29 changes: 23 additions & 6 deletions src/client/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,10 +322,14 @@ static void CL_ParseFrame(int extrabits)
}
}

player_fogchange_t fog_change = {0};
// parse playerstate
bits = MSG_ReadWord();
if (cl.psFlags & MSG_PS_MOREBITS && bits & PS_MOREBITS)
bits |= (uint32_t)MSG_ReadByte() << 16;

if (cls.serverProtocol > PROTOCOL_VERSION_DEFAULT) {
MSG_ParseDeltaPlayerstate_Enhanced(from, &frame.ps, bits, extraflags, cl.psFlags);
MSG_ParseDeltaPlayerstate_Enhanced(from, &frame.ps, &fog_change, bits, extraflags, cl.psFlags);
#if USE_DEBUG
if (cl_shownet->integer > 2 && (bits || extraflags)) {
Com_LPrintf(PRINT_DEVELOPER, " ");
Expand All @@ -351,7 +355,7 @@ static void CL_ParseFrame(int extrabits)
frame.clientNum = cl.clientNum;
}
} else {
MSG_ParseDeltaPlayerstate_Default(from, &frame.ps, bits, cl.psFlags);
MSG_ParseDeltaPlayerstate_Default(from, &frame.ps, &fog_change, bits, cl.psFlags);
#if USE_DEBUG
if (cl_shownet->integer > 2 && bits) {
Com_LPrintf(PRINT_DEVELOPER, " ");
Expand All @@ -362,6 +366,13 @@ static void CL_ParseFrame(int extrabits)
frame.clientNum = cl.clientNum;
}

if (fog_change.bits != 0) {
cl_fog_params_t fog_params;
fog_params.linear = fog_change.linear;
fog_params.height = fog_change.height;
V_FogParamsChanged(fog_change.bits, &fog_params, CL_FRAMETIME);
}

SHOWNET(2, "%3u:packetentities\n", msg_read.readcount);

// parse packetentities
Expand Down Expand Up @@ -561,6 +572,8 @@ static void read_q2pro_protocol_flags(void)
Com_DPrintf("Q2PRO protocol extensions v2 enabled\n");
cl.esFlags |= MSG_ES_EXTENSIONS_2;
cl.psFlags |= MSG_PS_EXTENSIONS_2;
if (cls.protocolVersion >= PROTOCOL_VERSION_Q2PRO_PLAYERFOG)
cl.psFlags |= MSG_PS_MOREBITS;
PmoveEnableExt(&cl.pmp);
}
cl.is_rerelease_game = (cls.serverProtocol == PROTOCOL_VERSION_RERELEASE) && (i & Q2PRO_PF_GAME3_COMPAT) == 0;
Expand Down Expand Up @@ -613,7 +626,7 @@ static void CL_ParseServerData(void)
if (protocol == PROTOCOL_VERSION_RERELEASE) {
// keep protocol as-is
cls.serverProtocol = protocol;
} else if (protocol == PROTOCOL_VERSION_EXTENDED || protocol == PROTOCOL_VERSION_EXTENDED_OLD) {
} else if (EXTENDED_SUPPORTED(protocol)) {
cl.csr = cs_remap_q2pro_new;
cls.serverProtocol = PROTOCOL_VERSION_DEFAULT;
} else if (protocol < PROTOCOL_VERSION_OLD || protocol > PROTOCOL_VERSION_DEFAULT) {
Expand Down Expand Up @@ -758,9 +771,13 @@ static void CL_ParseServerData(void)
cl.psFlags |= MSG_PS_EXTENSIONS;

// hack for demo playback
if (protocol == PROTOCOL_VERSION_EXTENDED) {
cl.esFlags |= MSG_ES_EXTENSIONS_2;
cl.psFlags |= MSG_PS_EXTENSIONS_2;
if (EXTENDED_SUPPORTED(protocol)) {
if (protocol >= PROTOCOL_VERSION_EXTENDED_LIMITS_2) {
cl.esFlags |= MSG_ES_EXTENSIONS_2;
cl.psFlags |= MSG_PS_EXTENSIONS_2;
}
if (protocol >= PROTOCOL_VERSION_EXTENDED_PLAYERFOG)
cl.psFlags |= MSG_PS_MOREBITS;
}

cl.pmp.extended_server_ver = cl.psFlags & MSG_PS_EXTENSIONS_2 ? 2 : 1;
Expand Down
Loading

0 comments on commit 78367cc

Please sign in to comment.