forked from UNLOZE/sm-plugins
add SMJSONAPI
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
public void API_PrintToChatAll(const char[] format, any ...)
|
||||
{
|
||||
char buffer[254];
|
||||
|
||||
for (int i = 1; i <= MaxClients; i++)
|
||||
{
|
||||
if (IsClientInGame(i))
|
||||
{
|
||||
SetGlobalTransTarget(i);
|
||||
VFormat(buffer, sizeof(buffer), format, 2);
|
||||
PrintToChat(i, "%s", buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void API_PrintCenterTextAll(const char[] format, any ...)
|
||||
{
|
||||
char buffer[254];
|
||||
|
||||
for (int i = 1; i <= MaxClients; i++)
|
||||
{
|
||||
if (IsClientInGame(i))
|
||||
{
|
||||
SetGlobalTransTarget(i);
|
||||
VFormat(buffer, sizeof(buffer), format, 2);
|
||||
PrintCenterText(i, "%s", buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void API_PrintHintTextToAll(const char[] format, any ...)
|
||||
{
|
||||
char buffer[254];
|
||||
|
||||
for (int i = 1; i <= MaxClients; i++)
|
||||
{
|
||||
if (IsClientInGame(i))
|
||||
{
|
||||
SetGlobalTransTarget(i);
|
||||
VFormat(buffer, sizeof(buffer), format, 2);
|
||||
PrintHintText(i, "%s", buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int API_GetMaxClients()
|
||||
{
|
||||
return MaxClients;
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
static KeyValues g_Config;
|
||||
|
||||
bool GameEvents_Init()
|
||||
{
|
||||
char sGame[32];
|
||||
GetGameFolderName(sGame, sizeof(sGame));
|
||||
|
||||
char sConfigFile[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, sConfigFile, sizeof(sConfigFile), "configs/Events.%s.cfg", sGame);
|
||||
if(!FileExists(sConfigFile))
|
||||
{
|
||||
SetFailState("Could not find config: \"%s\"", sConfigFile);
|
||||
}
|
||||
|
||||
g_Config = new KeyValues("allevents");
|
||||
if(!g_Config.ImportFromFile(sConfigFile))
|
||||
{
|
||||
delete g_Config;
|
||||
SetFailState("ImportFromFile() failed!");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void GameEvents_OnHook(Event event, const char[] name, bool dontBroadcast)
|
||||
{
|
||||
static char sEventName[32];
|
||||
event.GetName(sEventName, sizeof(sEventName));
|
||||
|
||||
g_Config.JumpToKey(sEventName);
|
||||
|
||||
JSONObject jEvent = new JSONObject();
|
||||
jEvent.SetString("name", sEventName);
|
||||
|
||||
JSONObject jEventData = new JSONObject();
|
||||
|
||||
if(g_Config.GotoFirstSubKey(false))
|
||||
{
|
||||
do
|
||||
{
|
||||
static char sKey[32];
|
||||
static char sType[8];
|
||||
|
||||
g_Config.GetSectionName(sKey, sizeof(sKey));
|
||||
g_Config.GetString(NULL_STRING, sType, sizeof(sType));
|
||||
|
||||
if(StrEqual(sKey, "_hooked"))
|
||||
continue;
|
||||
|
||||
if(StrEqual(sType, "short") || StrEqual(sType, "long") || StrEqual(sType, "byte"))
|
||||
{
|
||||
int iValue = event.GetInt(sKey);
|
||||
jEventData.SetInt(sKey, iValue);
|
||||
}
|
||||
else if(StrEqual(sType, "float"))
|
||||
{
|
||||
float fValue = event.GetFloat(sKey);
|
||||
jEventData.SetFloat(sKey, fValue);
|
||||
}
|
||||
else if(StrEqual(sType, "bool"))
|
||||
{
|
||||
bool bValue = event.GetBool(sKey);
|
||||
jEventData.SetBool(sKey, bValue);
|
||||
}
|
||||
else if(StrEqual(sType, "string"))
|
||||
{
|
||||
static char sValue[1024];
|
||||
event.GetString(sKey, sValue, sizeof(sValue));
|
||||
jEventData.SetString(sKey, sValue);
|
||||
}
|
||||
} while(g_Config.GotoNextKey(false));
|
||||
g_Config.Rewind();
|
||||
}
|
||||
|
||||
jEvent.Set("data", jEventData);
|
||||
|
||||
Subscribe_GameEvents_Publish(sEventName, jEvent);
|
||||
}
|
||||
|
||||
int GameEvents_Hook(const char[] sEventName)
|
||||
{
|
||||
if(!g_Config.JumpToKey(sEventName))
|
||||
return -1;
|
||||
|
||||
int Hooked = g_Config.GetNum("_hooked", 0);
|
||||
if(Hooked)
|
||||
{
|
||||
g_Config.SetNum("_hooked", Hooked + 1);
|
||||
return Hooked + 1;
|
||||
}
|
||||
|
||||
Hooked = HookEventEx(sEventName, GameEvents_OnHook, EventHookMode_Post);
|
||||
if(Hooked)
|
||||
g_Config.SetNum("_hooked", 1);
|
||||
|
||||
g_Config.Rewind();
|
||||
return Hooked ? 1 : -1;
|
||||
}
|
||||
|
||||
int GameEvents_Unhook(const char[] sEventName)
|
||||
{
|
||||
if(!g_Config.JumpToKey(sEventName))
|
||||
return -1;
|
||||
|
||||
int Hooked = g_Config.GetNum("_hooked", 0);
|
||||
if(!Hooked)
|
||||
return 0;
|
||||
|
||||
if(Hooked == 1)
|
||||
UnhookEvent(sEventName, GameEvents_OnHook, EventHookMode_Post);
|
||||
|
||||
g_Config.SetNum("_hooked", Hooked - 1);
|
||||
|
||||
g_Config.Rewind();
|
||||
return Hooked - 1;
|
||||
}
|
||||
|
||||
stock void GameEvents_HookAll()
|
||||
{
|
||||
g_Config.GotoFirstSubKey(false);
|
||||
|
||||
do
|
||||
{
|
||||
static char sKey[32];
|
||||
g_Config.GetSectionName(sKey, sizeof(sKey));
|
||||
|
||||
int Hooked = g_Config.GetNum("_hooked", 0);
|
||||
if(!Hooked)
|
||||
{
|
||||
if(HookEventEx(sKey, GameEvents_OnHook, EventHookMode_Post))
|
||||
g_Config.SetNum("_hooked", 1);
|
||||
}
|
||||
else
|
||||
g_Config.SetNum("_hooked", Hooked + 1);
|
||||
} while(g_Config.GotoNextKey(true));
|
||||
|
||||
g_Config.Rewind();
|
||||
}
|
||||
|
||||
stock void GameEvents_UnhookAll()
|
||||
{
|
||||
g_Config.GotoFirstSubKey(false);
|
||||
|
||||
do
|
||||
{
|
||||
static char sKey[32];
|
||||
g_Config.GetSectionName(sKey, sizeof(sKey));
|
||||
|
||||
int Hooked = g_Config.GetNum("_hooked", 0);
|
||||
if(Hooked)
|
||||
{
|
||||
UnhookEvent(sKey, GameEvents_OnHook, EventHookMode_Post);
|
||||
g_Config.SetNum("_hooked", 0);
|
||||
}
|
||||
} while(g_Config.GotoNextKey(true));
|
||||
|
||||
g_Config.Rewind();
|
||||
}
|
||||
@@ -0,0 +1,472 @@
|
||||
#pragma semicolon 1
|
||||
#pragma newdecls required
|
||||
#pragma dynamic 65535
|
||||
|
||||
#include <sourcemod>
|
||||
#include <AsyncSocket>
|
||||
#include <smjansson>
|
||||
|
||||
#define MAX_CLIENTS 16
|
||||
|
||||
#include "API.inc"
|
||||
#include "Subscribe.inc"
|
||||
|
||||
static AsyncSocket g_ServerSocket;
|
||||
|
||||
static AsyncSocket g_Client_Socket[MAX_CLIENTS] = { null, ... };
|
||||
static int g_Client_Subscriber[MAX_CLIENTS] = { -1, ... };
|
||||
|
||||
ConVar g_ListenAddr;
|
||||
ConVar g_ListenPort;
|
||||
|
||||
public Plugin myinfo =
|
||||
{
|
||||
name = "SM JSON API",
|
||||
author = "SourceMod TCP JSON API",
|
||||
description = "",
|
||||
version = "1.0",
|
||||
url = ""
|
||||
}
|
||||
|
||||
public void OnPluginStart()
|
||||
{
|
||||
Subscribe_OnPluginStart();
|
||||
|
||||
g_ListenAddr = CreateConVar("sm_jsonapi_addr", "127.0.0.1", "SM JSON API listen ip address", FCVAR_PROTECTED);
|
||||
g_ListenPort = CreateConVar("sm_jsonapi_port", "27021", "SM JSON API listen ip address", FCVAR_PROTECTED, true, 1025.0, true, 65535.0);
|
||||
|
||||
AutoExecConfig(true, "plugin.SMJSONAPI");
|
||||
}
|
||||
|
||||
public void OnConfigsExecuted()
|
||||
{
|
||||
if(g_ServerSocket)
|
||||
return;
|
||||
|
||||
g_ServerSocket = new AsyncSocket();
|
||||
|
||||
g_ServerSocket.SetConnectCallback(OnAsyncConnect);
|
||||
g_ServerSocket.SetErrorCallback(OnAsyncServerError);
|
||||
|
||||
char sAddr[32];
|
||||
g_ListenAddr.GetString(sAddr, sizeof(sAddr));
|
||||
int Port = g_ListenPort.IntValue;
|
||||
|
||||
g_ServerSocket.Listen(sAddr, Port);
|
||||
LogMessage("Listening on %s:%d", sAddr, Port);
|
||||
}
|
||||
|
||||
static void OnAsyncConnect(AsyncSocket socket)
|
||||
{
|
||||
int Client = GetFreeClientIndex();
|
||||
LogMessage("OnAsyncConnect(Client=%d)", Client);
|
||||
|
||||
if(Client == -1)
|
||||
{
|
||||
delete socket;
|
||||
return;
|
||||
}
|
||||
|
||||
g_Client_Socket[Client] = socket;
|
||||
socket.SetErrorCallback(OnAsyncClientError);
|
||||
socket.SetDataCallback(OnAsyncData);
|
||||
}
|
||||
|
||||
static void OnAsyncServerError(AsyncSocket socket, int error, const char[] errorName)
|
||||
{
|
||||
SetFailState("OnAsyncServerError(): %d, \"%s\"", error, errorName);
|
||||
}
|
||||
|
||||
static void OnAsyncClientError(AsyncSocket socket, int error, const char[] errorName)
|
||||
{
|
||||
int Client = ClientFromSocket(socket);
|
||||
LogMessage("OnAsyncClientError(Client=%d): %d, \"%s\"", Client, error, errorName);
|
||||
|
||||
if(Client == -1)
|
||||
{
|
||||
delete socket;
|
||||
return;
|
||||
}
|
||||
|
||||
if(g_Client_Subscriber[Client] != -1)
|
||||
{
|
||||
Subscriber_Destroy(g_Client_Subscriber[Client]);
|
||||
g_Client_Subscriber[Client] = -1;
|
||||
}
|
||||
|
||||
g_Client_Socket[Client] = null;
|
||||
delete socket;
|
||||
}
|
||||
|
||||
static void OnAsyncData(AsyncSocket socket, const char[] data, const int size)
|
||||
{
|
||||
int Client = ClientFromSocket(socket);
|
||||
|
||||
int iLine;
|
||||
int iColumn;
|
||||
static char sError[256];
|
||||
JSONValue jRequest = json_load_ex(data, sError, sizeof(sError), iLine, iColumn);
|
||||
|
||||
if(jRequest == null)
|
||||
{
|
||||
JSONObject jResponse = new JSONObject();
|
||||
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("type", "json");
|
||||
jError.SetString("error", sError);
|
||||
jError.SetInt("line", iLine);
|
||||
jError.SetInt("column", iColumn);
|
||||
|
||||
jResponse.Set("error", jError);
|
||||
|
||||
jResponse.ToString(sError, sizeof(sError));
|
||||
socket.WriteNull(sError);
|
||||
|
||||
delete jResponse;
|
||||
return;
|
||||
}
|
||||
|
||||
if(jRequest.IsObject)
|
||||
{
|
||||
//view_as<JSONObject>(jRequest).DumpToServer();
|
||||
JSONObject jResponse = new JSONObject();
|
||||
// Negative values and objects indicate errors
|
||||
// 0 and positive integers indicate success
|
||||
jResponse.SetInt("error", 0);
|
||||
|
||||
HandleRequest(Client, view_as<JSONObject>(jRequest), jResponse);
|
||||
|
||||
static char sResponse[4096];
|
||||
jResponse.ToString(sResponse, sizeof(sResponse));
|
||||
socket.WriteNull(sResponse);
|
||||
delete jResponse;
|
||||
}
|
||||
|
||||
delete jRequest;
|
||||
}
|
||||
|
||||
static int HandleRequest(int Client, JSONObject jRequest, JSONObject jResponse)
|
||||
{
|
||||
static char sMethod[32];
|
||||
if(jRequest.GetString("method", sMethod, sizeof(sMethod)) < 0)
|
||||
{
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", "Request has no 'method' string-value.");
|
||||
jResponse.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
jResponse.SetString("method", sMethod);
|
||||
|
||||
if(StrEqual(sMethod, "subscribe") || StrEqual(sMethod, "unsubscribe") || StrEqual(sMethod, "replay"))
|
||||
{
|
||||
int Subscriber = g_Client_Subscriber[Client];
|
||||
if(Subscriber == -1)
|
||||
{
|
||||
Subscriber = Subscriber_Create(Client);
|
||||
if(Subscriber < 0)
|
||||
{
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("type", "subscribe");
|
||||
jError.SetString("error", "Could not allocate a subscriber.");
|
||||
jError.SetInt("code", Subscriber);
|
||||
jResponse.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
g_Client_Subscriber[Client] = Subscriber;
|
||||
}
|
||||
|
||||
return Subscriber_HandleRequest(Subscriber, jRequest, jResponse);
|
||||
}
|
||||
else if(StrEqual(sMethod, "function"))
|
||||
{
|
||||
static char sFunction[64];
|
||||
if(jRequest.GetString("function", sFunction, sizeof(sFunction)) < 0)
|
||||
{
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", "Request has no 'function' string-value.");
|
||||
jResponse.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
jResponse.SetString("function", sFunction);
|
||||
|
||||
static char sAPIFunction[64];
|
||||
Format(sAPIFunction, sizeof(sAPIFunction), "API_%s", sFunction);
|
||||
|
||||
Function Fun = GetFunctionByName(INVALID_HANDLE, sAPIFunction);
|
||||
if(Fun == INVALID_FUNCTION)
|
||||
{
|
||||
int Res = Call_StartNative(sFunction);
|
||||
if(!Res)
|
||||
{
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", "Invalid function specified.");
|
||||
jError.SetInt("code", Res);
|
||||
jResponse.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
Call_StartFunction(INVALID_HANDLE, Fun);
|
||||
|
||||
JSONArray jArgsArray = view_as<JSONArray>(jRequest.Get("args"));
|
||||
if(jArgsArray == null || !jArgsArray.IsArray)
|
||||
{
|
||||
delete jArgsArray;
|
||||
Call_Cancel();
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", "Request has no 'args' array-value.");
|
||||
jResponse.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int aiValues[32];
|
||||
int iValues = 0;
|
||||
|
||||
float afValues[32];
|
||||
int fValues = 0;
|
||||
|
||||
static char asValues[16][1024];
|
||||
int sValues = 0;
|
||||
|
||||
for(int i = 0; i < jArgsArray.Length; i++)
|
||||
{
|
||||
bool Fail = false;
|
||||
JSONValue jValue;
|
||||
jValue = jArgsArray.Get(i);
|
||||
|
||||
char sType1[32];
|
||||
jValue.TypeToString(sType1, sizeof(sType1));
|
||||
|
||||
if(jValue.IsArray)
|
||||
{
|
||||
JSONArray jValueArray = view_as<JSONArray>(jValue);
|
||||
JSONValue jArrayValue = jValueArray.Get(0);
|
||||
|
||||
char sType2[32];
|
||||
jArrayValue.TypeToString(sType2, sizeof(sType2));
|
||||
|
||||
if(jArrayValue.IsInteger || jArrayValue.IsBoolean)
|
||||
{
|
||||
int iValues_ = iValues;
|
||||
for(int j = 0; j < jValueArray.Length; j++)
|
||||
{
|
||||
JSONInteger jInteger = view_as<JSONInteger>(jValueArray.Get(j));
|
||||
aiValues[iValues_++] = jInteger.Value;
|
||||
delete jInteger;
|
||||
}
|
||||
|
||||
Call_PushArrayEx(aiValues[iValues], jValueArray.Length, SM_PARAM_COPYBACK);
|
||||
iValues += jValueArray.Length;
|
||||
}
|
||||
else if(jArrayValue.IsFloat)
|
||||
{
|
||||
int fValues_ = fValues;
|
||||
for(int j = 0; j < jValueArray.Length; j++)
|
||||
{
|
||||
JSONFloat jFloat = view_as<JSONFloat>(jValueArray.Get(j));
|
||||
afValues[fValues_++] = jFloat.Value;
|
||||
delete jFloat;
|
||||
}
|
||||
|
||||
Call_PushArrayEx(afValues[fValues], jValueArray.Length, SM_PARAM_COPYBACK);
|
||||
fValues += jValueArray.Length;
|
||||
}
|
||||
/*else if(jArrayValue.IsString)
|
||||
{
|
||||
int sValues_ = sValues;
|
||||
for(int j = 0; j < jValueArray.Length; j++)
|
||||
{
|
||||
JSONString jString = view_as<JSONString>(jValueArray.Get(j));
|
||||
jString.GetString(asValues[sValues_++], sizeof(asValues[]));
|
||||
delete jString;
|
||||
}
|
||||
|
||||
Call_PushArrayEx(view_as<int>(asValues[sValues]), jValueArray.Length, SM_PARAM_COPYBACK);
|
||||
sValues += jValueArray.Length;
|
||||
}*/
|
||||
else if(jArrayValue.IsArray) // Special
|
||||
{
|
||||
static char sSpecial[32];
|
||||
view_as<JSONArray>(jArrayValue).GetString(0, sSpecial, sizeof(sSpecial));
|
||||
|
||||
if(StrEqual(sSpecial, "NULL_VECTOR"))
|
||||
Call_PushArrayEx(NULL_VECTOR, 3, 0);
|
||||
else if(StrEqual(sSpecial, "NULL_STRING"))
|
||||
Call_PushString(NULL_STRING);
|
||||
else
|
||||
Fail = true;
|
||||
}
|
||||
else
|
||||
Fail = true;
|
||||
|
||||
if(Fail)
|
||||
{
|
||||
Call_Cancel();
|
||||
delete jArrayValue;
|
||||
delete jValue;
|
||||
delete jArgsArray;
|
||||
|
||||
static char sType[16];
|
||||
jValue.TypeToString(sType, sizeof(sType));
|
||||
|
||||
char sError[128];
|
||||
FormatEx(sError, sizeof(sError), "Unsupported parameter in list %d of type '%s'", i, sType);
|
||||
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", sError);
|
||||
jResponse.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
delete jArrayValue;
|
||||
}
|
||||
else if(jValue.IsInteger || jValue.IsBoolean)
|
||||
{
|
||||
aiValues[iValues] = view_as<JSONInteger>(jValue).Value;
|
||||
Call_PushCell(aiValues[iValues++]);
|
||||
}
|
||||
else if(jValue.IsFloat)
|
||||
{
|
||||
afValues[fValues] = view_as<JSONFloat>(jValue).Value;
|
||||
Call_PushFloat(afValues[fValues++]);
|
||||
}
|
||||
else if(jValue.IsString)
|
||||
{
|
||||
// Broken: view_as<JSONString>(jValue).GetString(asValues[sValues], sizeof(asValues[]));
|
||||
JSONString jString = view_as<JSONString>(jValue);
|
||||
jString.GetString(asValues[sValues], sizeof(asValues[]));
|
||||
Call_PushStringEx(asValues[sValues++], sizeof(asValues[]), SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
|
||||
}
|
||||
else
|
||||
{
|
||||
Call_Cancel();
|
||||
delete jValue;
|
||||
delete jArgsArray;
|
||||
|
||||
static char sType[16];
|
||||
jValue.TypeToString(sType, sizeof(sType));
|
||||
|
||||
char sError[128];
|
||||
FormatEx(sError, sizeof(sError), "Unsupported parameter %d of type '%s'", i, sType);
|
||||
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", sError);
|
||||
jResponse.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
delete jValue;
|
||||
}
|
||||
|
||||
int Result;
|
||||
static char sException[1024];
|
||||
int Error = Call_FinishEx(Result, sException, sizeof(sException));
|
||||
|
||||
if(Error != SP_ERROR_NONE)
|
||||
{
|
||||
delete jArgsArray;
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetInt("error", Error);
|
||||
jError.SetString("exception", sException);
|
||||
jResponse.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
jResponse.SetInt("result", Result);
|
||||
|
||||
JSONArray jArgsResponse = new JSONArray();
|
||||
iValues = 0;
|
||||
fValues = 0;
|
||||
sValues = 0;
|
||||
|
||||
for(int i = 0; i < jArgsArray.Length; i++)
|
||||
{
|
||||
JSONValue jValue;
|
||||
jValue = jArgsArray.Get(i);
|
||||
|
||||
if(jValue.IsArray)
|
||||
{
|
||||
JSONArray jArrayResponse = new JSONArray();
|
||||
JSONArray jValueArray = view_as<JSONArray>(jValue);
|
||||
JSONValue jArrayValue = jValueArray.Get(0);
|
||||
|
||||
if(jArrayValue.IsInteger || jArrayValue.IsBoolean)
|
||||
{
|
||||
for(int j = 0; j < jValueArray.Length; j++)
|
||||
jArrayResponse.AppendInt(aiValues[iValues++]);
|
||||
}
|
||||
else if(jArrayValue.IsFloat)
|
||||
{
|
||||
for(int j = 0; j < jValueArray.Length; j++)
|
||||
jArrayResponse.AppendFloat(afValues[fValues++]);
|
||||
}
|
||||
else if(jArrayValue.IsString)
|
||||
{
|
||||
for(int j = 0; j < jValueArray.Length; j++)
|
||||
jArrayResponse.AppendString(asValues[sValues++]);
|
||||
}
|
||||
else if(jArrayValue.IsArray) // Special
|
||||
{
|
||||
static char sSpecial[32];
|
||||
view_as<JSONArray>(jArrayValue).GetString(0, sSpecial, sizeof(sSpecial));
|
||||
jArrayResponse.AppendString(sSpecial);
|
||||
}
|
||||
delete jArrayValue;
|
||||
jArgsResponse.Append(jArrayResponse);
|
||||
}
|
||||
else if(jValue.IsInteger || jValue.IsBoolean)
|
||||
{
|
||||
jArgsResponse.AppendInt(aiValues[iValues++]);
|
||||
}
|
||||
else if(jValue.IsFloat)
|
||||
{
|
||||
jArgsResponse.AppendFloat(afValues[fValues++]);
|
||||
}
|
||||
else if(jValue.IsString)
|
||||
{
|
||||
jArgsResponse.AppendString(asValues[sValues++]);
|
||||
}
|
||||
delete jValue;
|
||||
}
|
||||
|
||||
jResponse.Set("args", jArgsResponse);
|
||||
|
||||
delete jArgsArray;
|
||||
return 0;
|
||||
}
|
||||
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", "No handler found for requested method.");
|
||||
jResponse.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int PublishEvent(int Client, JSONObject Object)
|
||||
{
|
||||
if(Client < 0 || Client > MAX_CLIENTS || g_Client_Socket[Client] == null)
|
||||
return -1;
|
||||
|
||||
static char sEvent[4096];
|
||||
Object.ToString(sEvent, sizeof(sEvent));
|
||||
g_Client_Socket[Client].WriteNull(sEvent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int GetFreeClientIndex()
|
||||
{
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(!g_Client_Socket[i])
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ClientFromSocket(AsyncSocket socket)
|
||||
{
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(g_Client_Socket[i] == socket)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
#include "GameEvents.inc"
|
||||
|
||||
#define MAX_SUBSCRIBERS MAX_CLIENTS
|
||||
|
||||
enum
|
||||
{
|
||||
eSubscribeError_OutOfRange = -1,
|
||||
eSubscribeError_Inactive = -2,
|
||||
eSubscribeError_GameEvent = -3,
|
||||
}
|
||||
|
||||
static bool g_Subscriber_Active[MAX_SUBSCRIBERS] = { false, ... };
|
||||
static int g_Subscriber_Client[MAX_SUBSCRIBERS] = { -1, ... };
|
||||
|
||||
static ArrayList g_Subscriber_GameEvents[MAX_SUBSCRIBERS];
|
||||
|
||||
bool Subscribe_OnPluginStart()
|
||||
{
|
||||
GameEvents_Init();
|
||||
}
|
||||
|
||||
int Subscriber_Create(int Client)
|
||||
{
|
||||
int Index = Client;
|
||||
if(Index < 0 || Index >= MAX_SUBSCRIBERS || g_Subscriber_Active[Index])
|
||||
{
|
||||
Index = GetFreeSubscriberIndex();
|
||||
if(Index == eSubscribeError_OutOfRange)
|
||||
return eSubscribeError_OutOfRange;
|
||||
}
|
||||
|
||||
g_Subscriber_Active[Index] = true;
|
||||
g_Subscriber_Client[Index] = Client;
|
||||
|
||||
g_Subscriber_GameEvents[Index] = new ArrayList(ByteCountToCells(32));
|
||||
|
||||
return Index;
|
||||
}
|
||||
|
||||
int Subscriber_Destroy(int Index)
|
||||
{
|
||||
if(Index < 0 || Index >= MAX_SUBSCRIBERS)
|
||||
return eSubscribeError_OutOfRange;
|
||||
|
||||
if(!g_Subscriber_Active[Index])
|
||||
return eSubscribeError_Inactive;
|
||||
|
||||
for(int i = 0; i < g_Subscriber_GameEvents[Index].Length; i++)
|
||||
{
|
||||
static char sEventName[32];
|
||||
g_Subscriber_GameEvents[Index].GetString(i, sEventName, sizeof(sEventName));
|
||||
GameEvents_Unhook(sEventName);
|
||||
}
|
||||
|
||||
delete g_Subscriber_GameEvents[Index];
|
||||
|
||||
g_Subscriber_Active[Index] = false;
|
||||
g_Subscriber_Client[Index] = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Subscriber_HandleRequest(int Index, JSONObject Request, JSONObject Response)
|
||||
{
|
||||
static char sMethod[32];
|
||||
Request.GetString("method", sMethod, sizeof(sMethod));
|
||||
|
||||
static char sModule[32];
|
||||
if(Request.GetString("module", sModule, sizeof(sModule)) < 0)
|
||||
{
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", "Request has no 'module' string-value.");
|
||||
Response.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
Response.SetString("module", sModule);
|
||||
|
||||
if(StrEqual(sModule, "gameevents"))
|
||||
{
|
||||
JSONArray EventArray = view_as<JSONArray>(Request.Get("events"));
|
||||
if(EventArray == null || !EventArray.IsArray)
|
||||
{
|
||||
delete EventArray;
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", "Request has no 'events' array-value.");
|
||||
Response.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Method = 0;
|
||||
if(StrEqual(sMethod, "subscribe"))
|
||||
Method = 1;
|
||||
else if(StrEqual(sMethod, "unsubscribe"))
|
||||
Method = 2;
|
||||
else if(StrEqual(sMethod, "replay"))
|
||||
Method = 3;
|
||||
|
||||
JSONArray EventArrayResponse = new JSONArray();
|
||||
|
||||
for(int i = 0; i < EventArray.Length; i++)
|
||||
{
|
||||
static char sEventName[32];
|
||||
if(EventArray.GetString(i, sEventName, sizeof(sEventName)) < 0)
|
||||
{
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", "not a string-value");
|
||||
EventArrayResponse.Append(jError);
|
||||
continue;
|
||||
}
|
||||
|
||||
int Res;
|
||||
if(Method == 1)
|
||||
Res = Subscribe_GameEvents_Subscribe(Index, sEventName);
|
||||
else if(Method == 2)
|
||||
Res = Subscribe_GameEvents_Unsubscribe(Index, sEventName);
|
||||
else if(Method == 3)
|
||||
Res = Subscribe_GameEvents_Replay(Index, sEventName);
|
||||
|
||||
EventArrayResponse.AppendInt(Res);
|
||||
}
|
||||
delete EventArray;
|
||||
|
||||
Response.Set("events", EventArrayResponse);
|
||||
return 0;
|
||||
}
|
||||
|
||||
JSONObject jError = new JSONObject();
|
||||
jError.SetString("error", "No handler found for requested module.");
|
||||
Response.Set("error", jError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int GetFreeSubscriberIndex()
|
||||
{
|
||||
for(int i = 0; i < MAX_SUBSCRIBERS; i++)
|
||||
{
|
||||
if(!g_Subscriber_Active[i])
|
||||
return i;
|
||||
}
|
||||
return eSubscribeError_OutOfRange;
|
||||
}
|
||||
|
||||
/* GameEvents */
|
||||
static int Subscribe_GameEvents_Subscribe(int Index, const char[] sEventName)
|
||||
{
|
||||
if(Index < 0 || Index >= MAX_SUBSCRIBERS)
|
||||
return eSubscribeError_OutOfRange;
|
||||
|
||||
if(!g_Subscriber_Active[Index])
|
||||
return eSubscribeError_Inactive;
|
||||
|
||||
int Find = g_Subscriber_GameEvents[Index].FindString(sEventName);
|
||||
if(Find != -1)
|
||||
return Find;
|
||||
|
||||
if(GameEvents_Hook(sEventName) < 0)
|
||||
return eSubscribeError_GameEvent;
|
||||
|
||||
return g_Subscriber_GameEvents[Index].PushString(sEventName);
|
||||
}
|
||||
|
||||
static int Subscribe_GameEvents_Unsubscribe(int Index, const char[] sEventName)
|
||||
{
|
||||
if(Index < 0 || Index >= MAX_SUBSCRIBERS)
|
||||
return eSubscribeError_OutOfRange;
|
||||
|
||||
if(!g_Subscriber_Active[Index])
|
||||
return eSubscribeError_Inactive;
|
||||
|
||||
int Find = g_Subscriber_GameEvents[Index].FindString(sEventName);
|
||||
if(Find == -1)
|
||||
return 0;
|
||||
|
||||
if(GameEvents_Unhook(sEventName) < 0)
|
||||
return eSubscribeError_GameEvent;
|
||||
|
||||
g_Subscriber_GameEvents[Index].Erase(Find);
|
||||
return Find;
|
||||
}
|
||||
|
||||
static int Subscribe_GameEvents_Replay(int Index, const char[] sEventName)
|
||||
{
|
||||
if(Index < 0 || Index >= MAX_SUBSCRIBERS)
|
||||
return eSubscribeError_OutOfRange;
|
||||
|
||||
if(!g_Subscriber_Active[Index])
|
||||
return eSubscribeError_Inactive;
|
||||
|
||||
if(StrEqual(sEventName, "player_connect"))
|
||||
{
|
||||
for(int client = 1; client <= MaxClients; client++)
|
||||
{
|
||||
if(!IsClientConnected(client))
|
||||
continue;
|
||||
|
||||
char sName[MAX_NAME_LENGTH];
|
||||
GetClientName(client, sName, sizeof(sName));
|
||||
|
||||
char sSteamID[32];
|
||||
GetClientAuthId(client, AuthId_Engine, sSteamID, sizeof(sSteamID), false);
|
||||
|
||||
char sAddress[32];
|
||||
GetClientIP(client, sAddress, sizeof(sAddress), false);
|
||||
|
||||
JSONObject jEventData = new JSONObject();
|
||||
jEventData.SetString("name", sName);
|
||||
char sBuf[MAX_NAME_LENGTH];
|
||||
jEventData.GetString("name", sBuf, sizeof(sBuf));
|
||||
jEventData.SetInt("index", client - 1);
|
||||
jEventData.SetInt("userid", GetClientUserId(client));
|
||||
jEventData.SetString("networkid", sSteamID);
|
||||
jEventData.SetString("address", sAddress);
|
||||
jEventData.SetBool("bot", IsFakeClient(client));
|
||||
|
||||
Subscribe_GameEvents_FakePublish(g_Subscriber_Client[Index], sEventName, jEventData);
|
||||
}
|
||||
}
|
||||
else if(StrEqual(sEventName, "player_activate"))
|
||||
{
|
||||
for(int client = 1; client <= MaxClients; client++)
|
||||
{
|
||||
if(!IsClientInGame(client))
|
||||
continue;
|
||||
|
||||
JSONObject jEventData = new JSONObject();
|
||||
jEventData.SetInt("userid", GetClientUserId(client));
|
||||
|
||||
Subscribe_GameEvents_FakePublish(g_Subscriber_Client[Index], sEventName, jEventData);
|
||||
}
|
||||
}
|
||||
else
|
||||
return eSubscribeError_GameEvent;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Subscribe_GameEvents_FakePublish(int Index, const char[] sEventName, JSONObject jEventData)
|
||||
{
|
||||
if(Index < 0 || Index >= MAX_SUBSCRIBERS)
|
||||
return eSubscribeError_OutOfRange;
|
||||
|
||||
if(!g_Subscriber_Active[Index])
|
||||
return eSubscribeError_Inactive;
|
||||
|
||||
JSONObject jEvent = new JSONObject();
|
||||
jEvent.SetString("name", sEventName);
|
||||
jEvent.Set("data", jEventData);
|
||||
|
||||
JSONObject jPublish = new JSONObject();
|
||||
jPublish.SetString("method", "publish");
|
||||
jPublish.SetString("module", "gameevents");
|
||||
jPublish.Set("event", jEvent);
|
||||
|
||||
PublishEvent(g_Subscriber_Client[Index], jPublish);
|
||||
delete jPublish;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Subscribe_GameEvents_Publish(const char[] sEventName, JSONObject jEvent)
|
||||
{
|
||||
JSONObject jPublish = new JSONObject();
|
||||
jPublish.SetString("method", "publish");
|
||||
jPublish.SetString("module", "gameevents");
|
||||
jPublish.Set("event", jEvent);
|
||||
|
||||
for(int Index = 0; Index < MAX_SUBSCRIBERS; Index++)
|
||||
{
|
||||
if(!g_Subscriber_Active[Index])
|
||||
continue;
|
||||
|
||||
if(g_Subscriber_GameEvents[Index].FindString(sEventName) == -1)
|
||||
continue;
|
||||
|
||||
PublishEvent(g_Subscriber_Client[Index], jPublish);
|
||||
}
|
||||
|
||||
delete jPublish;
|
||||
}
|
||||
/* GameEvents */
|
||||
@@ -0,0 +1 @@
|
||||
../../../includes/AsyncSocket.inc
|
||||
@@ -0,0 +1 @@
|
||||
../../../includes/smjansson.inc
|
||||
Reference in New Issue
Block a user