[Merge] bugs/mod-downloading -> feature/vs2017
This commit is contained in:
commit
a4dd14cde7
@ -10,16 +10,21 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.
|
|||||||
|
|
||||||
- Show friend avatars when they play IW4x (request)
|
- Show friend avatars when they play IW4x (request)
|
||||||
- Cod4 style fast download for usermaps
|
- Cod4 style fast download for usermaps
|
||||||
|
- Display a toast when an update is available.
|
||||||
|
- Use the hourglass cursor while loading assets (with the native cursor feature).
|
||||||
|
- Show bots in parenthesis after the number of players in the serverlist (request).
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
- Show friend avatars when they play IW4x (request).
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fix lags and frame drops caused by server sorting
|
- Fix lags and frame drops caused by server sorting
|
||||||
- Fix demos on custom maps
|
- Fix demos on custom maps
|
||||||
- Can no longer join a lobby with an incorrect password
|
- Can no longer join a lobby with an incorrect password
|
||||||
|
- Fix lags and frame drops caused by server sorting.
|
||||||
|
- Fix demos on custom maps.
|
||||||
|
|
||||||
## [0.5.0] - 2017-06-04
|
## [0.5.0] - 2017-06-04
|
||||||
|
|
||||||
|
@ -11,12 +11,12 @@ namespace Components
|
|||||||
|
|
||||||
#pragma region Client
|
#pragma region Client
|
||||||
|
|
||||||
void Download::InitiateMapDownload(std::string map)
|
void Download::InitiateMapDownload(std::string map, bool needPassword)
|
||||||
{
|
{
|
||||||
Download::InitiateClientDownload(map, true);
|
Download::InitiateClientDownload(map, needPassword, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Download::InitiateClientDownload(std::string mod, bool map)
|
void Download::InitiateClientDownload(std::string mod, bool needPassword, bool map)
|
||||||
{
|
{
|
||||||
if (Download::CLDownload.running) return;
|
if (Download::CLDownload.running) return;
|
||||||
|
|
||||||
@ -29,6 +29,18 @@ namespace Components
|
|||||||
|
|
||||||
Command::Execute("openmenu mod_download_popmenu", false);
|
Command::Execute("openmenu mod_download_popmenu", false);
|
||||||
|
|
||||||
|
if (needPassword)
|
||||||
|
{
|
||||||
|
std::string pass = Dvar::Var("password").get<std::string>();
|
||||||
|
if (!pass.length())
|
||||||
|
{
|
||||||
|
// shouldn't ever happen but this is safe
|
||||||
|
Party::ConnectError("A password is required to connect to this server!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Download::CLDownload.hashedPassword = Utils::Cryptography::SHA256::Compute(pass);
|
||||||
|
}
|
||||||
|
|
||||||
Download::CLDownload.running = true;
|
Download::CLDownload.running = true;
|
||||||
Download::CLDownload.isMap = map;
|
Download::CLDownload.isMap = map;
|
||||||
Download::CLDownload.mod = mod;
|
Download::CLDownload.mod = mod;
|
||||||
@ -37,6 +49,7 @@ namespace Components
|
|||||||
Download::CLDownload.lastTimeStamp = 0;
|
Download::CLDownload.lastTimeStamp = 0;
|
||||||
Download::CLDownload.downBytes = 0;
|
Download::CLDownload.downBytes = 0;
|
||||||
Download::CLDownload.timeStampBytes = 0;
|
Download::CLDownload.timeStampBytes = 0;
|
||||||
|
Download::CLDownload.isPrivate = needPassword;
|
||||||
Download::CLDownload.target = Party::Target();
|
Download::CLDownload.target = Party::Target();
|
||||||
Download::CLDownload.thread = std::thread(Download::ModDownloader, &Download::CLDownload);
|
Download::CLDownload.thread = std::thread(Download::ModDownloader, &Download::CLDownload);
|
||||||
}
|
}
|
||||||
@ -192,7 +205,33 @@ namespace Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string url = "http://" + download->target.getString() + "/file/" + (download->isMap ? "map/" : "") + file.name;
|
std::string host = "http://" + download->target.getString();
|
||||||
|
std::string fastHost = "http://" + Dvar::Var("sv_wwwBaseUrl").get<std::string>();
|
||||||
|
|
||||||
|
std::string url;
|
||||||
|
|
||||||
|
// file directory for fasthost looks like this
|
||||||
|
// /-usermaps
|
||||||
|
// /-mp_test
|
||||||
|
// -mp_test.ff
|
||||||
|
// -mp_test.iwd
|
||||||
|
// /-mp_whatever
|
||||||
|
// /-mp_whatever.ff
|
||||||
|
// /-mods
|
||||||
|
// /-mod1
|
||||||
|
// -mod1.iwd
|
||||||
|
// -mod.ff
|
||||||
|
// /-mod2
|
||||||
|
// ...
|
||||||
|
if (Dvar::Var("sv_wwwDownload").get<bool>())
|
||||||
|
{
|
||||||
|
url = fastHost + path;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
url = host + "/file/" + (download->isMap ? "map/" : "") + file.name
|
||||||
|
+ (download->isPrivate ? ("?password=" + download->hashedPassword) : "");
|
||||||
|
}
|
||||||
|
|
||||||
Download::FileDownload fDownload;
|
Download::FileDownload fDownload;
|
||||||
fDownload.file = file;
|
fDownload.file = file;
|
||||||
@ -233,7 +272,9 @@ namespace Components
|
|||||||
|
|
||||||
std::string host = "http://" + download->target.getString();
|
std::string host = "http://" + download->target.getString();
|
||||||
|
|
||||||
std::string list = Utils::WebIO("IW4x", host + (download->isMap ? "/map" : "/list")).setTimeout(5000)->get();
|
std::string listUrl = host + (download->isMap ? "/map" : "/list") + (download->isPrivate ? ("?password=" + download->hashedPassword) : "");
|
||||||
|
|
||||||
|
std::string list = Utils::WebIO("IW4x", listUrl).setTimeout(5000)->get();
|
||||||
if (list.empty())
|
if (list.empty())
|
||||||
{
|
{
|
||||||
if (download->terminateThread) return;
|
if (download->terminateThread) return;
|
||||||
@ -361,6 +402,33 @@ namespace Components
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Download::VerifyPassword(mg_connection *nc, http_message* message)
|
||||||
|
{
|
||||||
|
std::string g_password = Dvar::Var("g_password").get<std::string>();
|
||||||
|
|
||||||
|
if (!g_password.size()) return true;
|
||||||
|
|
||||||
|
Utils::Memory::Allocator* alloc = Utils::Memory::GetAllocator();
|
||||||
|
|
||||||
|
// sha256 hashes are 64 chars long but we're gonna be safe here
|
||||||
|
char* buffer = alloc->allocateArray<char>(128);
|
||||||
|
int passLen = mg_get_http_var(&message->query_string, "password", buffer, 128);
|
||||||
|
|
||||||
|
if (passLen <= 0 || std::string(buffer, passLen) != g_password)//Utils::Cryptography::SHA256::Compute(g_password))
|
||||||
|
{
|
||||||
|
mg_printf(nc, ("HTTP/1.1 403 Forbidden\r\n"s +
|
||||||
|
"Content-Type: text/html\r\n"s +
|
||||||
|
"Connection: close\r\n"s +
|
||||||
|
"\r\n"s +
|
||||||
|
((passLen == 0) ? "Password Required"s : "Invalid Password"s)).c_str());
|
||||||
|
|
||||||
|
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Download::Forbid(mg_connection *nc)
|
void Download::Forbid(mg_connection *nc)
|
||||||
{
|
{
|
||||||
mg_printf(nc, "HTTP/1.1 403 Forbidden\r\n"
|
mg_printf(nc, "HTTP/1.1 403 Forbidden\r\n"
|
||||||
@ -372,11 +440,13 @@ namespace Components
|
|||||||
nc->flags |= MG_F_SEND_AND_CLOSE;
|
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Download::MapHandler(mg_connection *nc, int ev, void* /*ev_data*/)
|
void Download::MapHandler(mg_connection *nc, int ev, void* ev_data)
|
||||||
{
|
{
|
||||||
// Only handle http requests
|
// Only handle http requests
|
||||||
if (ev != MG_EV_HTTP_REQUEST) return;
|
if (ev != MG_EV_HTTP_REQUEST) return;
|
||||||
|
|
||||||
|
if (!Download::VerifyPassword(nc, reinterpret_cast<http_message*>(ev_data))) return;
|
||||||
|
|
||||||
static std::string mapnamePre;
|
static std::string mapnamePre;
|
||||||
static json11::Json jsonList;
|
static json11::Json jsonList;
|
||||||
|
|
||||||
@ -423,11 +493,13 @@ namespace Components
|
|||||||
nc->flags |= MG_F_SEND_AND_CLOSE;
|
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Download::ListHandler(mg_connection* nc, int ev, void* /*ev_data*/)
|
void Download::ListHandler(mg_connection* nc, int ev, void* ev_data)
|
||||||
{
|
{
|
||||||
// Only handle http requests
|
// Only handle http requests
|
||||||
if (ev != MG_EV_HTTP_REQUEST) return;
|
if (ev != MG_EV_HTTP_REQUEST) return;
|
||||||
|
|
||||||
|
if (!Download::VerifyPassword(nc, reinterpret_cast<http_message*>(ev_data))) return;
|
||||||
|
|
||||||
// if (!Download::IsClient(nc))
|
// if (!Download::IsClient(nc))
|
||||||
// {
|
// {
|
||||||
// Download::Forbid(nc);
|
// Download::Forbid(nc);
|
||||||
@ -487,6 +559,8 @@ namespace Components
|
|||||||
|
|
||||||
http_message* message = reinterpret_cast<http_message*>(ev_data);
|
http_message* message = reinterpret_cast<http_message*>(ev_data);
|
||||||
|
|
||||||
|
//if (!Download::VerifyPassword(nc, message)) return;
|
||||||
|
|
||||||
// if (!Download::IsClient(nc))
|
// if (!Download::IsClient(nc))
|
||||||
// {
|
// {
|
||||||
// Download::Forbid(nc);
|
// Download::Forbid(nc);
|
||||||
@ -567,12 +641,12 @@ namespace Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Download::InfoHandler(mg_connection* nc, int ev, void* /*ev_data*/)
|
void Download::InfoHandler(mg_connection* nc, int ev, void* ev_data)
|
||||||
{
|
{
|
||||||
// Only handle http requests
|
// Only handle http requests
|
||||||
if (ev != MG_EV_HTTP_REQUEST) return;
|
if (ev != MG_EV_HTTP_REQUEST) return;
|
||||||
|
|
||||||
//http_message* message = reinterpret_cast<http_message*>(ev_data);
|
//if (!Download::VerifyPassword(nc, reinterpret_cast<http_message*>(ev_data))) return;
|
||||||
|
|
||||||
Utils::InfoString status = ServerInfo::GetInfo();
|
Utils::InfoString status = ServerInfo::GetInfo();
|
||||||
|
|
||||||
@ -738,6 +812,12 @@ namespace Components
|
|||||||
mg_mgr_poll(&Download::Mgr, 100);
|
mg_mgr_poll(&Download::Mgr, 100);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Dvar::OnInit([]()
|
||||||
|
{
|
||||||
|
Dvar::Register<bool>("sv_wwwDownload", false, Game::dvar_flag::DVAR_FLAG_DEDISAVED, "Set to true to enable downloading maps/mods from an external server.");
|
||||||
|
Dvar::Register<const char*>("sv_wwwBaseUrl", "", Game::dvar_flag::DVAR_FLAG_DEDISAVED, "Set to the base url for the external map download.");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -746,6 +826,8 @@ namespace Components
|
|||||||
Dvar::Register<const char*>("ui_dl_timeLeft", "", Game::dvar_flag::DVAR_FLAG_NONE, "");
|
Dvar::Register<const char*>("ui_dl_timeLeft", "", Game::dvar_flag::DVAR_FLAG_NONE, "");
|
||||||
Dvar::Register<const char*>("ui_dl_progress", "", Game::dvar_flag::DVAR_FLAG_NONE, "");
|
Dvar::Register<const char*>("ui_dl_progress", "", Game::dvar_flag::DVAR_FLAG_NONE, "");
|
||||||
Dvar::Register<const char*>("ui_dl_transRate", "", Game::dvar_flag::DVAR_FLAG_NONE, "");
|
Dvar::Register<const char*>("ui_dl_transRate", "", Game::dvar_flag::DVAR_FLAG_NONE, "");
|
||||||
|
Dvar::Register<bool>("sv_wwwDownload", false, Game::dvar_flag::DVAR_FLAG_DEDISAVED, "Set to true to enable downloading maps/mods from an external server.");
|
||||||
|
Dvar::Register<const char*>("sv_wwwBaseUrl", "", Game::dvar_flag::DVAR_FLAG_DEDISAVED, "Set to the base url for the external map download.");
|
||||||
});
|
});
|
||||||
|
|
||||||
UIScript::Add("mod_download_cancel", [](UIScript::Token)
|
UIScript::Add("mod_download_cancel", [](UIScript::Token)
|
||||||
|
@ -11,8 +11,8 @@ namespace Components
|
|||||||
|
|
||||||
void preDestroy() override;
|
void preDestroy() override;
|
||||||
|
|
||||||
static void InitiateClientDownload(std::string mod, bool map = false);
|
static void InitiateClientDownload(std::string mod, bool needPassword, bool map = false);
|
||||||
static void InitiateMapDownload(std::string map);
|
static void InitiateMapDownload(std::string map, bool needPassword);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class ClientDownload
|
class ClientDownload
|
||||||
@ -25,8 +25,10 @@ namespace Components
|
|||||||
bool valid;
|
bool valid;
|
||||||
bool terminateThread;
|
bool terminateThread;
|
||||||
bool isMap;
|
bool isMap;
|
||||||
|
bool isPrivate;
|
||||||
mg_mgr mgr;
|
mg_mgr mgr;
|
||||||
Network::Address target;
|
Network::Address target;
|
||||||
|
std::string hashedPassword;
|
||||||
std::string mod;
|
std::string mod;
|
||||||
std::thread thread;
|
std::thread thread;
|
||||||
|
|
||||||
@ -209,6 +211,8 @@ namespace Components
|
|||||||
static std::thread ServerThread;
|
static std::thread ServerThread;
|
||||||
static bool Terminate;
|
static bool Terminate;
|
||||||
|
|
||||||
|
static bool VerifyPassword(mg_connection *nc, http_message* message);
|
||||||
|
|
||||||
static void EventHandler(mg_connection *nc, int ev, void *ev_data);
|
static void EventHandler(mg_connection *nc, int ev, void *ev_data);
|
||||||
static void ListHandler(mg_connection *nc, int ev, void *ev_data);
|
static void ListHandler(mg_connection *nc, int ev, void *ev_data);
|
||||||
static void MapHandler(mg_connection *nc, int ev, void *ev_data);
|
static void MapHandler(mg_connection *nc, int ev, void *ev_data);
|
||||||
|
@ -370,6 +370,9 @@ namespace Components
|
|||||||
info.set("matchtype", "0");
|
info.set("matchtype", "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info.set("wwwDownload", (Dvar::Var("sv_wwwDownload").get<bool>() ? "1" : "0"));
|
||||||
|
info.set("wwwUrl", Dvar::Var("sv_wwwBaseUrl").get<std::string>());
|
||||||
|
|
||||||
Network::SendCommand(address, "infoResponse", "\\" + info.build());
|
Network::SendCommand(address, "infoResponse", "\\" + info.build());
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -393,6 +396,18 @@ namespace Components
|
|||||||
|
|
||||||
std::string mod = Dvar::Var("fs_game").get<std::string>();
|
std::string mod = Dvar::Var("fs_game").get<std::string>();
|
||||||
|
|
||||||
|
// set fast server stuff here so its updated when we go to download stuff
|
||||||
|
if (info.get("wwwDownload") == "1"s)
|
||||||
|
{
|
||||||
|
Dvar::Var("sv_wwwDownload").set(true);
|
||||||
|
Dvar::Var("sv_wwwBaseUrl").set(info.get("wwwUrl"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Dvar::Var("sv_wwwDownload").set(false);
|
||||||
|
Dvar::Var("sv_wwwBaseUrl").set("");
|
||||||
|
}
|
||||||
|
|
||||||
if (info.get("challenge") != Party::Container.challenge)
|
if (info.get("challenge") != Party::Container.challenge)
|
||||||
{
|
{
|
||||||
Party::ConnectError("Invalid join response: Challenge mismatch.");
|
Party::ConnectError("Invalid join response: Challenge mismatch.");
|
||||||
@ -415,15 +430,19 @@ namespace Components
|
|||||||
{
|
{
|
||||||
Party::ConnectError("Invalid map or gametype.");
|
Party::ConnectError("Invalid map or gametype.");
|
||||||
}
|
}
|
||||||
|
else if (Party::Container.info.get("isPrivate") == "1"s && !Dvar::Var("password").get<std::string>().length())
|
||||||
|
{
|
||||||
|
Party::ConnectError("A password is required to join this server! Set it at the bottom of the serverlist.");
|
||||||
|
}
|
||||||
else if (isUsermap && usermapHash != Maps::GetUsermapHash(info.get("mapname")))
|
else if (isUsermap && usermapHash != Maps::GetUsermapHash(info.get("mapname")))
|
||||||
{
|
{
|
||||||
Command::Execute("closemenu popup_reconnectingtoparty");
|
Command::Execute("closemenu popup_reconnectingtoparty");
|
||||||
Download::InitiateMapDownload(info.get("mapname"));
|
Download::InitiateMapDownload(info.get("mapname"), info.get("isPrivate") == "1");
|
||||||
}
|
}
|
||||||
else if (!info.get("fs_game").empty() && Utils::String::ToLower(mod) != Utils::String::ToLower(info.get("fs_game")))
|
else if (!info.get("fs_game").empty() && Utils::String::ToLower(mod) != Utils::String::ToLower(info.get("fs_game")))
|
||||||
{
|
{
|
||||||
Command::Execute("closemenu popup_reconnectingtoparty");
|
Command::Execute("closemenu popup_reconnectingtoparty");
|
||||||
Download::InitiateClientDownload(info.get("fs_game"));
|
Download::InitiateClientDownload(info.get("fs_game"), info.get("isPrivate") == "1"s);
|
||||||
}
|
}
|
||||||
else if (!Dvar::Var("fs_game").get<std::string>().empty() && info.get("fs_game").empty())
|
else if (!Dvar::Var("fs_game").get<std::string>().empty() && info.get("fs_game").empty())
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user