1- #define DISCORD_NOT_INSTALLED
2-
31using Oxide . Core ;
42using System ;
53using System . Linq ;
4+ using UnityEngine ;
65using System . Collections . Generic ;
76using Newtonsoft . Json ;
8-
9- #if DISCORD_INSTALLED
10- using Oxide . Ext . Discord ;
11- using Oxide . Ext . Discord . Attributes ;
12- using Oxide . Ext . Discord . DiscordObjects ;
13- #endif
7+ using System . Collections ;
8+ using System . Text ;
9+ using UnityEngine . Networking ;
1410
1511namespace Oxide . Plugins
1612{
17- [ Info ( "Teams Logger" , "NickRimmer" , "1.3 " ) ]
13+ [ Info ( "Teams Logger" , "NickRimmer" , "1.4 " ) ]
1814 [ Description ( "Simple plugin to log team events" ) ]
1915 public class TeamsLogger : RustPlugin
2016 {
21- #if DISCORD_INSTALLED
22- [ DiscordClient ]
23- private DiscordClient _client ;
24- private Channel _discordChannel ;
25- #endif
26-
2717 private PluginConfig _config ;
18+ private DiscordComponent _discord ;
2819
2920 void Init ( )
3021 {
3122 _config = Config . ReadObject < PluginConfig > ( ) ;
3223 if ( IsFirstRun ( ) ) LogCurrentTeams ( ) ;
33- }
34-
35- void OnServerInitialized ( )
36- {
37- #if DISCORD_INSTALLED
38- if ( _config . PrintToDiscord ) InitDiscord ( ) ;
39- #else
40- if ( _config . PrintToDiscord ) PrintWarning ( "To enable Discord features, please define DISCORD_INSTALLED directive" ) ;
41- #endif
42- }
4324
44- private void Unload ( )
45- {
46- #if DISCORD_INSTALLED
47- if ( _client != null ) Discord . CloseClient ( _client ) ;
48- #endif
25+ if ( ! string . IsNullOrEmpty ( _config . DiscordHookUrl ) )
26+ {
27+ var loader = new GameObject ( "WebObject" ) ;
28+ _discord = loader . AddComponent < DiscordComponent > ( ) . Configure ( _config . DiscordHookUrl ) ;
29+ }
4930 }
5031
5132 private void PrintToConsole ( string message ) => Puts ( message ) ;
@@ -60,25 +41,16 @@ private void PrintToFile(string message)
6041
6142 private void PrintToDiscord ( string message )
6243 {
63- #if DISCORD_INSTALLED
64- if ( _client ? . DiscordServer == null )
44+ if ( _discord == null )
6545 {
66- PrintWarning ( "Discord doesn't connected" ) ;
67- return ;
68- }
69-
70- if ( _discordChannel == null )
71- {
72- PrintWarning ( $ "Discord channel with name '{ _config . DiscordBot . ChannelName } ' not found") ;
46+ PrintWarning ( "Discord wasn't configured, message can't be sent" ) ;
7347 return ;
7448 }
7549
7650 var timestamp = DateTime . Now . ToString ( "HH:mm:ss" ) ;
7751 message = $ "{ timestamp } | { message } ";
78- _discordChannel . CreateMessage ( _client , message ) ;
79- #else
80- PrintWarning ( "To enable discord features, please define DISCORD_INSTALLED directive" ) ;
81- #endif
52+
53+ _discord . SendTextMessage ( message ) ;
8254 }
8355
8456 #region Log exist teams on first run
@@ -119,51 +91,6 @@ private string GetUserInfo(ulong userId)
11991 }
12092 #endregion
12193
122- #region Discord connection
123- #if DISCORD_INSTALLED
124- private void InitDiscord ( )
125- {
126- Puts ( "Init Discord connection..." ) ;
127- if ( string . IsNullOrEmpty ( _config . DiscordBot . ApiKey ) )
128- {
129- PrintError ( $ "To enable Discord messages you need to specify 'DiscordConfig.ApiKey' value in config") ;
130- return ;
131- }
132-
133- Discord . CreateClient ( this , _config . DiscordBot . ApiKey ) ;
134- }
135-
136- void Discord_GuildCreate ( Guild guild )
137- {
138- if ( _config . DiscordBot . EnableBotStatus )
139- _client . UpdateStatus ( new Presence { Game = new Ext . Discord . DiscordObjects . Game
140- {
141- Name = covalence . Server . Name ,
142- Type = ActivityType . Watching
143- } } ) ;
144-
145- UpdateDiscordChannel ( ) ;
146- }
147-
148- void Discord_ChannelCreate ( Channel channel ) => UpdateDiscordChannel ( ) ;
149- void Discord_ChannelUpdate ( Channel updatedChannel , Channel oldChannel ) => UpdateDiscordChannel ( ) ;
150- void Discord_ChannelDelete ( Channel channel ) => UpdateDiscordChannel ( ) ;
151- //void Discord_GuildUpdate(Guild guild) => UpdateDiscordChannel();
152-
153- private void UpdateDiscordChannel ( )
154- {
155- _discordChannel = _client
156- . DiscordServer
157- . channels
158- . FirstOrDefault ( x => x . name . Equals ( _config . DiscordBot . ChannelName , StringComparison . InvariantCultureIgnoreCase ) ) ;
159-
160- if ( _discordChannel == null ) PrintWarning ( $ "Discord channel with name '{ _config . DiscordBot . ChannelName } ' not found") ;
161- else Puts ( $ "Connected to discord channel: '{ _discordChannel . name } ' ({ _discordChannel . id } )") ;
162- }
163-
164- #endif
165- #endregion
166-
16794 #region Team hooks
16895
16996 void OnTeamInvite ( BasePlayer inviter , BasePlayer target ) => LogKey (
@@ -302,26 +229,110 @@ private class PluginConfig
302229 [ JsonProperty ( "Print logs to Discord" ) ]
303230 public bool PrintToDiscord { get ; set ; } = false ;
304231
305- public PluginDiscordConfig DiscordBot = new PluginDiscordConfig ( ) ;
232+ [ JsonProperty ( "Discord hook url" ) ]
233+ public string DiscordHookUrl { get ; set ; }
234+ }
235+
236+ private class PluginData
237+ {
238+ public bool FirstStart { get ; set ; } = true ;
239+ }
306240
307- public class PluginDiscordConfig
241+ #endregion
242+
243+ #region Shared.Components
244+
245+ private class DiscordComponent : MonoBehaviour
246+ {
247+ private const float PostDelay = 1f ;
248+
249+ private readonly Queue < object > _queue = new Queue < object > ( ) ;
250+ private string _url ;
251+ private bool _busy = false ;
252+
253+ public DiscordComponent Configure ( string url )
308254 {
309- [ JsonProperty ( "Api key" ) ]
310- public string ApiKey { get ; set ; }
255+ if ( url == null ) throw new ArgumentNullException ( nameof ( url ) ) ;
256+ _url = url ;
311257
312- [ JsonProperty ( "Channel name" ) ]
313- public string ChannelName { get ; set ; } = "teams-logger" ;
258+ return this ;
259+ }
314260
315- [ JsonProperty ( "Show server name in status" ) ]
316- public bool EnableBotStatus { get ; set ; } = true ;
261+ public DiscordComponent SendTextMessage ( string message , params object [ ] args )
262+ {
263+ message = args ? . Any ( ) == true ? string . Format ( message , args ) : message ;
264+ return AddQueue ( new MessageRequest ( message ) ) ;
317265 }
318- }
319266
320- private class PluginData
321- {
322- public bool FirstStart { get ; set ; } = true ;
267+ #region Send requests to server
268+
269+ private DiscordComponent AddQueue ( object request )
270+ {
271+ _queue . Enqueue ( request ) ;
272+
273+ if ( ! _busy )
274+ StartCoroutine ( ProcessQueue ( ) ) ;
275+
276+ return this ;
277+ }
278+
279+ private IEnumerator ProcessQueue ( )
280+ {
281+ if ( _busy ) yield break ;
282+ _busy = true ;
283+
284+ while ( _queue . Any ( ) )
285+ {
286+ var request = _queue . Dequeue ( ) ;
287+ yield return ProcessRequest ( request ) ;
288+ }
289+
290+ _busy = false ;
291+ }
292+
293+ private IEnumerator ProcessRequest ( object request )
294+ {
295+ if ( string . IsNullOrEmpty ( _url ) )
296+ {
297+ print ( "[ERROR] Discord webhook URL wasn't specified" ) ;
298+ yield break ;
299+ }
300+
301+ var data = Encoding . UTF8 . GetBytes ( JsonConvert . SerializeObject ( request ) ) ;
302+ var uh = new UploadHandlerRaw ( data ) { contentType = "application/json" } ;
303+ var www = UnityWebRequest . Post ( _url , UnityWebRequest . kHttpVerbPOST ) ;
304+ www . uploadHandler = uh ;
305+
306+ yield return www . SendWebRequest ( ) ;
307+
308+ if ( www . isNetworkError || www . isHttpError )
309+ print ( $ "ERROR: { www . error } | { www . downloadHandler ? . text } ") ;
310+
311+ www . Dispose ( ) ;
312+
313+ // to avoid spam requests to Discord
314+ yield return new WaitForSeconds ( PostDelay ) ;
315+ }
316+
317+ #endregion
318+
319+ #region Requests
320+
321+ private class MessageRequest
322+ {
323+ [ JsonProperty ( "content" ) ]
324+ public string Content { get ; set ; }
325+
326+ public MessageRequest ( string content )
327+ {
328+ if ( content == null ) throw new ArgumentNullException ( nameof ( content ) ) ;
329+ Content = content ;
330+ }
331+ }
332+
333+ #endregion
323334 }
324335
325336 #endregion
326337 }
327- }
338+ }
0 commit comments