Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Modules/EngineDemoPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ std::string EngineDemoPlayer::GetLevelName() {
// 0x11: VPK internal checksums
// 0x12: incomplete speedrun summary
// 0x13: speedrun identifier
// 0x14: runtime vscript checksum
void EngineDemoPlayer::CustomDemoData(char *data, size_t length) {
if (data[0] == 0x03 || data[0] == 0x04) { // Entity input data
std::optional<int> slot;
Expand Down
27 changes: 27 additions & 0 deletions src/Modules/EngineDemoRecorder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,33 @@ static void RecordQueuedCommands() {
engine->demorecorder->queuedCommands.clear();
}

static void RecordQueuedVScriptChecksums() {
if (!engine->demorecorder->isRecordingDemo) return;
if (!engine->demorecorder->customDataReady) return;
if (engine->demorecorder->GetTick() < 0) return;

for (auto &queuedChecksum : engine->demorecorder->queuedVScriptChecksums) {
size_t nameLen = queuedChecksum.first.size();
size_t bufLen = nameLen + 6;
auto *buf = new uint8_t[bufLen];
buf[0] = 0x14;
*reinterpret_cast<uint32_t *>(buf + 1) = queuedChecksum.second;
strcpy(reinterpret_cast<char *>(buf + 5), queuedChecksum.first.c_str());
engine->demorecorder->RecordData(buf, bufLen);
delete[] buf;
}
engine->demorecorder->queuedVScriptChecksums.clear();
}

ON_EVENT(PRE_TICK) {
if (!engine->demorecorder->queuedVScriptChecksums.empty()) {
RecordQueuedVScriptChecksums();
}
}

ON_EVENT(SESSION_END) {
engine->demorecorder->queuedVScriptChecksums.clear();

if (*engine->demorecorder->m_bRecording && sar_autorecord.GetInt() == -1) {
engine->demorecorder->Stop();
}
Expand Down Expand Up @@ -172,6 +198,7 @@ DETOUR(EngineDemoRecorder::SetSignonState, int state) {
RecordTimestamp();
SpeedrunTimer::WriteIdToDemo(); // Write speedrun ID to every demo segment
RecordQueuedCommands();
RecordQueuedVScriptChecksums();
SpeedrunTimer::RecordIncompleteSummary();
engine->ExecuteCommand("echo \"SAR " SAR_VERSION " (Built " SAR_BUILT ")\"", true);
AddDemoFileChecksums();
Expand Down
3 changes: 3 additions & 0 deletions src/Modules/EngineDemoRecorder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include "Utils.hpp"

#include <string>
#include <utility>
#include <vector>

// Ticks before demo autostop
#define DEMO_AUTOSTOP_DELAY 15
Expand All @@ -28,6 +30,7 @@ class EngineDemoRecorder : public Module {
int autorecordStartNum = 1;

std::vector<std::string> queuedCommands = {};
std::vector<std::pair<std::string, uint32_t>> queuedVScriptChecksums = {};

char coopRadialMenuLastPos[8];

Expand Down
79 changes: 79 additions & 0 deletions src/Modules/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "Offsets.hpp"
#include "Utils.hpp"
#include "Variable.hpp"
#include "Utils/lodepng.hpp"

#include "Features/OverlayRender.hpp"

Expand Down Expand Up @@ -336,6 +337,70 @@ static bool FindClosestPassableSpace_Detour(void *entity, const Vector &ind_push
Hook FindClosestPassableSpace_Hook(&FindClosestPassableSpace_Detour);

static int (*UTIL_GetCommandClientIndex)();
static constexpr uint8_t SAR_MSG_VSCRIPT_RUNTIME_CHECKSUM = 0x14;

static size_t BoundedCStringLen(const char *str, size_t maxLen) {
if (!str) return 0;
size_t len = 0;
while (len < maxLen && str[len]) ++len;
return len;
}

static void RecordRuntimeVscriptChecksum(const char *scriptName, const char *scriptData) {
if (!scriptName || !*scriptName || !scriptData || !*scriptData) return;

// Meant to avoid an unbounded C-String search in case a file data ever isn't null-terminated
constexpr size_t MAX_SCRIPT_SIZE = 8 * 1024 * 1024;
size_t scriptLen = BoundedCStringLen(scriptData, MAX_SCRIPT_SIZE);
if (scriptLen == 0) return;

uint32_t sum = 0;
if (scriptLen < MAX_SCRIPT_SIZE) {
sum = lodepng_crc32(reinterpret_cast<const unsigned char *>(scriptData), scriptLen);
}

if (engine->demorecorder->isRecordingDemo && engine->demorecorder->GetTick() >= 0) {
size_t nameLen = strlen(scriptName);
size_t bufLen = nameLen + 6;
auto *buf = new uint8_t[bufLen];
buf[0] = SAR_MSG_VSCRIPT_RUNTIME_CHECKSUM;
*reinterpret_cast<uint32_t *>(buf + 1) = sum;
strcpy(reinterpret_cast<char *>(buf + 5), scriptName);
engine->demorecorder->RecordData(buf, bufLen);
delete[] buf;
} else {
engine->demorecorder->queuedVScriptChecksums.emplace_back(scriptName, sum);
}
}

#ifdef _WIN32
using _VScript_CompileScript = int(__rescall *)(void *thisptr, const char *scriptData, const char *scriptName);
#else
using _VScript_CompileScript = int(__cdecl *)(void *thisptr, const char *scriptData, const char *scriptName);
#endif
static _VScript_CompileScript VScript_CompileScript;
extern Hook g_VScriptCompileScriptHook;
#ifdef _WIN32
static int __fastcall VScript_CompileScript_Hook(void *thisptr, int edx, const char *scriptData, const char *scriptName)
#else
static int __cdecl VScript_CompileScript_Hook(void *thisptr, const char *scriptData, const char *scriptName)
#endif
{
#ifdef _WIN32
(void)edx;
#endif
(void)thisptr;

if (scriptName && *scriptName) {
RecordRuntimeVscriptChecksum(scriptName, scriptData);
}

g_VScriptCompileScriptHook.Disable();
auto ret = VScript_CompileScript(thisptr, scriptData, scriptName);
g_VScriptCompileScriptHook.Enable();
return ret;
}
Hook g_VScriptCompileScriptHook(&VScript_CompileScript_Hook);

extern Hook g_ViewPunch_Hook;
DETOUR_T(void, Server::ViewPunch, const QAngle &offset) {
Expand Down Expand Up @@ -969,6 +1034,20 @@ bool Server::Init() {
if (sar.game->Is(SourceGame_Portal2 | SourceGame_Portal2_2011)) {
Server::IsInPVS = (Server::_IsInPVS)Memory::Scan(this->Name(), Offsets::IsInPVS);
g_IsInPVS_Hook.SetFunc(IsInPVS);

#ifdef _WIN32
const char *vscriptModuleName = "vscript.dll";
#else
const char *vscriptModuleName = "vscript.so";
#endif

auto vscriptCompileScript = Memory::Absolute<uintptr_t>(vscriptModuleName, Offsets::VScript_CompileScript);
if (vscriptCompileScript) {
VScript_CompileScript = reinterpret_cast<_VScript_CompileScript>(vscriptCompileScript);
g_VScriptCompileScriptHook.SetFunc(VScript_CompileScript);
} else {
console->Warning("[sar] failed to find VScript_CompileScript at offset 0x%X\n", Offsets::VScript_CompileScript);
}
}

NetMessage::RegisterHandler(RESET_COOP_PROGRESS_MESSAGE_TYPE, &netResetCoopProgress);
Expand Down
1 change: 1 addition & 0 deletions src/Offsets/Portal 2 9568.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ OFFSET_DEFAULT(GetModel, 8, 8)
// Others
OFFSET_DEFAULT(tickcount, 95, 64)
OFFSET_DEFAULT(interval_per_tick, 65, 58)
OFFSET_DEFAULT(VScript_CompileScript, 0x28B50, 0x615D0)
OFFSET_DEFAULT(GetClientStateFunction, 4, 9)
OFFSET_EMPTY(cl)
OFFSET_DEFAULT(demoplayer, 74, 80)
Expand Down
Loading