Added demo writer interface, restructure
This commit is contained in:
parent
9834880bc5
commit
78de8690ab
@ -1,90 +1,100 @@
|
|||||||
|
|
||||||
#include "demofile.h"
|
#include "idemowriter.h"
|
||||||
#include "demofilebitbuf.h"
|
#include "demoreader.h"
|
||||||
#include "netmessages.h"
|
#include <cstdio>
|
||||||
#include <assert.h>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
void ParsePacket(const std::vector<unsigned char>& packet)
|
std::string GetExtension(const std::string& filename)
|
||||||
{
|
{
|
||||||
assert(packet.size() <= NET_MAX_PAYLOAD);
|
size_t index = filename.find_last_of(".");
|
||||||
CBitRead bitbuf(packet.data(), packet.size());
|
if (index != std::string::npos)
|
||||||
while (bitbuf.GetNumBitsLeft() >= NETMSG_TYPE_BITS)
|
|
||||||
{
|
{
|
||||||
uint32 typeId = bitbuf.ReadUBitLong(NETMSG_TYPE_BITS);
|
return filename.substr(index + 1);
|
||||||
printf("%i\n", typeId);
|
|
||||||
ProcessNetMsg(typeId, bitbuf);
|
|
||||||
}
|
}
|
||||||
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParseDemoSequence(const std::vector<unsigned char>& sequenceData)
|
enum class FileType
|
||||||
{
|
{
|
||||||
unsigned char cmd;
|
None,
|
||||||
int32 tick;
|
Dem,
|
||||||
int32 sequenceInfo1;
|
Json
|
||||||
int32 sequenceInfo2;
|
};
|
||||||
democmdinfo_t cmdInfo;
|
|
||||||
std::vector<unsigned char> buffer;
|
|
||||||
|
|
||||||
DemoSequenceReader reader(sequenceData);
|
FileType GetFileType(const std::string& filename)
|
||||||
for (;;)
|
|
||||||
{
|
{
|
||||||
reader.ReadCmdHeader(cmd, tick);
|
std::string ext = GetExtension(filename);
|
||||||
switch (cmd)
|
if (ext == "dem")
|
||||||
{
|
{
|
||||||
case dem_signon:
|
return FileType::Dem;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
if (ext == "json")
|
||||||
|
{
|
||||||
|
return FileType::Json;
|
||||||
}
|
}
|
||||||
|
return FileType::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(const int argc, const char* argv[])
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
CDemoFile demoFile;
|
std::string inputFile(argv[1]);
|
||||||
if (!demoFile.Open(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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto demoHeader = demoFile.GetDemoHeader();
|
FILE* inputFp = fopen(inputFile.c_str(), "rb");
|
||||||
ParseDemoSequence(demoFile.GetSignOnData());
|
if (!inputFp)
|
||||||
ParseDemoSequence(demoFile.GetDemoData());
|
{
|
||||||
demoFile.Close();
|
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;
|
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 "demofile.h"
|
||||||
|
#include "demotypes.h"
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
DemoSequenceReader::DemoSequenceReader(const std::vector<unsigned char>& sequenceData):
|
// DemoFileReader
|
||||||
m_sequenceData(sequenceData),
|
|
||||||
m_dataReadOffset(0)
|
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())
|
FILE* fp = m_demoFp;
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned char* sequenceData = m_sequenceData.data();
|
int32_t size;
|
||||||
size_t currentReadOffset = m_dataReadOffset;
|
fread(&size, sizeof(int32_t), 1, fp);
|
||||||
|
|
||||||
// read length of data block
|
|
||||||
const int32 size = *reinterpret_cast<const int32*>(sequenceData + currentReadOffset);
|
|
||||||
currentReadOffset += sizeof(int32);
|
|
||||||
|
|
||||||
if (buffer && (length < size))
|
if (buffer && (length < size))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "CDemoFile::ReadRawData: buffer overflow (%i).\n", size);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer)
|
if (buffer)
|
||||||
{
|
{
|
||||||
// read data into buffer
|
fread(buffer, 1, size, fp);
|
||||||
memcpy(buffer, sequenceData + currentReadOffset, size);
|
}
|
||||||
}
|
else
|
||||||
currentReadOffset += size;
|
{
|
||||||
|
fseek(fp, size, SEEK_CUR);
|
||||||
m_dataReadOffset = currentReadOffset;
|
}
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DemoSequenceReader::ReadRawData(std::vector<unsigned char>& buf,
|
void DemoFileReader::ReadSequenceInfo(int32_t& seqNum1, int32_t& seqNum2)
|
||||||
const int32 maxReadSize /*= MAX_READ_SIZE*/)
|
{
|
||||||
{
|
FILE* fp = m_demoFp;
|
||||||
if (m_sequenceData.empty())
|
fread(&seqNum1, sizeof(int32_t), 1, fp);
|
||||||
{
|
fread(&seqNum2, sizeof(int32_t), 1, fp);
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
|
void DemoFileReader::ReadCmdInfo(democmdinfo_t& info)
|
||||||
const unsigned char* sequenceData = m_sequenceData.data();
|
{
|
||||||
size_t currentReadOffset = m_dataReadOffset;
|
fread(&info, sizeof(democmdinfo_t), 1, m_demoFp);
|
||||||
|
}
|
||||||
// read length of data block
|
|
||||||
const int32 size = *reinterpret_cast<const int32*>(sequenceData + currentReadOffset);
|
void DemoFileReader::ReadCmdHeader(unsigned char& cmd, int32_t& tick)
|
||||||
currentReadOffset += sizeof(int32);
|
{
|
||||||
|
FILE* fp = m_demoFp;
|
||||||
if (size < 0)
|
fread(&cmd, sizeof(unsigned char), 1, fp);
|
||||||
{
|
fread(&tick, sizeof(int32_t), 1, fp);
|
||||||
fprintf(stderr, "DemoSequenceReader::ReadRawData: invalid size (%i).\n", size);
|
if (cmd >= 0)
|
||||||
return false;
|
{
|
||||||
}
|
assert(cmd <= dem_lastcmd);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(stderr, "CDemoFile::ReadCmdHeader: Missing end tag in demo file.\n");
|
|
||||||
cmd = dem_stop;
|
cmd = dem_stop;
|
||||||
}
|
}
|
||||||
m_dataReadOffset = currentReadOffset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 DemoSequenceReader::ReadUserCmd(std::vector<unsigned char>& buf,
|
int32_t DemoFileReader::ReadUserCmd(uint8_t* buffer, int32_t length)
|
||||||
const int32 maxReadSize /*= MAX_READ_SIZE*/)
|
|
||||||
{
|
{
|
||||||
if (m_sequenceData.empty())
|
int32_t sequenceNum;
|
||||||
|
fread(&sequenceNum, sizeof(int32_t), 1, m_demoFp);
|
||||||
|
if (ReadRawData(buffer, length) < 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return -1;
|
||||||
|
}
|
||||||
|
return sequenceNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int32 outgoing_sequence = *reinterpret_cast<const int32*>(m_sequenceData.data() + m_dataReadOffset);
|
// DemoFileWriter
|
||||||
m_dataReadOffset += sizeof(int32);
|
|
||||||
|
|
||||||
if (!ReadRawData(buf, maxReadSize))
|
DemoFileWriter::DemoFileWriter(FILE* fp) :
|
||||||
{
|
m_demoFp(fp)
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return outgoing_sequence;
|
|
||||||
}
|
|
||||||
|
|
||||||
CDemoFile::CDemoFile():
|
|
||||||
m_DemoHeader()
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
fread(&header, sizeof(demoheader_t), 1, m_demoFp);
|
||||||
|
|
||||||
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 );
|
void DemoFileWriter::WriteRawData(const uint8_t* buffer, int32_t length)
|
||||||
Length -= sizeof( m_DemoHeader );
|
|
||||||
|
|
||||||
if ( strcmp ( m_DemoHeader.demofilestamp, DEMO_HEADER_ID ) )
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, "CDemoFile::Open: %s has invalid demo header ID.\n", name);
|
FILE* fp = m_demoFp;
|
||||||
fclose( fp );
|
fwrite(&length, sizeof(int32_t), 1, fp);
|
||||||
return false;
|
fwrite(buffer, length, 1, fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( m_DemoHeader.demoprotocol != DEMO_PROTOCOL )
|
void DemoFileWriter::WriteSequenceInfo(int32_t seqNum1, int32_t seqNum2)
|
||||||
{
|
{
|
||||||
fprintf( stderr, "CDemoFile::Open: demo file protocol %i invalid, expected version is %i \n", m_DemoHeader.demoprotocol, DEMO_PROTOCOL );
|
FILE* fp = m_demoFp;
|
||||||
fclose( fp );
|
fwrite(&seqNum1, sizeof(int32_t), 1, fp);
|
||||||
return false;
|
fwrite(&seqNum2, sizeof(int32_t), 1, fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int32 signOnLength = m_DemoHeader.signonlength;
|
void DemoFileWriter::WriteCmdInfo(const democmdinfo_t& info)
|
||||||
if (signOnLength > 0)
|
|
||||||
{
|
{
|
||||||
m_signOnData.resize(signOnLength);
|
fwrite(&info, sizeof(democmdinfo_t), 1, m_demoFp);
|
||||||
fread(&m_signOnData[0], 1, signOnLength, fp);
|
|
||||||
Length -= signOnLength;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_fileBuffer.resize( Length );
|
void DemoFileWriter::WriteCmdHeader(unsigned char cmd, int32_t tick)
|
||||||
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 );
|
FILE* fp = m_demoFp;
|
||||||
Close();
|
fwrite(&cmd, sizeof(unsigned char), 1, fp);
|
||||||
return false;
|
fwrite(&tick, sizeof(int32_t), 1, fp);
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDemoFile::Close()
|
void DemoFileWriter::WriteUserCmd(int32_t sequenceNum, const uint8_t* buffer, int32_t length)
|
||||||
{
|
{
|
||||||
m_signOnData.clear();
|
fwrite(&sequenceNum, sizeof(int32_t), 1, m_demoFp);
|
||||||
m_fileBuffer.clear();
|
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
|
#pragma once
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <vector>
|
#include <cstdint>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
#define __STDC_FORMAT_MACROS
|
struct demoheader_t;
|
||||||
#include <inttypes.h>
|
struct democmdinfo_t;
|
||||||
|
|
||||||
#define DEMO_HEADER_ID "HL2DEMO"
|
class DemoFileReader
|
||||||
#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:
|
public:
|
||||||
DemoSequenceReader(const std::vector<unsigned char>& sequenceData);
|
DemoFileReader(FILE* fp);
|
||||||
|
|
||||||
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 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 ReadCmdInfo(democmdinfo_t& info);
|
||||||
|
void ReadCmdHeader(unsigned char& cmd, int32_t& tick);
|
||||||
void ReadCmdHeader(unsigned char &cmd, int32 &tick);
|
int32_t ReadUserCmd(uint8_t* buffer, int32_t length);
|
||||||
|
|
||||||
int32 ReadUserCmd(std::vector<unsigned char>& buf, const int32 maxReadSize = MAX_READ_SIZE);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::vector<unsigned char>& m_sequenceData;
|
FILE* m_demoFp;
|
||||||
size_t m_dataReadOffset;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CDemoFile
|
class DemoFileWriter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CDemoFile();
|
DemoFileWriter(FILE* fp);
|
||||||
~CDemoFile();
|
|
||||||
|
|
||||||
bool Open( const char *name );
|
void WriteDemoHeader(const demoheader_t& header);
|
||||||
void Close();
|
void WriteRawData(const uint8_t* buffer, int32_t length);
|
||||||
|
void WriteSequenceInfo(int32_t seqNum1, int32_t seqNum2);
|
||||||
const demoheader_t *GetDemoHeader() const;
|
void WriteCmdInfo(const democmdinfo_t& info);
|
||||||
|
void WriteCmdHeader(unsigned char cmd, int32_t tick);
|
||||||
const std::vector<unsigned char>& GetSignOnData() const;
|
void WriteUserCmd(int32_t sequenceNum, const uint8_t* buffer, int32_t length);
|
||||||
const std::vector<unsigned char>& GetDemoData() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
demoheader_t m_DemoHeader; //general demo info
|
FILE* m_demoFp;
|
||||||
|
|
||||||
std::vector<unsigned char> m_signOnData;
|
|
||||||
std::vector<unsigned char> m_fileBuffer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const demoheader_t *CDemoFile::GetDemoHeader() const
|
|
||||||
{
|
|
||||||
return &m_DemoHeader;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const std::vector<unsigned char>& CDemoFile::GetSignOnData() const
|
|
||||||
{
|
|
||||||
return m_signOnData;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const std::vector<unsigned char>& CDemoFile::GetDemoData() const
|
|
||||||
{
|
|
||||||
return m_fileBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // DEMOFILE_H
|
|
||||||
|
@ -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
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include "vector.h"
|
#include "vector.h"
|
||||||
|
|
||||||
@ -25,8 +26,6 @@ using byte = char;
|
|||||||
#define PLATFORM_WINDOWS_PC64 1
|
#define PLATFORM_WINDOWS_PC64 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define NULL nullptr
|
|
||||||
|
|
||||||
#define Assert(x) assert(x)
|
#define Assert(x) assert(x)
|
||||||
#define AssertMsg(x, ...) assert(x)
|
#define AssertMsg(x, ...) assert(x)
|
||||||
#define AssertMsg2(x, ...) assert(x)
|
#define AssertMsg2(x, ...) assert(x)
|
||||||
|
@ -6,16 +6,22 @@ solution "demboyz"
|
|||||||
configurations { "Debug", "Release" }
|
configurations { "Debug", "Release" }
|
||||||
platforms "x32"
|
platforms "x32"
|
||||||
|
|
||||||
vpaths
|
|
||||||
{
|
|
||||||
["Header Files"] = { "../**.h" },
|
|
||||||
["Source Files"] = { "../**.cpp" }
|
|
||||||
}
|
|
||||||
|
|
||||||
project "demboyz"
|
project "demboyz"
|
||||||
kind "ConsoleApp"
|
kind "ConsoleApp"
|
||||||
language "C++"
|
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"
|
configuration "Debug"
|
||||||
targetdir (_ACTION .. "/build/Debug")
|
targetdir (_ACTION .. "/build/Debug")
|
||||||
|
Loading…
Reference in New Issue
Block a user