// ── The player's own Rust identity ──────────────────────────────────────── // // `/player/rust` — where a signed-in player links the Steam account they play // on. It is the one page in this module a player is asked to *do* something on, // and the thing they are doing matters more than it looks: from phase 7 the link // is what in-game permissions are granted against, and from phase 13 it is what // rewards are handed to. // // **A player route renders no layout of its own.** Core wraps `/player/*` in its // own portal chrome, so this page starts at a heading — unlike the public pages // in this module, which render `PublicLayout` themselves. // // The three-step instruction at the top is not decoration. Nothing else on the // site tells a player that the code comes from the game, and a code field with no // explanation is a code field nobody can use. import { useCallback, useState } from 'react' import { ErrorState, Loading, useAsync } from '../../core.js' import { ago, shortId } from '../../lib/format.js' import api from '../../api.js' /** The code field, and the four answers it can produce. */ function LinkForm({ onLinked }) { const [code, setCode] = useState('') const [busy, setBusy] = useState(false) const [message, setMessage] = useState('') const [error, setError] = useState('') async function submit(event) { event.preventDefault() if (!code.trim() || busy) return setBusy(true) setMessage('') setError('') try { const result = await api.playerLinks.confirm(code.trim()) setMessage( result.already ? 'That account was already linked to you.' : `Linked ${result.link.name || shortId(result.link.steamId)}.`, ) setCode('') await onLinked() } catch (err) { // Every refusal the server sends is already a sentence aimed at a player — // "run /link again", "run /unlink in game", "try again in a minute" — so // this renders it rather than replacing it with one of its own. The three // are not interchangeable, and a page that flattened them into "could not // link that code" would send a player back to the server that is down. setError(err.message || 'Could not link that code.') } finally { setBusy(false) } } return (
) } /** One linked account, and the control that releases it. */ function LinkRow({ link, onRemoved }) { const [busy, setBusy] = useState(false) const [error, setError] = useState('') async function remove() { setBusy(true) setError('') try { await api.playerLinks.remove(link.steamId) await onRemoved() } catch (err) { setError(err.message || 'Could not unlink that account.') setBusy(false) } } return ({error}
)}Linking tells this site which Steam account is yours, so your play on our servers appears under your name here — and so rewards and permissions the site hands out can reach you in game.
/link in chat.
A link covers every server this community runs — a Steam account is one person wherever
they play, while stats are kept per server and per wipe. You can also type
{' '}/unlink in game to release one.
No Steam account is linked to this profile yet.
)}