mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-26 22:31:05 +00:00
Add demo format auto-detection.
nq now rejects anything that doesn't look like a .dem, and qw not only rejects anything that looks like neither a .qwd nor a .mvd, but even detects which one is being played by the contents rather than the file name (foo.mvd.gz would be mis-detected as a qwd!!).
This commit is contained in:
parent
dfc8f8bb20
commit
93e35d7ec0
2 changed files with 143 additions and 3 deletions
|
@ -35,6 +35,7 @@
|
||||||
# include <strings.h>
|
# include <strings.h>
|
||||||
#endif
|
#endif
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "QF/cmd.h"
|
#include "QF/cmd.h"
|
||||||
#include "QF/cvar.h"
|
#include "QF/cvar.h"
|
||||||
|
@ -374,6 +375,58 @@ CL_Record (const char *argv1, int track)
|
||||||
demo_start_recording (track);
|
demo_start_recording (track);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
demo_check_dem (void)
|
||||||
|
{
|
||||||
|
int c, ret = 0;
|
||||||
|
uint32_t len, bytes;
|
||||||
|
|
||||||
|
// .dem demo files begin with an ascii integer (possibly negative)
|
||||||
|
// representing the forced bgm track, followed by a newline
|
||||||
|
c = Qgetc (cls.demofile);
|
||||||
|
if (c == '-')
|
||||||
|
c = Qgetc (cls.demofile);
|
||||||
|
while (isdigit (c))
|
||||||
|
c = Qgetc (cls.demofile);
|
||||||
|
if (c != '\n')
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
// After the bgm track comes the packet length plus 3 floats for view
|
||||||
|
// angles (not included in the packet length)
|
||||||
|
Qread (cls.demofile, &len, sizeof (len));
|
||||||
|
len = LittleLong (len);
|
||||||
|
if (len > MAX_DEMMSG)
|
||||||
|
goto done;
|
||||||
|
Qseek (cls.demofile, 3 * 4, SEEK_CUR); // 3 * float (angles)
|
||||||
|
|
||||||
|
// Normally, svc_serverinfo is the first command in the packet, but some
|
||||||
|
// servers (eg, fitzquake) add in an svc_print command first. Allow
|
||||||
|
// multiple svc_print commands (but nothing else) before the svc_serverinfo
|
||||||
|
net_message->message->cursize = len;
|
||||||
|
bytes = Qread (cls.demofile, net_message->message->data, len);
|
||||||
|
if (bytes != len)
|
||||||
|
goto done;
|
||||||
|
MSG_BeginReading (net_message);
|
||||||
|
while (!ret) {
|
||||||
|
if (net_message->badread)
|
||||||
|
goto done;
|
||||||
|
c = MSG_ReadByte (net_message);
|
||||||
|
switch (c) {
|
||||||
|
case svc_print:
|
||||||
|
MSG_ReadString (net_message);
|
||||||
|
break;
|
||||||
|
case svc_serverinfo:
|
||||||
|
ret = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
Qseek (cls.demofile, 0, SEEK_SET);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
CL_StartDemo (void)
|
CL_StartDemo (void)
|
||||||
{
|
{
|
||||||
|
@ -396,6 +449,14 @@ CL_StartDemo (void)
|
||||||
dstring_delete (name);
|
dstring_delete (name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!demo_check_dem ()) {
|
||||||
|
Sys_Printf ("%s is not a valid .dem file.\n", name->str);
|
||||||
|
cls.demonum = -1; // stop demo loop
|
||||||
|
dstring_delete (name);
|
||||||
|
Qclose (cls.demofile);
|
||||||
|
cls.demofile = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
cls.demoplayback = true;
|
cls.demoplayback = true;
|
||||||
CL_SetState (ca_connected);
|
CL_SetState (ca_connected);
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#endif
|
#endif
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include "QF/cbuf.h"
|
#include "QF/cbuf.h"
|
||||||
#include "QF/cmd.h"
|
#include "QF/cmd.h"
|
||||||
|
@ -880,10 +881,80 @@ CL_Record (const char *argv1, int track)
|
||||||
demo_start_recording (track);
|
demo_start_recording (track);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint32_t
|
||||||
|
get_ulong (const byte *buf)
|
||||||
|
{
|
||||||
|
return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float
|
||||||
|
get_float (const byte *buf)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
uint32_t u;
|
||||||
|
float f;
|
||||||
|
} uf;
|
||||||
|
uf.u = get_ulong (buf);
|
||||||
|
return uf.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
demo_check_qwd_mvd (void)
|
||||||
|
{
|
||||||
|
byte buf[22];
|
||||||
|
size_t bytes;
|
||||||
|
int c, ret = 0;
|
||||||
|
float f;
|
||||||
|
uint32_t u;
|
||||||
|
|
||||||
|
bytes = Qread (cls.demofile, buf, sizeof (buf));
|
||||||
|
if (bytes != sizeof (buf))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if ((f = get_float (buf + 0)) >= 0 && !isinf (f) && !isnan (f)
|
||||||
|
&& buf[4] == dem_read && get_ulong (buf + 5) <= MAX_DEMMSG
|
||||||
|
&& get_ulong (buf + 9) == 1 && get_ulong (buf + 13) == 1
|
||||||
|
&& buf[17] == svc_serverdata
|
||||||
|
&& (u = get_ulong (buf + 18)) >= 26 && u <= PROTOCOL_VERSION) {
|
||||||
|
ret = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (buf[0] != 0 || (buf[1] != dem_read && buf[1] != dem_all)
|
||||||
|
|| (u = get_ulong (buf + 2)) > MAX_DEMMSG)
|
||||||
|
goto done;
|
||||||
|
Qseek (cls.demofile, 6, SEEK_SET);
|
||||||
|
net_message->message->cursize = u;
|
||||||
|
bytes = Qread (cls.demofile, net_message->message->data, u);
|
||||||
|
if (bytes != u)
|
||||||
|
goto done;
|
||||||
|
MSG_BeginReading (net_message);
|
||||||
|
while (!ret) {
|
||||||
|
if (net_message->badread)
|
||||||
|
goto done;
|
||||||
|
c = MSG_ReadByte (net_message);
|
||||||
|
switch (c) {
|
||||||
|
case svc_print:
|
||||||
|
MSG_ReadString (net_message);
|
||||||
|
break;
|
||||||
|
case svc_serverdata:
|
||||||
|
if (MSG_ReadLong (net_message) != PROTOCOL_VERSION)
|
||||||
|
goto done;
|
||||||
|
ret = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
Qseek (cls.demofile, 0, SEEK_SET);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
CL_StartDemo (void)
|
CL_StartDemo (void)
|
||||||
{
|
{
|
||||||
dstring_t *name;
|
dstring_t *name;
|
||||||
|
int type;
|
||||||
|
|
||||||
// open the demo file
|
// open the demo file
|
||||||
name = dstring_strdup (demoname);
|
name = dstring_strdup (demoname);
|
||||||
|
@ -897,16 +968,24 @@ CL_StartDemo (void)
|
||||||
dstring_delete (name);
|
dstring_delete (name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!(type = demo_check_qwd_mvd ())) {
|
||||||
|
Sys_Printf ("%s is not a valid .qwd or .mvd file.\n", name->str);
|
||||||
|
cls.demonum = -1; // stop demo loop
|
||||||
|
dstring_delete (name);
|
||||||
|
Qclose (cls.demofile);
|
||||||
|
cls.demofile = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
cls.demoplayback = true;
|
cls.demoplayback = true;
|
||||||
key_game_target = IMT_DEMO;
|
key_game_target = IMT_DEMO;
|
||||||
Key_SetKeyDest (key_game);
|
Key_SetKeyDest (key_game);
|
||||||
net_blocksend = 1;
|
net_blocksend = 1;
|
||||||
if (strequal (QFS_FileExtension (name->str), ".mvd")) {
|
if (type == 2) {
|
||||||
cls.demoplayback2 = true;
|
cls.demoplayback2 = true;
|
||||||
Sys_Printf ("mvd\n");
|
Sys_MaskPrintf (SYS_DEV, "mvd\n");
|
||||||
} else {
|
} else {
|
||||||
Sys_Printf ("qwd\n");
|
Sys_MaskPrintf (SYS_DEV, "qwd\n");
|
||||||
}
|
}
|
||||||
CL_SetState (ca_demostart);
|
CL_SetState (ca_demostart);
|
||||||
Netchan_Setup (&cls.netchan, net_from, 0, NC_QPORT_SEND);
|
Netchan_Setup (&cls.netchan, net_from, 0, NC_QPORT_SEND);
|
||||||
|
|
Loading…
Reference in a new issue