OhMyGame
OhMyGame is the open-source studio for making games with AI. Design, build, playtest, and publish games in one app, with your own model keys.
Play the Mount & Blade II: Bannerlord campaign with friends in a shared multiplayer world.
GamesTypeScript · PowerShellGitHub @Bannerlord-Coop-TeamOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Website of Bannerlord Coop
Translation pending
Taken from the repository README
Loading the full README.
Read the full README ↗Nightly builds are restricted to Testers and current Patreon, Boosty, and Afdian supporters, plus up to ten sponsored Discord accounts per eligible member. The installer is served by the private download gateway and verifies that entitlement on every run. See nightly-gateway/README.md for the security boundary and rollout order.
The official website for Bannerlord Co-op, a module that brings cooperative multiplayer to the Mount & Blade II: Bannerlord campaign.
By submitting a contribution to BannerlordCoop, you agree that your contribution may be used, modified, distributed, sublicensed, and relicensed by the BannerlordCoop project maintainers as part of the BannerlordCoop project.
You also confirm that you have the right to submit the contribution and that it does not knowingly include code copied from another project without permission.
Managed server owner/manager pages include a live-output panel that connects automatically. The browser connects only to the same-origin /api/servers/[serverId]/console route. That route revalidates the current Supabase user/session and forwards only the bearer token and validated server UUID to the fixed server-only CONTROL_PLANE_CONSOLE_ORIGIN; callers cannot select an upstream destination, actor, agent, process, or path.
The response is private, unbuffered SSE with a five-minute maximum session; the runner follows only new output (podman logs --follow --tail=0), so a connection never replays history and nothing is stored. The UI keeps one connection at a time and appends each connection's output to what it already shows: it renews an expired session, or a healthy stream that ends because the runner capped its log reader, at once while the tab is visible (or when the tab is shown again) for about half an hour without page activity, then pauses with a Reconnect button until the owner interacts again. Other closures use backoff bases of 2 s, 5 s, 10 s, 30 s and 60 s, each randomized within +/-25%, then independent uniform waits from 0 to 60 s so viewers recovering from a shared outage do not retry together. Exhausting the initial retries still signals lost-console guidance to Restart progress, while the console itself keeps reconnecting. Failed reconnects pause after half an hour without activity; hidden tabs defer reconnects until shown and refresh the inactivity allowance when shown again. The console waits while the server is stopped and reconnects as soon as the server is running again. Container-host logging and incomplete @DS@ control records are hidden. The UI retains at most 128 KiB and 2,000 lines. Production enablement still requires verified OpenNext/Cloudflare streaming and disconnect behavior plus the reviewed Oracle Caddy route; local mocks do not establish those deployment properties.
Each received chunk's decoded line events are appended together, and line/character retention runs once for that chunk. Each event still adds its trailing newline (including empty or multiline events), partial UTF-8/SSE frames wait for completion, and game phases are published in event order before the text update. The bounded history is still parsed when rendered, and scrolling back still pauses auto-follow. npx tsx --test src/app/components/servers/ManagedServerConsole.test.ts includes a full-buffer/100-event retention benchmark; it reports local synthetic timings, not production console latency.
Install dependencies:
npm install
Copy the example environment file and add your project values:
cp .env.example .env.local
YOUTUBE_API_KEY=your_api_key
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=your_publishable_key
SUPABASE_SECRET_KEY=your_secret_key
[email protected]
Environment files are ignored by Git. Do not commit API keys or other secrets.
Start the development server:
npm run dev
Open http://localhost:3000.
npm run dev # Start the development server
npm run lint # Run ESLint
npm run build # Create a production build
npm run start # Start the production server
Before pushing changes, run:
npm run lint
npm run build
The /login page uses Supabase Auth for Google, Discord, and passwordless email sign-in.
.env.local.http://localhost:3000/auth/callback and your production /auth/callback URL to the Supabase redirect allow list under Authentication → URL Configuration.The OAuth providers also require their Supabase callback URL (shown in the provider settings) to be allow-listed in the Google/Discord developer console.
Signed-in page and server action requests pass through src/middleware.ts. It refreshes the Supabase session once it is within five minutes of expiry and forwards the new cookies, so the page or action normally finds nothing left to refresh. A refresh inside a server action writes cookies, and Next then re-renders the whole page in the action response; the managed server page's background polls used to do this. The middleware sends its cookies as plain Set-Cookie headers, because cookies set through response.cookies reach the action's cookie store and cause the same re-render. Route handlers (/api/* and the OAuth callbacks) skip it: their cookie writes re-render nothing, and the callbacks install sessions that a refresh would overwrite. open-next.config.ts lets a server action's cookies win over the middleware's, as in Next itself, so a sign-out or impersonation change on the same request still applies. The file keeps the deprecated middleware name because Next 16's proxy.ts runs only on Node.js, which OpenNext Cloudflare supports only experimentally.
Apply reviewed SQL migrations in their coordinated rollout order. Applied migration history remains immutable, including historical external-console tables and RPCs. The website no longer reads or writes those legacy objects; this source removal does not drop production data or rewrite Auth metadata.
The protected /admin page lists Supabase Auth users, searches by member information, and stores one of Admin, Server Manager, Standard Server, Premium Server, Developer, Helper, or User in each user's protected app_metadata.role.
To enable it:
SUPABASE_SECRET_KEY. Never use this value in a NEXT_PUBLIC_ variable or browser component.SUPABASE_ADMIN_EMAILS to the email address of the first administrator. Multiple bootstrap administrators may be comma-separated./admin.Bootstrap administrators always retain admin access, preventing an accidental total lockout. Assigned roles take effect after the user's Auth session refreshes or they sign in again.
The protected /admin/control-plane page is the administrative surface for managed hosting. It reads fleet/server/job/release/audit state and submits the administrator operations it offers through the control-plane-admin Supabase Edge Function. The page has no form for publishing the hosting-region catalog (set-hosting-regions); that operation is sent through the same Edge Function by hand, as described in docs/server-onboarding.md. The function reauthenticates the current Discord administrator and relays the typed request to the Oracle control-plane web adapter. The website does not query the private control-plane schema or talk directly to VPS providers, runners, containers, or object storage. See docs/control-plane-admin.md and the control-plane repository's docs/managed-hosting/web-admin.md.
The legacy placeholder implementation (not the current authenticated My Servers/onboarding flow below) provides these simulated behaviors:
Admin and Server Manager members can manage every placeholder hosted server and view its assigned account.Standard Server and Premium Server members see the placeholder management experience for their plan.0 4 * * *.The public directory and legacy placeholder assigned-server records remain fixtures. Typed placeholder records—including fictitious account assignments—live in src/app/lib/hosting/servers.ts; they are not evidence of current account assignments or onboarding eligibility.
The placeholder design is documented in docs/server-hosting-design.md.
The current /servers page loads authenticated managed assignments from the control plane using registered server UUIDs. New setup uses unused explicitly granted quota, not membership or role claims. Available regions create an assigned stopped server; full regions accept private durable requests through the existing authenticated my-servers Edge Function. The public directory loads the anonymous public-servers endpoint independently of private inventory.
See website server onboarding for the strict contract, exact-request recovery, Discord password controls, mock-only screenshots/tests and required schema → backend → my-servers Edge → UI rollout order. The Supabase hosting deployment workflow deploys affected managed-hosting APIs from main; schema and backend prerequisites retain their separate rollout gates.
My Servers uses authenticated control-plane assignments only. Manage a server using its registered /servers/<UUID> route. Unknown and retired server IDs return signed-in visitors to /servers; no static alias, IP address or display name is used to associate a legacy server with a managed record.
Owners and managers use the managed console, its command input, lifecycle controls and log downloads. Support and administrator assignments remain read-only and do not connect to console streaming. Owners rename a server from Settings through the control plane. Managed backup, save/configuration transfer, visibility, maintenance and release settings retain their existing authorization boundaries.
The Mods tab lets owners and managers reorder, enable, upload and delete custom modules. The browser calls only the same-origin /api/servers/<UUID>/mods route handlers, which revalidate the session and relay an allowlisted route (including 8 MiB binary upload chunks) through the my-servers Edge Function to the control plane's /api/v1/mods/* routes. See server mods for the transport, retry and archive rules and the rollout order.
The legacy external WebSocket console, catalog, owner/operator assignment actions, live rename actions, gateway, Docker node agent and deployment recipes have been removed; old /servers/live/<id> links redirect to /servers. This source change does not stop an existing deployment or erase historical account metadata.
Configure CONTROL_PLANE_CONSOLE_ORIGIN with the fixed HTTPS control-plane origin used by the /v1/user/console-stream proxy.
NEXT_PUBLIC_SUPABASE_URLPublic URL for the Supabase project used by the browser and server auth clients.
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEYSupabase publishable key. Despite being browser-visible, row-level security and Auth policies must still protect project data. Never substitute the service-role key.
SUPABASE_SECRET_KEYServer-only Supabase secret key used by protected member-role administration to list users and update member roles. Never expose or commit it.
SUPABASE_ADMIN_EMAILSComma-separated bootstrap administrator emails. These users always have admin access and cannot be demoted through the member administration page.
CONTROL_PLANE_ORIGINOptional server-only origin for the website's direct control-plane reads: the administrator pane reads (/v1/admin/control-plane), owner inventory reads (/v1/user/control-plane) and the public directory (/v1/public/control-plane). Unset or empty uses the reviewed production origin https://control-plane.bannerlordcoop.com. An override must be a bare absolute https:// origin with no credentials, path, query or fragment, for example https://localhost:9443 for a local stack behind a trusted TLS proxy. Any other value fails closed: the read throws before a request is sent. The routes stay fixed in code; this value only selects the origin. It does not affect CONTROL_PLANE_CONSOLE_ORIGIN or the Edge Functions' CONTROL_PLANE_WEB_ORIGINS. Never use a NEXT_PUBLIC_ variable for it.
CONTROL_PLANE_CONSOLE_ORIGINServer-only bare HTTPS origin for the managed read-only console proxy, for example https://control-plane.example.com. The website reauthenticates the user/session and forwards only the requested registered server ID to /v1/user/console-stream. The retired CONSOLE_GATEWAY_URL and CONSOLE_SERVER_CATALOG variables are no longer read and can be removed from deployment settings separately.
YOUTUBE_API_KEYServer-only YouTube Data API v3 key used to retrieve:
The key is read only in src/app/lib/youtube.ts. Do not prefix it with NEXT_PUBLIC_, because that would expose it to browser code.
YouTube responses are cached for 24 hours.
The community statistic cards and server browser currently show an unavailable state. Their components and types are kept in place for the future game integration:
src/app/components/home/community/
src/app/components/utils/types/server.types.ts
The planned data flow is:
Bannerlord dedicated servers
→ central HTTPS registry API
→ Next.js website
Do not replace the unavailable state with mock production values. Live values should be introduced when the registry API contract and hosting are ready.
Official YouTube links and approved creator channel IDs are configured in:
src/app/components/home/media/CommunityMedia.tsx
Videos require only a YouTube URL:
{ href: "https://www.youtube.com/watch?v=VIDEO_ID" }
YouTube creators require only a channel ID:
{ channelId: "UC_CHANNEL_ID" }
The server-side YouTube utility retrieves the remaining metadata.
Creators on other platforms, such as Twitch, carry their full profile instead, because the site has no API integration for those platforms. Their avatar host must be allowed in next.config.ts:
{ profile: { id: "twitch:name", name: "Name", description: "", avatar: "https://...", href: "https://www.twitch.tv/name" } }
Creators appear in the order they are listed.
src/app/
├── components/
│ ├── home/ Homepage sections and interactive media
│ ├── layout/ Navbar and footer
│ ├── motion/ Shared animation components
│ └── utils/ Shared TypeScript types
├── lib/ Server-only integrations
├── globals.css Tailwind theme and global styles
├── layout.tsx Fonts and site metadata
└── page.tsx Homepage composition
Bannerlord Co-op is an independent community project and is not affiliated with or endorsed by TaleWorlds Entertainment.
Campaign deletion maps the control plane's save_still_loaded admission error to
localized guidance in all shipped locales: start the selected campaign, then stop
it before deleting the previously loaded campaign. Unknown codes keep the generic
failure message. The existing error and enqueue envelopes are unchanged. Durable
owner-visible delete-job outcomes remain tracked in ControlPlane #581.