Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .clippy.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Clippy configuration for OpenFight
# Clippy configuration for OpenCade
# See https://doc.rust-lang.org/clippy/configuration.html
# This file is read by `cargo clippy` at workspace root.
# Rust 1.78 reads this dotfile directly; keep a single config to avoid ambiguity.
Expand Down
12 changes: 6 additions & 6 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# OpenFight environment — copy to .env and adjust for your machine.
# OpenCade environment — copy to .env and adjust for your machine.
# Docker Compose reads this automatically when present.

DATABASE_URL=postgres://openfight:openfight@db:5432/openfight
DATABASE_URL=postgres://opencade:opencade@db:5432/opencade
# Generate with: openssl rand -hex 32
SESSION_SECRET=replace-with-at-least-32-random-bytes
ALLOWED_ORIGINS=http://localhost:1420,tauri://localhost
OPENFIGHT_ENV=production
OPENCADE_ENV=production

# Optional overrides:
# RUST_LOG=info
# PORT=8080
# POSTGRES_USER=openfight
# POSTGRES_PASSWORD=openfight
# POSTGRES_DB=openfight
# POSTGRES_USER=opencade
# POSTGRES_PASSWORD=opencade
# POSTGRES_DB=opencade
12 changes: 6 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ jobs:
postgres:
image: postgres:16-alpine
env:
POSTGRES_USER: openfight
POSTGRES_PASSWORD: openfight
POSTGRES_DB: openfight_test
POSTGRES_USER: opencade
POSTGRES_PASSWORD: opencade
POSTGRES_DB: opencade_test
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U openfight -d openfight_test"
--health-cmd "pg_isready -U opencade -d opencade_test"
--health-interval 5s
--health-timeout 5s
--health-retries 10
Expand All @@ -51,7 +51,7 @@ jobs:
- name: cargo test
run: cargo test --workspace --all-features --locked
env:
DATABASE_URL: postgres://openfight:openfight@localhost:5432/openfight_test
DATABASE_URL: postgres://opencade:opencade@localhost:5432/opencade_test
SESSION_SECRET: ci-test-secret-at-least-32-bytes-long

- name: Setup pnpm for protocol drift check
Expand All @@ -67,7 +67,7 @@ jobs:
run: pnpm install --frozen-lockfile

- name: Generate TypeScript protocol bindings
run: cargo test -p openfight-protocol --lib export_bindings
run: cargo test -p opencade-protocol --lib export_bindings

- name: Normalize generated protocol bindings
run: pnpm exec prettier --ignore-path /dev/null --write packages/protocol/src/generated
Expand Down
10 changes: 5 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# ──────────────────────────────────────────────────────────────
# OpenFight — .gitignore
# OpenCade — .gitignore
# Keep the repository free of build artefacts, secrets,
# proprietary binaries, ROMs, and user-local state.
# ──────────────────────────────────────────────────────────────
Expand Down Expand Up @@ -95,12 +95,12 @@ research/protocol/dumps/
!research/behavior/.gitkeep
!research/notes/.gitkeep

# ── OpenFight user data (mirrors %APPDATA%/OpenFight/) ──────
# ── OpenCade user data (mirrors %APPDATA%/OpenCade/) ──────
# Developers may run the app locally; never commit its state.
OpenFight/
%APPDATA%/OpenFight/
OpenCade/
%APPDATA%/OpenCade/
AppData/
*.openfight/
*.opencade/
config.toml
config.local.toml

Expand Down
16 changes: 8 additions & 8 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Repository Guidelines

> **Community:** https://discord.gg/Y4rDyTScPe — where we discuss OpenFight and everything around it (not only OpenFight).
> **Community:** https://discord.gg/Y4rDyTScPe — where we discuss OpenCade and everything around it (not only OpenCade).

## Project Overview

