sm-plugins/GFLClanru/scripting/GFLClanru.sp
2018-08-07 22:24:18 +02:00

506 lines
13 KiB
SourcePawn

#pragma semicolon 1
#include <sourcemod>
#include <SteamWorks>
#pragma newdecls required
#include <GFLClanru>
//#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<AsyncHasSteamIDReservedSlotCallbackFunc>(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;
}