[Maps] Download missing map on map rotation

This commit is contained in:
momo5502 2017-04-07 21:37:01 +02:00
parent 9cc8da0786
commit 0a00ceef9e
6 changed files with 171 additions and 107 deletions

View File

@ -549,6 +549,12 @@ namespace Components
Game::DB_LoadXAssets(&info, 1, true); Game::DB_LoadXAssets(&info, 1, true);
}); });
Command::Add("awaitDatabase", [](Command::Params*)
{
Logger::Print("Waiting for database...\n");
while (!Game::Sys_IsDatabaseReady()) std::this_thread::sleep_for(100ms);
});
#ifdef DEBUG #ifdef DEBUG
// ZoneBuilder debugging // ZoneBuilder debugging
Utils::IO::WriteFile("userraw/logs/iw4_reads.log", "", false); Utils::IO::WriteFile("userraw/logs/iw4_reads.log", "", false);
@ -558,7 +564,7 @@ namespace Components
FastFiles::StreamRead = true; FastFiles::StreamRead = true;
Utils::Hook::Call<void(bool)>(0x4B8DB0)(true); // currently set to Load_GfxWorld Utils::Hook::Call<void(bool)>(0x4B8DB0)(true); // currently set to Load_GfxWorld
FastFiles::StreamRead = false; FastFiles::StreamRead = false;
}, HOOK_CALL).install()->quick(); }, HOOK_CALL).install()/*->quick()*/;
#endif #endif
} }

View File

@ -416,6 +416,52 @@ namespace Components
return 0; return 0;
} }
int Maps::TriggerReconnectForMap(const char* mapname)
{
Theatre::StopRecording();
if(!Maps::CheckMapInstalled(mapname, false, true))
{
// Reconnecting forces the client to download the new map
Command::Execute("disconnect", false);
Command::Execute("awaitDatabase", false); // Wait for the database to load
Command::Execute("wait 100", false);
Command::Execute("openmenu popup_reconnectingtoparty", false);
Command::Execute("wait 8000", false); // Seems like 8000ms?
Command::Execute("closemenu popup_reconnectingtoparty", false);
Command::Execute("reconnect", false);
return true;
}
return false;
}
__declspec(naked) void Maps::RotateCheckStub()
{
__asm
{
push eax
pushad
push [esp + 28h]
call Maps::TriggerReconnectForMap
add esp, 4h
mov[esp + 20h], eax
popad
pop eax
test eax, eax
jnz skipRotation
push 487C50h // Rotate map
skipRotation:
retn
}
}
__declspec(naked) void Maps::SpawnServerStub() __declspec(naked) void Maps::SpawnServerStub()
{ {
__asm __asm
@ -622,7 +668,6 @@ namespace Components
} }
Dvar::Var("isDlcInstalled_All").setRaw(hasAllDlcs ? 1 : 0); Dvar::Var("isDlcInstalled_All").setRaw(hasAllDlcs ? 1 : 0);
} }
void Maps::reallocateEntryPool() void Maps::reallocateEntryPool()
@ -672,24 +717,29 @@ namespace Components
Utils::Hook::Set<Game::XAssetEntry*>(0x5BAEA2, Maps::EntryPool.data() + 1); Utils::Hook::Set<Game::XAssetEntry*>(0x5BAEA2, Maps::EntryPool.data() + 1);
} }
bool Maps::CheckMapInstalled(const char* mapname, bool error) // dlcIsTrue serves as a check if the map is a custom map and if it's missing
bool Maps::CheckMapInstalled(const char* mapname, bool error, bool dlcIsTrue)
{ {
if (FastFiles::Exists(mapname)) return true; if (FastFiles::Exists(mapname)) return true;
if (!error) return false;
for (auto& pack : Maps::DlcPacks) for (auto& pack : Maps::DlcPacks)
{ {
for (auto map : pack.maps) for (auto map : pack.maps)
{ {
if (map == std::string(mapname)) if (map == std::string(mapname))
{
if (error)
{ {
Components::Logger::SoftError("Missing DLC pack %s (%d) containing map %s (%s).\nPlease download it to play this map.", Components::Logger::SoftError("Missing DLC pack %s (%d) containing map %s (%s).\nPlease download it to play this map.",
pack.name.data(), pack.index, Game::UI_LocalizeMapName(mapname), mapname); pack.name.data(), pack.index, Game::UI_LocalizeMapName(mapname), mapname);
} }
return dlcIsTrue;
}
} }
} }
Components::Logger::SoftError("Missing map file %s.\nYou may have a damaged installation or are attempting to load a non-existant map.", mapname); if (error) Components::Logger::SoftError("Missing map file %s.\nYou may have a damaged installation or are attempting to load a non-existant map.", mapname);
return false; return false;
} }
@ -820,6 +870,10 @@ namespace Components
Utils::Hook(0x5A9D51, Maps::LoadMapLoadscreenStub, HOOK_CALL).install()->quick(); Utils::Hook(0x5A9D51, Maps::LoadMapLoadscreenStub, HOOK_CALL).install()->quick();
Utils::Hook(0x5B34DD, Maps::LoadMapLoadscreenStub, HOOK_CALL).install()->quick(); Utils::Hook(0x5B34DD, Maps::LoadMapLoadscreenStub, HOOK_CALL).install()->quick();
// Download the map before a maprotation if necessary
// Conflicts with Theater's SV map rotation check, but this one is safer!
Utils::Hook(0x5AA91C, Maps::RotateCheckStub, HOOK_CALL).install()->quick();
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_GAMEWORLD_SP, 1); Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_GAMEWORLD_SP, 1);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_IMAGE, 7168); Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_IMAGE, 7168);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_LOADED_SOUND, 2700); Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_LOADED_SOUND, 2700);

