public void SocketMessage(object sender, MessageEventArgs e) { RPayload payload = JsonConvert.DeserializeObject <RPayload>(e.Data); if (payload.Sequence.HasValue) { client.Sequence = payload.Sequence.Value; } if (client.Settings.Debugging) { Interface.Oxide.LogDebug($"Recieved socket message, OpCode: {payload.OpCode}"); } switch (payload.OpCode) { // Dispatch (dispatches an event) case OpCodes.Dispatch: { if (client.Settings.Debugging) { Interface.Oxide.LogDebug($"Recieved OpCode 0, event: {payload.EventName}"); } // Listed here: https://discordapp.com/developers/docs/topics/gateway#commands-and-events-gateway-events switch (payload.EventName) { case "READY": { /* * Moved to DiscordClient.Initialized -> Not at all cases will READY be called. * client.UpdatePluginReference(); * client.CallHook("DiscordSocket_Initialized"); */ Ready ready = payload.EventData.ToObject <Ready>(); if (ready.Guilds.Count != 0) { Interface.Oxide.LogWarning($"[Discord Extension] Your bot was found in {ready.Guilds.Count} Guilds!"); } if (ready.Guilds.Count == 0 && client.Settings.Debugging) { Interface.Oxide.LogDebug($"[Discord Extension] Ready event but no Guilds sent."); } client.DiscordServers = ready.Guilds; client.SessionID = ready.SessionID; client.CallHook("Discord_Ready", null, ready); break; } case "RESUMED": { Resumed resumed = payload.EventData.ToObject <Resumed>(); Interface.Oxide.LogWarning("[Discord Extension] Session resumed!"); client.CallHook("Discord_Resumed", null, resumed); break; } case "CHANNEL_CREATE": { Channel channelCreate = payload.EventData.ToObject <Channel>(); if (channelCreate.type == ChannelType.DM || channelCreate.type == ChannelType.GROUP_DM) { client.DMs.Add(channelCreate); } else { client.GetGuild(channelCreate.guild_id).channels.Add(channelCreate); } client.CallHook("Discord_ChannelCreate", null, channelCreate); break; } case "CHANNEL_UPDATE": { Channel channelUpdated = payload.EventData.ToObject <Channel>(); Channel channelPrevious = (channelUpdated.type == ChannelType.DM || channelUpdated.type == ChannelType.GROUP_DM) ? client.DMs?.FirstOrDefault(x => x.id == channelUpdated.id) : client.GetGuild(channelUpdated.guild_id).channels.FirstOrDefault(x => x.id == channelUpdated.id); if (channelPrevious != null) { if (channelUpdated.type == ChannelType.DM || channelUpdated.type == ChannelType.GROUP_DM) { client.DMs.Remove(channelPrevious); } else { client.GetGuild(channelUpdated.guild_id).channels.Remove(channelPrevious); } } if (channelUpdated.type == ChannelType.DM || channelUpdated.type == ChannelType.GROUP_DM) { client.DMs.Add(channelUpdated); } else { client.GetGuild(channelUpdated.guild_id).channels.Add(channelUpdated); } client.CallHook("Discord_ChannelUpdate", null, channelUpdated, channelPrevious); break; } case "CHANNEL_DELETE": { Channel channelDelete = payload.EventData.ToObject <Channel>(); client.GetGuild(channelDelete.guild_id).channels.Remove(channelDelete); client.CallHook("Discord_ChannelDelete", null, channelDelete); break; } case "CHANNEL_PINS_UPDATE": { ChannelPinsUpdate channelPinsUpdate = payload.EventData.ToObject <ChannelPinsUpdate>(); client.CallHook("Discord_ChannelPinsUpdate", null, channelPinsUpdate); break; } // NOTE: Some elements of Guild object is only sent with GUILD_CREATE case "GUILD_CREATE": { Guild guildCreate = payload.EventData.ToObject <Guild>(); string g_id = guildCreate.id; bool g_unavail = guildCreate.unavailable ?? false; if (client.GetGuild(g_id) == null) { client.DiscordServers.Add(guildCreate); if (client.Settings.Debugging) { Interface.Oxide.LogDebug($"[Discord Extension] Guild ID ({g_id}) added to list."); } } else if (g_unavail == false && (client.GetGuild(g_id)?.unavailable ?? false) == true) { client.UpdateGuild(g_id, guildCreate); if (client.Settings.Debugging) { Interface.Oxide.LogDebug($"[Discord Extension] Guild ID ({g_id}) updated to list."); } } client.CallHook("Discord_GuildCreate", null, guildCreate); break; } case "GUILD_UPDATE": { Guild guildUpdate = payload.EventData.ToObject <Guild>(); //client.UpdateGuild(guildUpdate.id, guildUpdate); // <-- DON'T REPLACE GUILD REFERENCE!!!! client.GetGuild(guildUpdate.id).Update(guildUpdate); client.CallHook("Discord_GuildUpdate", null, guildUpdate); break; } case "GUILD_DELETE": { Guild guildDelete = payload.EventData.ToObject <Guild>(); if (guildDelete.unavailable ?? false == true) // outage { Interface.Oxide.LogDebug($"[DEBUG] Guild ID {guildDelete.id} outage!"); client.UpdateGuild(guildDelete.id, guildDelete); } else { Interface.Oxide.LogDebug($"[DEBUG] Guild ID {guildDelete.id} removed from list"); client.DiscordServers.Remove(client.GetGuild(guildDelete.id)); // guildDelete may not be same reference } client.CallHook("Discord_GuildDelete", null, guildDelete); break; } case "GUILD_BAN_ADD": { User bannedUser = payload.EventData.ToObject <BanObject>().user; client.CallHook("Discord_GuildBanAdd", null, bannedUser); break; } case "GUILD_BAN_REMOVE": { User unbannedUser = payload.EventData.ToObject <BanObject>().user; client.CallHook("Discord_GuildBanRemove", null, unbannedUser); break; } case "GUILD_EMOJIS_UPDATE": { GuildEmojisUpdate guildEmojisUpdate = payload.EventData.ToObject <GuildEmojisUpdate>(); client.CallHook("Discord_GuildEmojisUpdate", null, guildEmojisUpdate); break; } case "GUILD_INTEGRATIONS_UPDATE": { GuildIntergrationsUpdate guildIntergrationsUpdate = payload.EventData.ToObject <GuildIntergrationsUpdate>(); client.CallHook("Discord_GuildIntergrationsUpdate", null, guildIntergrationsUpdate); break; } case "GUILD_MEMBER_ADD": { GuildMemberAdd memberAdded = payload.EventData.ToObject <GuildMemberAdd>(); GuildMember guildMember = memberAdded as GuildMember; client.GetGuild(memberAdded.guild_id)?.members.Add(guildMember); client.CallHook("Discord_MemberAdded", null, guildMember); break; } case "GUILD_MEMBER_REMOVE": { GuildMemberRemove memberRemoved = payload.EventData.ToObject <GuildMemberRemove>(); GuildMember member = client.GetGuild(memberRemoved.guild_id)?.members.FirstOrDefault(x => x.user.id == memberRemoved.user.id); if (member != null) { client.GetGuild(memberRemoved.guild_id)?.members.Remove(member); } client.CallHook("Discord_MemberRemoved", null, member); break; } case "GUILD_MEMBER_UPDATE": { GuildMemberUpdate memberUpdated = payload.EventData.ToObject <GuildMemberUpdate>(); GuildMember newMember = client.GetGuild(memberUpdated.guild_id)?.members.FirstOrDefault(x => x.user.id == memberUpdated.user.id); GuildMember oldMember = Newtonsoft.Json.Linq.JObject.FromObject(newMember).ToObject <GuildMember>(); // lazy way to copy the object if (newMember != null) { if (memberUpdated.user != null) { newMember.user = memberUpdated.user; } if (memberUpdated.nick != null) { newMember.nick = memberUpdated.nick; } if (memberUpdated.roles != null) { newMember.roles = memberUpdated.roles; } } client.CallHook("Discord_GuildMemberUpdate", null, memberUpdated, oldMember); break; } case "GUILD_MEMBERS_CHUNK": { GuildMembersChunk guildMembersChunk = payload.EventData.ToObject <GuildMembersChunk>(); client.CallHook("Discord_GuildMembersChunk", null, guildMembersChunk); break; } case "GUILD_ROLE_CREATE": { GuildRoleCreate guildRoleCreate = payload.EventData.ToObject <GuildRoleCreate>(); client.GetGuild(guildRoleCreate.guild_id)?.roles.Add(guildRoleCreate.role); client.CallHook("Discord_GuildRoleCreate", null, guildRoleCreate.role); break; } case "GUILD_ROLE_UPDATE": { GuildRoleUpdate guildRoleUpdate = payload.EventData.ToObject <GuildRoleUpdate>(); Role newRole = guildRoleUpdate.role; Role oldRole = client.GetGuild(guildRoleUpdate.guild_id).roles.FirstOrDefault(x => x.id == newRole.id); if (oldRole != null) { client.GetGuild(guildRoleUpdate.guild_id).roles.Remove(oldRole); } client.GetGuild(guildRoleUpdate.guild_id).roles.Add(newRole); client.CallHook("Discord_GuildRoleUpdate", null, newRole, oldRole); break; } case "GUILD_ROLE_DELETE": { GuildRoleDelete guildRoleDelete = payload.EventData.ToObject <GuildRoleDelete>(); Role deletedRole = client.GetGuild(guildRoleDelete.guild_id)?.roles.FirstOrDefault(x => x.id == guildRoleDelete.role_id); if (deletedRole != null) { client.GetGuild(guildRoleDelete.guild_id).roles.Remove(deletedRole); } client.CallHook("Discord_GuildRoleDelete", null, deletedRole); break; } case "MESSAGE_CREATE": { Message messageCreate = payload.EventData.ToObject <Message>(); Channel c; if (messageCreate.guild_id != null) { c = client.GetGuild(messageCreate.guild_id)?.channels.FirstOrDefault(x => x.id == messageCreate.channel_id); } else { c = client.DMs.FirstOrDefault(x => x.id == messageCreate.channel_id); } if (c != null) { c.last_message_id = messageCreate.id; } client.CallHook("Discord_MessageCreate", null, messageCreate); break; } case "MESSAGE_UPDATE": { Message messageUpdate = payload.EventData.ToObject <Message>(); client.CallHook("Discord_MessageUpdate", null, messageUpdate); break; } case "MESSAGE_DELETE": { MessageDelete messageDelete = payload.EventData.ToObject <MessageDelete>(); client.CallHook("Discord_MessageDelete", null, messageDelete); break; } case "MESSAGE_DELETE_BULK": { MessageDeleteBulk messageDeleteBulk = payload.EventData.ToObject <MessageDeleteBulk>(); client.CallHook("Discord_MessageDeleteBulk", null, messageDeleteBulk); break; } case "MESSAGE_REACTION_ADD": { MessageReactionUpdate messageReactionAdd = payload.EventData.ToObject <MessageReactionUpdate>(); client.CallHook("Discord_MessageReactionAdd", null, messageReactionAdd); break; } case "MESSAGE_REACTION_REMOVE": { MessageReactionUpdate messageReactionRemove = payload.EventData.ToObject <MessageReactionUpdate>(); client.CallHook("Discord_MessageReactionRemove", null, messageReactionRemove); break; } case "MESSAGE_REACTION_REMOVE_ALL": { MessageReactionRemoveAll messageReactionRemoveAll = payload.EventData.ToObject <MessageReactionRemoveAll>(); client.CallHook("Discord_MessageReactionRemoveAll", null, messageReactionRemoveAll); break; } /* * From Discord API docs: * The user object within this event can be partial, the only field which must be sent is the id field, everything else is optional. * Along with this limitation, no fields are required, and the types of the fields are not validated. * Your client should expect any combination of fields and types within this event. */ case "PRESENCE_UPDATE": { PresenceUpdate presenceUpdate = payload.EventData.ToObject <PresenceUpdate>(); User updatedPresence = presenceUpdate?.user; if (updatedPresence != null) { var updatedMember = client.GetGuild(presenceUpdate.guild_id)?.members.FirstOrDefault(x => x.user.id == updatedPresence.id); if (updatedMember != null) { //updatedMember.user = updatedPresence; updatedMember.user.Update(updatedPresence); } } client.CallHook("Discord_PresenceUpdate", null, updatedPresence); break; } // Bots should ignore this case "PRESENCES_REPLACE": break; case "TYPING_START": { TypingStart typingStart = payload.EventData.ToObject <TypingStart>(); client.CallHook("Discord_TypingStart", null, typingStart); break; } case "USER_UPDATE": { User userUpdate = payload.EventData.ToObject <User>(); //GuildMember memberUpdate = client.DiscordServer.members.FirstOrDefault(x => x.user.id == userUpdate.id); //memberUpdate.user = userUpdate; var guilds = client.DiscordServers.Where(x => x.members.FirstOrDefault(y => y.user.id == userUpdate.id) != null).ToList(); foreach (Guild g in guilds) { GuildMember memberUpdate = g.members.FirstOrDefault(x => x.user.id == userUpdate.id); memberUpdate.user = userUpdate; } client.CallHook("Discord_UserUpdate", null, userUpdate); break; } case "VOICE_STATE_UPDATE": { VoiceState voiceStateUpdate = payload.EventData.ToObject <VoiceState>(); client.CallHook("Discord_VoiceStateUpdate", null, voiceStateUpdate); break; } case "VOICE_SERVER_UPDATE": { VoiceServerUpdate voiceServerUpdate = payload.EventData.ToObject <VoiceServerUpdate>(); client.CallHook("Discord_VoiceServerUpdate", null, voiceServerUpdate); break; } case "WEBHOOKS_UPDATE": { WebhooksUpdate webhooksUpdate = payload.EventData.ToObject <WebhooksUpdate>(); client.CallHook("Discord_WebhooksUpdate", null, webhooksUpdate); break; } default: { client.CallHook("Discord_UnhandledEvent", null, payload); Interface.Oxide.LogWarning($"[Discord Extension] [Debug] Unhandled event: {payload.EventName}"); break; } } break; } // Heartbeat // https://discordapp.com/developers/docs/topics/gateway#gateway-heartbeat case OpCodes.Heartbeat: { Interface.Oxide.LogInfo($"[Discord Extension] Manully sent heartbeat (received opcode 1)"); client.SendHeartbeat(); break; } // Reconnect (used to tell clients to reconnect to the gateway) // we should immediately reconnect here case OpCodes.Reconnect: { Interface.Oxide.LogInfo($"[Discord Extension] Reconnect has been called (opcode 7)! Reconnecting..."); webSocket.hasConnectedOnce = true; // attempt resume opcode webSocket.Connect(client.WSSURL); break; } // Invalid Session (used to notify client they have an invalid session ID) case OpCodes.InvalidSession: { Interface.Oxide.LogInfo($"[Discord Extension] Invalid Session ID opcode recieved!"); client.requestReconnect = true; webSocket.hasConnectedOnce = false; webSocket.Disconnect(false); break; } // Hello (sent immediately after connecting, contains heartbeat and server debug information) case OpCodes.Hello: { Hello hello = payload.EventData.ToObject <Hello>(); client.CreateHeartbeat(hello.HeartbeatInterval); // Client should now perform identification //client.Identify(); if (webSocket.hasConnectedOnce) { Interface.Oxide.LogWarning("[Discord Extension] Attempting resume opcode..."); client.Resume(); } else { client.Identify(); webSocket.hasConnectedOnce = true; } break; } // Heartbeat ACK (sent immediately following a client heartbeat // that was received) // (See 'zombied or failed connections') case OpCodes.HeartbeatACK: { client.HeartbeatACK = true; break; } default: { Interface.Oxide.LogInfo($"[Discord Extension] Unhandled OP code: code {payload.OpCode}"); break; } } }
public void SocketMessage(object sender, MessageEventArgs e) { RPayload payload = JsonConvert.DeserializeObject <RPayload>(e.Data); if (payload.Sequence.HasValue) { client.Sequence = payload.Sequence.Value; } if (client.Settings.Debugging) { Interface.Oxide.LogDebug($"Recieved socket message, OpCode: {payload.OpCode}"); } switch (payload.OpCode) { // Dispatch (dispatches an event) case OpCodes.Dispatch: { if (client.Settings.Debugging) { Interface.Oxide.LogDebug($"Recieved OpCode 0, event: {payload.EventName}"); } // Listed here: https://discordapp.com/developers/docs/topics/gateway#commands-and-events-gateway-events switch (payload.EventName) { case "READY": { client.UpdatePluginReference(); client.CallHook("DiscordSocket_Initialized"); Ready ready = payload.EventData.ToObject <Ready>(); if (ready.Guilds.Count > 1) { Interface.Oxide.LogWarning($"[Oxide.Ext.Discord] Your bot was found in more than one Guild. Multiple guilds are not supported by this extension."); } if (ready.Guilds.Count == 0 && client.Settings.Debugging) { Interface.Oxide.LogDebug($"Ready event but no Guilds sent."); } client.DiscordServer = ready.Guilds.FirstOrDefault(); client.SessionID = ready.SessionID; client.CallHook("Discord_Ready", null, ready); break; } case "RESUMED": { Resumed resumed = payload.EventData.ToObject <Resumed>(); client.CallHook("Discord_Resumed", null, resumed); break; } case "CHANNEL_CREATE": { Channel channelCreate = payload.EventData.ToObject <Channel>(); client.DiscordServer.channels.Add(channelCreate); client.CallHook("Discord_ChannelCreate", null, channelCreate); break; } case "CHANNEL_UPDATE": { Channel channelUpdated = payload.EventData.ToObject <Channel>(); Channel channelPrevious = client.DiscordServer.channels.FirstOrDefault(x => x.id == channelUpdated.id); if (channelPrevious != null) { client.DiscordServer.channels.Remove(channelPrevious); } client.DiscordServer.channels.Add(channelUpdated); client.CallHook("Discord_ChannelUpdate", null, channelUpdated, channelPrevious); break; } case "CHANNEL_DELETE": { Channel channelDelete = payload.EventData.ToObject <Channel>(); client.DiscordServer.channels.Remove(channelDelete); client.CallHook("Discord_ChannelDelete", null, channelDelete); break; } case "CHANNEL_PINS_UPDATE": { ChannelPinsUpdate channelPinsUpdate = payload.EventData.ToObject <ChannelPinsUpdate>(); client.CallHook("Discord_ChannelPinsUpdate", null, channelPinsUpdate); break; } // this isn't set up right // https://discordapp.com/developers/docs/topics/gateway#guild-create case "GUILD_CREATE": { Guild guildCreate = payload.EventData.ToObject <Guild>(); client.DiscordServer = guildCreate; client.CallHook("Discord_GuildCreate", null, guildCreate); break; } case "GUILD_UPDATE": { Guild guildUpdate = payload.EventData.ToObject <Guild>(); client.CallHook("Discord_GuildUpdate", null, guildUpdate); break; } case "GUILD_DELETE": { Guild guildDelete = payload.EventData.ToObject <Guild>(); client.CallHook("Discord_GuildDelete", null, guildDelete); break; } case "GUILD_BAN_ADD": { User bannedUser = payload.EventData.ToObject <BanObject>().user; client.CallHook("Discord_GuildBanAdd", null, bannedUser); break; } case "GUILD_BAN_REMOVE": { User unbannedUser = payload.EventData.ToObject <BanObject>().user; client.CallHook("Discord_GuildBanRemove", null, unbannedUser); break; } case "GUILD_EMOJIS_UPDATE": { GuildEmojisUpdate guildEmojisUpdate = payload.EventData.ToObject <GuildEmojisUpdate>(); client.CallHook("Discord_GuildEmojisUpdate", null, guildEmojisUpdate); break; } case "GUILD_INTEGRATIONS_UPDATE": { GuildIntergrationsUpdate guildIntergrationsUpdate = payload.EventData.ToObject <GuildIntergrationsUpdate>(); client.CallHook("Discord_GuildIntergrationsUpdate", null, guildIntergrationsUpdate); break; } case "GUILD_MEMBER_ADD": { GuildMemberAdd memberAdded = payload.EventData.ToObject <GuildMemberAdd>(); GuildMember guildMember = memberAdded as GuildMember; client.DiscordServer.members.Add(guildMember); client.CallHook("Discord_MemberAdded", null, guildMember); break; } case "GUILD_MEMBER_REMOVE": { GuildMemberRemove memberRemoved = payload.EventData.ToObject <GuildMemberRemove>(); GuildMember member = client.DiscordServer.members.FirstOrDefault(x => x.user.id == memberRemoved.user.id); if (member != null) { client.DiscordServer.members.Remove(member); } client.CallHook("Discord_MemberRemoved", null, member); break; } case "GUILD_MEMBER_UPDATE": { GuildMemberUpdate memberUpdated = payload.EventData.ToObject <GuildMemberUpdate>(); GuildMember oldMember = client.DiscordServer.members.FirstOrDefault(x => x.user.id == memberUpdated.user.id); if (oldMember != null) { client.DiscordServer.members.Remove(oldMember); } client.CallHook("Discord_GuildMemberUpdate", null, memberUpdated, oldMember); break; } case "GUILD_MEMBERS_CHUNK": { GuildMembersChunk guildMembersChunk = payload.EventData.ToObject <GuildMembersChunk>(); client.CallHook("Discord_GuildMembersChunk", null, guildMembersChunk); break; } case "GUILD_ROLE_CREATE": { GuildRoleCreate guildRoleCreate = payload.EventData.ToObject <GuildRoleCreate>(); client.DiscordServer.roles.Add(guildRoleCreate.role); client.CallHook("Discord_GuildRoleCreate", null, guildRoleCreate.role); break; } case "GUILD_ROLE_UPDATE": { GuildRoleUpdate guildRoleUpdate = payload.EventData.ToObject <GuildRoleUpdate>(); Role newRole = guildRoleUpdate.role; Role oldRole = client.DiscordServer.roles.FirstOrDefault(x => x.id == newRole.id); if (oldRole != null) { client.DiscordServer.roles.Remove(oldRole); } client.DiscordServer.roles.Add(newRole); client.CallHook("Discord_GuildRoleUpdate", null, newRole, oldRole); break; } case "GUILD_ROLE_DELETE": { GuildRoleDelete guildRoleDelete = payload.EventData.ToObject <GuildRoleDelete>(); Role deletedRole = client.DiscordServer.roles.FirstOrDefault(x => x.id == guildRoleDelete.role_id); if (deletedRole != null) { client.DiscordServer.roles.Remove(deletedRole); } client.CallHook("Discord_GuildRoleDelete", null, deletedRole); break; } case "MESSAGE_CREATE": { Message messageCreate = payload.EventData.ToObject <Message>(); client.CallHook("Discord_MessageCreate", null, messageCreate); break; } case "MESSAGE_UPDATE": { Message messageUpdate = payload.EventData.ToObject <Message>(); client.CallHook("Discord_MessageUpdate", null, messageUpdate); break; } case "MESSAGE_DELETE": { MessageDelete messageDelete = payload.EventData.ToObject <MessageDelete>(); client.CallHook("Discord_MessageDelete", null, messageDelete); break; } case "MESSAGE_DELETE_BULK": { MessageDeleteBulk messageDeleteBulk = payload.EventData.ToObject <MessageDeleteBulk>(); client.CallHook("Discord_MessageDeleteBulk", null, messageDeleteBulk); break; } case "MESSAGE_REACTION_ADD": { MessageReactionUpdate messageReactionAdd = payload.EventData.ToObject <MessageReactionUpdate>(); client.CallHook("Discord_MessageReactionAdd", null, messageReactionAdd); break; } case "MESSAGE_REACTION_REMOVE": { MessageReactionUpdate messageReactionRemove = payload.EventData.ToObject <MessageReactionUpdate>(); client.CallHook("Discord_MessageReactionRemove", null, messageReactionRemove); break; } case "MESSAGE_REACTION_REMOVE_ALL": { MessageReactionRemoveAll messageReactionRemoveAll = payload.EventData.ToObject <MessageReactionRemoveAll>(); client.CallHook("Discord_MessageReactionRemoveAll", null, messageReactionRemoveAll); break; } case "PRESENCE_UPDATE": { PresenceUpdate presenceUpdate = payload.EventData.ToObject <PresenceUpdate>(); User updatedPresence = presenceUpdate?.user; if (updatedPresence != null) { var updatedMember = client.DiscordServer.members.FirstOrDefault(x => x.user.id == updatedPresence.id); if (updatedMember != null) { updatedMember.user = updatedPresence; } } client.CallHook("Discord_PresenceUpdate", null, updatedPresence); break; } case "TYPING_START": { TypingStart typingStart = payload.EventData.ToObject <TypingStart>(); client.CallHook("Discord_TypingStart", null, typingStart); break; } case "USER_UPDATE": { User userUpdate = payload.EventData.ToObject <User>(); GuildMember memberUpdate = client.DiscordServer.members.FirstOrDefault(x => x.user.id == userUpdate.id); memberUpdate.user = userUpdate; client.CallHook("Discord_UserUpdate", null, userUpdate); break; } case "VOICE_STATE_UPDATE": { VoiceState voiceStateUpdate = payload.EventData.ToObject <VoiceState>(); client.CallHook("Discord_VoiceStateUpdate", null, voiceStateUpdate); break; } case "VOICE_SERVER_UPDATE": { VoiceServerUpdate voiceServerUpdate = payload.EventData.ToObject <VoiceServerUpdate>(); client.CallHook("Discord_VoiceServerUpdate", null, voiceServerUpdate); break; } case "WEBHOOKS_UPDATE": { WebhooksUpdate webhooksUpdate = payload.EventData.ToObject <WebhooksUpdate>(); client.CallHook("Discord_WebhooksUpdate", null, webhooksUpdate); break; } default: { client.CallHook("Discord_UnhandledEvent", null, payload); Interface.Oxide.LogWarning($"[Discord Ext] [Debug] Unhandled event: {payload.EventName}"); break; } } break; } // Heartbeat // https://discordapp.com/developers/docs/topics/gateway#gateway-heartbeat case OpCodes.Heartbeat: { Interface.Oxide.LogInfo($"[DiscordExt] Manully sent heartbeat (received opcode 1)"); client.SendHeartbeat(); break; } // Reconnect (used to tell clients to reconnect to the gateway) // we should immediately reconnect here case OpCodes.Reconnect: { Interface.Oxide.LogInfo($"[DiscordExt] Reconnect has been called (opcode 7)! Reconnecting..."); webSocket.Connect(client.WSSURL); break; } // Invalid Session (used to notify client they have an invalid session ID) case OpCodes.InvalidSession: { Interface.Oxide.LogInfo($"[DiscordExt] Invalid Session ID opcode recieved!"); break; } // Hello (sent immediately after connecting, contains heartbeat and server debug information) case OpCodes.Hello: { Hello hello = payload.EventData.ToObject <Hello>(); client.CreateHeartbeat(hello.HeartbeatInterval); // Client should now perform identification client.Identify(); break; } // Heartbeat ACK (sent immediately following a client heartbeat // that was received) // This should be changed: https://discordapp.com/developers/docs/topics/gateway#heartbeating // (See 'zombied or failed connections') case OpCodes.HeartbeatACK: break; default: { Interface.Oxide.LogInfo($"[DiscordExt] Unhandled OP code: code {payload.OpCode}"); break; } } }