[Download] Implement gsc http download

This commit is contained in:
momo5502 2017-05-14 20:14:52 +02:00
parent 309e2d2987
commit a5a56f1e72
7 changed files with 316 additions and 27 deletions

View File

@ -4,6 +4,7 @@ namespace Components
{
mg_mgr Download::Mgr;
Download::ClientDownload Download::CLDownload;
std::vector<Download::ScriptDownload> Download::ScriptDownloads;
#pragma region Client
@ -87,7 +88,7 @@ namespace Components
{
if (hm->message.p)
{
fDownload->downloading = false;
fDownload->downloading = true;
return;
}
}
@ -200,6 +201,7 @@ namespace Components
Utils::String::Replace(url, " ", "%20");
download->valid = true;
ZeroMemory(&download->mgr, sizeof download->mgr);
mg_mgr_init(&download->mgr, &fDownload);
mg_connect_http(&download->mgr, Download::DownloadHandler, url.data(), nullptr, nullptr);
@ -701,6 +703,7 @@ namespace Components
{
if (Dedicated::IsEnabled())
{
ZeroMemory(&Download::Mgr, sizeof Download::Mgr);
mg_mgr_init(&Download::Mgr, nullptr);
Network::OnStart([] ()
@ -742,6 +745,53 @@ namespace Components
Download::CLDownload.clear();
});
}
QuickPatch::OnFrame([]()
{
for(auto i = Download::ScriptDownloads.begin(); i != Download::ScriptDownloads.end();)
{
i->work();
if(i->isDone())
{
i = Download::ScriptDownloads.erase(i);
}
else ++i;
}
});
Script::OnVMShutdown([]()
{
Download::ScriptDownloads.clear();
});
Script::AddFunction("httpGet", [](Game::scr_entref_t)
{
if (Game::Scr_GetNumParam() < 1) return;
std::string url = Game::Scr_GetString(0);
unsigned int object = Game::AllocObject();
Game::Scr_AddObject(object);
Download::ScriptDownloads.push_back({ url, object });
Game::RemoveRefToObject(object);
});
Script::AddFunction("httpCancel", [](Game::scr_entref_t)
{
if (Game::Scr_GetNumParam() < 1) return;
unsigned int object = Game::Scr_GetObject(0);
for(auto& download : Download::ScriptDownloads)
{
if(object == download.getObject())
{
download.notifyDone(false, std::string());
break;
}
}
});
}
Download::~Download()
@ -758,5 +808,7 @@ namespace Components
{
Download::CLDownload.clear();
}
Download::ScriptDownloads.clear();
}
}

View File

