diff --git a/inc/common/q2proto_shared.h b/inc/common/q2proto_shared.h index 73b8370ff..d9530d077 100644 --- a/inc/common/q2proto_shared.h +++ b/inc/common/q2proto_shared.h @@ -31,3 +31,5 @@ extern q2protoio_ioarg_t default_q2protoio_ioarg; #if USE_CLIENT #define Q2PROTO_IOARG_CLIENT_READ _Q2PROTO_IOARG_DEFAULT #endif + +extern bool nonfatal_client_read_errors; diff --git a/src/client/demo.c b/src/client/demo.c index 46d90001c..73dcb4106 100644 --- a/src/client/demo.c +++ b/src/client/demo.c @@ -800,6 +800,8 @@ static void CL_PlayDemo_f(void) Con_Popup(true); SCR_UpdateScreen(); + q2proto_init_clientcontext(&cls.q2proto_ctx); + // parse the first message just read CL_ParseServerMessage(); @@ -1177,11 +1179,9 @@ static void CL_Seek_f(void) cls.demo.seeking = false; } -static void parse_info_string(demoInfo_t *info, int clientNum, int index, const cs_remap_t *csr) +static void parse_info_string(demoInfo_t *info, int clientNum, int index, const char* string, const cs_remap_t *csr) { - char string[MAX_QPATH], *p; - - MSG_ReadString(string, sizeof(string)); + char *p; if (index >= csr->playerskins && index < csr->playerskins + MAX_CLIENTS) { if (index - csr->playerskins == clientNum) { @@ -1213,6 +1213,8 @@ bool CL_GetDemoInfo(const char *path, demoInfo_t *info) return false; } + nonfatal_client_read_errors = true; + type = read_first_message(f); if (type < 0) { goto fail; @@ -1221,50 +1223,45 @@ bool CL_GetDemoInfo(const char *path, demoInfo_t *info) info->mvd = type; if (type == 0) { - if (MSG_ReadByte() != svc_serverdata) { + q2proto_clientcontext_t demo_context; + q2proto_init_clientcontext(&demo_context); + + q2proto_svc_message_t message; + if (q2proto_client_read(&demo_context, Q2PROTO_IOARG_CLIENT_READ, &message) != Q2P_ERR_SUCCESS) goto fail; - } - int protocol = MSG_ReadLong(); - if (protocol == PROTOCOL_VERSION_RERELEASE) { - // Don't futz anything - } else if (EXTENDED_SUPPORTED(protocol)) { - csr = &cs_remap_q2pro_new; - } else if (protocol < PROTOCOL_VERSION_OLD || protocol > PROTOCOL_VERSION_DEFAULT) { + + if (message.type != Q2P_SVC_SERVERDATA) { goto fail; } - MSG_ReadLong(); - MSG_ReadByte(); - MSG_ReadString(NULL, 0); - clientNum = MSG_ReadShort(); - MSG_ReadString(NULL, 0); - - if (protocol == PROTOCOL_VERSION_RERELEASE) { - MSG_ReadWord(); - MSG_ReadByte(); - int protocol_flags = MSG_ReadWord(); - if (protocol_flags & Q2PRO_PF_EXTENSIONS) - csr = &cs_remap_q2pro_new; - if (!(protocol_flags & Q2PRO_PF_GAME3_COMPAT)) - csr = &cs_remap_rerelease; - MSG_ReadByte(); + switch(demo_context.features.server_game_type) + { + case Q2PROTO_GAME_VANILLA: + break; + case Q2PROTO_GAME_Q2PRO_EXTENDED: + case Q2PROTO_GAME_Q2PRO_EXTENDED_V2: + csr = &cs_remap_q2pro_new; + break; + case Q2PROTO_GAME_RERELEASE: + csr = &cs_remap_rerelease; + break; } + clientNum = message.serverdata.clientnum; while (1) { - c = MSG_ReadByte(); - if (c == -1) { + q2proto_error_t err = q2proto_client_read(&demo_context, Q2PROTO_IOARG_CLIENT_READ, &message); + if (err == Q2P_ERR_NO_MORE_INPUT) { if (read_next_message(f) <= 0) { break; } continue; // parse new message } - if (c != svc_configstring) { + if (message.type != Q2P_SVC_CONFIGSTRING) { break; } - index = MSG_ReadWord(); - if (index < 0 || index >= csr->end) { + if (message.configstring.index < 0 || message.configstring.index >= csr->end) { goto fail; } - parse_info_string(info, clientNum, index, csr); + parse_info_string(info, clientNum, message.configstring.index, message.configstring.value.str, csr); } } else { c = MSG_ReadByte(); @@ -1293,13 +1290,16 @@ bool CL_GetDemoInfo(const char *path, demoInfo_t *info) if (index < 0 || index >= csr->end) { goto fail; } - parse_info_string(info, clientNum, index, csr); + char string[MAX_QPATH]; + MSG_ReadString(string, sizeof(string)); + parse_info_string(info, clientNum, index, string, csr); } } res = true; fail: FS_CloseFile(f); + nonfatal_client_read_errors = false; return res; } diff --git a/src/client/parse.c b/src/client/parse.c index 90c4dad6a..01b388508 100644 --- a/src/client/parse.c +++ b/src/client/parse.c @@ -618,13 +618,8 @@ static void CL_ParseServerData(const q2proto_svc_serverdata_t *serverdata) cls.serverProtocol, protocol); } // BIG HACK to let demos from release work with the 3.0x patch!!! - if (protocol == PROTOCOL_VERSION_RERELEASE) { - // keep protocol as-is - cls.serverProtocol = protocol; - } 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) { + if (!EXTENDED_SUPPORTED(protocol) && (protocol != PROTOCOL_VERSION_RERELEASE) + && (protocol < PROTOCOL_VERSION_OLD || protocol > PROTOCOL_VERSION_DEFAULT)) { Com_Error(ERR_DROP, "Demo uses unsupported protocol version %d.", protocol); } else { cls.serverProtocol = protocol; @@ -767,7 +762,10 @@ static void CL_ParseServerData(const q2proto_svc_serverdata_t *serverdata) cl.pmp.flyhack = true; // fly hack is unconditionally enabled cl.pmp.flyfriction = 4; } else { - cls.protocolVersion = 0; + // Demo protocol, or vanilla + if (serverdata->q2pro.extensions) + cl.csr = cs_remap_q2pro_new; + cls.protocolVersion = serverdata->protocol_version; } if (cl.csr.extended) { diff --git a/src/common/q2proto-glue.c b/src/common/q2proto-glue.c index 3b22617e5..7badd361f 100644 --- a/src/common/q2proto-glue.c +++ b/src/common/q2proto-glue.c @@ -83,6 +83,8 @@ const void* q2protoio_read_raw(uintptr_t io_arg, size_t size, size_t* readcount) return io_read_data(io_arg, size, readcount); } +bool nonfatal_client_read_errors = false; + q2proto_error_t q2protoerr_client_read(uintptr_t io_arg, q2proto_error_t err, const char *msg, ...) { char buf[256]; @@ -92,7 +94,11 @@ q2proto_error_t q2protoerr_client_read(uintptr_t io_arg, q2proto_error_t err, co Q_vsnprintf(buf, sizeof(buf), msg, argptr); va_end(argptr); - Com_Error(ERR_DROP, "%s", buf); + if (nonfatal_client_read_errors) + Com_WPrintf("%s\n", buf); + else + Com_Error(ERR_DROP, "%s", buf); + return err; } #if Q2PROTO_SHOWNET