Added demo writer interface, restructure
This commit is contained in:
parent
9834880bc5
commit
78de8690ab
|
@ -1,90 +1,100 @@
|
|||
|
||||
#include "demofile.h"
|
||||
#include "demofilebitbuf.h"
|
||||
#include "netmessages.h"
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
#include "idemowriter.h"
|
||||
#include "demoreader.h"
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
void ParsePacket(const std::vector<unsigned char>& packet)
|
||||
std::string GetExtension(const std::string& filename)
|
||||
{
|
||||
assert(packet.size() <= NET_MAX_PAYLOAD);
|
||||
CBitRead bitbuf(packet.data(), packet.size());
|
||||
while (bitbuf.GetNumBitsLeft() >= NETMSG_TYPE_BITS)
|
||||
size_t index = filename.find_last_of(".");
|
||||
if (index != std::string::npos)
|
||||
{
|
||||
uint32 typeId = bitbuf.ReadUBitLong(NETMSG_TYPE_BITS);
|
||||
printf("%i\n", typeId);
|
||||
ProcessNetMsg(typeId, bitbuf);
|
||||
return filename.substr(index + 1);
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
void ParseDemoSequence(const std::vector<unsigned char>& sequenceData)
|
||||
enum class FileType
|
||||
{
|
||||
unsigned char cmd;
|
||||
int32 tick;
|
||||
int32 sequenceInfo1;
|
||||
int32 sequenceInfo2;
|
||||
democmdinfo_t cmdInfo;
|
||||
std::vector<unsigned char> buffer;
|
||||
None,
|
||||
Dem,
|
||||
Json
|
||||
};
|
||||
|
||||
DemoSequenceReader reader(sequenceData);
|
||||
for (;;)
|
||||
FileType GetFileType(const std::string& filename)
|
||||
{
|
||||
std::string ext = GetExtension(filename);
|
||||
if (ext == "dem")
|
||||
{
|
||||
reader.ReadCmdHeader(cmd, tick);
|
||||
switch (cmd)
|
||||
{
|
||||
case dem_signon:
|
||||
case dem_packet:
|
||||
reader.ReadCmdInfo(cmdInfo);
|
||||
reader.ReadSequenceInfo(sequenceInfo1, sequenceInfo2);
|
||||
assert(sequenceInfo1 == sequenceInfo2);
|
||||
reader.ReadRawData(buffer);
|
||||
ParsePacket(buffer);
|
||||
break;
|
||||
case dem_synctick:
|
||||
// nothing
|
||||
break;
|
||||
case dem_consolecmd:
|
||||
reader.ReadRawData(nullptr, 1024);
|
||||
break;
|
||||
case dem_usercmd:
|
||||
reader.ReadUserCmd(buffer, 256);
|
||||
break;
|
||||
case dem_datatables:
|
||||
// TODO: datatables
|
||||
reader.ReadRawData(nullptr, 64*1024);
|
||||
break;
|
||||
case dem_stop:
|
||||
// TODO assert frame and tick numbers
|
||||
break;
|
||||
case dem_customdata:
|
||||
reader.ReadRawData(nullptr, 0);
|
||||
break;
|
||||
case dem_stringtables:
|
||||
reader.ReadRawData(nullptr, 0);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
return FileType::Dem;
|
||||
}
|
||||
if (ext == "json")
|
||||
{
|
||||
return FileType::Json;
|
||||
}
|
||||
return FileType::None;
|
||||
}
|
||||
|
||||
int main(const int argc, const char* argv[])
|
||||
{
|
||||
if (argc < 2)
|
||||
if (argc != 3)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s <in>.dem/json <out>.dem/json\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
CDemoFile demoFile;
|
||||
if (!demoFile.Open(argv[1]))
|
||||
std::string inputFile(argv[1]);
|
||||
std::string outputFile(argv[2]);
|
||||
|
||||
FileType inputType = GetFileType(inputFile);
|
||||
FileType outputType = GetFileType(outputFile);
|
||||
if (inputType == FileType::None)
|
||||
{
|
||||
fprintf(stderr, "Error: Bad type for input file\n");
|
||||
return -1;
|
||||
}
|
||||
if (outputType == FileType::None)
|
||||
{
|
||||
fprintf(stderr, "Error: Bad type for output file\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto demoHeader = demoFile.GetDemoHeader();
|
||||
ParseDemoSequence(demoFile.GetSignOnData());
|
||||
ParseDemoSequence(demoFile.GetDemoData());
|
||||
demoFile.Close();
|
||||
FILE* inputFp = fopen(inputFile.c_str(), "rb");
|
||||
if (!inputFp)
|
||||
{
|
||||
fprintf(stderr, "Error: Could not open input file\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
FILE* outputFp = fopen(outputFile.c_str(), "wb");
|
||||
if (!outputFp)
|
||||
{
|
||||
fprintf(stderr, "Error: Could not open input file\n");
|
||||
fclose(inputFp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
IDemoWriter* writer;
|
||||
if (outputType == FileType::Dem)
|
||||
{
|
||||
writer = IDemoWriter::CreateDemoWriter(outputFp);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer = IDemoWriter::CreateJsonWriter(outputFp);
|
||||
}
|
||||
|
||||
if (inputType == FileType::Dem)
|
||||
{
|
||||
DemoReader::ProcessDem(inputFp, writer);
|
||||
}
|
||||
else
|
||||
{
|
||||
DemoReader::ProcessJson(inputFp, writer);
|
||||
}
|
||||
fclose(inputFp);
|
||||
fclose(outputFp);
|
||||
|
||||
IDemoWriter::FreeDemoWriter(writer);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,260 +1,121 @@
|
|||
//====== Copyright (c) 2014, Valve Corporation, All rights reserved. ========//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
// THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//===========================================================================//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <cstring>
|
||||
#include <assert.h>
|
||||
#include "demofile.h"
|
||||
#include "demotypes.h"
|
||||
#include <cassert>
|
||||
|
||||
DemoSequenceReader::DemoSequenceReader(const std::vector<unsigned char>& sequenceData):
|
||||
m_sequenceData(sequenceData),
|
||||
m_dataReadOffset(0)
|
||||
// DemoFileReader
|
||||
|
||||
DemoFileReader::DemoFileReader(FILE* fp):
|
||||
m_demoFp(fp)
|
||||
{
|
||||
}
|
||||
|
||||
int32 DemoSequenceReader::ReadRawData(char *buffer, int32 length)
|
||||
int32_t DemoFileReader::ReadRawData(uint8_t* buffer, int32_t length)
|
||||
{
|
||||
if (m_sequenceData.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
FILE* fp = m_demoFp;
|
||||
|
||||
const unsigned char* sequenceData = m_sequenceData.data();
|
||||
size_t currentReadOffset = m_dataReadOffset;
|
||||
|
||||
// read length of data block
|
||||
const int32 size = *reinterpret_cast<const int32*>(sequenceData + currentReadOffset);
|
||||
currentReadOffset += sizeof(int32);
|
||||
int32_t size;
|
||||
fread(&size, sizeof(int32_t), 1, fp);
|
||||
|
||||
if (buffer && (length < size))
|
||||
{
|
||||
fprintf(stderr, "CDemoFile::ReadRawData: buffer overflow (%i).\n", size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
// read data into buffer
|
||||
memcpy(buffer, sequenceData + currentReadOffset, size);
|
||||
}
|
||||
currentReadOffset += size;
|
||||
|
||||
m_dataReadOffset = currentReadOffset;
|
||||
return size;
|
||||
}
|
||||
|
||||
bool DemoSequenceReader::ReadRawData(std::vector<unsigned char>& buf,
|
||||
const int32 maxReadSize /*= MAX_READ_SIZE*/)
|
||||
{
|
||||
if (m_sequenceData.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned char* sequenceData = m_sequenceData.data();
|
||||
size_t currentReadOffset = m_dataReadOffset;
|
||||
|
||||
// read length of data block
|
||||
const int32 size = *reinterpret_cast<const int32*>(sequenceData + currentReadOffset);
|
||||
currentReadOffset += sizeof(int32);
|
||||
|
||||
if (size < 0)
|
||||
{
|
||||
fprintf(stderr, "DemoSequenceReader::ReadRawData: invalid size (%i).\n", size);
|
||||
return false;
|
||||
}
|
||||
if (maxReadSize < 0 || size > maxReadSize)
|
||||
{
|
||||
fprintf(stderr, "DemoSequenceReader::ReadRawData: invalid size (%i) with max (%i).\n", size, maxReadSize);
|
||||
return false;
|
||||
}
|
||||
|
||||
buf.resize(size);
|
||||
|
||||
// read data into buffer
|
||||
memcpy(buf.data(), sequenceData + currentReadOffset, size);
|
||||
currentReadOffset += size;
|
||||
|
||||
m_dataReadOffset = currentReadOffset;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DemoSequenceReader::ReadSequenceInfo(int32 &nSeqNrIn, int32 &nSeqNrOut)
|
||||
{
|
||||
if (m_sequenceData.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const unsigned char* sequenceData = m_sequenceData.data();
|
||||
size_t currentReadOffset = m_dataReadOffset;
|
||||
|
||||
nSeqNrIn = *reinterpret_cast<const int32*>(sequenceData + currentReadOffset);
|
||||
currentReadOffset += sizeof(int32);
|
||||
nSeqNrOut = *reinterpret_cast<const int32*>(sequenceData + currentReadOffset);
|
||||
currentReadOffset += sizeof(int32);
|
||||
|
||||
m_dataReadOffset = currentReadOffset;
|
||||
}
|
||||
|
||||
void DemoSequenceReader::ReadCmdInfo(democmdinfo_t& info)
|
||||
{
|
||||
if (m_sequenceData.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
size_t currentReadOffset = m_dataReadOffset;
|
||||
|
||||
memcpy(&info, m_sequenceData.data() + currentReadOffset, sizeof(democmdinfo_t));
|
||||
currentReadOffset += sizeof(democmdinfo_t);
|
||||
|
||||
m_dataReadOffset = currentReadOffset;
|
||||
}
|
||||
|
||||
void DemoSequenceReader::ReadCmdHeader(unsigned char& cmd, int32& tick)
|
||||
{
|
||||
if (m_sequenceData.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const unsigned char* sequenceData = m_sequenceData.data();
|
||||
size_t currentReadOffset = m_dataReadOffset;
|
||||
|
||||
// Read the command
|
||||
cmd = sequenceData[currentReadOffset];
|
||||
currentReadOffset += sizeof(unsigned char);
|
||||
|
||||
if (cmd > 0)
|
||||
{
|
||||
assert(cmd <= dem_lastcmd);
|
||||
|
||||
// Read the timestamp
|
||||
tick = *reinterpret_cast<const int32*>(sequenceData + currentReadOffset);
|
||||
currentReadOffset += sizeof(int32);
|
||||
fread(buffer, 1, size, fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
fseek(fp, size, SEEK_CUR);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void DemoFileReader::ReadSequenceInfo(int32_t& seqNum1, int32_t& seqNum2)
|
||||
{
|
||||
FILE* fp = m_demoFp;
|
||||
fread(&seqNum1, sizeof(int32_t), 1, fp);
|
||||
fread(&seqNum2, sizeof(int32_t), 1, fp);
|
||||
}
|
||||
|
||||
void DemoFileReader::ReadCmdInfo(democmdinfo_t& info)
|
||||
{
|
||||
fread(&info, sizeof(democmdinfo_t), 1, m_demoFp);
|
||||
}
|
||||
|
||||
void DemoFileReader::ReadCmdHeader(unsigned char& cmd, int32_t& tick)
|
||||
{
|
||||
FILE* fp = m_demoFp;
|
||||
fread(&cmd, sizeof(unsigned char), 1, fp);
|
||||
fread(&tick, sizeof(int32_t), 1, fp);
|
||||
if (cmd >= 0)
|
||||
{
|
||||
assert(cmd <= dem_lastcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "CDemoFile::ReadCmdHeader: Missing end tag in demo file.\n");
|
||||
cmd = dem_stop;
|
||||
}
|
||||
m_dataReadOffset = currentReadOffset;
|
||||
}
|
||||
|
||||
int32 DemoSequenceReader::ReadUserCmd(std::vector<unsigned char>& buf,
|
||||
const int32 maxReadSize /*= MAX_READ_SIZE*/)
|
||||
int32_t DemoFileReader::ReadUserCmd(uint8_t* buffer, int32_t length)
|
||||
{
|
||||
if (m_sequenceData.empty())
|
||||
int32_t sequenceNum;
|
||||
fread(&sequenceNum, sizeof(int32_t), 1, m_demoFp);
|
||||
if (ReadRawData(buffer, length) < 0)
|
||||
{
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int32 outgoing_sequence = *reinterpret_cast<const int32*>(m_sequenceData.data() + m_dataReadOffset);
|
||||
m_dataReadOffset += sizeof(int32);
|
||||
|
||||
if (!ReadRawData(buf, maxReadSize))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return outgoing_sequence;
|
||||
return sequenceNum;
|
||||
}
|
||||
|
||||
CDemoFile::CDemoFile():
|
||||
m_DemoHeader()
|
||||
// DemoFileWriter
|
||||
|
||||
DemoFileWriter::DemoFileWriter(FILE* fp) :
|
||||
m_demoFp(fp)
|
||||
{
|
||||
}
|
||||
|
||||
CDemoFile::~CDemoFile()
|
||||
void DemoFileWriter::WriteDemoHeader(const demoheader_t& header)
|
||||
{
|
||||
Close();
|
||||
fwrite(&header, sizeof(demoheader_t), 1, m_demoFp);
|
||||
}
|
||||
|
||||
bool CDemoFile::Open( const char *name )
|
||||
void DemoFileReader::ReadDemoHeader(demoheader_t& header)
|
||||
{
|
||||
Close();
|
||||
|
||||
FILE *fp = NULL;
|
||||
fp = fopen( name, "rb" );
|
||||
if( fp )
|
||||
{
|
||||
size_t Length;
|
||||
|
||||
fseek( fp, 0, SEEK_END );
|
||||
Length = ftell( fp );
|
||||
fseek( fp, 0, SEEK_SET );
|
||||
|
||||
if( Length < sizeof( m_DemoHeader ) )
|
||||
{
|
||||
fprintf( stderr, "CDemoFile::Open: file too small. %s.\n", name );
|
||||
fclose( fp );
|
||||
return false;
|
||||
}
|
||||
|
||||
fread( &m_DemoHeader, 1, sizeof( m_DemoHeader ), fp );
|
||||
Length -= sizeof( m_DemoHeader );
|
||||
|
||||
if ( strcmp ( m_DemoHeader.demofilestamp, DEMO_HEADER_ID ) )
|
||||
{
|
||||
fprintf(stderr, "CDemoFile::Open: %s has invalid demo header ID.\n", name);
|
||||
fclose( fp );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( m_DemoHeader.demoprotocol != DEMO_PROTOCOL )
|
||||
{
|
||||
fprintf( stderr, "CDemoFile::Open: demo file protocol %i invalid, expected version is %i \n", m_DemoHeader.demoprotocol, DEMO_PROTOCOL );
|
||||
fclose( fp );
|
||||
return false;
|
||||
}
|
||||
|
||||
const int32 signOnLength = m_DemoHeader.signonlength;
|
||||
if (signOnLength > 0)
|
||||
{
|
||||
m_signOnData.resize(signOnLength);
|
||||
fread(&m_signOnData[0], 1, signOnLength, fp);
|
||||
Length -= signOnLength;
|
||||
}
|
||||
|
||||
m_fileBuffer.resize( Length );
|
||||
fread( &m_fileBuffer[ 0 ], 1, Length, fp );
|
||||
|
||||
fclose( fp );
|
||||
fp = NULL;
|
||||
}
|
||||
|
||||
if ( !m_fileBuffer.size() )
|
||||
{
|
||||
fprintf( stderr, "CDemoFile::Open: couldn't open file %s.\n", name );
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
fread(&header, sizeof(demoheader_t), 1, m_demoFp);
|
||||
}
|
||||
|
||||
void CDemoFile::Close()
|
||||
void DemoFileWriter::WriteRawData(const uint8_t* buffer, int32_t length)
|
||||
{
|
||||
m_signOnData.clear();
|
||||
m_fileBuffer.clear();
|
||||
FILE* fp = m_demoFp;
|
||||
fwrite(&length, sizeof(int32_t), 1, fp);
|
||||
fwrite(buffer, length, 1, fp);
|
||||
}
|
||||
|
||||
void DemoFileWriter::WriteSequenceInfo(int32_t seqNum1, int32_t seqNum2)
|
||||
{
|
||||
FILE* fp = m_demoFp;
|
||||
fwrite(&seqNum1, sizeof(int32_t), 1, fp);
|
||||
fwrite(&seqNum2, sizeof(int32_t), 1, fp);
|
||||
}
|
||||
|
||||
void DemoFileWriter::WriteCmdInfo(const democmdinfo_t& info)
|
||||
{
|
||||
fwrite(&info, sizeof(democmdinfo_t), 1, m_demoFp);
|
||||
}
|
||||
|
||||
void DemoFileWriter::WriteCmdHeader(unsigned char cmd, int32_t tick)
|
||||
{
|
||||
FILE* fp = m_demoFp;
|
||||
fwrite(&cmd, sizeof(unsigned char), 1, fp);
|
||||
fwrite(&tick, sizeof(int32_t), 1, fp);
|
||||
}
|
||||
|
||||
void DemoFileWriter::WriteUserCmd(int32_t sequenceNum, const uint8_t* buffer, int32_t length)
|
||||
{
|
||||
fwrite(&sequenceNum, sizeof(int32_t), 1, m_demoFp);
|
||||
WriteRawData(buffer, length);
|
||||
}
|
||||
|
|
|
@ -1,280 +1,40 @@
|
|||
//====== Copyright (c) 2014, Valve Corporation, All rights reserved. ========//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
// THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//===========================================================================//
|
||||
|
||||
#ifndef DEMOFILE_H
|
||||
#define DEMOFILE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include <inttypes.h>
|
||||
struct demoheader_t;
|
||||
struct democmdinfo_t;
|
||||
|
||||
#define DEMO_HEADER_ID "HL2DEMO"
|
||||
#define DEMO_PROTOCOL 3
|
||||
|
||||
#if !defined( MAX_OSPATH )
|
||||
#define MAX_OSPATH 260 // max length of a filesystem pathname
|
||||
#endif
|
||||
|
||||
typedef int32_t int32;
|
||||
typedef uint32_t uint32;
|
||||
typedef int64_t int64;
|
||||
typedef uint64_t uint64;
|
||||
typedef unsigned long CRC32_t;
|
||||
|
||||
// Demo messages
|
||||
enum
|
||||
{
|
||||
// it's a startup message, process as fast as possible
|
||||
dem_signon = 1,
|
||||
// it's a normal network packet that we stored off
|
||||
dem_packet,
|
||||
// sync client clock to demo tick
|
||||
dem_synctick,
|
||||
// console command
|
||||
dem_consolecmd,
|
||||
// user input command
|
||||
dem_usercmd,
|
||||
// network data tables
|
||||
dem_datatables,
|
||||
// end of time.
|
||||
dem_stop,
|
||||
// a blob of binary data understood by a callback function
|
||||
dem_customdata,
|
||||
|
||||
dem_stringtables,
|
||||
|
||||
// Last command
|
||||
dem_lastcmd = dem_stringtables
|
||||
};
|
||||
|
||||
struct demoheader_t
|
||||
{
|
||||
char demofilestamp[ 8 ]; // Should be HL2DEMO
|
||||
int32 demoprotocol; // Should be DEMO_PROTOCOL
|
||||
int32 networkprotocol; // Should be PROTOCOL_VERSION
|
||||
char servername[ MAX_OSPATH ]; // Name of server
|
||||
char clientname[ MAX_OSPATH ]; // Name of client who recorded the game
|
||||
char mapname[ MAX_OSPATH ]; // Name of map
|
||||
char gamedirectory[ MAX_OSPATH ]; // Name of game directory (com_gamedir)
|
||||
float playback_time; // Time of track
|
||||
int32 playback_ticks; // # of ticks in track
|
||||
int32 playback_frames; // # of frames in track
|
||||
int32 signonlength; // length of sigondata in bytes
|
||||
};
|
||||
|
||||
#define FDEMO_NORMAL 0
|
||||
#define FDEMO_USE_ORIGIN2 ( 1 << 0 )
|
||||
#define FDEMO_USE_ANGLES2 ( 1 << 1 )
|
||||
#define FDEMO_NOINTERP ( 1 << 2 ) // don't interpolate between this an last view
|
||||
|
||||
#define MAX_SPLITSCREEN_CLIENTS 1
|
||||
|
||||
struct QAngle
|
||||
{
|
||||
float x, y, z;
|
||||
void Init( void )
|
||||
{
|
||||
x = y = z = 0.0f;
|
||||
}
|
||||
void Init( float _x, float _y, float _z )
|
||||
{
|
||||
x = _x;
|
||||
y = _y;
|
||||
z = _z;
|
||||
}
|
||||
};
|
||||
struct Vector
|
||||
{
|
||||
float x, y, z;
|
||||
void Init( void )
|
||||
{
|
||||
x = y = z = 0.0f;
|
||||
}
|
||||
void Init( float _x, float _y, float _z )
|
||||
{
|
||||
x = _x;
|
||||
y = _y;
|
||||
z = _z;
|
||||
}
|
||||
};
|
||||
|
||||
struct democmdinfo_t
|
||||
{
|
||||
democmdinfo_t( void )
|
||||
{
|
||||
}
|
||||
|
||||
struct Split_t
|
||||
{
|
||||
Split_t( void )
|
||||
{
|
||||
flags = FDEMO_NORMAL;
|
||||
viewOrigin.Init();
|
||||
viewAngles.Init();
|
||||
localViewAngles.Init();
|
||||
|
||||
// Resampled origin/angles
|
||||
viewOrigin2.Init();
|
||||
viewAngles2.Init();
|
||||
localViewAngles2.Init();
|
||||
}
|
||||
|
||||
Split_t& operator=( const Split_t& src )
|
||||
{
|
||||
if ( this == &src )
|
||||
return *this;
|
||||
|
||||
flags = src.flags;
|
||||
viewOrigin = src.viewOrigin;
|
||||
viewAngles = src.viewAngles;
|
||||
localViewAngles = src.localViewAngles;
|
||||
viewOrigin2 = src.viewOrigin2;
|
||||
viewAngles2 = src.viewAngles2;
|
||||
localViewAngles2 = src.localViewAngles2;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Vector& GetViewOrigin( void )
|
||||
{
|
||||
if ( flags & FDEMO_USE_ORIGIN2 )
|
||||
{
|
||||
return viewOrigin2;
|
||||
}
|
||||
return viewOrigin;
|
||||
}
|
||||
|
||||
const QAngle& GetViewAngles( void )
|
||||
{
|
||||
if ( flags & FDEMO_USE_ANGLES2 )
|
||||
{
|
||||
return viewAngles2;
|
||||
}
|
||||
return viewAngles;
|
||||
}
|
||||
const QAngle& GetLocalViewAngles( void )
|
||||
{
|
||||
if ( flags & FDEMO_USE_ANGLES2 )
|
||||
{
|
||||
return localViewAngles2;
|
||||
}
|
||||
return localViewAngles;
|
||||
}
|
||||
|
||||
void Reset( void )
|
||||
{
|
||||
flags = 0;
|
||||
viewOrigin2 = viewOrigin;
|
||||
viewAngles2 = viewAngles;
|
||||
localViewAngles2 = localViewAngles;
|
||||
}
|
||||
|
||||
int32 flags;
|
||||
|
||||
// original origin/viewangles
|
||||
Vector viewOrigin;
|
||||
QAngle viewAngles;
|
||||
QAngle localViewAngles;
|
||||
|
||||
// Resampled origin/viewangles
|
||||
Vector viewOrigin2;
|
||||
QAngle viewAngles2;
|
||||
QAngle localViewAngles2;
|
||||
};
|
||||
|
||||
void Reset( void )
|
||||
{
|
||||
for ( int i = 0; i < MAX_SPLITSCREEN_CLIENTS; ++i )
|
||||
{
|
||||
u[ i ].Reset();
|
||||
}
|
||||
}
|
||||
|
||||
Split_t u[ MAX_SPLITSCREEN_CLIENTS ];
|
||||
};
|
||||
|
||||
class DemoSequenceReader
|
||||
{
|
||||
static const int32 MAX_READ_SIZE = 1024 * 1024;
|
||||
public:
|
||||
DemoSequenceReader(const std::vector<unsigned char>& sequenceData);
|
||||
|
||||
int32 ReadRawData(char *buffer, int32 length);
|
||||
|
||||
bool ReadRawData(std::vector<unsigned char>& buf, const int32 maxReadSize = MAX_READ_SIZE);
|
||||
|
||||
void ReadSequenceInfo(int32 &nSeqNrIn, int32 &nSeqNrOutAck);
|
||||
|
||||
void ReadCmdInfo(democmdinfo_t& info);
|
||||
|
||||
void ReadCmdHeader(unsigned char &cmd, int32 &tick);
|
||||
|
||||
int32 ReadUserCmd(std::vector<unsigned char>& buf, const int32 maxReadSize = MAX_READ_SIZE);
|
||||
|
||||
private:
|
||||
const std::vector<unsigned char>& m_sequenceData;
|
||||
size_t m_dataReadOffset;
|
||||
};
|
||||
|
||||
class CDemoFile
|
||||
class DemoFileReader
|
||||
{
|
||||
public:
|
||||
CDemoFile();
|
||||
~CDemoFile();
|
||||
DemoFileReader(FILE* fp);
|
||||
|
||||
bool Open( const char *name );
|
||||
void Close();
|
||||
|
||||
const demoheader_t *GetDemoHeader() const;
|
||||
|
||||
const std::vector<unsigned char>& GetSignOnData() const;
|
||||
const std::vector<unsigned char>& GetDemoData() const;
|
||||
void ReadDemoHeader(demoheader_t& header);
|
||||
int32_t ReadRawData(uint8_t* buffer, int32_t length);
|
||||
void ReadSequenceInfo(int32_t& seqNum1, int32_t& seqNum2);
|
||||
void ReadCmdInfo(democmdinfo_t& info);
|
||||
void ReadCmdHeader(unsigned char& cmd, int32_t& tick);
|
||||
int32_t ReadUserCmd(uint8_t* buffer, int32_t length);
|
||||
|
||||
private:
|
||||
demoheader_t m_DemoHeader; //general demo info
|
||||
|
||||
std::vector<unsigned char> m_signOnData;
|
||||
std::vector<unsigned char> m_fileBuffer;
|
||||
FILE* m_demoFp;
|
||||
};
|
||||
|
||||
inline const demoheader_t *CDemoFile::GetDemoHeader() const
|
||||
class DemoFileWriter
|
||||
{
|
||||
return &m_DemoHeader;
|
||||
}
|
||||
public:
|
||||
DemoFileWriter(FILE* fp);
|
||||
|
||||
inline const std::vector<unsigned char>& CDemoFile::GetSignOnData() const
|
||||
{
|
||||
return m_signOnData;
|
||||
}
|
||||
void WriteDemoHeader(const demoheader_t& header);
|
||||
void WriteRawData(const uint8_t* buffer, int32_t length);
|
||||
void WriteSequenceInfo(int32_t seqNum1, int32_t seqNum2);
|
||||
void WriteCmdInfo(const democmdinfo_t& info);
|
||||
void WriteCmdHeader(unsigned char cmd, int32_t tick);
|
||||
void WriteUserCmd(int32_t sequenceNum, const uint8_t* buffer, int32_t length);
|
||||
|
||||
inline const std::vector<unsigned char>& CDemoFile::GetDemoData() const
|
||||
{
|
||||
return m_fileBuffer;
|
||||
}
|
||||
|
||||
#endif // DEMOFILE_H
|
||||
private:
|
||||
FILE* m_demoFp;
|
||||
};
|
||||
|
|
|
@ -1,691 +0,0 @@
|
|||
//====== Copyright (c) 2014, Valve Corporation, All rights reserved. ========//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
// THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//===========================================================================//
|
||||
|
||||
#include <assert.h>
|
||||
#include "demofilebitbuf.h"
|
||||
|
||||
const uint32 CBitRead::s_nMaskTable[33] = {
|
||||
0,
|
||||
( 1 << 1 ) - 1,
|
||||
( 1 << 2 ) - 1,
|
||||
( 1 << 3 ) - 1,
|
||||
( 1 << 4 ) - 1,
|
||||
( 1 << 5 ) - 1,
|
||||
( 1 << 6 ) - 1,
|
||||
( 1 << 7 ) - 1,
|
||||
( 1 << 8 ) - 1,
|
||||
( 1 << 9 ) - 1,
|
||||
( 1 << 10 ) - 1,
|
||||
( 1 << 11 ) - 1,
|
||||
( 1 << 12 ) - 1,
|
||||
( 1 << 13 ) - 1,
|
||||
( 1 << 14 ) - 1,
|
||||
( 1 << 15 ) - 1,
|
||||
( 1 << 16 ) - 1,
|
||||
( 1 << 17 ) - 1,
|
||||
( 1 << 18 ) - 1,
|
||||
( 1 << 19 ) - 1,
|
||||
( 1 << 20 ) - 1,
|
||||
( 1 << 21 ) - 1,
|
||||
( 1 << 22 ) - 1,
|
||||
( 1 << 23 ) - 1,
|
||||
( 1 << 24 ) - 1,
|
||||
( 1 << 25 ) - 1,
|
||||
( 1 << 26 ) - 1,
|
||||
( 1 << 27 ) - 1,
|
||||
( 1 << 28 ) - 1,
|
||||
( 1 << 29 ) - 1,
|
||||
( 1 << 30 ) - 1,
|
||||
0x7fffffff,
|
||||
0xffffffff,
|
||||
};
|
||||
|
||||
int CBitRead::GetNumBitsRead( void ) const
|
||||
{
|
||||
if ( ! m_pData ) // pesky null ptr bitbufs. these happen.
|
||||
return 0;
|
||||
|
||||
int nCurOfs = ( ( int( m_pDataIn ) - int( m_pData ) ) / 4 ) - 1;
|
||||
nCurOfs *= 32;
|
||||
nCurOfs += ( 32 - m_nBitsAvail );
|
||||
int nAdjust = 8 * ( m_nDataBytes & 3 );
|
||||
return MIN( nCurOfs + nAdjust, m_nDataBits );
|
||||
}
|
||||
|
||||
int CBitRead::GetNumBytesRead( void ) const
|
||||
{
|
||||
return ( ( GetNumBitsRead() + 7 ) >> 3 );
|
||||
}
|
||||
|
||||
void CBitRead::GrabNextDWord( bool bOverFlowImmediately )
|
||||
{
|
||||
if ( m_pDataIn == m_pBufferEnd )
|
||||
{
|
||||
m_nBitsAvail = 1; // so that next read will run out of words
|
||||
m_nInBufWord = 0;
|
||||
m_pDataIn++; // so seek count increments like old
|
||||
if ( bOverFlowImmediately )
|
||||
{
|
||||
SetOverflowFlag();
|
||||
}
|
||||
}
|
||||
else
|
||||
if ( m_pDataIn > m_pBufferEnd )
|
||||
{
|
||||
SetOverflowFlag();
|
||||
m_nInBufWord = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert( reinterpret_cast< int >( m_pDataIn ) + 3 < reinterpret_cast< int >( m_pBufferEnd ) );
|
||||
m_nInBufWord = *( m_pDataIn++ );
|
||||
}
|
||||
}
|
||||
|
||||
void CBitRead::FetchNext( void )
|
||||
{
|
||||
m_nBitsAvail = 32;
|
||||
GrabNextDWord( false );
|
||||
}
|
||||
|
||||
int CBitRead::ReadOneBit( void )
|
||||
{
|
||||
int nRet = m_nInBufWord & 1;
|
||||
if ( --m_nBitsAvail == 0 )
|
||||
{
|
||||
FetchNext();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nInBufWord >>= 1;
|
||||
}
|
||||
return nRet;
|
||||
}
|
||||
|
||||
unsigned int CBitRead::ReadUBitLong( int numbits )
|
||||
{
|
||||
if ( m_nBitsAvail >= numbits )
|
||||
{
|
||||
unsigned int nRet = m_nInBufWord & s_nMaskTable[ numbits ];
|
||||
m_nBitsAvail -= numbits;
|
||||
if ( m_nBitsAvail )
|
||||
{
|
||||
m_nInBufWord >>= numbits;
|
||||
}
|
||||
else
|
||||
{
|
||||
FetchNext();
|
||||
}
|
||||
return nRet;
|
||||
}
|
||||
else
|
||||
{
|
||||
// need to merge words
|
||||
unsigned int nRet = m_nInBufWord;
|
||||
numbits -= m_nBitsAvail;
|
||||
GrabNextDWord( true );
|
||||
if ( m_bOverflow )
|
||||
return 0;
|
||||
nRet |= ( ( m_nInBufWord & s_nMaskTable[ numbits ] ) << m_nBitsAvail );
|
||||
m_nBitsAvail = 32 - numbits;
|
||||
m_nInBufWord >>= numbits;
|
||||
return nRet;
|
||||
}
|
||||
}
|
||||
|
||||
int CBitRead::ReadSBitLong( int numbits )
|
||||
{
|
||||
int nRet = ReadUBitLong( numbits );
|
||||
// sign extend
|
||||
return ( nRet << ( 32 - numbits ) ) >> ( 32 - numbits );
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4715) // disable warning on not all cases
|
||||
// returning a value. throwing default:
|
||||
// in measurably reduces perf in bit
|
||||
// packing benchmark
|
||||
#endif
|
||||
unsigned int CBitRead::ReadUBitVar( void )
|
||||
{
|
||||
unsigned int ret = ReadUBitLong( 6 );
|
||||
switch( ret & ( 16 | 32 ) )
|
||||
{
|
||||
case 16:
|
||||
ret = ( ret & 15 ) | ( ReadUBitLong( 4 ) << 4 );
|
||||
assert( ret >= 16);
|
||||
break;
|
||||
|
||||
case 32:
|
||||
ret = ( ret & 15 ) | ( ReadUBitLong( 8 ) << 4 );
|
||||
assert( ret >= 256);
|
||||
break;
|
||||
case 48:
|
||||
ret = ( ret & 15 ) | ( ReadUBitLong( 32 - 4 ) << 4 );
|
||||
assert( ret >= 4096 );
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
int CBitRead::ReadChar( void )
|
||||
{
|
||||
return ReadSBitLong( sizeof( char ) << 3 );
|
||||
}
|
||||
|
||||
int CBitRead::ReadByte( void )
|
||||
{
|
||||
return ReadUBitLong( sizeof( unsigned char ) << 3 );
|
||||
}
|
||||
|
||||
int CBitRead::ReadShort( void )
|
||||
{
|
||||
return ReadSBitLong( sizeof( short ) << 3 );
|
||||
}
|
||||
|
||||
int CBitRead::ReadWord( void )
|
||||
{
|
||||
return ReadUBitLong( sizeof( unsigned short ) << 3 );
|
||||
}
|
||||
|
||||
bool CBitRead::Seek( int nPosition )
|
||||
{
|
||||
bool bSucc = true;
|
||||
if ( nPosition < 0 || nPosition > m_nDataBits )
|
||||
{
|
||||
SetOverflowFlag();
|
||||
bSucc = false;
|
||||
nPosition = m_nDataBits;
|
||||
}
|
||||
int nHead = m_nDataBytes & 3; // non-multiple-of-4 bytes at head of buffer. We put the "round off"
|
||||
// at the head to make reading and detecting the end efficient.
|
||||
|
||||
int nByteOfs = nPosition / 8;
|
||||
if ( ( m_nDataBytes < 4 ) || ( nHead && ( nByteOfs < nHead ) ) )
|
||||
{
|
||||
// partial first dword
|
||||
unsigned char const *pPartial = ( unsigned char const *) m_pData;
|
||||
if ( m_pData )
|
||||
{
|
||||
m_nInBufWord = *( pPartial++ );
|
||||
if ( nHead > 1 )
|
||||
{
|
||||
m_nInBufWord |= ( *pPartial++ ) << 8;
|
||||
}
|
||||
if ( nHead > 2 )
|
||||
{
|
||||
m_nInBufWord |= ( *pPartial++ ) << 16;
|
||||
}
|
||||
}
|
||||
m_pDataIn = ( uint32 const * ) pPartial;
|
||||
m_nInBufWord >>= ( nPosition & 31 );
|
||||
m_nBitsAvail = ( nHead << 3 ) - ( nPosition & 31 );
|
||||
}
|
||||
else
|
||||
{
|
||||
int nAdjPosition = nPosition - ( nHead << 3 );
|
||||
m_pDataIn = reinterpret_cast< uint32 const * > ( reinterpret_cast< unsigned char const * >( m_pData ) + ( ( nAdjPosition / 32 ) << 2 ) + nHead );
|
||||
if ( m_pData )
|
||||
{
|
||||
m_nBitsAvail = 32;
|
||||
GrabNextDWord();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nInBufWord = 0;
|
||||
m_nBitsAvail = 1;
|
||||
}
|
||||
m_nInBufWord >>= ( nAdjPosition & 31 );
|
||||
m_nBitsAvail = MIN( m_nBitsAvail, 32 - ( nAdjPosition & 31 ) ); // in case grabnextdword overflowed
|
||||
}
|
||||
return bSucc;
|
||||
}
|
||||
|
||||
|
||||
void CBitRead::StartReading( const void *pData, int nBytes, int iStartBit, int nBits )
|
||||
{
|
||||
// Make sure it's dword aligned and padded.
|
||||
assert( ( ( unsigned long )pData & 3 ) == 0 );
|
||||
m_pData = ( uint32 * ) pData;
|
||||
m_pDataIn = m_pData;
|
||||
m_nDataBytes = nBytes;
|
||||
|
||||
if ( nBits == -1 )
|
||||
{
|
||||
m_nDataBits = nBytes << 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert( nBits <= nBytes * 8 );
|
||||
m_nDataBits = nBits;
|
||||
}
|
||||
m_bOverflow = false;
|
||||
m_pBufferEnd = reinterpret_cast< uint32 const * > ( reinterpret_cast< unsigned char const * >( m_pData ) + nBytes );
|
||||
if ( m_pData )
|
||||
{
|
||||
Seek( iStartBit );
|
||||
}
|
||||
}
|
||||
|
||||
bool CBitRead::ReadString( char *pStr, int maxLen, bool bLine, int *pOutNumChars )
|
||||
{
|
||||
assert( maxLen != 0 );
|
||||
|
||||
bool bTooSmall = false;
|
||||
int iChar = 0;
|
||||
while(1)
|
||||
{
|
||||
char val = ReadChar();
|
||||
if ( val == 0 )
|
||||
break;
|
||||
else if ( bLine && val == '\n' )
|
||||
break;
|
||||
|
||||
if ( iChar < ( maxLen - 1 ) )
|
||||
{
|
||||
pStr[ iChar ] = val;
|
||||
++iChar;
|
||||
}
|
||||
else
|
||||
{
|
||||
bTooSmall = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure it's null-terminated.
|
||||
assert( iChar < maxLen );
|
||||
pStr[ iChar ] = 0;
|
||||
|
||||
if ( pOutNumChars )
|
||||
{
|
||||
*pOutNumChars = iChar;
|
||||
}
|
||||
|
||||
return !IsOverflowed() && !bTooSmall;
|
||||
}
|
||||
|
||||
// Read 1-5 bytes in order to extract a 32-bit unsigned value from the
|
||||
// stream. 7 data bits are extracted from each byte with the 8th bit used
|
||||
// to indicate whether the loop should continue.
|
||||
// This allows variable size numbers to be stored with tolerable
|
||||
// efficiency. Numbers sizes that can be stored for various numbers of
|
||||
// encoded bits are:
|
||||
// 8-bits: 0-127
|
||||
// 16-bits: 128-16383
|
||||
// 24-bits: 16384-2097151
|
||||
// 32-bits: 2097152-268435455
|
||||
// 40-bits: 268435456-0xFFFFFFFF
|
||||
uint32 CBitRead::ReadVarInt32()
|
||||
{
|
||||
uint32 result = 0;
|
||||
int count = 0;
|
||||
uint32 b;
|
||||
|
||||
do
|
||||
{
|
||||
if ( count == bitbuf::kMaxVarint32Bytes )
|
||||
{
|
||||
return result;
|
||||
}
|
||||
b = ReadUBitLong( 8 );
|
||||
result |= ( b & 0x7F ) << ( 7 * count );
|
||||
++count;
|
||||
} while ( b & 0x80 );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64 CBitRead::ReadVarInt64()
|
||||
{
|
||||
uint64 result = 0;
|
||||
int count = 0;
|
||||
uint64 b;
|
||||
|
||||
do
|
||||
{
|
||||
if ( count == bitbuf::kMaxVarintBytes )
|
||||
{
|
||||
return result;
|
||||
}
|
||||
b = ReadUBitLong( 8 );
|
||||
result |= static_cast<uint64>(b & 0x7F) << (7 * count);
|
||||
++count;
|
||||
} while (b & 0x80);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CBitRead::ReadBits( void *pOutData, int nBits )
|
||||
{
|
||||
unsigned char *pOut = ( unsigned char* )pOutData;
|
||||
int nBitsLeft = nBits;
|
||||
|
||||
|
||||
// align output to dword boundary
|
||||
while( ( ( unsigned long )pOut & 3 ) != 0 && nBitsLeft >= 8 )
|
||||
{
|
||||
*pOut = ( unsigned char )ReadUBitLong( 8 );
|
||||
++pOut;
|
||||
nBitsLeft -= 8;
|
||||
}
|
||||
|
||||
// read dwords
|
||||
while ( nBitsLeft >= 32 )
|
||||
{
|
||||
*( ( unsigned long* )pOut ) = ReadUBitLong( 32 );
|
||||
pOut += sizeof( unsigned long );
|
||||
nBitsLeft -= 32;
|
||||
}
|
||||
|
||||
// read remaining bytes
|
||||
while ( nBitsLeft >= 8 )
|
||||
{
|
||||
*pOut = ReadUBitLong( 8 );
|
||||
++pOut;
|
||||
nBitsLeft -= 8;
|
||||
}
|
||||
|
||||
// read remaining bits
|
||||
if ( nBitsLeft )
|
||||
{
|
||||
*pOut = ReadUBitLong( nBitsLeft );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool CBitRead::ReadBytes( void *pOut, int nBytes )
|
||||
{
|
||||
ReadBits( pOut, nBytes << 3 );
|
||||
return !IsOverflowed();
|
||||
}
|
||||
|
||||
#define BITS_PER_INT 32
|
||||
inline int GetBitForBitnum( int bitNum )
|
||||
{
|
||||
static int bitsForBitnum[] =
|
||||
{
|
||||
( 1 << 0 ),
|
||||
( 1 << 1 ),
|
||||
( 1 << 2 ),
|
||||
( 1 << 3 ),
|
||||
( 1 << 4 ),
|
||||
( 1 << 5 ),
|
||||
( 1 << 6 ),
|
||||
( 1 << 7 ),
|
||||
( 1 << 8 ),
|
||||
( 1 << 9 ),
|
||||
( 1 << 10 ),
|
||||
( 1 << 11 ),
|
||||
( 1 << 12 ),
|
||||
( 1 << 13 ),
|
||||
( 1 << 14 ),
|
||||
( 1 << 15 ),
|
||||
( 1 << 16 ),
|
||||
( 1 << 17 ),
|
||||
( 1 << 18 ),
|
||||
( 1 << 19 ),
|
||||
( 1 << 20 ),
|
||||
( 1 << 21 ),
|
||||
( 1 << 22 ),
|
||||
( 1 << 23 ),
|
||||
( 1 << 24 ),
|
||||
( 1 << 25 ),
|
||||
( 1 << 26 ),
|
||||
( 1 << 27 ),
|
||||
( 1 << 28 ),
|
||||
( 1 << 29 ),
|
||||
( 1 << 30 ),
|
||||
( 1 << 31 ),
|
||||
};
|
||||
|
||||
return bitsForBitnum[ (bitNum) & (BITS_PER_INT-1) ];
|
||||
}
|
||||
|
||||
float CBitRead::ReadBitAngle( int numbits )
|
||||
{
|
||||
float shift = (float)( GetBitForBitnum(numbits) );
|
||||
|
||||
int i = ReadUBitLong( numbits );
|
||||
float fReturn = (float)i * (360.0f / shift);
|
||||
|
||||
return fReturn;
|
||||
}
|
||||
|
||||
// Basic Coordinate Routines (these contain bit-field size AND fixed point scaling constants)
|
||||
float CBitRead::ReadBitCoord (void)
|
||||
{
|
||||
int intval=0,fractval=0,signbit=0;
|
||||
float value = 0.0;
|
||||
|
||||
|
||||
// Read the required integer and fraction flags
|
||||
intval = ReadOneBit();
|
||||
fractval = ReadOneBit();
|
||||
|
||||
// If we got either parse them, otherwise it's a zero.
|
||||
if ( intval || fractval )
|
||||
{
|
||||
// Read the sign bit
|
||||
signbit = ReadOneBit();
|
||||
|
||||
// If there's an integer, read it in
|
||||
if ( intval )
|
||||
{
|
||||
// Adjust the integers from [0..MAX_COORD_VALUE-1] to [1..MAX_COORD_VALUE]
|
||||
intval = ReadUBitLong( COORD_INTEGER_BITS ) + 1;
|
||||
}
|
||||
|
||||
// If there's a fraction, read it in
|
||||
if ( fractval )
|
||||
{
|
||||
fractval = ReadUBitLong( COORD_FRACTIONAL_BITS );
|
||||
}
|
||||
|
||||
// Calculate the correct floating point value
|
||||
value = intval + ((float)fractval * COORD_RESOLUTION);
|
||||
|
||||
// Fixup the sign if negative.
|
||||
if ( signbit )
|
||||
value = -value;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
float CBitRead::ReadBitCoordMP( EBitCoordType coordType )
|
||||
{
|
||||
bool bIntegral = ( coordType == kCW_Integral );
|
||||
bool bLowPrecision = ( coordType == kCW_LowPrecision );
|
||||
|
||||
int intval=0,fractval=0,signbit=0;
|
||||
float value = 0.0;
|
||||
|
||||
bool bInBounds = ReadOneBit() ? true : false;
|
||||
|
||||
if ( bIntegral )
|
||||
{
|
||||
// Read the required integer and fraction flags
|
||||
intval = ReadOneBit();
|
||||
// If we got either parse them, otherwise it's a zero.
|
||||
if ( intval )
|
||||
{
|
||||
// Read the sign bit
|
||||
signbit = ReadOneBit();
|
||||
|
||||
// If there's an integer, read it in
|
||||
// Adjust the integers from [0..MAX_COORD_VALUE-1] to [1..MAX_COORD_VALUE]
|
||||
if ( bInBounds )
|
||||
{
|
||||
value = ( float )( ReadUBitLong( COORD_INTEGER_BITS_MP ) + 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
value = ( float )( ReadUBitLong( COORD_INTEGER_BITS ) + 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read the required integer and fraction flags
|
||||
intval = ReadOneBit();
|
||||
|
||||
// Read the sign bit
|
||||
signbit = ReadOneBit();
|
||||
|
||||
// If we got either parse them, otherwise it's a zero.
|
||||
if ( intval )
|
||||
{
|
||||
if ( bInBounds )
|
||||
{
|
||||
intval = ReadUBitLong( COORD_INTEGER_BITS_MP ) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
intval = ReadUBitLong( COORD_INTEGER_BITS ) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// If there's a fraction, read it in
|
||||
fractval = ReadUBitLong( bLowPrecision ? COORD_FRACTIONAL_BITS_MP_LOWPRECISION : COORD_FRACTIONAL_BITS );
|
||||
|
||||
// Calculate the correct floating point value
|
||||
value = intval + ((float)fractval * ( bLowPrecision ? COORD_RESOLUTION_LOWPRECISION : COORD_RESOLUTION ) );
|
||||
}
|
||||
|
||||
// Fixup the sign if negative.
|
||||
if ( signbit )
|
||||
value = -value;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
float CBitRead::ReadBitCellCoord( int bits, EBitCoordType coordType )
|
||||
{
|
||||
bool bIntegral = ( coordType == kCW_Integral );
|
||||
bool bLowPrecision = ( coordType == kCW_LowPrecision );
|
||||
|
||||
int intval=0,fractval=0;
|
||||
float value = 0.0;
|
||||
|
||||
if ( bIntegral )
|
||||
{
|
||||
value = ( float )( ReadUBitLong( bits ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
intval = ReadUBitLong( bits );
|
||||
|
||||
// If there's a fraction, read it in
|
||||
fractval = ReadUBitLong( bLowPrecision ? COORD_FRACTIONAL_BITS_MP_LOWPRECISION : COORD_FRACTIONAL_BITS );
|
||||
|
||||
// Calculate the correct floating point value
|
||||
value = intval + ((float)fractval * ( bLowPrecision ? COORD_RESOLUTION_LOWPRECISION : COORD_RESOLUTION ) );
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void CBitRead::ReadBitVec3Coord( Vector& fa )
|
||||
{
|
||||
int xflag, yflag, zflag;
|
||||
|
||||
// This vector must be initialized! Otherwise, If any of the flags aren't set,
|
||||
// the corresponding component will not be read and will be stack garbage.
|
||||
fa.Init( 0, 0, 0 );
|
||||
|
||||
xflag = ReadOneBit();
|
||||
yflag = ReadOneBit();
|
||||
zflag = ReadOneBit();
|
||||
|
||||
if ( xflag )
|
||||
fa.x = ReadBitCoord();
|
||||
if ( yflag )
|
||||
fa.y = ReadBitCoord();
|
||||
if ( zflag )
|
||||
fa.z = ReadBitCoord();
|
||||
}
|
||||
|
||||
float CBitRead::ReadBitNormal (void)
|
||||
{
|
||||
// Read the sign bit
|
||||
int signbit = ReadOneBit();
|
||||
|
||||
// Read the fractional part
|
||||
unsigned int fractval = ReadUBitLong( NORMAL_FRACTIONAL_BITS );
|
||||
|
||||
// Calculate the correct floating point value
|
||||
float value = (float)fractval * NORMAL_RESOLUTION;
|
||||
|
||||
// Fixup the sign if negative.
|
||||
if ( signbit )
|
||||
value = -value;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void CBitRead::ReadBitVec3Normal( Vector& fa )
|
||||
{
|
||||
int xflag = ReadOneBit();
|
||||
int yflag = ReadOneBit();
|
||||
|
||||
if (xflag)
|
||||
fa.x = ReadBitNormal();
|
||||
else
|
||||
fa.x = 0.0f;
|
||||
|
||||
if (yflag)
|
||||
fa.y = ReadBitNormal();
|
||||
else
|
||||
fa.y = 0.0f;
|
||||
|
||||
// The first two imply the third (but not its sign)
|
||||
int znegative = ReadOneBit();
|
||||
|
||||
float fafafbfb = fa.x * fa.x + fa.y * fa.y;
|
||||
if (fafafbfb < 1.0f)
|
||||
fa.z = sqrt( 1.0f - fafafbfb );
|
||||
else
|
||||
fa.z = 0.0f;
|
||||
|
||||
if (znegative)
|
||||
fa.z = -fa.z;
|
||||
}
|
||||
|
||||
void CBitRead::ReadBitAngles( QAngle& fa )
|
||||
{
|
||||
Vector tmp;
|
||||
ReadBitVec3Coord( tmp );
|
||||
fa.Init( tmp.x, tmp.y, tmp.z );
|
||||
}
|
||||
|
||||
float CBitRead::ReadBitFloat( void )
|
||||
{
|
||||
uint32 nvalue = ReadUBitLong( 32 );
|
||||
return *( ( float * ) &nvalue );
|
||||
}
|
||||
|
|
@ -1,263 +0,0 @@
|
|||
//====== Copyright (c) 2014, Valve Corporation, All rights reserved. ========//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
// THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//===========================================================================//
|
||||
|
||||
#ifndef DEMOFILEBITBUF_H
|
||||
#define DEMOFILEBITBUF_H
|
||||
|
||||
#include <math.h>
|
||||
#include "demofile.h"
|
||||
|
||||
// OVERALL Coordinate Size Limits used in COMMON.C MSG_*BitCoord() Routines (and someday the HUD)
|
||||
#define COORD_INTEGER_BITS 14
|
||||
#define COORD_FRACTIONAL_BITS 5
|
||||
#define COORD_DENOMINATOR (1<<(COORD_FRACTIONAL_BITS))
|
||||
#define COORD_RESOLUTION (1.0f/(COORD_DENOMINATOR))
|
||||
|
||||
// Special threshold for networking multiplayer origins
|
||||
#define COORD_INTEGER_BITS_MP 11
|
||||
#define COORD_FRACTIONAL_BITS_MP_LOWPRECISION 3
|
||||
#define COORD_DENOMINATOR_LOWPRECISION (1<<(COORD_FRACTIONAL_BITS_MP_LOWPRECISION))
|
||||
#define COORD_RESOLUTION_LOWPRECISION (1.0f/(COORD_DENOMINATOR_LOWPRECISION))
|
||||
|
||||
#define NORMAL_FRACTIONAL_BITS 11
|
||||
#define NORMAL_DENOMINATOR ( (1<<(NORMAL_FRACTIONAL_BITS)) - 1 )
|
||||
#define NORMAL_RESOLUTION (1.0f/(NORMAL_DENOMINATOR))
|
||||
|
||||
enum EBitCoordType
|
||||
{
|
||||
kCW_None,
|
||||
kCW_LowPrecision,
|
||||
kCW_Integral
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// namespaced helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
namespace bitbuf
|
||||
{
|
||||
// ZigZag Transform: Encodes signed integers so that they can be
|
||||
// effectively used with varint encoding.
|
||||
//
|
||||
// varint operates on unsigned integers, encoding smaller numbers into
|
||||
// fewer bytes. If you try to use it on a signed integer, it will treat
|
||||
// this number as a very large unsigned integer, which means that even
|
||||
// small signed numbers like -1 will take the maximum number of bytes
|
||||
// (10) to encode. ZigZagEncode() maps signed integers to unsigned
|
||||
// in such a way that those with a small absolute value will have smaller
|
||||
// encoded values, making them appropriate for encoding using varint.
|
||||
//
|
||||
// int32 -> uint32
|
||||
// -------------------------
|
||||
// 0 -> 0
|
||||
// -1 -> 1
|
||||
// 1 -> 2
|
||||
// -2 -> 3
|
||||
// ... -> ...
|
||||
// 2147483647 -> 4294967294
|
||||
// -2147483648 -> 4294967295
|
||||
//
|
||||
// >> encode >>
|
||||
// << decode <<
|
||||
|
||||
inline uint32 ZigZagEncode32(int32 n)
|
||||
{
|
||||
// Note: the right-shift must be arithmetic
|
||||
return(n << 1) ^ (n >> 31);
|
||||
}
|
||||
|
||||
inline int32 ZigZagDecode32(uint32 n)
|
||||
{
|
||||
return(n >> 1) ^ -static_cast<int32>(n & 1);
|
||||
}
|
||||
|
||||
inline uint64 ZigZagEncode64(int64 n)
|
||||
{
|
||||
// Note: the right-shift must be arithmetic
|
||||
return(n << 1) ^ (n >> 63);
|
||||
}
|
||||
|
||||
inline int64 ZigZagDecode64(uint64 n)
|
||||
{
|
||||
return(n >> 1) ^ -static_cast<int64>(n & 1);
|
||||
}
|
||||
|
||||
const int kMaxVarintBytes = 10;
|
||||
const int kMaxVarint32Bytes = 5;
|
||||
}
|
||||
|
||||
class CBitRead
|
||||
{
|
||||
uint32 m_nInBufWord;
|
||||
int m_nBitsAvail;
|
||||
uint32 const *m_pDataIn;
|
||||
uint32 const *m_pBufferEnd;
|
||||
uint32 const *m_pData;
|
||||
|
||||
bool m_bOverflow;
|
||||
int m_nDataBits;
|
||||
size_t m_nDataBytes;
|
||||
|
||||
static const uint32 s_nMaskTable[ 33 ]; // 0 1 3 7 15 ..
|
||||
|
||||
public:
|
||||
CBitRead( const void *pData, int nBytes, int nBits = -1 )
|
||||
{
|
||||
m_bOverflow = false;
|
||||
m_nDataBits = -1;
|
||||
m_nDataBytes = 0;
|
||||
StartReading( pData, nBytes, 0, nBits );
|
||||
}
|
||||
|
||||
CBitRead( void )
|
||||
{
|
||||
m_bOverflow = false;
|
||||
m_nDataBits = -1;
|
||||
m_nDataBytes = 0;
|
||||
}
|
||||
|
||||
void SetOverflowFlag( void )
|
||||
{
|
||||
m_bOverflow = true;
|
||||
}
|
||||
|
||||
bool IsOverflowed( void ) const
|
||||
{
|
||||
return m_bOverflow;
|
||||
}
|
||||
|
||||
int Tell( void ) const
|
||||
{
|
||||
return GetNumBitsRead();
|
||||
}
|
||||
|
||||
size_t TotalBytesAvailable( void ) const
|
||||
{
|
||||
return m_nDataBytes;
|
||||
}
|
||||
|
||||
int GetNumBitsLeft( void ) const
|
||||
{
|
||||
return m_nDataBits - Tell();
|
||||
}
|
||||
|
||||
int GetNumBytesLeft( void ) const
|
||||
{
|
||||
return GetNumBitsLeft() >> 3;
|
||||
}
|
||||
|
||||
bool Seek( int nPosition );
|
||||
|
||||
bool SeekRelative( int nOffset )
|
||||
{
|
||||
return Seek( GetNumBitsRead() + nOffset );
|
||||
}
|
||||
|
||||
unsigned char const * GetBasePointer()
|
||||
{
|
||||
return reinterpret_cast< unsigned char const *>( m_pData );
|
||||
}
|
||||
|
||||
void StartReading( const void *pData, int nBytes, int iStartBit = 0, int nBits = -1 );
|
||||
|
||||
int GetNumBitsRead( void ) const;
|
||||
int GetNumBytesRead( void ) const;
|
||||
|
||||
void GrabNextDWord( bool bOverFlowImmediately = false );
|
||||
void FetchNext( void );
|
||||
unsigned int ReadUBitLong( int numbits );
|
||||
int ReadSBitLong( int numbits );
|
||||
unsigned int ReadUBitVar( void );
|
||||
unsigned int PeekUBitLong( int numbits );
|
||||
bool ReadBytes( void *pOut, int nBytes );
|
||||
|
||||
// Returns 0 or 1.
|
||||
int ReadOneBit( void );
|
||||
int ReadLong( void );
|
||||
int ReadChar( void );
|
||||
int ReadByte( void );
|
||||
int ReadShort( void );
|
||||
int ReadWord( void );
|
||||
float ReadFloat( void );
|
||||
void ReadBits( void *pOut, int nBits );
|
||||
|
||||
float ReadBitCoord();
|
||||
float ReadBitCoordMP( EBitCoordType coordType );
|
||||
float ReadBitCellCoord( int bits, EBitCoordType coordType );
|
||||
float ReadBitNormal();
|
||||
void ReadBitVec3Coord( Vector& fa );
|
||||
void ReadBitVec3Normal( Vector& fa );
|
||||
void ReadBitAngles( QAngle& fa );
|
||||
float ReadBitAngle( int numbits );
|
||||
float ReadBitFloat( void );
|
||||
|
||||
// Returns false if bufLen isn't large enough to hold the
|
||||
// string in the buffer.
|
||||
//
|
||||
// Always reads to the end of the string (so you can read the
|
||||
// next piece of data waiting).
|
||||
//
|
||||
// If bLine is true, it stops when it reaches a '\n' or a null-terminator.
|
||||
//
|
||||
// pStr is always null-terminated (unless bufLen is 0).
|
||||
//
|
||||
// pOutNumChars is set to the number of characters left in pStr when the routine is
|
||||
// complete (this will never exceed bufLen-1).
|
||||
//
|
||||
bool ReadString( char *pStr, int bufLen, bool bLine=false, int *pOutNumChars = NULL );
|
||||
|
||||
// reads a varint encoded integer
|
||||
uint32 ReadVarInt32();
|
||||
uint64 ReadVarInt64();
|
||||
int32 ReadSignedVarInt32() { return bitbuf::ZigZagDecode32( ReadVarInt32() ); }
|
||||
int64 ReadSignedVarInt64() { return bitbuf::ZigZagDecode64( ReadVarInt64() ); }
|
||||
};
|
||||
|
||||
inline unsigned int CBitRead::PeekUBitLong(int numbits)
|
||||
{
|
||||
int nSaveBA = m_nBitsAvail;
|
||||
int nSaveW = m_nInBufWord;
|
||||
uint32 const *pSaveP = m_pDataIn;
|
||||
unsigned int nRet = ReadUBitLong(numbits);
|
||||
m_nBitsAvail = nSaveBA;
|
||||
m_nInBufWord = nSaveW;
|
||||
m_pDataIn = pSaveP;
|
||||
return nRet;
|
||||
}
|
||||
|
||||
inline int CBitRead::ReadLong(void)
|
||||
{
|
||||
return (int)ReadUBitLong(sizeof(long) << 3);
|
||||
}
|
||||
|
||||
inline float CBitRead::ReadFloat(void)
|
||||
{
|
||||
uint32 nUval = ReadUBitLong(sizeof(long) << 3);
|
||||
return *((float *)&nUval);
|
||||
}
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) )
|
||||
#endif
|
||||
|
||||
#endif
|
10
demboyz/demoreader.h
Normal file
10
demboyz/demoreader.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
class IDemoWriter;
|
||||
|
||||
namespace DemoReader
|
||||
{
|
||||
void ProcessDem(void* inputFp, IDemoWriter* writer);
|
||||
void ProcessJson(void* inputFp, IDemoWriter* writer);
|
||||
}
|
180
demboyz/demotypes.h
Normal file
180
demboyz/demotypes.h
Normal file
|
@ -0,0 +1,180 @@
|
|||
//====== Copyright (c) 2014, Valve Corporation, All rights reserved. ========//
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
// THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//===========================================================================//
|
||||
|
||||
#pragma once
|
||||
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "vector.h"
|
||||
|
||||
#define DEMO_HEADER_ID "HL2DEMO"
|
||||
#define DEMO_PROTOCOL 3
|
||||
|
||||
#if !defined( MAX_OSPATH )
|
||||
#define MAX_OSPATH 260 // max length of a filesystem pathname
|
||||
#endif
|
||||
|
||||
// Demo messages
|
||||
enum
|
||||
{
|
||||
// it's a startup message, process as fast as possible
|
||||
dem_signon = 1,
|
||||
// it's a normal network packet that we stored off
|
||||
dem_packet,
|
||||
// sync client clock to demo tick
|
||||
dem_synctick,
|
||||
// console command
|
||||
dem_consolecmd,
|
||||
// user input command
|
||||
dem_usercmd,
|
||||
// network data tables
|
||||
dem_datatables,
|
||||
// end of time.
|
||||
dem_stop,
|
||||
// a blob of binary data understood by a callback function
|
||||
dem_customdata,
|
||||
|
||||
dem_stringtables,
|
||||
|
||||
// Last command
|
||||
dem_lastcmd = dem_stringtables
|
||||
};
|
||||
|
||||
struct demoheader_t
|
||||
{
|
||||
char demofilestamp[ 8 ]; // Should be HL2DEMO
|
||||
int32_t demoprotocol; // Should be DEMO_PROTOCOL
|
||||
int32_t networkprotocol; // Should be PROTOCOL_VERSION
|
||||
char servername[ MAX_OSPATH ]; // Name of server
|
||||
char clientname[ MAX_OSPATH ]; // Name of client who recorded the game
|
||||
char mapname[ MAX_OSPATH ]; // Name of map
|
||||
char gamedirectory[ MAX_OSPATH ]; // Name of game directory (com_gamedir)
|
||||
float playback_time; // Time of track
|
||||
int32_t playback_ticks; // # of ticks in track
|
||||
int32_t playback_frames; // # of frames in track
|
||||
int32_t signonlength; // length of sigondata in bytes
|
||||
};
|
||||
|
||||
#define FDEMO_NORMAL 0
|
||||
#define FDEMO_USE_ORIGIN2 ( 1 << 0 )
|
||||
#define FDEMO_USE_ANGLES2 ( 1 << 1 )
|
||||
#define FDEMO_NOINTERP ( 1 << 2 ) // don't interpolate between this an last view
|
||||
|
||||
#define MAX_SPLITSCREEN_CLIENTS 1
|
||||
|
||||
struct democmdinfo_t
|
||||
{
|
||||
democmdinfo_t( void )
|
||||
{
|
||||
}
|
||||
|
||||
struct Split_t
|
||||
{
|
||||
Split_t( void )
|
||||
{
|
||||
flags = FDEMO_NORMAL;
|
||||
viewOrigin.Init();
|
||||
viewAngles.Init();
|
||||
localViewAngles.Init();
|
||||
|
||||
// Resampled origin/angles
|
||||
viewOrigin2.Init();
|
||||
viewAngles2.Init();
|
||||
localViewAngles2.Init();
|
||||
}
|
||||
|
||||
Split_t& operator=( const Split_t& src )
|
||||
{
|
||||
if ( this == &src )
|
||||
return *this;
|
||||
|
||||
flags = src.flags;
|
||||
viewOrigin = src.viewOrigin;
|
||||
viewAngles = src.viewAngles;
|
||||
localViewAngles = src.localViewAngles;
|
||||
viewOrigin2 = src.viewOrigin2;
|
||||
viewAngles2 = src.viewAngles2;
|
||||
localViewAngles2 = src.localViewAngles2;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Vector& GetViewOrigin( void )
|
||||
{
|
||||
if ( flags & FDEMO_USE_ORIGIN2 )
|
||||
{
|
||||
return viewOrigin2;
|
||||
}
|
||||
return viewOrigin;
|
||||
}
|
||||
|
||||
const QAngle& GetViewAngles( void )
|
||||
{
|
||||
if ( flags & FDEMO_USE_ANGLES2 )
|
||||
{
|
||||
return viewAngles2;
|
||||
}
|
||||
return viewAngles;
|
||||
}
|
||||
const QAngle& GetLocalViewAngles( void )
|
||||
{
|
||||
if ( flags & FDEMO_USE_ANGLES2 )
|
||||
{
|
||||
return localViewAngles2;
|
||||
}
|
||||
return localViewAngles;
|
||||
}
|
||||
|
||||
void Reset( void )
|
||||
{
|
||||
flags = 0;
|
||||
viewOrigin2 = viewOrigin;
|
||||
viewAngles2 = viewAngles;
|
||||
localViewAngles2 = localViewAngles;
|
||||
}
|
||||
|
||||
int32_t flags;
|
||||
|
||||
// original origin/viewangles
|
||||
Vector viewOrigin;
|
||||
QAngle viewAngles;
|
||||
QAngle localViewAngles;
|
||||
|
||||
// Resampled origin/viewangles
|
||||
Vector viewOrigin2;
|
||||
QAngle viewAngles2;
|
||||
QAngle localViewAngles2;
|
||||
};
|
||||
|
||||
void Reset( void )
|
||||
{
|
||||
for ( int i = 0; i < MAX_SPLITSCREEN_CLIENTS; ++i )
|
||||
{
|
||||
u[ i ].Reset();
|
||||
}
|
||||
}
|
||||
|
||||
Split_t u[ MAX_SPLITSCREEN_CLIENTS ];
|
||||
};
|
28
demboyz/demowriter.cpp
Normal file
28
demboyz/demowriter.cpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "idemowriter.h"
|
||||
#include <cstdio>
|
||||
|
||||
class DemoWriter: public IDemoWriter
|
||||
{
|
||||
public:
|
||||
DemoWriter(FILE* outputFp);
|
||||
|
||||
virtual void StartWriting(demoheader_t& header) override final;
|
||||
virtual void EndWriting() override final;
|
||||
|
||||
virtual void StartCommandPacket(CommandPacket& packet) override final;
|
||||
virtual void EndCommandPacket() override final;
|
||||
|
||||
virtual void WriteNetPacket(NetPacket& packet) override final;
|
||||
};
|
||||
|
||||
IDemoWriter* IDemoWriter::CreateDemoWriter(void* outputFp)
|
||||
{
|
||||
return new DemoWriter(reinterpret_cast<FILE*>(outputFp));
|
||||
}
|
||||
|
||||
DemoWriter::DemoWriter(FILE* outputFp)
|
||||
{
|
||||
}
|
72
demboyz/demreader.cpp
Normal file
72
demboyz/demreader.cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
|
||||
#include "demoreader.h"
|
||||
#include "idemowriter.h"
|
||||
#include "demofile.h"
|
||||
|
||||
/*void ParsePacket(const std::vector<unsigned char>& packet)
|
||||
{
|
||||
assert(packet.size() <= NET_MAX_PAYLOAD);
|
||||
bf_read bitbuf(packet.data(), packet.size());
|
||||
while (bitbuf.GetNumBitsLeft() >= NETMSG_TYPE_BITS)
|
||||
{
|
||||
uint32 typeId = bitbuf.ReadUBitLong(NETMSG_TYPE_BITS);
|
||||
printf("%i\n", typeId);
|
||||
//ProcessNetMsg(typeId, bitbuf);
|
||||
}
|
||||
}
|
||||
|
||||
void ParseDemoSequence(const std::vector<unsigned char>& sequenceData)
|
||||
{
|
||||
CommandPacket packet;
|
||||
std::vector<uint8_t> buffer;
|
||||
|
||||
DemoSequenceReader reader(sequenceData);
|
||||
for (; reader.ReadCmdHeader(packet.cmd, packet.tick);)
|
||||
{
|
||||
switch (packet.cmd)
|
||||
{
|
||||
case dem_signon:
|
||||
case dem_packet:
|
||||
reader.ReadCmdInfo(packet.cmdInfo);
|
||||
reader.ReadSequenceInfo(packet.sequenceInfo1, packet.sequenceInfo2);
|
||||
assert(packet.sequenceInfo1 == packet.sequenceInfo2);
|
||||
reader.ReadRawData(buffer);
|
||||
ParsePacket(buffer);
|
||||
break;
|
||||
case dem_synctick:
|
||||
// nothing
|
||||
break;
|
||||
case dem_consolecmd:
|
||||
reader.ReadRawData(nullptr, 1024);
|
||||
break;
|
||||
case dem_usercmd:
|
||||
reader.ReadUserCmd(buffer, 256);
|
||||
break;
|
||||
case dem_datatables:
|
||||
// TODO: datatables
|
||||
reader.ReadRawData(nullptr, 64*1024);
|
||||
break;
|
||||
case dem_stop:
|
||||
// TODO assert frame and tick numbers
|
||||
break;
|
||||
case dem_customdata:
|
||||
reader.ReadRawData(nullptr, 0);
|
||||
break;
|
||||
case dem_stringtables:
|
||||
reader.ReadRawData(nullptr, 0);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
void DemoReader::ProcessDem(void* inputFp, IDemoWriter* writer)
|
||||
{
|
||||
DemoFileReader demoFile(reinterpret_cast<FILE*>(inputFp));
|
||||
|
||||
//auto demoHeader = demoFile.GetDemoHeader();
|
||||
//ParseDemoSequence(demoFile.GetSignOnData());
|
||||
//ParseDemoSequence(demoFile.GetDemoData());
|
||||
}
|
48
demboyz/idemowriter.h
Normal file
48
demboyz/idemowriter.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct democmdinfo_t;
|
||||
struct demoheader_t;
|
||||
struct CommandPacket;
|
||||
struct NetPacket;
|
||||
|
||||
struct CommandPacket
|
||||
{
|
||||
unsigned char cmd;
|
||||
int32_t tick;
|
||||
|
||||
democmdinfo_t* cmdInfo;
|
||||
int32_t sequenceInfo1;
|
||||
int32_t sequenceInfo2;
|
||||
};
|
||||
|
||||
struct NetPacket
|
||||
{
|
||||
uint32_t type;
|
||||
void* data;
|
||||
};
|
||||
|
||||
class IDemoWriter
|
||||
{
|
||||
public:
|
||||
virtual ~IDemoWriter() {}
|
||||
|
||||
virtual void StartWriting(demoheader_t& header) = 0;
|
||||
virtual void EndWriting() = 0;
|
||||
|
||||
virtual void StartCommandPacket(CommandPacket& packet) = 0;
|
||||
virtual void EndCommandPacket() = 0;
|
||||
|
||||
virtual void WriteNetPacket(NetPacket& packet) = 0;
|
||||
|
||||
public:
|
||||
static IDemoWriter* CreateJsonWriter(void* outputFp);
|
||||
static IDemoWriter* CreateDemoWriter(void* outputFp);
|
||||
|
||||
static void FreeDemoWriter(IDemoWriter* writer)
|
||||
{
|
||||
delete writer;
|
||||
}
|
||||
};
|
6
demboyz/jsonreader.cpp
Normal file
6
demboyz/jsonreader.cpp
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
#include "demoreader.h"
|
||||
|
||||
void DemoReader::ProcessJson(void* inputFp, IDemoWriter* writer)
|
||||
{
|
||||
}
|
24
demboyz/jsonwriter.cpp
Normal file
24
demboyz/jsonwriter.cpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "idemowriter.h"
|
||||
#include <cstdio>
|
||||
|
||||
class JsonWriter: public IDemoWriter
|
||||
{
|
||||
public:
|
||||
JsonWriter(FILE* outputFp);
|
||||
|
||||
virtual void StartWriting(demoheader_t& header) override final;
|
||||
virtual void EndWriting() override final;
|
||||
|
||||
virtual void StartCommandPacket(CommandPacket& packet) override final;
|
||||
virtual void EndCommandPacket() override final;
|
||||
|
||||
virtual void WriteNetPacket(NetPacket& packet) override final;
|
||||
};
|
||||
|
||||
IDemoWriter* IDemoWriter::CreateJsonWriter(void* outputFp)
|
||||
{
|
||||
return new JsonWriter(reinterpret_cast<FILE*>(outputFp));
|
||||
}
|
3
external/sourcesdk/valve_support.h
vendored
3
external/sourcesdk/valve_support.h
vendored
|
@ -2,6 +2,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <cassert>
|
||||
#include "vector.h"
|
||||
|
||||
|
@ -25,8 +26,6 @@ using byte = char;
|
|||
#define PLATFORM_WINDOWS_PC64 1
|
||||
#endif
|
||||
|
||||
#define NULL nullptr
|
||||
|
||||
#define Assert(x) assert(x)
|
||||
#define AssertMsg(x, ...) assert(x)
|
||||
#define AssertMsg2(x, ...) assert(x)
|
||||
|
|
|
@ -6,16 +6,22 @@ solution "demboyz"
|
|||
configurations { "Debug", "Release" }
|
||||
platforms "x32"
|
||||
|
||||
vpaths
|
||||
{
|
||||
["Header Files"] = { "../**.h" },
|
||||
["Source Files"] = { "../**.cpp" }
|
||||
}
|
||||
|
||||
project "demboyz"
|
||||
kind "ConsoleApp"
|
||||
language "C++"
|
||||
files { "../demboyz/**.h", "../demboyz/**.cpp" }
|
||||
files
|
||||
{
|
||||
"../demboyz/*.h",
|
||||
"../demboyz/*.cpp",
|
||||
"../demboyz/netmessages/*.h",
|
||||
"../demboyz/netmessages/*.cpp",
|
||||
"../external/sourcesdk/*.h",
|
||||
"../external/sourcesdk/*.cpp"
|
||||
}
|
||||
includedirs
|
||||
{
|
||||
"../external/sourcesdk"
|
||||
}
|
||||
|
||||
configuration "Debug"
|
||||
targetdir (_ACTION .. "/build/Debug")
|
||||
|
|
Loading…
Reference in New Issue
Block a user