@ -83,8 +83,144 @@ namespace Components
size_t receivedBytes;
};
class ScriptDownload
{
public:
ScriptDownload(std::string _url, unsigned int _object) : url(_url), object(_object), mgr(new mg_mgr), totalSize(0), receivedSize(0), done(false)
{
Game::AddRefToObject(this->getObject());
ZeroMemory(this->getMgr(), sizeof(*this->getMgr()));
mg_mgr_init(this->getMgr(), this);
mg_connect_http(this->getMgr(), ScriptDownload::Handler, this->getUrl().data(), nullptr, nullptr);
}
ScriptDownload(ScriptDownload&& other) noexcept
{
this->operator=(std::move(other));
}
ScriptDownload& operator=(ScriptDownload&& other) noexcept
{
this->object = other.object;
this->done = other.done;
this->totalSize = other.totalSize;
this->receivedSize = other.receivedSize;
this->url = std::move(other.url);
this->mgr = std::move(other.mgr);
this->getMgr()->user_data = this;
other.object = 0;
return *this;
}
~ScriptDownload()
{
if (this->getObject())
{
Game::RemoveRefToObject(this->getObject());
this->object = 0;
mg_mgr_free(this->getMgr());
}
}
void work()
{
mg_mgr_poll(this->getMgr(), 0);
}
void notifyProgress(size_t bytes)
{
this->receivedSize += bytes;
Game::Scr_AddInt(static_cast<int>(this->totalSize));
Game::Scr_AddInt(static_cast<int>(this->receivedSize));
Game::Scr_NotifyId(this->getObject(), Game::SL_GetString("progress", 0), 2);
}
void setSize(char* buf, size_t len)
{
if(buf && !this->totalSize)
{
std::string data(buf, len);
auto pos = data.find("Content-Length: ");
if(pos != std::string::npos)
{
data = data.substr(pos + 16);
pos = data.find("\r\n");
if (pos != std::string::npos)
{
data = data.substr(0, pos);
this->totalSize = size_t(atoll(data.data()));
return;
}
}
this->totalSize = ~0ul;
}
}
void notifyDone(bool success, std::string result)
{
if (this->isDone()) return;
Game::Scr_AddString(result.data()); // No binary data supported yet
Game::Scr_AddInt(success);
Game::Scr_NotifyId(this->getObject(), Game::SL_GetString("done", 0), 2);
this->done = true;
}
bool isDone() { return this->done; };
std::string getUrl() { return this->url; }
mg_mgr* getMgr() { return this->mgr.get(); }
unsigned int getObject() { return this->object; }
private:
std::string url;
unsigned int object;
std::shared_ptr<mg_mgr> mgr;
size_t totalSize;
size_t receivedSize;
bool done;
static void Handler(mg_connection *nc, int ev, void* ev_data)
{
http_message* hm = reinterpret_cast<http_message*>(ev_data);
ScriptDownload* object = reinterpret_cast<ScriptDownload*>(nc->mgr->user_data);
if (ev == MG_EV_RECV)
{
object->setSize(nc->recv_mbuf.buf, nc->recv_mbuf.len);
size_t bytes = static_cast<size_t>(*reinterpret_cast<int*>(ev_data));
object->notifyProgress(bytes);
}
else if (ev == MG_EV_HTTP_REPLY)
{
object->notifyDone(true, std::string(hm->body.p, hm->body.len));
}
else if(ev == MG_EV_CONNECT)
{
if (*static_cast<int*>(ev_data))
{
object->notifyDone(false, std::string());
}
}
}
};
static mg_mgr Mgr;
static ClientDownload CLDownload;
static std::vector<ScriptDownload> ScriptDownloads;
static void EventHandler(mg_connection *nc, int ev, void *ev_data);
static void ListHandler(mg_connection *nc, int ev, void *ev_data);

View File

