Author SHA1 Message Date
A1m` 07fc524d27 Fixed incorrect use of ReferenceToIndex, which caused some functions to be unstable during client connection. (#2)
While this function works well with the client indexes we pass in, as its name
suggests, we should essentially be passing player references, not client indexes.
The problem is that SourceMod looks for this player in the entity list, but they
might not be there when connecting, or they might be another client or a bot.

This makes the code unstable and confusing, and it works intermittently.
Steam doesn't care whether the player is in the entity list—it works with the
Steam ID. Using ReferenceToIndex here is fundamentally wrong and causes random
-1 errors, especially during OnClientConnect when the entity may not exist yet.

This commit replaces it with a direct client index lookup, which is correct and
reliable because params[1] is already a client index.
2026-07-13 21:39:04 +00:00
Nicholas Hastings 8fd7a1988c Update extension author and repository URL 2026-07-12 22:40:00 -04:00
Nicholas Hastings 65936e7d9c Fix size_t truncation warning in SetHTTPRequestRawPostBodyFromFile 2026-07-12 22:10:00 -04:00
Nicholas Hastings 645103735e Fix streaming HTTP response header and data callbacks 2026-07-12 21:20:00 -04:00
Nicholas Hastings a779d6d961 Expose SetAdvertiseServerActive 2026-07-12 15:17:29 -04:00
Nicholas Hastings c82feb1a4a Add methodmap for SteamWorksHTTPRequest 2026-07-12 13:59:38 -04:00
Nicholas Hastings ceeaf66b95 Add function docs to inc 2026-07-12 13:31:37 -04:00
9 changed files with 1043 additions and 53 deletions
+1
View File
@@ -72,6 +72,7 @@ void SteamWorks::SDK_OnUnload()
delete this->pSWHTTPNatives; delete this->pSWHTTPNatives;
delete this->pSWHTTP; delete this->pSWHTTP;
this->pSWHTTP = NULL; /* Requests freed via frame actions may outlive us; let their dtor detect this. */
delete this->pSWGameServer; delete this->pSWGameServer;
delete this->pSWGameData; delete this->pSWGameData;
} }
+43 -15
View File
@@ -190,6 +190,19 @@ static cell_t sm_ClearRules(IPluginContext *pContext, const cell_t *params)
return 1; return 1;
} }
static cell_t sm_SetAdvertiseServerActive(IPluginContext *pContext, const cell_t *params)
{
ISteamGameServer *pServer = GetGSPointer();
if (pServer == NULL)
{
return 0;
}
pServer->SetAdvertiseServerActive(!!params[1]);
return 1;
}
static cell_t sm_ForceHeartbeat(IPluginContext *pContext, const cell_t *params) static cell_t sm_ForceHeartbeat(IPluginContext *pContext, const cell_t *params)
{ {
/* Deprecated no-op: newer Steamworks SDKs removed ISteamGameServer::ForceHeartbeat(); /* Deprecated no-op: newer Steamworks SDKs removed ISteamGameServer::ForceHeartbeat();
@@ -205,12 +218,17 @@ static cell_t sm_UserHasLicenseForApp(IPluginContext *pContext, const cell_t *pa
{ {
return k_EUserHasLicenseResultNoAuth; return k_EUserHasLicenseResultNoAuth;
} }
int client = gamehelpers->ReferenceToIndex(params[1]); int client = params[1];
IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client); /* Man, including GameHelpers and PlayerHelpers for this native :(. */ if (client < 1 || client > playerhelpers->GetMaxClients())
if (pPlayer == NULL || pPlayer->IsConnected() == false)
{ {
return pContext->ThrowNativeError("Client index %d is invalid", params[1]); return pContext->ThrowNativeError("Client index %d is invalid", client);
}
IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client);
if (pPlayer == NULL || !pPlayer->IsConnected())
{
return pContext->ThrowNativeError("Client index %d is not connected", client);
} }
CSteamID checkid = CreateCommonCSteamID(pPlayer, params, 3, 4); CSteamID checkid = CreateCommonCSteamID(pPlayer, params, 3, 4);
@@ -232,12 +250,16 @@ static cell_t sm_UserHasLicenseForAppId(IPluginContext *pContext, const cell_t *
static cell_t sm_GetClientSteamID(IPluginContext *pContext, const cell_t *params) static cell_t sm_GetClientSteamID(IPluginContext *pContext, const cell_t *params)
{ {
int client = gamehelpers->ReferenceToIndex(params[1]); int client = params[1];
IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client); if (client < 1 || client > playerhelpers->GetMaxClients())
if (pPlayer == NULL || pPlayer->IsConnected() == false)
{ {
return pContext->ThrowNativeError("Client index %d is invalid", params[1]); return pContext->ThrowNativeError("Client index %d is invalid", client);
}
IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client);
if (pPlayer == NULL || !pPlayer->IsConnected())
{
return pContext->ThrowNativeError("Client index %d is not connected", client);
} }
CSteamID steamId = CreateCommonCSteamID(pPlayer, params, 4, 5); CSteamID steamId = CreateCommonCSteamID(pPlayer, params, 4, 5);
@@ -257,14 +279,19 @@ static cell_t sm_GetUserGroupStatus(IPluginContext *pContext, const cell_t *para
if (pServer == NULL) if (pServer == NULL)
{ {
return false; return 0;
} }
int client = gamehelpers->ReferenceToIndex(params[1]); int client = params[1];
IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client); /* Man, including GameHelpers and PlayerHelpers for this native :(. */ if (client < 1 || client > playerhelpers->GetMaxClients())
if (pPlayer == NULL || pPlayer->IsConnected() == false)
{ {
return pContext->ThrowNativeError("Client index %d is invalid", params[1]); return pContext->ThrowNativeError("Client index %d is invalid", client);
}
IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client);
if (pPlayer == NULL || !pPlayer->IsConnected())
{
return pContext->ThrowNativeError("Client index %d is not connected", client);
} }
CSteamID checkid = CreateCommonCSteamID(pPlayer, params, 3, 4); CSteamID checkid = CreateCommonCSteamID(pPlayer, params, 3, 4);
@@ -295,6 +322,7 @@ static sp_nativeinfo_t gsnatives[] = {
{"SteamWorks_IsConnected", sm_IsConnected}, {"SteamWorks_IsConnected", sm_IsConnected},
{"SteamWorks_SetRule", sm_SetRule}, {"SteamWorks_SetRule", sm_SetRule},
{"SteamWorks_ClearRules", sm_ClearRules}, {"SteamWorks_ClearRules", sm_ClearRules},
{"SteamWorks_SetAdvertiseServerActive", sm_SetAdvertiseServerActive},
{"SteamWorks_ForceHeartbeat", sm_ForceHeartbeat}, {"SteamWorks_ForceHeartbeat", sm_ForceHeartbeat},
{"SteamWorks_HasLicenseForApp", sm_UserHasLicenseForApp}, {"SteamWorks_HasLicenseForApp", sm_UserHasLicenseForApp},
{"SteamWorks_HasLicenseForAppId", sm_UserHasLicenseForAppId}, {"SteamWorks_HasLicenseForAppId", sm_UserHasLicenseForAppId},
+2 -2
View File
@@ -41,8 +41,8 @@
#define SMEXT_CONF_NAME "SteamWorks Extension" #define SMEXT_CONF_NAME "SteamWorks Extension"
#define SMEXT_CONF_DESCRIPTION "Exposes SteamWorks functions to Developers" #define SMEXT_CONF_DESCRIPTION "Exposes SteamWorks functions to Developers"
#define SMEXT_CONF_VERSION "1.2.3" #define SMEXT_CONF_VERSION "1.2.3"
#define SMEXT_CONF_AUTHOR "Kyle Sanderson" #define SMEXT_CONF_AUTHOR "Kyle Sanderson, AlliedModders"
#define SMEXT_CONF_URL "http://AlliedMods.net" #define SMEXT_CONF_URL "https://github.com/alliedmodders/SM-SteamWorks"
#define SMEXT_CONF_LOGTAG "STEAMWORKS" #define SMEXT_CONF_LOGTAG "STEAMWORKS"
#define SMEXT_CONF_LICENSE "GPLv3" #define SMEXT_CONF_LICENSE "GPLv3"
#define SMEXT_CONF_DATESTRING __DATE__ #define SMEXT_CONF_DATESTRING __DATE__
+27 -12
View File
@@ -60,11 +60,16 @@ static cell_t sm_RequestUserStats(IPluginContext *pContext, const cell_t *params
return 0; return 0;
} }
int client = gamehelpers->ReferenceToIndex(params[1]); int client = params[1];
IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client); /* Man, including GameHelpers and PlayerHelpers for this native :(. */ if (client < 1 || client > playerhelpers->GetMaxClients())
if (pPlayer == NULL || pPlayer->IsConnected() == false)
{ {
return pContext->ThrowNativeError("Client index %d is invalid", params[1]); return pContext->ThrowNativeError("Client index %d is invalid", client);
}
IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client);
if (pPlayer == NULL || !pPlayer->IsConnected())
{
return pContext->ThrowNativeError("Client index %d is not connected", client);
} }
CSteamID checkid = CreateCommonCSteamID(pPlayer, params); CSteamID checkid = CreateCommonCSteamID(pPlayer, params);
@@ -80,11 +85,16 @@ static cell_t sm_GetStatCell(IPluginContext *pContext, const cell_t *params)
return 0; return 0;
} }
int client = gamehelpers->ReferenceToIndex(params[1]); int client = params[1];
IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client); /* Man, including GameHelpers and PlayerHelpers for this native :(. */ if (client < 1 || client > playerhelpers->GetMaxClients())
if (pPlayer == NULL || pPlayer->IsConnected() == false)
{ {
return pContext->ThrowNativeError("Client index %d is invalid", params[1]); return pContext->ThrowNativeError("Client index %d is invalid", client);
}
IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client);
if (pPlayer == NULL || !pPlayer->IsConnected())
{
return pContext->ThrowNativeError("Client index %d is not connected", client);
} }
char *pName; char *pName;
@@ -123,11 +133,16 @@ static cell_t sm_GetStatFloat(IPluginContext *pContext, const cell_t *params)
return 0; return 0;
} }
int client = gamehelpers->ReferenceToIndex(params[1]); int client = params[1];
IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client); /* Man, including GameHelpers and PlayerHelpers for this native :(. */ if (client < 1 || client > playerhelpers->GetMaxClients())
if (pPlayer == NULL || pPlayer->IsConnected() == false)
{ {
return pContext->ThrowNativeError("Client index %d is invalid", params[1]); return pContext->ThrowNativeError("Client index %d is invalid", client);
}
IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(client);
if (pPlayer == NULL || !pPlayer->IsConnected())
{
return pContext->ThrowNativeError("Client index %d is not connected", client);
} }
char *pName; char *pName;
+43 -1
View File
@@ -23,7 +23,9 @@ static ISteamHTTP *GetHTTPPointer()
return g_SteamWorks.pSWGameServer->GetHTTP(); return g_SteamWorks.pSWGameServer->GetHTTP();
} }
SteamWorksHTTP::SteamWorksHTTP() SteamWorksHTTP::SteamWorksHTTP() :
m_CallbackHeadersReceived(this, &SteamWorksHTTP::OnHTTPHeadersReceived),
m_CallbackDataReceived(this, &SteamWorksHTTP::OnHTTPDataReceived)
{ {
this->typeHTTP = handlesys->CreateType("HTTPHandle", this, 0, NULL, NULL, myself->GetIdentity(), NULL); this->typeHTTP = handlesys->CreateType("HTTPHandle", this, 0, NULL, NULL, myself->GetIdentity(), NULL);
} }
@@ -38,6 +40,46 @@ HandleType_t SteamWorksHTTP::GetHTTPHandle(void)
return this->typeHTTP; return this->typeHTTP;
} }
void SteamWorksHTTP::RegisterRequest(SteamWorksHTTPRequest *pRequest)
{
if (pRequest->request != INVALID_HTTPREQUEST_HANDLE)
{
this->m_Requests[pRequest->request] = pRequest;
}
}
void SteamWorksHTTP::UnregisterRequest(SteamWorksHTTPRequest *pRequest)
{
if (pRequest->request != INVALID_HTTPREQUEST_HANDLE)
{
this->m_Requests.erase(pRequest->request);
}
}
SteamWorksHTTPRequest *SteamWorksHTTP::FindRequest(HTTPRequestHandle request)
{
auto it = this->m_Requests.find(request);
return (it == this->m_Requests.end()) ? NULL : it->second;
}
void SteamWorksHTTP::OnHTTPHeadersReceived(HTTPRequestHeadersReceived_t *pParam)
{
SteamWorksHTTPRequest *pRequest = this->FindRequest(pParam->m_hRequest);
if (pRequest != NULL)
{
pRequest->OnHTTPHeadersReceived(pParam);
}
}
void SteamWorksHTTP::OnHTTPDataReceived(HTTPRequestDataReceived_t *pParam)
{
SteamWorksHTTPRequest *pRequest = this->FindRequest(pParam->m_hRequest);
if (pRequest != NULL)
{
pRequest->OnHTTPDataReceived(pParam);
}
}
static void DelayedDeleteSteamWorksHTTPRequest(void *object) static void DelayedDeleteSteamWorksHTTPRequest(void *object)
{ {
SteamWorksHTTPRequest *pRequest = reinterpret_cast<SteamWorksHTTPRequest *>(object); SteamWorksHTTPRequest *pRequest = reinterpret_cast<SteamWorksHTTPRequest *>(object);
+20 -1
View File
@@ -21,6 +21,10 @@
#include "steam_gameserver.h" #include "steam_gameserver.h"
#include "smsdk_ext.h" #include "smsdk_ext.h"
#include <unordered_map>
class SteamWorksHTTPRequest;
class SteamWorksHTTP : class SteamWorksHTTP :
public IHandleTypeDispatch public IHandleTypeDispatch
{ {
@@ -31,12 +35,27 @@ class SteamWorksHTTP :
public: public:
void OnHandleDestroy(HandleType_t type, void *object); void OnHandleDestroy(HandleType_t type, void *object);
bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize); bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize);
public: public:
HandleType_t GetHTTPHandle(void); HandleType_t GetHTTPHandle(void);
/* Streaming responses report progress through HTTPRequestHeadersReceived_t /
HTTPRequestDataReceived_t. Steam delivers those as broadcast gameserver
callbacks (not as call results of the streaming API call), so a single
dispatcher here receives them and routes each one to the owning request by
its handle. Requests add/remove themselves as they are created/destroyed. */
void RegisterRequest(SteamWorksHTTPRequest *pRequest);
void UnregisterRequest(SteamWorksHTTPRequest *pRequest);
private:
SteamWorksHTTPRequest *FindRequest(HTTPRequestHandle request);
STEAM_GAMESERVER_CALLBACK(SteamWorksHTTP, OnHTTPHeadersReceived, HTTPRequestHeadersReceived_t, m_CallbackHeadersReceived);
STEAM_GAMESERVER_CALLBACK(SteamWorksHTTP, OnHTTPDataReceived, HTTPRequestDataReceived_t, m_CallbackDataReceived);
private: private:
HandleType_t typeHTTP; HandleType_t typeHTTP;
std::unordered_map<HTTPRequestHandle, SteamWorksHTTPRequest *> m_Requests;
}; };
#include "swhttprequest.h" #include "swhttprequest.h"
+51 -18
View File
@@ -67,6 +67,14 @@ SteamWorksHTTPRequest::SteamWorksHTTPRequest() : request(INVALID_HTTPREQUEST_HAN
SteamWorksHTTPRequest::~SteamWorksHTTPRequest() SteamWorksHTTPRequest::~SteamWorksHTTPRequest()
{ {
/* Requests are freed via a frame action, so on extension unload this can run
after the dispatcher itself has been torn down; pSWHTTP is nulled in that
case (see SDK_OnUnload), so guard against it. */
if (g_SteamWorks.pSWHTTP != NULL)
{
g_SteamWorks.pSWHTTP->UnregisterRequest(this);
}
ISteamHTTP *pHTTP = GetHTTPPointer(); ISteamHTTP *pHTTP = GetHTTPPointer();
if (pHTTP != NULL) if (pHTTP != NULL)
{ {
@@ -101,7 +109,10 @@ void SteamWorksHTTPRequest::OnHTTPRequestCompleted(HTTPRequestCompleted_t *pRequ
this->pCompletedForward->Execute(NULL); this->pCompletedForward->Execute(NULL);
} }
void SteamWorksHTTPRequest::OnHTTPHeadersReceived(HTTPRequestHeadersReceived_t *pRequest, bool bFailed) /* Streaming header/data notifications are success-only callbacks (unlike the
completion call result, they carry no IO-failure flag), so bFailure is always
false here. Failures still surface through the completion callback. */
void SteamWorksHTTPRequest::OnHTTPHeadersReceived(HTTPRequestHeadersReceived_t *pRequest)
{ {
if (this->pHeadersReceivedForward == NULL || this->pHeadersReceivedForward->GetFunctionCount() == 0) if (this->pHeadersReceivedForward == NULL || this->pHeadersReceivedForward->GetFunctionCount() == 0)
{ {
@@ -109,13 +120,13 @@ void SteamWorksHTTPRequest::OnHTTPHeadersReceived(HTTPRequestHeadersReceived_t *
} }
this->pHeadersReceivedForward->PushCell(this->handle); this->pHeadersReceivedForward->PushCell(this->handle);
this->pHeadersReceivedForward->PushCell(bFailed); this->pHeadersReceivedForward->PushCell(false);
this->pHeadersReceivedForward->PushCell(pRequest->m_ulContextValue >> 32); this->pHeadersReceivedForward->PushCell(pRequest->m_ulContextValue >> 32);
this->pHeadersReceivedForward->PushCell((pRequest->m_ulContextValue & 0x00000000FFFFFFFF)); this->pHeadersReceivedForward->PushCell((pRequest->m_ulContextValue & 0x00000000FFFFFFFF));
this->pHeadersReceivedForward->Execute(NULL); this->pHeadersReceivedForward->Execute(NULL);
} }
void SteamWorksHTTPRequest::OnHTTPDataReceived(HTTPRequestDataReceived_t *pRequest, bool bFailed) void SteamWorksHTTPRequest::OnHTTPDataReceived(HTTPRequestDataReceived_t *pRequest)
{ {
if (this->pDataReceivedForward == NULL || this->pDataReceivedForward->GetFunctionCount() == 0) if (this->pDataReceivedForward == NULL || this->pDataReceivedForward->GetFunctionCount() == 0)
{ {
@@ -123,7 +134,7 @@ void SteamWorksHTTPRequest::OnHTTPDataReceived(HTTPRequestDataReceived_t *pReque
} }
this->pDataReceivedForward->PushCell(this->handle); this->pDataReceivedForward->PushCell(this->handle);
this->pDataReceivedForward->PushCell(bFailed); this->pDataReceivedForward->PushCell(false);
this->pDataReceivedForward->PushCell(pRequest->m_cOffset); this->pDataReceivedForward->PushCell(pRequest->m_cOffset);
this->pDataReceivedForward->PushCell(pRequest->m_cBytesReceived); this->pDataReceivedForward->PushCell(pRequest->m_cBytesReceived);
this->pDataReceivedForward->PushCell(pRequest->m_ulContextValue >> 32); this->pDataReceivedForward->PushCell(pRequest->m_ulContextValue >> 32);
@@ -159,7 +170,9 @@ static cell_t sm_CreateHTTPRequest(IPluginContext *pContext, const cell_t *param
pRequest->request = request; pRequest->request = request;
pRequest->handle = handle; pRequest->handle = handle;
g_SteamWorks.pSWHTTP->RegisterRequest(pRequest);
return handle; return handle;
} }
@@ -296,23 +309,14 @@ static cell_t sm_SetCallbacks(IPluginContext *pContext, const cell_t *params)
static void SetCallbacks(SteamAPICall_t &hCall, SteamWorksHTTPRequest *pRequest) static void SetCallbacks(SteamAPICall_t &hCall, SteamWorksHTTPRequest *pRequest)
{ {
/* Only completion is a call result of this send. Header/data streaming
notifications are delivered as broadcast callbacks and routed to the request
by SteamWorksHTTP's dispatcher, so there is nothing to bind to hCall here. */
if (pRequest->pCompletedForward != NULL) if (pRequest->pCompletedForward != NULL)
{ {
pRequest->CompletedCallResult.SetGameserverFlag(); pRequest->CompletedCallResult.SetGameserverFlag();
pRequest->CompletedCallResult.Set(hCall, pRequest, &SteamWorksHTTPRequest::OnHTTPRequestCompleted); pRequest->CompletedCallResult.Set(hCall, pRequest, &SteamWorksHTTPRequest::OnHTTPRequestCompleted);
} }
if (pRequest->pHeadersReceivedForward != NULL)
{
pRequest->HeadersCallResult.SetGameserverFlag();
pRequest->HeadersCallResult.Set(hCall, pRequest, &SteamWorksHTTPRequest::OnHTTPHeadersReceived);
}
if (pRequest->pDataReceivedForward != NULL)
{
pRequest->DataCallResult.SetGameserverFlag();
pRequest->DataCallResult.Set(hCall, pRequest, &SteamWorksHTTPRequest::OnHTTPDataReceived);
}
} }
static cell_t sm_SendHTTPRequestAndStreamResponse(IPluginContext *pContext, const cell_t *params) static cell_t sm_SendHTTPRequestAndStreamResponse(IPluginContext *pContext, const cell_t *params)
@@ -500,7 +504,7 @@ static cell_t sm_SetHTTPRequestRawPostBodyFromFile(IPluginContext *pContext, con
} }
char *pBuffer = new char[size + 1]; char *pBuffer = new char[size + 1];
uint32_t itemsRead = fread(pBuffer, sizeof(char), size, pInputFile); size_t itemsRead = fread(pBuffer, sizeof(char), size, pInputFile);
fclose(pInputFile); fclose(pInputFile);
if (itemsRead != size) if (itemsRead != size)
@@ -706,6 +710,35 @@ static sp_nativeinfo_t httpnatives[] = {
{"SteamWorks_WriteHTTPResponseBodyToFile", sm_WriteHTTPResponseBodyToFile}, {"SteamWorks_WriteHTTPResponseBodyToFile", sm_WriteHTTPResponseBodyToFile},
{"SteamWorks_SendHTTPRequestAndStreamResponse", sm_SendHTTPRequestAndStreamResponse}, {"SteamWorks_SendHTTPRequestAndStreamResponse", sm_SendHTTPRequestAndStreamResponse},
{"SteamWorks_GetHTTPStreamingResponseBodyData", sm_GetHTTPStreamingResponseBodyData}, {"SteamWorks_GetHTTPStreamingResponseBodyData", sm_GetHTTPStreamingResponseBodyData},
/* SteamWorksHTTPRequest methodmap. These reuse the functions above; the implicit
`this` handle arrives as params[1], exactly like the hHandle/hRequest first
parameter of the free-function natives (and the constructor maps to the create
native, whose first argument is likewise params[1]). */
{"SteamWorksHTTPRequest.SteamWorksHTTPRequest", sm_CreateHTTPRequest},
{"SteamWorksHTTPRequest.SetContextValue", sm_SetHTTPRequestContextValue},
{"SteamWorksHTTPRequest.SetNetworkActivityTimeout", sm_SetHTTPRequestNetworkActivityTimeout},
{"SteamWorksHTTPRequest.SetHeaderValue", sm_SetHTTPRequestHeaderValue},
{"SteamWorksHTTPRequest.SetGetOrPostParameter", sm_SetHTTPRequestGetOrPostParameter},
{"SteamWorksHTTPRequest.SetUserAgentInfo", sm_SetHTTPRequestUserAgentInfo},
{"SteamWorksHTTPRequest.SetRequiresVerifiedCertificate", sm_SetHTTPRequestRequiresVerifiedCertificate},
{"SteamWorksHTTPRequest.SetAbsoluteTimeoutMS", sm_SetHTTPRequestAbsoluteTimeoutMS},
{"SteamWorksHTTPRequest.SetCallbacks", sm_SetCallbacks},
{"SteamWorksHTTPRequest.Send", sm_SendHTTPRequest},
{"SteamWorksHTTPRequest.SendAndStreamResponse", sm_SendHTTPRequestAndStreamResponse},
{"SteamWorksHTTPRequest.Defer", sm_DeferHTTPRequest},
{"SteamWorksHTTPRequest.Prioritize", sm_PrioritizeHTTPRequest},
{"SteamWorksHTTPRequest.GetResponseHeaderSize", sm_GetHTTPResponseHeaderSize},
{"SteamWorksHTTPRequest.GetResponseHeaderValue", sm_GetHTTPResponseHeaderValue},
{"SteamWorksHTTPRequest.GetResponseBodySize", sm_GetHTTPResponseBodySize},
{"SteamWorksHTTPRequest.GetResponseBodyData", sm_GetHTTPResponseBodyData},
{"SteamWorksHTTPRequest.GetStreamingResponseBodyData", sm_GetHTTPStreamingResponseBodyData},
{"SteamWorksHTTPRequest.GetDownloadProgressPct", sm_GetHTTPDownloadProgressPct},
{"SteamWorksHTTPRequest.GetWasTimedOut", sm_GetHTTPRequestWasTimedOut},
{"SteamWorksHTTPRequest.SetRawPostBody", sm_SetHTTPRequestRawPostBody},
{"SteamWorksHTTPRequest.SetRawPostBodyFromFile", sm_SetHTTPRequestRawPostBodyFromFile},
{"SteamWorksHTTPRequest.GetResponseBodyCallback", sm_GetHTTPResponseBodyCallback},
{"SteamWorksHTTPRequest.WriteResponseBodyToFile", sm_WriteHTTPResponseBodyToFile},
{NULL, NULL} {NULL, NULL}
}; };
+5 -4
View File
@@ -32,14 +32,15 @@ class SteamWorksHTTPRequest
Handle_t handle; Handle_t handle;
public: public:
/* Completion is a genuine call result of the send API call, so it stays a
CCallResult. Headers/data arrive as broadcast callbacks and are routed here
by SteamWorksHTTP's dispatcher, hence no per-request CCallResult for them. */
void OnHTTPRequestCompleted(HTTPRequestCompleted_t *pRequest, bool bFailed); void OnHTTPRequestCompleted(HTTPRequestCompleted_t *pRequest, bool bFailed);
void OnHTTPHeadersReceived(HTTPRequestHeadersReceived_t *pRequest, bool bFailed); void OnHTTPHeadersReceived(HTTPRequestHeadersReceived_t *pRequest);
void OnHTTPDataReceived(HTTPRequestDataReceived_t *pRequest, bool bFailed); void OnHTTPDataReceived(HTTPRequestDataReceived_t *pRequest);
public: public:
CCallResult<SteamWorksHTTPRequest, HTTPRequestCompleted_t> CompletedCallResult; CCallResult<SteamWorksHTTPRequest, HTTPRequestCompleted_t> CompletedCallResult;
CCallResult<SteamWorksHTTPRequest, HTTPRequestHeadersReceived_t> HeadersCallResult;
CCallResult<SteamWorksHTTPRequest, HTTPRequestDataReceived_t> DataCallResult;
public: public:
IChangeableForward *pCompletedForward; IChangeableForward *pCompletedForward;
+851
View File
@@ -245,6 +245,12 @@ enum EHTTPStatusCode
k_EHTTPStatusCode5xxUnknown = 599, k_EHTTPStatusCode5xxUnknown = 599,
}; };
/**
* Returns whether an HTTP status code represents success (a 2xx code).
*
* @param eStatusCode HTTP status code to test.
* @return True if the code is in the 2xx range, false otherwise.
*/
stock bool IsHTTPStatusSuccess(EHTTPStatusCode eStatusCode) stock bool IsHTTPStatusSuccess(EHTTPStatusCode eStatusCode)
{ {
return (eStatusCode >= k_EHTTPStatusCode200OK && eStatusCode < k_EHTTPStatusCode300MultipleChoices); return (eStatusCode >= k_EHTTPStatusCode200OK && eStatusCode < k_EHTTPStatusCode300MultipleChoices);
@@ -260,41 +266,326 @@ enum EGCResults
k_EGCResultInvalidMessage = 4, // Something was wrong with the message being sent with SendMessage k_EGCResultInvalidMessage = 4, // Something was wrong with the message being sent with SendMessage
}; };
/**
* Returns whether the server is VAC (Valve Anti-Cheat) secured.
*
* @return True if the server is VAC secured, false otherwise (including
* when not yet connected to Steam).
*/
native bool SteamWorks_IsVACEnabled(); native bool SteamWorks_IsVACEnabled();
/**
* Retrieves the server's public IP address as four octets.
*
* @param ipaddr Array that receives the IP address, most-significant octet first
* (e.g. 127.0.0.1 becomes {127, 0, 0, 1}).
* @return True on success, false if not connected to Steam or the public
* IP is not yet known.
*/
native bool SteamWorks_GetPublicIP(int ipaddr[4]); native bool SteamWorks_GetPublicIP(int ipaddr[4]);
/**
* Retrieves the server's public IP address packed into a single cell.
*
* @return The IPv4 address as a 32-bit value (host byte order), or 0 if not
* connected to Steam or the public IP is not yet known.
*/
native int SteamWorks_GetPublicIPCell(); native int SteamWorks_GetPublicIPCell();
/**
* Returns whether the Steam client library has been loaded by the extension.
*
* @return True if the Steam library is loaded, false otherwise.
*/
native bool SteamWorks_IsLoaded(); native bool SteamWorks_IsLoaded();
/**
* Sets the "gamedata" string for the server, used for matchmaking/server-browser filtering.
*
* @param sData Game data string.
* @return True on success, false if not connected to Steam.
*/
native bool SteamWorks_SetGameData(const char[] sData); native bool SteamWorks_SetGameData(const char[] sData);
/**
* Sets the game description reported to the server browser and client queries.
*
* @param sDesc Game description string.
* @return True on success, false if not connected to Steam.
*/
native bool SteamWorks_SetGameDescription(const char[] sDesc); native bool SteamWorks_SetGameDescription(const char[] sDesc);
/**
* Sets the map name reported to the server browser and client queries.
*
* @param sMapName Map name string.
* @return True on success, false if not connected to Steam.
*/
native bool SteamWorks_SetMapName(const char[] sMapName); native bool SteamWorks_SetMapName(const char[] sMapName);
/**
* Returns whether the server is currently logged on to Steam.
*
* @return True if logged on to Steam, false otherwise.
*/
native bool SteamWorks_IsConnected(); native bool SteamWorks_IsConnected();
/**
* Adds or updates a key/value pair sent in A2S rules queries.
*
* @param sKey Rule key.
* @param sValue Rule value.
* @return True on success, false if not connected to Steam.
*/
native bool SteamWorks_SetRule(const char[] sKey, const char[] sValue); native bool SteamWorks_SetRule(const char[] sKey, const char[] sValue);
/**
* Clears the entire list of key/value pairs sent in rules queries.
*
* @return True on success, false if not connected to Steam.
*/
native bool SteamWorks_ClearRules(); native bool SteamWorks_ClearRules();
/**
* Sets whether the server should be advertised on the master server list and
* respond to server browser / LAN discovery packets. Defaults to false; set
* other server parameters before enabling advertising.
*
* @param bActive True to advertise the server, false to hide it.
* @return True on success, false if not connected to Steam.
*/
native bool SteamWorks_SetAdvertiseServerActive(bool bActive);
/**
* Deprecated no-op. Newer Steamworks SDKs removed ForceHeartbeat; server list
* heartbeats are now sent implicitly by Steam.
*
* @return Always false.
*/
#pragma deprecated This function is deprecated in the SDK and no longer does anything in this extension #pragma deprecated This function is deprecated in the SDK and no longer does anything in this extension
native bool SteamWorks_ForceHeartbeat(); native bool SteamWorks_ForceHeartbeat();
/**
* Asynchronously requests whether a client is a member of a given Steam group.
* The result is delivered through the SteamWorks_OnClientGroupStatus forward.
*
* @param client Client index.
* @param groupid 32-bit account ID of the Steam group.
* @return True if the request was sent, false if not connected to Steam.
* @error Invalid client index.
*/
native bool SteamWorks_GetUserGroupStatus(int client, int groupid); native bool SteamWorks_GetUserGroupStatus(int client, int groupid);
/**
* Asynchronously requests whether a user is a member of a given Steam group.
* The result is delivered through the SteamWorks_OnClientGroupStatus forward.
*
* @param authid 32-bit account ID of the user to query.
* @param groupid 32-bit account ID of the Steam group.
* @return True if the request was sent, false if not connected to Steam.
*/
native bool SteamWorks_GetUserGroupStatusAuthID(int authid, int groupid); native bool SteamWorks_GetUserGroupStatusAuthID(int authid, int groupid);
/**
* Returns whether a client owns/has a license for the given application.
*
* @param client Client index.
* @param app Application (AppID) to check ownership of.
* @return An EUserHasLicenseForAppResult value; k_EUserHasLicenseResultNoAuth
* if not connected to Steam.
* @error Invalid client index.
*/
native EUserHasLicenseForAppResult SteamWorks_HasLicenseForApp(int client, int app); native EUserHasLicenseForAppResult SteamWorks_HasLicenseForApp(int client, int app);
/**
* Returns whether a user owns/has a license for the given application.
*
* @param authid 32-bit account ID of the user to check.
* @param app Application (AppID) to check ownership of.
* @return An EUserHasLicenseForAppResult value; k_EUserHasLicenseResultNoAuth
* if not connected to Steam.
*/
native EUserHasLicenseForAppResult SteamWorks_HasLicenseForAppId(int authid, int app); native EUserHasLicenseForAppResult SteamWorks_HasLicenseForAppId(int authid, int app);
/**
* Retrieves a client's 64-bit Steam ID (community ID) as a string.
*
* @param client Client index.
* @param sSteamID Buffer to store the rendered 64-bit Steam ID.
* @param length Maximum length of the buffer.
* @return Number of bytes written, including the null terminator.
* @error Invalid client index.
*/
native int SteamWorks_GetClientSteamID(int client, char[] sSteamID, int length); native int SteamWorks_GetClientSteamID(int client, char[] sSteamID, int length);
/**
* Asynchronously requests the stats of a user from Steam. Stats become available
* afterwards through SteamWorks_GetStatAuthIDCell / SteamWorks_GetStatAuthIDFloat.
*
* @param authid 32-bit account ID of the user whose stats to request.
* @param appid Application (AppID) to request stats for.
* @return True if the request was sent, false if not connected to Steam.
*/
native bool SteamWorks_RequestStatsAuthID(int authid, int appid); native bool SteamWorks_RequestStatsAuthID(int authid, int appid);
/**
* Asynchronously requests the stats of a client from Steam. Stats become available
* afterwards through SteamWorks_GetStatCell / SteamWorks_GetStatFloat.
*
* @param client Client index.
* @param appid Application (AppID) to request stats for.
* @return True if the request was sent, false if not connected to Steam.
* @error Invalid client index.
*/
native bool SteamWorks_RequestStats(int client, int appid); native bool SteamWorks_RequestStats(int client, int appid);
/**
* Retrieves an integer stat for a client. The client's stats must have been
* requested first with SteamWorks_RequestStats.
*
* @param client Client index.
* @param sKey Stat name.
* @param value Variable to store the stat value in.
* @return True on success, false on failure or if not connected to Steam.
* @error Invalid client index.
*/
native bool SteamWorks_GetStatCell(int client, const char[] sKey, int &value); native bool SteamWorks_GetStatCell(int client, const char[] sKey, int &value);
/**
* Retrieves an integer stat for a user. The user's stats must have been
* requested first with SteamWorks_RequestStatsAuthID.
*
* @param authid 32-bit account ID of the user.
* @param sKey Stat name.
* @param value Variable to store the stat value in.
* @return True on success, false on failure or if not connected to Steam.
*/
native bool SteamWorks_GetStatAuthIDCell(int authid, const char[] sKey, int &value); native bool SteamWorks_GetStatAuthIDCell(int authid, const char[] sKey, int &value);
/**
* Retrieves a floating-point stat for a client. The client's stats must have been
* requested first with SteamWorks_RequestStats.
*
* @param client Client index.
* @param sKey Stat name.
* @param value Variable to store the stat value in.
* @return True on success, false on failure or if not connected to Steam.
* @error Invalid client index.
*/
native bool SteamWorks_GetStatFloat(int client, const char[] sKey, float &value); native bool SteamWorks_GetStatFloat(int client, const char[] sKey, float &value);
/**
* Retrieves a floating-point stat for a user. The user's stats must have been
* requested first with SteamWorks_RequestStatsAuthID.
*
* @param authid 32-bit account ID of the user.
* @param sKey Stat name.
* @param value Variable to store the stat value in.
* @return True on success, false on failure or if not connected to Steam.
*/
native bool SteamWorks_GetStatAuthIDFloat(int authid, const char[] sKey, float &value); native bool SteamWorks_GetStatAuthIDFloat(int authid, const char[] sKey, float &value);
/**
* Creates a new HTTP request. The URL must be absolute and start with http:// or https://.
*
* The returned handle must be freed with CloseHandle/delete once the request is finished.
*
* @param method HTTP method to use.
* @param sURL Absolute URL for the request.
* @return A handle to the new HTTP request, or INVALID_HANDLE on failure
* (including when not connected to Steam).
*/
native Handle SteamWorks_CreateHTTPRequest(EHTTPMethod method, const char[] sURL); native Handle SteamWorks_CreateHTTPRequest(EHTTPMethod method, const char[] sURL);
/**
* Sets one or two context values that will be passed back to the request's callbacks.
* These let you associate arbitrary data with a request.
*
* @param hHandle HTTP request handle.
* @param data1 First context value.
* @param data2 Second context value.
* @return True on success, false on an invalid handle or if the request was
* already sent.
*/
native bool SteamWorks_SetHTTPRequestContextValue(Handle hHandle, any data1, any data2=0); native bool SteamWorks_SetHTTPRequestContextValue(Handle hHandle, any data1, any data2=0);
/**
* Sets a network-activity timeout, in seconds, for the request. Must be called before sending.
* The default is 60 seconds. The timer resets whenever more data is received.
*
* @param hHandle HTTP request handle.
* @param timeout Timeout in seconds.
* @return True on success, false on an invalid handle or if the request was
* already sent.
*/
native bool SteamWorks_SetHTTPRequestNetworkActivityTimeout(Handle hHandle, int timeout); native bool SteamWorks_SetHTTPRequestNetworkActivityTimeout(Handle hHandle, int timeout);
/**
* Sets a request header value. Must be called before sending the request.
*
* @param hHandle HTTP request handle.
* @param sName Header name.
* @param sValue Header value.
* @return True on success, false on an invalid handle or if the request was
* already sent.
*/
native bool SteamWorks_SetHTTPRequestHeaderValue(Handle hHandle, const char[] sName, const char[] sValue); native bool SteamWorks_SetHTTPRequestHeaderValue(Handle hHandle, const char[] sName, const char[] sValue);
/**
* Sets a GET or POST parameter on the request (which is used depends on the request method).
* Must be called before sending the request.
*
* @param hHandle HTTP request handle.
* @param sName Parameter name.
* @param sValue Parameter value.
* @return True on success, false on an invalid handle or if the request was
* already sent.
*/
native bool SteamWorks_SetHTTPRequestGetOrPostParameter(Handle hHandle, const char[] sName, const char[] sValue); native bool SteamWorks_SetHTTPRequestGetOrPostParameter(Handle hHandle, const char[] sName, const char[] sValue);
/**
* Appends extra user-agent info to the request. This does not clobber the normal user
* agent; it is added to the end.
*
* @param hHandle HTTP request handle.
* @param sUserAgentInfo Extra user-agent info string.
* @return True on success, false on an invalid handle.
*/
native bool SteamWorks_SetHTTPRequestUserAgentInfo(Handle hHandle, const char[] sUserAgentInfo); native bool SteamWorks_SetHTTPRequestUserAgentInfo(Handle hHandle, const char[] sUserAgentInfo);
/**
* Enables or disables verification of SSL/TLS certificates. By default, certificates
* are verified for all HTTPS requests.
*
* @param hHandle HTTP request handle.
* @param bRequireVerifiedCertificate True to require a verified certificate, false to disable.
* @return True on success, false on an invalid handle.
*/
native bool SteamWorks_SetHTTPRequestRequiresVerifiedCertificate(Handle hHandle, bool bRequireVerifiedCertificate); native bool SteamWorks_SetHTTPRequestRequiresVerifiedCertificate(Handle hHandle, bool bRequireVerifiedCertificate);
/**
* Sets an absolute timeout, in milliseconds, on the request. Unlike the network-activity
* timeout, this is a total time limit that does not reset as data arrives.
*
* @param hHandle HTTP request handle.
* @param unMilliseconds Total timeout in milliseconds.
* @return True on success, false on an invalid handle.
*/
native bool SteamWorks_SetHTTPRequestAbsoluteTimeoutMS(Handle hHandle, int unMilliseconds); native bool SteamWorks_SetHTTPRequestAbsoluteTimeoutMS(Handle hHandle, int unMilliseconds);
/**
* Called when an HTTP request has completed (or failed). The number of trailing context
* parameters matches how many values were passed to SteamWorks_SetHTTPRequestContextValue.
*
* @param hRequest HTTP request handle.
* @param bFailure True if the request failed due to an internal or network
* error (no response from the server).
* @param bRequestSuccessful True if any response was received from the server (even an
* error response).
* @param eStatusCode HTTP status code returned by the server.
* @param data1 First context value, if one was set.
* @param data2 Second context value, if one was set.
*/
typeset SteamWorksHTTPRequestCompleted typeset SteamWorksHTTPRequestCompleted
{ {
function void (Handle hRequest, bool bFailure, bool bRequestSuccessful, EHTTPStatusCode eStatusCode); function void (Handle hRequest, bool bFailure, bool bRequestSuccessful, EHTTPStatusCode eStatusCode);
@@ -302,6 +593,16 @@ typeset SteamWorksHTTPRequestCompleted
function void (Handle hRequest, bool bFailure, bool bRequestSuccessful, EHTTPStatusCode eStatusCode, any data1, any data2); function void (Handle hRequest, bool bFailure, bool bRequestSuccessful, EHTTPStatusCode eStatusCode, any data1, any data2);
}; };
/**
* Called when the response headers for a streaming request have been received. The number
* of trailing context parameters matches the context values set on the request.
*
* @param hRequest HTTP request handle.
* @param bFailure Always false; headers-received is a success-only notification. A
* failed request is reported through SteamWorksHTTPRequestCompleted.
* @param data1 First context value, if one was set.
* @param data2 Second context value, if one was set.
*/
typeset SteamWorksHTTPHeadersReceived typeset SteamWorksHTTPHeadersReceived
{ {
function void (Handle hRequest, bool bFailure); function void (Handle hRequest, bool bFailure);
@@ -309,6 +610,19 @@ typeset SteamWorksHTTPHeadersReceived
function void (Handle hRequest, bool bFailure, any data1, any data2); function void (Handle hRequest, bool bFailure, any data1, any data2);
}; };
/**
* Called when a chunk of data for a streaming request has been received. Pass the offset
* and byte count to SteamWorks_GetHTTPStreamingResponseBodyData to read the chunk. The
* number of trailing context parameters matches the context values set on the request.
*
* @param hRequest HTTP request handle.
* @param bFailure Always false; data-received is a success-only notification. A
* failed request is reported through SteamWorksHTTPRequestCompleted.
* @param offset Offset of this chunk within the response body.
* @param bytesreceived Number of bytes in this chunk.
* @param data1 First context value, if one was set.
* @param data2 Second context value, if one was set.
*/
typeset SteamWorksHTTPDataReceived typeset SteamWorksHTTPDataReceived
{ {
function void (Handle hRequest, bool bFailure, int offset, int bytesreceived); function void (Handle hRequest, bool bFailure, int offset, int bytesreceived);
@@ -316,6 +630,15 @@ typeset SteamWorksHTTPDataReceived
function void (Handle hRequest, bool bFailure, int offset, int bytesreceived, any data1, any data2); function void (Handle hRequest, bool bFailure, int offset, int bytesreceived, any data1, any data2);
}; };
/**
* Called by SteamWorks_GetHTTPResponseBodyCallback with the response body. Use the string
* overload for text bodies or the int[] overload for binary bodies.
*
* @param sData Response body as a string (text overload).
* @param data Response body as a byte array (binary overload).
* @param value The context value passed to SteamWorks_GetHTTPResponseBodyCallback.
* @param datalen Length of the body, in bytes (binary overload).
*/
typeset SteamWorksHTTPBodyCallback typeset SteamWorksHTTPBodyCallback
{ {
function void (const char[] sData); function void (const char[] sData);
@@ -323,39 +646,541 @@ typeset SteamWorksHTTPBodyCallback
function void (const int[] data, any value, int datalen); function void (const int[] data, any value, int datalen);
}; };
/**
* Sets the callbacks fired for a request. Must be called before sending the request.
* The completion callback is used by both regular and streaming requests; the headers and
* data callbacks are only fired for streaming requests.
*
* @param hHandle HTTP request handle.
* @param fCompleted Callback fired when the request completes, or INVALID_FUNCTION.
* @param fHeaders Callback fired when streaming headers arrive, or INVALID_FUNCTION.
* @param fData Callback fired when a streaming data chunk arrives, or INVALID_FUNCTION.
* @param hCalling Handle of the plugin that owns the callbacks, or INVALID_HANDLE for
* the calling plugin.
* @return True on success, false on an invalid handle.
* @error Invalid plugin handle or invalid function.
*/
native bool SteamWorks_SetHTTPCallbacks(Handle hHandle, SteamWorksHTTPRequestCompleted fCompleted = INVALID_FUNCTION, SteamWorksHTTPHeadersReceived fHeaders = INVALID_FUNCTION, SteamWorksHTTPDataReceived fData = INVALID_FUNCTION, Handle hCalling = INVALID_HANDLE); native bool SteamWorks_SetHTTPCallbacks(Handle hHandle, SteamWorksHTTPRequestCompleted fCompleted = INVALID_FUNCTION, SteamWorksHTTPHeadersReceived fHeaders = INVALID_FUNCTION, SteamWorksHTTPDataReceived fData = INVALID_FUNCTION, Handle hCalling = INVALID_HANDLE);
/**
* Sends an HTTP request. The result is delivered asynchronously to the completion callback
* set with SteamWorks_SetHTTPCallbacks.
*
* @param hRequest HTTP request handle.
* @return True if the request was sent, false on an invalid handle.
*/
native bool SteamWorks_SendHTTPRequest(Handle hRequest); native bool SteamWorks_SendHTTPRequest(Handle hRequest);
/**
* Sends an HTTP request and streams the response. Headers and data are delivered
* asynchronously to the callbacks set with SteamWorks_SetHTTPCallbacks.
*
* @param hRequest HTTP request handle.
* @return True if the request was sent, false on an invalid handle.
*/
native bool SteamWorks_SendHTTPRequestAndStreamResponse(Handle hRequest); native bool SteamWorks_SendHTTPRequestAndStreamResponse(Handle hRequest);
/**
* Moves an already-sent request to the tail of the client's request queue.
*
* @param hRequest HTTP request handle.
* @return True on success, false on an invalid handle or if the request has
* not been sent.
*/
native bool SteamWorks_DeferHTTPRequest(Handle hRequest); native bool SteamWorks_DeferHTTPRequest(Handle hRequest);
/**
* Moves an already-sent request to the head of the client's request queue.
*
* @param hRequest HTTP request handle.
* @return True on success, false on an invalid handle or if the request has
* not been sent.
*/
native bool SteamWorks_PrioritizeHTTPRequest(Handle hRequest); native bool SteamWorks_PrioritizeHTTPRequest(Handle hRequest);
/**
* Checks whether a response header is present and retrieves the size of its value, so a
* correctly-sized buffer can be allocated for SteamWorks_GetHTTPResponseHeaderValue.
* Call from the completion callback.
*
* @param hRequest HTTP request handle.
* @param sHeader Header name.
* @param size Variable to store the header value size in.
* @return True if the header is present, false otherwise.
*/
native bool SteamWorks_GetHTTPResponseHeaderSize(Handle hRequest, const char[] sHeader, int &size); native bool SteamWorks_GetHTTPResponseHeaderSize(Handle hRequest, const char[] sHeader, int &size);
/**
* Retrieves a response header value. Call from the completion callback. Use
* SteamWorks_GetHTTPResponseHeaderSize first to size the buffer.
*
* @param hRequest HTTP request handle.
* @param sHeader Header name.
* @param sValue Buffer to store the header value in.
* @param size Maximum length of the buffer.
* @return True on success, false if the header is not present or the buffer
* is too small.
*/
native bool SteamWorks_GetHTTPResponseHeaderValue(Handle hRequest, const char[] sHeader, char[] sValue, int size); native bool SteamWorks_GetHTTPResponseHeaderValue(Handle hRequest, const char[] sHeader, char[] sValue, int size);
/**
* Retrieves the size of the response body. Call from the completion callback.
*
* @param hRequest HTTP request handle.
* @param size Variable to store the body size in.
* @return True on success, false on an invalid handle.
*/
native bool SteamWorks_GetHTTPResponseBodySize(Handle hRequest, int &size); native bool SteamWorks_GetHTTPResponseBodySize(Handle hRequest, int &size);
/**
* Retrieves the response body. Call from the completion callback. Use
* SteamWorks_GetHTTPResponseBodySize first to size the buffer. Not valid for streaming
* responses.
*
* @param hRequest HTTP request handle.
* @param sBody Buffer to store the body in.
* @param length Length of the buffer, which must match the body size.
* @return True on success, false on an invalid handle, a streaming response,
* or an incorrectly-sized buffer.
*/
native bool SteamWorks_GetHTTPResponseBodyData(Handle hRequest, char[] sBody, int length); native bool SteamWorks_GetHTTPResponseBodyData(Handle hRequest, char[] sBody, int length);
/**
* Retrieves a chunk of a streaming response body. Call from the data-received callback,
* passing the offset and length reported by that callback.
*
* @param hRequest HTTP request handle.
* @param cOffset Offset of the chunk, as provided by the data-received callback.
* @param sBody Buffer to store the chunk in.
* @param length Length of the chunk, as provided by the data-received callback.
* @return True on success, false on an invalid handle, a non-streaming
* response, or a mismatched offset/length.
*/
native bool SteamWorks_GetHTTPStreamingResponseBodyData(Handle hRequest, int cOffset, char[] sBody, int length); native bool SteamWorks_GetHTTPStreamingResponseBodyData(Handle hRequest, int cOffset, char[] sBody, int length);
/**
* Retrieves download progress for the request. This is zero until a response header with a
* content-length has been received; for responses with no content-length it stays zero.
*
* @param hRequest HTTP request handle.
* @param percent Variable to store the progress percentage in.
* @return True on success, false on an invalid handle.
*/
native bool SteamWorks_GetHTTPDownloadProgressPct(Handle hRequest, float &percent); native bool SteamWorks_GetHTTPDownloadProgressPct(Handle hRequest, float &percent);
/**
* Checks whether the request failed because it timed out (rather than a harder failure).
*
* @param hRequest HTTP request handle.
* @param bWasTimedOut Variable to store the result in.
* @return True on success, false on an invalid handle.
*/
native bool SteamWorks_GetHTTPRequestWasTimedOut(Handle hRequest, bool &bWasTimedOut); native bool SteamWorks_GetHTTPRequestWasTimedOut(Handle hRequest, bool &bWasTimedOut);
/**
* Sets a raw body for a POST request. Fails on a GET request or if GET/POST parameters
* were already set. This makes the raw body the entire contents of the POST.
*
* @param hRequest HTTP request handle.
* @param sContentType Value for the Content-Type header.
* @param sBody Raw body data.
* @param bodylen Length of the body, in bytes.
* @return True on success, false on failure.
*/
native bool SteamWorks_SetHTTPRequestRawPostBody(Handle hRequest, const char[] sContentType, const char[] sBody, int bodylen); native bool SteamWorks_SetHTTPRequestRawPostBody(Handle hRequest, const char[] sContentType, const char[] sBody, int bodylen);
/**
* Sets a raw POST body read from a file (relative to the game directory). Same constraints
* as SteamWorks_SetHTTPRequestRawPostBody.
*
* @param hRequest HTTP request handle.
* @param sContentType Value for the Content-Type header.
* @param sFileName Path to the file, relative to the game directory.
* @return True on success, false on failure (e.g. an empty file).
* @error Unable to open the file for reading.
*/
native bool SteamWorks_SetHTTPRequestRawPostBodyFromFile(Handle hRequest, const char[] sContentType, const char[] sFileName); native bool SteamWorks_SetHTTPRequestRawPostBodyFromFile(Handle hRequest, const char[] sContentType, const char[] sFileName);
/**
* Retrieves the full response body and passes it to a callback. Useful for bodies larger
* than a single fixed buffer. Call from the completion callback.
*
* @param hRequest HTTP request handle.
* @param fCallback Callback that receives the body.
* @param data Context value passed through to the callback.
* @param hPlugin Handle of the plugin that owns the callback, or INVALID_HANDLE for
* the calling plugin.
* @return True on success, false on an invalid handle or if the body could not
* be retrieved.
* @error Invalid plugin handle or invalid function.
*/
native bool SteamWorks_GetHTTPResponseBodyCallback(Handle hRequest, SteamWorksHTTPBodyCallback fCallback, any data = 0, Handle hPlugin = INVALID_HANDLE); native bool SteamWorks_GetHTTPResponseBodyCallback(Handle hRequest, SteamWorksHTTPBodyCallback fCallback, any data = 0, Handle hPlugin = INVALID_HANDLE);
/**
* Writes the full response body to a file (relative to the game directory). Call from the
* completion callback.
*
* @param hRequest HTTP request handle.
* @param sFileName Path to the output file, relative to the game directory.
* @return True on success, false on an invalid handle or if the body could not
* be retrieved.
* @error Unable to open the file for writing.
*/
native bool SteamWorks_WriteHTTPResponseBodyToFile(Handle hRequest, const char[] sFileName); native bool SteamWorks_WriteHTTPResponseBodyToFile(Handle hRequest, const char[] sFileName);
methodmap SteamWorksHTTPRequest < Handle
{
/**
* Creates a new HTTP request.
*
* @param method HTTP method to use.
* @param sURL Absolute URL for the request.
* @return A new request handle, or INVALID_HANDLE on failure (including when
* not connected to Steam).
*/
public native SteamWorksHTTPRequest(EHTTPMethod method, const char[] sURL);
/**
* Sets one or two context values that will be passed back to the request's callbacks.
* These let you associate arbitrary data with a request.
*
* @param data1 First context value.
* @param data2 Second context value.
* @return True on success, false on an invalid handle or if the request was
* already sent.
*/
public native bool SetContextValue(any data1, any data2 = 0);
/**
* Sets a network-activity timeout, in seconds, for the request. Must be called before
* sending. The default is 60 seconds. The timer resets whenever more data is received.
*
* @param timeout Timeout in seconds.
* @return True on success, false on an invalid handle or if the request was
* already sent.
*/
public native bool SetNetworkActivityTimeout(int timeout);
/**
* Sets a request header value. Must be called before sending the request.
*
* @param sName Header name.
* @param sValue Header value.
* @return True on success, false on an invalid handle or if the request was
* already sent.
*/
public native bool SetHeaderValue(const char[] sName, const char[] sValue);
/**
* Sets a GET or POST parameter on the request (which is used depends on the request
* method). Must be called before sending the request.
*
* @param sName Parameter name.
* @param sValue Parameter value.
* @return True on success, false on an invalid handle or if the request was
* already sent.
*/
public native bool SetGetOrPostParameter(const char[] sName, const char[] sValue);
/**
* Appends extra user-agent info to the request. This does not clobber the normal user
* agent; it is added to the end.
*
* @param sUserAgentInfo Extra user-agent info string.
* @return True on success, false on an invalid handle.
*/
public native bool SetUserAgentInfo(const char[] sUserAgentInfo);
/**
* Enables or disables verification of SSL/TLS certificates. By default, certificates
* are verified for all HTTPS requests.
*
* @param bRequireVerifiedCertificate True to require a verified certificate, false to disable.
* @return True on success, false on an invalid handle.
*/
public native bool SetRequiresVerifiedCertificate(bool bRequireVerifiedCertificate);
/**
* Sets an absolute timeout, in milliseconds, on the request. Unlike the network-activity
* timeout, this is a total time limit that does not reset as data arrives.
*
* @param unMilliseconds Total timeout in milliseconds.
* @return True on success, false on an invalid handle.
*/
public native bool SetAbsoluteTimeoutMS(int unMilliseconds);
/**
* Sets the callbacks fired for a request. Must be called before sending the request.
* The completion callback is used by both regular and streaming requests; the headers
* and data callbacks are only fired for streaming requests.
*
* @param fCompleted Callback fired when the request completes, or INVALID_FUNCTION.
* @param fHeaders Callback fired when streaming headers arrive, or INVALID_FUNCTION.
* @param fData Callback fired when a streaming data chunk arrives, or INVALID_FUNCTION.
* @param hCalling Handle of the plugin that owns the callbacks, or INVALID_HANDLE for
* the calling plugin.
* @return True on success, false on an invalid handle.
* @error Invalid plugin handle or invalid function.
*/
public native bool SetCallbacks(SteamWorksHTTPRequestCompleted fCompleted = INVALID_FUNCTION, SteamWorksHTTPHeadersReceived fHeaders = INVALID_FUNCTION, SteamWorksHTTPDataReceived fData = INVALID_FUNCTION, Handle hCalling = INVALID_HANDLE);
/**
* Sends an HTTP request. The result is delivered asynchronously to the completion
* callback set with SetCallbacks.
*
* @return True if the request was sent, false on an invalid handle.
*/
public native bool Send();
/**
* Sends an HTTP request and streams the response. Headers and data are delivered
* asynchronously to the callbacks set with SetCallbacks.
*
* @return True if the request was sent, false on an invalid handle.
*/
public native bool SendAndStreamResponse();
/**
* Moves an already-sent request to the tail of the client's request queue.
*
* @return True on success, false on an invalid handle or if the request has
* not been sent.
*/
public native bool Defer();
/**
* Moves an already-sent request to the head of the client's request queue.
*
* @return True on success, false on an invalid handle or if the request has
* not been sent.
*/
public native bool Prioritize();
/**
* Checks whether a response header is present and retrieves the size of its value, so a
* correctly-sized buffer can be allocated for GetResponseHeaderValue. Call from the
* completion callback.
*
* @param sHeader Header name.
* @param size Variable to store the header value size in.
* @return True if the header is present, false otherwise.
*/
public native bool GetResponseHeaderSize(const char[] sHeader, int &size);
/**
* Retrieves a response header value. Call from the completion callback. Use
* GetResponseHeaderSize first to size the buffer.
*
* @param sHeader Header name.
* @param sValue Buffer to store the header value in.
* @param size Maximum length of the buffer.
* @return True on success, false if the header is not present or the buffer
* is too small.
*/
public native bool GetResponseHeaderValue(const char[] sHeader, char[] sValue, int size);
/**
* Retrieves the size of the response body. Call from the completion callback.
*
* @param size Variable to store the body size in.
* @return True on success, false on an invalid handle.
*/
public native bool GetResponseBodySize(int &size);
/**
* Retrieves the response body. Call from the completion callback. Use GetResponseBodySize
* first to size the buffer. Not valid for streaming responses.
*
* @param sBody Buffer to store the body in.
* @param length Length of the buffer, which must match the body size.
* @return True on success, false on an invalid handle, a streaming response,
* or an incorrectly-sized buffer.
*/
public native bool GetResponseBodyData(char[] sBody, int length);
/**
* Retrieves a chunk of a streaming response body. Call from the data-received callback,
* passing the offset and length reported by that callback.
*
* @param cOffset Offset of the chunk, as provided by the data-received callback.
* @param sBody Buffer to store the chunk in.
* @param length Length of the chunk, as provided by the data-received callback.
* @return True on success, false on an invalid handle, a non-streaming
* response, or a mismatched offset/length.
*/
public native bool GetStreamingResponseBodyData(int cOffset, char[] sBody, int length);
/**
* Retrieves download progress for the request. This is zero until a response header with
* a content-length has been received; for responses with no content-length it stays zero.
*
* @param percent Variable to store the progress percentage in.
* @return True on success, false on an invalid handle.
*/
public native bool GetDownloadProgressPct(float &percent);
/**
* Checks whether the request failed because it timed out (rather than a harder failure).
*
* @param bWasTimedOut Variable to store the result in.
* @return True on success, false on an invalid handle.
*/
public native bool GetWasTimedOut(bool &bWasTimedOut);
/**
* Sets a raw body for a POST request. Fails on a GET request or if GET/POST parameters
* were already set. This makes the raw body the entire contents of the POST.
*
* @param sContentType Value for the Content-Type header.
* @param sBody Raw body data.
* @param bodylen Length of the body, in bytes.
* @return True on success, false on failure.
*/
public native bool SetRawPostBody(const char[] sContentType, const char[] sBody, int bodylen);
/**
* Sets a raw POST body read from a file (relative to the game directory). Same constraints
* as SetRawPostBody.
*
* @param sContentType Value for the Content-Type header.
* @param sFileName Path to the file, relative to the game directory.
* @return True on success, false on failure (e.g. an empty file).
* @error Unable to open the file for reading.
*/
public native bool SetRawPostBodyFromFile(const char[] sContentType, const char[] sFileName);
/**
* Retrieves the full response body and passes it to a callback. Useful for bodies larger
* than a single fixed buffer. Call from the completion callback.
*
* @param fCallback Callback that receives the body.
* @param data Context value passed through to the callback.
* @param hPlugin Handle of the plugin that owns the callback, or INVALID_HANDLE for
* the calling plugin.
* @return True on success, false on an invalid handle or if the body could not
* be retrieved.
* @error Invalid plugin handle or invalid function.
*/
public native bool GetResponseBodyCallback(SteamWorksHTTPBodyCallback fCallback, any data = 0, Handle hPlugin = INVALID_HANDLE);
/**
* Writes the full response body to a file (relative to the game directory). Call from the
* completion callback.
*
* @param sFileName Path to the output file, relative to the game directory.
* @return True on success, false on an invalid handle or if the body could not
* be retrieved.
* @error Unable to open the file for writing.
*/
public native bool WriteResponseBodyToFile(const char[] sFileName);
};
/**
* Deprecated alias for SteamWorks_OnValidateClient, kept for backwards compatibility.
* Use SteamWorks_OnValidateClient in new code.
*
* @param ownerauthid 32-bit account ID of the account that owns the game license.
* @param authid 32-bit account ID of the validated client.
*/
forward void SW_OnValidateClient(int ownerauthid, int authid); forward void SW_OnValidateClient(int ownerauthid, int authid);
/**
* Called when a client has been validated by Steam. For clients playing on a borrowed
* (Family Sharing) license, the owner and client account IDs differ.
*
* @param ownerauthid 32-bit account ID of the account that owns the game license.
* @param authid 32-bit account ID of the validated client.
*/
forward void SteamWorks_OnValidateClient(int ownerauthid, int authid); forward void SteamWorks_OnValidateClient(int ownerauthid, int authid);
/**
* Called when the server successfully connects (logs on) to Steam.
*/
forward void SteamWorks_SteamServersConnected(); forward void SteamWorks_SteamServersConnected();
/**
* Called when the server fails to connect to Steam.
*
* @param result Result code describing the failure.
*/
forward void SteamWorks_SteamServersConnectFailure(EResult result); forward void SteamWorks_SteamServersConnectFailure(EResult result);
/**
* Called when the server is disconnected from Steam.
*
* @param result Result code describing the disconnection.
*/
forward void SteamWorks_SteamServersDisconnected(EResult result); forward void SteamWorks_SteamServersDisconnected(EResult result);
/**
* Called when the Steam master server has requested that the server restart. Return
* Plugin_Handled or higher to indicate the restart request has been handled.
*
* @return Plugin_Handled or higher to signal the restart was handled,
* Plugin_Continue otherwise.
*/
forward Action SteamWorks_RestartRequested(); forward Action SteamWorks_RestartRequested();
/**
* Called when the server is about to log on anonymously, giving a plugin the chance to
* supply a Game Server Login Token (GSLT) instead. Write the token into sToken.
*
* @param sToken Buffer to write the login token into.
* @param maxlen Maximum length of the buffer.
*/
forward void SteamWorks_TokenRequested(char[] sToken, int maxlen); forward void SteamWorks_TokenRequested(char[] sToken, int maxlen);
/**
* Called with the result of a SteamWorks_GetUserGroupStatus /
* SteamWorks_GetUserGroupStatusAuthID request.
*
* @param authid 32-bit account ID of the user.
* @param groupid 32-bit account ID of the group.
* @param isMember True if the user is a member of the group.
* @param isOfficer True if the user is an officer of the group.
*/
forward void SteamWorks_OnClientGroupStatus(int authid, int groupid, bool isMember, bool isOfficer); forward void SteamWorks_OnClientGroupStatus(int authid, int groupid, bool isMember, bool isOfficer);
/**
* Called when the game code sends a message to the Game Coordinator, letting a plugin
* observe or override it. Return a non-OK EGCResults value to supersede the send, or
* k_EGCResultOK to let it proceed.
*
* @param unMsgType Message type.
* @param pubData Message payload.
* @param cubData Size of the payload, in bytes.
* @return An EGCResults value to override the send, or k_EGCResultOK to allow it.
*/
forward EGCResults SteamWorks_GCSendMessage(int unMsgType, const char[] pubData, int cubData); forward EGCResults SteamWorks_GCSendMessage(int unMsgType, const char[] pubData, int cubData);
/**
* Called when a message from the Game Coordinator is available to be retrieved.
*
* @param cubData Size of the available message, in bytes.
*/
forward void SteamWorks_GCMsgAvailable(int cubData); forward void SteamWorks_GCMsgAvailable(int cubData);
/**
* Called when the game code retrieves a message from the Game Coordinator, letting a plugin
* observe or override it. Return a non-OK EGCResults value to supersede the retrieval.
*
* @param punMsgType Message type.
* @param pubDest Message payload.
* @param cubDest Size of the destination buffer, in bytes.
* @param pcubMsgSize Size of the message, in bytes.
* @return An EGCResults value to override the retrieval, or k_EGCResultOK to
* allow it.
*/
forward EGCResults SteamWorks_GCRetrieveMessage(int punMsgType, const char[] pubDest, int cubDest, int pcubMsgSize); forward EGCResults SteamWorks_GCRetrieveMessage(int punMsgType, const char[] pubDest, int cubDest, int pcubMsgSize);
/**
* Sends a message to the Game Coordinator.
*
* @param unMsgType Message type.
* @param pubData Message payload.
* @param cubData Size of the payload, in bytes.
* @return An EGCResults value; k_EGCResultNotLoggedOn if not connected to Steam.
*/
native EGCResults SteamWorks_SendMessageToGC(int unMsgType, const char[] pubData, int cubData); native EGCResults SteamWorks_SendMessageToGC(int unMsgType, const char[] pubData, int cubData);
public Extension __ext_SteamWorks = public Extension __ext_SteamWorks =
@@ -386,6 +1211,7 @@ public void __ext_SteamWorks_SetNTVOptional()
MarkNativeAsOptional("SteamWorks_IsConnected"); MarkNativeAsOptional("SteamWorks_IsConnected");
MarkNativeAsOptional("SteamWorks_SetRule"); MarkNativeAsOptional("SteamWorks_SetRule");
MarkNativeAsOptional("SteamWorks_ClearRules"); MarkNativeAsOptional("SteamWorks_ClearRules");
MarkNativeAsOptional("SteamWorks_SetAdvertiseServerActive");
MarkNativeAsOptional("SteamWorks_ForceHeartbeat"); MarkNativeAsOptional("SteamWorks_ForceHeartbeat");
MarkNativeAsOptional("SteamWorks_GetUserGroupStatus"); MarkNativeAsOptional("SteamWorks_GetUserGroupStatus");
MarkNativeAsOptional("SteamWorks_GetUserGroupStatusAuthID"); MarkNativeAsOptional("SteamWorks_GetUserGroupStatusAuthID");
@@ -425,5 +1251,30 @@ public void __ext_SteamWorks_SetNTVOptional()
MarkNativeAsOptional("SteamWorks_GetHTTPResponseBodyCallback"); MarkNativeAsOptional("SteamWorks_GetHTTPResponseBodyCallback");
MarkNativeAsOptional("SteamWorks_WriteHTTPResponseBodyToFile"); MarkNativeAsOptional("SteamWorks_WriteHTTPResponseBodyToFile");
MarkNativeAsOptional("SteamWorksHTTPRequest.SteamWorksHTTPRequest");
MarkNativeAsOptional("SteamWorksHTTPRequest.SetContextValue");
MarkNativeAsOptional("SteamWorksHTTPRequest.SetNetworkActivityTimeout");
MarkNativeAsOptional("SteamWorksHTTPRequest.SetHeaderValue");
MarkNativeAsOptional("SteamWorksHTTPRequest.SetGetOrPostParameter");
MarkNativeAsOptional("SteamWorksHTTPRequest.SetUserAgentInfo");
MarkNativeAsOptional("SteamWorksHTTPRequest.SetRequiresVerifiedCertificate");
MarkNativeAsOptional("SteamWorksHTTPRequest.SetAbsoluteTimeoutMS");
MarkNativeAsOptional("SteamWorksHTTPRequest.SetCallbacks");
MarkNativeAsOptional("SteamWorksHTTPRequest.Send");
MarkNativeAsOptional("SteamWorksHTTPRequest.SendAndStreamResponse");
MarkNativeAsOptional("SteamWorksHTTPRequest.Defer");
MarkNativeAsOptional("SteamWorksHTTPRequest.Prioritize");
MarkNativeAsOptional("SteamWorksHTTPRequest.GetResponseHeaderSize");
MarkNativeAsOptional("SteamWorksHTTPRequest.GetResponseHeaderValue");
MarkNativeAsOptional("SteamWorksHTTPRequest.GetResponseBodySize");
MarkNativeAsOptional("SteamWorksHTTPRequest.GetResponseBodyData");
MarkNativeAsOptional("SteamWorksHTTPRequest.GetStreamingResponseBodyData");
MarkNativeAsOptional("SteamWorksHTTPRequest.GetDownloadProgressPct");
MarkNativeAsOptional("SteamWorksHTTPRequest.GetWasTimedOut");
MarkNativeAsOptional("SteamWorksHTTPRequest.SetRawPostBody");
MarkNativeAsOptional("SteamWorksHTTPRequest.SetRawPostBodyFromFile");
MarkNativeAsOptional("SteamWorksHTTPRequest.GetResponseBodyCallback");
MarkNativeAsOptional("SteamWorksHTTPRequest.WriteResponseBodyToFile");
} }
#endif #endif