Files
DoomRTX/neo/engine/tools/engine_stubs.cpp
T
2026-05-18 21:35:07 -07:00

1688 lines
35 KiB
C++

// engine_stubs.cpp
//
#include "precompiled.h"
#include <windows.h>
#include <direct.h>
#include <io.h>
class idCommonStub : public idCommon {
public:
idCommonStub();
virtual ~idCommonStub();
virtual void Init(int argc, const char** argv, const char* cmdline);
virtual void Shutdown(void);
virtual void Quit(void);
virtual bool IsInitialized(void) const;
virtual void Frame(void);
virtual void GUIFrame(bool execCmd, bool network);
virtual void StartupVariable(const char* match, bool once);
#ifdef QUAKE4
virtual int GetUserCmdHz(void) const;
virtual int GetUserCmdMSec(void) const;
virtual int GetFrameTime(void) const;
virtual bool IsRenderableGameFrame(void) const;
virtual void SetRenderableGameFrame(bool in);
virtual const char* GetErrorMessage(void) const;
virtual bool IsToolActive(void) const;
#ifdef _RV_MEM_SYS_SUPPORT
virtual void InitHeaps(void);
virtual void ShutdownHeaps(void);
#endif
virtual void RunAlwaysThinkGUIs(int time);
virtual bool DoingDeclValidation(void);
virtual void SetCrashReportAutoSendString(const char* psString);
#endif
virtual void InitTool(const toolFlag_t tool, const idDict* dict);
virtual void ActivateTool(bool active);
virtual void WriteConfigToFile(const char* filename);
virtual void WriteFlaggedCVarsToFile(const char* filename, int flags, const char* setCmd);
#ifdef QUAKE4
virtual void BeginRedirect(char* buffer, int buffersize, void (*flush)(const char*), bool rcon = false);
#else
virtual void BeginRedirect(char* buffer, int buffersize, void (*flush)(const char*));
#endif
virtual void EndRedirect(void);
virtual void SetRefreshOnPrint(bool set);
virtual void Printf(const char* fmt, ...) id_attribute((format(printf, 2, 3)));
virtual void VPrintf(const char* fmt, va_list arg);
virtual void DPrintf(const char* fmt, ...) id_attribute((format(printf, 2, 3)));
virtual void Warning(const char* fmt, ...) id_attribute((format(printf, 2, 3)));
virtual void DWarning(const char* fmt, ...) id_attribute((format(printf, 2, 3)));
virtual void PrintWarnings(void);
virtual void ClearWarnings(const char* reason);
virtual void Error(const char* fmt, ...) id_attribute((format(printf, 2, 3)));
virtual void FatalError(const char* fmt, ...) id_attribute((format(printf, 2, 3)));
#ifdef QUAKE4
virtual void DumpWarnings(void);
#endif
virtual const idLangDict* GetLanguageDict(void);
#ifdef QUAKE4
virtual const char* GetLocalizedString(const char* token, int langIndex = -1);
virtual const idLangKeyValue* GetLocalizedString(int index, int langIndex = -1);
virtual int GetNumLanguages(void) const;
virtual int GetNumLocalizedStrings(void) const;
virtual const char* GetLanguage(int index) const;
virtual bool LanguageHasVO(int index) const;
#endif
virtual const char* KeysFromBinding(const char* bind);
virtual const char* BindingFromKey(const char* key);
virtual int ButtonState(int key);
virtual int KeyState(int key);
#ifdef QUAKE4
virtual int GetRModeForMachineSpec(int machineSpec) const;
virtual void SetDesiredMachineSpec(int machineSpec);
virtual bool IsRCon(void) const;
#endif
#ifdef PREY
virtual void MaterialKeyForBinding(const char* binding, char* materialName, char* keyText, bool* wideKey);
#endif
virtual float Get_com_engineHz_latched(void);
virtual int64_t Get_com_engineHz_numerator(void);
virtual int64_t Get_com_engineHz_denominator(void);
private:
void OutputString(const char* prefix, const char* text);
void VOutputf(const char* prefix, const char* fmt, va_list args);
private:
bool initialized;
bool quitRequested;
bool refreshOnPrint;
#ifdef QUAKE4
bool renderableGameFrame;
bool toolActive;
char errorMessage[4096];
#endif
char* redirectBuffer;
int redirectBufferSize;
int redirectBufferUsed;
void (*redirectFlush)(const char*);
};
idCommonStub commonLocal;
idCommon* common = &commonLocal;
idCommonStub::idCommonStub() {
initialized = false;
quitRequested = false;
refreshOnPrint = false;
#ifdef QUAKE4
renderableGameFrame = true;
toolActive = false;
errorMessage[0] = '\0';
#endif
redirectBuffer = NULL;
redirectBufferSize = 0;
redirectBufferUsed = 0;
redirectFlush = NULL;
}
idCommonStub::~idCommonStub() {
Shutdown();
}
void idCommonStub::OutputString(const char* prefix, const char* text) {
if (!text) {
text = "";
}
char finalBuffer[8192];
if (prefix && prefix[0]) {
idStr::snPrintf(finalBuffer, sizeof(finalBuffer), "%s%s", prefix, text);
}
else {
idStr::snPrintf(finalBuffer, sizeof(finalBuffer), "%s", text);
}
finalBuffer[sizeof(finalBuffer) - 1] = '\0';
if (redirectBuffer && redirectBufferSize > 0) {
const int len = (int)strlen(finalBuffer);
const int remaining = redirectBufferSize - redirectBufferUsed - 1;
if (remaining > 0) {
const int copyLen = len < remaining ? len : remaining;
memcpy(redirectBuffer + redirectBufferUsed, finalBuffer, copyLen);
redirectBufferUsed += copyLen;
redirectBuffer[redirectBufferUsed] = '\0';
}
if (redirectFlush) {
redirectFlush(finalBuffer);
}
}
fputs(finalBuffer, stdout);
fflush(stdout);
#ifdef _WIN32
OutputDebugStringA(finalBuffer);
#endif
}
void idCommonStub::VOutputf(const char* prefix, const char* fmt, va_list args) {
if (!fmt) {
OutputString(prefix, "\n");
return;
}
char buffer[8192];
idStr::vsnPrintf(buffer, sizeof(buffer), fmt, args);
buffer[sizeof(buffer) - 1] = '\0';
OutputString(prefix, buffer);
}
void idCommonStub::Init(int argc, const char** argv, const char* cmdline) {
initialized = true;
quitRequested = false;
Printf("idCommonStub::Init argc=%d cmdline=\"%s\"\n", argc, cmdline ? cmdline : "");
}
void idCommonStub::Shutdown(void) {
if (initialized) {
Printf("idCommonStub::Shutdown\n");
}
initialized = false;
}
void idCommonStub::Quit(void) {
quitRequested = true;
Printf("idCommonStub::Quit\n");
}
bool idCommonStub::IsInitialized(void) const {
return initialized;
}
void idCommonStub::Frame(void) {
// Stub.
}
void idCommonStub::GUIFrame(bool execCmd, bool network) {
// Stub.
}
void idCommonStub::StartupVariable(const char* match, bool once) {
// Stub.
}
#ifdef QUAKE4
int idCommonStub::GetUserCmdHz(void) const {
return 60;
}
int idCommonStub::GetUserCmdMSec(void) const {
return 16;
}
int idCommonStub::GetFrameTime(void) const {
return 16;
}
bool idCommonStub::IsRenderableGameFrame(void) const {
return renderableGameFrame;
}
void idCommonStub::SetRenderableGameFrame(bool in) {
renderableGameFrame = in;
}
const char* idCommonStub::GetErrorMessage(void) const {
return errorMessage;
}
bool idCommonStub::IsToolActive(void) const {
return toolActive;
}
#ifdef _RV_MEM_SYS_SUPPORT
void idCommonStub::InitHeaps(void) {
// Stub.
}
void idCommonStub::ShutdownHeaps(void) {
// Stub.
}
#endif
void idCommonStub::RunAlwaysThinkGUIs(int time) {
// Stub.
}
bool idCommonStub::DoingDeclValidation(void) {
return false;
}
void idCommonStub::SetCrashReportAutoSendString(const char* psString) {
// Stub.
}
#endif
void idCommonStub::InitTool(const toolFlag_t tool, const idDict* dict) {
#ifdef QUAKE4
toolActive = true;
#endif
Printf("idCommonStub::InitTool\n");
}
void idCommonStub::ActivateTool(bool active) {
#ifdef QUAKE4
toolActive = active;
#endif
Printf("idCommonStub::ActivateTool active=%d\n", active ? 1 : 0);
}
void idCommonStub::WriteConfigToFile(const char* filename) {
Printf("idCommonStub::WriteConfigToFile \"%s\"\n", filename ? filename : "");
}
void idCommonStub::WriteFlaggedCVarsToFile(const char* filename, int flags, const char* setCmd) {
Printf("idCommonStub::WriteFlaggedCVarsToFile \"%s\" flags=%d setCmd=\"%s\"\n",
filename ? filename : "",
flags,
setCmd ? setCmd : "");
}
#ifdef QUAKE4
void idCommonStub::BeginRedirect(char* buffer, int buffersize, void (*flush)(const char*), bool rcon) {
#else
void idCommonStub::BeginRedirect(char* buffer, int buffersize, void (*flush)(const char*)) {
#endif
redirectBuffer = buffer;
redirectBufferSize = buffersize;
redirectBufferUsed = 0;
redirectFlush = flush;
if (redirectBuffer && redirectBufferSize > 0) {
redirectBuffer[0] = '\0';
}
#ifdef QUAKE4
Printf("idCommonStub::BeginRedirect rcon=%d\n", rcon ? 1 : 0);
#else
Printf("idCommonStub::BeginRedirect\n");
#endif
}
void idCommonStub::EndRedirect(void) {
if (redirectFlush && redirectBuffer) {
redirectFlush(redirectBuffer);
}
redirectBuffer = NULL;
redirectBufferSize = 0;
redirectBufferUsed = 0;
redirectFlush = NULL;
}
void idCommonStub::SetRefreshOnPrint(bool set) {
refreshOnPrint = set;
}
void idCommonStub::Printf(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
VPrintf(fmt, args);
va_end(args);
}
void idCommonStub::VPrintf(const char* fmt, va_list arg) {
VOutputf("", fmt, arg);
}
void idCommonStub::DPrintf(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
VOutputf("DEBUG: ", fmt, args);
va_end(args);
}
void idCommonStub::Warning(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
VOutputf("WARNING: ", fmt, args);
va_end(args);
}
void idCommonStub::DWarning(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
VOutputf("DWARNING: ", fmt, args);
va_end(args);
}
void idCommonStub::PrintWarnings(void) {
Printf("idCommonStub::PrintWarnings: no queued warnings.\n");
}
void idCommonStub::ClearWarnings(const char* reason) {
Printf("idCommonStub::ClearWarnings reason=\"%s\"\n", reason ? reason : "");
}
void idCommonStub::Error(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
VOutputf("ERROR: ", fmt, args);
va_end(args);
#ifdef QUAKE4
va_list args2;
va_start(args2, fmt);
idStr::vsnPrintf(errorMessage, sizeof(errorMessage), fmt ? fmt : "", args2);
errorMessage[sizeof(errorMessage) - 1] = '\0';
va_end(args2);
#endif
// Stub behavior: do not throw unless you want this to behave like real common.
// throw idException( "idCommonStub::Error" );
}
void idCommonStub::FatalError(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
VOutputf("FATAL: ", fmt, args);
va_end(args);
#ifdef QUAKE4
va_list args2;
va_start(args2, fmt);
idStr::vsnPrintf(errorMessage, sizeof(errorMessage), fmt ? fmt : "", args2);
errorMessage[sizeof(errorMessage) - 1] = '\0';
va_end(args2);
#endif
#ifdef _WIN32
MessageBeep(MB_ICONERROR);
#endif
// Stub behavior: do not exit unless you want this to behave like real common.
// Sys_Quit();
}
#ifdef QUAKE4
void idCommonStub::DumpWarnings(void) {
Printf("idCommonStub::DumpWarnings: no queued warnings.\n");
}
#endif
const idLangDict* idCommonStub::GetLanguageDict(void) {
return NULL;
}
#ifdef QUAKE4
const char* idCommonStub::GetLocalizedString(const char* token, int langIndex) {
return token ? token : "";
}
const idLangKeyValue* idCommonStub::GetLocalizedString(int index, int langIndex) {
return NULL;
}
int idCommonStub::GetNumLanguages(void) const {
return 1;
}
int idCommonStub::GetNumLocalizedStrings(void) const {
return 0;
}
const char* idCommonStub::GetLanguage(int index) const {
return "english";
}
bool idCommonStub::LanguageHasVO(int index) const {
return false;
}
#endif
const char* idCommonStub::KeysFromBinding(const char* bind) {
return "";
}
const char* idCommonStub::BindingFromKey(const char* key) {
return "";
}
int idCommonStub::ButtonState(int key) {
return 0;
}
int idCommonStub::KeyState(int key) {
return 0;
}
#ifdef QUAKE4
int idCommonStub::GetRModeForMachineSpec(int machineSpec) const {
return -1;
}
void idCommonStub::SetDesiredMachineSpec(int machineSpec) {
Printf("idCommonStub::SetDesiredMachineSpec %d\n", machineSpec);
}
bool idCommonStub::IsRCon(void) const {
return false;
}
#endif
#ifdef PREY
void idCommonStub::MaterialKeyForBinding(const char* binding, char* materialName, char* keyText, bool* wideKey) {
if (materialName) {
materialName[0] = '\0';
}
if (keyText) {
keyText[0] = '\0';
}
if (wideKey) {
*wideKey = false;
}
}
#endif
float idCommonStub::Get_com_engineHz_latched(void) {
return 60.0f;
}
int64_t idCommonStub::Get_com_engineHz_numerator(void) {
return 60;
}
int64_t idCommonStub::Get_com_engineHz_denominator(void) {
return 1;
}
class idDeclManagerStub : public idDeclManager {
public:
idDeclManagerStub() {
initialized = false;
checksum = 0;
}
virtual ~idDeclManagerStub(void) {
Shutdown();
}
private:
bool initialized;
int checksum;
void StubPrint(const char* fmt, ...) const {
char buffer[4096];
va_list args;
va_start(args, fmt);
#if defined(_WIN32)
_vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, fmt ? fmt : "", args);
#else
vsnprintf(buffer, sizeof(buffer), fmt ? fmt : "", args);
buffer[sizeof(buffer) - 1] = '\0';
#endif
va_end(args);
if (common) {
common->Printf("%s", buffer);
}
else {
fputs(buffer, stdout);
fflush(stdout);
#ifdef _WIN32
OutputDebugStringA(buffer);
#endif
}
}
public:
virtual void Init(void) {
initialized = true;
StubPrint("idDeclManagerStub::Init\n");
}
virtual void Shutdown(void) {
if (initialized) {
StubPrint("idDeclManagerStub::Shutdown\n");
}
initialized = false;
}
virtual void Reload(bool force) {
StubPrint("idDeclManagerStub::Reload force=%d\n", force ? 1 : 0);
}
virtual void BeginLevelLoad(void) {
StubPrint("idDeclManagerStub::BeginLevelLoad\n");
}
virtual void EndLevelLoad(void) {
StubPrint("idDeclManagerStub::EndLevelLoad\n");
}
virtual void RegisterDeclType(const char* typeName, declType_t type, idDecl* (*allocator)(void)) {
StubPrint("idDeclManagerStub::RegisterDeclType typeName=\"%s\" type=%d\n", typeName ? typeName : "", (int)type);
}
virtual void RegisterDeclFolder(const char* folder, const char* extension, declType_t defaultType) {
StubPrint(
"idDeclManagerStub::RegisterDeclFolder folder=\"%s\" extension=\"%s\" defaultType=%d\n",
folder ? folder : "",
extension ? extension : "",
(int)defaultType
);
}
virtual int GetChecksum(void) const {
return checksum;
}
virtual int GetNumDeclTypes(void) const {
return 0;
}
virtual const char* GetDeclNameFromType(declType_t type) const {
return "";
}
virtual declType_t GetDeclTypeFromName(const char* typeName) const {
return DECL_MAX_TYPES;
}
virtual const idDecl* FindType(declType_t type, const char* name, bool makeDefault = true) {
StubPrint(
"idDeclManagerStub::FindType type=%d name=\"%s\" makeDefault=%d\n",
(int)type,
name ? name : "",
makeDefault ? 1 : 0
);
return NULL;
}
#ifdef QUAKE4
virtual const idDecl* FindType(declType_t type, const char* name, bool makeDefault, bool noCaching) {
StubPrint(
"idDeclManagerStub::FindType type=%d name=\"%s\" makeDefault=%d noCaching=%d\n",
(int)type,
name ? name : "",
makeDefault ? 1 : 0,
noCaching ? 1 : 0
);
return FindType(type, name, makeDefault);
}
#endif
virtual const idDecl* FindDeclWithoutParsing(declType_t type, const char* name, bool makeDefault = true) {
StubPrint(
"idDeclManagerStub::FindDeclWithoutParsing type=%d name=\"%s\" makeDefault=%d\n",
(int)type,
name ? name : "",
makeDefault ? 1 : 0
);
return NULL;
}
virtual void ReloadFile(const char* filename, bool force) {
StubPrint(
"idDeclManagerStub::ReloadFile filename=\"%s\" force=%d\n",
filename ? filename : "",
force ? 1 : 0
);
}
virtual int GetNumDecls(declType_t type) {
return 0;
}
virtual const idDecl* DeclByIndex(declType_t type, int index, bool forceParse = true) {
StubPrint(
"idDeclManagerStub::DeclByIndex type=%d index=%d forceParse=%d\n",
(int)type,
index,
forceParse ? 1 : 0
);
return NULL;
}
virtual void ListType(const idCmdArgs& args, declType_t type) {
StubPrint("idDeclManagerStub::ListType type=%d\n", (int)type);
}
virtual void PrintType(const idCmdArgs& args, declType_t type) {
StubPrint("idDeclManagerStub::PrintType type=%d\n", (int)type);
}
virtual bool CreateDeclFile(const char* fileName, declType_t defaultType) {
StubPrint(
"idDeclManagerStub::CreateDeclFile fileName=\"%s\" defaultType=%d\n",
fileName ? fileName : "",
(int)defaultType
);
return false;
}
virtual idDecl* CreateNewDecl(declType_t type, const char* name, const char* fileName, bool save = true) {
StubPrint(
"idDeclManagerStub::CreateNewDecl type=%d name=\"%s\" fileName=\"%s\" save=%d\n",
(int)type,
name ? name : "",
fileName ? fileName : "",
save ? 1 : 0
);
return NULL;
}
virtual bool SetDeclText(declType_t type, const char* name, const char* text, bool parse = true, bool save = false) {
StubPrint(
"idDeclManagerStub::SetDeclText type=%d name=\"%s\" parse=%d save=%d\n",
(int)type,
name ? name : "",
parse ? 1 : 0,
save ? 1 : 0
);
return false;
}
virtual bool SaveDecl(declType_t type, const char* name) {
StubPrint(
"idDeclManagerStub::SaveDecl type=%d name=\"%s\"\n",
(int)type,
name ? name : ""
);
return false;
}
virtual bool DeleteDecl(declType_t type, const char* name, bool deleteSourceText = true) {
StubPrint(
"idDeclManagerStub::DeleteDecl type=%d name=\"%s\" deleteSourceText=%d\n",
(int)type,
name ? name : "",
deleteSourceText ? 1 : 0
);
return false;
}
virtual bool RenameDecl(declType_t type, const char* oldName, const char* newName) {
StubPrint(
"idDeclManagerStub::RenameDecl type=%d oldName=\"%s\" newName=\"%s\"\n",
(int)type,
oldName ? oldName : "",
newName ? newName : ""
);
return false;
}
virtual void MediaPrint(const char* fmt, ...) id_attribute((format(printf, 2, 3))) {
char buffer[4096];
va_list args;
va_start(args, fmt);
#if defined(_WIN32)
_vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, fmt ? fmt : "", args);
#else
vsnprintf(buffer, sizeof(buffer), fmt ? fmt : "", args);
buffer[sizeof(buffer) - 1] = '\0';
#endif
va_end(args);
StubPrint("MEDIA: %s", buffer);
}
virtual void WritePrecacheCommands(idFile* f) {
StubPrint("idDeclManagerStub::WritePrecacheCommands\n");
}
#ifdef QUAKE4
virtual void ParseGuides(void) {
StubPrint("idDeclManagerStub::ParseGuides\n");
}
virtual void ShutdownGuides(void) {
StubPrint("idDeclManagerStub::ShutdownGuides\n");
}
virtual bool EvaluateGuide(idStr& name, idLexer* src, idStr& definition) {
StubPrint("idDeclManagerStub::EvaluateGuide name=\"%s\"\n", name.c_str());
return false;
}
virtual bool EvaluateInlineGuide(idStr& name, idStr& definition) {
StubPrint("idDeclManagerStub::EvaluateInlineGuide name=\"%s\"\n", name.c_str());
return false;
}
#endif
virtual const idMaterial* FindMaterial(const char* name, bool makeDefault = true) {
StubPrint(
"idDeclManagerStub::FindMaterial name=\"%s\" makeDefault=%d\n",
name ? name : "",
makeDefault ? 1 : 0
);
return NULL;
}
virtual const idDeclSkin* FindSkin(const char* name, bool makeDefault = true) {
StubPrint(
"idDeclManagerStub::FindSkin name=\"%s\" makeDefault=%d\n",
name ? name : "",
makeDefault ? 1 : 0
);
return NULL;
}
virtual const idSoundShader* FindSound(const char* name, bool makeDefault = true) {
StubPrint(
"idDeclManagerStub::FindSound name=\"%s\" makeDefault=%d\n",
name ? name : "",
makeDefault ? 1 : 0
);
return NULL;
}
virtual const idMaterial* MaterialByIndex(int index, bool forceParse = true) {
StubPrint(
"idDeclManagerStub::MaterialByIndex index=%d forceParse=%d\n",
index,
forceParse ? 1 : 0
);
return NULL;
}
virtual const idDeclSkin* SkinByIndex(int index, bool forceParse = true) {
StubPrint(
"idDeclManagerStub::SkinByIndex index=%d forceParse=%d\n",
index,
forceParse ? 1 : 0
);
return NULL;
}
virtual const idSoundShader* SoundByIndex(int index, bool forceParse = true) {
StubPrint(
"idDeclManagerStub::SoundByIndex index=%d forceParse=%d\n",
index,
forceParse ? 1 : 0
);
return NULL;
}
virtual const class idDeclTable* FindTable(const char* name, bool makeDefault = true) {
StubPrint(
"idDeclManagerStub::FindTable name=\"%s\" makeDefault=%d\n",
name ? name : "",
makeDefault ? 1 : 0
);
return NULL;
}
#ifdef QUAKE4
virtual const class rvDeclMatType* FindMaterialType(const char* name, bool makeDefault = true) {
StubPrint(
"idDeclManagerStub::FindMaterialType name=\"%s\" makeDefault=%d\n",
name ? name : "",
makeDefault ? 1 : 0
);
return NULL;
}
virtual const class rvDeclLipSync* FindLipSync(const char* name, bool makeDefault = true) {
StubPrint(
"idDeclManagerStub::FindLipSync name=\"%s\" makeDefault=%d\n",
name ? name : "",
makeDefault ? 1 : 0
);
return NULL;
}
virtual const class rvDeclPlayback* FindPlayback(const char* name, bool makeDefault = true) {
StubPrint(
"idDeclManagerStub::FindPlayback name=\"%s\" makeDefault=%d\n",
name ? name : "",
makeDefault ? 1 : 0
);
return NULL;
}
virtual const class rvDeclEffect* FindEffect(const char* name, bool makeDefault = true) {
StubPrint(
"idDeclManagerStub::FindEffect name=\"%s\" makeDefault=%d\n",
name ? name : "",
makeDefault ? 1 : 0
);
return NULL;
}
virtual const class rvDeclMatType* MaterialTypeByIndex(int index, bool forceParse = true) {
StubPrint(
"idDeclManagerStub::MaterialTypeByIndex index=%d forceParse=%d\n",
index,
forceParse ? 1 : 0
);
return NULL;
}
virtual const class rvDeclLipSync* LipSyncByIndex(int index, bool forceParse = true) {
StubPrint(
"idDeclManagerStub::LipSyncByIndex index=%d forceParse=%d\n",
index,
forceParse ? 1 : 0
);
return NULL;
}
virtual const class rvDeclPlayback* PlaybackByIndex(int index, bool forceParse = true) {
StubPrint(
"idDeclManagerStub::PlaybackByIndex index=%d forceParse=%d\n",
index,
forceParse ? 1 : 0
);
return NULL;
}
virtual const class rvDeclEffect* EffectByIndex(int index, bool forceParse = true) {
StubPrint(
"idDeclManagerStub::EffectByIndex index=%d forceParse=%d\n",
index,
forceParse ? 1 : 0
);
return NULL;
}
#endif
};
idDeclManagerStub declManagerLocal;
idDeclManager* declManager = &declManagerLocal;
#ifndef MAX_OSPATH
#define MAX_OSPATH 256
#endif
#ifndef MAX_SYS_STUB_EVENTS
#define MAX_SYS_STUB_EVENTS 64
#endif
#ifndef MAX_SYS_STUB_CRITICAL_SECTIONS
#define MAX_SYS_STUB_CRITICAL_SECTIONS 64
#endif
#ifndef MAX_SYS_STUB_THREADS
#define MAX_SYS_STUB_THREADS 64
#endif
/*
===============================================================================
Globals expected by other code
===============================================================================
*/
idSys* sys = NULL;
idEventLoop* eventLoop = NULL;
int g_thread_count = 0;
static xthreadInfo* sys_stub_thread_storage[MAX_SYS_STUB_THREADS];
xthreadInfo* g_threads[MAX_THREADS];
/*
===============================================================================
com_developer
If this constructor does not match your branch, change only this one line.
Doom 3-style branches usually support:
idCVar( name, value, flags, description )
===============================================================================
*/
#ifndef CVAR_BOOL
#define CVAR_BOOL 0
#endif
#ifndef CVAR_SYSTEM
#define CVAR_SYSTEM 0
#endif
idCVar com_developer(
"developer",
"0",
CVAR_SYSTEM | CVAR_BOOL,
"Stubbed developer cvar"
);
/*
===============================================================================
Debug/helper functions
===============================================================================
*/
static void SysStub_DebugPrint(const char* text) {
if (!text) {
return;
}
#ifdef _WIN32
OutputDebugStringA(text);
#endif
fputs(text, stdout);
fflush(stdout);
}
static void SysStub_NormalizeSlashes(char* path) {
if (!path) {
return;
}
for (char* p = path; *p; p++) {
if (*p == '\\') {
*p = '/';
}
}
}
static void SysStub_CopyString(char* dst, int dstSize, const char* src) {
if (!dst || dstSize <= 0) {
return;
}
if (!src) {
src = "";
}
#ifdef _WIN32
strncpy_s(dst, dstSize, src, _TRUNCATE);
#else
strncpy(dst, src, dstSize - 1);
dst[dstSize - 1] = '\0';
#endif
}
static bool SysStub_StringEndsWith(const char* text, const char* suffix) {
if (!text || !suffix) {
return false;
}
const size_t textLen = strlen(text);
const size_t suffixLen = strlen(suffix);
if (suffixLen > textLen) {
return false;
}
#ifdef _WIN32
return _stricmp(text + textLen - suffixLen, suffix) == 0;
#else
return strcasecmp(text + textLen - suffixLen, suffix) == 0;
#endif
}
static const char* SysStub_GetExePathFull(void) {
static char exePath[MAX_OSPATH];
exePath[0] = '\0';
#ifdef _WIN32
GetModuleFileNameA(NULL, exePath, sizeof(exePath));
exePath[sizeof(exePath) - 1] = '\0';
#else
ssize_t len = readlink("/proc/self/exe", exePath, sizeof(exePath) - 1);
if (len > 0) {
exePath[len] = '\0';
}
else if (getcwd(exePath, sizeof(exePath)) == NULL) {
strcpy(exePath, ".");
}
#endif
SysStub_NormalizeSlashes(exePath);
if (exePath[0] == '\0') {
strcpy(exePath, ".");
}
return exePath;
}
static const char* SysStub_GetExeDirectory(void) {
static char exeDir[MAX_OSPATH];
SysStub_CopyString(exeDir, sizeof(exeDir), SysStub_GetExePathFull());
SysStub_NormalizeSlashes(exeDir);
char* lastSlash = strrchr(exeDir, '/');
if (lastSlash) {
*lastSlash = '\0';
}
if (exeDir[0] == '\0') {
strcpy(exeDir, ".");
}
return exeDir;
}
static bool SysStub_IsDirectory(const char* path) {
if (!path || !path[0]) {
return false;
}
#ifdef _WIN32
DWORD attribs = GetFileAttributesA(path);
if (attribs == INVALID_FILE_ATTRIBUTES) {
return false;
}
return (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0;
#else
struct stat st;
if (stat(path, &st) != 0) {
return false;
}
return S_ISDIR(st.st_mode);
#endif
}
/*
===============================================================================
Sys_FileTimeStamp
Required linker symbol:
__int64 __cdecl Sys_FileTimeStamp( struct _iobuf * )
===============================================================================
*/
int64_t Sys_FileTimeStamp(FILE* fp) {
if (!fp) {
return 0;
}
#ifdef _WIN32
const int fd = _fileno(fp);
if (fd < 0) {
return 0;
}
HANDLE hFile = (HANDLE)_get_osfhandle(fd);
if (hFile == INVALID_HANDLE_VALUE) {
return 0;
}
FILETIME writeTime;
if (!GetFileTime(hFile, NULL, NULL, &writeTime)) {
return 0;
}
ULARGE_INTEGER uli;
uli.LowPart = writeTime.dwLowDateTime;
uli.HighPart = writeTime.dwHighDateTime;
// FILETIME is 100ns ticks since Jan 1 1601.
// Unix timestamp is seconds since Jan 1 1970.
const uint64_t windowsTicks = uli.QuadPart;
const uint64_t unixTicks = windowsTicks - 116444736000000000ULL;
return (int64_t)(unixTicks / 10000000ULL);
#else
const int fd = fileno(fp);
if (fd < 0) {
return 0;
}
struct stat st;
if (fstat(fd, &st) != 0) {
return 0;
}
return (int64_t)st.st_mtime;
#endif
}
/*
===============================================================================
Paths
===============================================================================
*/
const char* Sys_EXEPath(void) {
return SysStub_GetExeDirectory();
}
const char* Sys_DefaultBasePath(void) {
return SysStub_GetExeDirectory();
}
const char* Sys_DefaultSavePath(void) {
return SysStub_GetExeDirectory();
}
const char* Sys_DefaultCDPath(void) {
return "";
}
/*
===============================================================================
Sys_Mkdir
Recursive mkdir.
===============================================================================
*/
void Sys_Mkdir(const char* path) {
if (!path || !path[0]) {
return;
}
char temp[MAX_OSPATH * 4];
SysStub_CopyString(temp, sizeof(temp), path);
SysStub_NormalizeSlashes(temp);
const int len = (int)strlen(temp);
if (len <= 0) {
return;
}
// Do not try to create "C:" by itself.
for (char* p = temp; *p; p++) {
if (*p != '/') {
continue;
}
// Skip drive root, for example C:/.
if (p == temp + 2 && temp[1] == ':') {
continue;
}
// Skip leading slash.
if (p == temp) {
continue;
}
*p = '\0';
if (temp[0] && !SysStub_IsDirectory(temp)) {
#ifdef _WIN32
_mkdir(temp);
#else
mkdir(temp, 0755);
#endif
}
*p = '/';
}
if (!SysStub_IsDirectory(temp)) {
#ifdef _WIN32
_mkdir(temp);
#else
mkdir(temp, 0755);
#endif
}
}
/*
===============================================================================
Sys_ListFiles
Real directory listing.
Returns count added.
Behavior:
- extension NULL / empty: lists everything except "." and ".."
- extension "/" : lists folders only
- extension ".ext" : lists files ending in .ext
- extension "ext" : also treated like ".ext"
===============================================================================
*/
int Sys_ListFiles(const char* directory, const char* extension, idList<idStr>& list) {
if (!directory || !directory[0]) {
return 0;
}
const int startCount = list.Num();
const bool listFoldersOnly = extension && strcmp(extension, "/") == 0;
const bool hasExtensionFilter = extension && extension[0] && !listFoldersOnly;
char normalizedExtension[128];
normalizedExtension[0] = '\0';
if (hasExtensionFilter) {
if (extension[0] == '.') {
SysStub_CopyString(normalizedExtension, sizeof(normalizedExtension), extension);
}
else {
#ifdef _WIN32
_snprintf_s(normalizedExtension, sizeof(normalizedExtension), _TRUNCATE, ".%s", extension);
#else
snprintf(normalizedExtension, sizeof(normalizedExtension), ".%s", extension);
normalizedExtension[sizeof(normalizedExtension) - 1] = '\0';
#endif
}
}
#ifdef _WIN32
char searchPath[MAX_OSPATH * 4];
SysStub_CopyString(searchPath, sizeof(searchPath), directory);
SysStub_NormalizeSlashes(searchPath);
const int searchLen = (int)strlen(searchPath);
if (searchLen > 0 && searchPath[searchLen - 1] != '/') {
strcat_s(searchPath, sizeof(searchPath), "/");
}
strcat_s(searchPath, sizeof(searchPath), "*");
WIN32_FIND_DATAA findData;
HANDLE hFind = FindFirstFileA(searchPath, &findData);
if (hFind == INVALID_HANDLE_VALUE) {
return 0;
}
do {
const char* name = findData.cFileName;
if (!strcmp(name, ".") || !strcmp(name, "..")) {
continue;
}
const bool isDirectory = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
if (listFoldersOnly) {
if (!isDirectory) {
continue;
}
}
else {
if (isDirectory) {
continue;
}
if (hasExtensionFilter && !SysStub_StringEndsWith(name, normalizedExtension)) {
continue;
}
}
list.Append(idStr(name));
} while (FindNextFileA(hFind, &findData));
FindClose(hFind);
#else
DIR* dir = opendir(directory);
if (!dir) {
return 0;
}
struct dirent* entry;
while ((entry = readdir(dir)) != NULL) {
const char* name = entry->d_name;
if (!strcmp(name, ".") || !strcmp(name, "..")) {
continue;
}
char fullPath[MAX_OSPATH * 4];
snprintf(fullPath, sizeof(fullPath), "%s/%s", directory, name);
fullPath[sizeof(fullPath) - 1] = '\0';
const bool isDirectory = SysStub_IsDirectory(fullPath);
if (listFoldersOnly) {
if (!isDirectory) {
continue;
}
}
else {
if (isDirectory) {
continue;
}
if (hasExtensionFilter && !SysStub_StringEndsWith(name, normalizedExtension)) {
continue;
}
}
list.Append(idStr(name));
}
closedir(dir);
#endif
return list.Num() - startCount;
}
/*
===============================================================================
Critical sections
===============================================================================
*/
#ifdef _WIN32
static CRITICAL_SECTION sys_stub_criticalSections[MAX_SYS_STUB_CRITICAL_SECTIONS];
static bool sys_stub_criticalSectionsInitialized[MAX_SYS_STUB_CRITICAL_SECTIONS];
static void SysStub_InitCriticalSection(int index) {
if (index < 0 || index >= MAX_SYS_STUB_CRITICAL_SECTIONS) {
return;
}
if (!sys_stub_criticalSectionsInitialized[index]) {
InitializeCriticalSection(&sys_stub_criticalSections[index]);
sys_stub_criticalSectionsInitialized[index] = true;
}
}
#endif
void Sys_EnterCriticalSection(int index) {
#ifdef _WIN32
if (index < 0 || index >= MAX_SYS_STUB_CRITICAL_SECTIONS) {
return;
}
SysStub_InitCriticalSection(index);
EnterCriticalSection(&sys_stub_criticalSections[index]);
#else
(void)index;
#endif
}
void Sys_LeaveCriticalSection(int index) {
#ifdef _WIN32
if (index < 0 || index >= MAX_SYS_STUB_CRITICAL_SECTIONS) {
return;
}
SysStub_InitCriticalSection(index);
LeaveCriticalSection(&sys_stub_criticalSections[index]);
#else
(void)index;
#endif
}
/*
===============================================================================
Events
===============================================================================
*/
#ifdef _WIN32
static HANDLE sys_stub_events[MAX_SYS_STUB_EVENTS];
static HANDLE SysStub_GetEvent(int index) {
if (index < 0 || index >= MAX_SYS_STUB_EVENTS) {
return NULL;
}
if (!sys_stub_events[index]) {
sys_stub_events[index] = CreateEventA(
NULL,
FALSE, // auto reset
FALSE, // initially not signaled
NULL
);
}
return sys_stub_events[index];
}
#endif
void Sys_WaitForEvent(int index) {
#ifdef _WIN32
HANDLE eventHandle = SysStub_GetEvent(index);
if (!eventHandle) {
return;
}
WaitForSingleObject(eventHandle, INFINITE);
#else
(void)index;
#endif
}
void Sys_TriggerEvent(int index) {
#ifdef _WIN32
HANDLE eventHandle = SysStub_GetEvent(index);
if (!eventHandle) {
return;
}
SetEvent(eventHandle);
#else
(void)index;
#endif
}
/*
===============================================================================
Thread creation
Required linker symbol:
void Sys_CreateThread(
unsigned int (__cdecl*)(void *),
void *,
enum xthreadPriority,
struct xthreadInfo &,
char const *,
struct xthreadInfo ** const,
int *
)
===============================================================================
*/
#ifdef _WIN32
struct sysStubThreadStart_t {
unsigned int (*function)(void*);
void* parameter;
};
static unsigned __stdcall SysStub_ThreadTrampoline(void* arg) {
sysStubThreadStart_t* start = (sysStubThreadStart_t*)arg;
unsigned int result = 0;
if (start && start->function) {
result = start->function(start->parameter);
}
delete start;
return result;
}
#endif
void Sys_CreateThread(
unsigned int (*function)(void*),
void* parameter,
xthreadPriority priority,
xthreadInfo& info,
const char* name,
xthreadInfo** const threads,
int* thread_count
) {
#ifdef _WIN32
memset(&info, 0, sizeof(info));
sysStubThreadStart_t* start = new sysStubThreadStart_t;
start->function = function;
start->parameter = parameter;
unsigned int threadId = 0;
HANDLE handle = (HANDLE)_beginthreadex(
NULL,
0,
SysStub_ThreadTrampoline,
start,
0,
&threadId
);
if (!handle) {
delete start;
SysStub_DebugPrint("Sys_CreateThread failed\n");
return;
}
// This assumes your xthreadInfo has these common Doom 3 fields.
// If your struct differs, comment these out or adjust names.
info.threadHandle = (int)handle;
info.threadId = threadId;
info.name = name;
switch (priority) {
case THREAD_NORMAL:
SetThreadPriority(handle, THREAD_PRIORITY_NORMAL);
break;
default:
SetThreadPriority(handle, THREAD_PRIORITY_NORMAL);
break;
}
if (threads && thread_count) {
if (*thread_count >= 0 && *thread_count < MAX_SYS_STUB_THREADS) {
threads[*thread_count] = &info;
(*thread_count)++;
}
}
g_thread_count++;
char buffer[512];
#ifdef _WIN32
_snprintf_s(
buffer,
sizeof(buffer),
_TRUNCATE,
"Sys_CreateThread created \"%s\" id=%u\n",
name ? name : "",
threadId
);
#else
snprintf(buffer, sizeof(buffer), "Sys_CreateThread created\n");
#endif
SysStub_DebugPrint(buffer);
#else
(void)function;
(void)parameter;
(void)priority;
(void)info;
(void)name;
(void)threads;
(void)thread_count;
#endif
}
/*
===============================================================================
idEventLoop::JournalLevel
Stubbed to 0 so file system reads do not try to journal.
===============================================================================
*/
int idEventLoop::JournalLevel(void) const {
return 0;
}