@ -8,6 +8,8 @@ namespace Components
std::vector<std::string> Script::ScriptNameStack;
unsigned short Script::FunctionName;
Utils::Signal<Script::Callback> Script::VMShutdownSignal;
void Script::FunctionError()
{
std::string funcName = Game::SL_ConvertToString(Script::FunctionName);
@ -245,22 +247,25 @@ namespace Components
Script::ScriptFunctions.push_back({ name, function, isDev });
}
Game::scr_function_t Script::GetFunction(const char** name, int* isDev)
void Script::OnVMShutdown(Utils::Slot<Script::Callback> callback)
{
if (name && *name) OutputDebugStringA(*name);
Script::VMShutdownSignal.connect(callback);
}
Game::scr_function_t Script::GetFunction(void* caller, const char** name, int* isDev)
{
for (auto& function : Script::ScriptFunctions)
{
if (name)
if (name && *name)
{
if(std::string(*name) == function.getName())
if(Utils::String::ToLower(*name) == Utils::String::ToLower(function.getName()))
{
*name = function.getName();
*isDev = function.isDev();
return function.getFunction();
}
}
else
else if(caller == reinterpret_cast<void*>(0x465781))
{
Game::Scr_RegisterFunction(function.getFunction());
}
@ -273,37 +278,39 @@ namespace Components
{
__asm
{
push [esp + 8h]
push [esp + 8h]
mov eax, 5FA2B0h
call eax
test eax, eax
jnz returnSafe
sub esp, 8h
push [esp + 10h]
call Script::GetFunction
add esp, 0Ch
returnSafe:
add esp, 8h
pop edi
pop esi
retn
}
}
void Script::ScrShutdownSystemStub(int num)
{
Script::VMShutdownSignal();
// Scr_ShutdownSystem
Utils::Hook::Call<void(int)>(0x421EE0)(num);
}
int Script::SetExpFogStub()
{
if(Game::Scr_GetNumParam() == 6)
if (Game::Scr_GetNumParam() == 6)
{
Game::VariableValue*& scr_stack = *reinterpret_cast<Game::VariableValue**>(0x2040D00);
if(scr_stack)
{
std::memmove(&scr_stack[-4], &scr_stack[-5], sizeof(Game::VariableValue) * 6);
scr_stack += 1;
scr_stack[-6].type = Game::VAR_FLOAT;
scr_stack[-6].u.floatValue = 0;
std::memmove(&Game::scriptContainer->stack[-4], &Game::scriptContainer->stack[-5], sizeof(Game::VariableValue) * 6);
Game::scriptContainer->stack += 1;
Game::scriptContainer->stack[-6].type = Game::VAR_FLOAT;
Game::scriptContainer->stack[-6].u.floatValue = 0;
++*reinterpret_cast<DWORD*>(0x2040D0C);
}
++Game::scriptContainer->numParam;
}
return Game::Scr_GetNumParam();
@ -322,9 +329,18 @@ namespace Components
Utils::Hook(0x48EFFE, Script::LoadGameType, HOOK_CALL).install()->quick();
Utils::Hook(0x45D44A, Script::LoadGameTypeScript, HOOK_CALL).install()->quick();
Utils::Hook(0x44E72E, Script::GetFunctionStub, HOOK_CALL).install()->quick();
Utils::Hook(0x44E736, Script::GetFunctionStub, HOOK_JUMP).install()->quick(); // Scr_GetFunction
//Utils::Hook(0x4EC8E5, Script::GetFunctionStub, HOOK_JUMP).install()->quick(); // Scr_GetMethod
Utils::Hook(0x5F41A3, Script::SetExpFogStub, HOOK_CALL).install()->quick();
Utils::Hook(0x47548B, Script::ScrShutdownSystemStub, HOOK_CALL).install()->quick();
Utils::Hook(0x4D06BA, Script::ScrShutdownSystemStub, HOOK_CALL).install()->quick();
Script::AddFunction("debugBox", [](Game::scr_entref_t)
{
MessageBoxA(nullptr, Game::Scr_GetString(0), "DEBUG", 0);
}, true);
}
Script::~Script()
@ -333,5 +349,6 @@ namespace Components
Script::ScriptHandles.clear();
Script::ScriptNameStack.clear();
Script::ScriptFunctions.clear();
Script::VMShutdownSignal.clear();
}
}

View File

@ -6,6 +6,8 @@ namespace Components
class Script : public Component
{
public:
typedef void(Callback)();
class Function
{
public:
@ -31,6 +33,8 @@ namespace Components
static int LoadScriptAndLabel(std::string script, std::string label);
static void AddFunction(std::string name, Game::scr_function_t function, bool isDev = false);
static void OnVMShutdown(Utils::Slot<Callback> callback);
private:
static std::string ScriptName;
static std::vector<int> ScriptHandles;
@ -38,6 +42,8 @@ namespace Components
static std::vector<std::string> ScriptNameStack;
static unsigned short FunctionName;
static Utils::Signal<Callback> VMShutdownSignal;
static void CompileError(unsigned int offset, const char* message, ...);
static void PrintSourcePos(const char* filename, unsigned int offset);
@ -53,9 +59,11 @@ namespace Components
static void LoadGameType();
static void LoadGameTypeScript();
static Game::scr_function_t GetFunction(const char** name, int* isDev);
static Game::scr_function_t GetFunction(void* caller, const char** name, int* isDev);
static void GetFunctionStub();
static void ScrShutdownSystemStub(int);
static int SetExpFogStub();
};
}

