2016-05-29 10:16:15 -04:00
|
|
|
#include "STDInclude.hpp"
|
|
|
|
|
|
|
|
namespace Components
|
|
|
|
{
|
|
|
|
std::string Script::ScriptName;
|
|
|
|
std::vector<int> Script::ScriptHandles;
|
|
|
|
std::vector<std::string> Script::ScriptNameStack;
|
|
|
|
unsigned short Script::FunctionName;
|
|
|
|
|
|
|
|
void Script::FunctionError()
|
|
|
|
{
|
|
|
|
std::string funcName = Game::SL_ConvertToString(Script::FunctionName);
|
|
|
|
|
2016-06-03 18:06:07 -04:00
|
|
|
Game::Scr_ShutdownAllocNode();
|
|
|
|
|
|
|
|
Logger::Print(23, "\n");
|
|
|
|
Logger::Print(23, "******* script compile error *******\n");
|
|
|
|
Logger::Print(23, "Error: unknown function %s in %s\n", funcName.data(), Script::ScriptName.data());
|
|
|
|
Logger::Print(23, "************************************\n");
|
2016-05-29 10:16:15 -04:00
|
|
|
|
2016-06-04 08:25:55 -04:00
|
|
|
Logger::Error(5, "script compile error\nunknown function %s\n%s\n\n", funcName.data(), Script::ScriptName.data());
|
2016-05-29 10:16:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void __declspec(naked) Script::StoreFunctionNameStub()
|
|
|
|
{
|
|
|
|
__asm
|
|
|
|
{
|
|
|
|
mov eax, [esp - 8h]
|
|
|
|
mov Script::FunctionName, ax
|
|
|
|
|
|
|
|
sub esp, 0Ch
|
|
|
|
push 0
|
|
|
|
push edi
|
|
|
|
|
|
|
|
mov eax, 612DB6h
|
|
|
|
jmp eax
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Script::StoreScriptName(const char* name)
|
|
|
|
{
|
|
|
|
Script::ScriptNameStack.push_back(Script::ScriptName);
|
|
|
|
Script::ScriptName = name;
|
|
|
|
|
|
|
|
if (!Utils::EndsWith(Script::ScriptName, ".gsc"))
|
|
|
|
{
|
|
|
|
Script::ScriptName.append(".gsc");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void __declspec(naked) Script::StoreScriptNameStub()
|
|
|
|
{
|
|
|
|
__asm
|
|
|
|
{
|
|
|
|
lea ecx, [esp + 10h]
|
|
|
|
push ecx
|
|
|
|
|
|
|
|
call Script::StoreScriptName
|
|
|
|
add esp, 4h
|
|
|
|
|
|
|
|
push ebp
|
|
|
|
mov ebp, ds:1CDEAA8h
|
|
|
|
mov ecx, 427DC3h
|
|
|
|
jmp ecx
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Script::RestoreScriptName()
|
|
|
|
{
|
|
|
|
Script::ScriptName = Script::ScriptNameStack.back();
|
|
|
|
Script::ScriptNameStack.pop_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
void __declspec(naked) Script::RestoreScriptNameStub()
|
|
|
|
{
|
|
|
|
__asm
|
|
|
|
{
|
|
|
|
call Script::RestoreScriptName
|
|
|
|
|
|
|
|
mov ds:1CDEAA8h, ebp
|
|
|
|
|
|
|
|
mov eax, 427E77h
|
|
|
|
jmp eax
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-04 08:25:55 -04:00
|
|
|
void Script::PrintSourcePos(const char* filename, unsigned int offset)
|
2016-05-29 10:16:15 -04:00
|
|
|
{
|
2016-06-04 08:25:55 -04:00
|
|
|
FileSystem::File script(filename);
|
2016-05-29 10:16:15 -04:00
|
|
|
|
2016-06-04 08:25:55 -04:00
|
|
|
if (script.Exists())
|
2016-05-29 10:16:15 -04:00
|
|
|
{
|
2016-06-04 08:25:55 -04:00
|
|
|
std::string buffer = script.GetBuffer();
|
|
|
|
Utils::Replace(buffer, "\t", " ");
|
2016-05-29 10:16:15 -04:00
|
|
|
|
2016-06-04 08:25:55 -04:00
|
|
|
int line = 1;
|
|
|
|
int lineOffset = 0;
|
|
|
|
int inlineOffset = 0;
|
2016-05-29 10:16:15 -04:00
|
|
|
|
2016-06-04 08:25:55 -04:00
|
|
|
for (unsigned int i = 0; i < buffer.size(); ++i)
|
2016-05-29 10:16:15 -04:00
|
|
|
{
|
2016-06-04 08:25:55 -04:00
|
|
|
// Terminate line
|
|
|
|
if (i == offset)
|
2016-05-29 10:16:15 -04:00
|
|
|
{
|
2016-06-04 08:25:55 -04:00
|
|
|
while (buffer[i] != '\r' && buffer[i] != '\n' && buffer[i] != '\0')
|
2016-05-29 10:16:15 -04:00
|
|
|
{
|
2016-06-04 08:25:55 -04:00
|
|
|
++i;
|
2016-05-29 10:16:15 -04:00
|
|
|
}
|
|
|
|
|
2016-06-04 08:25:55 -04:00
|
|
|
buffer[i] = '\0';
|
2016-05-29 10:16:15 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-06-04 08:25:55 -04:00
|
|
|
if (buffer[i] == '\n')
|
2016-05-29 10:16:15 -04:00
|
|
|
{
|
2016-06-04 08:25:55 -04:00
|
|
|
++line;
|
|
|
|
lineOffset = i; // Includes the line break!
|
|
|
|
inlineOffset = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
++inlineOffset;
|
2016-05-29 10:16:15 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-04 08:25:55 -04:00
|
|
|
Logger::Print(23, "in file %s, line %d:", filename, line);
|
|
|
|
Logger::Print(23, "%s\n", buffer.data() + lineOffset);
|
2016-05-29 10:16:15 -04:00
|
|
|
|
2016-06-04 08:25:55 -04:00
|
|
|
for (int i = 0; i < (inlineOffset - 1); ++i)
|
2016-05-29 10:16:15 -04:00
|
|
|
{
|
2016-06-03 18:06:07 -04:00
|
|
|
Logger::Print(23, " ");
|
2016-05-29 10:16:15 -04:00
|
|
|
}
|
|
|
|
|
2016-06-03 18:06:07 -04:00
|
|
|
Logger::Print(23, "*\n");
|
2016-05-29 10:16:15 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-06-04 08:25:55 -04:00
|
|
|
Logger::Print(23, "in file %s, offset %d\n", filename, offset);
|
2016-05-29 10:16:15 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-04 08:25:55 -04:00
|
|
|
void Script::CompileError(unsigned int offset, const char* message, ...)
|
2016-05-29 10:16:15 -04:00
|
|
|
{
|
|
|
|
char msgbuf[1024] = { 0 };
|
|
|
|
va_list v;
|
|
|
|
va_start(v, message);
|
|
|
|
_vsnprintf(msgbuf, sizeof(msgbuf), message, v);
|
|
|
|
va_end(v);
|
|
|
|
|
|
|
|
Game::Scr_ShutdownAllocNode();
|
|
|
|
|
2016-06-03 18:06:07 -04:00
|
|
|
Logger::Print(23, "\n");
|
|
|
|
Logger::Print(23, "******* script compile error *******\n");
|
|
|
|
Logger::Print(23, "Error: %s ", msgbuf);
|
2016-05-29 10:16:15 -04:00
|
|
|
Script::PrintSourcePos(Script::ScriptName.data(), offset);
|
2016-06-04 08:25:55 -04:00
|
|
|
Logger::Print(23, "************************************\n\n");
|
2016-05-29 10:16:15 -04:00
|
|
|
|
2016-06-03 18:06:07 -04:00
|
|
|
Logger::Error(5, "script compile error\n%s\n%s\n(see console for actual details)\n", msgbuf, Script::ScriptName.data());
|
2016-05-29 10:16:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
int Script::LoadScriptAndLabel(std::string script, std::string label)
|
|
|
|
{
|
|
|
|
Logger::Print("Loading script %s.gsc...\n", script.data());
|
|
|
|
|
|
|
|
if (!Game::Scr_LoadScript(script.data()))
|
|
|
|
{
|
|
|
|
Logger::Print("Script %s encountered an error while loading. (doesn't exist?)", script.data());
|
2016-06-03 18:06:07 -04:00
|
|
|
Logger::Error(1, (char*)0x70B810, script.data());
|
2016-05-29 10:16:15 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Logger::Print("Script %s.gsc loaded successfully.\n", script.data());
|
|
|
|
}
|
|
|
|
|
|
|
|
Logger::Print("Finding script handle %s::%s...\n", script.data(), label.data());
|
|
|
|
int handle = Game::Scr_GetFunctionHandle(script.data(), label.data());
|
|
|
|
if (handle)
|
|
|
|
{
|
|
|
|
Logger::Print("Script handle %s::%s loaded successfully.\n", script.data(), label.data());
|
|
|
|
return handle;
|
|
|
|
}
|
|
|
|
|
|
|
|
Logger::Print("Script handle %s::%s couldn't be loaded. (file with no entry point?)\n", script.data(), label.data());
|
|
|
|
return handle;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Script::LoadGameType()
|
|
|
|
{
|
|
|
|
for (auto handle : Script::ScriptHandles)
|
|
|
|
{
|
|
|
|
Game::Scr_FreeThread(Game::Scr_ExecThread(handle, 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
Game::Scr_LoadGameType();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Script::LoadGameTypeScript()
|
|
|
|
{
|
|
|
|
Script::ScriptHandles.clear();
|
|
|
|
|
|
|
|
auto list = FileSystem::GetFileList("scripts/", "gsc");
|
|
|
|
|
|
|
|
for (auto file : list)
|
|
|
|
{
|
|
|
|
file = "scripts/" + file;
|
|
|
|
|
|
|
|
if (Utils::EndsWith(file, ".gsc"))
|
|
|
|
{
|
|
|
|
file = file.substr(0, file.size() - 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
int handle = Script::LoadScriptAndLabel(file, "init");
|
|
|
|
|
|
|
|
if (handle)
|
|
|
|
{
|
|
|
|
Script::ScriptHandles.push_back(handle);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Game::GScr_LoadGameTypeScript();
|
|
|
|
}
|
|
|
|
|
|
|
|
Script::Script()
|
|
|
|
{
|
|
|
|
Utils::Hook(0x612DB0, Script::StoreFunctionNameStub, HOOK_JUMP).Install()->Quick();
|
|
|
|
Utils::Hook(0x427E71, Script::RestoreScriptNameStub, HOOK_JUMP).Install()->Quick();
|
|
|
|
Utils::Hook(0x427DBC, Script::StoreScriptNameStub, HOOK_JUMP).Install()->Quick();
|
|
|
|
|
|
|
|
Utils::Hook(0x612E8D, Script::FunctionError, HOOK_CALL).Install()->Quick();
|
|
|
|
Utils::Hook(0x612EA2, Script::FunctionError, HOOK_CALL).Install()->Quick();
|
|
|
|
Utils::Hook(0x434260, Script::CompileError, HOOK_JUMP).Install()->Quick();
|
|
|
|
|
|
|
|
Utils::Hook(0x48EFFE, Script::LoadGameType, HOOK_CALL).Install()->Quick();
|
|
|
|
Utils::Hook(0x45D44A, Script::LoadGameTypeScript, HOOK_CALL).Install()->Quick();
|
|
|
|
}
|
|
|
|
|
|
|
|
Script::~Script()
|
|
|
|
{
|
|
|
|
Script::ScriptName.clear();
|
|
|
|
Script::ScriptHandles.clear();
|
|
|
|
Script::ScriptNameStack.clear();
|
|
|
|
}
|
|
|
|
}
|