Skip to content
This repository has been archived by the owner on Jul 24, 2021. It is now read-only.

Commit

Permalink
New: Auto-join known players
Browse files Browse the repository at this point in the history
Spectating discord users will be automatically joined to the lobby if their saved in-game name matches an unlinked player from the capture.

See the README for more details.

Closes #33
  • Loading branch information
jftanner committed Oct 29, 2020
1 parent e5e2428 commit 486bdc7
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 11 deletions.
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ It's got a few features, so far:
- Automatically controls the server-mute and server-deafen settings for players in the voice channel.
- Automatically updates Discord nicknames to match in-game names, when possible. (And back!)
- Keeps the text channel clean, by removing commands and old lobby updates.
- Auto-joins returning players with the same in-game name. (No more `!sau join`!)

If there's another feature you'd really want, you can [request it](https://github.com/tanndev/silence-among-us/issues/new)!

Expand Down Expand Up @@ -118,7 +119,9 @@ Currently, the only configurable option is `prefix`, but this list will grow wit
_Note:_ Each deployed instance of the bot uses a different settings database.

#### Prefix
(**Default:** `!sau|!s`)
- **Default:** `!sau|!s`
- **Example:** `!sau config set prefix !sau|!s`

The `prefix` option allows you to change which prefixes the bot listens to.

If you want to set multiple options, you can separate prefixes with spaces or `|`.
Expand All @@ -131,6 +134,15 @@ If you want to run multiple instances of the bot, you'll need to set each of the

To make test them, you can use `!sau-rollcall` in a channel with all of them, to make sure they have unique prefixes.

#### Auto-join
- **Default:** `true`
- **Valid Options:** `on`, `off`, `true`, `false`
- **Example:** `!sau config set autojoin on`

With this feature enabled, discord users spectating an automated lobby will be automatically joined to the lobby if their saved in-game name matches an unlinked player from the capture. This auto-join is done whenever a user connects to the voice channel _and_ whenever the capture reports a new player has connected to the game. So users can connect to the game and discord in either order.

Use `!sau config set autojoin off` to disable this feature for your server.

## Privacy
**Note:** This section only applies to the Tanndev-hosted instances of the bot.
It's an open-source project, so we can't control what other people choose to do with the code.
Expand Down
10 changes: 9 additions & 1 deletion classes/GuildConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,18 @@ const SETTINGS = {
prefix: {
defaultValue: '!sau|!s',
setter: (value) => {
const stripped = value.toLowerCase().trim().split(/[\s|]+/g,).join('|');
const stripped = value.toLowerCase().trim().split(/[\s|]+/g).join('|');
if (!stripped) throw new Error("Can't set an empty command prefix.");
return stripped;
}
},
autojoin: {
defaultValue: true,
setter: (value) => {
if (value.match(/^(:?1|t(?:rue)?|y(?:es)?|on)$/i)) return true;
if (value.match(/^(:?0|f(?:alse)?|n(?:O)?|off)$/i)) return false;
throw new Error("Autojoin must be either `on` or `off`");
}
}
};

Expand Down
63 changes: 54 additions & 9 deletions classes/Lobby.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const { Permissions, MessageEmbed } = require('discord.js');
const { client, clientReady } = require('../discord-bot/discord-bot');
const Database = require('./Database');
const GuildConfig = require('./GuildConfig');
const UserConfig = require('./UserConfig');
const Player = require('./Player');
const Room = require('./Room');

Expand Down Expand Up @@ -100,7 +101,7 @@ const ready = clientReady
restoredPlayers.forEach(player => lobby._players.add(player));

// Handle everyone still in the channel.
await Promise.all(voiceChannel.members.map(member => lobby.guildMemberConnected(member)));
await Promise.all(voiceChannel.members.map(member => lobby.guildMemberConnected(member, false)));

// Handle everyone who has left.
await Promise.all(restoredPlayers
Expand Down Expand Up @@ -339,6 +340,10 @@ class Lobby {
this.scheduleInfoPost();
}

async getGuildConfig() {
return GuildConfig.load(this.voiceChannel.guild.id);
}

/**
* Searches for players in the lobby.
*
Expand All @@ -347,6 +352,7 @@ class Lobby {
*/
getGuildMemberPlayer(guildMember) {
// TODO Store a map of these, rather than a slow search.
if (!guildMember) return undefined;
return this.players.find(player => player.matchesGuildMember(guildMember));
}

Expand All @@ -357,13 +363,39 @@ class Lobby {
*/
getAmongUsPlayer(name) {
// TODO Store a map of these, rather than a slow search.
if (!name) return undefined;
return this.players.find(player => player.matchesAmongUsName(name));
}

async amongUsJoin({ name, color, dead }) {
async amongUsJoin({ name, color, dead }, allowAutoJoin = true) {
let player = this.getAmongUsPlayer(name);

// If there's no player yet, add them.
// If there's no player yet, try to auto-join them.
if (!player && allowAutoJoin) {
// Look for a valid auto-join target.
const guildConfig = await this.getGuildConfig();
if (guildConfig.get('autojoin')) {
const spectators = this.players.filter(player => player.isSpectating);
const playerCache = await Promise.all(spectators.map(async player => {
const { amongUsName } = await UserConfig.load(player.discordId);
return { player, amongUsName };
}));

// Find all matching players.
const matchingPlayers = playerCache
.filter(({ amongUsName }) => amongUsName === name)
.map(({ player }) => player);

// Only auto-join if there's exactly one matching player.
if (matchingPlayers.length === 1) {
player = matchingPlayers[0];
this.emit(`Auto-join guild member ${player.discordId} as "${name}".`);
player.joinGame(name);
}
}
}

// If there's still no player, create one.
if (!player) {
player = new Player(this);
this._players.add(player);
Expand Down Expand Up @@ -443,8 +475,8 @@ class Lobby {
return;
}

// For everyone else, add/update them
await this.amongUsJoin({ name, color, dead, disconnected });
// For everyone else, add/update them (without auto-join)
await this.amongUsJoin({ name, color, dead, disconnected }, false);
}

async guildMemberJoin(guildMember, amongUsName) {
Expand Down Expand Up @@ -500,8 +532,8 @@ class Lobby {
await player.leaveGame();
await this.setPlayerForCurrentPhase(player);

// If the player was being tracked by automation, create a new one.
if (color) await this.amongUsJoin({ name, color, dead });
// If the player was being tracked by automation, create a new one. (Without auto-joining.)
if (color) await this.amongUsJoin({ name, color, dead }, false);

// Schedule updates.
this.scheduleInfoPost();
Expand Down Expand Up @@ -532,7 +564,7 @@ class Lobby {
this.scheduleSave();
}

async guildMemberConnected(guildMember) {
async guildMemberConnected(guildMember, allowAutoJoin = true) {
// Ignore bots.
if (guildMember.user.bot) return null;

Expand All @@ -543,6 +575,19 @@ class Lobby {
this._players.add(player);
}

// Auto-join, if enabled.
if (allowAutoJoin && player.isSpectating) {
const guildConfig = await this.getGuildConfig();
if (guildConfig.get('autojoin')) {
const { amongUsName } = await UserConfig.load(guildMember.id);
const existingPlayer = this.getAmongUsPlayer(amongUsName);
if (existingPlayer && !existingPlayer.discordId) {
this.emit(`Auto-join guild member ${guildMember.id} as "${amongUsName}".`);
return this.guildMemberJoin(guildMember, amongUsName);
}
}
}

// Make sure their voice state matches the current game phase.
await this.setPlayerForCurrentPhase(player);

Expand Down Expand Up @@ -715,7 +760,7 @@ class Lobby {
*/
async scheduleInfoPost(options = {}) {
// Get the guild command prefix for command hints.
const guildConfig = await GuildConfig.load(this.voiceChannel.guild.id);
const guildConfig = await this.getGuildConfig();
const prefix = guildConfig.defaultPrefix;

// Get room info.
Expand Down

0 comments on commit 486bdc7

Please sign in to comment.