Skip to content
vihduttaPublic

About

Multiplayer game with a tasty twist.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Repository files navigation

foodwars

A multiplayer chef battle arena for your browser.

Build and deploy status Node.js 22 or newer TypeScript

What is foodwars?

Foodwars is a multiplayer top-down shooter where you battle other chefs in a shared kitchen. It runs in your browser and allows you to join friends using a kitchen code or link. You can also sign in with Google to save your results and see how you compare on the leaderboards!

Usage

Enter a username, join a kitchen, and click START COOKING! to start. Share the kitchen link with a friend if you want to join the same game.

Control Action
W / A / S / D Move
Mouse Aim
Left mouse button Fire
R Reload

Installation

You need Node.js 22 or newer, npm, Redis, and Google OAuth credentials. To save accounts and game stats, you will also need a Supabase project. The database setup is covered below. You can use Docker Compose to run the app and Redis together.

git clone https://github.com/vihdutta/foodwars.git
cd foodwars
nvm install
nvm use
npm ci

If you do not use nvm, install a compatible Node.js version before running npm ci.

Create a .env file in the project folder using the settings below. For local Google sign-in, register http://localhost:8080/auth/google/callback as an authorized redirect URI and set GOOGLE_CALLBACK_URL to that exact value.

Start Redis, then start the application:

docker compose up -d redis
npm run dev

Open http://localhost:8080 to play. npm run dev builds the TypeScript files and starts the server. You will need to restart it after making changes.

To run both services in containers instead, with the same .env file:

docker compose up --build

To build and run the app without tsx, use npm run build followed by npm start.

Configuration

Variable Purpose
GOOGLE_CLIENT_ID Google OAuth client ID; required by the authentication setup.
GOOGLE_CLIENT_SECRET Google OAuth client secret.
GOOGLE_CALLBACK_URL Set to http://localhost:8080/auth/google/callback for local sign-in.
SESSION_SECRET Private random session signing secret; required in production. Generate one with node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))".
SUPABASE_URL Supabase project URL for accounts and persistent statistics.
SUPABASE_SECRET_KEY Server-side Supabase secret key. SUPABASE_SERVICE_ROLE_KEY is also supported.
REDIS_URL Defaults to redis://localhost:6379. Compose supplies redis://redis:6379.
PORT HTTP port; defaults to 8080. The supplied Compose mapping uses this default.
PUBLIC_URL Base URL for the OAuth callback when GOOGLE_CALLBACK_URL is unset; defaults to https://foodwars.vihdutta.com.
NODE_ENV Set to production for deployment; enables secure session cookies, requiring HTTPS.

Keep .env and Supabase server credentials private. The browser accesses account and statistics data through Express endpoints.

Database setup

The SQL files set up the database functions. You will need to create the users and game_results tables separately using the fields in src/services/supabase.ts. The schema needs unique users.google_user_id and users.username values, generated numeric primary keys, and a foreign key from game_results.google_user_id to users.google_user_id.

After creating the tables, apply the function definitions in sql/2_create_leaderboard_function.sql, sql/3_create_user_stats_function.sql, and sql/4_create_other_functions.sql. Review sql/5_grant_permissions.sql for execution grants.

Results for signed-in players are saved when a round ends or when they disconnect. Each disconnected session is saved as a separate result. If a save fails, the server logs the error but does not retry it later. This means results can be lost if the database goes down or the server crashes.

How it works

flowchart LR
    Browser[Browser · PixiJS + TypeScript] <-->|HTTP / Socket.IO| Server[Express + game server]
    Server <-->|Sessions / round statistics| Redis[(Redis)]
    Server <-->|Accounts / results / leaderboards| Supabase[(Supabase · PostgreSQL)]
    Browser <-->|Sign-in redirects| Google[Google OAuth]
    Server <-->|Passport authentication| Google
Loading

The Node.js server keeps track of the game. Redis stores sessions and stats for the current round, while Supabase stores accounts and past results. The browser uses PixiJS to draw the game and Tailwind CSS for the menus.

Development

Command What it does
npm run dev Build TypeScript and launch the server with tsx.
npm run build Compile server and browser TypeScript.
npm start Run the compiled server.
npm test Run regression tests.
npm run test:integration Build and run HTTP, socket, session, and round checks; requires Redis.
npm run check:supabase Check live tables and RPCs without writing records.
npm run check:supabase:writes Create disposable records, verify writes and aggregates, then remove them. Requires a configured database and write permissions.

The read check only checks that data can be read. To check inserts and updates too, use the write check. It creates temporary records and removes them afterward. The OAuth tests simulate responses from Google, so you will still need to test Google sign-in manually.

Project structure

foodwars/
├── .github/
│   └── workflows/       # Build, audit, test, and deploy
├── public/
│   ├── images/          # Game artwork
│   ├── js/              # Browser TypeScript modules
│   ├── index.html       # Game entry page
│   └── style.css
├── scripts/             # Integration and live database checks
├── sql/                 # PostgreSQL functions and grants
├── src/
│   ├── backend/         # Authentication, physics, maps, and rounds
│   ├── services/        # Redis, Supabase, and statistics persistence
│   ├── tilesets/        # Tiled maps and tileset definitions
│   ├── types/           # Shared game types
│   ├── constants.ts     # Game and server configuration
│   └── server.ts        # Express and Socket.IO server
├── tests/               # Regression tests
├── Dockerfile
├── docker-compose.yml
├── package.json
└── tsconfig.json

Deployment

The GitHub Actions workflow runs when you push to main. You can also start it manually from GitHub Actions. It installs and audits dependencies, builds the app, and runs the tests before pushing a Docker image and deploying it to AWS Lightsail over SSH.

Add these values to the GitHub production environment:

Kind Names
Variables DOCKERHUB_USERNAME, LIGHTSAIL_PUBLIC_IP, LIGHTSAIL_USERNAME
Secrets DOCKERHUB_ACCESS_TOKEN, LIGHTSAIL_SSH_KEY, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, SUPABASE_URL, SESSION_SECRET
Supabase secret SUPABASE_SECRET_KEY or SUPABASE_SERVICE_ROLE_KEY

Local .env values are not copied to GitHub. The workflow targets foodwars.vihdutta.com, writes the host configuration, and restarts the containers. It assumes Docker and NGINX are available on the host. Review the domain, DNS, and HTTPS configuration before using it for another deployment.

About

Multiplayer game with a tasty twist.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages