#include "core/globals.sp" #define RIPEXT_SUPPORT //#define STEAMWORKS_SUPPORT #define DISABLE_JSON #define DEBUG #if defined RIPEXT_SUPPORT #include #define PLUGIN_VERSION "1.0 (RipExt)" #endif #if defined STEAMWORKS_SUPPORT //#define SM_INT64_SUPPORTED //#pragma dynamic 131072 #include #include //#include #define PLUGIN_VERSION "1.0 (SteamWorks)" #endif public Plugin myinfo = { name = "Facti13 Backend Integration", author = "gsd", description = "Update server info directly without RCON", version = PLUGIN_VERSION, url = "https://tf2.pblr-nyk.pro" } Handle g_timer = INVALID_HANDLE; int g_lastupdate = 0; bool g_warned = true; bool g_updating = false; public OnPluginStart() { SetupGlobalConVar(); RegAdminCmd("fbi_test", TestUpdate, ADMFLAG_ROOT); g_timer = CreateTimer(15, timerCall, 0, TIMER_REPEAT); } public OnPluginEnd() { UnSetupGlobalConvar(); if (g_timer != INVALID_HANDLE) { KillTimer(g_timer); } } #if defined STEAMWORKS_SUPPORT public void OnJsonRequestComplete(Handle hRequest, bool bFailure, bool bRequestSuccessful, EHTTPStatusCode eStatusCode) { #if defined DEBUG LogMessage("OnJsonRequestComplete stage") #endif g_updating = false; g_lastupdate = GetTime(); if (bFailure) { if(g_warned) { LogMessage("Failed response! Code: %i", eStatusCode); g_warned = false; } delete hRequest; return; } if (!bRequestSuccessful || eStatusCode != k_EHTTPStatusCode200OK) { if(g_warned) { LogMessage("Failed response! Code: %i", eStatusCode); g_warned = false; } delete hRequest; return; } if (eStatusCode == k_EHTTPStatusCode200OK) { if(!g_warned) { LogMessage("Success send payload, after error"); g_warned = true; } } delete hRequest; return; } stock void createRequest(const char[] sJsonPayload) { #if defined DEBUG LogMessage("CreateRequest stage") #endif //char sURL[256]; //Format(sURL, sizeof(sURL), "%s/report", g_url); LogMessage("Use report endpoint: %s", g_url); Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodPOST, g_url); if (hRequest == INVALID_HANDLE) { g_updating = false; g_lastupdate = GetTime(); LogError("Не удалось создать запрос"); return; } SteamWorks_SetHTTPRequestRawPostBody(hRequest, "application/json; charset=UTF-8", sJsonPayload, strlen(sJsonPayload)); if (strlen(g_cookie) > 0) { SteamWorks_SetHTTPRequestHeaderValue(hRequest, "Cookie", g_cookie); } SteamWorks_SetHTTPCallbacks(hRequest, OnJsonRequestComplete); if (!SteamWorks_SendHTTPRequest(hRequest)) { g_updating = false; g_lastupdate = GetTime(); LogError("Cannot send server info"); delete hRequest; } } JSONObject createPayload() { #if defined DEBUG LogMessage("CreatePayload"); #endif JSONObject payload = new JSONObject(); payload.SetBool("status", true); int player_count = 0; payload.SetInt("max_players", MaxClients); char map_name[128]; GetCurrentMap(map_name, sizeof(map_name)); payload.SetString("map_name", map_name); JSONArray players = new JSONArray(); for(int client = 0; client <= MaxClients; client++) { if (IsValidClient(client)) { player_count++; JSONObject player = new JSONObject(); /* Name */ char name[64]; GetClientName(client, name, sizeof(name)); player.SetString("name", name); /* Score */ player.SetInt("score", GetClientFrags(client)); player.SetInt("deads", GetClientDeaths(client)); /* Duration */ char duration[16]; int ct = RoundFloat(GetClientTime(client)); int h = ct / 3600; int m = ct % 3600 / 60; int s = ct % 60; Format(duration, sizeof(duration), "%02d:%02d:%02d", h, m, s); player.SetString("duration", duration); /* Id */ player.SetInt("id", GetClientUserId(client)); /* Ip */ char ip[32]; GetClientIP(client, ip, sizeof(ip), false); player.SetString("ip", ip); /* Loss */ player.SetInt("loss",RoundFloat(GetClientAvgLoss(client, NetFlow_Both)*1000.0)); /* Ping */ player.SetInt("ping",RoundFloat(GetClientLatency(client, NetFlow_Both)*1000.0)); /* State */ player.SetString("state", "active") /* Steam 2 так надо, не надо спрашивать почему*/ char steam2[32]; GetClientAuthId(client, AuthId_Steam3, steam2, sizeof(steam2)); player.SetString("steam2", steam2); /* Position on map */ float pos[3]; GetClientAbsOrigin(client, pos); player.SetFloat("pos_x", pos[0]); player.SetFloat("pos_y", pos[1]); player.SetFloat("pos_z", pos[2]); /* Player class */ player.SetInt("clz", TF2_GetPlayerClass(client)); /* Player team */ player.SetInt("team", TF2_GetClientTeam(client)); /* push */ players.Push(player); } } payload.Set("players", players); payload.SetInt("player_count", player_count); return payload; } stock void ProcessUpdateStatus() { g_updating = true; #if defined DEBUG LogMessage("ProcessUpdateStatus stage") #endif JSONObject payload = createPayload(); //int payload_size = 1024*8; char payload_str[1024*8]; payload.ToString(payload_str, 1024*8); //payload.Encode(payload_str, 1024*8); //payload.Remove("players"); //json_cleanup_and_delete(players); //json_cleanup_and_delete(payload); createRequest(payload_str); } #endif #if defined RIPEXT_SUPPORT HTTPRequest createRequest() { #if defined DEBUG LogMessage("CreateRequest"); #endif HTTPRequest client = INVALID_HANDLE; if (strlen(g_url)>0) { client = new HTTPRequest(g_url); client.SetHeader("Cookie", g_cookie); client.Timeout = 3; } else { LogMessage("[FBI] Client not builded"); } return client; } JSONObject createPayload() { #if defined DEBUG LogMessage("CreatePayload"); #endif JSONObject payload = new JSONObject(); payload.SetBool("status", true); int player_count = 0; payload.SetInt("max_players", MaxClients); char map_name[128]; GetCurrentMap(map_name, sizeof(map_name)); payload.SetString("map_name", map_name); JSONArray players = new JSONArray(); for(int client = 0; client <= MaxClients; client++) { if (IsValidClient(client)) { player_count++; JSONObject player = new JSONObject(); /* Name */ char name[64]; GetClientName(client, name, sizeof(name)); player.SetString("name", name); /* Score */ player.SetInt("score", GetClientFrags(client)); player.SetInt("deads", GetClientDeaths(client)); /* Duration */ char duration[16]; int ct = RoundFloat(GetClientTime(client)); int h = ct / 3600; int m = ct % 3600 / 60; int s = ct % 60; Format(duration, sizeof(duration), "%02d:%02d:%02d", h, m, s); player.SetString("duration", duration); /* Id */ player.SetInt("id", GetClientUserId(client)); /* Ip */ char ip[32]; GetClientIP(client, ip, sizeof(ip), false); player.SetString("ip", ip); /* Loss */ player.SetInt("loss",RoundFloat(GetClientAvgLoss(client, NetFlow_Both)*1000.0)); /* Ping */ player.SetInt("ping",RoundFloat(GetClientLatency(client, NetFlow_Both)*1000.0)); /* State */ player.SetString("state", "active") /* Steam 2 так надо, не надо спрашивать почему*/ char steam2[32]; GetClientAuthId(client, AuthId_Steam3, steam2, sizeof(steam2)); player.SetString("steam2", steam2); /* Position on map */ float pos[3]; GetClientAbsOrigin(client, pos); player.SetFloat("pos_x", pos[0]); player.SetFloat("pos_y", pos[1]); player.SetFloat("pos_z", pos[2]); /* Player class */ player.SetInt("clz", TF2_GetPlayerClass(client)); /* Player team */ player.SetInt("team", TF2_GetClientTeam(client)); /* push */ players.Push(player); } } payload.Set("players", players); payload.SetInt("player_count", player_count); return payload; } void ProcessUpdateStatus() { #if defined DEBUG LogMessage("ProcessUpdateStatus"); #endif g_updating = true; JSONObject payload = createPayload(); createRequest().Post(payload, Request_Callback); } void Request_Callback(HTTPResponse response, any value){ #if defined DEBUG LogMessage("Request Callback: %i", response.Status); #endif g_updating = false; g_lastupdate = GetTime(); if (response.Status == HTTPStatus_OK){ if(!g_warned) { LogMessage("Success send payload, after error"); g_warned = true; } return; } else{ if(g_warned) { LogMessage("Failed response! Code: %i", response.Status); g_warned = false; } return; } } #endif void UpdateStatus(){ if (!g_setuped) return; if (g_updating) return; if (GetTime() - g_lastupdate < 5) return; //g_updating = true; ProcessUpdateStatus(); //g_lastupdate = GetTime(); } public Action timerCall(Handle:t, any:d) { UpdateStatus(); return Plugin_Continue; } public Action TestUpdate(int client, int args){ //UpdateStatus(); ProcessUpdateStatus(); ReplyToCommand(client, "OK! Last update: %d", g_lastupdate) return Plugin_Handled; } public OnClientDisconnect(int client) { UpdateStatus(); } public OnClientAuthorized(int client) { UpdateStatus(); } public OnMapStart() { UpdateStatus(); } public OnMapEnd() { UpdateStatus(); }