diff --git a/AdvancedTargeting/scripting/AdvancedTargeting.sp b/AdvancedTargeting/scripting/AdvancedTargeting.sp index b8de761..6b9ebc4 100644 --- a/AdvancedTargeting/scripting/AdvancedTargeting.sp +++ b/AdvancedTargeting/scripting/AdvancedTargeting.sp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include @@ -437,17 +437,14 @@ public void OnClientAuthorized(int client, const char[] auth) char sSteam64ID[32]; Steam32IDtoSteam64ID(auth, sSteam64ID, sizeof(sSteam64ID)); + // format=json instead of format=vdf: ripext only exposes the response body + // as decoded JSON, so we ask Steam's own API for JSON directly rather than + // working around a missing raw-body accessor. static char sRequest[256]; - FormatEx(sRequest, sizeof(sRequest), "http://api.steampowered.com/ISteamUser/GetFriendList/v0001/?key=%s&steamid=%s&relationship=friend&format=vdf", STEAM_API_KEY, sSteam64ID); + FormatEx(sRequest, sizeof(sRequest), "http://api.steampowered.com/ISteamUser/GetFriendList/v0001/?key=%s&steamid=%s&relationship=friend&format=json", STEAM_API_KEY, sSteam64ID); - Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodGET, sRequest); - if (!hRequest || - !SteamWorks_SetHTTPRequestContextValue(hRequest, client) || - !SteamWorks_SetHTTPCallbacks(hRequest, OnTransferComplete) || - !SteamWorks_SendHTTPRequest(hRequest)) - { - CloseHandle(hRequest); - } + HTTPRequest hRequest = new HTTPRequest(sRequest); + hRequest.Get(OnTransferComplete, client); } public void OnClientDisconnect(int client) @@ -458,52 +455,38 @@ public void OnClientDisconnect(int client) g_FriendsArray[client] = INVALID_HANDLE; } -public int OnTransferComplete(Handle hRequest, bool bFailure, bool bRequestSuccessful, EHTTPStatusCode eStatusCode, int client) +public void OnTransferComplete(HTTPResponse response, any client) { - if(bFailure || !bRequestSuccessful || eStatusCode != k_EHTTPStatusCode200OK) + if(response.Status != HTTPStatus_OK || response.Data == null) { // Private profile or maybe steam down? - //LogError("SteamAPI HTTP Response failed: %d", eStatusCode); - CloseHandle(hRequest); + //LogError("SteamAPI HTTP Response failed: %d", response.Status); return; } - int Length; - SteamWorks_GetHTTPResponseBodySize(hRequest, Length); - - char[] sData = new char[Length]; - SteamWorks_GetHTTPResponseBodyData(hRequest, sData, Length); - //SteamWorks_GetHTTPResponseBodyCallback(hRequest, APIWebResponse, client); - - CloseHandle(hRequest); - - APIWebResponse(sData, client); + APIWebResponse(view_as(response.Data), client); } -public void APIWebResponse(const char[] sData, int client) +public void APIWebResponse(JSONObject Response, int client) { - KeyValues Response = new KeyValues("SteamAPIResponse"); - if(!Response.ImportFromString(sData, "SteamAPIResponse")) + if(!Response.HasKey("friendslist")) { - LogError("ImportFromString(sData, \"SteamAPIResponse\") failed."); + LogError("GetFriendList response missing \"friendslist\" key."); delete Response; return; } - if(!Response.JumpToKey("friends")) + JSONObject friendslist = view_as(Response.Get("friendslist")); + + // No friends, or private profile - Steam returns {"friendslist":{}} in that case. + if(!friendslist.HasKey("friends")) { - LogError("JumpToKey(\"friends\") failed."); + delete friendslist; delete Response; return; } - // No friends? - if(!Response.GotoFirstSubKey()) - { - //LogError("GotoFirstSubKey() failed."); - delete Response; - return; - } + JSONArray friends = view_as(friendslist.Get("friends")); if(g_FriendsArray[client] != INVALID_HANDLE) CloseHandle(g_FriendsArray[client]); @@ -511,18 +494,20 @@ public void APIWebResponse(const char[] sData, int client) g_FriendsArray[client] = CreateArray(); char sCommunityID[32]; - do + int len = friends.Length; + for(int i = 0; i < len; i++) { - Response.GetString("steamid", sCommunityID, sizeof(sCommunityID)); - - PushArrayCell(g_FriendsArray[client], Steam64toSteam3(sCommunityID)); + JSONObject friendEntry = view_as(friends.Get(i)); + if(friendEntry.GetString("steamid", sCommunityID, sizeof(sCommunityID))) + PushArrayCell(g_FriendsArray[client], Steam64toSteam3(sCommunityID)); + delete friendEntry; } - while(Response.GotoNextKey()); + delete friends; + delete friendslist; delete Response; } - stock bool Steam32IDtoSteam64ID(const char[] sSteam32ID, char[] sSteam64ID, int Size) { if(strlen(sSteam32ID) < 11 || strncmp(sSteam32ID[0], "STEAM_0:", 8)) @@ -634,3 +619,4 @@ public int Native_ReadClientFriends(Handle plugin, int numParams) return 0; } + diff --git a/AntiBhopCheat/scripting/AntiBhopCheat.sp b/AntiBhopCheat/scripting/AntiBhopCheat.sp index e78d89b..e20e83a 100644 --- a/AntiBhopCheat/scripting/AntiBhopCheat.sp +++ b/AntiBhopCheat/scripting/AntiBhopCheat.sp @@ -426,9 +426,12 @@ NotifyAdmins(int client, const char[] sReason) if(IsClientInGame(i) && !IsFakeClient(i) && CheckCommandAccess(i, "sm_stats", ADMFLAG_GENERIC)) { CPrintToChat(i, "{green}[SM]{default} %L has been detected for {red}%s{default}, please check your console!", client, sReason); - FormatStats(i, client); + char sBuffer[2000]; + FormatStats(i, client, sBuffer, 0); PrintToConsole(client, "%s", "\n"); - FormatStreak(i, client, 0); + int len = FormatStats(-1, client, sBuffer, sizeof(sBuffer)); + sBuffer[len++] = '\n'; + FormatStreak(i, client, 0, sBuffer[len], sizeof(sBuffer) - len); } } @@ -464,12 +467,13 @@ public Action Command_Stats(int client, int argc) for(int i = 0; i < iTargetCount; i++) { - FormatStats(client, iTargets[i]); + char sBuffer[2000]; + FormatStats(i, client, sBuffer, 0); PrintToConsole(client, "%s", "\n"); for(int j = 0; j < 3; j++) { - FormatStreak(client, iTargets[i], j); + FormatStreak(client, iTargets[i], j, sBuffer[0], sizeof(sBuffer) - 0); PrintToConsole(client, "%s", "\n"); } } @@ -509,13 +513,14 @@ public Action Command_Streak(int client, int argc) for(int i = 0; i < iTargetCount; i++) { - FormatStreak(client, iTargets[i], iStreak); + char sBuffer[2000]; + FormatStreak(client, iTargets[i], iStreak, sBuffer[0], 0); } return Plugin_Handled; } -int FormatStats(int client, int iTarget, char[] sBuf=0, int len=0) +int FormatStats(int client, int iTarget, char[] sBuf, int len=0) { int iUserID = GetClientUserId(iTarget); char sAuth[32]; @@ -545,7 +550,7 @@ int FormatStats(int client, int iTarget, char[] sBuf=0, int len=0) return iBuf; } -int FormatStreak(int client, int iTarget, int iStreak, char[] sBuf=0, int len=0) +int FormatStreak(int client, int iTarget, int iStreak, char[] sBuf, int len=0) { int iUserID = GetClientUserId(iTarget); char sAuth[32]; diff --git a/BossHP/scripting/BossHP.sp b/BossHP/scripting/BossHP.sp index cebf0e7..01c4868 100644 --- a/BossHP/scripting/BossHP.sp +++ b/BossHP/scripting/BossHP.sp @@ -248,7 +248,8 @@ public void OnMapStart() if(StrEqual(sMethod, "breakable")) { char sBreakable[64]; - if(!KvConfig.GetString("breakable", sBreakable, sizeof(sBreakable))) + KvConfig.GetString("breakable", sBreakable, sizeof(sBreakable), "not found"); + if(StrEqual(sBreakable, "not found")) { LogError("Could not find \"breakable\" in \"%s\"", sSection); continue; @@ -263,7 +264,8 @@ public void OnMapStart() else if(StrEqual(sMethod, "counter")) { char sCounter[64]; - if(!KvConfig.GetString("counter", sCounter, sizeof(sCounter))) + KvConfig.GetString("counter", sCounter, sizeof(sCounter), "not found"); + if (StrEqual(sCounter, "not found")) { LogError("Could not find \"counter\" in \"%s\"", sSection); continue; @@ -278,21 +280,24 @@ public void OnMapStart() else if(StrEqual(sMethod, "hpbar")) { char sIterator[64]; - if(!KvConfig.GetString("iterator", sIterator, sizeof(sIterator))) + KvConfig.GetString("iterator", sIterator, sizeof(sIterator), "not found"); + if (StrEqual(sIterator, "not found")) { LogError("Could not find \"iterator\" in \"%s\"", sSection); continue; } char sCounter[64]; - if(!KvConfig.GetString("counter", sCounter, sizeof(sCounter))) + KvConfig.GetString("counter", sCounter, sizeof(sCounter), "not found"); + if (StrEqual(sCounter, "not found")) { LogError("Could not find \"counter\" in \"%s\"", sSection); continue; } char sBackup[64]; - if(!KvConfig.GetString("backup", sBackup, sizeof(sBackup))) + KvConfig.GetString("backup", sBackup, sizeof(sBackup), "not found"); + if (StrEqual(sBackup, "not found")) { LogError("Could not find \"backup\" in \"%s\"", sSection); continue; diff --git a/CELT_VOICE/scripting/nosteam_celt_audio.sp b/CELT_VOICE/scripting/nosteam_celt_audio.sp index 6fb0a63..8cc8d67 100644 --- a/CELT_VOICE/scripting/nosteam_celt_audio.sp +++ b/CELT_VOICE/scripting/nosteam_celt_audio.sp @@ -4,7 +4,7 @@ #include #include #include -#include +#include #tryinclude #include #include @@ -22,6 +22,8 @@ bool g_bSkipInfection = false; char g_sLastWebclientIp[64]; +int g_iHttpFileCounter; + public Plugin myinfo = { name = "NoSteam CELT Voice override", @@ -73,7 +75,7 @@ public Action check_mutes(Handle timer, any data) } else { - //maybe this is a fix? maybe not. + //maybe this is a fix? maybe not. clear_steam_listen_override(i); } for (int j = 1; j <= MaxClients; j++) @@ -145,28 +147,17 @@ public void SendWebclientNameToSignaling(const char[] webclientName) // Adjust port/path to match your signaling servers actual endpoint FormatEx(url, sizeof(url), "http://127.0.0.1:3000/webclient-name"); - Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodPOST, url); - if (hRequest == null) - { - return; - } + HTTPRequest hRequest = new HTTPRequest(url); // Send the name as a POST body parameter - SteamWorks_SetHTTPRequestGetOrPostParameter(hRequest, "name", webclientName); - - if (!SteamWorks_SetHTTPCallbacks(hRequest, OnWebclientNamePosted) || - !SteamWorks_SendHTTPRequest(hRequest)) - { - delete hRequest; - } + hRequest.AppendFormParam("name", "%s", webclientName); + hRequest.PostForm(OnWebclientNamePosted); } -public int OnWebclientNamePosted(Handle hRequest, bool bFailure, bool bRequestSuccessful, - EHTTPStatusCode eStatusCode, any data) +public void OnWebclientNamePosted(HTTPResponse response, any value) { - // Fire-and-forget: we dont care about the response, just clean up. - delete hRequest; - return 0; + // Fire-and-forget: we dont care about the response. ripext closes the + // request handle for us once this callback returns. } public void OnMapStart() @@ -259,7 +250,7 @@ public Action ZR_OnClientMotherZombieEligible(int client) public Action Timer_SendVoiceInit(Handle timer, int Serial) { - int client; + int client; if ((client = GetClientFromSerial(Serial)) == 0) { return Plugin_Handled; @@ -276,53 +267,53 @@ public Action Timer_SendVoiceInit(Handle timer, int Serial) * If the IP has changed since the last * check and a webclient player is currently connected, forces them to * reconnect with the new password via ClientCommand. + * + * ripext's HTTPResponse only exposes the body as decoded JSON, unlike + * SteamWorks' GetHTTPResponseBodyCallback which handed back a plain char[]. + * Rather than change the signaling server's response format, we use + * HTTPRequest.DownloadFile() to write the raw body to a temp file and read + * it back as plain text, keeping the endpoint untouched. **/ public void PollWebclientCurrentIp() { - Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodGET, "http://127.0.0.1:3000/webclient-current-ip"); - if (hRequest == null) - { - return; - } + g_iHttpFileCounter++; - if (!SteamWorks_SetHTTPCallbacks(hRequest, OnWebclientCurrentIpReceived) || - !SteamWorks_SendHTTPRequest(hRequest)) - { - delete hRequest; - } + char sPath[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, sPath, sizeof(sPath), "data/nosteamcelt_ip_%d.tmp", g_iHttpFileCounter); + + HTTPRequest hRequest = new HTTPRequest("http://127.0.0.1:3000/webclient-current-ip"); + hRequest.DownloadFile(sPath, OnWebclientCurrentIpDownloaded, g_iHttpFileCounter); } -public int OnWebclientCurrentIpReceived(Handle hRequest, bool bFailure, bool bRequestSuccessful, - EHTTPStatusCode eStatusCode, any data) +public void OnWebclientCurrentIpDownloaded(HTTPStatus status, any value) { - if (bFailure || !bRequestSuccessful || eStatusCode != k_EHTTPStatusCode200OK) - { - delete hRequest; - return 0; - } + char sPath[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, sPath, sizeof(sPath), "data/nosteamcelt_ip_%d.tmp", value); - int bodySize; - bool gotSize = SteamWorks_GetHTTPResponseBodySize(hRequest, bodySize); + if (status != HTTPStatus_OK) + { + DeleteFile(sPath); + return; + } char newIp[64]; newIp[0] = '\0'; - if (gotSize && bodySize > 0 && bodySize < sizeof(newIp)) + File hFile = OpenFile(sPath, "r"); + if (hFile != null) { - SteamWorks_GetHTTPResponseBodyData(hRequest, newIp, bodySize); + hFile.ReadLine(newIp, sizeof(newIp)); + delete hFile; } + DeleteFile(sPath); - delete hRequest; + TrimString(newIp); if (newIp[0] == '\0') - { - return 0; - } + return; if (StrEqual(newIp, g_sLastWebclientIp)) - { - return 0; - } + return; for (int i = 1; i <= MaxClients; i++) { @@ -334,7 +325,6 @@ public int OnWebclientCurrentIpReceived(Handle hRequest, bool bFailure, bool bRe break; } } - return 0; } public EConnect OnClientPreConnectEx(const char[] sName, char sPassword[255], const char[] sIP, const char[] sSteam32ID, char sRejectReason[255]) @@ -344,7 +334,7 @@ public EConnect OnClientPreConnectEx(const char[] sName, char sPassword[255], co if (sv_set_steam_id_ips != null) { sv_set_steam_id_ips.GetString(allowedIp, sizeof(allowedIp)); - //this is to handle that the connect extension receives the password parameter for the webclient as its real connecting IP. + //this is to handle that the connect extension receives the password parameter for the webclient as its real connecting IP. //works both for the client command retry and for the case that somebody presses the connect button in the clients Menu as the same password //is applied again. if (StrEqual(sIP, allowedIp) && strlen(g_sLastWebclientIp) > 0) @@ -353,7 +343,7 @@ public EConnect OnClientPreConnectEx(const char[] sName, char sPassword[255], co LogMessage("Backfilled empty password for webclient with cached IP: %s", g_sLastWebclientIp); } } - // ET_LowEvent takes the LOWEST value returned across all plugins hooking this forward. + // ET_LowEvent takes the LOWEST value returned across all plugins hooking this forward. //this plugin returns 1 (Accept), meanwhile the reserved slot plugin still might return 0 (reject) or -1 (async) to overrule the decision from this return value. return k_OnClientPreConnectEx_Accept; } @@ -364,3 +354,4 @@ stock bool IsValidClient(int client) return true; return false; } + diff --git a/Discord_UNLOZE/scripting/Discord_UNLOZE.sp b/Discord_UNLOZE/scripting/Discord_UNLOZE.sp index 8dbe44b..6801498 100644 --- a/Discord_UNLOZE/scripting/Discord_UNLOZE.sp +++ b/Discord_UNLOZE/scripting/Discord_UNLOZE.sp @@ -2,9 +2,8 @@ #include #include -#include +#include #include -#include #include #include #include @@ -139,6 +138,9 @@ public void OnAdminAFKTimeChanged(ConVar convar, const char[] oldValue, const ch g_iAdminAFKTime = g_cvAdminAFKTime.IntValue; } +//---------------------------------------------------------------------------------------------------- +// Purpose: Steam player summary lookup (avatar) - now via ripext, JSON instead of VDF +//---------------------------------------------------------------------------------------------------- public void OnClientAuthorized(int client, const char[] sAuthID32) { if (IsFakeClient(client)) @@ -149,19 +151,44 @@ public void OnClientAuthorized(int client, const char[] sAuthID32) if (!Steam32IDtoSteam64ID(sAuthID32, sAuthID64, sizeof(sAuthID64))) return; - static char sRequest[256]; + char sRequest[256]; - FormatEx(sRequest, sizeof(sRequest), "http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=%s&steamids=%s&format=vdf", STEAM_API_KEY, sAuthID64); + FormatEx(sRequest, sizeof(sRequest), "http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=%s&steamids=%s&format=json", STEAM_API_KEY, sAuthID64); - Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodGET, sRequest); + HTTPRequest req = new HTTPRequest(sRequest); + req.Get(OnTransferComplete, GetClientSerial(client)); +} - if (!hRequest || - !SteamWorks_SetHTTPRequestContextValue(hRequest, client) || - !SteamWorks_SetHTTPCallbacks(hRequest, OnTransferComplete) || - !SteamWorks_SendHTTPRequest(hRequest)) +public void OnTransferComplete(HTTPResponse response, any serial) +{ + int client = GetClientFromSerial(serial); + if (!client) //Player disconnected. + return; + + if (response.Status != HTTPStatus_OK || response.Data == null) + return; + + APIWebResponse(view_as(response.Data), client); +} + +public void APIWebResponse(JSONObject root, int client) +{ + if (!root.HasKey("players")) + return; + + JSONArray players = view_as(root.Get("players")); + + if (players == null || !players.Length) { - delete hRequest; + delete players; + return; } + + JSONObject player = view_as(players.Get(0)); + player.GetString("avatarfull", g_sAvatarURL[client], sizeof(g_sAvatarURL[])); + + delete player; + delete players; } public Action Command_PrintToAdminChat(int args) @@ -197,6 +224,9 @@ public Action Command_PrintToAllChat(int args) return Plugin_Handled; } +//---------------------------------------------------------------------------------------------------- +// Purpose: Drains the rate-limit queue - now via ripext +//---------------------------------------------------------------------------------------------------- public Action Timer_DataProcessor(Handle hThis) { if (!g_bProcessingData) @@ -205,8 +235,6 @@ public Action Timer_DataProcessor(Handle hThis) if (g_iRatelimitRemaining == 0 && GetTime() < g_iRatelimitReset) return Plugin_Handled; - //PrintToServer("[Timer_DataProcessor] Array Length #1: %d", g_arrQueuedMessages.Length); - char sContent[1024]; g_arrQueuedMessages.GetString(0, sContent, sizeof(sContent)); g_arrQueuedMessages.Erase(0); @@ -218,28 +246,13 @@ public Action Timer_DataProcessor(Handle hThis) if (g_arrQueuedMessages.Length == 0) g_bProcessingData = false; - //PrintToServer("[Timer_DataProcessor] Array Length #2: %d", g_arrQueuedMessages.Length); + JSONObject data = JSONObject.FromString(sContent); - //PrintToServer("%s | %s", sURL, sContent); + HTTPRequest req = new HTTPRequest(sURL); + req.Post(data, OnHTTPRequestCompleted); - Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodPOST, sURL); + delete data; - JSONObject RequestJSON = view_as(json_load(sContent)); - - if (!hRequest || - !SteamWorks_SetHTTPRequestContextValue(hRequest, RequestJSON) || - !SteamWorks_SetHTTPCallbacks(hRequest, OnHTTPRequestCompleted) || - !SteamWorks_SetHTTPRequestRawPostBody(hRequest, "application/json", sContent, strlen(sContent)) || - !SteamWorks_SetHTTPRequestNetworkActivityTimeout(hRequest, 10) || - !SteamWorks_SendHTTPRequest(hRequest)) - { - LogError("Discord SteamWorks_CreateHTTPRequest failed."); - - delete RequestJSON; - delete hRequest; - - return Plugin_Handled; - } return Plugin_Handled; } @@ -300,27 +313,11 @@ stock void Discord_MakeStringSafe(const char[] sOrigin, char[] sOut, int iOutSiz { if (sOrigin[i] < 0x20 && sOrigin[i] != 0x0) { - //sOut[iCurIndex] = 0x20; - //iCurIndex++; continue; } switch (sOrigin[i]) { - // case '"': - // { - // strcopy(sOut[iCurIndex], iOutSize, "\\u0022"); - // iCurIndex += 6; - - // continue; - // } - // case '\\': - // { - // strcopy(sOut[iCurIndex], iOutSize, "\\u005C"); - // iCurIndex += 6; - - // continue; - // } case '@': { strcopy(sOut[iCurIndex], iOutSize, "@​"); //@ + zero-width space @@ -358,102 +355,12 @@ stock void Discord_MakeStringSafe(const char[] sOrigin, char[] sOut, int iOutSiz } } -stock int OnTransferComplete(Handle hRequest, bool bFailure, bool bRequestSuccessful, EHTTPStatusCode eStatusCode, int client) -{ - if (bFailure || !bRequestSuccessful || eStatusCode != k_EHTTPStatusCode200OK) - { - if (eStatusCode != k_EHTTPStatusCode429TooManyRequests) - { - LogError("SteamAPI HTTP Response failed: %d", eStatusCode); - } - - delete hRequest; - return 0; - } - - int iBodyLength; - SteamWorks_GetHTTPResponseBodySize(hRequest, iBodyLength); - - char[] sData = new char[iBodyLength]; - SteamWorks_GetHTTPResponseBodyData(hRequest, sData, iBodyLength); - - delete hRequest; - - APIWebResponse(sData, client); - return 0; -} - -stock void APIWebResponse(const char[] sData, int client) -{ - KeyValues kvResponse = new KeyValues("SteamAPIResponse"); - - if (!kvResponse.ImportFromString(sData, "SteamAPIResponse")) - { - //LogError("kvResponse.ImportFromString(\"SteamAPIResponse\") in APIWebResponse failed."); - - delete kvResponse; - return; - } - - if (!kvResponse.JumpToKey("players")) - { - //LogError("kvResponse.JumpToKey(\"players\") in APIWebResponse failed."); - - delete kvResponse; - return; - } - - if (!kvResponse.GotoFirstSubKey()) - { - //LogError("kvResponse.GotoFirstSubKey() in APIWebResponse failed."); - - delete kvResponse; - return; - } - - kvResponse.GetString("avatarfull", g_sAvatarURL[client], sizeof(g_sAvatarURL[])); - - delete kvResponse; -} - -stock void HTTPPostJSON(const char[] sURL, const char[] sText) -{ - // if (g_iRatelimitRemaining > 0 && !g_bProcessingData && GetTime() < g_iRatelimitReset) - // { - Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodPOST, sURL); - - JSONObject RequestJSON = view_as(json_load(sText)); - - if (!hRequest || - !SteamWorks_SetHTTPRequestContextValue(hRequest, RequestJSON) || - !SteamWorks_SetHTTPCallbacks(hRequest, OnHTTPRequestCompleted) || - !SteamWorks_SetHTTPRequestRawPostBody(hRequest, "application/json", sText, strlen(sText)) || - !SteamWorks_SetHTTPRequestNetworkActivityTimeout(hRequest, 15) || - !SteamWorks_SendHTTPRequest(hRequest)) - { - LogError("Discord SteamWorks_CreateHTTPRequest failed."); - - delete RequestJSON; - delete hRequest; - - return; - } - // } - // else - // { - // g_arrQueuedMessages.PushString(sText); - // g_arrQueuedMessages.PushString(sURL); - // g_bProcessingData = true; - // } - - //delete hRequest; -} - +//---------------------------------------------------------------------------------------------------- +// Purpose: Webhook POST helper - now via ripext +//---------------------------------------------------------------------------------------------------- stock void Discord_POST(const char[] sURL, char[] sText, bool bUsingUsername=false, char[] sUsername=NULL_STRING, bool bUsingAvatar=false, char[] sAvatarURL=NULL_STRING, bool bSafe=true, bool bTimestamp=true) { - //PrintToServer("[Discord_POST] Called with text: %s", sText); - - JSONRootNode hJSONRoot = new JSONObject(); + JSONObject hJSONRoot = new JSONObject(); char sSafeText[4096]; char sFinal[4096]; @@ -463,13 +370,13 @@ stock void Discord_POST(const char[] sURL, char[] sText, bool bUsingUsername=fal TrimString(sUsername); if (g_Regex_Clyde.Match(sUsername) > 0 || strlen(sUsername) < 2) - (view_as(hJSONRoot)).SetString("username", "Invalid Name"); + hJSONRoot.SetString("username", "Invalid Name"); else - (view_as(hJSONRoot)).SetString("username", sUsername); + hJSONRoot.SetString("username", sUsername); } if (bUsingAvatar) - (view_as(hJSONRoot)).SetString("avatar_url", sAvatarURL); + hJSONRoot.SetString("avatar_url", sAvatarURL); if (bSafe) { @@ -488,85 +395,61 @@ stock void Discord_POST(const char[] sURL, char[] sText, bool bUsingUsername=fal Format(sSafeText, sizeof(sSafeText), "[ *%s* ] %s", sTime, sText); } - (view_as(hJSONRoot)).SetString("content", sSafeText); - (view_as(hJSONRoot)).ToString(sFinal, sizeof(sFinal), 0); - - //hJSONRoot.DumpToServer(); - - delete hJSONRoot; + hJSONRoot.SetString("content", sSafeText); if ((g_iRatelimitRemaining > 0 || GetTime() >= g_iRatelimitReset) && !g_bProcessingData) { - //PrintToServer("[Discord_POST] Have allowances and not processing data"); + HTTPRequest req = new HTTPRequest(sURL); + req.Post(hJSONRoot, OnHTTPRequestCompleted); - Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodPOST, sURL); - - JSONObject RequestJSON = view_as(json_load(sFinal)); - - if (!hRequest || - !SteamWorks_SetHTTPRequestContextValue(hRequest, RequestJSON) || - !SteamWorks_SetHTTPCallbacks(hRequest, OnHTTPRequestCompleted) || - !SteamWorks_SetHTTPRequestRawPostBody(hRequest, "application/json", sFinal, strlen(sFinal)) || - !SteamWorks_SetHTTPRequestNetworkActivityTimeout(hRequest, 10) || - !SteamWorks_SendHTTPRequest(hRequest)) - { - LogError("Discord SteamWorks_CreateHTTPRequest failed."); - - delete RequestJSON; - delete hRequest; - - return; - } + delete hJSONRoot; } else { - //PrintToServer("[Discord_POST] Have allowances? [%s] | Is processing data? [%s]", g_iRatelimitRemaining > 0 ? "YES":"NO", g_bProcessingData?"YES":"NO"); + hJSONRoot.ToString(sFinal, sizeof(sFinal), 0); + delete hJSONRoot; + g_arrQueuedMessages.PushString(sFinal); g_arrQueuedMessages.PushString(sURL); g_bProcessingData = true; } - - //delete hRequest; //nonono } -public int OnHTTPRequestCompleted(Handle hRequest, bool bFailure, bool bRequestSuccessful, EHTTPStatusCode eStatusCode, JSONObject RequestJSON) +public void OnHTTPRequestCompleted(HTTPResponse response, any value) { - if (bFailure || !bRequestSuccessful || (eStatusCode != k_EHTTPStatusCode200OK && eStatusCode != k_EHTTPStatusCode204NoContent)) + if (response.Status != HTTPStatus_OK && response.Status != HTTPStatus_NoContent) { - if (eStatusCode != k_EHTTPStatusCode429TooManyRequests) - LogError("Discord HTTP request failed: %d", eStatusCode); + if (response.Status != HTTPStatus_TooManyRequests) + LogError("Discord HTTP request failed: %d", response.Status); - if (eStatusCode == k_EHTTPStatusCode400BadRequest) + if (response.Status == HTTPStatus_BadRequest && response.Data != null) { char sData[2048]; - (view_as(RequestJSON)).ToString(sData, sizeof(sData), 0); + response.Data.ToString(sData, sizeof(sData), 0); LogError("Malformed request? Dumping request data:\n%s", sData); } - else if (eStatusCode == k_EHTTPStatusCode429TooManyRequests) + else if (response.Status == HTTPStatus_TooManyRequests) { g_iRatelimitRemaining = 0; g_iRatelimitReset = GetTime() + 5; } - delete RequestJSON; - delete hRequest; - - return 0; + return; } static int iLastRatelimitRemaining = 0; static int iLastRatelimitReset = 0; char sTmp[32]; - bool bHeaderExists = SteamWorks_GetHTTPResponseHeaderValue(hRequest, "x-ratelimit-remaining", sTmp, sizeof(sTmp)); + bool bHeaderExists = response.GetHeader("x-ratelimit-remaining", sTmp, sizeof(sTmp)); if (!bHeaderExists) LogError("x-ratelimit-remaining header value could not be retrieved"); int iRatelimitRemaining = StringToInt(sTmp); - bHeaderExists = SteamWorks_GetHTTPResponseHeaderValue(hRequest, "x-ratelimit-reset", sTmp, sizeof(sTmp)); + bHeaderExists = response.GetHeader("x-ratelimit-reset", sTmp, sizeof(sTmp)); if (!bHeaderExists) LogError("x-ratelimit-reset header value could not be retrieved"); @@ -578,12 +461,6 @@ public int OnHTTPRequestCompleted(Handle hRequest, bool bFailure, bool bRequestS g_iRatelimitRemaining = iRatelimitRemaining; g_iRatelimitReset = iRatelimitReset; } - - //PrintToServer("limit: %d | remaining: %d || reset %d - now %d", g_iRatelimitLimit, g_iRatelimitRemaining, g_iRatelimitReset, GetTime()); - - delete RequestJSON; - delete hRequest; - return 0; } stock bool IsValidClient(int client) @@ -815,29 +692,7 @@ public void CallAdmin_OnReportHandled(int client, int id) Call_PushCell(5); Call_Finish(); } -// -/* -public Action Oryx_OnTrigger(int client, int &level, char[] cheat) -{ - char sUsername[MAX_NAME_LENGTH]; - GetClientName(client, sUsername, sizeof(sUsername)); - char currentMap[64]; - GetCurrentMap(currentMap, sizeof(currentMap)); - - char sAuthID[32]; - GetClientAuthId(client, AuthId_Steam2, sAuthID, sizeof(sAuthID), false); - char sMessage[1900]; - Format(sMessage, sizeof(sMessage), "```%s - Tick: %d``````NAME: %N\nSTEAMID: %s\nTRIGGER LEVEL: %i\n%s```", currentMap, GetGameTickCount(), client, sAuthID, level, cheat); - - if (g_sAvatarURL[client][0] != '\0') - Discord_POST(DISCORD_ANTIBHOPCHEAT_WEBHOOKURL, sMessage, true, sUsername, true, g_sAvatarURL[client], false); - else - Discord_POST(DISCORD_ANTIBHOPCHEAT_WEBHOOKURL, sMessage, true, sUsername, false, "", false); - - return Plugin_Continue; -} -*/ public void AntiBhopCheat_OnClientDetected(int client, char[] sReason, char[] sStats) { char sCurrentMap[64]; @@ -907,7 +762,6 @@ public void EW_OnClientRestricted(int client, int target, int hours, int minutes Call_Finish(); } - public void EW_OnClientUnrestricted(int client, int target) { char sCurrentMap[64]; diff --git a/FixFuncRotating/scripting/FixFuncRotating.sp b/FixFuncRotating/scripting/FixFuncRotating.sp index 1bd90ed..f4ef708 100644 --- a/FixFuncRotating/scripting/FixFuncRotating.sp +++ b/FixFuncRotating/scripting/FixFuncRotating.sp @@ -1,5 +1,7 @@ #pragma semicolon 1 +#pragma newdecls required + #define PLUGIN_AUTHOR "Cloud Strife" #define PLUGIN_VERSION "1.0" @@ -21,15 +23,17 @@ public Plugin myinfo = Handle g_CFuncRotating_StartForward = null; Handle g_CFuncRotating_UpdateSpeed = null; -stock float FloatMod(float num, float denom) +/* +float FloatMod(float num, float denom) { return num - denom * RoundToFloor(num / denom); } -stock float operator%(float oper1, float oper2) +float operator%(float oper1, float oper2) { return FloatMod(oper1, oper2); } +*/ // Set m_bStopAtStartPos to false public MRESReturn CFuncRotating_InputStartForward(int entity) @@ -106,4 +110,4 @@ public void OnPluginStart() { LogError("Could not enable detour for CFuncRotating::UpdateSpeed"); } -} \ No newline at end of file +} diff --git a/PlayerManager/scripting/include/PlayerManager.inc b/PlayerManager/scripting/include/PlayerManager.inc index 1970e5c..aa00903 100644 --- a/PlayerManager/scripting/include/PlayerManager.inc +++ b/PlayerManager/scripting/include/PlayerManager.inc @@ -18,13 +18,13 @@ native bool PM_IsPlayerSteam(int client); * Retrieve clients usertype. * * @param client The client index. - * @param type The buffer to write to. - * @param maxlength The maximum buffer length. + * @param type The integer to write to (1 = Steam, 0 = NoSteam). * * @return True on success, false otherwise. * @error Invalid client index, not connected or fake client. */ -native bool PM_GetPlayerType(int client, char[] type, int maxlength); +//native bool PM_GetPlayerType(int client, int type); +native bool PM_GetPlayerType(int client, char[] buffer, int maxlength); /** * Retrieve clients globally unique identifier (GUID). @@ -40,7 +40,7 @@ native int PM_GetPlayerGUID(int client); public SharedPlugin __pl_PlayerManager = { name = "PlayerManager", - file = "PlayerManager_Connect.smx", + file = "PlayerManager.smx", #if defined REQUIRE_PLUGIN required = 1 @@ -50,10 +50,10 @@ public SharedPlugin __pl_PlayerManager = }; #if !defined REQUIRE_PLUGIN - public void __pl_PlayerManager_SetNTVOptional() - { - MarkNativeAsOptional("PM_IsPlayerSteam"); - MarkNativeAsOptional("PM_GetPlayerType"); - MarkNativeAsOptional("PM_GetPlayerGUID"); - } +public void __pl_PlayerManager_SetNTVOptional() +{ + MarkNativeAsOptional("PM_IsPlayerSteam"); + MarkNativeAsOptional("PM_GetPlayerType"); + MarkNativeAsOptional("PM_GetPlayerGUID"); +} #endif diff --git a/SMJSONAPI/scripting/AsyncSocket.inc b/SMJSONAPI/scripting/AsyncSocket.inc new file mode 100644 index 0000000..0d71d62 --- /dev/null +++ b/SMJSONAPI/scripting/AsyncSocket.inc @@ -0,0 +1,63 @@ +#if defined _AsyncSocket_included + #endinput +#endif +#define _AsyncSocket_included + +typedef AsyncSocketConnectCallback = function void(AsyncSocket socket); + +typedef AsyncSocketErrorCallback = function void(AsyncSocket socket, int error, const char[] errorName); + +typedef AsyncSocketDataCallback = function void(AsyncSocket socket, const char[] data, const int size); + +methodmap AsyncSocket < Handle { + public native AsyncSocket(); + + public native bool Connect(const char[] host, const int port); + + public native bool Listen(const char[] host, const int port); + + public native bool Write(const char[] data, int length = -1); + + public bool WriteNull(const char[] data) + { + return this.Write(data, strlen(data) + 1); + } + + public native bool SetConnectCallback(AsyncSocketConnectCallback callback); + + public native bool SetErrorCallback(AsyncSocketErrorCallback callback); + + public native bool SetDataCallback(AsyncSocketDataCallback callback); +} + +/** + * Do not edit below this line! + */ +public Extension __ext_AsyncSocket = +{ + name = "AsyncSocket", + file = "AsyncSocket.ext", +#if defined AUTOLOAD_EXTENSIONS + autoload = 1, +#else + autoload = 0, +#endif +#if defined REQUIRE_EXTENSIONS + required = 1, +#else + required = 0, +#endif +}; + +#if !defined REQUIRE_EXTENSIONS +public __ext_AsyncSocket_SetNTVOptional() +{ + MarkNativeAsOptional("AsyncSocket.AsyncSocket"); + MarkNativeAsOptional("AsyncSocket.Connect"); + MarkNativeAsOptional("AsyncSocket.Listen"); + MarkNativeAsOptional("AsyncSocket.Write"); + MarkNativeAsOptional("AsyncSocket.SetConnectCallback"); + MarkNativeAsOptional("AsyncSocket.SetErrorCallback"); + MarkNativeAsOptional("AsyncSocket.SetDataCallback"); +} +#endif diff --git a/SMJSONAPI/scripting/smjansson.inc b/SMJSONAPI/scripting/smjansson.inc new file mode 100644 index 0000000..0bc2f19 --- /dev/null +++ b/SMJSONAPI/scripting/smjansson.inc @@ -0,0 +1,1763 @@ +#if defined _jansson_included_ + #endinput +#endif +#define _jansson_included_ + +/** + * --- Type + * + * The JSON specification (RFC 4627) defines the following data types: + * object, array, string, number, boolean, and null. + * JSON types are used dynamically; arrays and objects can hold any + * other data type, including themselves. For this reason, Jansson's + * type system is also dynamic in nature. There's one Handle type to + * represent all JSON values, and the referenced structure knows the + * type of the JSON value it holds. + * + */ +enum JSONType { + JSONType_Object, + JSONType_Array, + JSONType_String, + JSONType_Integer, + JSONType_Float, + JSONType_True, + JSONType_False, + JSONType_Null +}; + +/** + * Return the type of the JSON value. + * + * @param hObj Handle to the JSON value + * + * @return JSONType of the value. + */ +native JSONType json_typeof(JSONValue hObj); + +/** + * The type of a JSON value is queried and tested using these macros + * + * @param %1 Handle to the JSON value + * + * @return True if the value has the correct type. + */ +#define json_is_object(%1) ( json_typeof(%1) == JSONType_Object ) +#define json_is_array(%1) ( json_typeof(%1) == JSONType_Array ) +#define json_is_string(%1) ( json_typeof(%1) == JSONType_String ) +#define json_is_integer(%1) ( json_typeof(%1) == JSONType_Integer ) +#define json_is_real(%1) ( json_typeof(%1) == JSONType_Float ) +#define json_is_true(%1) ( json_typeof(%1) == JSONType_True ) +#define json_is_false(%1) ( json_typeof(%1) == JSONType_False ) +#define json_is_null(%1) ( json_typeof(%1) == JSONType_Null ) +#define json_is_number(%1) ( json_typeof(%1) == JSONType_Integer || json_typeof(%1) == JSONType_Float ) +#define json_is_boolean(%1) ( json_typeof(%1) == JSONType_True || json_typeof(%1) == JSONType_False ) + +/** + * Saves json_type as a String in output + * + * @param input json_type value to convert to string + * @param output Buffer to store the json_type value + * @param maxlength Maximum length of string buffer. + * + * @return False if the type does not exist. + */ +stock bool Stringify_json_type(JSONType input, char[] output, int maxlength) { + switch(input) { + case JSONType_Object: strcopy(output, maxlength, "Object"); + case JSONType_Array: strcopy(output, maxlength, "Array"); + case JSONType_String: strcopy(output, maxlength, "String"); + case JSONType_Integer: strcopy(output, maxlength, "Integer"); + case JSONType_Float: strcopy(output, maxlength, "Float"); + case JSONType_True: strcopy(output, maxlength, "True"); + case JSONType_False: strcopy(output, maxlength, "False"); + case JSONType_Null: strcopy(output, maxlength, "Null"); + default: return false; + } + + return true; +} + +/** + * --- Equality + * + * - Two integer or real values are equal if their contained numeric + * values are equal. An integer value is never equal to a real value, + * though. + * - Two strings are equal if their contained UTF-8 strings are equal, + * byte by byte. Unicode comparison algorithms are not implemented. + * - Two arrays are equal if they have the same number of elements and + * each element in the first array is equal to the corresponding + * element in the second array. + * - Two objects are equal if they have exactly the same keys and the + * value for each key in the first object is equal to the value of + * the corresponding key in the second object. + * - Two true, false or null values have no "contents", so they are + * equal if their types are equal. + * + */ + +/** + * Test whether two JSON values are equal. + * + * @param hObj Handle to the first JSON node + * @param hOther Handle to the second JSON node + * + * @return Returns false if they are inequal or one + * or both of the pointers are NULL. + */ +native bool json_equal(JSONValue hObj, JSONValue hOther); + + + + +/** + * --- Copying + * + * Jansson supports two kinds of copying: shallow and deep. There is + * a difference between these methods only for arrays and objects. + * + * Shallow copying only copies the first level value (array or object) + * and uses the same child values in the copied value. + * + * Deep copying makes a fresh copy of the child values, too. Moreover, + * all the child values are deep copied in a recursive fashion. + * + */ + +/** + * Get a shallow copy of the passed object + * + * @param hObj Handle to JSON object to be copied + * + * @return Returns a shallow copy of the object, + * or INVALID_HANDLE on error. + */ +native JSONValue json_copy(JSONValue hObj); + +/** + * Get a deep copy of the passed object + * + * @param hObj Handle to JSON object to be copied + * + * @return Returns a deep copy of the object, + * or INVALID_HANDLE on error. + */ +native JSONValue json_deep_copy(JSONValue hObj); + + + + +/** + * --- Objects + * + * A JSON object is a dictionary of key-value pairs, where the + * key is a Unicode string and the value is any JSON value. + * + */ + +/** + * Returns a handle to a new JSON object, or INVALID_HANDLE on error. + * Initially, the object is empty. + * + * @return Handle to a new JSON object. + */ +native JSONObject json_object(); + +/** + * Returns the number of elements in hObj + * + * @param hObj Handle to JSON object + * + * @return Number of elements in hObj, + * or 0 if hObj is not a JSON object. + */ +native int json_object_size(JSONObject hObj); + +/** + * Get a value corresponding to sKey from hObj + * + * @param hObj Handle to JSON object to get a value from + * @param sKey Key to retrieve + * + * @return Handle to a the JSON object or + * INVALID_HANDLE on error. + */ +native JSONValue json_object_get(JSONObject hObj, const char[] sKey); + +/** + * Set the value of sKey to hValue in hObj. + * If there already is a value for key, it is replaced by the new value. + * + * @param hObj Handle to JSON object to set a value on + * @param sKey Key to store in the object + * Must be a valid null terminated UTF-8 encoded + * Unicode string. + * @param hValue Value to store in the object + * + * @return True on success. + */ +native bool json_object_set(JSONObject hObj, const char[] sKey, JSONValue hValue); + +/** + * Set the value of sKey to hValue in hObj. + * If there already is a value for key, it is replaced by the new value. + * This function automatically closes the Handle to the value object. + * + * @param hObj Handle to JSON object to set a value on + * @param sKey Key to store in the object + * Must be a valid null terminated UTF-8 encoded + * Unicode string. + * @param hValue Value to store in the object + * + * @return True on success. + */ +native bool json_object_set_new(JSONObject hObj, const char[] sKey, JSONValue hValue); + +/** + * Delete sKey from hObj if it exists. + * + * @param hObj Handle to JSON object to delete a key from + * @param sKey Key to delete + * + * @return True on success. + */ +native bool json_object_del(JSONObject hObj, const char[] sKey); + +/** + * Remove all elements from hObj. + * + * @param hObj Handle to JSON object to remove all + * elements from. + * + * @return True on success. + */ +native bool json_object_clear(JSONObject hObj); + +/** + * Update hObj with the key-value pairs from hOther, overwriting + * existing keys. + * + * @param hObj Handle to JSON object to update + * @param hOther Handle to JSON object to get update + * keys/values from. + * + * @return True on success. + */ +native bool json_object_update(JSONObject hObj, JSONObject hOther); + +/** + * Like json_object_update(), but only the values of existing keys + * are updated. No new keys are created. + * + * @param hObj Handle to JSON object to update + * @param hOther Handle to JSON object to get update + * keys/values from. + * + * @return True on success. + */ +native bool json_object_update_existing(JSONObject hObj, JSONObject hOther); + +/** + * Like json_object_update(), but only new keys are created. + * The value of any existing key is not changed. + * + * @param hObj Handle to JSON object to update + * @param hOther Handle to JSON object to get update + * keys/values from. + * + * @return True on success. + */ +native bool json_object_update_missing(JSONObject hObj, JSONObject hOther); + + + + +/** + * Object iteration + * + * Example code: + * - We assume hObj is a Handle to a valid JSON object. + * + * + * new Handle:hIterator = json_object_iter(hObj); + * while(hIterator != INVALID_HANDLE) + * { + * new String:sKey[128]; + * json_object_iter_key(hIterator, sKey, sizeof(sKey)); + * + * new Handle:hValue = json_object_iter_value(hIterator); + * + * // Do something with sKey and hValue + * + * delete hValue; + * + * hIterator = json_object_iter_next(hObj, hIterator); + * } + * + */ + +/** + * Returns a handle to an iterator which can be used to iterate over + * all key-value pairs in hObj. + * If you are not iterating to the end of hObj make sure to close the + * handle to the iterator manually. + * + * @param hObj Handle to JSON object to get an iterator + * for. + * + * @return Handle to JSON object iterator, + * or INVALID_HANDLE on error. + */ +native JSONObjectIterator json_object_iter(JSONObject hObj); + +/** + * Like json_object_iter(), but returns an iterator to the key-value + * pair in object whose key is equal to key. + * Iterating forward to the end of object only yields all key-value + * pairs of the object if key happens to be the first key in the + * underlying hash table. + * + * @param hObj Handle to JSON object to get an iterator + * for. + * @param sKey Start key for the iterator + * + * @return Handle to JSON object iterator, + * or INVALID_HANDLE on error. + */ +native JSONObjectIterator json_object_iter_at(JSONObject hObj, const char[] sKey); + +/** + * Returns an iterator pointing to the next key-value pair in object. + * This automatically closes the Handle to the iterator hIter. + * + * @param hObj Handle to JSON object. + * @param hIter Handle to JSON object iterator. + * + * @return Handle to JSON object iterator, + * or INVALID_HANDLE on error, or if the + * whole object has been iterated through. + */ +native JSONObjectIterator json_object_iter_next(JSONObject hObj, JSONObjectIterator hIter); + +/** + * Extracts the associated key of hIter as a null terminated UTF-8 + * encoded string in the passed buffer. + * + * @param hIter Handle to the JSON String object + * @param sKeyBuffer Buffer to store the value of the String. + * @param maxlength Maximum length of string buffer. + * @error Invalid JSON Object Iterator. + * @return Length of the returned string or -1 on error. + */ +native int json_object_iter_key(JSONObjectIterator hIter, char[] sKeyBuffer, int maxlength); + +/** + * Returns a handle to the value hIter is pointing at. + * + * @param hIter Handle to JSON object iterator. + * + * @return Handle to value or INVALID_HANDLE on error. + */ +native JSONValue json_object_iter_value(JSONObjectIterator hIter); + +/** + * Set the value of the key-value pair in hObj, that is pointed to + * by hIter, to hValue. + * + * @param hObj Handle to JSON object. + * @param hIter Handle to JSON object iterator. + * @param hValue Handle to JSON value. + * + * @return True on success. + */ +native bool json_object_iter_set(JSONObject hObj, JSONObjectIterator hIter, JSONValue hValue); + +/** + * Set the value of the key-value pair in hObj, that is pointed to + * by hIter, to hValue. + * This function automatically closes the Handle to the value object. + * + * @param hObj Handle to JSON object. + * @param hIter Handle to JSON object iterator. + * @param hValue Handle to JSON value. + * + * @return True on success. + */ +native bool json_object_iter_set_new(JSONObject hObj, JSONObjectIterator hIter, JSONValue hValue); + + + + +/** + * Arrays + * + * A JSON array is an ordered collection of other JSON values. + * + */ + +/** + * Returns a handle to a new JSON array, or INVALID_HANDLE on error. + * + * @return Handle to the new JSON array + */ +native JSONArray json_array(); + +/** + * Returns the number of elements in hArray + * + * @param hObj Handle to JSON array + * + * @return Number of elements in hArray, + * or 0 if hObj is not a JSON array. + */ +native int json_array_size(JSONArray hArray); + +/** + * Returns the element in hArray at position iIndex. + * + * @param hArray Handle to JSON array to get a value from + * @param iIndex Position to retrieve + * + * @return Handle to a the JSON object or + * INVALID_HANDLE on error. + */ +native JSONValue json_array_get(JSONArray hArray, int iIndex); + +/** + * Replaces the element in array at position iIndex with hValue. + * The valid range for iIndex is from 0 to the return value of + * json_array_size() minus 1. + * + * @param hArray Handle to JSON array + * @param iIndex Position to replace + * @param hValue Value to store in the array + * + * @return True on success. + */ +native bool json_array_set(JSONArray hArray, int iIndex, JSONValue hValue); + +/** + * Replaces the element in array at position iIndex with hValue. + * The valid range for iIndex is from 0 to the return value of + * json_array_size() minus 1. + * This function automatically closes the Handle to the value object. + * + * @param hArray Handle to JSON array + * @param iIndex Position to replace + * @param hValue Value to store in the array + * + * @return True on success. + */ +native bool json_array_set_new(JSONArray hArray, int iIndex, JSONValue hValue); + +/** + * Appends value to the end of array, growing the size of array by 1. + * + * @param hArray Handle to JSON array + * @param hValue Value to append to the array + * + * @return True on success. + */ +native bool json_array_append(JSONArray hArray, JSONValue hValue); + +/** + * Appends value to the end of array, growing the size of array by 1. + * This function automatically closes the Handle to the value object. + * + * @param hArray Handle to JSON array + * @param hValue Value to append to the array + * + * @return True on success. + */ +native bool json_array_append_new(JSONArray hArray, JSONValue hValue); + +/** + * Inserts value to hArray at position iIndex, shifting the elements at + * iIndex and after it one position towards the end of the array. + * + * @param hArray Handle to JSON array + * @param iIndex Position to insert at + * @param hValue Value to store in the array + * + * @return True on success. + */ +native bool json_array_insert(JSONArray hArray, int iIndex, JSONValue hValue); + +/** + * Inserts value to hArray at position iIndex, shifting the elements at + * iIndex and after it one position towards the end of the array. + * This function automatically closes the Handle to the value object. + * + * @param hArray Handle to JSON array + * @param iIndex Position to insert at + * @param hValue Value to store in the array + * + * @return True on success. + */ +native bool json_array_insert_new(JSONArray hArray, int iIndex, JSONValue hValue); + +/** + * Removes the element in hArray at position iIndex, shifting the + * elements after iIndex one position towards the start of the array. + * + * @param hArray Handle to JSON array + * @param iIndex Position to insert at + * + * @return True on success. + */ +native bool json_array_remove(JSONArray hArray, int iIndex); + +/** + * Removes all elements from hArray. + * + * @param hArray Handle to JSON array + * + * @return True on success. + */ +native bool json_array_clear(JSONArray hArray); + +/** + * Appends all elements in hOther to the end of hArray. + * + * @param hArray Handle to JSON array to be extended + * @param hOther Handle to JSON array, source to copy from + * + * @return True on success. + */ +native bool json_array_extend(JSONArray hArray, JSONArray hOther); + + + + +/** + * Booleans & NULL + * + */ + +/** + * Returns a handle to a new JSON Boolean with value true, + * or INVALID_HANDLE on error. + * + * @return Handle to the new Boolean object + */ +native JSONValue json_true(); + +/** + * Returns a handle to a new JSON Boolean with value false, + * or INVALID_HANDLE on error. + * + * @return Handle to the new Boolean object + */ +native JSONValue json_false(); + +/** + * Returns a handle to a new JSON Boolean with the value passed + * in bState or INVALID_HANDLE on error. + * + * @param bState Value for the new Boolean object + * @return Handle to the new Boolean object + */ +native JSONValue json_boolean(bool bState); + +/** + * Returns a handle to a new JSON NULL or INVALID_HANDLE on error. + * + * @return Handle to the new NULL object + */ +native JSONValue json_null(); + + + + +/** + * Strings + * + * Jansson uses UTF-8 as the character encoding. All JSON strings must + * be valid UTF-8 (or ASCII, as it's a subset of UTF-8). Normal null + * terminated C strings are used, so JSON strings may not contain + * embedded null characters. + * + */ + +/** + * Returns a handle to a new JSON string, or INVALID_HANDLE on error. + * + * @param sValue Value for the new String object + * Must be a valid UTF-8 encoded Unicode string. + * @return Handle to the new String object + */ +native JSONString json_string(const char[] sValue); + +/** + * Saves the associated value of hString as a null terminated UTF-8 + * encoded string in the passed buffer. + * + * @param hString Handle to the JSON String object + * @param sValueBuffer Buffer to store the value of the String. + * @param maxlength Maximum length of string buffer. + * @error Invalid JSON String Object. + * @return Length of the returned string or -1 on error. + */ +native int json_string_value(JSONString hString, char[] sValueBuffer, int maxlength); + +/** + * Sets the associated value of JSON String object to value. + * + * @param hString Handle to the JSON String object + * @param sValue Value to set the object to. + * Must be a valid UTF-8 encoded Unicode string. + * @error Invalid JSON String Object. + * @return True on success. + */ +native bool json_string_set(JSONString hString, const char[] sValue); + + + + +/** + * Numbers + * + * The JSON specification only contains one numeric type, 'number'. + * The C (and Pawn) programming language has distinct types for integer + * and floating-point numbers, so for practical reasons Jansson also has + * distinct types for the two. They are called 'integer' and 'real', + * respectively. (Whereas 'real' is a 'Float' for Pawn). + * Therefore a number is represented by either a value of the type + * JSONType_Integer or of the type JSONType_Float. + * + */ + +/** + * Returns a handle to a new JSON integer, or INVALID_HANDLE on error. + * + * @param iValue Value for the new Integer object + * @return Handle to the new Integer object + */ +native JSONInteger json_integer(int iValue); + +/** + * Returns the associated value of a JSON Integer Object. + * + * @param hInteger Handle to the JSON Integer object + * @error Invalid JSON Integer Object. + * @return Value of the hInteger, + * or 0 if hInteger is not a JSON integer. + */ +native int json_integer_value(JSONInteger hInteger); + +/** + * Sets the associated value of JSON Integer to value. + * + * @param hInteger Handle to the JSON Integer object + * @param iValue Value to set the object to. + * @error Invalid JSON Integer Object. + * @return True on success. + */ +native bool json_integer_set(JSONInteger hInteger, int iValue); + + + + +/** + * Returns a handle to a new JSON real, or INVALID_HANDLE on error. + * + * @param fValue Value for the new Real object + * @return Handle to the new String object + */ +native JSONFloat json_real(float fValue); + +/** + * Returns the associated value of a JSON Real. + * + * @param hReal Handle to the JSON Real object + * @error Invalid JSON Real Object. + * @return Float value of hReal, + * or 0.0 if hReal is not a JSON Real. + */ +native float json_real_value(JSONFloat hReal); + +/** + * Sets the associated value of JSON Real to fValue. + * + * @param hReal Handle to the JSON Integer object + * @param fValue Value to set the object to. + * @error Invalid JSON Real handle. + * @return True on success. + */ +native bool json_real_set(JSONFloat hReal, float value); + +/** + * Returns the associated value of a JSON integer or a + * JSON Real, cast to Float regardless of the actual type. + * + * @param hNumber Handle to the JSON Number + * @error Not a JSON Real or JSON Integer + * @return Float value of hNumber, + * or 0.0 on error. + */ +native float json_number_value(JSONNumber hNumber); + + + + +/** + * Decoding + * + * This sections describes the functions that can be used to decode JSON text + * to the Jansson representation of JSON data. The JSON specification requires + * that a JSON text is either a serialized array or object, and this + * requirement is also enforced with the following functions. In other words, + * the top level value in the JSON text being decoded must be either array or + * object. + * + */ + +/** + * Decodes the JSON string sJSON and returns the array or object it contains. + * Errors while decoding can be found in the sourcemod error log. + * + * @param sJSON String containing valid JSON + + * @return Handle to JSON object or array. + * or INVALID_HANDLE on error. + */ +native JSONValue json_load(const char[] sJSON); + +/** + * Decodes the JSON string sJSON and returns the array or object it contains. + * This function provides additional error feedback and does not log errors + * to the sourcemod error log. + * + * @param sJSON String containing valid JSON + * @param sErrorText This buffer will be filled with the error + * message. + * @param maxlen Size of the buffer + * @param iLine This int will contain the line of the error + * @param iColumn This int will contain the column of the error + * + * @return Handle to JSON object or array. + * or INVALID_HANDLE on error. + */ +native JSONValue json_load_ex(const char[] sJSON, char[] sErrorText, int maxlen, int &iLine, int &iColumn); + +/** + * Decodes the JSON text in file sFilePath and returns the array or object + * it contains. + * Errors while decoding can be found in the sourcemod error log. + * + * @param sFilePath Path to a file containing pure JSON + * + * @return Handle to JSON object or array. + * or INVALID_HANDLE on error. + */ +native JSONValue json_load_file(const char sFilePath[PLATFORM_MAX_PATH]); + +/** + * Decodes the JSON text in file sFilePath and returns the array or object + * it contains. + * This function provides additional error feedback and does not log errors + * to the sourcemod error log. + * + * @param sFilePath Path to a file containing pure JSON + * @param sErrorText This buffer will be filled with the error + * message. + * @param maxlen Size of the buffer + * @param iLine This int will contain the line of the error + * @param iColumn This int will contain the column of the error + * + * @return Handle to JSON object or array. + * or INVALID_HANDLE on error. + */ +native JSONValue json_load_file_ex(const char sFilePath[PLATFORM_MAX_PATH], char[] sErrorText, int maxlen, int &iLine, int &iColumn); + + + +/** + * Encoding + * + * This sections describes the functions that can be used to encode values + * to JSON. By default, only objects and arrays can be encoded directly, + * since they are the only valid root values of a JSON text. + * + */ + +/** + * Saves the JSON representation of hObject in sJSON. + * + * @param hObject String containing valid JSON + * @param sJSON Buffer to store the created JSON string. + * @param maxlength Maximum length of string buffer. + * @param iIndentWidth Indenting with iIndentWidth spaces. + * The valid range for this is between 0 and 31 (inclusive), + * other values result in an undefined output. If this is set + * to 0, no newlines are inserted between array and object items. + * @param bEnsureAscii If this is set, the output is guaranteed + * to consist only of ASCII characters. This is achieved + * by escaping all Unicode characters outside the ASCII range. + * @param bSortKeys If this flag is used, all the objects in output are sorted + * by key. This is useful e.g. if two JSON texts are diffed + * or visually compared. + * @param bPreserveOrder If this flag is used, object keys in the output are sorted + * into the same order in which they were first inserted to + * the object. For example, decoding a JSON text and then + * encoding with this flag preserves the order of object keys. + * @return Length of the returned string or -1 on error. + */ +native int json_dump(JSONValue hObject, char[] sJSON, int maxlength, int iIndentWidth = 4, bool bEnsureAscii = false, bool bSortKeys = false, bool bPreserveOrder = false); + +/** + * Write the JSON representation of hObject to the file sFilePath. + * If sFilePath already exists, it is overwritten. + * + * @param hObject String containing valid JSON + * @param sFilePath Buffer to store the created JSON string. + * @param iIndentWidth Indenting with iIndentWidth spaces. + * The valid range for this is between 0 and 31 (inclusive), + * other values result in an undefined output. If this is set + * to 0, no newlines are inserted between array and object items. + * @param bEnsureAscii If this is set, the output is guaranteed + * to consist only of ASCII characters. This is achieved + * by escaping all Unicode characters outside the ASCII range. + * @param bSortKeys If this flag is used, all the objects in output are sorted + * by key. This is useful e.g. if two JSON texts are diffed + * or visually compared. + * @param bPreserveOrder If this flag is used, object keys in the output are sorted + * into the same order in which they were first inserted to + * the object. For example, decoding a JSON text and then + * encoding with this flag preserves the order of object keys. + * @return Length of the returned string or -1 on error. + */ +native bool json_dump_file(JSONValue hObject, const char[] sFilePath, int iIndentWidth = 4, bool bEnsureAscii = false, bool bSortKeys = false, bool bPreserveOrder = false); + + + + +/** + * MethodMaps + * + * Again: EXPERIMENTAL! + * + */ + + +enum JSONObjectUpdateType { + Update_All = 0, + Update_Existing, + Update_Missing +}; + +/** + * Base methodmap for all of smjansson's handles + */ +methodmap JSONValue < Handle { + property JSONType Type { + public get() { + return json_typeof(this); + } + } + + property bool IsObject { + public get() { + return (this.Type == JSONType_Object); + } + } + + property bool IsArray { + public get() { + return (this.Type == JSONType_Array); + } + } + + property bool IsString { + public get() { + return (this.Type == JSONType_String); + } + } + + property bool IsInteger { + public get() { + return (this.Type == JSONType_Integer); + } + } + + property bool IsFloat { + public get() { + return (this.Type == JSONType_Float); + } + } + + property bool IsTrue { + public get() { + return (this.Type == JSONType_True); + } + } + + property bool IsFalse { + public get() { + return (this.Type == JSONType_False); + } + } + + property bool IsNull { + public get() { + return (this.Type == JSONType_Null); + } + } + + property bool IsNumber { + public get() { + return (this.Type == JSONType_Integer || this.Type == JSONType_Float); + } + } + + property bool IsBoolean { + public get() { + return (this.Type == JSONType_True || this.Type == JSONType_False); + } + } + + property any Value { + // not implemented + } + + public bool Equals(JSONValue other) { + return json_equal(this, other); + } + + public JSONValue Copy(bool deep = false) { + if (deep) { + return view_as(json_deep_copy(this)); + } else { + return view_as(json_copy(this)); + } + } + + public void TypeToString(char[] buffer, int maxlength) { + if (!Stringify_json_type(view_as(this.Type), buffer, maxlength)) { + ThrowError("Attempting to get type of a non-SMJansson handle"); + } + } +} + +methodmap JSONBoolean < JSONValue { + public JSONBoolean(bool value) { + return view_as(json_boolean(value)); + } + + property bool Value { + public get() { + if (this.Type == JSONType_True) { + return true; + } else if (this.Type == JSONType_False) { + return false; + } + ThrowError("Not a JSONBoolean value"); + return false; + } + } +} + +methodmap JSONNull < JSONValue { + public JSONNull() { + return view_as(json_null()); + } +} + +methodmap JSONString < JSONValue { + public JSONString(const char[] value) { + return view_as(json_string(value)); + } + + public static JSONString Format(int bufferSize = 4096, const char[] format, any ...) { + char[] buffer = new char[bufferSize]; + VFormat(buffer, bufferSize, format, 3); + return new JSONString(buffer); + } + + public int GetString(char[] buffer, int length) { + return json_string_value(this, buffer, length); + } + + public bool SetString(char[] value) { + return json_string_set(this, value); + } +} + +/** + * Base map inherited by JSONInteger and JSONFloat to get the value of either, cast to float. + */ +methodmap JSONNumber < JSONValue { + public float FloatValue() { + return json_number_value(this); + } +} + +methodmap JSONInteger < JSONNumber { + public JSONInteger(int value) { + return view_as(json_integer(value)); + } + + property int Value { + public get() { + return json_integer_value(this); + } + public set(int value) { + json_integer_set(this, value); + } + } +} + +methodmap JSONFloat < JSONNumber { + public JSONFloat(float value) { + return view_as(json_real(value)); + } + + property float Value { + public get() { + return json_real_value(this); + } + public set(float value) { + json_real_set(this, value); + } + } +} + +/** + * Provides a few functions for valid root nodes (JSONArray and JSONObject) + */ +methodmap JSONRootNode < JSONValue { + /** + * Dumps the contents of the given root node to a string. + * + * @return Number of characters written + */ + public int ToString(char[] buffer, int maxlength, int indentWidth = 4, + bool asciiOnly = false, bool sortKeys = false, bool preserveOrder = false) { + return json_dump(this, buffer, maxlength, indentWidth, asciiOnly, sortKeys, + preserveOrder); + } + + /** + * @return True on success + */ + public bool ToFile(const char[] filePath, int indentWidth = 4, bool asciiOnly = false, + bool sortKeys = false, bool preserveOrder = false) { + return json_dump_file(this, filePath, indentWidth, asciiOnly, sortKeys, preserveOrder); + } + + public static JSONRootNode FromFile(const char[] filePath) { + char path[PLATFORM_MAX_PATH]; + strcopy(path, sizeof(path), filePath); + return view_as(json_load_file(path)); + } + + public static JSONRootNode Pack(const char[] packString, ArrayList params) { + return view_as(JSONValue_ByPack(packString, params)); + } + + public void DumpToServer() { + char sMsg[4096]; + this.ToString(sMsg, sizeof(sMsg)); + + PrintToServer(sMsg); + } +} + +methodmap JSONArray < JSONRootNode { + public JSONArray() { + return view_as(json_array()); + } + + property int Length { + public get() { + if (this.Type != JSONType_Array) { + ThrowError("Handle is not an array"); + } + return json_array_size(this); + } + } + + public JSONValue Get(int index) { + return view_as(json_array_get(this, index)); + } + + public bool Set(int index, JSONValue value, bool autoClose = true) { + if (autoClose) { + return json_array_set_new(this, index, value); + } + return json_array_set(this, index, value); + } + + public bool Append(JSONValue value, bool autoClose = true) { + if (autoClose) { + return json_array_append_new(this, value); + } + return json_array_append(this, value); + } + + public bool Insert(int index, JSONValue value, bool autoClose = true) { + if (autoClose) { + return json_array_insert_new(this, index, value); + } + return json_array_insert(this, index, value); + } + + public bool Remove(int index) { + return json_array_remove(this, index); + } + + public bool Clear() { + return json_array_clear(this); + } + + public bool Extend(JSONArray other) { + return json_array_extend(this, other); + } + + /** + * Utility functions + */ + + /* Booleans */ + + public bool GetBool(int index, bool defValue = false) { + JSONValue value = this.Get(index); + if(!value) + return defValue; + + JSONType type = value.Type; + delete value; + + switch (type) { + case JSONType_True: { return true; } + case JSONType_False: { return false; } + } + return defValue; + } + + public bool SetBool(int index, bool value) { + return this.Set(index, new JSONBoolean(value)); + } + + public bool AppendBool(bool value) { + return this.Append(new JSONBoolean(value)); + } + + public bool InsertBool(int index, bool value) { + return this.Insert(index, new JSONBoolean(value)); + } + + /* Floats */ + + public float GetFloat(int index, float defValue = 0.0) { + JSONValue value = this.Get(index); + if(!value) + return defValue; + + float result = (json_is_number(value) ? + (view_as(value)).FloatValue() : defValue); + delete value; + + return result; + } + + public bool SetFloat(int index, float value) { + return this.Set(index, new JSONFloat(value)); + } + + public bool AppendFloat(float value) { + return this.Append(new JSONFloat(value)); + } + + public bool InsertFloat(int index, float value) { + return this.Insert(index, new JSONFloat(value)); + } + + /* Integers */ + + public int GetInt(int index, int defValue = 0) { + JSONValue value = this.Get(index); + if(!value) + return defValue; + + int result = value.Type == JSONType_Integer ? (view_as(value)).Value : 0; + delete value; + + return result; + } + + public bool SetInt(int index, int value) { + return this.Set(index, new JSONInteger(value)); + } + + public bool AppendInt(int value) { + return this.Append(new JSONInteger(value)); + } + + public bool InsertInt(int index, int value) { + return this.Insert(index, new JSONInteger(value)); + } + + /* Strings */ + + public int GetString(int index, char[] buffer, int maxlength) { + JSONValue value = this.Get(index); + if(!value) + return -1; + + int result = -1; + if (value.Type == JSONType_String) { + result = (view_as(value)).GetString(buffer, maxlength); + } + delete value; + return result; + } + + public bool SetString(int index, const char[] value) { + return this.Set(index, new JSONString(value)); + } + + public bool AppendString(const char[] value) { + return this.Append(new JSONString(value)); + } + + public bool InsertString(int index, const char[] value) { + return this.Insert(index, new JSONString(value)); + } + + /* Misc. functions */ + + public static JSONArray FromFile(const char[] filePath) { + JSONRootNode data = JSONRootNode.FromFile(filePath); + + if (data.Type == JSONType_Array) { + return view_as(data); + } else { + ThrowError("File loaded by JSONArray.FromFile was not an array"); + delete data; + return null; + } + } + + public static JSONArray Pack(const char[] packString, ArrayList params) { + int length = strlen(packString); + if (packString[0] == '[' && packString[length - 1] == ']') { + return view_as(JSONRootNode.Pack(packString, params)); + } else { + ThrowError("Pack string '%s' is not appropriate for creating a JSONArray", + packString); + return null; + } + } +} + +methodmap JSONObject < JSONRootNode { + public JSONObject() { + return view_as(json_object()); + } + + property int Size { + public get() { + return json_object_size(this); + } + } + + public JSONValue Get(const char[] key) { + return view_as(json_object_get(this, key)); + } + + public bool Set(const char[] key, JSONValue value, bool autoClose = true) { + if (autoClose) { + return json_object_set_new(this, key, value); + } + return json_object_set(this, key, value); + } + + /** + * @return true on success + */ + public bool Remove(const char[] key) { + return json_object_del(this, key); + } + + public bool Clear() { + return json_object_clear(this); + } + + public bool Update(JSONObject other, JSONObjectUpdateType updateType = Update_All) { + switch (updateType) { + case Update_Existing: { + return json_object_update_existing(this, other); + } + case Update_Missing: { + return json_object_update_missing(this, other); + } + } + return json_object_update(this, other); + } + + /** + * Utility functions + */ + + public bool GetBool(const char[] key, bool defValue = false) { + JSONValue value = this.Get(key); + if(!value) + return defValue; + + JSONType type = value.Type; + delete value; + + switch (type) { + case JSONType_True: { return true; } + case JSONType_False: { return false; } + } + return defValue; + } + + public bool SetBool(const char[] key, bool value) { + return this.Set(key, new JSONBoolean(value)); + } + + /* Floats */ + + public float GetFloat(const char[] key, float defValue = 0.0) { + JSONValue value = this.Get(key); + if(!value) + return defValue; + + float result = (json_is_number(value) ? + (view_as(value)).FloatValue() : defValue); + delete value; + + return result; + } + + public bool SetFloat(const char[] key, float value) { + return this.Set(key, new JSONFloat(value)); + } + + /* Integers */ + + public int GetInt(const char[] key, int defValue = 0) { + JSONValue value = this.Get(key); + if(!value) + return defValue; + + int result = value.Type == JSONType_Integer ? + (view_as(value)).Value : defValue; + delete value; + + return result; + } + + public bool SetInt(const char[] key, int value) { + return this.Set(key, new JSONInteger(value)); + } + + /* Strings */ + + public int GetString(const char[] key, char[] buffer, int maxlength) { + JSONValue value = this.Get(key); + if(!value) + return -1; + + int result = -1; + if (value.Type == JSONType_String) { + result = (view_as(value)).GetString(buffer, maxlength); + } + delete value; + return result; + } + + public bool SetString(const char[] key, const char[] value) { + return this.Set(key, new JSONString(value)); + } + + /* Misc. functions */ + + public static JSONObject FromFile(const char[] filePath) { + JSONRootNode data = JSONRootNode.FromFile(filePath); + + if (data.Type == JSONType_Object) { + return view_as(data); + } else { + ThrowError("File loaded by JSONObject.FromFile was not an object"); + delete data; + return null; + } + } + + public static JSONObject Pack(const char[] packString, ArrayList params) { + int length = strlen(packString); + if (packString[0] == '{' && packString[length - 1] == '}') { + return view_as(JSONRootNode.Pack(packString, params)); + } else { + ThrowError("Pack string '%s' is not appropriate for creating a JSONObject", + packString); + return null; + } + } +} + +methodmap JSONObjectIterator < Handle { + public static JSONObjectIterator From(JSONObject obj, const char[] key = "") { + if (strlen(key) > 0) { + return view_as(json_object_iter_at(obj, key)); + } + return view_as(json_object_iter(obj)); + } + + public JSONObjectIterator Next(JSONObject obj) { + return view_as(json_object_iter_next(obj, this)); + } + + public int GetKey(char[] buffer, int maxlength) { + return json_object_iter_key(this, buffer, maxlength); + } + + public JSONValue GetValue() { + return view_as(json_object_iter_value(this)); + } + + public bool SetValue(JSONObject obj, JSONValue value, bool autoclose = true) { + if (autoclose) { + return json_object_iter_set_new(obj, this, value); + } + return json_object_iter_set(obj, this, value); + } +} + + +/** + * Some additional constructors + * + * + */ + +/** + * Returns a handle to a new JSON string, or INVALID_HANDLE on error. + * Formats the string according to the SourceMod format rules. + * The result must be a valid UTF-8 encoded Unicode string. + * + * @param sFormat Formatting rules. + * @param ... Variable number of format parameters. + * @return Handle to the new String object + */ +public JSONString JSONString_ByFormat(const char[] sFormat, ...) { + char sTmp[4096]; + VFormat(sTmp, sizeof(sTmp), sFormat, 2); + + return new JSONString(sTmp); +} + + +/** + * Returns a handle to a new JSON string, or INVALID_HANDLE on error. + * This stock allows to specify the size of the temporary buffer used + * to create the string. Use this if the default of 4096 is not enough + * for your string. + * Formats the string according to the SourceMod format rules. + * The result must be a valid UTF-8 encoded Unicode string. + * + * @param tmpBufferLength Size of the temporary buffer + * @param sFormat Formatting rules. + * @param ... Variable number of format parameters. + * @return Handle to the new String object + */ +public JSONString JSONString_ByFormatEx(int tmpBufferLength, const char[] sFormat, ...) { + char[] sTmp = new char[tmpBufferLength]; + VFormat(sTmp, tmpBufferLength, sFormat, 3); + + return new JSONString(sTmp); +} + + +/** + * Pack String Rules + * + * Here's the full list of format characters: + * n Output a JSON null value. No argument is consumed. + * s Output a JSON string, consuming one argument. + * b Output a JSON bool value, consuming one argument. + * i Output a JSON integer value, consuming one argument. + * f Output a JSON real value, consuming one argument. + * r Output a JSON real value, consuming one argument. + * [] Build an array with contents from the inner format string, + * recursive value building is supported. + * No argument is consumed. + * {} Build an array with contents from the inner format string. + * The first, third, etc. format character represent a key, + * and must be s (as object keys are always strings). The + * second, fourth, etc. format character represent a value. + * Recursive value building is supported. + * No argument is consumed. + * + */ + +/** + * This method can be used to create json objects/arrays directly + * without having to create the structure. + * See 'Pack String Rules' for more details. + * + * @param sPackString Pack string similiar to Format()s fmt. + * See 'Pack String Rules'. + * @param hParams ADT Array containing all keys and values + * in the order they appear in the pack string. + * + * @error Invalid pack string or pack string and + * ADT Array don't match up regarding type + * or size. + * @return Handle to JSON element. + */ +public JSONValue JSONValue_ByPack(const char[] sPackString, Handle hParams) { + int iPos = 0; + return json_pack_element_(sPackString, iPos, hParams); +} + + + + + +/** +* Internal stocks used by json_pack(). Don't use these directly! +* +*/ +public JSONArray json_pack_array_(const char[] sFormat, int &iPos, Handle hParams) { + JSONArray hObj = new JSONArray(); + int iStrLen = strlen(sFormat); + + for(; iPos < iStrLen;) { + int this_char = sFormat[iPos]; + + if(this_char == 32 || this_char == 58 || this_char == 44) { + // Skip whitespace, ',' and ':' + iPos++; + continue; + } + + if(this_char == 93) { + // array end + iPos++; + break; + } + + // Get the next entry as value + // This automatically increments the position! + JSONValue hValue = json_pack_element_(sFormat, iPos, hParams); + + // Append the value to the array. + hObj.Append(hValue); + } + + return hObj; +} + +public JSONObject json_pack_object_(const char[] sFormat, int &iPos, Handle hParams) { + JSONObject hObj = new JSONObject(); + int iStrLen = strlen(sFormat); + + for(; iPos < iStrLen;) { + int this_char = sFormat[iPos]; + + if(this_char == 32 || this_char == 58 || this_char == 44) { + // Skip whitespace, ',' and ':' + iPos++; + continue; + } + + if(this_char == 125) { + // } --> object end + iPos++; + break; + } + + if(this_char != 115) { + LogError("Object keys must be strings at %d.", iPos); + delete hObj; + return view_as(INVALID_HANDLE); + } + + // Get the key string for this object from + // the hParams array. + char sKey[255]; + GetArrayString(hParams, 0, sKey, sizeof(sKey)); + RemoveFromArray(hParams, 0); + + // Advance one character in the pack string, + // because we've just read the Key string for + // this object. + iPos++; + + // Get the next entry as value + // This automatically increments the position! + JSONValue hValue = json_pack_element_(sFormat, iPos, hParams); + + // Insert into object + hObj.Set(sKey, hValue); + } + + return hObj; +} + +public JSONValue json_pack_element_(const char[] sFormat, int &iPos, Handle hParams) { + int this_char = sFormat[iPos]; + while(this_char == 32 || this_char == 58 || this_char == 44) { + iPos++; + this_char = sFormat[iPos]; + } + + // Advance one character in the pack string + iPos++; + + switch(this_char) { + case 91: { + // { --> Array + return json_pack_array_(sFormat, iPos, hParams); + } + + case 123: { + // { --> Object + return json_pack_object_(sFormat, iPos, hParams); + + } + + case 98: { + // b --> Boolean + int iValue = GetArrayCell(hParams, 0); + RemoveFromArray(hParams, 0); + + return json_boolean(view_as(iValue)); + } + + case 102, 114: { + // r,f --> Real (Float) + float fValue = GetArrayCell(hParams, 0); + RemoveFromArray(hParams, 0); + + return json_real(fValue); + } + + case 110: { + // n --> NULL + return json_null(); + } + + case 115: { + // s --> String + char sKey[255]; + GetArrayString(hParams, 0, sKey, sizeof(sKey)); + RemoveFromArray(hParams, 0); + + return json_string(sKey); + } + + case 105: { + // i --> Integer + int iValue = GetArrayCell(hParams, 0); + RemoveFromArray(hParams, 0); + + return json_integer(iValue); + } + } + + SetFailState("Invalid pack String '%s'. Type '%s' not supported at %i", sFormat, this_char, iPos); + return json_null(); +} + + +/** + * Not yet implemented + * + * native json_object_foreach(Handle:hObj, ForEachCallback:cb); + * native Handle:json_unpack(const String:sFormat[], ...); + * + */ + + + /** + * Do not edit below this line! + */ +public Extension __ext_smjansson = +{ + name = "SMJansson", + file = "smjansson.ext", +#if defined AUTOLOAD_EXTENSIONS + autoload = 1, +#else + autoload = 0, +#endif +#if defined REQUIRE_EXTENSIONS + required = 1, +#else + required = 0, +#endif +}; + +#if !defined REQUIRE_EXTENSIONS +public __ext_smjansson_SetNTVOptional() +{ + MarkNativeAsOptional("json_typeof"); + MarkNativeAsOptional("json_equal"); + + MarkNativeAsOptional("json_copy"); + MarkNativeAsOptional("json_deep_copy"); + + MarkNativeAsOptional("json_object"); + MarkNativeAsOptional("json_object_size"); + MarkNativeAsOptional("json_object_get"); + MarkNativeAsOptional("json_object_set"); + MarkNativeAsOptional("json_object_set_new"); + MarkNativeAsOptional("json_object_del"); + MarkNativeAsOptional("json_object_clear"); + MarkNativeAsOptional("json_object_update"); + MarkNativeAsOptional("json_object_update_existing"); + MarkNativeAsOptional("json_object_update_missing"); + + MarkNativeAsOptional("json_object_iter"); + MarkNativeAsOptional("json_object_iter_at"); + MarkNativeAsOptional("json_object_iter_next"); + MarkNativeAsOptional("json_object_iter_key"); + MarkNativeAsOptional("json_object_iter_value"); + MarkNativeAsOptional("json_object_iter_set"); + MarkNativeAsOptional("json_object_iter_set_new"); + + MarkNativeAsOptional("json_array"); + MarkNativeAsOptional("json_array_size"); + MarkNativeAsOptional("json_array_get"); + MarkNativeAsOptional("json_array_set"); + MarkNativeAsOptional("json_array_set_new"); + MarkNativeAsOptional("json_array_append"); + MarkNativeAsOptional("json_array_append_new"); + MarkNativeAsOptional("json_array_insert"); + MarkNativeAsOptional("json_array_insert_new"); + MarkNativeAsOptional("json_array_remove"); + MarkNativeAsOptional("json_array_clear"); + MarkNativeAsOptional("json_array_extend"); + + MarkNativeAsOptional("json_string"); + MarkNativeAsOptional("json_string_value"); + MarkNativeAsOptional("json_string_set"); + + MarkNativeAsOptional("json_integer"); + MarkNativeAsOptional("json_integer_value"); + MarkNativeAsOptional("json_integer_set"); + + MarkNativeAsOptional("json_real"); + MarkNativeAsOptional("json_real_value"); + MarkNativeAsOptional("json_real_set"); + MarkNativeAsOptional("json_number_value"); + + MarkNativeAsOptional("json_boolean"); + MarkNativeAsOptional("json_true"); + MarkNativeAsOptional("json_false"); + MarkNativeAsOptional("json_null"); + + MarkNativeAsOptional("json_load"); + MarkNativeAsOptional("json_load_file"); + + MarkNativeAsOptional("json_dump"); + MarkNativeAsOptional("json_dump_file"); +} +#endif diff --git a/SourceTV/scripting/SourceTV.sp b/SourceTV/scripting/SourceTV.sp index 4da2ff6..0bdb398 100644 --- a/SourceTV/scripting/SourceTV.sp +++ b/SourceTV/scripting/SourceTV.sp @@ -25,7 +25,8 @@ public void SourceTV_OnSpectatorPutInServer(int client) SourceTV_GetClientName(client, sName, sizeof(sName)); - if(SourceTV_GetClientIP(client, sIP, sizeof(sIP)) && GeoipCountry(sIP, sCountry, sizeof(sCountry))) + SourceTV_GetClientIP(client, sIP, sizeof(sIP)); + if (strlen(sIP) != 0 && GeoipCountry(sIP, sCountry, sizeof(sCountry))) PrintToChatAll("\x04[\x03SourceTV\x04] %s connected from %s", sName, sCountry); else PrintToChatAll("\x04[\x03SourceTV\x04] %s connected", sName); diff --git a/StageDisplay/scripting/StageDisplay.sp b/StageDisplay/scripting/StageDisplay.sp index 579bf4a..0c09fbf 100644 --- a/StageDisplay/scripting/StageDisplay.sp +++ b/StageDisplay/scripting/StageDisplay.sp @@ -115,7 +115,8 @@ public void CheckStage() if(StrEqual(sMethod, "counter")) { char sCounter[64]; - if(!g_Config.GetString("counter", sCounter, sizeof(sCounter))) + g_Config.GetString("counter", sCounter, sizeof(sCounter), "not found"); + if (StrEqual(sCounter, "not found")) { LogError("Could not find \"counter\""); return; @@ -172,7 +173,8 @@ public void CheckStage() bHasDiffCounter = true; char sDiffCounter[64]; - if(!g_Config.GetString("counter", sDiffCounter, sizeof(sDiffCounter))) + g_Config.GetString("counter", sDiffCounter, sizeof(sDiffCounter), "not found"); + if (StrEqual(sDiffCounter, "not found")) { LogError("Could not find \"diffcounter\""); return; diff --git a/UNLOZE_ForumIntegration/scripting/UNLOZE_ForumIntegration.sp b/UNLOZE_ForumIntegration/scripting/UNLOZE_ForumIntegration.sp index 59f3463..715a12a 100644 --- a/UNLOZE_ForumIntegration/scripting/UNLOZE_ForumIntegration.sp +++ b/UNLOZE_ForumIntegration/scripting/UNLOZE_ForumIntegration.sp @@ -6,7 +6,7 @@ // //==================================================================================================== #include -#include +#include #include #include //#define UNLOZE_APIKEY here #include @@ -131,68 +131,71 @@ public void OnClientAuthorized(int client, const char[] sSteamID32) FormatEx(sRequest, sizeof(sRequest), "https://unloze.com/api/private_api.php?api_key=%s&steam_id=%s", UNLOZE_APIKEY, sSteamID64); int iSerial = GetClientSerial(client); - Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodGET, sRequest); - if (!hRequest || - !SteamWorks_SetHTTPCallbacks(hRequest, OnClientAuthorized_OnTransferComplete) || - !SteamWorks_SetHTTPRequestContextValue(hRequest, iSerial) || - !SteamWorks_SendHTTPRequest(hRequest)) - { - delete hRequest; - } + + char sPath[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, sPath, sizeof(sPath), "data/unloze_forum_%d.tmp", iSerial); + + HTTPRequest hRequest = new HTTPRequest(sRequest); + hRequest.DownloadFile(sPath, OnClientAuthorized_OnDownloaded, iSerial); } //---------------------------------------------------------------------------------------------------- -// Purpose: +// Purpose: ripexts HTTPResponse only exposes the body as decoded JSON, unlike +// SteamWorks' GetHTTPResponseBodyCallback which handed back a plain char[]. +// Rather than change private_api.php's response format, we use +// HTTPRequest.DownloadFile() to write the raw "GROUP\r\nNAME" body to a temp +// file and parse it back exactly like the original SteamWorks version did. //---------------------------------------------------------------------------------------------------- -public int OnClientAuthorized_OnTransferComplete(Handle hRequest, bool bFailure, bool bSuccessful, EHTTPStatusCode eStatusCode, int iSerial) +public void OnClientAuthorized_OnDownloaded(HTTPStatus status, any iSerial) { + char sPath[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, sPath, sizeof(sPath), "data/unloze_forum_%d.tmp", iSerial); + int client = GetClientFromSerial(iSerial); if (!client) //Player disconnected. { - delete hRequest; - return 0; + DeleteFile(sPath); + return; } - - if (bFailure || !bSuccessful || eStatusCode != k_EHTTPStatusCode200OK) + + if (status != HTTPStatus_OK) { + DeleteFile(sPath); G_bResponseFailed[client] = true; if (G_bPreAdminChecked[client]) NotifyPostAdminCheck(client); - delete hRequest; - return 0; + return; } - - SteamWorks_GetHTTPResponseBodyCallback(hRequest, OnClientAuthorized_OnTransferResponse, iSerial); - return 0; -} -//---------------------------------------------------------------------------------------------------- -// Purpose: -//---------------------------------------------------------------------------------------------------- -public int OnClientAuthorized_OnTransferResponse(char[] sData, int iSerial) -{ - char splitData[2][32]; + char sGroup[64], sName[32]; + sGroup[0] = '\0'; + sName[0] = '\0'; - int client = GetClientFromSerial(iSerial); - - if (!client) //Player disconnected. - return 0; - - TrimString(sData); - StripQuotes(sData); - - LogMessage("reached sData with status 200: %s", sData); - ExplodeString(sData, "\r\n", splitData, 2, sizeof(splitData[])); - - if(strlen(splitData[1]) > 0) - strcopy(G_sName[client], sizeof(G_sName[]), splitData[1]); - - if(!StrEqual(splitData[0], "NOGROUP")) + File hFile = OpenFile(sPath, "r"); + if (hFile != null) { - strcopy(G_sGroup[client], sizeof(G_sGroup[]), splitData[0]); + hFile.ReadLine(sGroup, sizeof(sGroup)); + hFile.ReadLine(sName, sizeof(sName)); + delete hFile; + } + DeleteFile(sPath); + + TrimString(sGroup); + StripQuotes(sGroup); + TrimString(sName); + StripQuotes(sName); + + LogMessage("reached sData with status 200: %s", sGroup); + + if (strlen(sName) > 0) + strcopy(G_sName[client], sizeof(G_sName[]), sName); + + if (!StrEqual(sGroup, "NOGROUP")) + { + strcopy(G_sGroup[client], sizeof(G_sGroup[]), sGroup); G_bResponsePassed[client] = true; @@ -201,7 +204,6 @@ public int OnClientAuthorized_OnTransferResponse(char[] sData, int iSerial) } else G_bResponseFailed[client] = true; //users with just a forum name did not pass the VIP check! so the response "failed" (but we store their forum name for later!) - return 0; } //---------------------------------------------------------------------------------------------------- @@ -263,7 +265,7 @@ public int Native_GetClientForumName(Handle plugin, int numParams) { int len = GetNativeCell(2); int client = GetNativeCell(1); - + SetNativeString(2, G_sName[client], len+1); return 0; } @@ -295,40 +297,39 @@ public int Native_AsyncHasSteamIDReservedSlot(Handle plugin, int numParams) hDataPack.WriteCell(plugin); hDataPack.WriteCell(data); - Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodGET, sRequest); - if (!hRequest || - !SteamWorks_SetHTTPCallbacks(hRequest, Native_AsyncHasSteamIDReservedSlot_OnTransferComplete) || - !SteamWorks_SetHTTPRequestContextValue(hRequest, hDataPack) || - !SteamWorks_SendHTTPRequest(hRequest)) - { - delete hRequest; - } + // The DataPack handle value is unique among currently-open handles, so it + // doubles as a collision-free key for the temp file this specific + // in-flight request will use. + char sPath[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, sPath, sizeof(sPath), "data/unloze_reslot_%d.tmp", view_as(hDataPack)); + + HTTPRequest hRequest = new HTTPRequest(sRequest); + hRequest.DownloadFile(sPath, Native_AsyncHasSteamIDReservedSlot_OnDownloaded, hDataPack); return 0; } //---------------------------------------------------------------------------------------------------- -// Purpose: +// Purpose: same DownloadFile-to-tempfile approach as OnClientAuthorized_OnDownloaded +// above - keeps private_api.php's raw "GROUP\r\nNAME" text response untouched. //---------------------------------------------------------------------------------------------------- -public int Native_AsyncHasSteamIDReservedSlot_OnTransferComplete(Handle hRequest, bool bFailure, bool bSuccessful, EHTTPStatusCode eStatusCode, DataPack hDataPack) +public void Native_AsyncHasSteamIDReservedSlot_OnDownloaded(HTTPStatus status, DataPack hDataPack) { - if (bFailure || !bSuccessful || eStatusCode != k_EHTTPStatusCode200OK) + char sPath[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, sPath, sizeof(sPath), "data/unloze_reslot_%d.tmp", view_as(hDataPack)); + + char sData[32] = "NOGROUP"; + + if (status == HTTPStatus_OK) { - char sData[32] = "NOGROUP"; - Native_AsyncHasSteamIDReservedSlot_OnTransferResponse(sData, hDataPack); - - delete hRequest; - return 0; + File hFile = OpenFile(sPath, "r"); + if (hFile != null) + { + hFile.ReadLine(sData, sizeof(sData)); + delete hFile; + } } + DeleteFile(sPath); - SteamWorks_GetHTTPResponseBodyCallback(hRequest, Native_AsyncHasSteamIDReservedSlot_OnTransferResponse, hDataPack); - return 0; -} - -//---------------------------------------------------------------------------------------------------- -// Purpose: -//---------------------------------------------------------------------------------------------------- -public int Native_AsyncHasSteamIDReservedSlot_OnTransferResponse(char[] sData, DataPack hDataPack) -{ hDataPack.Reset(); char sSteamID32[32]; @@ -347,7 +348,7 @@ public int Native_AsyncHasSteamIDReservedSlot_OnTransferResponse(char[] sData, D TrimString(sData); StripQuotes(sData); - + SplitString(sData, "\r\n", splitData, sizeof(splitData)); int result; @@ -363,7 +364,6 @@ public int Native_AsyncHasSteamIDReservedSlot_OnTransferResponse(char[] sData, D Call_Finish(); delete hDataPack; - return 0; } //---------------------------------------------------------------------------------------------------- diff --git a/VPN-Check/scripting/VPN-Check.sp b/VPN-Check/scripting/VPN-Check.sp index b96cc71..9318a5f 100644 --- a/VPN-Check/scripting/VPN-Check.sp +++ b/VPN-Check/scripting/VPN-Check.sp @@ -1,7 +1,6 @@ #include -#include +#include #include -#include #undef REQUIRE_PLUGIN #tryinclude @@ -151,72 +150,63 @@ public void SQL_OnQueryCompleted(Database db, DBResultSet results, const char[] GetClientIP(client, sIP, sizeof(sIP)); char sRequest[256]; - FormatEx(sRequest, sizeof(sRequest), "use a url here", sIP, APIKEY); + FormatEx(sRequest, sizeof(sRequest), "use a url here", sIP, APIKEY); //PrintToConsoleAll(sRequest); - Handle hRequest = SteamWorks_CreateHTTPRequest(k_EHTTPMethodGET, sRequest); - if (!hRequest || - !SteamWorks_SetHTTPCallbacks(hRequest, OnTransferComplete) || - !SteamWorks_SetHTTPRequestContextValue(hRequest, iSerial) || - !SteamWorks_SendHTTPRequest(hRequest)) - { - delete hRequest; - } + HTTPRequest hRequest = new HTTPRequest(sRequest); + hRequest.Get(OnTransferComplete, iSerial); } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- -public int OnTransferComplete(Handle hRequest, bool bFailure, bool bSuccessful, EHTTPStatusCode eStatusCode, int iSerial) +public void OnTransferComplete(HTTPResponse response, any iSerial) { int client = GetClientFromSerial(iSerial); if (!client) //Player disconnected. - { - delete hRequest; - return 0; - } + return; - if (bFailure || !bSuccessful || eStatusCode != k_EHTTPStatusCode200OK) + if (response.Status != HTTPStatus_OK || response.Data == null) { - delete hRequest; g_bStatus[client] = STATUS_ERROR; - LogError("Request-Error: %d", eStatusCode); - return 0; + LogError("Request-Error: %d", response.Status); + return; } - SteamWorks_GetHTTPResponseBodyCallback(hRequest, OnTransferResponse, iSerial); - return 0; -} - -//---------------------------------------------------------------------------------------------------- -// Purpose: -//---------------------------------------------------------------------------------------------------- -public int OnTransferResponse(char[] sData, int iSerial) -{ - int client = GetClientFromSerial(iSerial); - if (!client) //Player disconnected. - return 0; - char sIP[32]; GetClientIP(client, sIP, sizeof(sIP)); - JSON_Object obj = json_decode(sData); + // ripext already decodes the JSON body for us as a native JSONObject; no + JSONObject obj = view_as(response.Data); char sStatus[32]; - obj.GetString("status", sStatus, sizeof(sStatus)); + if (!obj.GetString("status", sStatus, sizeof(sStatus))) + sStatus[0] = '\0'; + if (!StrEqual(sStatus, "ok") && !StrEqual(sStatus, "warning")) { char sMessage[256]; - obj.GetString("message", sMessage, sizeof(sMessage)); + if (!obj.GetString("message", sMessage, sizeof(sMessage))) + sMessage[0] = '\0'; LogError("API-Response: %s: %s", sStatus, sMessage); g_bStatus[client] = STATUS_ERROR; - json_cleanup_and_delete(obj); - return 0; + delete obj; + return; } - JSON_Object ipobj = obj.GetObject(sIP); + if (!obj.HasKey(sIP)) + { + LogError("API-Response: no entry for IP %s", sIP); + g_bStatus[client] = STATUS_ERROR; + delete obj; + return; + } + + JSONObject ipobj = view_as(obj.Get(sIP)); char sProxy[16]; - ipobj.GetString("proxy", sProxy, sizeof(sProxy)); + if (!ipobj.GetString("proxy", sProxy, sizeof(sProxy))) + sProxy[0] = '\0'; + if (StrEqual(sProxy, "no")) g_bStatus[client] = STATUS_SAFE; else @@ -238,10 +228,8 @@ public int OnTransferResponse(char[] sData, int iSerial) Format(sQuery, sizeof(sQuery), "INSERT INTO ip_table (ip, type, last_check) VALUES ('%s', '%d', '%d') ON DUPLICATE KEY UPDATE type='%d', last_check='%d';", sIP, g_bStatus[client], iCurrentTime, g_bStatus[client], iCurrentTime); g_hDatabase.Query(SQL_OnQueryCompleted, sQuery, _, DBPrio_Low); - //https://github.com/clugg/sm-json/blob/master/addons/sourcemod/scripting/json_test.sp#L446 - //as far as i can tell i just need to call json_cleanup_and_delete() on the most outer json object, all its children should get cleaned and deleted as well. - json_cleanup_and_delete(obj); - return 0; + delete ipobj; + delete obj; } //---------------------------------------------------------------------------------------------------- @@ -405,3 +393,4 @@ public void OnLibraryRemoved(const char[] sName) if (strcmp(sName, "PlayerManager", false) == 0) g_bPMLoaded = false; } + diff --git a/WeaponCleaner/scripting/WeaponCleaner.sp b/WeaponCleaner/scripting/WeaponCleaner.sp index 1925953..c119eb1 100644 --- a/WeaponCleaner/scripting/WeaponCleaner.sp +++ b/WeaponCleaner/scripting/WeaponCleaner.sp @@ -87,16 +87,21 @@ public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] n public void OnMapStart() { - if(g_hTimer != INVALID_HANDLE && CloseHandle(g_hTimer)) + if(g_hTimer != INVALID_HANDLE) + { + CloseHandle(g_hTimer); g_hTimer = INVALID_HANDLE; - + } g_hTimer = CreateTimer(TIMER_INTERVAL, Timer_CleanupWeapons, INVALID_HANDLE, TIMER_REPEAT); } public void OnMapEnd() { - if(g_hTimer != INVALID_HANDLE && CloseHandle(g_hTimer)) + if(g_hTimer != INVALID_HANDLE) + { + CloseHandle(g_hTimer); g_hTimer = INVALID_HANDLE; + } } public void OnClientPutInServer(int client) diff --git a/custom-chatcolors/scripting/custom-chatcolors.sp b/custom-chatcolors/scripting/custom-chatcolors.sp index f1145bd..f69f2da 100644 --- a/custom-chatcolors/scripting/custom-chatcolors.sp +++ b/custom-chatcolors/scripting/custom-chatcolors.sp @@ -2701,11 +2701,11 @@ public Action Event_PlayerSay(Handle event, const char[] name, bool dontBroadcas { if (g_msgAuthor == -1 || GetClientOfUserId(GetEventInt(event, "userid")) != g_msgAuthor) { - return; + return Plugin_Handled; } if (strlen(g_msgText) == 0) - return; + return Plugin_Handled; int[] players = new int[MaxClients + 1]; int playersNum = 0; @@ -2738,7 +2738,7 @@ public Action Event_PlayerSay(Handle event, const char[] name, bool dontBroadcas if (!playersNum) { g_msgAuthor = -1; - return; + return Plugin_Handled; } Handle SayText2 = StartMessage("SayText2", players, playersNum, USERMSG_RELIABLE | USERMSG_BLOCKHOOKS); @@ -2759,6 +2759,7 @@ public Action Event_PlayerSay(Handle event, const char[] name, bool dontBroadcas } g_msgAuthor = -1; + return Plugin_Handled; } // 888b 888 d8888 88888888888 8888888 888 888 8888888888 .d8888b. diff --git a/includes/AsyncSocket.inc b/includes/AsyncSocket.inc index a662238..0d71d62 100644 --- a/includes/AsyncSocket.inc +++ b/includes/AsyncSocket.inc @@ -20,7 +20,7 @@ methodmap AsyncSocket < Handle { public bool WriteNull(const char[] data) { - this.Write(data, strlen(data) + 1); + return this.Write(data, strlen(data) + 1); } public native bool SetConnectCallback(AsyncSocketConnectCallback callback); diff --git a/includes/smjansson.inc b/includes/smjansson.inc index 3cbaf06..0bc2f19 100644 --- a/includes/smjansson.inc +++ b/includes/smjansson.inc @@ -1052,9 +1052,9 @@ methodmap JSONRootNode < JSONValue { return view_as(json_load_file(path)); } - public static JSONRootNode Pack(const char[] packString, ArrayList params) { - return JSONValue_ByPack(packString, params); - } + public static JSONRootNode Pack(const char[] packString, ArrayList params) { + return view_as(JSONValue_ByPack(packString, params)); + } public void DumpToServer() { char sMsg[4096];