diff --git a/fastdl-rotator/scripting/fastdl_rotater.sp b/fastdl-rotator/scripting/fastdl_rotater.sp index 59876db..772f6aa 100644 --- a/fastdl-rotator/scripting/fastdl_rotater.sp +++ b/fastdl-rotator/scripting/fastdl_rotater.sp @@ -1,23 +1,22 @@ #include #include -#include +#include #include #pragma semicolon 1 #pragma newdecls required -Handle hPlayerSlot = INVALID_HANDLE; GameData gamedatafile; //Handle to the gamedata char originalConVar[1024]; //original sv_downloadurl value char g_cBackupURLS[2][1024]; char g_cIPaddresses[MAXPLAYERS + 1][256]; -int g_icurrentClient; StringMap g_SteamIDRotations; bool g_bDoesIndexHaveBZ2[sizeof(g_cBackupURLS)]; //must have same size as g_cBackupURLS +bool g_bRotated[MAXPLAYERS + 1]; ConVar downloadurl; // sv_downloadurl -public Plugin myinfo = +public Plugin myinfo = { name = "Fastdownload rotater", description = "Rotates fastdl used for clients when missing map errors happen", @@ -42,45 +41,30 @@ public void OnPluginStart() //we only use one backup fastdl but you could potentially have several. downloadurl = FindConVar("sv_downloadurl"); //Save original downloadurl, so we can send it to clients who we cant locate - downloadurl.GetString(originalConVar, sizeof(originalConVar)); + downloadurl.GetString(originalConVar, sizeof(originalConVar)); gamedatafile = LoadGameConfigFile("fastdl_rotater.games"); - + if(gamedatafile == null) SetFailState("Cannot load fastdl_rotater.games.txt! Make sure you have it installed!"); - + Handle detourBuildConVarMessage = DHookCreateDetour(Address_Null, CallConv_CDECL, ReturnType_Void, ThisPointer_Ignore); if(detourBuildConVarMessage == null) SetFailState("Failed to create detour for Host_BuildConVarUpdateMessage!"); - + if(!DHookSetFromConf(detourBuildConVarMessage, gamedatafile, SDKConf_Signature, "Host_BuildConVarUpdateMessage")) SetFailState("Failed to load Host_BuildConVarUpdateMessage signature from gamedata!"); DHookAddParam(detourBuildConVarMessage, HookParamType_Unknown); DHookAddParam(detourBuildConVarMessage, HookParamType_Int); - DHookAddParam(detourBuildConVarMessage, HookParamType_Bool); - + DHookAddParam(detourBuildConVarMessage, HookParamType_Bool); + if(!DHookEnableDetour(detourBuildConVarMessage, false, buildConVarMessageDetCallback_Pre)) SetFailState("Failed to detour Host_BuildConVarUpdateMessage PreHook!"); - - Handle detourSendServerInfo = DHookCreateDetour(Address_Null, CallConv_THISCALL, ReturnType_Bool, ThisPointer_Address); - if(detourSendServerInfo == null) - SetFailState("Failed to create detour for CBaseClient::SendServerInfo!"); - - if(!DHookSetFromConf(detourSendServerInfo, gamedatafile, SDKConf_Signature, "CBaseClient::SendServerInfo")) - SetFailState("Failed to load CBaseClient::SendServerInfo signature from gamedata!"); - - if(!DHookEnableDetour(detourSendServerInfo, false, sendServerInfoDetCallback_Pre)) - SetFailState("Failed to detour CBaseClient::SendServerInfo PreHook!"); HookEvent("player_disconnect", Event_PlayerDisconnect, EventHookMode_Pre); - StartPrepSDKCall(SDKCall_Raw); - PrepSDKCall_SetFromConf(gamedatafile, SDKConf_Virtual, "CBaseClient::GetPlayerSlot"); - PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); - hPlayerSlot = EndPrepSDKCall(); - OnMapStart(); } @@ -93,12 +77,13 @@ public Action Event_PlayerDisconnect(Handle event, const char[] name, bool dontB if (StrContains(reason, "Map is missing") != -1) { GetClientIP(client, g_cIPaddresses[client], sizeof(g_cIPaddresses[])); - + int rotated = -1; g_SteamIDRotations.GetValue(g_cIPaddresses[client], rotated); rotated++; g_SteamIDRotations.SetValue(g_cIPaddresses[client], rotated, true); } + g_bRotated[client] = false; return Plugin_Continue; } @@ -113,32 +98,32 @@ public void OnMapStart() g_bDoesIndexHaveBZ2[i] = false; //resetting to false until the http header finished FormatEx(sRequest, sizeof(sRequest), "%s%s%s%s", g_cBackupURLS[i], "maps/", map, ".bsp.bz2"); - Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodHEAD, sRequest); - if (!hRequest || - !SteamWorks_SetHTTPCallbacks(hRequest, OnTransferComplete) || - !SteamWorks_SetHTTPRequestContextValue(hRequest, i) || - !SteamWorks_SendHTTPRequest(hRequest)) - { - delete hRequest; - } + HTTPRequest hRequest = new HTTPRequest(sRequest); + + // ripext has no HEAD verb (SteamWorks' k_EHTTPMethodHEAD has no + // equivalent native here). Ask for just the first byte via a Range + // header on a GET instead, so we still avoid downloading the whole + // (potentially large) .bsp.bz2 just to check whether it exists. + // A server that honors Range answers 206/200 without the full body; + // one that doesn't just falls back to sending the whole file. + hRequest.SetHeader("Range", "bytes=0-0"); + hRequest.Get(OnTransferComplete, i); } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- -public int OnTransferComplete(Handle hRequest, bool bFailure, bool bSuccessful, EHTTPStatusCode eStatusCode, int url_index) +public void OnTransferComplete(HTTPResponse response, any url_index) { - if (bFailure || !bSuccessful || eStatusCode != k_EHTTPStatusCode200OK) - { - g_bDoesIndexHaveBZ2[url_index] = false; - } - else + if (response.Status == HTTPStatus_OK || response.Status == HTTPStatus_PartialContent) { g_bDoesIndexHaveBZ2[url_index] = true; } - delete hRequest; - return 0; + else + { + g_bDoesIndexHaveBZ2[url_index] = false; + } } public void OnMapEnd() @@ -166,46 +151,42 @@ public void OnConfigsExecuted() downloadurl.GetString(originalConVar, sizeof(originalConVar)); } -public MRESReturn sendServerInfoDetCallback_Pre(Address pointer, Handle hReturn, Handle hParams) //First callback -{ - int client; - client = view_as(SDKCall(hPlayerSlot, pointer)) + 1; //we just use linux anyways, no reason to check OS. - g_icurrentClient = client; - return MRES_Ignored; -} - public MRESReturn buildConVarMessageDetCallback_Pre(Handle hParams) //Second callback { - if (g_icurrentClient > 0 && g_icurrentClient <= MaxClients && IsClientConnected(g_icurrentClient)) + for (int client = 1; client <= MaxClients; client++) { - //LogMessage("client %N in buildConVarMessageDetCallback_Pre", g_icurrentClient); - char clientIPAddress[64]; //IP of the connecting client - GetClientIP(g_icurrentClient, clientIPAddress, sizeof(clientIPAddress)); - - for (int i = 0; i < sizeof(g_cIPaddresses); i++) + if (IsClientConnected(client)) { - if (StrEqual(g_cIPaddresses[i], clientIPAddress)) + //LogMessage("client %N in buildConVarMessageDetCallback_Pre", client); + char clientIPAddress[64]; + GetClientIP(client, clientIPAddress, sizeof(clientIPAddress)); + + for (int i = 0; i < sizeof(g_cIPaddresses); i++) { - int rotated = -1; - g_SteamIDRotations.GetValue(clientIPAddress, rotated); - - //0 = ovh uk unloze. 1 = ovh uk unloze. 2 = default sv_downloadurl again. so not overwriting anything - rotated = rotated % 3; - - //the bz2 file does not exist on the backup urls so rotate to the next working one. - while (rotated < sizeof(g_cBackupURLS) && !g_bDoesIndexHaveBZ2[rotated]) + if (StrEqual(g_cIPaddresses[i], clientIPAddress) && !g_bRotated[client]) { - rotated++; + g_bRotated[client] = true; //its only from disconnecting that the clients needs to be rotated again by matching IP. + int rotated = -1; + g_SteamIDRotations.GetValue(clientIPAddress, rotated); + + //0 = ovh uk unloze. 1 = ovh uk unloze. 2 = default sv_downloadurl again. so not overwriting anything + rotated = rotated % 3; + + //the bz2 file does not exist on the backup urls so rotate to the next working one. + while (rotated < sizeof(g_cBackupURLS) && !g_bDoesIndexHaveBZ2[rotated]) + { + rotated++; + } + if (rotated < sizeof(g_cBackupURLS)) + { + char map[256]; + GetCurrentMap(map, sizeof(map)); + g_SteamIDRotations.SetValue(clientIPAddress, rotated, true); //adapting in case of increment. + LogMessage("client %N had missing map with default sv_downloadurl on %s. using %s instead.", client, map, g_cBackupURLS[rotated]); + setConVarValue(g_cBackupURLS[rotated]); + } + break; } - if (rotated < sizeof(g_cBackupURLS)) - { - char map[256]; - GetCurrentMap(map, sizeof(map)); - g_SteamIDRotations.SetValue(clientIPAddress, rotated, true); //adapting in case of increment. - LogMessage("client %N had missing map with default sv_downloadurl on %s. using %s instead.", g_icurrentClient, map, g_cBackupURLS[rotated]); - setConVarValue(g_cBackupURLS[rotated]); - } - break; } } } @@ -216,6 +197,6 @@ void setConVarValue(char[] value) //Sets the actual ConVar value { int oldflags = GetConVarFlags(downloadurl); SetConVarFlags(downloadurl, oldflags &~ FCVAR_REPLICATED); - SetConVarString(downloadurl, value, true, false); + SetConVarString(downloadurl, value, true, false); SetConVarFlags(downloadurl, oldflags|FCVAR_REPLICATED); }