OverloadedOrama

Making a Discord Bot with Godot (Part Three)

Jul 3rd, 2019
135
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. extends HTTPRequest
  2.  
  3. var token := "YourTokenHere" #make sure to actually replace this with your token!
  4. var client : WebSocketClient
  5. var heartbeat_interval : float
  6. var last_sequence : float
  7. var session_id : String
  8. var heartbeat_ack_received := true
  9. var invalid_session_is_resumable : bool
  10.  
  11. func _ready() -> void:
  12. randomize()
  13. client = WebSocketClient.new()
  14. client.connect_to_url("wss://gateway.discord.gg/?v=6&encoding=json")
  15. client.connect("connection_established", self, "_connection_established")
  16. client.connect("connection_closed", self, "_connection_closed")
  17. client.connect("server_close_request", self, "_server_close_request")
  18. client.connect("data_received", self, "_data_received")
  19.  
  20. func _process(delta : float) -> void:
  21. #check if the client is not disconnected, there's no point to poll it if it is
  22. if client.get_connection_status() != NetworkedMultiplayerPeer.CONNECTION_DISCONNECTED:
  23. client.poll()
  24. else:
  25. #If it is disconnected, try to resume
  26. client.connect_to_url("wss://gateway.discord.gg/?v=6&encoding=json")
  27.  
  28. func _connection_established(protocol : String) -> void:
  29. print("We are connected! Protocol: %s" % protocol)
  30.  
  31. func _connection_closed(was_clean_close : bool) -> void:
  32. print("We disconnected. Clean close: %s" % was_clean_close)
  33.  
  34. func _server_close_request(code : int, reason : String) -> void:
  35. print("The server requested a clean close. Code: %s, reason: %s" % [code, reason])
  36.  
  37. func _data_received() -> void:
  38. var packet := client.get_peer(1).get_packet()
  39. var data := packet.get_string_from_utf8()
  40. var json_parsed := JSON.parse(data)
  41. var dict : Dictionary = json_parsed.result
  42. var op = str(dict["op"]) #convert it to string for easier checking
  43. print(op)
  44. match op:
  45. "0": #Opcode 0 Dispatch (Events)
  46. handle_events(dict)
  47. "9": #Opcode 9 Invalid Session
  48. invalid_session_is_resumable = dict["d"]
  49. $InvalidSessionTimer.one_shot = true
  50. $InvalidSessionTimer.wait_time = rand_range(1, 5)
  51. $InvalidSessionTimer.start()
  52. "10": #Opcode 10 Hello
  53. #Set our timer
  54. heartbeat_interval = dict["d"]["heartbeat_interval"] / 1000
  55. $HeartbeatTimer.wait_time = heartbeat_interval
  56. $HeartbeatTimer.start()
  57.  
  58. var d := {}
  59. if !session_id:
  60. #Send Opcode 2 Identify to the Gateway
  61. d = {
  62. "op" : 2,
  63. "d" : { "token" : token, "properties" : {} }
  64. }
  65. else:
  66. #Send Opcode 6 Resume to the Gateway
  67. d = {
  68. "op" : 6,
  69. "d" : { "token" : token, "session_id" : session_id, "seq" : last_sequence}
  70. }
  71. send_dictionary_as_packet(d)
  72. "11": #Opcode 11 Heartbeat ACK
  73. heartbeat_ack_received = true
  74. print("We've received a Heartbeat ACK from the gateway.")
  75.  
  76.  
  77. func _on_HeartbeatTimer_timeout() -> void: #Send Opcode 1 Heartbeat payloads every heartbeat_interval
  78. if !heartbeat_ack_received:
  79. #We haven't received a Heartbeat ACK back, so we'll disconnect
  80. client.disconnect_from_host(1002)
  81. return
  82. var d := {"op" : 1, "d" : last_sequence}
  83. send_dictionary_as_packet(d)
  84. heartbeat_ack_received = false
  85. print("We've send a Heartbeat to the gateway.")
  86.  
  87. func send_dictionary_as_packet(d : Dictionary) -> void:
  88. var query = to_json(d)
  89. client.get_peer(1).put_packet(query.to_utf8())
  90.  
  91. func handle_events(dict : Dictionary) -> void:
  92. last_sequence = dict["s"]
  93. var event_name : String = dict["t"]
  94. print(event_name)
  95. match event_name:
  96. "READY":
  97. session_id = dict["d"]["session_id"]
  98. "GUILD_MEMBER_ADD":
  99. var guild_id = dict["d"]["guild_id"]
  100. var headers := ["Authorization: Bot %s" % token]
  101.  
  102. #Get all channels of the guild
  103. request("https://discordapp.com/api/guilds/%s/channels" % guild_id, headers)
  104. var data_received = yield(self, "request_completed") #await
  105. var channels = JSON.parse(data_received[3].get_string_from_utf8()).result
  106. var channel_id
  107. for channel in channels:
  108. #Find the first text channel and get its ID
  109. if str(channel["type"]) == "0":
  110. channel_id = channel["id"]
  111. break
  112. if channel_id: #if we found at least one text channel
  113. var username = dict["d"]["user"]["username"]
  114. var message_to_send := {"content" : "Welcome %s!" % username}
  115. var query := JSON.print(message_to_send)
  116. headers.append("Content-Type: application/json")
  117. request("https://discordapp.com/api/v6/channels/%s/messages" % channel_id, headers, true, HTTPClient.METHOD_POST, query)
  118. "MESSAGE_CREATE":
  119. var channel_id = dict["d"]["channel_id"]
  120. var message_content = dict["d"]["content"]
  121.  
  122. var headers := ["Authorization: Bot %s" % token, "Content-Type: application/json"]
  123. var query : String
  124.  
  125. if message_content.to_upper() == "ORAMA":
  126. var message_to_send := {"content" : "Interactive"}
  127. query = JSON.print(message_to_send)
  128. elif message_content.to_upper() == "WEBSITE":
  129. var message_to_send := {"content" : "http://oramagamestudios.com/"}
  130. query = JSON.print(message_to_send)
  131. elif message_content.to_upper() == "BLOG":
  132. var message_to_send := {"content" : "https://functionoverload590613498.wordpress.com"}
  133. query = JSON.print(message_to_send)
  134. elif message_content.to_upper() == "GITHUB":
  135. var message_to_send := {"content" : "https://github.com/OverloadedOrama"}
  136. query = JSON.print(message_to_send)
  137. if query:
  138. request("https://discordapp.com/api/v6/channels/%s/messages" % channel_id, headers, true, HTTPClient.METHOD_POST, query)
  139.  
  140. func _on_InvalidSessionTimer_timeout() -> void:
  141. var d := {}
  142. if invalid_session_is_resumable && session_id:
  143. #Send Opcode 6 Resume to the Gateway
  144. d = {
  145. "op" : 6,
  146. "d" : { "token" : token, "session_id" : session_id, "seq" : last_sequence}
  147. }
  148. else:
  149. #Send Opcode 2 Identify to the Gateway
  150. d = {
  151. "op" : 2,
  152. "d" : { "token" : token, "properties" : {} }
  153. }
  154. send_dictionary_as_packet(d)
RAW Paste Data