OpenFight — open-source arcade netplay platform, clean-room alternative to proprietary Fightcade. Monorepo at `D:/OpenFight` (Apache-2.0) with Tauri + React + TypeScript client and Rust + Axum + PostgreSQL server. `D:/Fightcade` (v2.1.45) is **read-only reference** — never copied into this repo (see `docs/ARCHITECTURE.md §2` and `docs/reference-fightcade-install.md`). Goal: lobby → challenge → versioned signaling → P2P (or WS relay) → safe emulator launch.
OpenCade — open-source arcade netplay platform, clean-room alternative to proprietary Fightcade. Monorepo at `D:/OpenCade` (Apache-2.0) with Tauri + React + TypeScript client and Rust + Axum + PostgreSQL server. `D:/Fightcade` (v2.1.45) is **read-only reference** — never copied into this repo (see `docs/ARCHITECTURE.md §2` and `docs/reference-fightcade-install.md`). Goal: lobby → challenge → versioned signaling → P2P (or WS relay) → safe emulator launch.

## Architecture & Data Flow

Expand All @@ -22,7 +22,7 @@ OpenFight — open-source arcade netplay platform, clean-room alternative to pro
- `packages/emulator-sdk/` — `pub trait EmulatorAdapter { detect/validate/get_version/launch/stop/configure }` + `LaunchCtx`, `ChildHandle`. No shell, path canonicalization + prefix check.
- `packages/game-definitions/` — declarative `games/*.toml` (`schema_version=1`, `id`, `name`, `emulator="fbneo"`, `[launch] args=["{rom}"]`, `[validation] required_files=["neogeo.zip"]`) + `src/loader.rs` + legacy `emulator/*.json` → TOML importer (build-time only).
- `adapters/fbneo/` — only required adapter in MVP (`fcadefbneo.exe` detection, `fcadefbneo.default.ini` version check, safe arg building). Future `flycast`/`snes9x` behind feature flags.
- `services/relay/` — placeholder crate `openfight-relay` (future STUN/TURN); not required for MVP (in-process WS relay suffices).
- `services/relay/` — placeholder crate `opencade-relay` (future STUN/TURN); not required for MVP (in-process WS relay suffices).
- `research/` — **not shipped** — `observations/`, `protocol/`, `binaries/` (gitignored), `network/`, `behavior/`, `notes/` + `GUARDRAILS.md`. Keep `research/binaries/.gitkeep`.
- `docs/` — `ARCHITECTURE.md` (authoritative), `reference-fightcade-install.md` (read-only install notes).
- `tests/`, `docker/`, `.github/workflows/` — integration tests, compose overlay, CI.
Expand All @@ -39,7 +39,7 @@ pnpm format && pnpm lint # prettier + eslint
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cargo run -p openfight-server -- --migrate # sqlx migrate run
cargo run -p opencade-server -- --migrate # sqlx migrate run
cargo run -p game-defs-import -- D:/Fightcade/emulator/fbneo_roms.json --out packages/game-definitions/games

# infra
Expand All @@ -48,13 +48,13 @@ curl http://localhost:8080/health && curl http://localhost:8080/ready
psql $DATABASE_URL -f apps/server/migrations/001_users.sql

