[ScriptErrors]: Add useful errors to scripts (#721)

This commit is contained in:
Edo 2023-01-16 17:55:26 +00:00 committed by GitHub
parent f34377b456
commit 33f554effd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 1582 additions and 340 deletions

View File

@ -3,6 +3,7 @@
#include "Int64.hpp"
#include "IO.hpp"
#include "Script.hpp"
#include "ScriptError.hpp"
#include "ScriptExtension.hpp"
#include "ScriptPatches.hpp"
#include "ScriptStorage.hpp"
@ -14,6 +15,7 @@ namespace Components
Loader::Register(new Int64());
Loader::Register(new IO());
Loader::Register(new Script());
Loader::Register(new ScriptError());
Loader::Register(new ScriptExtension());
Loader::Register(new ScriptPatches());
Loader::Register(new ScriptStorage());

View File

@ -6,10 +6,6 @@ namespace Components
std::vector<Script::ScriptFunction> Script::CustomScrFunctions;
std::vector<Script::ScriptMethod> Script::CustomScrMethods;
std::string Script::ScriptName;
std::vector<std::string> Script::ScriptNameStack;
unsigned short Script::FunctionName;
std::unordered_map<int, std::string> Script::ScriptBaseProgramNum;
int Script::LastFrameTime = -1;
std::unordered_map<const char*, const char*> Script::ReplacedFunctions;
@ -18,191 +14,6 @@ namespace Components
std::unordered_map<std::string, int> Script::ScriptMainHandles;
std::unordered_map<std::string, int> Script::ScriptInitHandles;
void Script::FunctionError()
{
const auto* funcName = Game::SL_ConvertToString(FunctionName);
Game::Scr_ShutdownAllocNode();
Logger::Print(Game::CON_CHANNEL_PARSERSCRIPT, "\n");
Logger::Print(Game::CON_CHANNEL_PARSERSCRIPT, "******* script compile error *******\n");
Logger::Print(Game::CON_CHANNEL_PARSERSCRIPT, "Error: unknown function {} in {}\n", funcName, ScriptName);
Logger::Print(Game::CON_CHANNEL_PARSERSCRIPT, "************************************\n");
Logger::Error(Game::ERR_SCRIPT_DROP, "script compile error\nunknown function {}\n{}\n\n", funcName, ScriptName);
}
__declspec(naked) void Script::StoreFunctionNameStub()
{
__asm
{
mov eax, [esp - 8h]
mov FunctionName, ax
sub esp, 0Ch
push 0
push edi
mov eax, 612DB6h
jmp eax
}
}
void Script::RuntimeError(const char* codePos, unsigned int index, const char* msg, const char* dialogMessage)
{
// Allow error messages to be printed if developer mode is on
// Should check scrVarPub.developer but it's absent
// in this version of the game so let's check the dvar
if (!Game::scrVmPub->terminal_error && !(*Game::com_developer)->current.integer)
return;
// If were are developing let's call RuntimeErrorInternal
// scrVmPub.debugCode seems to be always false
if (Game::scrVmPub->debugCode || Game::scrVarPub->developer_script)
{
Game::RuntimeErrorInternal(Game::CON_CHANNEL_PARSERSCRIPT, codePos, index, msg);
}
else
{
Logger::Print(Game::CON_CHANNEL_PARSERSCRIPT, "{}\n", msg);
}
// Let's not throw error unless we have to
if (Game::scrVmPub->terminal_error)
{
if (dialogMessage == nullptr)
dialogMessage = "";
Logger::Error(Game::ERR_SCRIPT_DROP, "\x15script runtime error\n(see console for details)\n{}\n{}", msg, dialogMessage);
}
}
void Script::StoreScriptName(const char* name)
{
ScriptNameStack.push_back(ScriptName);
ScriptName = name;
if (!Utils::String::EndsWith(ScriptName, ".gsc"))
{
ScriptName.append(".gsc");
}
}
__declspec(naked) void Script::StoreScriptNameStub()
{
__asm
{
pushad
lea ecx, [esp + 30h]
push ecx
call StoreScriptName
add esp, 4h
popad
push ebp
mov ebp, ds:1CDEAA8h
push 427DC3h
retn
}
}
void Script::RestoreScriptName()
{
ScriptName = ScriptNameStack.back();
ScriptNameStack.pop_back();
}
__declspec(naked) void Script::RestoreScriptNameStub()
{
__asm
{
pushad
call RestoreScriptName
popad
mov ds:1CDEAA8h, ebp
push 427E77h
retn
}
}
void Script::PrintSourcePos(const char* filename, unsigned int offset)
{
FileSystem::File script(filename);
if (script.exists())
{
std::string buffer = script.getBuffer();
Utils::String::Replace(buffer, "\t", " ");
auto line = 1, lineOffset = 0, inlineOffset = 0;
for (size_t i = 0; i < buffer.size(); ++i)
{
// Terminate line
if (i == offset)
{
while (buffer[i] != '\r' && buffer[i] != '\n' && buffer[i] != '\0')
{
++i;
}
buffer[i] = '\0';
break;
}
if (buffer[i] == '\n')
{
++line;
lineOffset = static_cast<int>(i); // Includes the line break!
inlineOffset = 0;
}
else
{
++inlineOffset;
}
}
Logger::Print(Game::CON_CHANNEL_PARSERSCRIPT, "in file {}, line {}:", filename, line);
Logger::Print(Game::CON_CHANNEL_PARSERSCRIPT, "{}\n", buffer.substr(lineOffset));
for (auto i = 0; i < (inlineOffset - 1); ++i)
{
Logger::Print(Game::CON_CHANNEL_PARSERSCRIPT, " ");
}
Logger::Print(Game::CON_CHANNEL_PARSERSCRIPT, "*\n");
}
else
{
Logger::Print(Game::CON_CHANNEL_PARSERSCRIPT, "in file {}, offset {}\n", filename, offset);
}
}
void Script::CompileError(unsigned int offset, const char* message, ...)
{
char msgbuf[1024] = {0};
va_list va;
va_start(va, message);
_vsnprintf_s(msgbuf, _TRUNCATE, message, va);
va_end(va);
Game::Scr_ShutdownAllocNode();
Logger::Print(Game::CON_CHANNEL_PARSERSCRIPT, "\n");
Logger::Print(Game::CON_CHANNEL_PARSERSCRIPT, "******* script compile error *******\n");
Logger::Print(Game::CON_CHANNEL_PARSERSCRIPT, "Error: {} ", msgbuf);
PrintSourcePos(ScriptName.data(), offset);
Logger::Print(Game::CON_CHANNEL_PARSERSCRIPT, "************************************\n\n");
Logger::Error(Game::ERR_SCRIPT_DROP, "script compile error\n{}\n{}\n(see console for actual details)\n", msgbuf, ScriptName);
}
void Script::Scr_LoadGameType_Stub()
{
for (const auto& handle : ScriptMainHandles)
@ -376,77 +187,6 @@ namespace Components
return Utils::Hook::Call<Game::BuiltinMethod(const char**, int*)>(0x5FA360)(pName, type); // Player_GetMethod
}
void Script::StoreScriptBaseProgramNum()
{
ScriptBaseProgramNum.insert_or_assign(Utils::Hook::Get<int>(0x1CFEEF8), ScriptName);
}
void Script::Scr_PrintPrevCodePos(int scriptPos)
{
auto bestCodePos = -1, nextCodePos = -1, offset = -1;
std::string file;
for (const auto& [key, value] : ScriptBaseProgramNum)
{
const auto codePos = key;
if (codePos > scriptPos)
{
if (nextCodePos == -1 || codePos < nextCodePos)
nextCodePos = codePos;
continue;
}
if (codePos < bestCodePos)
continue;
bestCodePos = codePos;
file = value;
offset = scriptPos - bestCodePos;
}
if (bestCodePos == -1)
return;
Logger::Print(Game::CON_CHANNEL_PARSERSCRIPT, "\n@ {} ({} - {})\n", scriptPos, bestCodePos, nextCodePos);
Logger::Print(Game::CON_CHANNEL_PARSERSCRIPT, "in {} ({} through the source)\n\n", file, ((offset * 100.0f) / (nextCodePos - bestCodePos)));
}
__declspec(naked) void Script::Scr_PrintPrevCodePosStub()
{
__asm
{
push esi
call Scr_PrintPrevCodePos
add esp, 4h
pop esi
retn
}
}
__declspec(naked) void Script::StoreScriptBaseProgramNumStub()
{
__asm
{
// execute our hook
pushad
call StoreScriptBaseProgramNum
popad
// execute overwritten code caused by the jump hook
sub eax, ds:201A460h // gScrVarPub_programBuffer
add esp, 0Ch
mov ds:1CFEEF8h, eax // gScrCompilePub_programLen
// jump back to the original code
push 426C3Bh
retn
}
}
unsigned int Script::SetExpFogStub()
{
if (Game::Scr_GetNumParam() == 6)
@ -636,23 +376,10 @@ namespace Components
Script::Script()
{
Utils::Hook(0x612DB0, StoreFunctionNameStub, HOOK_JUMP).install()->quick();
Utils::Hook(0x427E71, RestoreScriptNameStub, HOOK_JUMP).install()->quick();
Utils::Hook(0x427DBC, StoreScriptNameStub, HOOK_JUMP).install()->quick();
Utils::Hook(0x426C2D, StoreScriptBaseProgramNumStub, HOOK_JUMP).install()->quick();
Utils::Hook(0x42281B, Scr_PrintPrevCodePosStub, HOOK_JUMP).install()->quick();
Utils::Hook(0x61E3AD, RuntimeError, HOOK_CALL).install()->quick();
Utils::Hook(0x621976, RuntimeError, HOOK_CALL).install()->quick();
Utils::Hook(0x62246E, RuntimeError, HOOK_CALL).install()->quick();
// Skip check in GScr_CheckAllowedToSetPersistentData to prevent log spam in RuntimeError.
// On IW5 the function is entirely nullsubbed
Utils::Hook::Set<std::uint8_t>(0x5F8DBF, 0xEB);
Utils::Hook(0x612E8D, FunctionError, HOOK_CALL).install()->quick();
Utils::Hook(0x612EA2, FunctionError, HOOK_CALL).install()->quick();
Utils::Hook(0x434260, CompileError, HOOK_JUMP).install()->quick();
Utils::Hook(0x48EFFE, Scr_LoadGameType_Stub, HOOK_CALL).install()->quick();
Utils::Hook(0x48F008, Scr_StartupGameType_Stub, HOOK_CALL).install()->quick();
Utils::Hook(0x45D44A, GScr_LoadGameTypeScript_Stub, HOOK_CALL).install()->quick();

View File

@ -57,10 +57,6 @@ namespace Components
static std::vector<ScriptFunction> CustomScrFunctions;
static std::vector<ScriptMethod> CustomScrMethods;
static std::string ScriptName;
static std::vector<std::string> ScriptNameStack;
static unsigned short FunctionName;
static std::unordered_map<int, std::string> ScriptBaseProgramNum;
static int LastFrameTime;
static std::unordered_map<std::string, int> ScriptMainHandles;
@ -69,19 +65,6 @@ namespace Components
static std::unordered_map<const char*, const char*> ReplacedFunctions;
static const char* ReplacedPos;
static void CompileError(unsigned int offset, const char* message, ...);
static void PrintSourcePos(const char* filename, unsigned int offset);
static void FunctionError();
static void StoreFunctionNameStub();
static void RuntimeError(const char* codePos, unsigned int index, const char* msg, const char* dialogMessage);
static void StoreScriptName(const char* name);
static void StoreScriptNameStub();
static void RestoreScriptName();
static void RestoreScriptNameStub();
static void Scr_LoadGameType_Stub();
static void Scr_StartupGameType_Stub();
static void GScr_LoadGameTypeScript_Stub();
@ -89,11 +72,6 @@ namespace Components
static Game::BuiltinFunction BuiltIn_GetFunctionStub(const char** pName, int* type);
static Game::BuiltinMethod BuiltIn_GetMethodStub(const char** pName, int* type);
static void StoreScriptBaseProgramNumStub();
static void StoreScriptBaseProgramNum();
static void Scr_PrintPrevCodePosStub();
static void Scr_PrintPrevCodePos(int);
static unsigned int SetExpFogStub();
static void GetReplacedPos(const char* pos);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,67 @@
#pragma once
namespace Components
{
class ScriptError : public Component
{
public:
ScriptError();
static int Scr_IsInOpcodeMemory(const char* pos);
static int Scr_GetLineNum(unsigned int bufferIndex, unsigned int sourcePos);
static void RuntimeError(const char* codePos, unsigned int index, const char* msg, const char* dialogMessage);
private:
// Replacement for variables not present in currently available structs
static int developer_;
static Game::scrParserGlob_t scrParserGlob;
static Game::scrParserPub_t scrParserPub;
static Game::HunkUser* g_debugUser;
static void AddOpcodePos(unsigned int sourcePos, int type);
static void RemoveOpcodePos();
static void AddThreadStartOpcodePos(unsigned int sourcePos);
static unsigned int Scr_GetPrevSourcePos(const char* codePos, unsigned int index);
static Game::OpcodeLookup* Scr_GetPrevSourcePosOpcodeLookup(const char* codePos);
static void Scr_CopyFormattedLine(char* line, const char* rawLine);
static int Scr_GetLineNumInternal(const char* buf, unsigned int sourcePos, const char** startLine, int* col, Game::SourceBufferInfo* binfo);
static unsigned int Scr_GetSourceBuffer(const char* codePos);
static void Scr_PrintPrevCodePos(int channel, const char* codePos, unsigned int index);
static int Scr_GetLineInfo(const char* buf, unsigned int sourcePos, int* col, char* line, Game::SourceBufferInfo* binfo);
static void Scr_PrintSourcePos(int channel, const char* filename, const char* buf, unsigned int sourcePos);
static void RuntimeErrorInternal(int channel, const char* codePos, unsigned int index, const char* msg);
static void CompileError(unsigned int sourcePos, const char* msg, ...);
static void CompileError2(const char* codePos, const char* msg, ...);
static void Scr_GetTextSourcePos(const char* buf, const char* codePos, char* line);
static void Scr_InitOpcodeLookup();
static void Scr_ShutdownOpcodeLookup();
static void EmitThreadInternal_Stub();
static Game::SourceBufferInfo* Scr_GetNewSourceBuffer();
static void Scr_AddSourceBufferInternal(const char* extFilename, const char* codePos, char* sourceBuf, int len, bool doEolFixup, bool archive);
static char* Scr_ReadFile_FastFile(const char* filename, const char* extFilename, const char* codePos, bool archive);
static char* Scr_ReadFile_LoadObj(const char* filename, const char* extFilename, const char* codePos, bool archive);
static char* Scr_ReadFile(const char* filename, const char* extFilename, const char* codePos, bool archive);
static char* Scr_AddSourceBuffer(const char* filename, const char* extFilename, const char* codePos, bool archive);
static unsigned int Scr_LoadScriptInternal_Hk(const char* filename, Game::PrecacheEntry* entries, int entriesCount);
static void Scr_Settings_Hk(int developer, int developer_script, int abort_on_error);
static void MT_Reset_Stub();
static void SL_ShutdownSystem_Stub(unsigned int user);
static void Hunk_InitDebugMemory();
static void Hunk_ShutdownDebugMemory();
static void* Hunk_AllocDebugMem(int size);
static void Hunk_FreeDebugMem(void* ptr);
};
}

View File

@ -8,7 +8,7 @@ namespace Components
auto fileHandle = 0;
auto fileSize = Game::FS_FOpenFileRead(filename, &fileHandle);
if (fileHandle != 0)
if (fileHandle)
{
if ((fileSize + 1) <= size)
{
@ -37,7 +37,7 @@ namespace Components
auto fileHandle = 0;
auto fileSize = Game::FS_FOpenFileRead(filename, &fileHandle);
if (fileHandle != 0)
if (fileHandle)
{
if (fileSize < 0x8000)
{
@ -99,9 +99,8 @@ namespace Components
const char* RawFiles::Com_LoadInfoString_Hk(const char* fileName, const char* fileDesc, const char* ident, char* loadBuffer)
{
const char* buffer;
buffer = Com_LoadInfoString_LoadObj(fileName, fileDesc, ident, loadBuffer);
const auto* buffer = Com_LoadInfoString_LoadObj(fileName, fileDesc, ident, loadBuffer);
if (!buffer)
{
buffer = Game::Com_LoadInfoString_FastFile(fileName, fileDesc, ident, loadBuffer);

View File

@ -56,7 +56,7 @@ BOOL APIENTRY DllMain(HINSTANCE /*hinstDLL*/, DWORD fdwReason, LPVOID /*lpvReser
#ifndef DEBUG_BINARY_CHECK
const auto* binary = reinterpret_cast<const char*>(0x6F9358);
if (binary == nullptr || std::strcmp(binary, BASEGAME_NAME) != 0)
if (binary == nullptr || std::memcmp(binary, BASEGAME_NAME, 14) != 0)
#endif
{
MessageBoxA(nullptr,

View File

@ -247,9 +247,6 @@ namespace Game
Vec2Normalize_t Vec2Normalize = Vec2Normalize_t(0x416F70);
Vec2NormalizeFast_t Vec2NormalizeFast = Vec2NormalizeFast_t(0x5FC830);
Z_VirtualAlloc_t Z_VirtualAlloc = Z_VirtualAlloc_t(0x4CFBA0);
Z_Malloc_t Z_Malloc = Z_Malloc_t(0x4F3680);
I_strncpyz_t I_strncpyz = I_strncpyz_t(0x4D6F80);
I_CleanStr_t I_CleanStr = I_CleanStr_t(0x4AD470);

View File

@ -569,12 +569,6 @@ namespace Game
typedef void(*Vec2NormalizeFast_t)(float* v);
extern Vec2NormalizeFast_t Vec2NormalizeFast;
typedef void*(*Z_VirtualAlloc_t)(int size);
extern Z_VirtualAlloc_t Z_VirtualAlloc;
typedef void*(*Z_Malloc_t)(int size);
extern Z_Malloc_t Z_Malloc;
typedef void(*I_strncpyz_t)(char* dest, const char* src, int destsize);
extern I_strncpyz_t I_strncpyz;

View File

@ -10,6 +10,7 @@
#include "Script.hpp"
#include "Server.hpp"
#include "System.hpp"
#include "Zone.hpp"
namespace Game
{

View File

@ -6,6 +6,12 @@ namespace Game
RemoveRefToObject_t RemoveRefToObject = RemoveRefToObject_t(0x437190);
AllocObject_t AllocObject = AllocObject_t(0x434320);
AddRefToValue_t AddRefToValue = AddRefToValue_t(0x482740);
FindVariable_t FindVariable = FindVariable_t(0x4AB650);
GetVariable_t GetVariable = GetVariable_t(0x419970);
RemoveVariable_t RemoveVariable = RemoveVariable_t(0x480B40);
FindObject_t FindObject = FindObject_t(0x4CF2F0);
GetObject_t GetObject = GetObject_t(0x48B9D0);
GetNewVariable_t GetNewVariable = GetNewVariable_t(0x4CC520);
AllocThread_t AllocThread = AllocThread_t(0x4F78C0);
VM_Execute_0_t VM_Execute_0 = VM_Execute_0_t(0x6222A0);
@ -16,7 +22,9 @@ namespace Game
Scr_StartupGameType_t Scr_StartupGameType = Scr_StartupGameType_t(0x438720);
Scr_LoadScript_t Scr_LoadScript = Scr_LoadScript_t(0x45D940);
Scr_ReadFile_FastFile_t Scr_ReadFile_FastFile = Scr_ReadFile_FastFile_t(0x61AAB0);
Scr_GetFunctionHandle_t Scr_GetFunctionHandle = Scr_GetFunctionHandle_t(0x4234F0);
Scr_CreateCanonicalFilename_t Scr_CreateCanonicalFilename = Scr_CreateCanonicalFilename_t(0x4A0220);
Scr_GetString_t Scr_GetString = Scr_GetString_t(0x425900);
Scr_GetConstString_t Scr_GetConstString = Scr_GetConstString_t(0x494830);
@ -75,10 +83,18 @@ namespace Game
SL_AddRefToString_t SL_AddRefToString = SL_AddRefToString_t(0x4D9B00);
SL_RemoveRefToString_t SL_RemoveRefToString = SL_RemoveRefToString_t(0x47CD70);
ScriptParse_t ScriptParse = ScriptParse_t(0x48A4F0);
ScriptCompile_t ScriptCompile = ScriptCompile_t(0x426B80);
scr_const_t* scr_const = reinterpret_cast<scr_const_t*>(0x1AA2E00);
scrVmPub_t* scrVmPub = reinterpret_cast<scrVmPub_t*>(0x2040CF0);
scrVarPub_t* scrVarPub = reinterpret_cast<scrVarPub_t*>(0x201A408);
scrCompilePub_t* scrCompilePub = reinterpret_cast<scrCompilePub_t*>(0x1CDEEC0);
scrAnimPub_t* scrAnimPub = reinterpret_cast<scrAnimPub_t*>(0x1CDEAA0);
char* g_EndPos = reinterpret_cast<char*>(0x2045498);
bool* g_loadedImpureScript = reinterpret_cast<bool*>(0x1DC2208);
game_hudelem_s* g_hudelems = reinterpret_cast<game_hudelem_s*>(0x18565A8);

View File

@ -14,6 +14,24 @@ namespace Game
typedef void(*AddRefToValue_t)(int type, VariableUnion u);
extern AddRefToValue_t AddRefToValue;
typedef unsigned int(*FindVariable_t)(unsigned int parentId, unsigned int unsignedValue);
extern FindVariable_t FindVariable;
typedef unsigned int(*GetVariable_t)(unsigned int parentId, unsigned int unsignedValue);
extern GetVariable_t GetVariable;
typedef void(*RemoveVariable_t)(unsigned int parentId, unsigned int unsignedValue);
extern RemoveVariable_t RemoveVariable;
typedef unsigned int(*FindObject_t)(unsigned int parentId, unsigned int id);
extern FindObject_t FindObject;
typedef unsigned int(*GetObject_t)(unsigned int parentId, unsigned int id);
extern GetObject_t GetObject;
typedef unsigned int(*GetNewVariable_t)(unsigned int parentId, unsigned int unsignedValue);
extern GetNewVariable_t GetNewVariable;
typedef unsigned int(*AllocThread_t)(unsigned int self);
extern AllocThread_t AllocThread;
@ -44,7 +62,7 @@ namespace Game
typedef void(*Scr_ShutdownAllocNode_t)();
extern Scr_ShutdownAllocNode_t Scr_ShutdownAllocNode;
typedef char* (*Scr_GetGameTypeNameForScript_t)(const char* pszGameTypeScript);
typedef char*(*Scr_GetGameTypeNameForScript_t)(const char* pszGameTypeScript);
extern Scr_GetGameTypeNameForScript_t Scr_GetGameTypeNameForScript;
typedef int(*Scr_IsValidGameType_t)(const char* pszGameType);
@ -59,6 +77,15 @@ namespace Game
typedef int(*Scr_LoadScript_t)(const char*);
extern Scr_LoadScript_t Scr_LoadScript;
typedef char*(*Scr_ReadFile_FastFile_t)(const char* filename, const char* extFilename, const char* codePos, const char* archive);
extern Scr_ReadFile_FastFile_t Scr_ReadFile_FastFile;
typedef int(*Scr_GetFunctionHandle_t)(const char* filename, const char* name);
extern Scr_GetFunctionHandle_t Scr_GetFunctionHandle;
typedef unsigned int(*Scr_CreateCanonicalFilename_t)(const char* filename);
extern Scr_CreateCanonicalFilename_t Scr_CreateCanonicalFilename;
typedef const char*(*Scr_GetString_t)(unsigned int index);
extern Scr_GetString_t Scr_GetString;
@ -86,9 +113,6 @@ namespace Game
typedef unsigned int(*Scr_GetEntityId_t)(int entnum, unsigned int classnum);
extern Scr_GetEntityId_t Scr_GetEntityId;
typedef int(*Scr_GetFunctionHandle_t)(const char* filename, const char* name);
extern Scr_GetFunctionHandle_t Scr_GetFunctionHandle;
typedef int(*Scr_ExecThread_t)(int handle, unsigned int paramcount);
extern Scr_ExecThread_t Scr_ExecThread;
@ -176,6 +200,18 @@ namespace Game
typedef void(*SL_RemoveRefToString_t)(unsigned int stringValue);
extern SL_RemoveRefToString_t SL_RemoveRefToString;
typedef void(*ScriptParse_t)(sval_u* parseData, unsigned char user);
extern ScriptParse_t ScriptParse;
typedef void(*ScriptCompile_t)(sval_u* val, unsigned int filePosId, unsigned int fileCountId, unsigned int scriptId, PrecacheEntry* entries, int entriesCount);
extern ScriptCompile_t ScriptCompile;
constexpr auto MAX_OPCODE_LOOKUP_SIZE = 0x1000000;
constexpr auto MAX_SOURCEPOS_LOOKUP_SIZE = 0x800000;
constexpr auto MAX_SOURCEBUF_LOOKUP_SIZE = 0x40000;
constexpr auto LOCAL_VAR_STACK_SIZE = 64;
extern void IncInParam();
extern void Scr_AddBool(int value);
@ -188,6 +224,11 @@ namespace Game
extern scrVmPub_t* scrVmPub;
extern scrVarPub_t* scrVarPub;
extern scrCompilePub_t* scrCompilePub;
extern scrAnimPub_t* scrAnimPub;
extern char* g_EndPos;
extern bool* g_loadedImpureScript;
extern game_hudelem_s* g_hudelems;
}

View File

@ -5949,6 +5949,38 @@ namespace Game
int dataCount;
};
struct PrecacheEntry
{
unsigned __int16 filename;
bool include;
unsigned int sourcePos;
};
struct XAnimParent
{
unsigned short flags;
unsigned short children;
};
struct XAnimEntry
{
unsigned short numAnims;
unsigned short parent;
union
{
XAnimParts* parts;
XAnimParent animParent;
} ___u2;
};
struct XAnim_s
{
unsigned int size;
const char* debugName;
const char** debugAnimNames;
XAnimEntry entries[1];
};
struct HunkUser
{
HunkUser* current;
@ -6102,6 +6134,154 @@ namespace Game
static_assert(sizeof(scrVarPub_t) == 0x24060);
struct scrCompilePub_t
{
int value_count;
int far_function_count;
unsigned int loadedscripts;
unsigned int scriptsPos;
unsigned int scriptsCount;
unsigned int scriptsDefine;
unsigned int builtinFunc;
unsigned int builtinMeth;
unsigned __int16 canonicalStrings[65536];
const char* in_ptr;
bool in_ptr_valid;
const char* parseBuf;
bool script_loading;
bool allowedBreakpoint;
int developer_statement;
char* opcodePos;
unsigned int programLen;
int func_table_size;
int func_table[1024];
};
enum
{
SOURCE_TYPE_BREAKPOINT = 0x1,
SOURCE_TYPE_CALL = 0x2,
SOURCE_TYPE_CALL_POINTER = 0x4,
SOURCE_TYPE_THREAD_START = 0x8,
SOURCE_TYPE_BUILTIN_CALL = 0x10,
SOURCE_TYPE_NOTIFY = 0x20,
SOURCE_TYPE_GETFUNCTION = 0x40,
SOURCE_TYPE_WAIT = 0x80,
};
struct OpcodeLookup
{
const char* codePos;
unsigned int sourcePosIndex;
unsigned __int16 sourcePosCount;
int profileTime;
int profileBuiltInTime;
int profileUsage;
};
static_assert(sizeof(OpcodeLookup) == 24);
struct SourceLookup
{
unsigned int sourcePos;
int type;
};
struct SaveSourceBufferInfo
{
char* buf;
char* sourceBuf;
int len;
};
struct scrParserGlob_t
{
OpcodeLookup* opcodeLookup;
unsigned int opcodeLookupMaxSize;
unsigned int opcodeLookupLen;
SourceLookup* sourcePosLookup;
unsigned int sourcePosLookupMaxSize;
unsigned int sourcePosLookupLen;
unsigned int sourceBufferLookupMaxSize;
const char* currentCodePos;
unsigned int currentSourcePosCount;
SaveSourceBufferInfo* saveSourceBufferLookup;
unsigned int saveSourceBufferLookupLen;
int delayedSourceIndex;
int threadStartSourceIndex;
};
struct SourceBufferInfo
{
const char* codePos;
char* buf;
const char* sourceBuf;
int len;
int sortedIndex;
bool archive;
int time;
int avgTime;
int maxTime;
float totalTime;
float totalBuiltIn;
};
struct scrParserPub_t
{
SourceBufferInfo* sourceBufferLookup;
unsigned int sourceBufferLookupLen;
const char* scriptfilename;
const char* sourceBuf;
};
struct scr_animtree_t
{
XAnim_s* anims;
};
struct scrAnimPub_t
{
unsigned int animtrees;
unsigned int animtree_node;
unsigned int animTreeNames;
scr_animtree_t xanim_lookup[2][128];
unsigned int xanim_num[2];
unsigned int animTreeIndex;
bool animtree_loading;
};
struct scr_localVar_t
{
unsigned int name;
unsigned int sourcePos;
};
struct scr_block_t
{
int abortLevel;
int localVarsCreateCount;
int localVarsPublicCount;
int localVarsCount;
char localVarsInitBits[8];
scr_localVar_t localVars[64];
};
union sval_u
{
int type;
unsigned int stringValue;
unsigned int idValue;
float floatValue;
int intValue;
sval_u* node;
unsigned int sourcePosValue;
const char* codePosValue;
const char* debugString;
scr_block_t* block;
};
static_assert(sizeof(sval_u) == 0x4);
struct scr_const_t
{
scr_string_t _;
@ -8452,33 +8632,7 @@ namespace Game
float scale;
};
struct XAnimParent
{
unsigned short flags;
unsigned short children;
};
struct XAnimEntry
{
unsigned short numAnims;
unsigned short parent;
union
{
XAnimParts* parts;
XAnimParent animParent;
};
};
struct XAnim_s
{
unsigned int size;
const char* debugName;
const char** debugAnimNames;
XAnimEntry entries[1];
};
struct __declspec(align(4)) XAnimTree_s
struct XAnimTree_s
{
XAnim_s* anims;
int info_usage;

View File

@ -24,6 +24,7 @@ namespace Game
Sys_SuspendOtherThreads_t Sys_SuspendOtherThreads = Sys_SuspendOtherThreads_t(0x45A190);
Sys_SetValue_t Sys_SetValue = Sys_SetValue_t(0x4B2F50);
Sys_CreateFile_t Sys_CreateFile = Sys_CreateFile_t(0x4B2EF0);
Sys_OutOfMemErrorInternal_t Sys_OutOfMemErrorInternal = Sys_OutOfMemErrorInternal_t(0x4B2E60);
char(*sys_exitCmdLine)[1024] = reinterpret_cast<char(*)[1024]>(0x649FB68);

View File

@ -68,6 +68,9 @@ namespace Game
typedef Sys_File(*Sys_CreateFile_t)(const char* dir, const char* filename);
extern Sys_CreateFile_t Sys_CreateFile;
typedef void(*Sys_OutOfMemErrorInternal_t)(const char* filename, int line);
extern Sys_OutOfMemErrorInternal_t Sys_OutOfMemErrorInternal;
extern char(*sys_exitCmdLine)[1024];
extern RTL_CRITICAL_SECTION* s_criticalSection;
@ -99,3 +102,5 @@ namespace Game
}
};
}
#define Sys_OutOfMemError() Game::Sys_OutOfMemErrorInternal(__FILE__, __LINE__);

75
src/Game/Zone.cpp Normal file
View File

@ -0,0 +1,75 @@
#include <STDInclude.hpp>
namespace Game
{
Z_VirtualAlloc_t Z_VirtualAlloc = Z_VirtualAlloc_t(0x4CFBA0);
Z_Malloc_t Z_Malloc = Z_Malloc_t(0x4F3680);
Hunk_UserCreate_t Hunk_UserCreate = Hunk_UserCreate_t(0x430E90);
Hunk_UserDestroy_t Hunk_UserDestroy = Hunk_UserDestroy_t(0x435910);
Hunk_AllocateTempMemoryHigh_t Hunk_AllocateTempMemoryHigh = Hunk_AllocateTempMemoryHigh_t(0x475B30);
Hunk_UserAlloc_t Hunk_UserAlloc = Hunk_UserAlloc_t(0x45D1C0);
TempMalloc_t TempMalloc = TempMalloc_t(0x4613A0);
int Z_TryVirtualCommitInternal(void* ptr, int size)
{
assert((size >= 0));
return VirtualAlloc(ptr, size, (size > 0x20000 ? 0 : MEM_TOP_DOWN) | MEM_COMMIT, PAGE_READWRITE) != nullptr;
}
void Z_VirtualDecommitInternal(void* ptr, int size)
{
assert((size >= 0));
#pragma warning(push)
#pragma warning(disable: 6250)
[[maybe_unused]] const auto result = VirtualFree(ptr, size, MEM_DECOMMIT);
#pragma warning(pop)
}
void Z_VirtualCommitInternal(void* ptr, int size)
{
if (Z_TryVirtualCommitInternal(ptr, size))
{
return;
}
Sys_OutOfMemError();
}
void Z_VirtualFreeInternal(void* ptr)
{
VirtualFree(ptr, 0, MEM_RELEASE);
}
void Z_VirtualCommit(void* ptr, int size)
{
assert(ptr);
assert(size);
Z_VirtualCommitInternal(ptr, size);
}
void* Z_VirtualReserve(int size)
{
assert((size >= 0));
void* buf = VirtualAlloc(nullptr, size, (size > 0x20000 ? 0 : MEM_TOP_DOWN) | MEM_RESERVE, PAGE_READWRITE);
assert(buf);
return buf;
}
void Z_VirtualDecommit(void* ptr, int size)
{
assert(ptr);
assert(size);
Z_VirtualDecommitInternal(ptr, size);
}
void Z_VirtualFree(void* ptr)
{
Z_VirtualFreeInternal(ptr);
}
}

32
src/Game/Zone.hpp Normal file
View File

@ -0,0 +1,32 @@
#pragma once
namespace Game
{
typedef void*(*Z_VirtualAlloc_t)(int size);
extern Z_VirtualAlloc_t Z_VirtualAlloc;
typedef void*(*Z_Malloc_t)(int size);
extern Z_Malloc_t Z_Malloc;
typedef HunkUser*(*Hunk_UserCreate_t)(int maxSize, const char* name, bool fixed, int type);
extern Hunk_UserCreate_t Hunk_UserCreate;
typedef void(*Hunk_UserDestroy_t)(HunkUser* user);
extern Hunk_UserDestroy_t Hunk_UserDestroy;
typedef void*(*Hunk_AllocateTempMemoryHigh_t)(int size);
extern Hunk_AllocateTempMemoryHigh_t Hunk_AllocateTempMemoryHigh;
typedef void*(*Hunk_UserAlloc_t)(HunkUser* user, int size, int alignment);
extern Hunk_UserAlloc_t Hunk_UserAlloc;
typedef char*(*TempMalloc_t)(int len);
extern TempMalloc_t TempMalloc;
constexpr auto PAGE_SIZE = 4096;
extern void* Z_VirtualReserve(int size);
extern void Z_VirtualCommit(void* ptr, int size);
extern void Z_VirtualDecommit(void* ptr, int size);
extern void Z_VirtualFree(void* ptr);
}

View File

@ -95,6 +95,10 @@ using namespace std::literals;
#undef min
#endif
#ifdef GetObject
#undef GetObject
#endif
#define AssertSize(x, size) \
static_assert(sizeof(x) == (size), \
"Structure has an invalid size. " #x " must be " #size " bytes")