Skip to content

Commit 237d536

Browse files
author
Alex L
authored
patch infinite money glitch by mutexing coin transfers and blackjack (#526)
1 parent 8bedc02 commit 237d536

File tree

4 files changed

+58
-24
lines changed

4 files changed

+58
-24
lines changed

src/commandDetails/coin/transfer.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import { SapphireClient, container } from '@sapphire/framework';
22
import { CommandInteraction, EmbedBuilder, Message, User, userMention } from 'discord.js';
33
import {
4-
CodeyCommandOptionType,
54
CodeyCommandDetails,
5+
CodeyCommandOptionType,
6+
SapphireAfterReplyType,
67
SapphireMessageExecuteType,
7-
getUserFromMessage,
88
SapphireMessageResponseWithMetadata,
9-
SapphireAfterReplyType,
9+
getUserFromMessage,
1010
} from '../../codeyCommand';
1111
import { getCoinBalanceByUserId, transferTracker } from '../../components/coin';
1212
import { getCoinEmoji } from '../../components/emojis';
13+
import { gamesByPlayerId } from '../../components/games/blackjack.js';
1314

1415
const coinTransferExecuteCommand: SapphireMessageExecuteType = async (
1516
client,
@@ -57,6 +58,20 @@ const coinTransferExecuteCommand: SapphireMessageExecuteType = async (
5758
return new SapphireMessageResponseWithMetadata(`You can't transfer less than 1 coin.`, {});
5859
}
5960

61+
if (transferTracker.transferringUsers.has(sendingUser.id)) {
62+
return new SapphireMessageResponseWithMetadata(
63+
`Please finish your current transfer first.`,
64+
{},
65+
);
66+
}
67+
68+
if (gamesByPlayerId.has(sendingUser.id)) {
69+
return new SapphireMessageResponseWithMetadata(
70+
`Please finish your current blackjack game before transferring coins.`,
71+
{},
72+
);
73+
}
74+
6075
const transfer = await transferTracker.startTransfer(
6176
sendingUser,
6277
receivingUser,

src/commandDetails/games/blackjack.ts

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,39 @@
11
import { container } from '@sapphire/framework';
22
import {
3-
Colors,
4-
EmbedBuilder,
5-
ButtonBuilder,
6-
ButtonStyle,
73
ActionRowBuilder,
4+
ButtonBuilder,
85
ButtonInteraction,
6+
ButtonStyle,
7+
Colors,
98
ComponentType,
9+
EmbedBuilder,
1010
} from 'discord.js';
1111
import {
12+
CodeyCommandDetails,
13+
CodeyCommandOptionType,
14+
SapphireMessageExecuteType,
15+
SapphireMessageResponse,
16+
getUserFromMessage,
17+
} from '../../codeyCommand';
18+
import {
19+
UserCoinEvent,
1220
adjustCoinBalanceByUserId,
1321
getCoinBalanceByUserId,
14-
UserCoinEvent,
22+
transferTracker,
1523
} from '../../components/coin';
1624
import { getCoinEmoji, getEmojiByName } from '../../components/emojis';
1725
import {
1826
BlackjackAction,
1927
BlackjackHand,
2028
BlackjackStage,
2129
CardSuit,
22-
endGame,
2330
GameState,
31+
endGame,
32+
gamesByPlayerId,
2433
performGameAction,
2534
startGame,
2635
} from '../../components/games/blackjack';
2736
import { pluralize } from '../../utils/pluralize';
28-
import {
29-
CodeyCommandDetails,
30-
CodeyCommandOptionType,
31-
SapphireMessageExecuteType,
32-
SapphireMessageResponse,
33-
getUserFromMessage,
34-
} from '../../codeyCommand';
3537

3638
// CodeyCoin constants
3739
const DEFAULT_BET = 10;
@@ -223,6 +225,14 @@ const blackjackExecuteCommand: SapphireMessageExecuteType = async (
223225
return `You don't have enough coins to place that bet. ${getEmojiByName('codey_sad')}`;
224226
}
225227

228+
if (transferTracker.transferringUsers.has(author)) {
229+
return `Please finish your current coin transfer before starting a game.`;
230+
}
231+
232+
if (gamesByPlayerId.has(author)) {
233+
return `Please finish your current game before starting another one!`;
234+
}
235+
226236
// Initialize the game
227237
let game = startGame(bet, author, channel);
228238
if (!game) {

src/components/coin.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
import _, { uniqueId } from 'lodash';
2-
import { openDB } from './db';
31
import { SapphireClient } from '@sapphire/framework';
42
import {
5-
Colors,
63
ActionRowBuilder,
4+
BaseMessageOptions,
75
ButtonBuilder,
6+
ButtonStyle,
7+
Colors,
88
EmbedBuilder,
99
User,
10-
ButtonStyle,
11-
BaseMessageOptions,
1210
} from 'discord.js';
11+
import _, { uniqueId } from 'lodash';
1312
import { SapphireSentMessageType } from '../codeyCommand';
13+
import { updateMessageEmbed } from '../utils/embeds';
1414
import { pluralize } from '../utils/pluralize';
15+
import { openDB } from './db';
1516
import { getCoinEmoji, getEmojiByName } from './emojis';
16-
import { updateMessageEmbed } from '../utils/embeds';
1717

1818
export enum BonusType {
1919
Daily = 0,
@@ -323,9 +323,11 @@ const TransferTimeout = 600000; // in ms (600000 ms == 10 mins)
323323

324324
class TransferTracker {
325325
transfers: Map<string, Transfer>; // id, transfer
326+
transferringUsers: Set<string>;
326327

327328
constructor() {
328329
this.transfers = new Map<string, Transfer>();
330+
this.transferringUsers = new Set<string>();
329331
}
330332
getTransferFromId(id: string): Transfer | undefined {
331333
return this.transfers.get(id);
@@ -351,8 +353,9 @@ class TransferTracker {
351353
reason: reason,
352354
result: TransferResult.Pending,
353355
};
354-
const transfer = new Transfer(channelId, client, transferId, transferState);
356+
const transfer = new Transfer(channelId, client, transferId, transferState, this);
355357
this.transfers.set(transferId, transfer);
358+
this.transferringUsers.add(sender.id);
356359
setTimeout(async () => {
357360
if (transfer.state.result === TransferResult.Pending) {
358361
transfer.state.result = TransferResult.Timeout;
@@ -370,6 +373,7 @@ class TransferTracker {
370373
throw new Error(`No transfer with transfer ID ${transferId} found`);
371374
}
372375

376+
this.transferringUsers.delete(transfer.state.sender.id);
373377
if (transfer.state.result === TransferResult.Pending) return;
374378
await transfer.handleTransaction();
375379
}
@@ -383,17 +387,20 @@ export class Transfer {
383387
state: TransferState;
384388
transferId: string;
385389
transferMessage!: SapphireSentMessageType;
390+
tracker: TransferTracker;
386391

387392
constructor(
388393
channelId: string,
389394
client: SapphireClient<boolean>,
390395
transferId: string,
391396
transferState: TransferState,
397+
tracker: TransferTracker,
392398
) {
393399
this.channelId = channelId;
394400
this.state = transferState;
395401
this.client = client;
396402
this.transferId = transferId;
403+
this.tracker = tracker;
397404
}
398405

399406
// called if state is (believed to be) no longer pending. Transfers coins and updates balances if transfer is confirmed
@@ -420,6 +427,8 @@ export class Transfer {
420427
<string>(this.state.reason ?? ''),
421428
this.client.user?.id,
422429
);
430+
431+
this.tracker.transferringUsers.delete(this.state.sender.id);
423432
}
424433
}
425434

src/components/games/blackjack.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export enum CardSuit {
3838
}
3939

4040
// keeps track of games by player's Discord IDs
41-
const gamesByPlayerId = new Map<string, BlackjackGame>();
41+
export const gamesByPlayerId = new Map<string, BlackjackGame>();
4242

4343
// maps action Enum to game action
4444
const gameActionsMap = new Map<BlackjackAction, () => Action>([

0 commit comments

Comments
 (0)