add support for split demo files (UNLOZE)
This commit is contained in:
parent
3b723a64e0
commit
d4a0d51bfc
@ -8,13 +8,19 @@
|
||||
|
||||
int main(const int argc, const char* argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
if (argc < 2)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s <in>.dem\n", argv[0]);
|
||||
fprintf(stderr, "Usage: %s <in>.dem [in2.dem] ...\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::filesystem::path inputFile(argv[1]);
|
||||
DemoReader::Init();
|
||||
SourceGameContext *context = nullptr;
|
||||
|
||||
bool error = false;
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
std::filesystem::path inputFile(argv[i]);
|
||||
FILE* inputFp = fopen(inputFile.c_str(), "rb");
|
||||
if (!inputFp)
|
||||
{
|
||||
@ -22,18 +28,29 @@ int main(const int argc, const char* argv[])
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::filesystem::path outputDir = inputFile.filename().replace_extension();
|
||||
std::filesystem::path outputDirVoice = outputDir.string() + "/voice";
|
||||
static std::filesystem::path outputDir = inputFile.filename().replace_extension();
|
||||
static std::filesystem::path outputDirVoice = outputDir.string() + "/voice";
|
||||
if (i == 1)
|
||||
{
|
||||
std::filesystem::create_directory(outputDir);
|
||||
std::filesystem::create_directory(outputDirVoice);
|
||||
|
||||
SourceGameContext context = SourceGameContext(outputDir, outputDirVoice);
|
||||
if (!context.init())
|
||||
context = new SourceGameContext(outputDir, outputDirVoice);
|
||||
if(!context->init())
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool error = !DemoReader::ProcessDem(inputFp, &context);
|
||||
bool dirty = DemoReader::ProcessDem(inputFp, context);
|
||||
if(dirty)
|
||||
error = true;
|
||||
|
||||
fclose(inputFp);
|
||||
}
|
||||
|
||||
context->End();
|
||||
delete context;
|
||||
|
||||
DemoReader::DeInit();
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -24,6 +24,15 @@ Logic::~Logic()
|
||||
}
|
||||
|
||||
void Logic::Start()
|
||||
{
|
||||
tickBase = curTick;
|
||||
if(curTick)
|
||||
{
|
||||
data["demoheader"]["playback_time"] = data["demoheader"]["playback_time"].get<float>() + context->header.playback_time;
|
||||
data["demoheader"]["playback_ticks"] = data["demoheader"]["playback_ticks"].get<int32_t>() + context->header.playback_ticks;
|
||||
data["demoheader"]["playback_frames"] = data["demoheader"]["playback_frames"].get<int32_t>() + context->header.playback_frames;
|
||||
}
|
||||
else
|
||||
{
|
||||
data["demoheader"] = json({
|
||||
{"demofilestamp", context->header.demofilestamp},
|
||||
@ -38,8 +47,9 @@ void Logic::Start()
|
||||
{"playback_frames", context->header.playback_frames},
|
||||
{"signonlength", context->header.signonlength}
|
||||
});
|
||||
}
|
||||
|
||||
// std::cout << data.dump(2, ' ', false, json::error_handler_t::replace) << "\n";
|
||||
// std::cout << data["demoheader"].dump(2, ' ', false, json::error_handler_t::replace) << "\n";
|
||||
}
|
||||
|
||||
void Logic::Finish(bool dirty)
|
||||
@ -59,9 +69,12 @@ void Logic::Finish(bool dirty)
|
||||
{
|
||||
data["demoheader"]["playback_ticks"] = curTick;
|
||||
data["demoheader"]["playback_time"] = curTick * context->fTickInterval;
|
||||
data["demoheader"]["playback_frames"] = context->curFrame;
|
||||
data["demoheader"]["playback_frames"] = data["demoheader"]["playback_frames"].get<int32_t>() - context->header.playback_frames + context->curFrame;
|
||||
}
|
||||
}
|
||||
|
||||
void Logic::End()
|
||||
{
|
||||
data["voice"]["total_time"] = voiceTotalTime;
|
||||
data["voice"]["active_time"] = voiceActiveTime;
|
||||
|
||||
|
@ -18,6 +18,7 @@ struct Logic
|
||||
|
||||
void Start();
|
||||
void Finish(bool dirty);
|
||||
void End();
|
||||
|
||||
struct
|
||||
{
|
||||
@ -41,6 +42,7 @@ struct Logic
|
||||
void OnRoundStart(int timelimit);
|
||||
void OnRoundEnd(const char *message, int reason, int winner);
|
||||
|
||||
int32_t tickBase = 0;
|
||||
int32_t curTick = 0;
|
||||
float voiceTotalTime = 0.0f;
|
||||
float voiceActiveTime = 0.0f;
|
||||
|
@ -52,6 +52,9 @@ bool SourceGameContext::init()
|
||||
}
|
||||
|
||||
voiceWriter = new VoiceDataWriter(this, outputDirVoice.c_str());
|
||||
if(!voiceWriter->init())
|
||||
return false;
|
||||
|
||||
logic = new Logic(this);
|
||||
return true;
|
||||
}
|
||||
@ -64,8 +67,20 @@ void SourceGameContext::Start()
|
||||
|
||||
void SourceGameContext::Finish(bool dirty)
|
||||
{
|
||||
voiceWriter->Finish();
|
||||
logic->Finish(dirty);
|
||||
voiceWriter->Finish();
|
||||
|
||||
for(int i = 0; i < MAX_PLAYERS; i++)
|
||||
players[i].connected = false;
|
||||
|
||||
curTick = -1;
|
||||
curFrame = -1;
|
||||
}
|
||||
|
||||
void SourceGameContext::End()
|
||||
{
|
||||
logic->End();
|
||||
voiceWriter->End();
|
||||
}
|
||||
|
||||
void SourceGameContext::StartCommandPacket(const CommandPacket& packet)
|
||||
@ -76,7 +91,7 @@ void SourceGameContext::StartCommandPacket(const CommandPacket& packet)
|
||||
return;
|
||||
|
||||
curTick = packet.tick;
|
||||
logic->curTick = curTick;
|
||||
logic->curTick = logic->tickBase + curTick;
|
||||
|
||||
voiceWriter->StartCommandPacket(packet);
|
||||
}
|
||||
|
@ -75,6 +75,7 @@ struct SourceGameContext
|
||||
|
||||
void Start();
|
||||
void Finish(bool dirty);
|
||||
void End();
|
||||
|
||||
void StartCommandPacket(const CommandPacket& packet);
|
||||
void EndCommandPacket(const PacketTrailingBits& trailingBits);
|
||||
|
@ -10,6 +10,9 @@
|
||||
#include "sourcesdk/bitbuf.h"
|
||||
#include <cstdint>
|
||||
|
||||
static NetHandlers::NetDataStructArray s_netDataStructs;
|
||||
static DemHandlers::DemDataStructArray s_demDataStructs;
|
||||
|
||||
PacketTrailingBits ParsePacket(uint8_t* packet, size_t length,
|
||||
SourceGameContext& context,
|
||||
const NetHandlers::NetDataStructArray& netDataStructs)
|
||||
@ -38,13 +41,20 @@ PacketTrailingBits ParsePacket(uint8_t* packet, size_t length,
|
||||
return trailingBits;
|
||||
}
|
||||
|
||||
void DemoReader::Init()
|
||||
{
|
||||
NetHandlers::CreateNetMsgStructs(s_netDataStructs);
|
||||
DemHandlers::CreateDemMsgStructs(s_demDataStructs);
|
||||
}
|
||||
|
||||
void DemoReader::DeInit()
|
||||
{
|
||||
DemHandlers::DestroyDemMsgStructs(s_demDataStructs);
|
||||
NetHandlers::DestroyNetMsgStructs(s_netDataStructs);
|
||||
}
|
||||
|
||||
bool DemoReader::ProcessDem(std::FILE* inputFp, SourceGameContext* context)
|
||||
{
|
||||
NetHandlers::NetDataStructArray netDataStructs;
|
||||
DemHandlers::DemDataStructArray demDataStructs;
|
||||
NetHandlers::CreateNetMsgStructs(netDataStructs);
|
||||
DemHandlers::CreateDemMsgStructs(demDataStructs);
|
||||
|
||||
DemoFileReader reader(inputFp);
|
||||
{
|
||||
reader.ReadDemoHeader(context->header);
|
||||
@ -59,7 +69,7 @@ bool DemoReader::ProcessDem(std::FILE* inputFp, SourceGameContext* context)
|
||||
do
|
||||
{
|
||||
reader.ReadCmdHeader(packet.cmd, packet.tick);
|
||||
packet.data = demDataStructs[packet.cmd];
|
||||
packet.data = s_demDataStructs[packet.cmd];
|
||||
DemHandlers::DemMsg_FileRead(packet.cmd, reader, packet.data);
|
||||
|
||||
PacketTrailingBits trailingBits = PacketTrailingBits();
|
||||
@ -68,7 +78,7 @@ bool DemoReader::ProcessDem(std::FILE* inputFp, SourceGameContext* context)
|
||||
if (packet.cmd == dem_packet || packet.cmd == dem_signon)
|
||||
{
|
||||
Array<uint8_t> buffer = reader.ReadRawData(NET_MAX_PAYLOAD);
|
||||
trailingBits = ParsePacket(buffer.begin(), buffer.length(), *context, netDataStructs);
|
||||
trailingBits = ParsePacket(buffer.begin(), buffer.length(), *context, s_netDataStructs);
|
||||
}
|
||||
|
||||
else if (packet.cmd == dem_stringtables)
|
||||
@ -100,8 +110,5 @@ bool DemoReader::ProcessDem(std::FILE* inputFp, SourceGameContext* context)
|
||||
|
||||
context->Finish(dirty);
|
||||
|
||||
DemHandlers::DestroyDemMsgStructs(demDataStructs);
|
||||
NetHandlers::DestroyNetMsgStructs(netDataStructs);
|
||||
|
||||
return !dirty;
|
||||
return dirty;
|
||||
}
|
||||
|
@ -5,5 +5,7 @@
|
||||
|
||||
namespace DemoReader
|
||||
{
|
||||
void Init();
|
||||
void DeInit();
|
||||
bool ProcessDem(std::FILE* inputFp, SourceGameContext* context);
|
||||
}
|
||||
|
@ -138,16 +138,26 @@ VoiceDataWriter::VoiceDataWriter(SourceGameContext* context, const char* outputP
|
||||
{
|
||||
}
|
||||
|
||||
void VoiceDataWriter::Start()
|
||||
bool VoiceDataWriter::init()
|
||||
{
|
||||
int error = CELT_OK;
|
||||
const CeltConfig& config = sCeltConfigs[sQuality];
|
||||
m_celtMode = celt_mode_create(config.sampleRate, config.frameSizeSamples, &error);
|
||||
assert(error == CELT_OK);
|
||||
assert(m_celtMode);
|
||||
return error == CELT_OK;
|
||||
}
|
||||
|
||||
void VoiceDataWriter::Start()
|
||||
{
|
||||
m_tickBase = m_curTick;
|
||||
}
|
||||
|
||||
void VoiceDataWriter::Finish()
|
||||
{
|
||||
}
|
||||
|
||||
void VoiceDataWriter::End()
|
||||
{
|
||||
if(m_isSilenced)
|
||||
{
|
||||
@ -175,7 +185,7 @@ void VoiceDataWriter::Finish()
|
||||
void VoiceDataWriter::StartCommandPacket(const CommandPacket& packet)
|
||||
{
|
||||
m_lastTick = m_curTick;
|
||||
m_curTick = packet.tick;
|
||||
m_curTick = m_tickBase + packet.tick;
|
||||
}
|
||||
|
||||
void VoiceDataWriter::EndCommandPacket(const PacketTrailingBits& trailingBits)
|
||||
@ -184,8 +194,8 @@ void VoiceDataWriter::EndCommandPacket(const PacketTrailingBits& trailingBits)
|
||||
if (m_curTick <= tickMargin)
|
||||
return;
|
||||
|
||||
// Skip silence if noone talks for at least 3 seconds
|
||||
if((m_curTick - m_lastVoiceTick) / context->fTickRate > 3.0)
|
||||
// Skip silence if noone talks for at least 1.5 seconds
|
||||
if((m_curTick - m_lastVoiceTick) / context->fTickRate > 1.5)
|
||||
{
|
||||
if(!m_isSilenced)
|
||||
{
|
||||
|
@ -54,9 +54,11 @@ class VoiceDataWriter
|
||||
{
|
||||
public:
|
||||
VoiceDataWriter(SourceGameContext *context, const char* outputPath);
|
||||
bool init();
|
||||
|
||||
void Start();
|
||||
void Finish();
|
||||
void End();
|
||||
|
||||
void StartCommandPacket(const CommandPacket& packet);
|
||||
void EndCommandPacket(const PacketTrailingBits& trailingBits);
|
||||
@ -95,6 +97,7 @@ private:
|
||||
eCodec m_Codec = CODEC_NONE;
|
||||
|
||||
public:
|
||||
int32_t m_tickBase = 0;
|
||||
bool m_isSilenced = false;
|
||||
std::vector<std::pair<int32_t, int32_t>> m_silence;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user