├── .gitignore ├── README.md ├── discord ├── DiscordRequest.sp ├── GetGuildChannels.sp ├── GetGuilds.sp ├── GuildMembers.sp ├── GuildRole.sp ├── ListenToChannel.sp ├── MessageObject.sp ├── SendMessage.sp ├── SendWebHook.sp ├── UserObject.sp ├── deletemessage.sp └── reactions.sp ├── discord_api.smx ├── discord_api.sp ├── examples ├── discord_test.sp └── outdated │ ├── README.md │ ├── discord_announcement.sp │ ├── discord_calladmin.sp │ └── discord_test.sp └── include ├── csgocolors.inc ├── discord.inc └── discord ├── GuildMember.inc ├── bot.inc ├── channel.inc ├── message_embed.inc ├── stocks.inc └── webhook.inc /.gitignore: -------------------------------------------------------------------------------- 1 | *.smx 2 | discord_api.zip -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sourcemod-discord 2 | Discord API for Sourcemod. There's a lot more to add. Changes will be happening that will break existing plugins, sorry. Still a bit messy 3 | 4 | # IMPORTANT 5 | Before you are able to send messages, you have to create a websocket connection with the bot atleast once. Simply, do this: 6 | http://scooterx3.net/2016-05-25/discord-bot.html 7 | 8 | (Or paste this into browser -> console: http://pastebin.com/3g2HbTjY ) 9 | 10 | ## Installation 11 | - Put discord.inc in your include folder 12 | - Compile discord_api.sp and put it in your sourcemod/plugins folder 13 | - Install smjansson and SteamWorks extension (Might need to restart server after) 14 | 15 | Optional examples: 16 | - Edit the .sp by replacing `` with your bot token. 17 | - Compile and place in sourcemod/plugins 18 | 19 | Bot Token can be obtained from: 20 | 21 | https://discord.com/developers/applications/me 22 | 23 | Create a new user and turn into bot account, reveal Token and copy. 24 | 25 | ## Features 26 | - List all guilds 27 | - List all Channels for guilds 28 | - Send Messages to Channel 29 | - Listen for messages for Channel 30 | 31 | ## API 32 | For full list view `discord.inc` and take a look at `discord_test.sp` for examples. 33 | 34 | ### Note 35 | > DiscordBot and DiscordChannel are both Handles. Everytime DiscordBot is passed, it's the same Handle to the Bot. This should not be closed unless you don't need that Bot anymore. DiscordChannel are handles to the Channel. Everytime Channel is passed the handle is closed after. If you need to keep the Channel Handle, Clone it. E.g `DiscordChannel newChannel = CloneHandle(Channel);` 36 | 37 | 38 | ### OnChannelMessage 39 | Both Bot and channel are destroyed after it's called. 40 | -------------------------------------------------------------------------------- /discord/DiscordRequest.sp: -------------------------------------------------------------------------------- 1 | /* 2 | stock Handle PrepareRequest(DiscordBot bot, char[] url, EHTTPMethod method=k_EHTTPMethodGET, Handle hJson=null, SteamWorksHTTPDataReceived DataReceived = INVALID_FUNCTION, SteamWorksHTTPRequestCompleted RequestCompleted = INVALID_FUNCTION) { 3 | static char stringJson[16384]; 4 | stringJson[0] = '\0'; 5 | if(hJson != null) { 6 | json_dump(hJson, stringJson, sizeof(stringJson), 0, true); 7 | } 8 | 9 | //Format url 10 | static char turl[128]; 11 | FormatEx(turl, sizeof(turl), "https://discord.com/api/%s", url); 12 | 13 | Handle request = SteamWorks_CreateHTTPRequest(method, turl); 14 | if(request == null) { 15 | return null; 16 | } 17 | 18 | if(bot != null) { 19 | BuildAuthHeader(request, bot); 20 | } 21 | 22 | SteamWorks_SetHTTPRequestRawPostBody(request, "application/json; charset=UTF-8", stringJson, strlen(stringJson)); 23 | 24 | SteamWorks_SetHTTPRequestNetworkActivityTimeout(request, 30); 25 | 26 | if(RequestCompleted == INVALID_FUNCTION) { 27 | //I had some bugs previously where it wouldn't send request and return code 0 if I didn't set request completed. 28 | //This is just a safety then, my issue could have been something else and I will test more later on 29 | RequestCompleted = HTTPCompleted; 30 | } 31 | 32 | if(DataReceived == INVALID_FUNCTION) { 33 | //Need to close the request handle 34 | DataReceived = HTTPDataReceive; 35 | } 36 | 37 | SteamWorks_SetHTTPCallbacks(request, RequestCompleted, HeadersReceived, DataReceived); 38 | if(hJson != null) delete hJson; 39 | 40 | return request; 41 | } 42 | */ 43 | 44 | methodmap DiscordRequest < Handle { 45 | public DiscordRequest(char[] url, EHTTPMethod method) { 46 | Handle request = SteamWorks_CreateHTTPRequest(method, url); 47 | return view_as(request); 48 | } 49 | 50 | public void SetJsonBody(Handle hJson) 51 | { 52 | if (this != INVALID_HANDLE && this != null) 53 | { 54 | static char stringJson[16384]; 55 | stringJson[0] = '\0'; 56 | if(hJson != null) { 57 | json_dump(hJson, stringJson, sizeof(stringJson), 0, true); 58 | } 59 | SteamWorks_SetHTTPRequestRawPostBody(this, "application/json; charset=UTF-8", stringJson, strlen(stringJson)); 60 | if(hJson != null) delete hJson; 61 | } 62 | } 63 | 64 | public void SetJsonBodyEx(Handle hJson) 65 | { 66 | if (this != INVALID_HANDLE && this != null) 67 | { 68 | static char stringJson[16384]; 69 | stringJson[0] = '\0'; 70 | if(hJson != null) { 71 | json_dump(hJson, stringJson, sizeof(stringJson), 0, true); 72 | } 73 | SteamWorks_SetHTTPRequestRawPostBody(this, "application/json; charset=UTF-8", stringJson, strlen(stringJson)); 74 | } 75 | } 76 | 77 | property int Timeout { 78 | public set(int timeout) 79 | { 80 | if (this != INVALID_HANDLE && this != null) 81 | SteamWorks_SetHTTPRequestNetworkActivityTimeout(this, timeout); 82 | } 83 | } 84 | 85 | public void SetCallbacks(SteamWorksHTTPRequestCompleted OnComplete, SteamWorksHTTPDataReceived DataReceived) 86 | { 87 | if (this != INVALID_HANDLE && this != null) 88 | SteamWorks_SetHTTPCallbacks(this, OnComplete, HeadersReceived, DataReceived); 89 | } 90 | 91 | public void SetContextValue(any data1, any data2) 92 | { 93 | if (this != INVALID_HANDLE && this != null) 94 | SteamWorks_SetHTTPRequestContextValue(this, data1, data2); 95 | } 96 | 97 | public void SetData(any data1, char[] route) 98 | { 99 | if (this != INVALID_HANDLE && this != null) 100 | SteamWorks_SetHTTPRequestContextValue(this, data1, UrlToDP(route)); 101 | } 102 | 103 | public void SetBot(DiscordBot bot) 104 | { 105 | if (this != INVALID_HANDLE && this != null) 106 | BuildAuthHeader(this, bot); 107 | } 108 | 109 | public void Send(char[] route) 110 | { 111 | if (this != INVALID_HANDLE && this != null) 112 | DiscordSendRequest(this, route); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /discord/GetGuildChannels.sp: -------------------------------------------------------------------------------- 1 | public int Native_DiscordBot_GetGuildChannels(Handle plugin, int numParams) { 2 | DiscordBot bot = GetNativeCell(1); 3 | 4 | char guild[32]; 5 | GetNativeString(2, guild, sizeof(guild)); 6 | 7 | Function fCallback = GetNativeCell(3); 8 | Function fCallbackAll = GetNativeCell(4); 9 | any data = GetNativeCell(5); 10 | 11 | DataPack dp = CreateDataPack(); 12 | WritePackCell(dp, bot); 13 | WritePackString(dp, guild); 14 | WritePackCell(dp, plugin); 15 | WritePackFunction(dp, fCallback); 16 | WritePackFunction(dp, fCallbackAll); 17 | WritePackCell(dp, data); 18 | 19 | ThisSendRequest(bot, guild, dp); 20 | } 21 | 22 | static void ThisSendRequest(DiscordBot bot, char[] guild, DataPack dp) { 23 | char url[64]; 24 | FormatEx(url, sizeof(url), "guilds/%s/channels", guild); 25 | 26 | Handle request = PrepareRequest(bot, url, k_EHTTPMethodGET, null, GetGuildChannelsData); 27 | if(request == null) { 28 | CreateTimer(2.0, GetGuildChannelsDelayed, dp); 29 | return; 30 | } 31 | 32 | SteamWorks_SetHTTPRequestContextValue(request, dp, UrlToDP(url)); 33 | 34 | DiscordSendRequest(request, url); 35 | } 36 | 37 | public Action GetGuildChannelsDelayed(Handle timer, any data) { 38 | DataPack dp = view_as(data); 39 | ResetPack(dp); 40 | 41 | DiscordBot bot = ReadPackCell(dp); 42 | 43 | char guild[32]; 44 | ReadPackString(dp, guild, sizeof(guild)); 45 | 46 | ThisSendRequest(bot, guild, dp); 47 | } 48 | 49 | public int GetGuildChannelsData(Handle request, bool failure, int offset, int statuscode, any dp) { 50 | if(failure || statuscode != 200) { 51 | if(statuscode == 429 || statuscode == 500) { 52 | ResetPack(dp); 53 | DiscordBot bot = ReadPackCell(dp); 54 | 55 | char guild[32]; 56 | ReadPackString(dp, guild, sizeof(guild)); 57 | 58 | ThisSendRequest(bot, guild, view_as(dp)); 59 | 60 | delete request; 61 | return; 62 | } 63 | LogError("[DISCORD] Couldn't Retrieve Guild Channels - Fail %i %i", failure, statuscode); 64 | delete request; 65 | delete view_as(dp); 66 | return; 67 | } 68 | SteamWorks_GetHTTPResponseBodyCallback(request, GetGuildChannelsData_Data, dp); 69 | delete request; 70 | } 71 | 72 | public int GetGuildChannelsData_Data(const char[] data, any datapack) { 73 | Handle hJson = json_load(data); 74 | 75 | //Read from datapack to get info 76 | Handle dp = view_as(datapack); 77 | ResetPack(dp); 78 | int bot = ReadPackCell(dp); 79 | 80 | char guild[32]; 81 | ReadPackString(dp, guild, sizeof(guild)); 82 | 83 | Handle plugin = view_as(ReadPackCell(dp)); 84 | Function func = ReadPackFunction(dp); 85 | Function funcAll = ReadPackFunction(dp); 86 | any pluginData = ReadPackCell(dp); 87 | delete dp; 88 | 89 | //Create forwards 90 | Handle fForward = INVALID_HANDLE; 91 | Handle fForwardAll = INVALID_HANDLE; 92 | if(func != INVALID_FUNCTION) { 93 | fForward = CreateForward(ET_Ignore, Param_Cell, Param_String, Param_Cell, Param_Cell); 94 | AddToForward(fForward, plugin, func); 95 | } 96 | 97 | if(funcAll != INVALID_FUNCTION) { 98 | fForwardAll = CreateForward(ET_Ignore, Param_Cell, Param_String, Param_Cell, Param_Cell); 99 | AddToForward(fForwardAll, plugin, funcAll); 100 | } 101 | 102 | ArrayList alChannels = null; 103 | 104 | if(funcAll != INVALID_FUNCTION) { 105 | alChannels = CreateArray(); 106 | } 107 | 108 | //Loop through json 109 | for(int i = 0; i < json_array_size(hJson); i++) { 110 | Handle hObject = json_array_get(hJson, i); 111 | 112 | DiscordChannel Channel = view_as(hObject); 113 | 114 | if(fForward != INVALID_HANDLE) { 115 | Call_StartForward(fForward); 116 | Call_PushCell(bot); 117 | Call_PushString(guild); 118 | Call_PushCell(Channel); 119 | Call_PushCell(pluginData); 120 | Call_Finish(); 121 | } 122 | 123 | if(fForwardAll != INVALID_HANDLE) { 124 | alChannels.Push(Channel); 125 | }else { 126 | delete Channel; 127 | } 128 | } 129 | 130 | if(fForwardAll != INVALID_HANDLE) { 131 | Call_StartForward(fForwardAll); 132 | Call_PushCell(bot); 133 | Call_PushString(guild); 134 | Call_PushCell(alChannels); 135 | Call_PushCell(pluginData); 136 | Call_Finish(); 137 | 138 | for(int i = 0; i < alChannels.Length; i++) { 139 | Handle hChannel = view_as(alChannels.Get(i)); 140 | delete hChannel; 141 | } 142 | 143 | delete alChannels; 144 | delete fForwardAll; 145 | } 146 | 147 | if(fForward != INVALID_HANDLE) { 148 | delete fForward; 149 | } 150 | 151 | delete hJson; 152 | } -------------------------------------------------------------------------------- /discord/GetGuilds.sp: -------------------------------------------------------------------------------- 1 | public int Native_DiscordBot_GetGuilds(Handle plugin, int numParams) { 2 | DiscordBot bot = GetNativeCell(1); 3 | Function fCallback = GetNativeCell(2); 4 | Function fCallbackAll = GetNativeCell(3); 5 | any data = GetNativeCell(4); 6 | 7 | DataPack dp = CreateDataPack(); 8 | WritePackCell(dp, bot); 9 | WritePackCell(dp, plugin); 10 | WritePackFunction(dp, fCallback); 11 | WritePackFunction(dp, fCallbackAll); 12 | WritePackCell(dp, data); 13 | 14 | ThisSendRequest(bot, dp); 15 | } 16 | 17 | static void ThisSendRequest(DiscordBot bot, DataPack dp) { 18 | char url[64]; 19 | FormatEx(url, sizeof(url), "users/@me/guilds"); 20 | 21 | Handle request = PrepareRequest(bot, url, k_EHTTPMethodGET, null, GetGuildsData); 22 | if(request == null) { 23 | CreateTimer(2.0, GetGuildsDelayed, dp); 24 | return; 25 | } 26 | 27 | SteamWorks_SetHTTPRequestContextValue(request, dp, UrlToDP(url)); 28 | 29 | DiscordSendRequest(request, url); 30 | } 31 | 32 | public Action GetGuildsDelayed(Handle timer, any data) { 33 | DataPack dp = view_as(data); 34 | ResetPack(dp); 35 | 36 | DiscordBot bot = ReadPackCell(dp); 37 | 38 | ThisSendRequest(bot, dp); 39 | } 40 | 41 | public int GetGuildsData(Handle request, bool failure, int offset, int statuscode, any dp) { 42 | if(failure || statuscode != 200) { 43 | if(statuscode == 429 || statuscode == 500) { 44 | ResetPack(dp); 45 | DiscordBot bot = ReadPackCell(dp); 46 | ThisSendRequest(bot, dp); 47 | 48 | delete request; 49 | return; 50 | } 51 | LogError("[DISCORD] Couldn't Retrieve Guilds - Fail %i %i", failure, statuscode); 52 | delete request; 53 | delete view_as(dp); 54 | return; 55 | } 56 | SteamWorks_GetHTTPResponseBodyCallback(request, GetGuildsData_Data, dp); 57 | delete request; 58 | } 59 | 60 | public int GetGuildsData_Data(const char[] data, any datapack) { 61 | Handle hJson = json_load(data); 62 | 63 | //Read from datapack to get info 64 | Handle dp = view_as(datapack); 65 | ResetPack(dp); 66 | int bot = ReadPackCell(dp); 67 | Handle plugin = view_as(ReadPackCell(dp)); 68 | Function func = ReadPackFunction(dp); 69 | Function funcAll = ReadPackFunction(dp); 70 | any pluginData = ReadPackCell(dp); 71 | delete dp; 72 | 73 | //Create forwards 74 | Handle fForward = INVALID_HANDLE; 75 | Handle fForwardAll = INVALID_HANDLE; 76 | if(func != INVALID_FUNCTION) { 77 | fForward = CreateForward(ET_Ignore, Param_Cell, Param_String, Param_String, Param_String, Param_Cell, Param_Cell, Param_Cell); 78 | AddToForward(fForward, plugin, func); 79 | } 80 | 81 | if(funcAll != INVALID_FUNCTION) { 82 | fForwardAll = CreateForward(ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell); 83 | AddToForward(fForwardAll, plugin, funcAll); 84 | } 85 | 86 | ArrayList alId = null; 87 | ArrayList alName = null; 88 | ArrayList alIcon = null; 89 | ArrayList alOwner = null; 90 | ArrayList alPermissions = null; 91 | 92 | if(funcAll != INVALID_FUNCTION) { 93 | alId = CreateArray(32); 94 | alName = CreateArray(64); 95 | alIcon = CreateArray(128); 96 | alOwner = CreateArray(); 97 | alPermissions = CreateArray(); 98 | } 99 | 100 | //Loop through json 101 | for(int i = 0; i < json_array_size(hJson); i++) { 102 | Handle hObject = json_array_get(hJson, i); 103 | 104 | static char id[32]; 105 | static char name[64]; 106 | static char icon[128]; 107 | bool owner = false; 108 | int permissions; 109 | 110 | JsonObjectGetString(hObject, "id", id, sizeof(id)); 111 | JsonObjectGetString(hObject, "name", name, sizeof(name)); 112 | JsonObjectGetString(hObject, "icon", icon, sizeof(icon)); 113 | 114 | owner = JsonObjectGetBool(hObject, "owner"); 115 | permissions = JsonObjectGetBool(hObject, "permissions"); 116 | 117 | if(fForward != INVALID_HANDLE) { 118 | Call_StartForward(fForward); 119 | Call_PushCell(bot); 120 | Call_PushString(id); 121 | Call_PushString(name); 122 | Call_PushString(icon); 123 | Call_PushCell(owner); 124 | Call_PushCell(permissions); 125 | Call_PushCell(pluginData); 126 | Call_Finish(); 127 | } 128 | 129 | if(fForwardAll != INVALID_HANDLE) { 130 | alId.PushString(id); 131 | alName.PushString(name); 132 | alIcon.PushString(icon); 133 | alOwner.Push(owner); 134 | alPermissions.Push(permissions); 135 | } 136 | 137 | delete hObject; 138 | } 139 | 140 | if(fForwardAll != INVALID_HANDLE) { 141 | Call_StartForward(fForwardAll); 142 | Call_PushCell(bot); 143 | Call_PushCell(alId); 144 | Call_PushCell(alName); 145 | Call_PushCell(alIcon); 146 | Call_PushCell(alOwner); 147 | Call_PushCell(alPermissions); 148 | Call_PushCell(pluginData); 149 | Call_Finish(); 150 | 151 | delete alId; 152 | delete alName; 153 | delete alIcon; 154 | delete alOwner; 155 | delete alPermissions; 156 | 157 | delete fForwardAll; 158 | } 159 | 160 | if(fForward != INVALID_HANDLE) { 161 | delete fForward; 162 | } 163 | 164 | delete hJson; 165 | } -------------------------------------------------------------------------------- /discord/GuildMembers.sp: -------------------------------------------------------------------------------- 1 | /** 2 | * public native void GetGuildMembers(char[] guild, OnGetMembers fCallback, char[] afterUserID="", int limit=250); 3 | */ 4 | public int Native_DiscordBot_GetGuildMembers(Handle plugin, int numParams) { 5 | DiscordBot bot = view_as(CloneHandle(GetNativeCell(1))); 6 | 7 | char guild[32]; 8 | GetNativeString(2, guild, sizeof(guild)); 9 | 10 | Function fCallback = GetNativeCell(3); 11 | 12 | int limit = GetNativeCell(4); 13 | 14 | char afterID[32]; 15 | GetNativeString(5, afterID, sizeof(afterID)); 16 | 17 | Handle hData = json_object(); 18 | json_object_set_new(hData, "bot", bot); 19 | json_object_set_new(hData, "guild", json_string(guild)); 20 | json_object_set_new(hData, "limit", json_integer(limit)); 21 | json_object_set_new(hData, "afterID", json_string(afterID)); 22 | 23 | Handle fwd = CreateForward(ET_Ignore, Param_Cell, Param_String, Param_Cell); 24 | AddToForward(fwd, plugin, fCallback); 25 | json_object_set_new(hData, "callback", json_integer(view_as(fwd))); 26 | 27 | GetMembers(hData); 28 | } 29 | 30 | public int Native_DiscordBot_GetGuildMembersAll(Handle plugin, int numParams) { 31 | DiscordBot bot = view_as(CloneHandle(GetNativeCell(1))); 32 | 33 | char guild[32]; 34 | GetNativeString(2, guild, sizeof(guild)); 35 | 36 | Function fCallback = GetNativeCell(3); 37 | 38 | int limit = GetNativeCell(4); 39 | 40 | char afterID[32]; 41 | GetNativeString(5, afterID, sizeof(afterID)); 42 | 43 | Handle hData = json_object(); 44 | json_object_set_new(hData, "bot", bot); 45 | json_object_set_new(hData, "guild", json_string(guild)); 46 | json_object_set_new(hData, "limit", json_integer(limit)); 47 | json_object_set_new(hData, "afterID", json_string(afterID)); 48 | 49 | Handle fwd = CreateForward(ET_Ignore, Param_Cell, Param_String, Param_Cell); 50 | AddToForward(fwd, plugin, fCallback); 51 | json_object_set_new(hData, "callback", json_integer(view_as(fwd))); 52 | 53 | GetMembers(hData); 54 | } 55 | 56 | static void GetMembers(Handle hData) { 57 | DiscordBot bot = view_as(json_object_get(hData, "bot")); 58 | 59 | char guild[32]; 60 | JsonObjectGetString(hData, "guild", guild, sizeof(guild)); 61 | 62 | int limit = JsonObjectGetInt(hData, "limit"); 63 | 64 | char afterID[32]; 65 | JsonObjectGetString(hData, "afterID", afterID, sizeof(afterID)); 66 | 67 | char url[256]; 68 | if(StrEqual(afterID, "")) { 69 | FormatEx(url, sizeof(url), "https://discord.com/api/guilds/%s/members?limit=%i", guild, limit); 70 | }else { 71 | FormatEx(url, sizeof(url), "https://discord.com/api/guilds/%s/members?limit=%i&afterID=%s", guild, limit, afterID); 72 | } 73 | 74 | char route[128]; 75 | FormatEx(route, sizeof(route), "guild/%s/members", guild); 76 | 77 | DiscordRequest request = new DiscordRequest(url, k_EHTTPMethodGET); 78 | if(request == null) { 79 | delete bot; 80 | CreateTimer(2.0, SendGetMembers, hData); 81 | return; 82 | } 83 | request.SetCallbacks(HTTPCompleted, MembersDataReceive); 84 | request.SetBot(bot); 85 | request.SetData(hData, route); 86 | 87 | request.Send(route); 88 | 89 | delete bot; 90 | } 91 | 92 | public Action SendGetMembers(Handle timer, any data) { 93 | GetMembers(view_as(data)); 94 | } 95 | 96 | 97 | public MembersDataReceive(Handle request, bool failure, int offset, int statuscode, any dp) { 98 | if(failure || (statuscode != 200)) { 99 | if(statuscode == 400) { 100 | PrintToServer("BAD REQUEST"); 101 | } 102 | 103 | if(statuscode == 429 || statuscode == 500) { 104 | GetMembers(dp); 105 | 106 | delete request; 107 | return; 108 | } 109 | LogError("[DISCORD] Couldn't Send GetMembers - Fail %i %i", failure, statuscode); 110 | delete request; 111 | delete view_as(dp); 112 | return; 113 | } 114 | SteamWorks_GetHTTPResponseBodyCallback(request, GetMembersData, dp); 115 | delete request; 116 | } 117 | 118 | public int GetMembersData(const char[] data, any dp) { 119 | Handle hJson = json_load(data); 120 | Handle hData = view_as(dp); 121 | DiscordBot bot = view_as(json_object_get(hData, "bot")); 122 | 123 | Handle fwd = view_as(JsonObjectGetInt(hData, "callback")); 124 | 125 | char guild[32]; 126 | JsonObjectGetString(hData, "guild", guild, sizeof(guild)); 127 | 128 | if(fwd != null) { 129 | Call_StartForward(fwd); 130 | Call_PushCell(bot); 131 | Call_PushString(guild); 132 | Call_PushCell(hJson); 133 | Call_Finish(); 134 | } 135 | 136 | delete bot; 137 | if(JsonObjectGetBool(hData, "autoPaginate")) { 138 | int size = json_array_size(hJson); 139 | int limit = JsonObjectGetInt(hData, "limit"); 140 | if(limit == size) { 141 | Handle hLast = json_array_get(hJson, size - 1); 142 | char lastID[32]; 143 | json_string_value(hLast, lastID, sizeof(lastID)); 144 | delete hJson; 145 | delete hLast; 146 | 147 | json_object_set_new(hData, "afterID", json_string(lastID)); 148 | GetMembers(hData); 149 | return; 150 | } 151 | } 152 | 153 | delete hJson; 154 | delete hData; 155 | delete fwd; 156 | } -------------------------------------------------------------------------------- /discord/GuildRole.sp: -------------------------------------------------------------------------------- 1 | public int Native_DiscordBot_GetGuildRoles(Handle plugin, int numParams) { 2 | DiscordBot bot = view_as(CloneHandle(GetNativeCell(1))); 3 | 4 | char guild[32]; 5 | GetNativeString(2, guild, sizeof(guild)); 6 | 7 | Function fCallback = GetNativeCell(3); 8 | 9 | any data = GetNativeCell(4); 10 | 11 | Handle hData = json_object(); 12 | json_object_set_new(hData, "bot", bot); 13 | json_object_set_new(hData, "guild", json_string(guild)); 14 | json_object_set_new(hData, "data1", json_integer(view_as(data))); 15 | 16 | Handle fwd = CreateForward(ET_Ignore, Param_Cell, Param_String, Param_Cell, Param_Cell); 17 | AddToForward(fwd, plugin, fCallback); 18 | json_object_set_new(hData, "callback", json_integer(view_as(fwd))); 19 | 20 | GetGuildRoles(hData); 21 | } 22 | 23 | static void GetGuildRoles(Handle hData) { 24 | DiscordBot bot = view_as(json_object_get(hData, "bot")); 25 | 26 | char guild[32]; 27 | JsonObjectGetString(hData, "guild", guild, sizeof(guild)); 28 | 29 | 30 | char url[256]; 31 | FormatEx(url, sizeof(url), "https://discord.com/api/guilds/%s/roles", guild); 32 | 33 | char route[128]; 34 | FormatEx(route, sizeof(route), "guild/%s/roles", guild); 35 | 36 | DiscordRequest request = new DiscordRequest(url, k_EHTTPMethodGET); 37 | if(request == null) { 38 | delete bot; 39 | CreateTimer(2.0, SendGetGuildRoles, hData); 40 | return; 41 | } 42 | request.SetCallbacks(HTTPCompleted, GetGuildRolesReceive); 43 | request.SetBot(bot); 44 | request.SetData(hData, route); 45 | 46 | request.Send(route); 47 | 48 | delete bot; 49 | } 50 | 51 | public Action SendGetGuildRoles(Handle timer, any data) { 52 | GetGuildRoles(view_as(data)); 53 | } 54 | 55 | 56 | public GetGuildRolesReceive(Handle request, bool failure, int offset, int statuscode, any dp) { 57 | if(failure || (statuscode != 200)) { 58 | if(statuscode == 400) { 59 | PrintToServer("BAD REQUEST"); 60 | } 61 | 62 | if(statuscode == 429 || statuscode == 500) { 63 | GetGuildRoles(dp); 64 | 65 | delete request; 66 | return; 67 | } 68 | LogError("[DISCORD] Couldn't Send GetGuildRoles - Fail %i %i", failure, statuscode); 69 | delete request; 70 | delete view_as(dp); 71 | return; 72 | } 73 | SteamWorks_GetHTTPResponseBodyCallback(request, GetRolesData, dp); 74 | delete request; 75 | } 76 | 77 | public int GetRolesData(const char[] data, any dp) { 78 | Handle hJson = json_load(data); 79 | Handle hData = view_as(dp); 80 | DiscordBot bot = view_as(json_object_get(hData, "bot")); 81 | 82 | Handle fwd = view_as(JsonObjectGetInt(hData, "callback")); 83 | 84 | char guild[32]; 85 | JsonObjectGetString(hData, "guild", guild, sizeof(guild)); 86 | 87 | any data1 = JsonObjectGetInt(hData, "data1"); 88 | 89 | if(fwd != null) { 90 | Call_StartForward(fwd); 91 | Call_PushCell(bot); 92 | Call_PushString(guild); 93 | Call_PushCell(view_as(hJson)); 94 | Call_PushCell(data1); 95 | Call_Finish(); 96 | } 97 | 98 | delete bot; 99 | delete hJson; 100 | delete hData; 101 | delete fwd; 102 | } -------------------------------------------------------------------------------- /discord/ListenToChannel.sp: -------------------------------------------------------------------------------- 1 | public int Native_DiscordBot_StartTimer(Handle plugin, int numParams) { 2 | DiscordBot bot = GetNativeCell(1); 3 | DiscordChannel channel = GetNativeCell(2); 4 | Function func = GetNativeCell(3); 5 | 6 | Handle hObj = json_object(); 7 | json_object_set(hObj, "bot", bot); 8 | json_object_set(hObj, "channel", channel); 9 | 10 | Handle fwd = CreateForward(ET_Ignore, Param_Cell, Param_Cell, Param_Cell); 11 | AddToForward(fwd, plugin, func); 12 | 13 | json_object_set_new(hObj, "callback", json_integer(view_as(fwd))); 14 | 15 | GetMessages(hObj); 16 | } 17 | 18 | public void GetMessages(Handle hObject) { 19 | DiscordBot bot = view_as(json_object_get(hObject, "bot")); 20 | DiscordChannel channel = view_as(json_object_get(hObject, "channel")); 21 | //Handle fwd = view_as(json_object_get(hObject, "callback")); 22 | 23 | char channelID[32]; 24 | channel.GetID(channelID, sizeof(channelID)); 25 | 26 | char lastMessage[64]; 27 | channel.GetLastMessageID(lastMessage, sizeof(lastMessage)); 28 | 29 | char url[256]; 30 | FormatEx(url, sizeof(url), "channels/%s/messages?limit=%i&after=%s", channelID, 100, lastMessage); 31 | 32 | Handle request = PrepareRequest(bot, url, _, null, OnGetMessage); 33 | if(request == null) { 34 | delete bot; 35 | delete channel; 36 | CreateTimer(2.0, GetMessagesDelayed, hObject); 37 | return; 38 | } 39 | 40 | char route[128]; 41 | FormatEx(route, sizeof(route), "channels/%s", channelID); 42 | 43 | SteamWorks_SetHTTPRequestContextValue(request, hObject, UrlToDP(route)); 44 | 45 | delete bot; 46 | delete channel; 47 | 48 | DiscordSendRequest(request, route); 49 | } 50 | 51 | public Action GetMessagesDelayed(Handle timer, any data) { 52 | GetMessages(view_as(data)); 53 | } 54 | 55 | public Action CheckMessageTimer(Handle timer, any dpt) { 56 | GetMessages(view_as(dpt)); 57 | } 58 | 59 | public int OnGetMessage(Handle request, bool failure, int offset, int statuscode, any dp) { 60 | if(failure || statuscode != 200) { 61 | if(statuscode == 429 || statuscode == 500) { 62 | GetMessages(view_as(dp)); 63 | delete request; 64 | return; 65 | } 66 | LogError("[DISCORD] Couldn't Retrieve Messages - Fail %i %i", failure, statuscode); 67 | delete request; 68 | Handle fwd = view_as(JsonObjectGetInt(view_as(dp), "callback")); 69 | if(fwd != null) delete fwd; 70 | delete view_as(dp); 71 | return; 72 | } 73 | 74 | SteamWorks_GetHTTPResponseBodyCallback(request, OnGetMessage_Data, dp); 75 | delete request; 76 | } 77 | 78 | public int OnGetMessage_Data(const char[] data, any dpt) { 79 | Handle hObj = view_as(dpt); 80 | 81 | DiscordBot Bot = view_as(json_object_get(hObj, "bot")); 82 | DiscordChannel channel = view_as(json_object_get(hObj, "channel")); 83 | Handle fwd = view_as(JsonObjectGetInt(hObj, "callback")); 84 | 85 | if(!Bot.IsListeningToChannel(channel) || GetForwardFunctionCount(fwd) == 0) { 86 | delete Bot; 87 | delete channel; 88 | delete hObj; 89 | delete fwd; 90 | return; 91 | } 92 | 93 | Handle hJson = json_load(data); 94 | 95 | if(json_is_array(hJson)) { 96 | for(int i = json_array_size(hJson) - 1; i >= 0; i--) { 97 | Handle hObject = json_array_get(hJson, i); 98 | 99 | //The reason we find Channel for each message instead of global incase 100 | //Bot stops listening for the channel while we are still sending messages 101 | char channelID[32]; 102 | JsonObjectGetString(hObject, "channel_id", channelID, sizeof(channelID)); 103 | 104 | //Find Channel corresponding to Channel id 105 | //DiscordChannel Channel = Bot.GetListeningChannelByID(channelID); 106 | if(!Bot.IsListeningToChannelID(channelID)) { 107 | //Channel is no longer listed to, remove any handles & stop 108 | delete hObject; 109 | delete hJson; 110 | 111 | delete fwd; 112 | delete Bot; 113 | delete channel; 114 | delete hObj; 115 | return; 116 | } 117 | 118 | char id[32]; 119 | JsonObjectGetString(hObject, "id", id, sizeof(id)); 120 | 121 | if(i == 0) { 122 | channel.SetLastMessageID(id); 123 | } 124 | 125 | //Get info and fire forward 126 | if(fwd != null) { 127 | Call_StartForward(fwd); 128 | Call_PushCell(Bot); 129 | Call_PushCell(channel); 130 | Call_PushCell(view_as(hObject)); 131 | Call_Finish(); 132 | } 133 | 134 | delete hObject; 135 | } 136 | } 137 | 138 | CreateTimer(Bot.MessageCheckInterval, CheckMessageTimer, hObj); 139 | 140 | delete Bot; 141 | delete channel; 142 | 143 | 144 | delete hJson; 145 | } -------------------------------------------------------------------------------- /discord/MessageObject.sp: -------------------------------------------------------------------------------- 1 | public int Native_DiscordMessage_GetID(Handle plugin, int numParams) { 2 | Handle hJson = GetNativeCell(1); 3 | char buffer[64]; 4 | JsonObjectGetString(hJson, "id", buffer, sizeof(buffer)); 5 | SetNativeString(2, buffer, GetNativeCell(3)); 6 | } 7 | 8 | public int Native_DiscordMessage_IsPinned(Handle plugin, int numParams) { 9 | Handle hJson = GetNativeCell(1); 10 | return JsonObjectGetBool(hJson, "pinned"); 11 | } 12 | 13 | public int Native_DiscordMessage_GetAuthor(Handle plugin, int numParams) { 14 | Handle hJson = GetNativeCell(1); 15 | 16 | Handle hAuthor = json_object_get(hJson, "author"); 17 | 18 | DiscordUser user = view_as(CloneHandle(hAuthor, plugin)); 19 | delete hAuthor; 20 | 21 | return _:user; 22 | } 23 | 24 | public int Native_DiscordMessage_GetContent(Handle plugin, int numParams) { 25 | Handle hJson = GetNativeCell(1); 26 | static char buffer[2000]; 27 | JsonObjectGetString(hJson, "content", buffer, sizeof(buffer)); 28 | SetNativeString(2, buffer, GetNativeCell(3)); 29 | } 30 | 31 | public int Native_DiscordMessage_GetChannelID(Handle plugin, int numParams) { 32 | Handle hJson = GetNativeCell(1); 33 | char buffer[64]; 34 | JsonObjectGetString(hJson, "channel_id", buffer, sizeof(buffer)); 35 | SetNativeString(2, buffer, GetNativeCell(3)); 36 | } -------------------------------------------------------------------------------- /discord/SendMessage.sp: -------------------------------------------------------------------------------- 1 | public int Native_DiscordBot_SendMessageToChannel(Handle plugin, int numParams) { 2 | DiscordBot bot = GetNativeCell(1); 3 | char channel[32]; 4 | static char message[2048]; 5 | GetNativeString(2, channel, sizeof(channel)); 6 | GetNativeString(3, message, sizeof(message)); 7 | 8 | Function fCallback = GetNativeCell(4); 9 | any data = GetNativeCell(5); 10 | Handle fForward = null; 11 | if(fCallback != INVALID_FUNCTION) { 12 | fForward = CreateForward(ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_Cell); 13 | AddToForward(fForward, plugin, fCallback); 14 | } 15 | 16 | SendMessage(bot, channel, message, fForward, data); 17 | } 18 | 19 | public int Native_DiscordBot_SendMessage(Handle plugin, int numParams) { 20 | DiscordBot bot = GetNativeCell(1); 21 | 22 | DiscordChannel Channel = GetNativeCell(2); 23 | char channelID[32]; 24 | Channel.GetID(channelID, sizeof(channelID)); 25 | 26 | static char message[2048]; 27 | GetNativeString(3, message, sizeof(message)); 28 | 29 | Function fCallback = GetNativeCell(4); 30 | any data = GetNativeCell(5); 31 | Handle fForward = null; 32 | if(fCallback != INVALID_FUNCTION) { 33 | fForward = CreateForward(ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_Cell); 34 | AddToForward(fForward, plugin, fCallback); 35 | } 36 | 37 | SendMessage(bot, channelID, message, fForward, data); 38 | } 39 | 40 | public int Native_DiscordChannel_SendMessage(Handle plugin, int numParams) { 41 | DiscordChannel channel = view_as(GetNativeCell(1)); 42 | 43 | char channelID[32]; 44 | channel.GetID(channelID, sizeof(channelID)); 45 | 46 | DiscordBot bot = GetNativeCell(2); 47 | 48 | static char message[2048]; 49 | GetNativeString(3, message, sizeof(message)); 50 | 51 | Function fCallback = GetNativeCell(4); 52 | any data = GetNativeCell(5); 53 | Handle fForward = null; 54 | if(fCallback != INVALID_FUNCTION) { 55 | fForward = CreateForward(ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_Cell); 56 | AddToForward(fForward, plugin, fCallback); 57 | } 58 | 59 | SendMessage(bot, channelID, message, fForward, data); 60 | } 61 | 62 | static void SendMessage(DiscordBot bot, char[] channel, char[] message, Handle fForward, any data) { 63 | Handle hJson = json_object(); 64 | 65 | json_object_set_new(hJson, "content", json_string(message)); 66 | 67 | char url[64]; 68 | FormatEx(url, sizeof(url), "channels/%s/messages", channel); 69 | 70 | DataPack dpSafety = new DataPack(); 71 | WritePackCell(dpSafety, bot); 72 | WritePackString(dpSafety, channel); 73 | WritePackString(dpSafety, message); 74 | WritePackCell(dpSafety, fForward); 75 | WritePackCell(dpSafety, data); 76 | 77 | Handle request = PrepareRequest(bot, url, k_EHTTPMethodPOST, hJson, GetSendMessageData); 78 | if(request == null) { 79 | delete hJson; 80 | CreateTimer(2.0, SendMessageDelayed, dpSafety); 81 | return; 82 | } 83 | 84 | SteamWorks_SetHTTPRequestContextValue(request, dpSafety, UrlToDP(url)); 85 | 86 | DiscordSendRequest(request, url); 87 | } 88 | 89 | public Action SendMessageDelayed(Handle timer, any data) { 90 | DataPack dp = view_as(data); 91 | ResetPack(dp); 92 | 93 | DiscordBot bot = ReadPackCell(dp); 94 | 95 | char channel[32]; 96 | ReadPackString(dp, channel, sizeof(channel)); 97 | 98 | char message[2048]; 99 | ReadPackString(dp, message, sizeof(message)); 100 | 101 | Handle fForward = ReadPackCell(dp); 102 | any dataa = ReadPackCell(dp); 103 | 104 | delete dp; 105 | 106 | SendMessage(bot, channel, message, fForward, dataa); 107 | } 108 | 109 | public int GetSendMessageData(Handle request, bool failure, int offset, int statuscode, any dp) { 110 | if(failure || statuscode != 200) { 111 | if(statuscode == 429 || statuscode == 500) { 112 | ResetPack(dp); 113 | DiscordBot bot = ReadPackCell(dp); 114 | 115 | char channel[32]; 116 | ReadPackString(dp, channel, sizeof(channel)); 117 | 118 | char message[2048]; 119 | ReadPackString(dp, message, sizeof(message)); 120 | 121 | Handle fForward = ReadPackCell(dp); 122 | any data = ReadPackCell(dp); 123 | 124 | delete view_as(dp); 125 | 126 | SendMessage(bot, channel, message, fForward, data); 127 | 128 | delete request; 129 | return; 130 | } 131 | LogError("[DISCORD] Couldn't Send Message - Fail %i %i", failure, statuscode); 132 | delete request; 133 | delete view_as(dp); 134 | return; 135 | } 136 | delete request; 137 | delete view_as(dp); 138 | } -------------------------------------------------------------------------------- /discord/SendWebHook.sp: -------------------------------------------------------------------------------- 1 | public int Native_DiscordWebHook_Send(Handle plugin, int numParams) { 2 | DiscordWebHook hook = GetNativeCell(1); 3 | SendWebHook(view_as(hook)); 4 | } 5 | 6 | public void SendWebHook(DiscordWebHook hook) { 7 | if(!JsonObjectGetBool(hook, "__selfCopy", false)) { 8 | hook = view_as(json_deep_copy(hook)); 9 | json_object_set_new(hook, "__selfCopy", json_true()); 10 | } 11 | Handle hJson = hook.Data; 12 | 13 | char url[256]; 14 | hook.GetUrl(url, sizeof(url)); 15 | 16 | if(hook.SlackMode) { 17 | if(StrContains(url, "/slack") == -1) { 18 | Format(url, sizeof(url), "%s/slack", url); 19 | } 20 | 21 | RenameJsonObject(hJson, "content", "text"); 22 | RenameJsonObject(hJson, "embeds", "attachments"); 23 | 24 | Handle hAttachments = json_object_get(hJson, "attachments"); 25 | if(hAttachments != null) { 26 | if(json_is_array(hAttachments)) { 27 | for(int i = 0; i < json_array_size(hAttachments); i++) { 28 | Handle hEmbed = json_array_get(hAttachments, i); 29 | 30 | Handle hFields = json_object_get(hEmbed, "fields"); 31 | if(hFields) { 32 | if(json_is_array(hFields)) { 33 | for(int j = 0; j < json_array_size(hFields); j++) { 34 | Handle hField = json_array_get(hFields, j); 35 | RenameJsonObject(hField, "name", "title"); 36 | RenameJsonObject(hField, "inline", "short"); 37 | //json_array_set_new(hFields, j, hField); 38 | delete hField; 39 | } 40 | } 41 | 42 | //json_object_set_new(hEmbed, "fields", hFields); 43 | delete hFields; 44 | } 45 | 46 | //json_array_set_new(hAttachments, i, hEmbed); 47 | delete hEmbed; 48 | } 49 | } 50 | 51 | //json_object_set_new(hJson, "attachments", hAttachments); 52 | delete hAttachments; 53 | } 54 | } 55 | 56 | //Send 57 | DiscordRequest request = new DiscordRequest(url, k_EHTTPMethodPOST); 58 | request.SetCallbacks(HTTPCompleted, SendWebHookReceiveData); 59 | request.SetJsonBodyEx(hJson); 60 | //Handle request = PrepareRequestRaw(null, url, k_EHTTPMethodPOST, hJson, SendWebHookReceiveData); 61 | if(request == null) { 62 | CreateTimer(2.0, SendWebHookDelayed, hook); 63 | return; 64 | } 65 | 66 | //request.SetContextValue(hJson, UrlToDP(url)); 67 | DataPack pack = new DataPack(); 68 | pack.WriteCell(hJson); 69 | pack.WriteCell(view_as(hook)); 70 | request.SetContextValue(pack, UrlToDP(url)); 71 | 72 | //DiscordSendRequest(request, url); 73 | request.Send(url); 74 | } 75 | 76 | public Action SendWebHookDelayed(Handle timer, any data) { 77 | SendWebHook(view_as(data)); 78 | } 79 | 80 | public SendWebHookReceiveData(Handle request, bool failure, int offset, int statuscode, any datapack) { 81 | DataPack dp = view_as(datapack); 82 | dp.Reset(); 83 | Handle hJson = dp.ReadCell(); 84 | DiscordWebHook hook = dp.ReadCell(); 85 | delete dp; 86 | if(failure || (statuscode != 200 && statuscode != 204)) { 87 | if(statuscode == 400) { 88 | PrintToServer("BAD REQUEST"); 89 | SteamWorks_GetHTTPResponseBodyCallback(request, WebHookData, hJson); 90 | } 91 | 92 | if(statuscode == 429 || statuscode == 500) { 93 | SendWebHook(view_as(hook)); 94 | 95 | delete request; 96 | return; 97 | } 98 | LogError("[DISCORD] Couldn't Send Webhook - Fail %i %i", failure, statuscode); 99 | delete request; 100 | delete hJson; 101 | return; 102 | } 103 | delete request; 104 | delete hJson; 105 | } 106 | 107 | public int WebHookData(const char[] data, any dp) { 108 | PrintToServer("DATA RECE: %s", data); 109 | static char stringJson[16384]; 110 | stringJson[0] = '\0'; 111 | json_dump(view_as(dp), stringJson, sizeof(stringJson), 0, true); 112 | PrintToServer("DATA SENT: %s", stringJson); 113 | } 114 | -------------------------------------------------------------------------------- /discord/UserObject.sp: -------------------------------------------------------------------------------- 1 | public int Native_DiscordUser_GetID(Handle plugin, int numParams) { 2 | Handle hJson = GetNativeCell(1); 3 | char buffer[64]; 4 | JsonObjectGetString(hJson, "id", buffer, sizeof(buffer)); 5 | SetNativeString(2, buffer, GetNativeCell(3)); 6 | } 7 | 8 | public int Native_DiscordUser_GetUsername(Handle plugin, int numParams) { 9 | Handle hJson = GetNativeCell(1); 10 | char buffer[64]; 11 | JsonObjectGetString(hJson, "username", buffer, sizeof(buffer)); 12 | SetNativeString(2, buffer, GetNativeCell(3)); 13 | } 14 | 15 | public int Native_DiscordUser_GetDiscriminator(Handle plugin, int numParams) { 16 | Handle hJson = GetNativeCell(1); 17 | char buffer[16]; 18 | JsonObjectGetString(hJson, "discriminator", buffer, sizeof(buffer)); 19 | SetNativeString(2, buffer, GetNativeCell(3)); 20 | } 21 | 22 | public int Native_DiscordUser_GetAvatar(Handle plugin, int numParams) { 23 | Handle hJson = GetNativeCell(1); 24 | char buffer[256]; 25 | JsonObjectGetString(hJson, "avatar", buffer, sizeof(buffer)); 26 | SetNativeString(2, buffer, GetNativeCell(3)); 27 | } 28 | 29 | public int Native_DiscordUser_GetEmail(Handle plugin, int numParams) { 30 | Handle hJson = GetNativeCell(1); 31 | char buffer[64]; 32 | JsonObjectGetString(hJson, "email", buffer, sizeof(buffer)); 33 | SetNativeString(2, buffer, GetNativeCell(3)); 34 | } 35 | 36 | public int Native_DiscordUser_IsVerified(Handle plugin, int numParams) { 37 | Handle hJson = GetNativeCell(1); 38 | return JsonObjectGetBool(hJson, "verified"); 39 | } 40 | 41 | public int Native_DiscordUser_IsBot(Handle plugin, int numParams) { 42 | Handle hJson = GetNativeCell(1); 43 | return JsonObjectGetBool(hJson, "bot"); 44 | } -------------------------------------------------------------------------------- /discord/deletemessage.sp: -------------------------------------------------------------------------------- 1 | public int Native_DiscordBot_DeleteMessageID(Handle plugin, int numParams) { 2 | DiscordBot bot = GetNativeCell(1); 3 | 4 | char channelid[64]; 5 | GetNativeString(2, channelid, sizeof(channelid)); 6 | 7 | char msgid[64]; 8 | GetNativeString(3, msgid, sizeof(msgid)); 9 | 10 | Function fCallback = GetNativeCell(4); 11 | any data = GetNativeCell(5); 12 | 13 | DataPack dp = CreateDataPack(); 14 | WritePackCell(dp, bot); 15 | WritePackString(dp, channelid); 16 | WritePackString(dp, msgid); 17 | WritePackCell(dp, plugin); 18 | WritePackFunction(dp, fCallback); 19 | WritePackCell(dp, data); 20 | 21 | ThisDeleteMessage(bot, channelid, msgid, dp); 22 | } 23 | 24 | public int Native_DiscordBot_DeleteMessage(Handle plugin, int numParams) { 25 | DiscordBot bot = GetNativeCell(1); 26 | 27 | char channelid[64]; 28 | DiscordChannel channel = GetNativeCell(2); 29 | channel.GetID(channelid, sizeof(channelid)); 30 | 31 | char msgid[64]; 32 | DiscordMessage msg = GetNativeCell(3); 33 | msg.GetID(msgid, sizeof(msgid)); 34 | 35 | Function fCallback = GetNativeCell(4); 36 | any data = GetNativeCell(5); 37 | 38 | DataPack dp = CreateDataPack(); 39 | WritePackCell(dp, bot); 40 | WritePackString(dp, channelid); 41 | WritePackString(dp, msgid); 42 | WritePackCell(dp, plugin); 43 | WritePackFunction(dp, fCallback); 44 | WritePackCell(dp, data); 45 | 46 | ThisDeleteMessage(bot, channelid, msgid, dp); 47 | } 48 | 49 | static void ThisDeleteMessage(DiscordBot bot, char[] channelid, char[] msgid, DataPack dp) { 50 | char url[64]; 51 | FormatEx(url, sizeof(url), "channels/%s/messages/%s", channelid, msgid); 52 | 53 | Handle request = PrepareRequest(bot, url, k_EHTTPMethodDELETE, null, MessageDeletedResp); 54 | if(request == null) { 55 | CreateTimer(2.0, ThisDeleteMessageDelayed, dp); 56 | return; 57 | } 58 | 59 | SteamWorks_SetHTTPRequestContextValue(request, dp, UrlToDP(url)); 60 | 61 | DiscordSendRequest(request, url); 62 | } 63 | 64 | public Action ThisDeleteMessageDelayed(Handle timer, any data) { 65 | DataPack dp = view_as(data); 66 | ResetPack(dp); 67 | 68 | DiscordBot bot = ReadPackCell(dp); 69 | 70 | char channelid[32]; 71 | ReadPackString(dp, channelid, sizeof(channelid)); 72 | 73 | char msgid[32]; 74 | ReadPackString(dp, msgid, sizeof(msgid)); 75 | 76 | ThisDeleteMessage(bot, channelid, msgid, dp); 77 | } 78 | 79 | public int MessageDeletedResp(Handle request, bool failure, int offset, int statuscode, any dp) { 80 | if(failure || statuscode != 204) { 81 | if(statuscode == 429 || statuscode == 500) { 82 | ResetPack(dp); 83 | DiscordBot bot = ReadPackCell(dp); 84 | 85 | char channelid[32]; 86 | ReadPackString(dp, channelid, sizeof(channelid)); 87 | 88 | char msgid[32]; 89 | ReadPackString(dp, msgid, sizeof(msgid)); 90 | 91 | ThisDeleteMessage(bot, channelid, msgid, view_as(dp)); 92 | 93 | delete request; 94 | return; 95 | } 96 | LogError("[DISCORD] Couldn't delete message - Fail %i %i", failure, statuscode); 97 | delete request; 98 | delete view_as(dp); 99 | return; 100 | } 101 | 102 | ResetPack(dp); 103 | DiscordBot bot = ReadPackCell(dp); 104 | 105 | char channelid[32]; 106 | ReadPackString(dp, channelid, sizeof(channelid)); 107 | 108 | char msgid[32]; 109 | ReadPackString(dp, msgid, sizeof(msgid)); 110 | 111 | Handle plugin = view_as(ReadPackCell(dp)); 112 | Function func = ReadPackFunction(dp); 113 | any pluginData = ReadPackCell(dp); 114 | 115 | Handle fForward = INVALID_HANDLE; 116 | if(func != INVALID_FUNCTION) { 117 | fForward = CreateForward(ET_Ignore, Param_Cell, Param_Cell); 118 | AddToForward(fForward, plugin, func); 119 | 120 | Call_StartForward(fForward); 121 | Call_PushCell(bot); 122 | Call_PushCell(pluginData); 123 | Call_Finish(); 124 | delete fForward; 125 | } 126 | 127 | delete view_as(dp); 128 | delete request; 129 | } -------------------------------------------------------------------------------- /discord/reactions.sp: -------------------------------------------------------------------------------- 1 | public int Native_DiscordBot_AddReaction(Handle plugin, int numParams) { 2 | DiscordBot bot = GetNativeCell(1); 3 | 4 | char channel[32]; 5 | GetNativeString(2, channel, sizeof(channel)); 6 | 7 | char msgid[64]; 8 | GetNativeString(3, msgid, sizeof(msgid)); 9 | 10 | char emoji[128]; 11 | GetNativeString(4, emoji, sizeof(emoji)); 12 | 13 | AddReaction(bot, channel, msgid, emoji); 14 | } 15 | 16 | public int Native_DiscordBot_DeleteReaction(Handle plugin, int numParams) { 17 | DiscordBot bot = GetNativeCell(1); 18 | 19 | char channel[32]; 20 | GetNativeString(2, channel, sizeof(channel)); 21 | 22 | char msgid[64]; 23 | GetNativeString(3, msgid, sizeof(msgid)); 24 | 25 | char emoji[128]; 26 | GetNativeString(4, emoji, sizeof(emoji)); 27 | 28 | char user[128]; 29 | GetNativeString(5, user, sizeof(user)); 30 | 31 | DeleteReaction(bot, channel, msgid, emoji, user); 32 | } 33 | 34 | public int Native_DiscordBot_GetReaction(Handle plugin, int numParams) { 35 | DiscordBot bot = GetNativeCell(1); 36 | 37 | char channel[32]; 38 | GetNativeString(2, channel, sizeof(channel)); 39 | 40 | char msgid[64]; 41 | GetNativeString(3, msgid, sizeof(msgid)); 42 | 43 | char emoji[128]; 44 | GetNativeString(4, emoji, sizeof(emoji)); 45 | 46 | OnGetReactions fCallback = GetNativeCell(5); 47 | Handle fForward = null; 48 | if(fCallback != INVALID_FUNCTION) { 49 | fForward = CreateForward(ET_Ignore, Param_Cell, Param_Cell, Param_String, Param_String, Param_String, Param_String, Param_Cell); 50 | AddToForward(fForward, plugin, fCallback); 51 | } 52 | 53 | any data = GetNativeCell(6); 54 | 55 | GetReaction(bot, channel, msgid, emoji, fForward, data); 56 | } 57 | 58 | ///channels/{channel.id}/messages/{message.id}/reactions/{emoji}/@me 59 | public void AddReaction(DiscordBot bot, char[] channel, char[] messageid, char[] emoji) { 60 | char url[256]; 61 | FormatEx(url, sizeof(url), "channels/%s/messages/%s/reactions/%s/@me", channel, messageid, emoji); 62 | 63 | Handle request = PrepareRequest(bot, url, k_EHTTPMethodPUT, null, AddReactionReceiveData); 64 | 65 | DataPack dp = new DataPack(); 66 | WritePackCell(dp, bot); 67 | WritePackString(dp, channel); 68 | WritePackString(dp, messageid); 69 | WritePackString(dp, emoji); 70 | 71 | if(request == dp) { 72 | CreateTimer(2.0, AddReactionDelayed, dp); 73 | return; 74 | } 75 | 76 | char route[128]; 77 | FormatEx(route, sizeof(route), "channels/%s/messages/msgid/reactions", channel); 78 | 79 | SteamWorks_SetHTTPRequestContextValue(request, dp, UrlToDP(route)); 80 | 81 | DiscordSendRequest(request, url); 82 | } 83 | 84 | public Action AddReactionDelayed(Handle timer, any data) { 85 | DataPack dp = view_as(data); 86 | 87 | DiscordBot bot = ReadPackCell(dp); 88 | char channel[64]; 89 | char messageid[64]; 90 | char emoji[64]; 91 | ReadPackString(dp, channel, sizeof(channel)); 92 | ReadPackString(dp, messageid, sizeof(messageid)); 93 | ReadPackString(dp, emoji, sizeof(emoji)); 94 | delete dp; 95 | 96 | AddReaction(bot, channel, messageid, emoji); 97 | } 98 | 99 | public AddReactionReceiveData(Handle request, bool failure, int offset, int statuscode, any data) { 100 | if(failure || statuscode != 204) { 101 | if(statuscode == 429 || statuscode == 500) { 102 | 103 | DataPack dp = view_as(data); 104 | 105 | DiscordBot bot = ReadPackCell(dp); 106 | char channel[64]; 107 | char messageid[64]; 108 | char emoji[64]; 109 | ReadPackString(dp, channel, sizeof(channel)); 110 | ReadPackString(dp, messageid, sizeof(messageid)); 111 | ReadPackString(dp, emoji, sizeof(emoji)); 112 | delete dp; 113 | 114 | AddReaction(bot, channel, messageid, emoji); 115 | 116 | delete request; 117 | return; 118 | } 119 | LogError("[DISCORD] Couldn't Add Reaction - Fail %i %i", failure, statuscode); 120 | delete request; 121 | delete view_as(data); 122 | delete view_as(data); 123 | return; 124 | } 125 | delete request; 126 | delete view_as(data); 127 | } 128 | 129 | ///channels/{channel.id}/messages/{message.id}/reactions/{emoji}/{user.id} 130 | public void DeleteReaction(DiscordBot bot, char[] channel, char[] messageid, char[] emoji, char[] userid) { 131 | char url[256]; 132 | 133 | if(StrEqual(userid, "@all")) { 134 | FormatEx(url, sizeof(url), "channels/%s/messages/%s/reactions/%s", channel, messageid, emoji); 135 | }else { 136 | FormatEx(url, sizeof(url), "channels/%s/messages/%s/reactions/%s/%s", channel, messageid, emoji, userid); 137 | } 138 | 139 | Handle request = PrepareRequest(bot, url, k_EHTTPMethodDELETE, null, DeleteReactionReceiveData); 140 | 141 | DataPack dp = new DataPack(); 142 | WritePackCell(dp, bot); 143 | WritePackString(dp, channel); 144 | WritePackString(dp, messageid); 145 | WritePackString(dp, emoji); 146 | WritePackString(dp, userid); 147 | 148 | if(request == dp) { 149 | CreateTimer(2.0, DeleteReactionDelayed, dp); 150 | return; 151 | } 152 | 153 | char route[128]; 154 | FormatEx(route, sizeof(route), "channels/%s/messages/msgid/reactions", channel); 155 | 156 | SteamWorks_SetHTTPRequestContextValue(request, dp, UrlToDP(route)); 157 | 158 | DiscordSendRequest(request, url); 159 | } 160 | 161 | public Action DeleteReactionDelayed(Handle timer, any data) { 162 | DataPack dp = view_as(data); 163 | 164 | DiscordBot bot = ReadPackCell(dp); 165 | char channel[64]; 166 | char messageid[64]; 167 | char emoji[64]; 168 | char userid[64]; 169 | ReadPackString(dp, channel, sizeof(channel)); 170 | ReadPackString(dp, messageid, sizeof(messageid)); 171 | ReadPackString(dp, emoji, sizeof(emoji)); 172 | ReadPackString(dp, userid, sizeof(userid)); 173 | delete dp; 174 | 175 | DeleteReaction(bot, channel, messageid, emoji, userid); 176 | } 177 | 178 | public DeleteReactionReceiveData(Handle request, bool failure, int offset, int statuscode, any data) { 179 | if(failure || statuscode != 204) { 180 | if(statuscode == 429 || statuscode == 500) { 181 | 182 | DataPack dp = view_as(data); 183 | 184 | DiscordBot bot = ReadPackCell(dp); 185 | char channel[64]; 186 | char messageid[64]; 187 | char emoji[64]; 188 | char userid[64]; 189 | ReadPackString(dp, channel, sizeof(channel)); 190 | ReadPackString(dp, messageid, sizeof(messageid)); 191 | ReadPackString(dp, emoji, sizeof(emoji)); 192 | ReadPackString(dp, userid, sizeof(userid)); 193 | delete dp; 194 | 195 | DeleteReaction(bot, channel, messageid, emoji, userid); 196 | 197 | delete request; 198 | return; 199 | } 200 | LogError("[DISCORD] Couldn't Delete Reaction - Fail %i %i", failure, statuscode); 201 | delete request; 202 | delete view_as(data); 203 | return; 204 | } 205 | delete request; 206 | delete view_as(data); 207 | } 208 | 209 | public void GetReaction(DiscordBot bot, char[] channel, char[] messageid, char[] emoji, Handle fForward, any data) { 210 | char url[256]; 211 | FormatEx(url, sizeof(url), "channels/%s/messages/%s/reactions/%s", channel, messageid, emoji); 212 | 213 | Handle request = PrepareRequest(bot, url, k_EHTTPMethodGET, null, GetReactionReceiveData); 214 | 215 | DataPack dp = new DataPack(); 216 | WritePackCell(dp, bot); 217 | WritePackString(dp, channel); 218 | WritePackString(dp, messageid); 219 | WritePackString(dp, emoji); 220 | WritePackCell(dp, fForward); 221 | WritePackCell(dp, data); 222 | 223 | if(request == dp) { 224 | CreateTimer(2.0, GetReactionDelayed, dp); 225 | return; 226 | } 227 | 228 | char route[128]; 229 | FormatEx(route, sizeof(route), "channels/%s/messages/msgid/reactions", channel); 230 | 231 | SteamWorks_SetHTTPRequestContextValue(request, dp, UrlToDP(route)); 232 | 233 | DiscordSendRequest(request, url); 234 | } 235 | 236 | public Action GetReactionDelayed(Handle timer, any data) { 237 | DataPack dp = view_as(data); 238 | 239 | DiscordBot bot = ReadPackCell(dp); 240 | char channel[64]; 241 | char messageid[64]; 242 | char emoji[64]; 243 | ReadPackString(dp, channel, sizeof(channel)); 244 | ReadPackString(dp, messageid, sizeof(messageid)); 245 | ReadPackString(dp, emoji, sizeof(emoji)); 246 | Handle fForward = ReadPackCell(dp); 247 | any addData = ReadPackCell(dp); 248 | delete dp; 249 | 250 | GetReaction(bot, channel, messageid, emoji, fForward, addData); 251 | } 252 | 253 | public GetReactionReceiveData(Handle request, bool failure, int offset, int statuscode, any data) { 254 | if(failure || statuscode != 204) { 255 | if(statuscode == 429 || statuscode == 500) { 256 | 257 | DataPack dp = view_as(data); 258 | 259 | DiscordBot bot = ReadPackCell(dp); 260 | char channel[64]; 261 | char messageid[64]; 262 | char emoji[64]; 263 | ReadPackString(dp, channel, sizeof(channel)); 264 | ReadPackString(dp, messageid, sizeof(messageid)); 265 | ReadPackString(dp, emoji, sizeof(emoji)); 266 | Handle fForward = ReadPackCell(dp); 267 | any addData = ReadPackCell(dp); 268 | delete dp; 269 | 270 | GetReaction(bot, channel, messageid, emoji, fForward, addData); 271 | 272 | delete request; 273 | return; 274 | } 275 | LogError("[DISCORD] Couldn't Delete Reaction - Fail %i %i", failure, statuscode); 276 | delete request; 277 | delete view_as(data); 278 | return; 279 | } 280 | 281 | SteamWorks_GetHTTPResponseBodyCallback(request, GetReactionsData, data); 282 | 283 | delete request; 284 | } 285 | 286 | public int GetReactionsData(const char[] data, any datapack) { 287 | DataPack dp = view_as(datapack); 288 | 289 | DiscordBot bot = ReadPackCell(dp); 290 | char channel[64]; 291 | char messageid[64]; 292 | char emoji[64]; 293 | ReadPackString(dp, channel, sizeof(channel)); 294 | ReadPackString(dp, messageid, sizeof(messageid)); 295 | ReadPackString(dp, emoji, sizeof(emoji)); 296 | Handle fForward = ReadPackCell(dp); 297 | any addData = ReadPackCell(dp); 298 | delete dp; 299 | 300 | Handle hJson = json_load(data); 301 | 302 | ArrayList alUsers = new ArrayList(); 303 | 304 | if(json_is_array(hJson)) { 305 | for(int i = 0; i < json_array_size(hJson); i++) { 306 | DiscordUser user = view_as(json_array_get(hJson, i)); 307 | alUsers.Push(user); 308 | } 309 | } 310 | delete hJson; 311 | 312 | if(fForward != null) { 313 | Call_StartForward(fForward); 314 | Call_PushCell(bot); 315 | Call_PushCell(alUsers); 316 | Call_PushString(channel); 317 | Call_PushString(messageid); 318 | Call_PushString(emoji); 319 | Call_PushCell(addData); 320 | Call_Finish(); 321 | } 322 | 323 | for(int i = 0; i < alUsers.Length; i++) { 324 | DiscordUser user = alUsers.Get(i); 325 | delete user; 326 | } 327 | delete alUsers; 328 | } -------------------------------------------------------------------------------- /discord_api.smx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cruze03/sourcemod-discord/fdf074ca1144babcac5ab0f2425697d9ef4ea727/discord_api.smx -------------------------------------------------------------------------------- /discord_api.sp: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | #pragma dynamic 25000 3 | 4 | #define PLUGIN_VERSION "0.1.107" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "discord/DiscordRequest.sp" 12 | #include "discord/SendMessage.sp" 13 | #include "discord/GetGuilds.sp" 14 | #include "discord/GetGuildChannels.sp" 15 | #include "discord/ListenToChannel.sp" 16 | #include "discord/SendWebHook.sp" 17 | #include "discord/reactions.sp" 18 | #include "discord/UserObject.sp" 19 | #include "discord/MessageObject.sp" 20 | #include "discord/GuildMembers.sp" 21 | #include "discord/GuildRole.sp" 22 | #include "discord/deletemessage.sp" 23 | 24 | //For rate limitation 25 | Handle hRateLimit = null; 26 | Handle hRateReset = null; 27 | Handle hRateLeft = null; 28 | 29 | public Plugin myinfo = { 30 | name = "Discord API", 31 | author = "Deathknife", 32 | description = "", 33 | version = PLUGIN_VERSION, 34 | url = "" 35 | }; 36 | 37 | public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) { 38 | CreateNative("DiscordBot.GetToken", Native_DiscordBot_Token_Get); 39 | 40 | //SendMessage.sp 41 | CreateNative("DiscordBot.SendMessage", Native_DiscordBot_SendMessage); 42 | CreateNative("DiscordBot.SendMessageToChannelID", Native_DiscordBot_SendMessageToChannel); 43 | CreateNative("DiscordChannel.SendMessage", Native_DiscordChannel_SendMessage); 44 | 45 | //deletemessage.sp 46 | CreateNative("DiscordBot.DeleteMessageID", Native_DiscordBot_DeleteMessageID); 47 | CreateNative("DiscordBot.DeleteMessage", Native_DiscordBot_DeleteMessage); 48 | 49 | //ListenToChannel.sp 50 | CreateNative("DiscordBot.StartTimer", Native_DiscordBot_StartTimer); 51 | 52 | //GetGuilds.sp 53 | CreateNative("DiscordBot.GetGuilds", Native_DiscordBot_GetGuilds); 54 | //GetGuildChannels.sp 55 | CreateNative("DiscordBot.GetGuildChannels", Native_DiscordBot_GetGuildChannels); 56 | //GuildRole.sp 57 | CreateNative("DiscordBot.GetGuildRoles", Native_DiscordBot_GetGuildRoles); 58 | 59 | //reactions.sp 60 | CreateNative("DiscordBot.AddReactionID", Native_DiscordBot_AddReaction); 61 | CreateNative("DiscordBot.DeleteReactionID", Native_DiscordBot_DeleteReaction); 62 | CreateNative("DiscordBot.GetReactionID", Native_DiscordBot_GetReaction); 63 | 64 | //GuildMembers.sp 65 | CreateNative("DiscordBot.GetGuildMembers", Native_DiscordBot_GetGuildMembers); 66 | CreateNative("DiscordBot.GetGuildMembersAll", Native_DiscordBot_GetGuildMembersAll); 67 | 68 | //CreateNative("DiscordChannel.Destroy", Native_DiscordChannel_Destroy); 69 | 70 | //SendWebHook.sp 71 | CreateNative("DiscordWebHook.Send", Native_DiscordWebHook_Send); 72 | //CreateNative("DiscordWebHook.AddField", Native_DiscordWebHook_AddField); 73 | //CreateNative("DiscordWebHook.DeleteFields", Native_DiscordWebHook_DeleteFields); 74 | 75 | //UserObject.sp 76 | CreateNative("DiscordUser.GetID", Native_DiscordUser_GetID); 77 | CreateNative("DiscordUser.GetUsername", Native_DiscordUser_GetUsername); 78 | CreateNative("DiscordUser.GetDiscriminator", Native_DiscordUser_GetDiscriminator); 79 | CreateNative("DiscordUser.GetAvatar", Native_DiscordUser_GetAvatar); 80 | CreateNative("DiscordUser.IsVerified", Native_DiscordUser_IsVerified); 81 | CreateNative("DiscordUser.GetEmail", Native_DiscordUser_GetEmail); 82 | CreateNative("DiscordUser.IsBot", Native_DiscordUser_IsBot); 83 | 84 | //MessageObject.sp 85 | CreateNative("DiscordMessage.GetID", Native_DiscordMessage_GetID); 86 | CreateNative("DiscordMessage.IsPinned", Native_DiscordMessage_IsPinned); 87 | CreateNative("DiscordMessage.GetAuthor", Native_DiscordMessage_GetAuthor); 88 | CreateNative("DiscordMessage.GetContent", Native_DiscordMessage_GetContent); 89 | CreateNative("DiscordMessage.GetChannelID", Native_DiscordMessage_GetChannelID); 90 | 91 | RegPluginLibrary("discord-api"); 92 | 93 | return APLRes_Success; 94 | } 95 | 96 | public void OnPluginStart() { 97 | hRateLeft = new StringMap(); 98 | hRateReset = new StringMap(); 99 | hRateLimit = new StringMap(); 100 | } 101 | 102 | public int Native_DiscordBot_Token_Get(Handle plugin, int numParams) { 103 | DiscordBot bot = GetNativeCell(1); 104 | static char token[196]; 105 | JsonObjectGetString(bot, "token", token, sizeof(token)); 106 | SetNativeString(2, token, GetNativeCell(3)); 107 | } 108 | 109 | stock void BuildAuthHeader(Handle request, DiscordBot Bot) { 110 | static char buffer[256]; 111 | static char token[196]; 112 | JsonObjectGetString(Bot, "token", token, sizeof(token)); 113 | FormatEx(buffer, sizeof(buffer), "Bot %s", token); 114 | SteamWorks_SetHTTPRequestHeaderValue(request, "Authorization", buffer); 115 | } 116 | 117 | 118 | stock Handle PrepareRequest(DiscordBot bot, char[] url, EHTTPMethod method=k_EHTTPMethodGET, Handle hJson=null, SteamWorksHTTPDataReceived DataReceived = INVALID_FUNCTION, SteamWorksHTTPRequestCompleted RequestCompleted = INVALID_FUNCTION) { 119 | static char stringJson[16384]; 120 | stringJson[0] = '\0'; 121 | if(hJson != null) { 122 | json_dump(hJson, stringJson, sizeof(stringJson), 0, true); 123 | } 124 | 125 | //Format url 126 | static char turl[128]; 127 | FormatEx(turl, sizeof(turl), "https://discord.com/api/%s", url); 128 | 129 | Handle request = SteamWorks_CreateHTTPRequest(method, turl); 130 | if(request == null) { 131 | return null; 132 | } 133 | 134 | if(bot != null) { 135 | BuildAuthHeader(request, bot); 136 | } 137 | 138 | SteamWorks_SetHTTPRequestRawPostBody(request, "application/json; charset=UTF-8", stringJson, strlen(stringJson)); 139 | 140 | SteamWorks_SetHTTPRequestNetworkActivityTimeout(request, 30); 141 | 142 | if(RequestCompleted == INVALID_FUNCTION) { 143 | //I had some bugs previously where it wouldn't send request and return code 0 if I didn't set request completed. 144 | //This is just a safety then, my issue could have been something else and I will test more later on 145 | RequestCompleted = HTTPCompleted; 146 | } 147 | 148 | if(DataReceived == INVALID_FUNCTION) { 149 | //Need to close the request handle 150 | DataReceived = HTTPDataReceive; 151 | } 152 | 153 | SteamWorks_SetHTTPCallbacks(request, RequestCompleted, HeadersReceived, DataReceived); 154 | if(hJson != null) delete hJson; 155 | 156 | return request; 157 | } 158 | 159 | stock Handle PrepareRequestRaw(DiscordBot bot, char[] url, EHTTPMethod method=k_EHTTPMethodGET, Handle hJson=null, SteamWorksHTTPDataReceived DataReceived = INVALID_FUNCTION, SteamWorksHTTPRequestCompleted RequestCompleted = INVALID_FUNCTION) { 160 | static char stringJson[16384]; 161 | stringJson[0] = '\0'; 162 | if(hJson != null) { 163 | json_dump(hJson, stringJson, sizeof(stringJson), 0, true); 164 | } 165 | 166 | Handle request = SteamWorks_CreateHTTPRequest(method, url); 167 | if(request == null) { 168 | return null; 169 | } 170 | 171 | if(bot != null) { 172 | BuildAuthHeader(request, bot); 173 | } 174 | 175 | SteamWorks_SetHTTPRequestRawPostBody(request, "application/json; charset=UTF-8", stringJson, strlen(stringJson)); 176 | 177 | SteamWorks_SetHTTPRequestNetworkActivityTimeout(request, 30); 178 | 179 | if(RequestCompleted == INVALID_FUNCTION) { 180 | //I had some bugs previously where it wouldn't send request and return code 0 if I didn't set request completed. 181 | //This is just a safety then, my issue could have been something else and I will test more later on 182 | RequestCompleted = HTTPCompleted; 183 | } 184 | 185 | if(DataReceived == INVALID_FUNCTION) { 186 | //Need to close the request handle 187 | DataReceived = HTTPDataReceive; 188 | } 189 | 190 | SteamWorks_SetHTTPCallbacks(request, RequestCompleted, HeadersReceived, DataReceived); 191 | if(hJson != null) delete hJson; 192 | 193 | return request; 194 | } 195 | 196 | public int HTTPCompleted(Handle request, bool failure, bool requestSuccessful, EHTTPStatusCode statuscode, any data, any data2) { 197 | } 198 | 199 | public int HTTPDataReceive(Handle request, bool failure, int offset, int statuscode, any dp) { 200 | delete request; 201 | } 202 | 203 | public int HeadersReceived(Handle request, bool failure, any data, any datapack) { 204 | DataPack dp = view_as(datapack); 205 | if(failure) { 206 | delete dp; 207 | return; 208 | } 209 | 210 | char xRateLimit[16]; 211 | char xRateLeft[16]; 212 | char xRateReset[32]; 213 | 214 | bool exists = false; 215 | 216 | exists = SteamWorks_GetHTTPResponseHeaderValue(request, "X-RateLimit-Limit", xRateLimit, sizeof(xRateLimit)); 217 | exists = SteamWorks_GetHTTPResponseHeaderValue(request, "X-RateLimit-Remaining", xRateLeft, sizeof(xRateLeft)); 218 | exists = SteamWorks_GetHTTPResponseHeaderValue(request, "X-RateLimit-Reset", xRateReset, sizeof(xRateReset)); 219 | 220 | //Get url 221 | char route[128]; 222 | ResetPack(dp); 223 | ReadPackString(dp, route, sizeof(route)); 224 | delete dp; 225 | 226 | int reset = StringToInt(xRateReset); 227 | if(reset > GetTime() + 3) { 228 | reset = GetTime() + 3; 229 | } 230 | 231 | if(exists) { 232 | SetTrieValue(hRateReset, route, reset); 233 | SetTrieValue(hRateLeft, route, StringToInt(xRateLeft)); 234 | SetTrieValue(hRateLimit, route, StringToInt(xRateLimit)); 235 | }else { 236 | SetTrieValue(hRateReset, route, -1); 237 | SetTrieValue(hRateLeft, route, -1); 238 | SetTrieValue(hRateLimit, route, -1); 239 | } 240 | } 241 | 242 | /* 243 | This is rate limit imposing for per-route basis. Doesn't support global limit yet. 244 | */ 245 | public void DiscordSendRequest(Handle request, const char[] route) { 246 | //Check for reset 247 | int time = GetTime(); 248 | int resetTime; 249 | 250 | int defLimit = 0; 251 | if(!GetTrieValue(hRateLimit, route, defLimit)) { 252 | defLimit = 1; 253 | } 254 | 255 | bool exists = GetTrieValue(hRateReset, route, resetTime); 256 | 257 | if(!exists) { 258 | SetTrieValue(hRateReset, route, GetTime() + 5); 259 | SetTrieValue(hRateLeft, route, defLimit - 1); 260 | SteamWorks_SendHTTPRequest(request); 261 | return; 262 | } 263 | 264 | if(time == -1) { 265 | //No x-rate-limit send 266 | SteamWorks_SendHTTPRequest(request); 267 | return; 268 | } 269 | 270 | if(time > resetTime) { 271 | SetTrieValue(hRateLeft, route, defLimit - 1); 272 | SteamWorks_SendHTTPRequest(request); 273 | return; 274 | }else { 275 | int left; 276 | GetTrieValue(hRateLeft, route, left); 277 | if(left == 0) { 278 | float remaining = 1.0; 279 | Handle dp = new DataPack(); 280 | WritePackCell(dp, request); 281 | WritePackString(dp, route); 282 | CreateTimer(remaining, SendRequestAgain, dp); 283 | }else { 284 | left--; 285 | SetTrieValue(hRateLeft, route, left); 286 | SteamWorks_SendHTTPRequest(request); 287 | } 288 | } 289 | } 290 | 291 | public Handle UrlToDP(char[] url) { 292 | DataPack dp = new DataPack(); 293 | WritePackString(dp, url); 294 | return dp; 295 | } 296 | 297 | public Action SendRequestAgain(Handle timer, any dp) { 298 | ResetPack(dp); 299 | Handle request = ReadPackCell(dp); 300 | char route[128]; 301 | ReadPackString(dp, route, sizeof(route)); 302 | delete view_as(dp); 303 | DiscordSendRequest(request, route); 304 | } 305 | 306 | stock bool RenameJsonObject(Handle hJson, char[] key, char[] toKey) { 307 | Handle hObject = json_object_get(hJson, key); 308 | if(hObject != null) { 309 | json_object_set_new(hJson, toKey, hObject); 310 | json_object_del(hJson, key); 311 | return true; 312 | } 313 | return false; 314 | } 315 | -------------------------------------------------------------------------------- /examples/discord_test.sp: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #define PLUGIN_VERSION "1.10" 4 | 5 | #include 6 | #include 7 | 8 | #define BOT_TOKEN "" 9 | #define WEBHOOK "" 10 | 11 | public Plugin myinfo = 12 | { 13 | name = "Discord Test", 14 | author = "Deathknife", 15 | description = "", 16 | version = PLUGIN_VERSION, 17 | url = "" 18 | }; 19 | 20 | DiscordBot gBot; 21 | 22 | public void OnPluginStart() { 23 | RegConsoleCmd("sm_getguilds", Cmd_GetGuilds); 24 | RegConsoleCmd("sm_recreatebot", Cmd_RecreateBot); 25 | RegConsoleCmd("sm_webhooktest", Cmd_Webhook); 26 | RegConsoleCmd("sm_sendmsg", Cmd_SendMsg); 27 | RegConsoleCmd("sm_getroles", Cmd_GetRoles); 28 | } 29 | 30 | public void OnAllPluginsLoaded() { 31 | gBot = new DiscordBot(BOT_TOKEN); 32 | } 33 | 34 | public Action Cmd_Webhook(int client, int argc) { 35 | DiscordWebHook hook = new DiscordWebHook(WEBHOOK); 36 | hook.SlackMode = true; 37 | 38 | hook.SetContent("@here"); 39 | hook.SetUsername("Server"); 40 | 41 | MessageEmbed Embed = new MessageEmbed(); 42 | 43 | Embed.SetColor("#ff2222"); 44 | Embed.SetTitle("Testing WebHook"); 45 | Embed.AddField("Field1", "Test1", true); 46 | Embed.AddField("abc def", "deef", true); 47 | 48 | hook.Embed(Embed); 49 | 50 | hook.Send(); 51 | delete hook; 52 | 53 | hook = new DiscordWebHook(""); 54 | hook.SetUsername("Testing"); 55 | hook.SlackMode = false; 56 | hook.SetContent("Testing 1 2 3"); 57 | hook.Send(); 58 | delete hook; 59 | } 60 | 61 | public Action Cmd_GetRoles(int client, int argc) { 62 | if(client == 0) 63 | { 64 | ReplyToCommand(client, "[SM] This command cannot be used from console."); 65 | return Plugin_Handled; 66 | } 67 | 68 | gBot.GetGuilds(GuildListGetRoles, _, GetClientUserId(client)); 69 | ReplyToCommand(client, "Trying!"); 70 | return Plugin_Handled; 71 | } 72 | 73 | public void GuildListGetRoles(DiscordBot bot, char[] id, char[] name, char[] icon, bool owner, int permissions, any data) { 74 | int client = GetClientOfUserId(data); 75 | if(client > 0 && IsClientConnected(client) && IsClientInGame(client)) { 76 | bot.GetGuildRoles(id, OnGetRoles, data); 77 | } 78 | } 79 | 80 | public void OnGetRoles(DiscordBot bot, char[] guild, RoleList roles, any data) { 81 | PrintToChatAll("%i a", data); 82 | int client = GetClientOfUserId(data); 83 | if(client > 0 && IsClientConnected(client) && IsClientInGame(client)) { 84 | PrintToConsole(client, "Roles for guild %s", guild); 85 | for(int i = 0; i < roles.Size; i++) { 86 | Role role = roles.Get(i); 87 | char id[64]; 88 | char name[64]; 89 | role.GetID(id, sizeof(id)); 90 | role.GetName(name, sizeof(name)); 91 | PrintToConsole(client, "Role %s %s", id, name); 92 | } 93 | } 94 | } 95 | 96 | public Action Cmd_GetGuilds(int client, int argc) { 97 | if(client == 0) 98 | { 99 | ReplyToCommand(client, "[SM] This command cannot be used from console."); 100 | return Plugin_Handled; 101 | } 102 | 103 | gBot.GetGuilds(GuildList, GuildListAll, GetClientUserId(client)); 104 | ReplyToCommand(client, "Trying!"); 105 | return Plugin_Handled; 106 | } 107 | 108 | public Action Cmd_RecreateBot(int client, int argc) { 109 | if(gBot != null) { 110 | gBot.StopListening(); 111 | delete gBot; 112 | } 113 | gBot = new DiscordBot(BOT_TOKEN); 114 | ReplyToCommand(client, "Recreated"); 115 | } 116 | 117 | public void GuildList(DiscordBot bot, char[] id, char[] name, char[] icon, bool owner, int permissions, any data) { 118 | int client = GetClientOfUserId(data); 119 | if(client > 0 && IsClientConnected(client) && IsClientInGame(client)) { 120 | PrintToConsole(client, "Guild [%s] [%s] [%s] [%i] [%i]", id, name, icon, owner, permissions); 121 | gBot.GetGuildChannels(id, ChannelList, INVALID_FUNCTION, data); 122 | } 123 | } 124 | 125 | public void ChannelList(DiscordBot bot, char[] guild, DiscordChannel Channel, any data) { 126 | int client = GetClientOfUserId(data); 127 | if(client > 0 && IsClientConnected(client) && IsClientInGame(client)) { 128 | char name[32]; 129 | char id[32]; 130 | Channel.GetID(id, sizeof(id)); 131 | Channel.GetName(name, sizeof(name)); 132 | PrintToConsole(client, "Channel for Guild(%s) - [%s] [%s]", guild, id, name); 133 | 134 | if(Channel.IsText) { 135 | //Send a message with all ways 136 | //gBot.SendMessage(Channel, "Sending message with DiscordBot.SendMessage"); 137 | //gBot.SendMessageToChannelID(id, "Sending message with DiscordBot.SendMessageToChannelID"); 138 | //Channel.SendMessage(gBot, "Sending message with DiscordChannel.SendMessage"); 139 | 140 | gBot.StartListeningToChannel(Channel, OnMessage); 141 | } 142 | } 143 | } 144 | 145 | public void OnMessage(DiscordBot Bot, DiscordChannel Channel, DiscordMessage message) { 146 | char sMessage[2048]; 147 | message.GetContent(sMessage, sizeof(sMessage)); 148 | 149 | char sAuthor[128]; 150 | message.GetAuthor().GetUsername(sAuthor, sizeof(sAuthor)); 151 | 152 | PrintToChatAll("[DISCORD] %s: %s", sAuthor, sMessage); 153 | 154 | if(StrEqual(sMessage, "Ping", false)) { 155 | gBot.SendMessage(Channel, "Pong!"); 156 | } 157 | } 158 | 159 | public void GuildListAll(DiscordBot bot, ArrayList Alid, ArrayList Alname, ArrayList Alicon, ArrayList Alowner, ArrayList Alpermissions, any data) { 160 | int client = GetClientOfUserId(data); 161 | if(client > 0 && IsClientConnected(client) && IsClientInGame(client)) { 162 | char id[32]; 163 | char name[64]; 164 | char icon[128]; 165 | bool owner; 166 | int permissions; 167 | 168 | PrintToConsole(client, "Dumping Guilds from arraylist"); 169 | 170 | for(int i = 0; i < Alid.Length; i++) { 171 | GetArrayString(Alid, i, id, sizeof(id)); 172 | GetArrayString(Alname, i, name, sizeof(name)); 173 | GetArrayString(Alicon, i, icon, sizeof(icon)); 174 | owner = GetArrayCell(Alowner, i); 175 | permissions = GetArrayCell(Alpermissions, i); 176 | PrintToConsole(client, "Guild: [%s] [%s] [%s] [%i] [%i]", id, name, icon, owner, permissions); 177 | } 178 | } 179 | } 180 | 181 | public Action Cmd_SendMsg(int client, int argc) { 182 | if(client == 0) 183 | { 184 | ReplyToCommand(client, "[SM] This command cannot be used from console."); 185 | return Plugin_Handled; 186 | } 187 | 188 | if(argc != 2) 189 | { 190 | ReplyToCommand(client, "[SM] Usage: sm_sendmsg ."); 191 | return Plugin_Handled; 192 | } 193 | 194 | char channelid[64]; 195 | GetCmdArg(1, channelid, sizeof(channelid)); 196 | 197 | char message[256]; 198 | GetCmdArg(2, message, sizeof(message)); 199 | 200 | gBot.SendMessageToChannelID(channelid, message, OnMessageSent, GetClientUserId(client)); 201 | 202 | return Plugin_Handled; 203 | } 204 | 205 | public void OnMessageSent(DiscordBot bot, char[] channel, DiscordMessage message, any data) 206 | { 207 | int client = GetClientOfUserId(data); 208 | ReplyToCommand(client, "Message sent!"); 209 | } -------------------------------------------------------------------------------- /examples/outdated/README.md: -------------------------------------------------------------------------------- 1 | # discord_test.sp 2 | On the command: `sm_getguilds` / `!getguilds` the plugin will list all guilds and channels in the client console. It will hook into every channel and print any messages in discord channel to the server console. If the message is `Ping` it will reply with `Pong`. `sm_recreatebot` will delete the bot and create it again(for testing purposes) 3 | 4 | Not recommended to use this plugin on live server. 5 | 6 | # discord_announcement.sp 7 | The plugin will hook into any channels with the name of `server-announcement` and print any messages sent in that channel to all players on servers with the `[Announcement]` prefix. 8 | 9 | Should be fine to have this on a live server. 10 | 11 | # discord_calladmin.sp 12 | The plugin finds all channels with the name of `call-admin` and stores them. When a client types `!calladmin` it will send a message to all those channels. 13 | 14 | Should be fine to have this on a live server. -------------------------------------------------------------------------------- /examples/outdated/discord_announcement.sp: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #define PLUGIN_VERSION "1.00" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | public Plugin myinfo = { 10 | name = "Announcements from Discord", 11 | author = "Deathknife", 12 | description = "", 13 | version = PLUGIN_VERSION, 14 | url = "" 15 | }; 16 | 17 | DiscordBot gBot = null; 18 | 19 | public void OnPluginStart() { 20 | // 21 | } 22 | 23 | public OnAllPluginsLoaded() { 24 | //Create bot with a token 25 | gBot = new DiscordBot(""); 26 | 27 | //Check for messages every 5 seconds. Default is 1 second. Since this is announcement, time accuracy is not necessary 28 | gBot.MessageCheckInterval = 5.0; 29 | 30 | //Get all guilds then channels to find any channel with the name of server-announcement 31 | gBot.GetGuilds(GuildList); 32 | } 33 | 34 | public void GuildList(DiscordBot bot, char[] id, char[] name, char[] icon, bool owner, int permissions, any data) { 35 | //Retrieve all channels for the guild 36 | bot.GetGuildChannels(id, ChannelList); 37 | } 38 | 39 | public void ChannelList(DiscordBot bot, char[] guild, DiscordChannel Channel, any data) { 40 | //Verify that the channel is a text channel 41 | if(Channel.IsText) { 42 | //Get name of channel 43 | char name[32]; 44 | Channel.GetName(name, sizeof(name)); 45 | 46 | //Compare name of channel to 'server-announcement' 47 | if(StrEqual(name, "server-announcement", false)) { 48 | //Start listening to channel 49 | bot.StartListeningToChannel(Channel, OnMessage); 50 | } 51 | } 52 | } 53 | 54 | public void OnMessage(DiscordBot Bot, DiscordChannel Channel, const char[] message) { 55 | //Received a message, print it out. 56 | CPrintToChatAll("{green}[Announcement]{normal} %s", message); 57 | } -------------------------------------------------------------------------------- /examples/outdated/discord_calladmin.sp: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #define PLUGIN_VERSION "1.00" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | public Plugin myinfo = { 11 | name = "Call Admin to Discord", 12 | author = "Deathknife", 13 | description = "", 14 | version = PLUGIN_VERSION, 15 | url = "" 16 | }; 17 | 18 | DiscordBot gBot = null; 19 | ArrayList CallAdminChannels = null; 20 | 21 | ConVar gHostPort; 22 | ConVar gHostname; 23 | 24 | //To prevent spam 25 | int LastUsage[MAXPLAYERS + 1]; 26 | 27 | public void OnPluginStart() { 28 | RegConsoleCmd("sm_calladmin", Cmd_CallAdmin); 29 | 30 | CallAdminChannels = new ArrayList(); 31 | 32 | gHostname = FindConVar("hostname"); 33 | gHostPort = FindConVar("hostport"); 34 | } 35 | 36 | public OnAllPluginsLoaded() { 37 | //Create bot with a token 38 | gBot = new DiscordBot(""); 39 | 40 | //Get all guilds then channels to find any channel with the name of call-admin 41 | gBot.GetGuilds(GuildList); 42 | } 43 | 44 | public Action Cmd_CallAdmin(int client, int argc) { 45 | //Add minimum 60 seconds interval before calling an admin again 46 | if(GetTime() < LastUsage[client] + 60) { 47 | CReplyToCommand(client, "{red}Please wait before calling an admin again!"); 48 | return Plugin_Continue; 49 | } 50 | 51 | //Format Message to send 52 | char message[256]; 53 | 54 | char name[32]; 55 | GetClientName(client, name, sizeof(name)); 56 | //Replace ` with nothing as we will use `NAME` in discord message 57 | ReplaceString(name, sizeof(name), "`", ""); 58 | 59 | char authid[32]; 60 | GetClientAuthId(client, AuthId_Steam2, authid, sizeof(authid)); 61 | 62 | char ip[64]; 63 | GetIP(ip, sizeof(ip)); 64 | 65 | char hostname[64]; 66 | GetConVarString(gHostname, hostname, sizeof(hostname)); 67 | 68 | FormatEx(message, sizeof(message), "`%s` (`%s`) has called an Admin on %s\nConnect: steam://connect/%s", name, authid, hostname, ip); 69 | 70 | //Send Message to all channels we stored 71 | for(int i = 0; i < CallAdminChannels.Length; i++) { 72 | DiscordChannel Channel = CallAdminChannels.Get(i); 73 | Channel.SendMessage(gBot, message); 74 | } 75 | CReplyToCommand(client, "{green}Called an Admin"); 76 | LastUsage[client] = GetTime(); 77 | return Plugin_Continue; 78 | } 79 | 80 | public void OnClientPutInServer(int client) { 81 | LastUsage[client] = 0; 82 | } 83 | 84 | public void GuildList(DiscordBot bot, char[] id, char[] name, char[] icon, bool owner, int permissions, any data) { 85 | //Retrieve all channels for the guild 86 | //PrintToServer("Guild %s", name); 87 | bot.GetGuildChannels(id, ChannelList); 88 | } 89 | 90 | public void ChannelList(DiscordBot bot, char[] guild, DiscordChannel Channel, any data) { 91 | //Verify that the channel is a text channel 92 | if(Channel.IsText) { 93 | //Get name of channel 94 | char name[32]; 95 | Channel.GetName(name, sizeof(name)); 96 | //PrintToServer("Channel name %s", name); 97 | 98 | //Compare name of channel to 'call-admin' 99 | if(StrEqual(name, "call-admin", false)) { 100 | PrintToServer("Added Call Admin Channel"); 101 | //Store The Channel 102 | 103 | //Duplicate the Channel handle as the 'Channel' handle is closed after the forwards are called 104 | DiscordChannel newChannel = view_as(CloneHandle(Channel)); 105 | 106 | //Store it into array 107 | CallAdminChannels.Push(newChannel); 108 | } 109 | } 110 | } 111 | 112 | //Stores IP into buffer using SteamWorks 113 | stock void GetIP(char[] buffer, int maxlength) { 114 | int ip[4]; 115 | SteamWorks_GetPublicIP(ip); 116 | strcopy(buffer, maxlength, ""); 117 | 118 | FormatEx(buffer, maxlength, "%d.%d.%d.%d:%d", ip[0], ip[1], ip[2], ip[3], gHostPort.IntValue); 119 | } 120 | -------------------------------------------------------------------------------- /examples/outdated/discord_test.sp: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #define PLUGIN_VERSION "1.10" 4 | 5 | #include 6 | #include 7 | 8 | #define BOT_TOKEN "INSERT TOKEN HERE" 9 | 10 | public Plugin myinfo = 11 | { 12 | name = "Discord Test", 13 | author = "Deathknife", 14 | description = "", 15 | version = PLUGIN_VERSION, 16 | url = "" 17 | }; 18 | 19 | DiscordBot gBot; 20 | 21 | public void OnPluginStart() { 22 | RegConsoleCmd("sm_getguilds", Cmd_GetGuilds); 23 | RegConsoleCmd("sm_recreatebot", Cmd_RecreateBot); 24 | RegConsoleCmd("sm_webhooktest", Cmd_Webhook); 25 | } 26 | 27 | public void OnPluginEnd() { 28 | if(gBot != null) { 29 | gBot.DestroyData(); 30 | delete gBot; 31 | } 32 | } 33 | 34 | public void OnAllPluginsLoaded() { 35 | gBot = new DiscordBot(BOT_TOKEN); 36 | } 37 | 38 | public Action Cmd_Webhook(int client, int argc) { 39 | DiscordWebHook hook = new DiscordWebHook("https://ptb.discord.com/api/webhooks/265660968086929419/z3_F8CEGNu1Wtdygv4v0Pg4YRBA8QxgmzFKqjkEleSf2BOuQ8Xz7Ub05ku2j-O2vofy7"); 40 | hook.SlackMode = true; 41 | 42 | hook.SetUsername("Server"); 43 | hook.SetColor("#ff2222"); 44 | hook.SetTitle("Testing WebHook"); 45 | hook.SetContent("@here"); 46 | hook.AddField("Field1", "Test1", true); 47 | hook.AddField("abc def", "deef", true); 48 | hook.Send(); 49 | delete hook; 50 | 51 | hook = new DiscordWebHook("https://ptb.discord.com/api/webhooks/265660968086929419/z3_F8CEGNu1Wtdygv4v0Pg4YRBA8QxgmzFKqjkEleSf2BOuQ8Xz7Ub05ku2j-O2vofy7"); 52 | hook.SetUsername("Testing"); 53 | hook.SlackMode = false; 54 | hook.SetContent("Testing 1 2 3"); 55 | hook.Send(); 56 | delete hook; 57 | } 58 | 59 | 60 | public Action Cmd_GetGuilds(int client, int argc) { 61 | gBot.GetGuilds(GuildList, GuildListAll, GetClientUserId(client)); 62 | ReplyToCommand(client, "Trying!"); 63 | return Plugin_Handled; 64 | } 65 | 66 | public Action Cmd_RecreateBot(int client, int argc) { 67 | if(gBot != null) { 68 | gBot.DestroyData(); 69 | delete gBot; 70 | } 71 | gBot = new DiscordBot(BOT_TOKEN); 72 | ReplyToCommand(client, "Recreated"); 73 | } 74 | 75 | public void GuildList(DiscordBot bot, char[] id, char[] name, char[] icon, bool owner, int permissions, any data) { 76 | int client = GetClientOfUserId(data); 77 | if(client > 0 && IsClientConnected(client) && IsClientInGame(client)) { 78 | PrintToConsole(client, "Guild [%s] [%s] [%s] [%i] [%i]", id, name, icon, owner, permissions); 79 | gBot.GetGuildChannels(id, ChannelList, INVALID_FUNCTION, data); 80 | } 81 | } 82 | 83 | public void ChannelList(DiscordBot bot, char[] guild, DiscordChannel Channel, any data) { 84 | int client = GetClientOfUserId(data); 85 | if(client > 0 && IsClientConnected(client) && IsClientInGame(client)) { 86 | char name[32]; 87 | char id[32]; 88 | Channel.GetID(id, sizeof(id)); 89 | Channel.GetName(name, sizeof(name)); 90 | PrintToConsole(client, "Channel for Guild(%s) - [%s] [%s]", guild, id, name); 91 | 92 | if(Channel.IsText) { 93 | //Send a message with all ways 94 | gBot.SendMessage(Channel, "Sending message with DiscordBot.SendMessage"); 95 | gBot.SendMessageToChannelID(id, "Sending message with DiscordBot.SendMessageToChannelID"); 96 | Channel.SendMessage(gBot, "Sending message with DiscordChannel.SendMessage"); 97 | 98 | gBot.StartListeningToChannel(Channel, OnMessage); 99 | } 100 | } 101 | } 102 | 103 | public void OnMessage(DiscordBot Bot, DiscordChannel Channel, const char[] message) { 104 | PrintToServer("Message from discord: %s", message); 105 | 106 | if(StrEqual(message, "Ping", false)) { 107 | gBot.SendMessage(Channel, "Pong!"); 108 | } 109 | } 110 | 111 | public void GuildListAll(DiscordBot bot, ArrayList Alid, ArrayList Alname, ArrayList Alicon, ArrayList Alowner, ArrayList Alpermissions, any data) { 112 | int client = GetClientOfUserId(data); 113 | if(client > 0 && IsClientConnected(client) && IsClientInGame(client)) { 114 | char id[32]; 115 | char name[64]; 116 | char icon[128]; 117 | bool owner; 118 | int permissions; 119 | 120 | PrintToConsole(client, "Dumping Guilds from arraylist"); 121 | 122 | for(int i = 0; i < Alid.Length; i++) { 123 | GetArrayString(Alid, i, id, sizeof(id)); 124 | GetArrayString(Alname, i, name, sizeof(name)); 125 | GetArrayString(Alicon, i, icon, sizeof(icon)); 126 | owner = GetArrayCell(Alowner, i); 127 | permissions = GetArrayCell(Alpermissions, i); 128 | PrintToConsole(client, "Guild: [%s] [%s] [%s] [%i] [%i]", id, name, icon, owner, permissions); 129 | } 130 | } 131 | } 132 | 133 | public Action Cmd_SendMsg(int client, int argc) { 134 | // 135 | } -------------------------------------------------------------------------------- /include/csgocolors.inc: -------------------------------------------------------------------------------- 1 | /************************************************************************** 2 | * * 3 | * Colored Chat Functions * 4 | * Author: exvel, Editor: Popoklopsi, Powerlord, Bara * 5 | * Version: 1.1.3 * 6 | * * 7 | **************************************************************************/ 8 | 9 | 10 | #if defined _colors_included 11 | #endinput 12 | #endif 13 | #define _colors_included 14 | 15 | #define MAX_MESSAGE_LENGTH 250 16 | #define MAX_COLORS 16 17 | 18 | #define SERVER_INDEX 0 19 | #define NO_INDEX -1 20 | #define NO_PLAYER -2 21 | 22 | enum Colors 23 | { 24 | Color_Default = 0, 25 | Color_Darkred, 26 | Color_Pink, 27 | Color_Green, 28 | Color_Lightgreen, 29 | Color_Lime, 30 | Color_Red, 31 | Color_Grey, 32 | Color_Olive, 33 | Color_A, 34 | Color_Lightblue, 35 | Color_Blue, 36 | Color_D, 37 | Color_Purple, 38 | Color_Darkrange, 39 | Color_Orange 40 | } 41 | 42 | /* Colors' properties */ 43 | new String:CTag[][] = {"{normal}", "{darkred}", "{pink}", "{green}", "{lightgreen}", "{lime}", "{red}", "{grey}", "{olive}", "{a}", "{lightblue}", "{blue}", "{d}", "{purple}", "{darkorange}", "{orange}"}; 44 | new String:CTagCode[][] = {"\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", "\x08", "\x09", "\x0A", "\x0B", "\x0C", "\x0D", "\x0E", "\x0F", "\x10"}; 45 | new bool:CTagReqSayText2[] = {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}; 46 | new bool:CEventIsHooked = false; 47 | new bool:CSkipList[MAXPLAYERS+1] = {false,...}; 48 | 49 | /* Game default profile */ 50 | new bool:CProfile_Colors[] = {true, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false}; 51 | new CProfile_TeamIndex[] = {NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX, NO_INDEX}; 52 | new bool:CProfile_SayText2 = false; 53 | 54 | /** 55 | * Prints a message to a specific client in the chat area. 56 | * Supports color tags. 57 | * 58 | * @param client Client index. 59 | * @param szMessage Message (formatting rules). 60 | * @return No return 61 | * 62 | * On error/Errors: If the client is not connected an error will be thrown. 63 | */ 64 | stock CPrintToChat(client, const String:szMessage[], any:...) 65 | { 66 | if (client <= 0 || client > MaxClients) 67 | ThrowError("Invalid client index %d", client); 68 | 69 | if (!IsClientInGame(client)) 70 | ThrowError("Client %d is not in game", client); 71 | 72 | decl String:szBuffer[MAX_MESSAGE_LENGTH]; 73 | decl String:szCMessage[MAX_MESSAGE_LENGTH]; 74 | 75 | SetGlobalTransTarget(client); 76 | 77 | Format(szBuffer, sizeof(szBuffer), "\x01%s", szMessage); 78 | VFormat(szCMessage, sizeof(szCMessage), szBuffer, 3); 79 | 80 | new index = CFormat(szCMessage, sizeof(szCMessage)); 81 | 82 | if (index == NO_INDEX) 83 | PrintToChat(client, "%s", szCMessage); 84 | else 85 | CSayText2(client, index, szCMessage); 86 | } 87 | 88 | stock CReplyToCommand(client, const String:szMessage[], any:...) 89 | { 90 | 91 | decl String:szCMessage[MAX_MESSAGE_LENGTH]; 92 | VFormat(szCMessage, sizeof(szCMessage), szMessage, 3); 93 | 94 | if (client == 0) 95 | { 96 | CRemoveTags(szCMessage, sizeof(szCMessage)); 97 | PrintToServer("%s", szCMessage); 98 | } 99 | else if (GetCmdReplySource() == SM_REPLY_TO_CONSOLE) 100 | { 101 | CRemoveTags(szCMessage, sizeof(szCMessage)); 102 | PrintToConsole(client, "%s", szCMessage); 103 | } 104 | else 105 | { 106 | CPrintToChat(client, "%s", szCMessage); 107 | } 108 | } 109 | 110 | 111 | /** 112 | * Prints a message to all clients in the chat area. 113 | * Supports color tags. 114 | * 115 | * @param client Client index. 116 | * @param szMessage Message (formatting rules) 117 | * @return No return 118 | */ 119 | stock CPrintToChatAll(const String:szMessage[], any:...) 120 | { 121 | decl String:szBuffer[MAX_MESSAGE_LENGTH]; 122 | 123 | for (new i = 1; i <= MaxClients; i++) 124 | { 125 | if (IsClientInGame(i) && !IsFakeClient(i) && !CSkipList[i]) 126 | { 127 | SetGlobalTransTarget(i); 128 | VFormat(szBuffer, sizeof(szBuffer), szMessage, 2); 129 | 130 | CPrintToChat(i, "%s", szBuffer); 131 | } 132 | 133 | CSkipList[i] = false; 134 | } 135 | } 136 | 137 | /** 138 | * Prints a message to a specific client in the chat area. 139 | * Supports color tags and teamcolor tag. 140 | * 141 | * @param client Client index. 142 | * @param author Author index whose color will be used for teamcolor tag. 143 | * @param szMessage Message (formatting rules). 144 | * @return No return 145 | * 146 | * On error/Errors: If the client or author are not connected an error will be thrown. 147 | */ 148 | stock CPrintToChatEx(client, author, const String:szMessage[], any:...) 149 | { 150 | if (client <= 0 || client > MaxClients) 151 | ThrowError("Invalid client index %d", client); 152 | 153 | if (!IsClientInGame(client)) 154 | ThrowError("Client %d is not in game", client); 155 | 156 | if (author < 0 || author > MaxClients) 157 | ThrowError("Invalid client index %d", author); 158 | 159 | decl String:szBuffer[MAX_MESSAGE_LENGTH]; 160 | decl String:szCMessage[MAX_MESSAGE_LENGTH]; 161 | 162 | SetGlobalTransTarget(client); 163 | 164 | Format(szBuffer, sizeof(szBuffer), "\x01%s", szMessage); 165 | VFormat(szCMessage, sizeof(szCMessage), szBuffer, 4); 166 | 167 | new index = CFormat(szCMessage, sizeof(szCMessage), author); 168 | 169 | if (index == NO_INDEX) 170 | PrintToChat(client, "%s", szCMessage); 171 | else 172 | CSayText2(client, author, szCMessage); 173 | } 174 | 175 | /** 176 | * Prints a message to all clients in the chat area. 177 | * Supports color tags and teamcolor tag. 178 | * 179 | * @param author Author index whos color will be used for teamcolor tag. 180 | * @param szMessage Message (formatting rules). 181 | * @return No return 182 | * 183 | * On error/Errors: If the author is not connected an error will be thrown. 184 | */ 185 | stock CPrintToChatAllEx(author, const String:szMessage[], any:...) 186 | { 187 | if (author < 0 || author > MaxClients) 188 | ThrowError("Invalid client index %d", author); 189 | 190 | if (!IsClientInGame(author)) 191 | ThrowError("Client %d is not in game", author); 192 | 193 | decl String:szBuffer[MAX_MESSAGE_LENGTH]; 194 | 195 | for (new i = 1; i <= MaxClients; i++) 196 | { 197 | if (IsClientInGame(i) && !IsFakeClient(i) && !CSkipList[i]) 198 | { 199 | SetGlobalTransTarget(i); 200 | VFormat(szBuffer, sizeof(szBuffer), szMessage, 3); 201 | 202 | CPrintToChatEx(i, author, "%s", szBuffer); 203 | } 204 | 205 | CSkipList[i] = false; 206 | } 207 | } 208 | 209 | /** 210 | * Removes color tags from the string. 211 | * 212 | * @param szMessage String. 213 | * @return No return 214 | */ 215 | stock CRemoveTags(String:szMessage[], maxlength) 216 | { 217 | for (new i = 0; i < MAX_COLORS; i++) 218 | ReplaceString(szMessage, maxlength, CTag[i], "", false); 219 | 220 | ReplaceString(szMessage, maxlength, "{teamcolor}", "", false); 221 | } 222 | 223 | /** 224 | * Checks whether a color is allowed or not 225 | * 226 | * @param tag Color Tag. 227 | * @return True when color is supported, otherwise false 228 | */ 229 | stock CColorAllowed(Colors:color) 230 | { 231 | if (!CEventIsHooked) 232 | { 233 | CSetupProfile(); 234 | 235 | CEventIsHooked = true; 236 | } 237 | 238 | return CProfile_Colors[color]; 239 | } 240 | 241 | /** 242 | * Replace the color with another color 243 | * Handle with care! 244 | * 245 | * @param color color to replace. 246 | * @param newColor color to replace with. 247 | * @noreturn 248 | */ 249 | stock CReplaceColor(Colors:color, Colors:newColor) 250 | { 251 | if (!CEventIsHooked) 252 | { 253 | CSetupProfile(); 254 | 255 | CEventIsHooked = true; 256 | } 257 | 258 | CProfile_Colors[color] = CProfile_Colors[newColor]; 259 | CProfile_TeamIndex[color] = CProfile_TeamIndex[newColor]; 260 | 261 | CTagReqSayText2[color] = CTagReqSayText2[newColor]; 262 | Format(CTagCode[color], sizeof(CTagCode[]), CTagCode[newColor]) 263 | } 264 | 265 | /** 266 | * This function should only be used right in front of 267 | * CPrintToChatAll or CPrintToChatAllEx and it tells 268 | * to those funcions to skip specified client when printing 269 | * message to all clients. After message is printed client will 270 | * no more be skipped. 271 | * 272 | * @param client Client index 273 | * @return No return 274 | */ 275 | stock CSkipNextClient(client) 276 | { 277 | if (client <= 0 || client > MaxClients) 278 | ThrowError("Invalid client index %d", client); 279 | 280 | CSkipList[client] = true; 281 | } 282 | 283 | /** 284 | * Replaces color tags in a string with color codes 285 | * 286 | * @param szMessage String. 287 | * @param maxlength Maximum length of the string buffer. 288 | * @return Client index that can be used for SayText2 author index 289 | * 290 | * On error/Errors: If there is more then one team color is used an error will be thrown. 291 | */ 292 | stock CFormat(String:szMessage[], maxlength, author=NO_INDEX) 293 | { 294 | decl String:szGameName[30]; 295 | 296 | GetGameFolderName(szGameName, sizeof(szGameName)); 297 | 298 | /* Hook event for auto profile setup on map start */ 299 | if (!CEventIsHooked) 300 | { 301 | CSetupProfile(); 302 | HookEvent("server_spawn", CEvent_MapStart, EventHookMode_PostNoCopy); 303 | 304 | CEventIsHooked = true; 305 | } 306 | 307 | new iRandomPlayer = NO_INDEX; 308 | 309 | // On CS:GO set invisible precolor 310 | if (StrEqual(szGameName, "csgo", false)) 311 | Format(szMessage, maxlength, " \x01\x0B\x01%s", szMessage); 312 | 313 | /* If author was specified replace {teamcolor} tag */ 314 | if (author != NO_INDEX) 315 | { 316 | if (CProfile_SayText2) 317 | { 318 | ReplaceString(szMessage, maxlength, "{teamcolor}", "\x03", false); 319 | 320 | iRandomPlayer = author; 321 | } 322 | /* If saytext2 is not supported by game replace {teamcolor} with green tag */ 323 | else 324 | ReplaceString(szMessage, maxlength, "{teamcolor}", CTagCode[Color_Green], false); 325 | } 326 | else 327 | ReplaceString(szMessage, maxlength, "{teamcolor}", "", false); 328 | 329 | /* For other color tags we need a loop */ 330 | for (new i = 0; i < MAX_COLORS; i++) 331 | { 332 | /* If tag not found - skip */ 333 | if (StrContains(szMessage, CTag[i], false) == -1) 334 | continue; 335 | 336 | /* If tag is not supported by game replace it with green tag */ 337 | else if (!CProfile_Colors[i]) 338 | ReplaceString(szMessage, maxlength, CTag[i], CTagCode[Color_Green], false); 339 | 340 | /* If tag doesn't need saytext2 simply replace */ 341 | else if (!CTagReqSayText2[i]) 342 | ReplaceString(szMessage, maxlength, CTag[i], CTagCode[i], false); 343 | 344 | /* Tag needs saytext2 */ 345 | else 346 | { 347 | /* If saytext2 is not supported by game replace tag with green tag */ 348 | if (!CProfile_SayText2) 349 | ReplaceString(szMessage, maxlength, CTag[i], CTagCode[Color_Green], false); 350 | 351 | /* Game supports saytext2 */ 352 | else 353 | { 354 | /* If random player for tag wasn't specified replace tag and find player */ 355 | if (iRandomPlayer == NO_INDEX) 356 | { 357 | /* Searching for valid client for tag */ 358 | iRandomPlayer = CFindRandomPlayerByTeam(CProfile_TeamIndex[i]); 359 | 360 | /* If player not found replace tag with green color tag */ 361 | if (iRandomPlayer == NO_PLAYER) 362 | ReplaceString(szMessage, maxlength, CTag[i], CTagCode[Color_Green], false); 363 | 364 | /* If player was found simply replace */ 365 | else 366 | ReplaceString(szMessage, maxlength, CTag[i], CTagCode[i], false); 367 | 368 | } 369 | /* If found another team color tag throw error */ 370 | else 371 | { 372 | //ReplaceString(szMessage, maxlength, CTag[i], ""); 373 | ThrowError("Using two team colors in one message is not allowed"); 374 | } 375 | } 376 | 377 | } 378 | } 379 | 380 | return iRandomPlayer; 381 | } 382 | 383 | /** 384 | * Founds a random player with specified team 385 | * 386 | * @param color_team Client team. 387 | * @return Client index or NO_PLAYER if no player found 388 | */ 389 | stock CFindRandomPlayerByTeam(color_team) 390 | { 391 | if (color_team == SERVER_INDEX) 392 | return 0; 393 | else 394 | { 395 | for (new i = 1; i <= MaxClients; i++) 396 | { 397 | if (IsClientInGame(i) && GetClientTeam(i) == color_team) 398 | return i; 399 | } 400 | } 401 | 402 | return NO_PLAYER; 403 | } 404 | 405 | /** 406 | * Sends a SayText2 usermessage to a client 407 | * 408 | * @param szMessage Client index 409 | * @param maxlength Author index 410 | * @param szMessage Message 411 | * @return No return. 412 | */ 413 | stock CSayText2(client, author, const String:szMessage[]) 414 | { 415 | new Handle:hBuffer = StartMessageOne("SayText2", client, USERMSG_RELIABLE|USERMSG_BLOCKHOOKS); 416 | 417 | if(GetFeatureStatus(FeatureType_Native, "GetUserMessageType") == FeatureStatus_Available && GetUserMessageType() == UM_Protobuf) 418 | { 419 | PbSetInt(hBuffer, "ent_idx", author); 420 | PbSetBool(hBuffer, "chat", true); 421 | PbSetString(hBuffer, "msg_name", szMessage); 422 | PbAddString(hBuffer, "params", ""); 423 | PbAddString(hBuffer, "params", ""); 424 | PbAddString(hBuffer, "params", ""); 425 | PbAddString(hBuffer, "params", ""); 426 | } 427 | else 428 | { 429 | BfWriteByte(hBuffer, author); 430 | BfWriteByte(hBuffer, true); 431 | BfWriteString(hBuffer, szMessage); 432 | } 433 | 434 | EndMessage(); 435 | } 436 | 437 | /** 438 | * Creates game color profile 439 | * This function must be edited if you want to add more games support 440 | * 441 | * @return No return. 442 | */ 443 | stock CSetupProfile() 444 | { 445 | decl String:szGameName[30]; 446 | GetGameFolderName(szGameName, sizeof(szGameName)); 447 | 448 | if (StrEqual(szGameName, "cstrike", false)) 449 | { 450 | CProfile_Colors[Color_Lightgreen] = true; 451 | CProfile_Colors[Color_Red] = true; 452 | CProfile_Colors[Color_Blue] = true; 453 | CProfile_Colors[Color_Olive] = true; 454 | CProfile_TeamIndex[Color_Lightgreen] = SERVER_INDEX; 455 | CProfile_TeamIndex[Color_Red] = 2; 456 | CProfile_TeamIndex[Color_Blue] = 3; 457 | CProfile_SayText2 = true; 458 | } 459 | else if (StrEqual(szGameName, "csgo", false)) 460 | { 461 | CProfile_Colors[Color_Default] = true; 462 | CProfile_Colors[Color_Darkred] = true; 463 | CProfile_Colors[Color_Pink] = true; 464 | CProfile_Colors[Color_Green] = true; 465 | CProfile_Colors[Color_Lightgreen] = true; 466 | CProfile_Colors[Color_Lime] = true; 467 | CProfile_Colors[Color_Red] = true; 468 | CProfile_Colors[Color_Grey] = true; 469 | CProfile_Colors[Color_Olive] = true; 470 | CProfile_Colors[Color_A] = true; 471 | CProfile_Colors[Color_Lightblue] = true; 472 | CProfile_Colors[Color_Blue] = true; 473 | CProfile_Colors[Color_D] = true; 474 | CProfile_Colors[Color_Purple] = true; 475 | CProfile_Colors[Color_Darkrange] = true; 476 | CProfile_Colors[Color_Orange] = true; 477 | CProfile_Colors[Color_Red] = true; 478 | CProfile_Colors[Color_Blue] = true; 479 | CProfile_Colors[Color_Olive] = true; 480 | CProfile_Colors[Color_Darkred] = true; 481 | CProfile_Colors[Color_Lime] = true; 482 | CProfile_Colors[Color_Purple] = true; 483 | CProfile_Colors[Color_Grey] = true; 484 | CProfile_Colors[Color_Orange] = true; 485 | CProfile_TeamIndex[Color_Red] = 2; 486 | CProfile_TeamIndex[Color_Blue] = 3; 487 | CProfile_SayText2 = true; 488 | } 489 | else if (StrEqual(szGameName, "tf", false)) 490 | { 491 | CProfile_Colors[Color_Lightgreen] = true; 492 | CProfile_Colors[Color_Red] = true; 493 | CProfile_Colors[Color_Blue] = true; 494 | CProfile_Colors[Color_Olive] = true; 495 | CProfile_TeamIndex[Color_Lightgreen] = SERVER_INDEX; 496 | CProfile_TeamIndex[Color_Red] = 2; 497 | CProfile_TeamIndex[Color_Blue] = 3; 498 | CProfile_SayText2 = true; 499 | } 500 | else if (StrEqual(szGameName, "left4dead", false) || StrEqual(szGameName, "left4dead2", false)) 501 | { 502 | CProfile_Colors[Color_Lightgreen] = true; 503 | CProfile_Colors[Color_Red] = true; 504 | CProfile_Colors[Color_Blue] = true; 505 | CProfile_Colors[Color_Olive] = true; 506 | CProfile_TeamIndex[Color_Lightgreen] = SERVER_INDEX; 507 | CProfile_TeamIndex[Color_Red] = 3; 508 | CProfile_TeamIndex[Color_Blue] = 2; 509 | CProfile_SayText2 = true; 510 | } 511 | else if (StrEqual(szGameName, "hl2mp", false)) 512 | { 513 | /* hl2mp profile is based on mp_teamplay convar */ 514 | if (GetConVarBool(FindConVar("mp_teamplay"))) 515 | { 516 | CProfile_Colors[Color_Red] = true; 517 | CProfile_Colors[Color_Blue] = true; 518 | CProfile_Colors[Color_Olive] = true; 519 | CProfile_TeamIndex[Color_Red] = 3; 520 | CProfile_TeamIndex[Color_Blue] = 2; 521 | CProfile_SayText2 = true; 522 | } 523 | else 524 | { 525 | CProfile_SayText2 = false; 526 | CProfile_Colors[Color_Olive] = true; 527 | } 528 | } 529 | else if (StrEqual(szGameName, "dod", false)) 530 | { 531 | CProfile_Colors[Color_Olive] = true; 532 | CProfile_SayText2 = false; 533 | } 534 | /* Profile for other games */ 535 | else 536 | { 537 | if (GetUserMessageId("SayText2") == INVALID_MESSAGE_ID) 538 | { 539 | CProfile_SayText2 = false; 540 | } 541 | else 542 | { 543 | CProfile_Colors[Color_Red] = true; 544 | CProfile_Colors[Color_Blue] = true; 545 | CProfile_TeamIndex[Color_Red] = 2; 546 | CProfile_TeamIndex[Color_Blue] = 3; 547 | CProfile_SayText2 = true; 548 | } 549 | } 550 | } 551 | 552 | public Action:CEvent_MapStart(Handle:event, const String:name[], bool:dontBroadcast) 553 | { 554 | CSetupProfile(); 555 | 556 | for (new i = 1; i <= MaxClients; i++) 557 | CSkipList[i] = false; 558 | } 559 | 560 | -------------------------------------------------------------------------------- /include/discord.inc: -------------------------------------------------------------------------------- 1 | #if defined _discord_included 2 | #endinput 3 | #endif 4 | #define _discord_included 5 | 6 | #include 7 | #include 8 | 9 | typedef DiscordGuildsRetrieve = function void (DiscordBot bot, char[] id, char[] name, char[] icon, bool owner, int permissions, any data); 10 | 11 | typedef DiscordGuildsRetrievedAll = function void (DiscordBot bot, ArrayList id, ArrayList name, ArrayList icon, ArrayList owner, ArrayList permissions, any data); 12 | 13 | //Channel are Handles that are closed immediately after forwards called. To keep, clone. Or store id if thats what you want 14 | typedef DiscordGuildChannelsRetrieve = function void (DiscordBot bot, char[] guild, DiscordChannel Channel, any data); 15 | 16 | typedef DiscordGuildChannelsRetrieveAll = function void (DiscordBot bot, char[] guild, ArrayList Channels, any data); 17 | 18 | typedef DiscordGuildGetRoles = function void (DiscordBot bot, char[] guild, RoleList Roles, any data); 19 | 20 | /** 21 | * Called when message is received 22 | * bot/channel/message are all destroyed after callback is sent. 23 | * You can clone it if need to keep. 24 | */ 25 | typeset OnChannelMessage { 26 | function void(DiscordBot bot, DiscordChannel channel, DiscordMessage message); 27 | }; 28 | 29 | typedef OnGetReactions = function void (DiscordBot bot, ArrayList Users, char[] channelID, const char[] messageID, const char[] emoji, any data); 30 | 31 | typedef OnMessageSent = function void(DiscordBot bot, char[] channel, DiscordMessage message, any data); 32 | 33 | typedef OnMessageDeleted = function void(DiscordBot bot, any data); 34 | 35 | //hMemberList is JSON array containing guild members 36 | typedef OnGetMembers = function void(DiscordBot bot, char[] guild, Handle hMemberList); 37 | 38 | methodmap Role < Handle { 39 | public void GetID(char[] buffer, int maxlength) { 40 | JsonObjectGetString(this, "id", buffer, maxlength); 41 | } 42 | 43 | public void GetName(char[] buffer, int maxlength) { 44 | JsonObjectGetString(this, "name", buffer, maxlength); 45 | } 46 | 47 | public int GetColor() { 48 | return JsonObjectGetInt(this, "color"); 49 | } 50 | 51 | public int GetPosition() { 52 | return JsonObjectGetInt(this, "position"); 53 | } 54 | 55 | public int GetPermissions() { 56 | return JsonObjectGetInt(this, "permissions"); 57 | } 58 | 59 | public bool Hoist() { 60 | return JsonObjectGetBool(this, "hoist"); 61 | } 62 | 63 | public bool Managed() { 64 | return JsonObjectGetBool(this, "managed"); 65 | } 66 | 67 | public bool Mentionable() { 68 | return JsonObjectGetBool(this, "mentionable"); 69 | } 70 | }; 71 | 72 | methodmap RoleList < Handle { 73 | property int Size { 74 | public get() { 75 | return json_array_size(this); 76 | } 77 | } 78 | public Role GetRole(int i) { 79 | return view_as( 80 | json_array_get(this, i) 81 | ); 82 | } 83 | public Role Get(int i) { 84 | return this.GetRole(i); 85 | } 86 | 87 | }; 88 | 89 | /* 90 | { 91 | "id": "80351110224678912", 92 | "username": "Nelly", 93 | "discriminator": "1337", 94 | "avatar": "8342729096ea3675442027381ff50dfe", 95 | "verified": true, 96 | "email": "nelly@discord.com" 97 | } 98 | */ 99 | //It's a JSON Handle with the above info TODO stop using natives! 100 | methodmap DiscordUser < Handle { 101 | public native void GetID(char[] buffer, int maxlength); 102 | 103 | public native void GetUsername(char[] buffer, int maxlength); 104 | 105 | public native void GetDiscriminator(char[] buffer, int maxlength); 106 | public int GetDiscriminatorInt() { 107 | char buffer[16]; 108 | this.GetDiscriminator(buffer, sizeof(buffer)); 109 | return StringToInt(buffer); 110 | } 111 | 112 | public native void GetAvatar(char[] buffer, int maxlength); 113 | 114 | public native bool IsVerified(); 115 | 116 | public native void GetEmail(char[] buffer, int maxlength); 117 | 118 | public native bool IsBot(); 119 | }; 120 | 121 | /* 122 | 123 | {"timestamp": "2017-01-15T20:26:35.353000+00:00", "mention_everyone": false, "id": "270287641155469313", "pinned": false, "edited_timestamp": null, "author": {"username": "DK-Bot", "discriminator": "6274", "bot": true, "id": "186256454863290369", "avatar": null}, "mention_roles": [], "content": "ab", "channel_id": "229677130483499008", "mentions": [], "type": 0} 124 | */ 125 | methodmap DiscordMessage < Handle { 126 | public native void GetID(char[] buffer, int maxlength); 127 | 128 | public native bool IsPinned(); 129 | 130 | public native DiscordUser GetAuthor(); 131 | 132 | public native void GetContent(char[] buffer, int maxlength); 133 | 134 | public native void GetChannelID(char[] buffer, int maxlength); 135 | }; 136 | 137 | #include 138 | #include 139 | #include 140 | #include 141 | #include 142 | 143 | public SharedPlugin __pl_discordapi = 144 | { 145 | name = "discord-api", 146 | file = "discord-api.smx", 147 | #if defined REQUIRE_PLUGIN 148 | required = 1, 149 | #else 150 | required = 0, 151 | #endif 152 | }; 153 | 154 | #if !defined REQUIRE_PLUGIN 155 | public void __pl_discordapi_SetNTVOptional() 156 | { 157 | MarkNativeAsOptional("DiscordUser.GetID"); 158 | MarkNativeAsOptional("DiscordUser.GetUsername"); 159 | MarkNativeAsOptional("DiscordUser.GetDiscriminator"); 160 | MarkNativeAsOptional("DiscordUser.GetAvatar"); 161 | MarkNativeAsOptional("DiscordUser.IsVerified"); 162 | MarkNativeAsOptional("DiscordUser.GetEmail"); 163 | MarkNativeAsOptional("DiscordUser.IsBot"); 164 | MarkNativeAsOptional("DiscordMessage.GetID"); 165 | MarkNativeAsOptional("DiscordMessage.IsPinned"); 166 | MarkNativeAsOptional("DiscordMessage.DiscordUser GetAuthor"); 167 | MarkNativeAsOptional("DiscordMessage.GetContent"); 168 | MarkNativeAsOptional("DiscordMessage.GetChannelID"); 169 | MarkNativeAsOptional("DiscordBot.StartTimer"); 170 | MarkNativeAsOptional("DiscordBot.AddReactionID"); 171 | MarkNativeAsOptional("DiscordBot.DeleteReactionID"); 172 | MarkNativeAsOptional("DiscordBot.GetReactionID"); 173 | MarkNativeAsOptional("DiscordBot.GetToken"); 174 | MarkNativeAsOptional("DiscordBot.SendMessage"); 175 | MarkNativeAsOptional("DiscordBot.SendMessageToChannelID"); 176 | MarkNativeAsOptional("DiscordBot.DeleteMessageID"); 177 | MarkNativeAsOptional("DiscordBot.DeleteMessage"); 178 | MarkNativeAsOptional("DiscordBot.GetGuilds"); 179 | MarkNativeAsOptional("DiscordBot.GetGuildChannels"); 180 | MarkNativeAsOptional("DiscordBot.GetGuildMembers"); 181 | MarkNativeAsOptional("DiscordBot.GetGuildMembersAll"); 182 | MarkNativeAsOptional("DiscordBot.GetGuildRoles"); 183 | MarkNativeAsOptional("DiscordChannel.SendMessage"); 184 | MarkNativeAsOptional("DiscordWebHook.Send"); 185 | } 186 | #endif -------------------------------------------------------------------------------- /include/discord/GuildMember.inc: -------------------------------------------------------------------------------- 1 | methodmap DiscordGuildUser < Handle { 2 | //Returns User Object 3 | public DiscordUser GetUser() { 4 | return view_as(json_object_get(this, "user")); 5 | } 6 | 7 | //Returns player's nick 8 | public void GetNickname(char[] buffer, int maxlength) { 9 | JsonObjectGetString(this, "nick", buffer, maxlength); 10 | } 11 | 12 | //Returns JSON array list of roles. You can manually loop through them for now. 13 | public Handle GetRoles() { 14 | return json_object_get(this, "roles"); 15 | } 16 | 17 | //Returns the date the user joined the guild in format: "2015-04-26T06:26:56.936000+00:00" 18 | public void GetJoinedAt(char[] buffer, int maxlength) { 19 | JsonObjectGetString(this, "joined_at", buffer, maxlength); 20 | } 21 | 22 | public bool IsDeaf() { 23 | return JsonObjectGetBool(this, "deaf"); 24 | } 25 | 26 | public bool IsMute() { 27 | return JsonObjectGetBool(this, "mute"); 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /include/discord/bot.inc: -------------------------------------------------------------------------------- 1 | methodmap DiscordBot < StringMap { 2 | public DiscordBot(const char[] token) { 3 | Handle json = json_object(); 4 | json_object_set_new(json, "token", json_string(token)); 5 | 6 | return view_as(json); 7 | } 8 | 9 | public void StopListening() { 10 | json_object_del(this, "listeningChannels"); 11 | } 12 | 13 | property float MessageCheckInterval { 14 | public get() { 15 | return JsonObjectGetFloat(this, "messageInterval", 3.0); 16 | } 17 | public set(float value) { 18 | json_object_set_new(this, "messageInterval", json_real(value)); 19 | } 20 | } 21 | 22 | public native void StartTimer(DiscordChannel Channel, OnChannelMessage fCallback); 23 | 24 | /** 25 | * Retrieves a list of Channels the bot is listening to for messages 26 | */ 27 | public Handle GetListeningChannels() { 28 | return json_object_get(this, "listeningChannels"); 29 | } 30 | 31 | /** 32 | * Checks if the bot is listening to channel for messages 33 | * @param DiscordChannel Channel 34 | */ 35 | public bool IsListeningToChannel(DiscordChannel Channel) { 36 | char id[32]; 37 | Channel.GetID(id, sizeof(id)); 38 | 39 | Handle hChannels = this.GetListeningChannels(); 40 | if(hChannels == null) return false; 41 | 42 | for(int i = 0; i < json_array_size(hChannels); i++) { 43 | DiscordChannel tempChannel = view_as(json_array_get(hChannels, i)); 44 | static char tempID[32]; 45 | tempChannel.GetID(tempID, sizeof(tempID)); 46 | if(StrEqual(id, tempID, false)) { 47 | delete tempChannel; 48 | delete hChannels; 49 | return true; 50 | } 51 | delete tempChannel; 52 | } 53 | delete hChannels; 54 | return false; 55 | } 56 | 57 | /** 58 | * Checks if the bot is listening to channel for messages 59 | * @param DiscordChannel Channel 60 | */ 61 | public bool IsListeningToChannelID(const char[] id) { 62 | Handle hChannels = this.GetListeningChannels(); 63 | if(hChannels == null) return false; 64 | 65 | for(int i = 0; i < json_array_size(hChannels); i++) { 66 | DiscordChannel tempChannel = view_as(json_array_get(hChannels, i)); 67 | static char tempID[32]; 68 | tempChannel.GetID(tempID, sizeof(tempID)); 69 | if(StrEqual(id, tempID, false)) { 70 | delete tempChannel; 71 | delete hChannels; 72 | return true; 73 | } 74 | delete tempChannel; 75 | } 76 | delete hChannels; 77 | return false; 78 | } 79 | 80 | /** 81 | * Stops the bot from listening to that channel for messages 82 | * @param DiscordChannel Channel 83 | */ 84 | public void StopListeningToChannel(DiscordChannel Channel) { 85 | char id[32]; 86 | Channel.GetID(id, sizeof(id)); 87 | 88 | Handle channels = this.GetListeningChannels(); 89 | if(channels == null) return; 90 | 91 | static char tempID[32]; 92 | 93 | for(int i = 0; i < json_array_size(channels); i++) { 94 | DiscordChannel tempChannel = view_as(json_array_get(channels, i)); 95 | tempChannel.GetID(tempID, sizeof(tempID)); 96 | if(StrEqual(id, tempID, false)) { 97 | json_array_remove(channels, i); 98 | i--; 99 | } 100 | delete tempChannel; 101 | } 102 | delete channels; 103 | } 104 | 105 | public void StopListeningToChannels() 106 | { 107 | Handle channels = this.GetListeningChannels(); 108 | if(channels == null) return; 109 | for(int i = 0; i < json_array_size(channels); i++) 110 | { 111 | json_array_remove(channels, i); 112 | } 113 | delete channels; 114 | } 115 | 116 | 117 | /** 118 | * Stops the bot from listening to that channel id for messages 119 | * @param DiscordChannel Channel 120 | */ 121 | public void StopListeningToChannelID(const char[] id) { 122 | Handle channels = this.GetListeningChannels(); 123 | if(channels == null) return; 124 | 125 | for(int i = 0; i < json_array_size(channels); i++) { 126 | DiscordChannel tempChannel = view_as(json_array_get(channels, i)); 127 | static char tempID[32]; 128 | tempChannel.GetID(tempID, sizeof(tempID)); 129 | if(StrEqual(id, tempID, false)) { 130 | json_array_remove(channels, i); 131 | i--; 132 | } 133 | delete tempChannel; 134 | } 135 | delete channels; 136 | } 137 | 138 | public DiscordChannel GetListeningChannelByID(const char[] id) { 139 | Handle channels = this.GetListeningChannels(); 140 | if(channels == null) return null; 141 | 142 | for(int i = 0; i < json_array_size(channels); i++) { 143 | DiscordChannel tempChannel = view_as(json_array_get(channels, i)); 144 | static char tempID[32]; 145 | tempChannel.GetID(tempID, sizeof(tempID)); 146 | if(StrEqual(id, tempID, false)) { 147 | delete channels; 148 | return tempChannel; 149 | } 150 | } 151 | delete channels; 152 | return null; 153 | } 154 | 155 | /** 156 | * Start listening to the channel for messages. 157 | * The Channel handle is duplicated. Feel free to close yours. 158 | * @param DiscordChannel Channel 159 | */ 160 | public void StartListeningToChannel(DiscordChannel Channel, OnChannelMessage fCallback) { 161 | if(this.IsListeningToChannel(Channel)) return; 162 | 163 | Handle channels = this.GetListeningChannels(); 164 | 165 | if(channels == null) { 166 | channels = json_array(); 167 | json_object_set(this, "listeningChannels", channels); 168 | } 169 | 170 | json_array_append(channels, Channel); 171 | delete channels; 172 | 173 | //Handle fForward = CreateForward(ET_Ignore, Param_Cell, Param_Cell, Param_String, Param_String, Param_String, Param_String, Param_String, Param_Cell); 174 | //AddToForward(fForward, GetMyHandle(), callback); 175 | 176 | this.StartTimer(Channel, fCallback); 177 | } 178 | 179 | 180 | public native void AddReactionID(const char[] channel, const char[] messageid, const char[] emoji); 181 | 182 | public void AddReaction(DiscordChannel channel, const char[] messageid, const char[] emoji) { 183 | char channelid[64]; 184 | channel.GetID(channelid, sizeof(channelid)); 185 | this.AddReactionID(channelid, messageid, emoji); 186 | } 187 | 188 | public native void DeleteReactionID(const char[] channel, const char[] messageid, const char[] emoji, const char[] user); 189 | 190 | public void DeleteReaction(DiscordChannel channel, const char[] messageid, const char[] emoji, const char[] user) { 191 | char chid[64]; 192 | channel.GetID(chid, sizeof(chid)); 193 | this.DeleteReactionID(chid, messageid, emoji, user); 194 | } 195 | 196 | public void DeleteReactionSelf(DiscordChannel channel, const char[] messageid, const char[] emoji) { 197 | this.DeleteReaction(channel, messageid, emoji, "@me"); 198 | } 199 | public void DeleteReactionAll(DiscordChannel channel, const char[] messageid, const char[] emoji) { 200 | this.DeleteReaction(channel, messageid, emoji, "@all"); 201 | } 202 | 203 | public void DeleteReactionSelfID(const char[] channel, const char[] messageid, const char[] emoji) { 204 | this.DeleteReactionID(channel, messageid, emoji, "@me"); 205 | } 206 | public void DeleteReactionAllID(const char[] channel, const char[] messageid, const char[] emoji) { 207 | this.DeleteReactionID(channel, messageid, emoji, "@all"); 208 | } 209 | 210 | public native void GetReactionID(const char[] channel, const char[] messageid, const char[] emoji, OnGetReactions fCallback=INVALID_FUNCTION, any data=0); 211 | 212 | public void GetReaction(DiscordChannel channel, const char[] messageid, const char[] emoji, OnGetReactions fCallback=INVALID_FUNCTION, any data=0) { 213 | char id[64]; 214 | channel.GetID(id, sizeof(id)); 215 | this.GetReactionID(id, messageid, emoji, fCallback, data); 216 | } 217 | 218 | public native void GetToken(char[] token, int maxlength); 219 | 220 | public native void SendMessage(DiscordChannel channel, char[] message, OnMessageSent fCallback=INVALID_FUNCTION, any data=0); 221 | 222 | public native void SendMessageToChannelID(char[] channel, char[] message, OnMessageSent fCallback=INVALID_FUNCTION, any data=0); 223 | 224 | public native void DeleteMessageID(char[] channel, char[] message, OnMessageDeleted fCallback=INVALID_FUNCTION, any data=0); 225 | public native void DeleteMessage(DiscordChannel channel, DiscordMessage message, OnMessageDeleted fCallback=INVALID_FUNCTION, any data=0); 226 | 227 | 228 | public native void GetGuilds(DiscordGuildsRetrieve fCallback = INVALID_FUNCTION, DiscordGuildsRetrievedAll fCallbackAll = INVALID_FUNCTION, any data=0); 229 | 230 | public native void GetGuildChannels(char[] guild, DiscordGuildChannelsRetrieve fCallback = INVALID_FUNCTION, DiscordGuildChannelsRetrieveAll fCallbackAll = INVALID_FUNCTION, any data=0); 231 | 232 | /** 233 | * ATM takes guild id, hopefully later on i will implement guild objects. 234 | * Limit is from 1-1000 235 | */ 236 | public native void GetGuildMembers(char[] guild, OnGetMembers fCallback, int limit=250, char[] afterUserID=""); 237 | 238 | /** 239 | * Same as above but displays ALL members, paginating automatically. 240 | * perPage is how many it should display per callback. 1-1000 241 | */ 242 | public native void GetGuildMembersAll(char[] guild, OnGetMembers fCallback, int perPage=250, char[] afterUserID=""); 243 | 244 | public native void GetGuildRoles(char[] guild, DiscordGuildGetRoles fCallback, any data); 245 | }; 246 | -------------------------------------------------------------------------------- /include/discord/channel.inc: -------------------------------------------------------------------------------- 1 | enum 2 | { 3 | GUILD_TEXT = 0, 4 | DM, 5 | GUILD_VOICE, 6 | GROUP_DM, 7 | GUILD_CATEGORY 8 | }; 9 | 10 | methodmap DiscordChannel < StringMap { 11 | public DiscordChannel() { 12 | Handle hObj = json_object(); 13 | return view_as(hObj); 14 | } 15 | 16 | public native void SendMessage(DiscordBot Bot, char[] message, OnMessageSent fCallback=INVALID_FUNCTION, any data=0); 17 | 18 | public void GetGuildID(char[] buffer, int maxlength) { 19 | JsonObjectGetString(this, "guild_id", buffer, maxlength); 20 | } 21 | 22 | public void GetID(char[] buffer, int maxlength) { 23 | JsonObjectGetString(this, "id", buffer, maxlength); 24 | } 25 | 26 | public void GetName(char[] buffer, int maxlength) { 27 | JsonObjectGetString(this, "name", buffer, maxlength); 28 | } 29 | 30 | property int Position { 31 | public get() { 32 | return JsonObjectGetInt(this, "position"); 33 | } 34 | } 35 | 36 | property bool IsPrivate { 37 | public get() { 38 | return JsonObjectGetBool(this, "is_private"); 39 | } 40 | } 41 | 42 | public void GetTopic(char[] buffer, int maxlength) { 43 | JsonObjectGetString(this, "topic", buffer, maxlength); 44 | } 45 | 46 | public void GetLastMessageID(char[] buffer, int maxlength) { 47 | JsonObjectGetString(this, "last_message_id", buffer, maxlength); 48 | } 49 | 50 | public void SetLastMessageID(const char[] id) { 51 | json_object_set_new(this, "last_message_id", json_string(id)); 52 | } 53 | 54 | property int Type { 55 | public get() { 56 | return JsonObjectGetInt(this, "type"); 57 | } 58 | } 59 | 60 | property int Bitrate { 61 | public get() { 62 | return JsonObjectGetInt(this, "bitrate"); 63 | } 64 | } 65 | 66 | property int UserLimit { 67 | public get() { 68 | return JsonObjectGetInt(this, "user_limit"); 69 | } 70 | } 71 | 72 | property bool IsText { 73 | public get() { 74 | return this.Type == GUILD_TEXT; 75 | } 76 | } 77 | }; 78 | -------------------------------------------------------------------------------- /include/discord/message_embed.inc: -------------------------------------------------------------------------------- 1 | methodmap MessageEmbed < Handle { 2 | public MessageEmbed() { 3 | Handle hObj = json_object(); 4 | return view_as(hObj); 5 | } 6 | 7 | public bool GetColor(char[] buffer, int maxlength) { 8 | return JsonObjectGetString(this, "color", buffer, maxlength); 9 | } 10 | 11 | public void SetColor(const char[] color) { 12 | json_object_set_new(this, "color", json_string(color)); 13 | } 14 | 15 | public bool GetTitle(char[] buffer, int maxlength) { 16 | return JsonObjectGetString(this, "title", buffer, maxlength); 17 | } 18 | 19 | public void SetTitle(const char[] title) { 20 | json_object_set_new(this, "title", json_string(title)); 21 | } 22 | 23 | public bool GetTitleLink(char[] buffer, int maxlength) { 24 | return JsonObjectGetString(this, "title_link", buffer, maxlength); 25 | } 26 | 27 | public void SetTitleLink(const char[] title_link) { 28 | json_object_set_new(this, "title_link", json_string(title_link)); 29 | } 30 | 31 | public bool GetImage(char[] buffer, int maxlength) { 32 | return JsonObjectGetString(this, "image_url", buffer, maxlength); 33 | } 34 | 35 | public void SetImage(const char[] image_url) { 36 | json_object_set_new(this, "image_url", json_string(image_url)); 37 | } 38 | 39 | public bool GetAuthor(char[] buffer, int maxlength) { 40 | return JsonObjectGetString(this, "author_name", buffer, maxlength); 41 | } 42 | 43 | public void SetAuthor(const char[] author_name) { 44 | json_object_set_new(this, "author_name", json_string(author_name)); 45 | } 46 | 47 | public bool GetAuthorLink(char[] buffer, int maxlength) { 48 | return JsonObjectGetString(this, "author_link", buffer, maxlength); 49 | } 50 | 51 | public void SetAuthorLink(const char[] author_link) { 52 | json_object_set_new(this, "author_link", json_string(author_link)); 53 | } 54 | 55 | public bool GetAuthorIcon(char[] buffer, int maxlength) { 56 | return JsonObjectGetString(this, "author_icon", buffer, maxlength); 57 | } 58 | 59 | public void SetAuthorIcon(const char[] author_icon) { 60 | json_object_set_new(this, "author_icon", json_string(author_icon)); 61 | } 62 | 63 | public bool GetThumb(char[] buffer, int maxlength) { 64 | return JsonObjectGetString(this, "thumb_url", buffer, maxlength); 65 | } 66 | 67 | public void SetThumb(const char[] thumb_url) { 68 | json_object_set_new(this, "thumb_url", json_string(thumb_url)); 69 | } 70 | 71 | public bool GetFooter(char[] buffer, int maxlength) { 72 | return JsonObjectGetString(this, "footer", buffer, maxlength); 73 | } 74 | 75 | public void SetFooter(const char[] footer) { 76 | json_object_set_new(this, "footer", json_string(footer)); 77 | } 78 | 79 | public bool GetFooterIcon(char[] buffer, int maxlength) { 80 | return JsonObjectGetString(this, "footer_icon", buffer, maxlength); 81 | } 82 | 83 | public void SetFooterIcon(const char[] footer_icon) { 84 | json_object_set_new(this, "footer_icon", json_string(footer_icon)); 85 | } 86 | /** 87 | * Note: Setting Fields will delete the handle! 88 | */ 89 | property Handle Fields { 90 | public get() { 91 | return json_object_get(this, "fields"); 92 | } 93 | 94 | public set(Handle value) { 95 | json_object_set_new(this, "fields", value); 96 | } 97 | } 98 | 99 | public void AddField(const char[] name, const char[] value, bool inline) { 100 | Handle hObj = json_object(); 101 | json_object_set_new(hObj, "name", json_string(name)); 102 | json_object_set_new(hObj, "value", json_string(value)); 103 | json_object_set_new(hObj, "inline", json_boolean(inline)); 104 | Handle hArray = this.Fields; 105 | if(hArray == null) { 106 | hArray = json_array(); 107 | } 108 | json_array_append_new(hArray, hObj); 109 | this.Fields = hArray; 110 | } 111 | 112 | //Below don't support Slack Mode 113 | public bool GetDescription(char[] buffer, int maxlength) { 114 | return JsonObjectGetString(this, "description", buffer, maxlength); 115 | } 116 | 117 | public void SetDescription(const char[] description) { 118 | json_object_set_new(this, "description", json_string(description)); 119 | } 120 | 121 | public bool GetURL(char[] buffer, int maxlength) { 122 | return JsonObjectGetString(this, "url", buffer, maxlength); 123 | } 124 | 125 | public void SetURL(const char[] url) { 126 | json_object_set_new(this, "url", json_string(url)); 127 | } 128 | }; 129 | -------------------------------------------------------------------------------- /include/discord/stocks.inc: -------------------------------------------------------------------------------- 1 | stock int JsonObjectGetInt(Handle hElement, char[] key) { 2 | Handle hObject = json_object_get(hElement, key); 3 | if(hObject == INVALID_HANDLE) return 0; 4 | 5 | int value; 6 | if(json_is_integer(hObject)) { 7 | value = json_integer_value(hObject); 8 | }else if(json_is_string(hObject)) { 9 | char buffer[12]; 10 | json_string_value(hObject, buffer, sizeof(buffer)); 11 | value = StringToInt(buffer); 12 | } 13 | CloseHandle(hObject); 14 | return value; 15 | } 16 | 17 | stock bool JsonObjectGetString(Handle hElement, char[] key, char[] buffer, maxlength) { 18 | Handle hObject = json_object_get(hElement, key); 19 | if(hObject == INVALID_HANDLE) return false; 20 | 21 | if(json_is_integer(hObject)) { 22 | IntToString(json_integer_value(hObject), buffer, maxlength); 23 | }else if(json_is_string(hObject)) { 24 | json_string_value(hObject, buffer, maxlength); 25 | }else if(json_is_real(hObject)) { 26 | FloatToString(json_real_value(hObject), buffer, maxlength); 27 | }else if(json_is_true(hObject)) { 28 | FormatEx(buffer, maxlength, "true"); 29 | }else if(json_is_false(hObject)) { 30 | FormatEx(buffer, maxlength, "false"); 31 | } 32 | CloseHandle(hObject); 33 | return true; 34 | } 35 | 36 | stock bool JsonObjectGetBool(Handle hElement, char[] key, bool defaultvalue=false) { 37 | Handle hObject = json_object_get(hElement, key); 38 | if(hObject == INVALID_HANDLE) return defaultvalue; 39 | 40 | bool ObjectBool = defaultvalue; 41 | 42 | if(json_is_integer(hObject)) { 43 | ObjectBool = view_as(json_integer_value(hObject)); 44 | }else if(json_is_string(hObject)) { 45 | char buffer[11]; 46 | json_string_value(hObject, buffer, sizeof(buffer)); 47 | if(StrEqual(buffer, "true", false)) { 48 | ObjectBool = true; 49 | }else if(StrEqual(buffer, "false", false)) { 50 | ObjectBool = false; 51 | }else { 52 | int x = StringToInt(buffer); 53 | ObjectBool = view_as(x); 54 | } 55 | }else if(json_is_real(hObject)) { 56 | ObjectBool = view_as(RoundToFloor(json_real_value(hObject))); 57 | }else if(json_is_true(hObject)) { 58 | ObjectBool = true; 59 | }else if(json_is_false(hObject)) { 60 | ObjectBool = false; 61 | } 62 | CloseHandle(hObject); 63 | return ObjectBool; 64 | } 65 | 66 | stock float JsonObjectGetFloat(Handle hJson, char[] key, float defaultValue=0.0) { 67 | Handle hObject = json_object_get(hJson, key); 68 | if(hObject == INVALID_HANDLE) return defaultValue; 69 | 70 | float value = defaultValue; 71 | if(json_is_integer(hObject)) { 72 | value = float(json_integer_value(hObject)); 73 | }else if(json_is_real(hObject)) { 74 | value = json_real_value(hObject); 75 | }else if(json_is_string(hObject)) { 76 | char buffer[12]; 77 | json_string_value(hObject, buffer, sizeof(buffer)); 78 | value = StringToFloat(buffer); 79 | } 80 | CloseHandle(hObject); 81 | return value; 82 | } 83 | -------------------------------------------------------------------------------- /include/discord/webhook.inc: -------------------------------------------------------------------------------- 1 | methodmap DiscordWebHook < Handle { 2 | public DiscordWebHook(char[] url) { 3 | Handle mp = json_object(); 4 | json_object_set_new(mp, "__url", json_string(url)); 5 | Handle data = json_object(); 6 | json_object_set_new(mp, "__data", data); 7 | 8 | return view_as(mp); 9 | } 10 | 11 | public void GetUrl(char[] buffer, int maxlength) { 12 | JsonObjectGetString(this, "__url", buffer, maxlength); 13 | } 14 | 15 | /** 16 | * Gets/Sets if the hook should be sent as Slack. 17 | * Note: color is different for slack than discord msg. 18 | * 19 | * @return True if Slack, otherwise false. 20 | */ 21 | property bool SlackMode { 22 | public get() { 23 | return JsonObjectGetBool(this, "__slack", false); 24 | } 25 | 26 | public set(bool value) { 27 | json_object_set_new(this, "__slack", (value) ? json_true() : json_false()); 28 | } 29 | } 30 | 31 | property Handle Data { 32 | public get() { 33 | return json_object_get(this, "__data"); 34 | } 35 | 36 | public set(Handle value) { 37 | json_object_set_new(this, "__data", value); 38 | } 39 | } 40 | 41 | public void UpdateDataObject(char[] key, Handle hObject) { 42 | Handle data = this.Data; 43 | json_object_set_new(data, key, hObject); 44 | delete data; 45 | } 46 | 47 | public bool GetDataBool(char[] key, bool defaultValue=false) { 48 | Handle data = this.Data; 49 | bool value = JsonObjectGetBool(data, key, defaultValue); 50 | delete data; 51 | return value; 52 | } 53 | 54 | public bool GetDataString(char[] key, char[] buffer, int maxlength) { 55 | Handle data = this.Data; 56 | bool success = JsonObjectGetString(data, key, buffer, maxlength); 57 | delete data; 58 | return success; 59 | } 60 | 61 | /** 62 | * Note: Deletes the MessageEmbed Object! 63 | */ 64 | public void Embed(MessageEmbed Object) { 65 | //this.UpdateDataObject("embeds", Object); 66 | Handle data = this.Data; 67 | Handle hArray = json_object_get(data, "embeds"); 68 | 69 | if(hArray == null) { 70 | hArray = json_array(); 71 | json_object_set(data, "embeds", hArray); 72 | } 73 | 74 | json_array_append_new(hArray, Object); 75 | delete hArray; 76 | delete data; 77 | 78 | } 79 | 80 | property bool tts { 81 | public get() { 82 | return this.GetDataBool("tts", false); 83 | } 84 | 85 | public set(bool value) { 86 | this.UpdateDataObject("tts", json_boolean(value)); 87 | } 88 | } 89 | 90 | public bool GetUsername(char[] buffer, int maxlength) { 91 | return this.GetDataString("username", buffer, maxlength); 92 | } 93 | 94 | public void SetUsername(const char[] name) { 95 | this.UpdateDataObject("username", json_string(name)); 96 | } 97 | 98 | public bool GetAvatar(char[] buffer, int maxlength) { 99 | return this.GetDataString("icon_url", buffer, maxlength); 100 | } 101 | 102 | public void SetAvatar(const char[] icon_url) { 103 | this.UpdateDataObject("icon_url", json_string(icon_url)); 104 | } 105 | 106 | public bool GetContent(char[] buffer, int maxlength) { 107 | return this.GetDataString("content", buffer, maxlength); 108 | } 109 | 110 | public void SetContent(const char[] content) { 111 | this.UpdateDataObject("content", json_string(content)); 112 | } 113 | 114 | /*property Handle OnComplete { 115 | public get() { 116 | Handle fForward = null; 117 | if(!GetTrieValue(this, "callback", fForward)) { 118 | return null; 119 | } 120 | 121 | return fForward; 122 | } 123 | 124 | public set(Handle value) { 125 | SetTrieValue(this, "callback", value); 126 | SetTrieValue(this, "plugin", GetMyHandle()); 127 | } 128 | } 129 | 130 | property Handle CallbackPlugin { 131 | public get() { 132 | Handle value = null; 133 | if(!GetTrieValue(this, "plugin", value)) { 134 | return null; 135 | } 136 | 137 | return value; 138 | } 139 | }*/ 140 | 141 | public native void Send(); 142 | }; 143 | --------------------------------------------------------------------------------