Skip to content

feat: customizable lobby size for bot games (Fixes #180)#197

Open
subha0319 wants to merge 3 commits into
ShrimpCryptid:developmentfrom
subha0319:development
Open

feat: customizable lobby size for bot games (Fixes #180)#197
subha0319 wants to merge 3 commits into
ShrimpCryptid:developmentfrom
subha0319:development

Conversation

@subha0319
Copy link
Copy Markdown

Problem

Currently, the game only generates bots to fulfill the minimum required player count (5 players). Users cannot choose to play larger games (e.g., 7 or 10 players) filled primarily with bots. This PR addresses [Issue #180] to allow the lobby host to set a custom target game size that the server will auto-fill with bot players.

Solution

I introduced a targetLobbySize variable to the lobby state and updated the bot generation logic in Lobby.java to fill the lobby up to this target size rather than the hardcoded MIN_PLAYERS. I also wired up a pre-existing but unused COMMAND_SET_LOBBY_SIZE WebSocket command in the backend and added a dropdown UI to the frontend for the lobby host to control this setting.

Type of change

  • New feature (non-breaking change which adds functionality)

Change summary:

  • Added targetLobbySize state tracking to the Java backend and modified bot generation math.
  • Wired up the set-lobby-size WebSocket command in SecretHitlerServer.java to update the lobby size securely.
  • Registered the new WebSocket command payload in the TypeScript definitions (commands.ts).
  • Added a dropdown UI in App.tsx for the host (VIP) to adjust the target game size.
  • Synchronized the target size state across all connected clients via the PACKET_LOBBY payload so non-hosts can view the updated settings.

Steps to Verify:

  1. Start both the Java backend (in debug mode via $env:DEBUG_MODE="true"; ./gradlew run) and the React frontend.
  2. In your primary browser window, create a new lobby and verify that a "Target Game Size" dropdown appears, defaulting to 5.
  3. Change the dropdown value to a larger number (e.g., 8).
  4. Open an Incognito/Private window and join the same lobby. Verify that this non-host player sees the static text Target Game Size: 8 and that it updates dynamically if the host changes it again.
  5. Have all human players select an icon, then click "Start Game" from the host window.
  6. Expected behavior: The game should start and the player list should reflect the total number of human players plus enough newly generated bots to exactly match the target game size selected by the host. (e.g., 2 Humans + 6 Bots = 8 Player Game).

Screenshots:

(screenshots showing the new dropdown in the lobby UI and the generated bots in-game)

  1. Dropdown in the lobby UI for Host: Screenshot 2026-04-26 150103

  2. Dropdown in the lobby UI for non-host player: Screenshot 2026-04-26 150202

  3. Generated bots in-game for Host: Screenshot 2026-04-26 150244

  4. Generated bots in-game for non-host: Screenshot 2026-04-26 150305

Keyfiles:

  1. backend/src/ main/java/server/SecretHitlerServer.java
  2. backend/src/main/java/server/util/Lobby.java
  3. frontend/src/App.tsx
  4. frontend/src/types/commands.ts

Copy link
Copy Markdown
Owner

@ShrimpCryptid ShrimpCryptid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, thank you so much for the contribution! I left some initial thoughts and suggestions here, feel free to re-request me once you've had a chance to take a look. I generally like this PR and I'm very pleased that it's such a small change overall :)

I will warn that it might take a while before these changes are populated on production, because the development branch and the production branch are out of sync due to some bugs that got introduced in the Typescript refactor. I haven't had time to dedicate to chasing those down yet.


static String DEFAULT_ICON = "p_default";

private int targetLobbySize = SecretHitlerGame.MIN_PLAYERS;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider renaming to minLobbySize?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed targetLobbySize to minLobbySize across both the Java backend and the React frontend state.

Comment thread frontend/src/App.tsx Outdated
<div style={{ marginTop: "5px", display: "flex", alignItems: "center", color: "white" }}>
<label style={{ marginRight: "10px" }}>Target Game Size:</label>
<select
value={this.state.targetLobbySize}
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't do this anywhere else on the app but I wonder if this value needs to be set optimistically in case of high latency. Not something that needs to be changed now!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left this as it is for now as suggested, but happy to revisit later if latency becomes an issue.

Comment thread frontend/src/App.tsx Outdated

{isVIP ? (
<div style={{ marginTop: "5px", display: "flex", alignItems: "center", color: "white" }}>
<label style={{ marginRight: "10px" }}>Target Game Size:</label>
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm trying to decide on the best language here, since I worry that "Target game size" isn't immediately obvious, and you can actually have more players than the target size. My next thought is "Minimum game size", but that might suggest to players that they have to hit a minimum # of players before they can start a game.

What do you think about changing this to "Game Size" and changing the options in the dropdown to {n}+ Players?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Game Size" sounds good.

Changed the label to "Game Size" with "{n}+ Players" options, and wrapped the <select> in the <label> for screen readers.

I also added a quick ternary check so it correctly says "10 Players" instead of "10+ Players" when maxed out, along with a small subtitle reminding players about the bots.

Comment thread frontend/src/App.tsx Outdated

{isVIP ? (
<div style={{ marginTop: "5px", display: "flex", alignItems: "center", color: "white" }}>
<label style={{ marginRight: "10px" }}>Target Game Size:</label>
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please change the label element here to wrap the select element for accessibility? Or add an id to the select and a for field to the label. https://dequeuniversity.com/rules/axe/4.5/select-name

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrapped the <select> in the <label> for accessibility.

Comment thread frontend/src/App.tsx
Comment on lines 949 to 954
<button
id={"lobby-change-icon-button"}
onClick={this.onClickChangeIcon}
>
CHANGE ICON
</button>
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image

It looks like this button got taller because of the added player configuration controls. Could you try reorganizing where the player select dropdown is in the DOM to prevent that? (This is also likely my fault due to some outdated button styling rules, sorry!)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved the new controls completely out of the top flex container, so the 'Change Icon' button is back to its normal size.

@subha0319 subha0319 requested a review from ShrimpCryptid April 28, 2026 18:57
@subha0319
Copy link
Copy Markdown
Author

subha0319 commented Apr 28, 2026

@ShrimpCryptid Thanks so much for the review! No worries at all about the deployment delay.

I've pushed a new commit that addresses all your feedback.

Let me know if everything looks good or if anything needs to be changed.

Copy link
Copy Markdown
Owner

@ShrimpCryptid ShrimpCryptid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry it took me a bit to get back to this! I like the changes, had one more suggestion.

Comment thread frontend/src/App.tsx Outdated
usernames: message[PARAM_USERNAMES],
icons: message[PARAM_ICON],
page: PAGE.LOBBY,
minLobbySize: message["minLobbySize"] || 5,
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please make minLobbySize into a constant?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've extracted the string key into a PARAM_MIN_LOBBY_SIZE constant on both the constants/index.ts and the SecretHitlerServer.java.

@subha0319 subha0319 requested a review from ShrimpCryptid May 9, 2026 12:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants