-
Notifications
You must be signed in to change notification settings - Fork 34
/
GameStateValidator.ts
171 lines (157 loc) 路 5.4 KB
/
GameStateValidator.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import MessagingTunnel from '@bot/messaging/MessagingTunnel';
import GameStateManager from '@bot/state/GameStateManager';
import InteractionConfig from '@config/InteractionConfig';
import { GuildMember, PermissionString } from 'discord.js';
/**
* Validates state of a messaging tunnel
* in order to create a game or a duel request.
*
* @author Utarwyn
* @since 2.2.0
*/
export default class GameStateValidator {
/**
* List with all permissions that the bot needs to work properly.
* @private
*/
private static readonly PERM_LIST: PermissionString[] = [
'ADD_REACTIONS',
'READ_MESSAGE_HISTORY',
'SEND_MESSAGES',
'VIEW_CHANNEL'
]; // bot doesn't need manage message to delete its own message
/**
* Stores configuration of the module.
* @private
*/
private readonly manager: GameStateManager;
/**
* Creates the game state validator.
*
* @param manager game state manager
*/
constructor(manager: GameStateManager) {
this.manager = manager;
}
/**
* Retrieves the module configuration.
*/
public get config(): InteractionConfig {
return this.manager.bot.configuration;
}
/**
* Retrieves collection of member cooldown end times.
*/
public get cooldownEndTimes(): Map<string, number> {
return this.manager.memberCooldownEndTimes;
}
/**
* Checks if an interaction through a messaging tunnel is valid or not.
*
* @param tunnel messaging tunnel object
* @returns true if the interaction is valid, false otherwise
*/
public isInteractionValid(tunnel: MessagingTunnel): boolean {
return this.isMessagingAllowed(tunnel) && this.isMemberAllowed(tunnel.author);
}
/**
* Checks if creating a new game is possible based on channel state and author.
*
* @param tunnel messaging tunnel object
* @param invited invited guild member, can be undefined
* @returns true if a game can be created, false otherwise
*/
public isNewGamePossible(tunnel: MessagingTunnel, invited?: GuildMember): boolean {
return (
// Check if one of both entites is already playing
!this.manager.gameboards.some(gameboard =>
[tunnel.author, invited].some(
entity => entity && gameboard.entities.includes(entity)
)
) &&
// Check if there is already a game inside the channel or bypass option enabled
(this.config.simultaneousGames ||
!this.manager.gameboards.some(
gameboard => gameboard.tunnel.channel === tunnel.channel
))
);
}
/**
* Checks if a messaging tunnel takes place in an allowed channel.
*
* @param tunnel module messaging tunnel
* @returns true if channel allowed
* @private
*/
private isMessagingAllowed(tunnel: MessagingTunnel): boolean {
return (
this.hasPermissionsInChannel(tunnel) &&
(!this.config.allowedChannelIds ||
this.config.allowedChannelIds.length === 0 ||
this.config.allowedChannelIds.includes(tunnel.channel.id))
);
}
/**
* Checks if bot has permissions to operate
* in a specific channel based on the messaging tunnel.
*
* @param tunnel messaging tunnel
* @return true if bot got all permissions, false otherwise
* @private
*/
private hasPermissionsInChannel(tunnel: MessagingTunnel): boolean {
const allowed =
tunnel.channel.guild.me
?.permissionsIn(tunnel.channel)
?.has(GameStateValidator.PERM_LIST) ?? false;
if (!allowed) {
console.error(
`Cannot operate because of a lack of permissions in the channel #${tunnel.channel.name}`
);
}
return allowed;
}
/**
* Checks if the messaging tunnel can be
* used for a specific member of the guild.
*
* @param member discord.js guild member object
* @returns true if the member got permissions
* @private
*/
private isMemberAllowed(member: GuildMember): boolean {
return this.isMemberAllowedByRole(member) && this.isMemberAllowedByCooldown(member);
}
/**
* Verifies if a member can use
* the messaging tunnel based on its roles.
*
* @param member discord.js member object
* @returns true if the member is allowed based on its roles
* @private
*/
private isMemberAllowedByRole(member: GuildMember): boolean {
return (
!this.config.allowedRoleIds ||
this.config.allowedRoleIds.length == 0 ||
member.permissions.has('ADMINISTRATOR') ||
member.roles.cache.some(role => this.config.allowedRoleIds!.includes(role.id))
);
}
/**
* Verifies if a member can use
* the messaging tunnel based on its cooldown.
*
* @param member discord.js guild member instance
* @returns true if the user do not have a valid cooldown in progress
* @private
*/
private isMemberAllowedByCooldown(member: GuildMember): boolean {
return (
!this.config.requestCooldownTime ||
this.config.requestCooldownTime === 0 ||
!this.cooldownEndTimes.has(member.id) ||
this.cooldownEndTimes.get(member.id)! < Date.now()
);
}
}