# diagnostics
pnpm tauri dev -- --log openfight # client logs to %APPDATA%/OpenFight/logs/openfight.log
pnpm tauri dev -- --log opencade # client logs to %APPDATA%/OpenCade/logs/opencade.log
```

## Code Conventions & Common Patterns

- **Formatting:** `cargo fmt` (rustfmt edition 2021, `max_width=100`) and `pnpm format` (Prettier) — CI blocks on `fmt --check`. `clippy -D warnings` required.
- **Naming:** crates `openfight-*`, TS packages `@openfight/*`, adapters `fbneo` (kebab), TOML ids `sfiii3`, `kof98` (snake, lowercase). DB tables `snake_case`; API/WS JSON also `snake_case` via `#[serde(rename_all = "snake_case")]` for payload keys and `#[serde(rename = "type")]` for the `type` field (see `Envelope` in `apps/server/src/main.rs:17-24` and `packages/protocol`).
- **Naming:** crates `opencade-*`, TS packages `@opencade/*`, adapters `fbneo` (kebab), TOML ids `sfiii3`, `kof98` (snake, lowercase). DB tables `snake_case`; API/WS JSON also `snake_case` via `#[serde(rename_all = "snake_case")]` for payload keys and `#[serde(rename = "type")]` for the `type` field (see `Envelope` in `apps/server/src/main.rs:17-24` and `packages/protocol`).
- **Error handling:** `thiserror` + `anyhow` in Rust, never `unwrap()` in server paths; TS `Result<T,E>`-style returns from `src/lib/api.ts`. Structured `tracing` logs (JSON in prod, pretty in dev) — never log tokens, passwords, or ROM paths with PII.
- **Async:** Tokio everywhere server-side; Tauri commands `async` with `#[tauri::command(async)]`; WS client uses `tokio-tungstenite` + backoff. No blocking in async context.
- **Protocol:** every WS message `Envelope {type:"signaling.offer", version:"1.0", request_id, timestamp, payload:{room_id,candidate}}` with `version` as **string** `"1.0"` canonical (compat `"1"` accepted) matching `pub const PROTOCOL_VERSION: &str = "1.0"` and `is_supported_version` in `packages/protocol/src/lib.rs:14-21` / `pub version: String` in `apps/server/src/main.rs:20`. Server validates `version` then `type`, returns `{code:"unknown_type"}` for unknown `type`, `{code:"version_unsupported"}` for unsupported version; forward-compatible bump via `"2.0"` handler.
Expand Down Expand Up @@ -83,14 +83,14 @@ pnpm tauri dev -- --log openfight # client logs to %APPDATA%/OpenFight/logs/ope
- **Runtime:** Rust 1.78+ (MSRV), Tauri 1.x (WebView2 on Windows), Node 20+ with **pnpm 9** (not npm/yarn), Postgres 16-alpine (sqlx compile-time checked). No Bun. No Electron.
- **Package manager:** `pnpm` at root (`pnpm-workspace.yaml` covers `apps/*`, `packages/*`, `adapters/*`, `services/*`) — `pnpm install` only, commit `pnpm-lock.yaml`.
- **Build:** `cargo build --workspace`, `pnpm -C apps/client build`, `tauri build` (MSI/NSIS on Windows). Docker multi-stage `rust:1.78 → debian:bookworm-slim`.
- **Env:** `DATABASE_URL=postgres://openfight:openfight@db:5432/openfight`, `SESSION_SECRET` (32B CSPRNG), `RUST_LOG=info,openfight_server=debug`. Never commit `.env` (see `.env.example`).
- **Env:** `DATABASE_URL=postgres://opencade:opencade@db:5432/opencade`, `SESSION_SECRET` (32B CSPRNG), `RUST_LOG=info,opencade_server=debug`. Never commit `.env` (see `.env.example`).
- **OS:** Windows 10/11 primary (Tauri), Linux/macOS viable via same stack — no `.lnk` shortcuts, use `tauri::path`.
- **Tooling constraints:** keep `disableDevTools` off in dev, on in prod via Tauri `tauri.conf.json > build > devPath`. No `shell` permission in `tauri.conf.json`; use `process` allowlist.

## Testing & QA

- **No ROMs/binaries in tests:** use fixtures under `tests/fixtures/` (tiny TOML, mock adapter). `research/binaries/` is gitignored.
- **Unit:** `cargo test -p openfight-protocol -- envelope serde`, `-p emulator-sdk -- arg escaping`, `-p game-definitions -- loader/scan`, `pnpm test` for `packages/shared` (Vitest).
- **Unit:** `cargo test -p opencade-protocol -- envelope serde`, `-p emulator-sdk -- arg escaping`, `-p game-definitions -- loader/scan`, `pnpm test` for `packages/shared` (Vitest).
- **Integration:** `cargo test --workspace -- --ignored` (spins `Axum` + `postgres` via `docker compose up -d db`, registers two users, WS presence → `challenge.send/accept` → `signaling.offer/answer/candidate` → `room PLAYING` → disconnect).
- ** networking:** LAN, same NAT, different NAT, symmetric NAT (expect relay fallback), packet loss/latency injection via `tc`; `diagnostics:network_test` command asserts `nat:cone|symmetric`, `rtt_ms`, `relay_reachable`.
- **Manual QA loop (MVP):** `docker compose up -d` → `curl /health` → `pnpm tauri dev` → login → `Games` shows owned `sfiii3` (needs `sfiii3.zip` + `neogeo.zip` under `emulator/fbneo/ROMs/` scanned locally) → challenge peer in `Lobbies/:gameId` → accept → `CONNECTING` (P2P or relay) → emulator spawns `fcadefbneo.exe` with escaped `C:\path with spaces\sfiii3.zip` → play → `FINISHED` → export logs `Settings → Export Logs`.
Expand Down
16 changes: 8 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Contributing to OpenFight
# Contributing to OpenCade

Thank you for helping build an open, self-hostable alternative for arcade netplay. This document describes how to contribute safely and consistently. By contributing you agree that your contributions will be licensed under the **Apache License 2.0** (see `LICENSE`).

> **Golden rule:** OpenFight is a **clean-room reimplementation**. We study the existing proprietary platform only as a black box, write down what we observe, and then independently design and implement. We never copy, paste, decompile, or redistribute proprietary code, binaries, ROMs, or assets.
> **Golden rule:** OpenCade is a **clean-room reimplementation**. We study the existing proprietary platform only as a black box, write down what we observe, and then independently design and implement. We never copy, paste, decompile, or redistribute proprietary code, binaries, ROMs, or assets.

---

Expand Down Expand Up @@ -65,7 +65,7 @@ Copy-Item .env.example .env
## Repository Layout

```
openfight/
opencade/
├── apps/
│ ├── client/ # Tauri + React + TypeScript desktop client
│ │ └── src-tauri/ # Rust native layer (process/fs/logging)
Expand All @@ -80,7 +80,7 @@ openfight/
│ ├── fbneo/ # FBNeo adapter (first adapter)
│ └── mame/ # (future)
├── services/
│ └── relay/ # openfight-relay (TURN-like fallback)
│ └── relay/ # opencade-relay (TURN-like fallback)
├── research/ # NOT SHIPPED — observations only (see GUARDRAILS.md)
├── docs/
├── docker/
Expand Down Expand Up @@ -167,7 +167,7 @@ Observation → Documentation → Design → Implementation

2. **Documentation** — Write a short note in `research/notes/` or `research/behavior/` describing the observed behaviour, the evidence, your confidence (Low / Medium / High), and the _implementation implication_ in your own words. Example template is in `research/GUARDRAILS.md`.

3. **Design** — In the PR or a `docs/` ADR, describe the OpenFight design you propose _without referencing proprietary source_. Cite only your observation note and public specs.
3. **Design** — In the PR or a `docs/` ADR, describe the OpenCade design you propose _without referencing proprietary source_. Cite only your observation note and public specs.

4. **Implementation** — Write original Rust / TypeScript from the design. Do not copy decompiled output, do not paraphrase `lib/main.js`, do not look at `fcade.exe` strings while coding.

Expand All @@ -183,7 +183,7 @@ The following will be rejected in CI and in review:
- Decompiled or transcribed proprietary source, including `fc2-electron/resources/app/lib/main.js` and `lib/static/login.js`.
- Copyrighted ROMs or archives: `*.zip` / `*.7z` / `*.chd` game images, `emulator/*.json` outputs copied as committed TOML without review.
- Proprietary assets: `assets/*.wav` challenge sounds, icons, or other Fightcade media.
- Credentials, API keys, tokens, `.env` with secrets, `%APPDATA%/OpenFight/` dumps.
- Credentials, API keys, tokens, `.env` with secrets, `%APPDATA%/OpenCade/` dumps.
- `research/binaries/` content.

See `research/GUARDRAILS.md` for the full allow / deny matrix and the local importer workflow for `emulator/*.json` → TOML.
Expand Down Expand Up @@ -251,7 +251,7 @@ pnpm test

# If you touched Docker / migrations
docker compose config --quiet
cargo test -p openfight-server --test api_integration # if present
cargo test -p opencade-server --test api_integration # if present
```

Include in the PR description: which levels you tested and on what OS. For UI changes, attach a screenshot or short clip.
Expand All @@ -275,4 +275,4 @@ Draft PRs are welcome for early feedback — mark as `Draft` and note what is st

---

Thank you for building OpenFight the right way — original code, open protocol, self-hostable infrastructure.
Thank you for building OpenCade the right way — original code, open protocol, self-hostable infrastructure.
Loading
Loading