View File

@ -2,6 +2,9 @@
namespace Game
{
AddRefToObject_t AddRefToObject = AddRefToObject_t(0x61C360);
AllocObject_t AllocObject = AllocObject_t(0x434320);
AngleVectors_t AngleVectors = AngleVectors_t(0x4691A0);
BG_GetNumWeapons_t BG_GetNumWeapons = BG_GetNumWeapons_t(0x4F5CC0);
@ -201,21 +204,30 @@ namespace Game
R_FlushSun_t R_FlushSun = R_FlushSun_t(0x53FB50);
R_SortWorldSurfaces_t R_SortWorldSurfaces = R_SortWorldSurfaces_t(0x53DC10);
RemoveRefToObject_t RemoveRefToObject = RemoveRefToObject_t(0x437190);
Scr_LoadGameType_t Scr_LoadGameType = Scr_LoadGameType_t(0x4D9520);
Scr_LoadScript_t Scr_LoadScript = Scr_LoadScript_t(0x45D940);
Scr_GetFunctionHandle_t Scr_GetFunctionHandle = Scr_GetFunctionHandle_t(0x4234F0);
Scr_GetString_t Scr_GetString = Scr_GetString_t(0x425900);
Scr_GetFloat_t Scr_GetFloat = Scr_GetFloat_t(0x443140);
Scr_GetInt_t Scr_GetInt = Scr_GetInt_t(0x4F31D0);
Scr_GetObject_t Scr_GetObject = Scr_GetObject_t(0x462100);
Scr_GetNumParam_t Scr_GetNumParam = Scr_GetNumParam_t(0x4B0E90);
Scr_ExecThread_t Scr_ExecThread = Scr_ExecThread_t(0x4AD0B0);
Scr_FreeThread_t Scr_FreeThread = Scr_FreeThread_t(0x4BD320);
Scr_AddString_t Scr_AddString = Scr_AddString_t(0x412310);
Scr_AddInt_t Scr_AddInt = Scr_AddInt_t(0x41D7D0);
Scr_AddFloat_t Scr_AddFloat = Scr_AddFloat_t(0x61E860);
Scr_AddObject_t Scr_AddObject = Scr_AddObject_t(0x430F40);
Scr_Notify_t Scr_Notify = Scr_Notify_t(0x4A4750);
Scr_ClearOutParams_t Scr_ClearOutParams = Scr_ClearOutParams_t(0x4386E0);
Scr_RegisterFunction_t Scr_RegisterFunction = Scr_RegisterFunction_t(0x492D50);
Scr_ShutdownAllocNode_t Scr_ShutdownAllocNode = Scr_ShutdownAllocNode_t(0x441650);
@ -367,6 +379,8 @@ namespace Game
XZone* g_zones = reinterpret_cast<XZone*>(0x14C0F80);
unsigned short* db_hashTable = reinterpret_cast<unsigned short*>(0x12412B0);
ScriptContainer* scriptContainer = reinterpret_cast<ScriptContainer*>(0x2040D00);
XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize)
{
int elSize = DB_GetXAssetSizeHandlers[type]();
@ -713,6 +727,27 @@ namespace Game
Game::SV_GameSendServerCommand(clientNum, 0, Utils::String::VA("%c \"%s\"", 0x67, message.data()));
}
__declspec(naked) void Scr_NotifyId(unsigned int /*id*/, unsigned __int16 /*stringValue*/, unsigned int /*paramcount*/)
{
__asm
{
pushad
mov eax, [esp + 2Ch] // paramcount
push [esp + 28h] // stringValue
push [esp + 28h] // id
mov edx, 61E670h // Scr_NotifyId
call edx
add esp, 8h
popad
retn
}
}
__declspec(naked) void IN_KeyUp(kbutton_t* /*button*/)
{
__asm

View File

@ -2,6 +2,12 @@
namespace Game
{
typedef void(__cdecl * AddRefToObject_t)(unsigned int id);
extern AddRefToObject_t AddRefToObject;
typedef unsigned int(__cdecl * AllocObject_t)();
extern AllocObject_t AllocObject;
typedef void(__cdecl * AngleVectors_t)(float *angles, float *forward, float *right, float *up);
extern AngleVectors_t AngleVectors;
@ -508,12 +514,21 @@ namespace Game
typedef GfxWorld*(__cdecl * R_SortWorldSurfaces_t)();
extern R_SortWorldSurfaces_t R_SortWorldSurfaces;
typedef void(__cdecl * RemoveRefToObject_t)(unsigned int id);
extern RemoveRefToObject_t RemoveRefToObject;
typedef void(__cdecl * Scr_AddString_t)(const char* str);
extern Scr_AddString_t Scr_AddString;
typedef int(__cdecl * Scr_AddFloat_t)(float);
typedef void(__cdecl * Scr_AddInt_t)(int num);
extern Scr_AddInt_t Scr_AddInt;
typedef void(__cdecl * Scr_AddFloat_t)(float);
extern Scr_AddFloat_t Scr_AddFloat;
typedef void(__cdecl * Scr_AddObject_t)(unsigned int id);
extern Scr_AddObject_t Scr_AddObject;
typedef void(__cdecl * Scr_ShutdownAllocNode_t)();
extern Scr_ShutdownAllocNode_t Scr_ShutdownAllocNode;
@ -523,9 +538,18 @@ namespace Game
typedef int(__cdecl * Scr_LoadScript_t)(const char*);
extern Scr_LoadScript_t Scr_LoadScript;
typedef char* (__cdecl * Scr_GetString_t)(int);
extern Scr_GetString_t Scr_GetString;
typedef float(__cdecl * Scr_GetFloat_t)(int);
extern Scr_GetFloat_t Scr_GetFloat;
typedef int(__cdecl * Scr_GetInt_t)(int);
extern Scr_GetInt_t Scr_GetInt;
typedef unsigned int(__cdecl * Scr_GetObject_t)(int);
extern Scr_GetObject_t Scr_GetObject;
typedef int(__cdecl * Scr_GetNumParam_t)();
extern Scr_GetNumParam_t Scr_GetNumParam;
@ -541,6 +565,9 @@ namespace Game
typedef void(__cdecl * Scr_Notify_t)(gentity_t *ent, unsigned __int16 stringValue, unsigned int paramcount);
extern Scr_Notify_t Scr_Notify;
typedef void(__cdecl * Scr_ClearOutParams_t)();
extern Scr_ClearOutParams_t Scr_ClearOutParams;
typedef void(__cdecl * Scr_RegisterFunction_t)(scr_function_t function);
extern Scr_RegisterFunction_t Scr_RegisterFunction;
@ -764,6 +791,8 @@ namespace Game
extern XZone* g_zones;
extern unsigned short* db_hashTable;
extern ScriptContainer* scriptContainer;
XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize);
void Menu_FreeItemMemory(Game::itemDef_t* item);
const char* TableLookup(StringTable* stringtable, int row, int column);
@ -792,6 +821,7 @@ namespace Game
void Scr_iPrintLn(int clientNum, std::string message);
void Scr_iPrintLnBold(int clientNum, std::string message);
void Scr_NotifyId(unsigned int id, unsigned __int16 stringValue, unsigned int paramcount);
void IN_KeyUp(kbutton_t* button);
void IN_KeyDown(kbutton_t* button);

View File

@ -18,7 +18,7 @@ namespace Game
typedef vec_t vec3_t[3];
typedef vec_t vec4_t[4];
typedef int scr_entref_t;
typedef unsigned int scr_entref_t;
typedef void(__cdecl * scr_function_t)(scr_entref_t);
typedef enum
@ -4044,6 +4044,17 @@ namespace Game
int type;
};
struct ScriptContainer
{
Game::VariableValue* stack;
char unk1;
char unk2;
char unk3;
char pad;
DWORD unk4;
int numParam;
};
#ifndef IDA
}
#endif