View File

@ -55,7 +55,7 @@ namespace Components
static std::string CurrentMainZone; static std::string CurrentMainZone;
static bool CheckMapInstalled(const char* mapname, bool error = false); static bool CheckMapInstalled(const char* mapname, bool error = false, bool dlcIsTrue = false);
static UserMapContainer* GetUserMap(); static UserMapContainer* GetUserMap();
static unsigned int GetUsermapHash(std::string map); static unsigned int GetUsermapHash(std::string map);
@ -102,7 +102,8 @@ namespace Components
static void SpawnServerStub(); static void SpawnServerStub();
static void LoadMapLoadscreenStub(); static void LoadMapLoadscreenStub();
static void IwdFreeStub(Game::iwd_t* iwd); static int TriggerReconnectForMap(const char* mapname);
static void RotateCheckStub();
void reallocateEntryPool(); void reallocateEntryPool();
}; };

View File

@ -267,7 +267,7 @@ namespace Components
{ {
if (Party::Container.valid) if (Party::Container.valid)
{ {
if ((Game::Sys_Milliseconds() - Party::Container.joinTime) > 5000) if ((Game::Sys_Milliseconds() - Party::Container.joinTime) > 10'000)
{ {
Party::Container.valid = false; Party::Container.valid = false;
Party::ConnectError("Server connection timed out."); Party::ConnectError("Server connection timed out.");
@ -276,7 +276,7 @@ namespace Components
if (Party::Container.awaitingPlaylist) if (Party::Container.awaitingPlaylist)
{ {
if ((Game::Sys_Milliseconds() - Party::Container.requestTime) > 5000) if ((Game::Sys_Milliseconds() - Party::Container.requestTime) > 5'000)
{ {
Party::Container.awaitingPlaylist = false; Party::Container.awaitingPlaylist = false;
Party::ConnectError("Playlist request timed out."); Party::ConnectError("Playlist request timed out.");

View File

@ -321,22 +321,23 @@ namespace Components
void Theatre::MapChangeStub() void Theatre::MapChangeStub()
{ {
if (*Game::demoRecording) Theatre::StopRecording();
{
Command::Execute("stoprecord", true);
}
Utils::Hook::Call<void()>(0x464A60)(); Utils::Hook::Call<void()>(0x464A60)();
} }
// DANGEROUS, DON'T USE THIS ONE!
void Theatre::MapChangeSVStub(char* a1, char* a2) void Theatre::MapChangeSVStub(char* a1, char* a2)
{
Theatre::StopRecording();
Utils::Hook::Call<void(char*, char*)>(0x487C50)(a1, a2);
}
void Theatre::StopRecording()
{ {
if (*Game::demoRecording) if (*Game::demoRecording)
{ {
Command::Execute("stoprecord", true); Command::Execute("stoprecord", true);
} }
Utils::Hook::Call<void(char*, char*)>(0x487C50)(a1, a2);
} }
Theatre::Theatre() Theatre::Theatre()
@ -359,7 +360,7 @@ namespace Components
// Autorecording // Autorecording
Utils::Hook(0x5A1D6A, Theatre::InitCGameStub, HOOK_CALL).install()->quick(); Utils::Hook(0x5A1D6A, Theatre::InitCGameStub, HOOK_CALL).install()->quick();
Utils::Hook(0x4A712A, Theatre::MapChangeStub, HOOK_CALL).install()->quick(); Utils::Hook(0x4A712A, Theatre::MapChangeStub, HOOK_CALL).install()->quick();
Utils::Hook(0x5AA91C, Theatre::MapChangeSVStub, HOOK_CALL).install()->quick(); //Utils::Hook(0x5AA91C, Theatre::MapChangeSVStub, HOOK_CALL).install()->quick();
// UIScripts // UIScripts
UIScript::Add("loadDemos", Theatre::LoadDemos); UIScript::Add("loadDemos", Theatre::LoadDemos);

View File

@ -11,6 +11,8 @@ namespace Components
const char* getName() override { return "Theatre"; }; const char* getName() override { return "Theatre"; };
#endif #endif
static void StopRecording();
private: private:
class DemoInfo class DemoInfo
{ {