Skip to content

Commit

Permalink
fix: infinite xp glitch (#114)
Browse files Browse the repository at this point in the history
  • Loading branch information
HeadTriXz committed Apr 21, 2024
1 parent 710e994 commit 83023b1
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 20 deletions.
43 changes: 36 additions & 7 deletions apps/barry/src/modules/leveling/events/voiceStateUpdate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ import { DiscordAPIError } from "@discordjs/rest";
*/
type GuildGatewayVoiceState = PickRequired<GatewayVoiceState, "guild_id">;

/**
* Represents the type of voice channel update.
*/
enum VoiceChannelUpdateType {
JOIN = 1 << 0,
LEAVE = 1 << 1
}

/**
* Represents an event handler that tracks user voice activity.
*/
Expand All @@ -34,20 +42,41 @@ export default class extends Event<LevelingModule> {
return;
}

const blacklisted = await this.#isBlacklisted(state, channelID);
if (blacklisted) {
return;
const type = this.#getType(state, channelID);
if (type & VoiceChannelUpdateType.LEAVE) {
await this.#updateVoiceMinutes(state.guild_id, state.user_id, channelID);
}

if (state.channel_id === null) {
return this.#updateVoiceMinutes(state.guild_id, state.user_id, channelID);
}
if (type & VoiceChannelUpdateType.JOIN) {
const blacklisted = await this.#isBlacklisted(state, channelID);
if (blacklisted) {
return;
}

if (channelID === undefined) {
await this.client.redis.set(`voice:${state.guild_id}:${state.user_id}`, Date.now());
}
}

/**
* Gets the type of voice channel update.
*
* @param state The voice state data received from the gateway.
* @param channelID The ID of the previous channel the user was in.
* @returns The type of voice channel update.
*/
#getType(state: GatewayVoiceState, channelID?: string): VoiceChannelUpdateType {
let type = 0;
if (state.channel_id !== null) {
type |= VoiceChannelUpdateType.JOIN;
}

if (channelID !== undefined || state.channel_id === null) {
type |= VoiceChannelUpdateType.LEAVE;
}

return type;
}

/**
* Checks if the user (or channel) is blacklisted from receiving experience points.
*
Expand Down
21 changes: 12 additions & 9 deletions apps/barry/tests/modules/leveling/events/voiceStateUpdate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ describe("VoiceStateUpdate Event", () => {
guildID: guildID,
enabled: true,
ignoredChannels: [],
ignoredRoles: []
ignoredRoles: [],
messageRep: false
});

vi.spyOn(module.memberActivity, "getOrCreate").mockResolvedValue({
Expand All @@ -52,6 +53,8 @@ describe("VoiceStateUpdate Event", () => {
reputation: 2,
voiceMinutes: 0
});

vi.mocked(redis.get).mockResolvedValue(null);
});

afterEach(() => {
Expand Down Expand Up @@ -119,34 +122,34 @@ describe("VoiceStateUpdate Event", () => {
expect(incrementSpy).toHaveBeenCalledOnce();
});

it("should not update voice minutes if the channel is blacklisted", async () => {
it("should not keep track of voice minutes if the channel is blacklisted", async () => {
vi.mocked(event.module.settings.getOrCreate).mockResolvedValue({
guildID: guildID,
enabled: true,
ignoredChannels: [channelID],
ignoredRoles: []
ignoredRoles: [],
messageRep: false
});
const incrementSpy = vi.spyOn(event.module.memberActivity, "increment");

await event.execute(state, channelID);

expect(incrementSpy).not.toHaveBeenCalled();
expect(redis.set).not.toHaveBeenCalled();
});

it("should not update voice minutes if the user has a blacklisted role", async () => {
it("should not keep track of voice minutes if the user has a blacklisted role", async () => {
state.member = { ...mockMember, roles: ["68239102456844360"] };

vi.mocked(event.module.settings.getOrCreate).mockResolvedValue({
guildID: guildID,
enabled: true,
ignoredChannels: [],
ignoredRoles: ["68239102456844360"]
ignoredRoles: ["68239102456844360"],
messageRep: false
});
const incrementSpy = vi.spyOn(event.module.memberActivity, "increment");

await event.execute(state, channelID);

expect(incrementSpy).not.toHaveBeenCalled();
expect(redis.set).not.toHaveBeenCalled();
});

it("should not update voice minutes if the start time is not cached", async () => {
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 83023b1

Please sign in to comment.