From db7cee19ae96d6174357371e16678f40d9e7b37b Mon Sep 17 00:00:00 2001 From: BotoX Date: Tue, 7 Aug 2018 22:24:18 +0200 Subject: [PATCH] add GFLClanru --- GFLClanru/scripting/GFLClanru.sp | 505 ++++++++++++++++++++++++ GFLClanru/scripting/GFLClanruClantag.sp | 76 ++++ 2 files changed, 581 insertions(+) create mode 100644 GFLClanru/scripting/GFLClanru.sp create mode 100644 GFLClanru/scripting/GFLClanruClantag.sp diff --git a/GFLClanru/scripting/GFLClanru.sp b/GFLClanru/scripting/GFLClanru.sp new file mode 100644 index 0000000..3426fb6 --- /dev/null +++ b/GFLClanru/scripting/GFLClanru.sp @@ -0,0 +1,505 @@ +#pragma semicolon 1 +#include +#include + +#pragma newdecls required +#include + +//#define GFL_API_KEY "secret" +#include "GFLClanruAPI.secret" + +bool g_bLateLoad = false; +float g_fMonthlyCosts = 45.0; +KeyValues g_Response[MAXPLAYERS + 1]; +bool g_bResponseFailed[MAXPLAYERS + 1]; +bool g_bClientPreAdminChecked[MAXPLAYERS + 1]; + +public Plugin myinfo = +{ + name = "GFLCLan.ru API Integration", + author = "BotoX", + description = "Handles donators.", + version = "0.1", + url = "" +} + +public void OnPluginStart() +{ + RegConsoleCmd("sm_tier", Command_Tier, "[GFLClan.ru] Displays donator info."); + RegConsoleCmd("sm_vip", Command_Tier, "[GFLClan.ru] Displays donator info."); +} + +public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) +{ + CreateNative("AsyncHasSteamIDReservedSlot", Native_AsyncHasSteamIDReservedSlot); + RegPluginLibrary("GFLClanru"); + + g_bLateLoad = late; + return APLRes_Success; +} + +public void OnRebuildAdminCache(AdminCachePart part) +{ + if(part != AdminCache_Admins) + return; + + CreateTimer(1.0, OnRebuildAdminCachePost, 0, TIMER_FLAG_NO_MAPCHANGE); +} + +public Action OnRebuildAdminCachePost(Handle timer) +{ + for(int client = 1; client <= MaxClients; client++) + { + if(g_bClientPreAdminChecked[client] && g_Response[client]) + OnReceiveUser(client); + } + + return Plugin_Stop; +} + +public void OnClientConnected(int client) +{ + g_bClientPreAdminChecked[client] = false; + g_bResponseFailed[client] = false; +} + +public void OnClientAuthorized(int client, const char[] auth) +{ + if(IsFakeClient(client)) + return; + + char sSteam64ID[32]; + Steam32IDtoSteam64ID(auth, sSteam64ID, sizeof(sSteam64ID)); + + int UserSerial = GetClientSerial(client); + + static char sRequest[256]; + FormatEx(sRequest, sizeof(sRequest), "http://direct.gflclan.ru/api/self/Server/OnClientAuthorized?key=%s&steamid=%s", GFL_API_KEY, sSteam64ID); + + Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodGET, sRequest); + if (!hRequest || + !SteamWorks_SetHTTPRequestContextValue(hRequest, UserSerial) || + !SteamWorks_SetHTTPCallbacks(hRequest, OnClientAuthorized_OnTransferComplete) || + !SteamWorks_SetHTTPRequestHeaderValue(hRequest, "Accept", "application/vdf") || + !SteamWorks_SendHTTPRequest(hRequest)) + { + LogError("%L SteamWorks_CreateHTTPRequest failed.", client); + CloseHandle(hRequest); + g_bResponseFailed[client] = true; + } + + return; +} + +public int OnClientAuthorized_OnTransferComplete(Handle hRequest, bool bFailure, bool bRequestSuccessful, EHTTPStatusCode eStatusCode, int UserSerial) +{ + int client = GetClientFromSerial(UserSerial); + if(!client) // Player disconnected + { + CloseHandle(hRequest); + return; + } + + if(bFailure || !bRequestSuccessful || eStatusCode != k_EHTTPStatusCode200OK) + { + LogError("%L OnClientAuthorized HTTP Response failed: %d", client, eStatusCode); + CloseHandle(hRequest); + g_bResponseFailed[client] = true; + + if(g_bClientPreAdminChecked[client]) + NotifyPostAdminCheck(client); + + return; + } + + SteamWorks_GetHTTPResponseBodyCallback(hRequest, OnClientAuthorized_APIWebResponse, UserSerial); + CloseHandle(hRequest); +} + +public int OnClientAuthorized_APIWebResponse(const char[] sData, int UserSerial) +{ + int client = GetClientFromSerial(UserSerial); + if(!client) // Player disconnected + return; + + KeyValues Response = new KeyValues("OnClientAuthorized_APIWebResponse"); + if(!Response.ImportFromString(sData, "OnClientAuthorized_APIWebResponse")) + { + LogError("%L ImportFromString(sData, \"OnClientAuthorized_APIWebResponse\") failed.", client); + delete Response; + + if(g_bClientPreAdminChecked[client]) + NotifyPostAdminCheck(client); + + return; + } + g_Response[client] = Response; + + if(g_bClientPreAdminChecked[client]) + { + LogMessage("%L APIWebResponse late.", client); + NotifyPostAdminCheck(client); + } +} + +public Action OnClientPreAdminCheck(int client) +{ + g_bClientPreAdminChecked[client] = true; + if(g_Response[client] || g_bResponseFailed[client]) + return Plugin_Continue; + + RunAdminCacheChecks(client); + + return Plugin_Handled; +} + +public void OnClientPostAdminFilter(int client) +{ + OnReceiveUser(client); +} + +public void OnClientDisconnect(int client) +{ + g_bClientPreAdminChecked[client] = false; + g_bResponseFailed[client] = false; + delete g_Response[client]; +} + +void OnReceiveUser(int client) +{ + KeyValues Response = g_Response[client]; + if(!Response) + return; + + ArrayList Groups = new ArrayList(ByteCountToCells(32)); + + if(Response.JumpToKey("forum")) + { + int Member = Response.GetNum("member"); + if(Member) + { + int LastSeen = Response.GetNum("last_seen"); + int Expires = RoundFloat(LastSeen + 86400.0 * 7.0); + int Now = GetTime(); + + if(Now < Expires) + { + Groups.PushString("Member"); + } + } + } + Response.Rewind(); + + if(Response.JumpToKey("donations") && Response.GotoFirstSubKey()) + { + do + { + char sGroup[32]; + Response.GetString("group", sGroup, sizeof(sGroup)); + char sState[32]; + Response.GetString("state", sState, sizeof(sState)); + int Tier = Response.GetNum("tier"); + int Deactivate = Response.GetNum("deactivate", 0); + + if(StrEqual(sState, "active")) + { + Groups.PushString(sGroup); + } + else if(Deactivate && (StrEqual(sState, "expired") || StrEqual(sState, "refunded") || StrEqual(sState, "reversed"))) + { + 0; + } + } + while(Response.GotoNextKey()); + } + Response.Rewind(); + + if(!Groups.Length) + { + delete Groups; + return; + } + + AdminId adm; + // Use a pre-existing admin if we can + if((adm = GetUserAdmin(client)) == INVALID_ADMIN_ID) + { + LogMessage("Creating new admin for %L", client); + adm = CreateAdmin(""); + SetUserAdmin(client, adm, true); + } + + for(int i = 0; i < Groups.Length; i++) + { + char sGroup[32]; + Groups.GetString(i, sGroup, sizeof(sGroup)); + + GroupId grp; + if((grp = FindAdmGroup(sGroup)) != INVALID_GROUP_ID) + { + LogMessage("Adding %L to group %s", client, sGroup); + AdminInheritGroup(adm, grp); + } + else + LogError("%L Group %s not found!", client, sGroup); + } + + delete Groups; +} + +public void OnClientPostAdminCheck(int client) +{ + KeyValues Response = g_Response[client]; + if(!Response) + return; + + Response.JumpToKey("donations"); + Response.GotoFirstSubKey(); + do + { + int Created = Response.GetNum("created"); + int Activated = Response.GetNum("activated"); + int Expires = Response.GetNum("expires"); + int Length = Response.GetNum("length"); + char sGroup[32]; + Response.GetString("group", sGroup, sizeof(sGroup)); + char sState[32]; + Response.GetString("state", sState, sizeof(sState)); + int Tier = Response.GetNum("tier"); + int Anonymous = Response.GetNum("anonymous"); + int New = Response.GetNum("new"); + int Deactivate = Response.GetNum("deactivate", 0); + float fNetAmount = Response.GetFloat("net_amount", 0.0); + + if(StrEqual(sState, "active")) + { + static char sExpireDate[32]; + FormatTime(sExpireDate, sizeof(sExpireDate), "%a, %d %b %Y %H:%M:%S +00", Expires); + + int Remaining = Expires - Created; + float RemainingDays = Remaining / 3600.0 / 24.0; + + PrintToChat(client, "\x04[GFLClan.ru]\x01 Donator \x03Tier %d\x01 enabled. Valid until %s (%.1f days)", + Tier, sExpireDate, RemainingDays); + + if(New) + { + float fDays = fNetAmount * (30.5 / g_fMonthlyCosts); + PrintCenterText(client, "Your Tier %d donation has been activated! Thank you <3", Tier); + if(fNetAmount && !Anonymous) + PrintToChatAll("\x04[GFLClan.ru]\x01 \x03%N\x01's donation paid for %.1f days of server uptime, thanks!", client, fDays); + } + else if(Remaining < 86400) // less than 24 hours + { + int Hours = RoundToFloor(Remaining / 3600.0); + int Minutes = Remaining % 60; + PrintCenterText(client, "Oy vey goyim! Your tier %d donation will expire in %d hours and %d minutes.", Tier, Hours, Minutes); + } + } + else if(StrEqual(sState, "queued")) + { + float Days = Length / 3600.0 / 24.0; + PrintToChat(client, "\x04[GFLClan.ru]\x01 Donator \x03Tier %d\x01 queued. Length: %.1f days", + Tier, Days); + } + else if(StrEqual(sState, "expired")) + { + PrintCenterText(client, "Oy gevalt goyim! Your tier %d donation has expired.", Tier); + } + else if(StrEqual(sState, "refunded")) + { + PrintCenterText(client, "OY GEVALT GOYIM YOUR DONATION HAS BEEN REFUNDED!"); + } + else if(StrEqual(sState, "reversed")) + { + PrintCenterText(client, "OY GEVALT GOYIM YOUR DONATION HAS BEEN REVERSED!"); + } + } + while(Response.GotoNextKey()); + Response.Rewind(); + + Response.JumpToKey("forum"); + Response.GotoFirstSubKey(); + int Member = Response.GetNum("member"); + if(Member) + { + int LastSeen = Response.GetNum("last_seen"); + int Expires = RoundFloat(LastSeen + 86400.0 * 7.0); + int Now = GetTime(); + + if(Now < Expires) + { + static char sExpireDate[32]; + FormatTime(sExpireDate, sizeof(sExpireDate), "%a, %d %b %Y %H:%M:%S +00", Expires); + + PrintToChat(client, "\x04[GFLClan.ru]\x01 \x03Member\x01 enabled. Remember to log in until %s (%.1f days)", + sExpireDate, (Expires - Now) / 3600.0 / 24.0); + } + } +} + +public Action Command_Tier(int client, int args) +{ + KeyValues Response = g_Response[client]; + if(!Response) + { + ReplyToCommand(client, "\x04[GFLClan.ru]\x01 No donator info available!"); + return Plugin_Handled; + } + + Response.JumpToKey("donations"); + Response.GotoFirstSubKey(); + do + { + int Created = Response.GetNum("created"); + int Expires = Response.GetNum("expires"); + int Length = Response.GetNum("length"); + char sState[32]; + Response.GetString("state", sState, sizeof(sState)); + int Tier = Response.GetNum("tier"); + + if(StrEqual(sState, "active")) + { + static char sExpireDate[32]; + FormatTime(sExpireDate, sizeof(sExpireDate), "%a, %d %b %Y %H:%M:%S +00", Expires); + + int Remaining = Expires - Created; + float RemainingDays = Remaining / 3600.0 / 24.0; + + PrintToChat(client, "\x04[GFLClan.ru]\x01 Donator \x03Tier %d\x01 active. Valid until %s (%.1f days)", + Tier, sExpireDate, RemainingDays); + } + else if(StrEqual(sState, "queued")) + { + float Days = Length / 3600.0 / 24.0; + PrintToChat(client, "\x04[GFLClan.ru]\x01 Donator \x03Tier %d\x01 queued. Length: %.1f days", + Tier, Days); + } + } + while(Response.GotoNextKey()); + Response.Rewind(); + + Response.JumpToKey("forum"); + Response.GotoFirstSubKey(); + int Member = Response.GetNum("member"); + if(Member) + { + int LastSeen = Response.GetNum("last_seen"); + int Expires = RoundFloat(LastSeen + 86400.0 * 7.0); + int Now = GetTime(); + + if(Now < Expires) + { + static char sExpireDate[32]; + FormatTime(sExpireDate, sizeof(sExpireDate), "%a, %d %b %Y %H:%M:%S +00", Expires); + + PrintToChat(client, "\x04[GFLClan.ru]\x01 \x03Member\x01 active. Remember to log in until %s (%.1f days)", + sExpireDate, (Expires - Now) / 3600.0 / 24.0); + } + } + + return Plugin_Handled; +} + +public int Native_AsyncHasSteamIDReservedSlot(Handle plugin, int numParams) +{ + char sSteam32ID[32]; + GetNativeString(1, sSteam32ID, sizeof(sSteam32ID)); + + AsyncHasSteamIDReservedSlotCallbackFunc Callback; + Callback = GetNativeCell(2); + + any Data; + Data = GetNativeCell(3); + + char sSteam64ID[32]; + Steam32IDtoSteam64ID(sSteam32ID, sSteam64ID, sizeof(sSteam64ID)); + + static char sRequest[256]; + FormatEx(sRequest, sizeof(sRequest), "http://direct.gflclan.ru/api/self/Server/HasSteamIDReservedSlot?key=%s&steamid=%s", GFL_API_KEY, sSteam64ID); + + DataPack Pack = new DataPack(); + Pack.WriteString(sSteam32ID); + Pack.WriteCell(plugin); + Pack.WriteFunction(Callback); + Pack.WriteCell(Data); + + Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodGET, sRequest); + if (!hRequest || + !SteamWorks_SetHTTPRequestNetworkActivityTimeout(hRequest, 3) || + !SteamWorks_SetHTTPRequestContextValue(hRequest, Pack) || + !SteamWorks_SetHTTPCallbacks(hRequest, Native_AsyncHasSteamIDReservedSlot_OnTransferComplete) || + !SteamWorks_SendHTTPRequest(hRequest)) + { + CloseHandle(hRequest); + } +} + +public int Native_AsyncHasSteamIDReservedSlot_OnTransferComplete(Handle hRequest, bool bFailure, bool bRequestSuccessful, EHTTPStatusCode eStatusCode, DataPack Pack) +{ + if(bFailure || !bRequestSuccessful || eStatusCode != k_EHTTPStatusCode200OK) + { + LogError("Native_AsyncHasSteamIDReservedSlot HTTP Response failed: %d", eStatusCode); + CloseHandle(hRequest); + // Simulate false response + char sData[2] = "0"; + Native_AsyncHasSteamIDReservedSlot_APIWebResponse(sData, Pack); + return; + } + + SteamWorks_GetHTTPResponseBodyCallback(hRequest, Native_AsyncHasSteamIDReservedSlot_APIWebResponse, Pack); + CloseHandle(hRequest); +} + +public int Native_AsyncHasSteamIDReservedSlot_APIWebResponse(char[] sData, DataPack Pack) +{ + Pack.Reset(); + char sSteam32ID[32]; + Pack.ReadString(sSteam32ID, sizeof(sSteam32ID)); + + Handle plugin; + plugin = Pack.ReadCell(); + + AsyncHasSteamIDReservedSlotCallbackFunc Callback; + Callback = view_as(Pack.ReadFunction()); + + any Data; + Data = Pack.ReadCell(); + + delete Pack; + + TrimString(sData); + int Result = StringToInt(sData); + + Call_StartFunction(plugin, Callback); + Call_PushString(sSteam32ID); + Call_PushCell(Result); + Call_PushCell(Data); + Call_Finish(); + + return 0; +} + + +stock bool Steam32IDtoSteam64ID(const char[] sSteam32ID, char[] sSteam64ID, int Size) +{ + if(strlen(sSteam32ID) < 11 || strncmp(sSteam32ID[0], "STEAM_", 6)) + { + sSteam64ID[0] = 0; + return false; + } + + int iUpper = 765611979; + int isSteam64ID = StringToInt(sSteam32ID[10]) * 2 + 60265728 + sSteam32ID[8] - 48; + + int iDiv = isSteam64ID / 100000000; + int iIdx = 9 - (iDiv ? (iDiv / 10 + 1) : 0); + iUpper += iDiv; + + IntToString(isSteam64ID, sSteam64ID[iIdx], Size - iIdx); + iIdx = sSteam64ID[9]; + IntToString(iUpper, sSteam64ID, Size); + sSteam64ID[9] = iIdx; + + return true; +} diff --git a/GFLClanru/scripting/GFLClanruClantag.sp b/GFLClanru/scripting/GFLClanruClantag.sp new file mode 100644 index 0000000..a54bf53 --- /dev/null +++ b/GFLClanru/scripting/GFLClanruClantag.sp @@ -0,0 +1,76 @@ +#include +#include + +#define CLANID "24069756" +#define GROUP "Clantag" + +bool g_bInGroup[MAXPLAYERS + 1]; + +public Plugin myinfo = +{ + name = "GFLClan.ru Clantag", + author = "BotoX", + description = "Assign group to people wearing gfl clantag", + version = "1.0", + url = "" +}; + +public void OnPluginStart() +{ + /* Handle late load */ + for(int client = 1; client <= MaxClients; client++) + { + if(IsClientInGame(client) && IsClientAuthorized(client)) + { + OnClientPostAdminFilter(client); + } + } +} + +public void OnClientPostAdminFilter(int client) +{ + CheckClantag(client); +} + +public void OnClientSettingsChanged(int client) +{ + CheckClantag(client); +} + +public void OnClientDisconnect(int client) +{ + g_bInGroup[client] = false; +} + +bool CheckClantag(int client) +{ + if(!IsClientAuthorized(client) || g_bInGroup[client]) + return false; + + char sClanID[32]; + GetClientInfo(client, "cl_clanid", sClanID, sizeof(sClanID)); + + if(!StrEqual(sClanID, CLANID)) + return false; + + AdminId adm; + // Use a pre-existing admin if we can + if((adm = GetUserAdmin(client)) == INVALID_ADMIN_ID) + { + LogMessage("Creating new admin for %L", client); + adm = CreateAdmin(""); + SetUserAdmin(client, adm, true); + } + + GroupId grp; + if((grp = FindAdmGroup(GROUP)) != INVALID_GROUP_ID) + { + if(adm.InheritGroup(grp)) + { + LogMessage("Added %L to group %s", client, GROUP); + return true; + } + } + + return false; +}