mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-05-03 07:50:58 +00:00
319 lines
No EOL
6.1 KiB
C
319 lines
No EOL
6.1 KiB
C
#include "m_alloc.h"
|
|
#include "i_system.h"
|
|
#include "d_proto.h"
|
|
#include "d_ticcmd.h"
|
|
#include "d_net.h"
|
|
#include "doomdef.h"
|
|
#include "doomstat.h"
|
|
#include "cmdlib.h"
|
|
#include "z_zone.h"
|
|
|
|
demoqueue_t DemoQueue[MAXPLAYERS];
|
|
|
|
|
|
char *ReadString (byte **stream)
|
|
{
|
|
char *string = *stream;
|
|
|
|
*stream += strlen (string) + 1;
|
|
return copystring (string);
|
|
}
|
|
|
|
int ReadByte (byte **stream)
|
|
{
|
|
byte v = **stream;
|
|
*stream += 1;
|
|
return v;
|
|
}
|
|
|
|
int ReadWord (byte **stream)
|
|
{
|
|
short v = (((*stream)[0]) << 8) | (((*stream)[1]));
|
|
*stream += 2;
|
|
return v;
|
|
}
|
|
|
|
int ReadLong (byte **stream)
|
|
{
|
|
int v = (((*stream)[0]) << 24) | (((*stream)[1]) << 16) | (((*stream)[2]) << 8) | (((*stream)[3]));
|
|
*stream += 4;
|
|
return v;
|
|
}
|
|
|
|
void WriteString (const char *string, byte **stream)
|
|
{
|
|
char *p = *stream;
|
|
|
|
while (*string) {
|
|
*p++ = *string++;
|
|
}
|
|
|
|
*p++ = 0;
|
|
*stream = p;
|
|
}
|
|
|
|
|
|
void WriteByte (byte v, byte **stream)
|
|
{
|
|
**stream = v;
|
|
*stream += 1;
|
|
}
|
|
|
|
void WriteWord (short v, byte **stream)
|
|
{
|
|
(*stream)[0] = v >> 8;
|
|
(*stream)[1] = v & 255;
|
|
*stream += 2;
|
|
}
|
|
|
|
void WriteLong (int v, byte **stream)
|
|
{
|
|
(*stream)[0] = v >> 24;
|
|
(*stream)[1] = (v >> 16) & 255;
|
|
(*stream)[2] = (v >> 8) & 255;
|
|
(*stream)[3] = v & 255;
|
|
*stream += 4;
|
|
}
|
|
|
|
// Returns the number of bytes read
|
|
int UnpackUserCmd (usercmd_t *ucmd, byte **stream)
|
|
{
|
|
byte *start = *stream;
|
|
byte flags;
|
|
byte flags2;
|
|
|
|
// make sure the ucmd is empty
|
|
memset (ucmd, 0, sizeof(usercmd_t));
|
|
|
|
flags = ReadByte (stream);
|
|
if (flags & UCMDF_MORE)
|
|
flags2 = ReadByte (stream);
|
|
else
|
|
flags2 = 0;
|
|
|
|
if (flags) {
|
|
if (flags & UCMDF_BUTTONS)
|
|
ucmd->buttons = ReadByte (stream);
|
|
if (flags & UCMDF_PITCH)
|
|
ucmd->pitch = ReadWord (stream);
|
|
if (flags & UCMDF_YAW)
|
|
ucmd->yaw = ReadWord (stream);
|
|
if (flags & UCMDF_FORWARDMOVE)
|
|
ucmd->forwardmove = ReadWord (stream);
|
|
if (flags & UCMDF_SIDEMOVE)
|
|
ucmd->sidemove = ReadWord (stream);
|
|
if (flags & UCMDF_UPMOVE)
|
|
ucmd->upmove = ReadWord (stream);
|
|
if (flags & UCMDF_IMPULSE)
|
|
ucmd->impulse = ReadByte (stream);
|
|
|
|
if (flags2) {
|
|
if (flags2 & UCMDF_ROLL)
|
|
ucmd->roll = ReadWord (stream);
|
|
if (flags2 & UCMDF_USE)
|
|
ucmd->use = ReadByte (stream);
|
|
}
|
|
}
|
|
|
|
return *stream - start;
|
|
}
|
|
|
|
// Returns the number of bytes written
|
|
int PackUserCmd (usercmd_t *ucmd, byte **stream)
|
|
{
|
|
byte flags = 0;
|
|
byte flags2 = 0;
|
|
byte *temp = *stream;
|
|
byte *start = *stream;
|
|
|
|
WriteByte (0, stream); // Make room for the packing bits
|
|
if (ucmd->roll || ucmd->use) {
|
|
flags |= UCMDF_MORE;
|
|
WriteByte (0, stream); // Make room for more packing bits
|
|
}
|
|
|
|
if (ucmd->buttons) {
|
|
flags |= UCMDF_BUTTONS;
|
|
WriteByte (ucmd->buttons, stream);
|
|
}
|
|
if (ucmd->pitch) {
|
|
flags |= UCMDF_PITCH;
|
|
WriteWord (ucmd->pitch, stream);
|
|
}
|
|
if (ucmd->yaw) {
|
|
flags |= UCMDF_YAW;
|
|
WriteWord (ucmd->yaw, stream);
|
|
}
|
|
if (ucmd->forwardmove) {
|
|
flags |= UCMDF_FORWARDMOVE;
|
|
WriteWord (ucmd->forwardmove, stream);
|
|
}
|
|
if (ucmd->sidemove) {
|
|
flags |= UCMDF_SIDEMOVE;
|
|
WriteWord (ucmd->sidemove, stream);
|
|
}
|
|
if (ucmd->upmove) {
|
|
flags |= UCMDF_UPMOVE;
|
|
WriteWord (ucmd->upmove, stream);
|
|
}
|
|
if (ucmd->impulse) {
|
|
flags |= UCMDF_IMPULSE;
|
|
WriteByte (ucmd->impulse, stream);
|
|
}
|
|
|
|
if (ucmd->roll) {
|
|
flags2 |= UCMDF_ROLL;
|
|
WriteWord (ucmd->roll, stream);
|
|
}
|
|
if (ucmd->use) {
|
|
flags2 |= UCMDF_USE;
|
|
WriteByte (ucmd->use, stream);
|
|
}
|
|
|
|
// Write the packing bits
|
|
WriteByte (flags, &temp);
|
|
if (flags2)
|
|
WriteByte (flags2, &temp);
|
|
|
|
return *stream - start;
|
|
}
|
|
|
|
int WriteUserCmdMessage (usercmd_t *ucmd, byte **stream)
|
|
{
|
|
WriteByte (DEM_USERCMD, stream);
|
|
return PackUserCmd (ucmd, stream) + 1;
|
|
}
|
|
|
|
|
|
int SkipTicCmd (byte **stream, int count)
|
|
{
|
|
int i;
|
|
byte *flow = *stream;
|
|
int skip;
|
|
int type;
|
|
BOOL moreticdata;
|
|
|
|
for (i = count; i > 0; i--) {
|
|
flow += 2; // Skip consistancy marker
|
|
|
|
moreticdata = true;
|
|
|
|
while (moreticdata) {
|
|
type = *flow++;
|
|
|
|
switch (type) {
|
|
case DEM_MUSICCHANGE:
|
|
case DEM_PRINT:
|
|
case DEM_CENTERPRINT:
|
|
case DEM_UINFCHANGED:
|
|
case DEM_SINFCHANGED:
|
|
case DEM_GIVECHEAT:
|
|
case DEM_CHANGEMAP:
|
|
skip = strlen (flow) + 1;
|
|
break;
|
|
|
|
case DEM_GENERICCHEAT:
|
|
case DEM_DROPPLAYER:
|
|
skip = 1;
|
|
break;
|
|
|
|
case DEM_SAY:
|
|
skip = 2 + strlen (flow + 1);
|
|
break;
|
|
|
|
case DEM_USERCMD:
|
|
moreticdata = false;
|
|
skip = 1;
|
|
if (*flow & UCMDF_BUTTONS) skip += 1;
|
|
if (*flow & UCMDF_PITCH) skip += 2;
|
|
if (*flow & UCMDF_YAW) skip += 2;
|
|
if (*flow & UCMDF_FORWARDMOVE) skip += 2;
|
|
if (*flow & UCMDF_SIDEMOVE) skip += 2;
|
|
if (*flow & UCMDF_UPMOVE) skip += 2;
|
|
if (*flow & UCMDF_IMPULSE) skip += 1;
|
|
|
|
if (*flow & UCMDF_MORE) {
|
|
flow++;
|
|
if (*flow & UCMDF_ROLL) skip += 2;
|
|
if (*flow & UCMDF_USE) skip += 1;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
// All other commands are assumed to have zero parameters
|
|
skip = 0;
|
|
break;
|
|
}
|
|
flow += skip;
|
|
}
|
|
}
|
|
|
|
skip = flow - *stream;
|
|
*stream = flow;
|
|
|
|
return skip;
|
|
}
|
|
|
|
void ReadTicCmd (ticcmd_t *tcmd, byte **stream, int player)
|
|
{
|
|
int type, queuelen;
|
|
byte *start;
|
|
|
|
tcmd->consistancy = ReadWord (stream);
|
|
|
|
start = *stream;
|
|
|
|
while ((type = ReadByte (stream)) != DEM_USERCMD)
|
|
Net_DoCommand (type, stream, player);
|
|
|
|
// Save special "ticcmds" for later saving to a demo
|
|
if (demorecording && ((queuelen = *stream - start - 1) > 0)) {
|
|
if (DemoQueue[player].queue)
|
|
Z_Free (DemoQueue[player].queue);
|
|
|
|
DemoQueue[player].queue = Z_Malloc (queuelen, PU_STATIC, NULL);
|
|
memcpy (DemoQueue[player].queue, start, queuelen);
|
|
DemoQueue[player].size = queuelen;
|
|
}
|
|
|
|
UnpackUserCmd (&tcmd->ucmd, stream);
|
|
}
|
|
|
|
|
|
byte *lenspot;
|
|
|
|
// Write the header of an IFF chunk and leave space
|
|
// for the length field.
|
|
void StartChunk (int id, byte **stream)
|
|
{
|
|
WriteLong (id, stream);
|
|
lenspot = *stream;
|
|
*stream += 4;
|
|
}
|
|
|
|
// Write the length field for the chunk and insert
|
|
// pad byte if the chunk is odd-sized.
|
|
void FinishChunk (byte **stream)
|
|
{
|
|
int len;
|
|
|
|
if (!lenspot)
|
|
return;
|
|
|
|
len = *stream - lenspot - 4;
|
|
WriteLong (len, &lenspot);
|
|
if (len & 1)
|
|
WriteByte (0, stream);
|
|
|
|
lenspot = NULL;
|
|
}
|
|
|
|
// Skip past an unknown chunk. *stream should be
|
|
// pointing to the chunk's length field.
|
|
void SkipChunk (byte **stream)
|
|
{
|
|
int len;
|
|
|
|
len = ReadLong (stream);
|
|
stream += len + (len & 1);
|
|
} |