Skip to content

ShreyasPrasad/codemafia

Repository files navigation

codemafia

How to Play

codemafia is a take on the game of Codenames, in which teams compete to the guess the coloured words indicated by their "spymaster". In this variant, however, each team has an undercover operative that can see the other team's words as well as the black word. Their objective is to sabotage their own team's attempts to guess correctly.

Architecture

The project consists of a front and back end, both of which are built using Rust. The backend leverages the Axum server framework and highly relies on Tokio tasks and message passing to orchestrate a real-time game. The frontend is built using the Yew framework, allowing for static WASM resources to be compiled and served.

Backend

The backend high leverages the Tokio async runtime to maintain and coordinate active games. Each player's WebSocket connection is contained in a single Tokio task. These client tasks submit client messages materialized by the WebSocket connection to the game server (another Tokio task). Similarly, the client tasks relay events they receive from the game server downstream back to the player using the WebSocket.

Synchronization

Whenever possible, channels and message passing are used in place of conventional Mutex-based locking. In particular, tokio::sync::mpsc allows for a number of Tokio tasks to concurrently send messages to a single receiving task. The messages are then processed synchronously by the receiving task. When one-off messages need to be asynchronously returned the sender, tokio::sync::oneshot is frequently used.

Game Creation

When a game is created, a unique 4-character code is generated and returned to the creator so they can distribute it to other players. When other players join using the room code, they are added to the list of players under the Room structure.

Event Generation

Events are the messages sent from the server back to the client. The backend includes a robust event generation and dispatch system. Any task can submit an event with any number of recipients, each specified by their game ID or in-game role. The EventDispatcher is responsible for accepting an event tagged with a recipient and contacting the necessary client tasks. The flexibility of this system can be observed in the game code that dispatches different board information to different players, based on their role. Ensuring a separation of concerns between game code and event dispatching makes it easy to keep the game code minimal and maintainable.

Sharing Types

To support real-time communication between the frontend and backend, WebSockets are leveraged. Given that Rust is used across the stack, the opportunity to share WebSocket message structures exists. The shared crate contains these shared rust structures. The frontend is responsible for receiving/processes server event structures and sending client message structures, whereas the backend sends server events and receives/processes client messages. Using a shared crate leverages Rust's powerful type system for validating and working with socket messages.

  • All the supported shared messages are specified under the message module.
  • All the supported shared events are specified under the events module.

Motivation

The big motivation behind this project was to gain more exposure to async programming in Rust. In particular, the project makes use of tokio primitives and uses the axum web framework to maintain websocket connections with clients. Hopefully, this project can serve as a resource for future devs looking to create a full-stack Rust project, with shared types between the front and back end.

Also, this project was an opportunity to delve deeper into WASM-based frontend apps, the supposed cryptonite to the JavaScript framework monopoly.

About

A mafia-esque variant of the game Codenames, made using Rust.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages