diff --git a/assets/openapi.json b/assets/openapi.json index 7385d82d..241479f5 100644 Binary files a/assets/openapi.json and b/assets/openapi.json differ diff --git a/assets/schemas.json b/assets/schemas.json index d4027444..29878690 100644 Binary files a/assets/schemas.json and b/assets/schemas.json differ diff --git a/package-lock.json b/package-lock.json index 16b2df2a..cfc708df 100644 Binary files a/package-lock.json and b/package-lock.json differ diff --git a/src/gateway/events/Connection.ts b/src/gateway/events/Connection.ts index bc74dee6..f0c82750 100644 --- a/src/gateway/events/Connection.ts +++ b/src/gateway/events/Connection.ts @@ -111,8 +111,8 @@ export async function Connection( if (socket.encoding === "etf" && !erlpack) throw new Error("Erlpack is not installed: 'npm i @yukikaze-bot/erlpack'"); - socket.version = Number(searchParams.get("version")) || 8; - if (socket.version != 8) + socket.version = Number(searchParams.get("v")) || 9; + if (socket.version != 9 && socket.version != 6) return socket.close(CLOSECODES.Invalid_API_version); // @ts-ignore diff --git a/src/gateway/opcodes/Identify.ts b/src/gateway/opcodes/Identify.ts index abbe77a5..25f31b81 100644 --- a/src/gateway/opcodes/Identify.ts +++ b/src/gateway/opcodes/Identify.ts @@ -409,41 +409,66 @@ export async function onIdentify(this: WebSocket, data: Payload) { const pending_guilds: Guild[] = []; // Generate guilds list ( make them unavailable if user is bot ) - const guilds: GuildOrUnavailable[] = members.map((member) => { - member.guild.channels = member.guild.channels - /* - //TODO maybe implement this correctly, by causing create and delete events for users who can newly view and not view the channels, along with doing these checks correctly, as they don't currently take into account that the owner of the guild is always able to view channels, with potentially other issues - .filter((channel) => { - const perms = Permissions.finalPermission({ - user: { - id: member.id, - roles: member.roles.map((x) => x.id), - }, - guild: member.guild, - channel, - }); + let guilds: GuildOrUnavailable[]; - return perms.has("VIEW_CHANNEL"); - }) - */ + if (this.version === 6) { + const membersByGuild = new Map(); + + for (const member of members) { + if (!membersByGuild.has(member.guild_id)) { + membersByGuild.set(member.guild_id, []); + } + + membersByGuild.get(member.guild_id)!.push({ + ...member.toPublicMember(), + roles: member.roles + .filter((r) => r.id !== member.guild.id) + .map((r) => r.id), + user: user.toPublicUser(), + }); + } + + guilds = members.map((member) => { + const g = member.guild; + + return { + ...g.toJSON(), + joined_at: member.joined_at, + channels: g.channels, + roles: g.roles, + emojis: g.emojis, + stickers: g.stickers, + voice_states: g.voice_states ?? [], + members: membersByGuild.get(g.id) ?? [], + member_count: membersByGuild.get(g.id)?.length ?? 1, + presences: [], + guild_scheduled_events: [], + threads: [], + large: false, + }; + }); + } else { + guilds = members.map((member) => { + member.guild.channels = member.guild.channels .map((channel) => { channel.position = member.guild.channel_ordering.indexOf(channel.id); return channel; }) .sort((a, b) => a.position - b.position); - if (user.bot) { - pending_guilds.push(member.guild); - return { id: member.guild.id, unavailable: true }; - } + if (user.bot) { + pending_guilds.push(member.guild); + return { id: member.guild.id, unavailable: true }; + } - return { - ...member.guild.toJSON(), - joined_at: member.joined_at, - guild_scheduled_events: [], - threads: [], - }; - }); + return { + ...member.guild.toJSON(), + joined_at: member.joined_at, + guild_scheduled_events: [], + threads: [], + }; + }); + } const generateGuildsListTime = taskSw.getElapsedAndReset(); // Generate user_guild_settings @@ -555,7 +580,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { d = { v: 6, ...base, - heartbeat_interval: 45_000, + heartbeat_interval: 45000, guilds, private_channels: channels, presences: [], @@ -745,50 +770,46 @@ export async function onIdentify(this: WebSocket, data: Payload) { }), ); - const pendingGuildsTime = Date.now(); + if (this.version == 9) { + const readySupplementalGuilds = (guilds.filter((guild) => !guild.unavailable) as Guild[]).map((guild) => { + return { + voice_states: guild.voice_states.map((state) => { + // quick fix -murdle + const voiceState: any = {}; + PublicVoiceStateProjection.forEach((x) => { + voiceState[x] = state[x]; + }); + return voiceState as PublicVoiceState; + }), + id: guild.id, + embedded_activities: [], + }; + }); - const readySupplementalGuilds = (guilds.filter((guild) => !guild.unavailable) as Guild[]).map((guild) => { - return { - voice_states: guild.voice_states.map((state) => { - // quick fix -murdle - const voiceState: any = {}; - PublicVoiceStateProjection.forEach((x) => { - voiceState[x] = state[x]; - }); - return voiceState as PublicVoiceState; - }), - id: guild.id, - embedded_activities: [], - }; - }); - - // TODO: ready supplemental - await Send(this, { - op: OPCodes.DISPATCH, - t: EVENTEnum.ReadySupplemental, - s: this.sequence++, - d: { - merged_presences: { - guilds: [], - friends: [], + // TODO: ready supplemental + await Send(this, { + op: OPCodes.DISPATCH, + t: EVENTEnum.ReadySupplemental, + s: this.sequence++, + d: { + merged_presences: { + guilds: [], + friends: [], + }, + // these merged members seem to be all users currently in vc in your guilds + merged_members: [], + lazy_private_channels: [], + guilds: readySupplementalGuilds, // { voice_states: [], id: string, embedded_activities: [] } + // embedded_activities are users currently in an activity? + disclose: [], // Config.get().general.uniqueUsernames ? ["pomelo"] : [] }, - // these merged members seem to be all users currently in vc in your guilds - merged_members: [], - lazy_private_channels: [], - guilds: readySupplementalGuilds, // { voice_states: [], id: string, embedded_activities: [] } - // embedded_activities are users currently in an activity? - disclose: [], // Config.get().general.uniqueUsernames ? ["pomelo"] : [] - }, - }); - - const readySupplementalTime = Date.now(); + }); + } //TODO send GUILD_MEMBER_LIST_UPDATE //TODO send VOICE_STATE_UPDATE to let the client know if another device is already connected to a voice channel await setupListener.call(this); - const setupListenerTime = Date.now(); - console.log(`[Gateway] IDENTIFY ${this.user_id} in ${totalSw.elapsed().totalMilliseconds}ms`, process.env.LOG_GATEWAY_TRACES ? JSON.stringify(d._trace, null, 2) : ""); }